* Re: Problem with put_reg_into_stack
[not found] <no.id>
@ 1998-12-12 19:15 ` H.J. Lu
1999-08-06 12:06 ` Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3 John David Anglin
` (162 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: H.J. Lu @ 1998-12-12 19:15 UTC (permalink / raw)
To: hjl; +Cc: egcs-bugs, egcs-patches, matthew, us, ml
>
> Hi,
>
> Here is a simplified version of my previous bug report. I think that
> may be another addressof related bug. mark_addressable () in
> cp/typeck.c has
>
> case CONST_DECL:
> case RESULT_DECL:
> if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
> && !DECL_ARTIFICIAL (x) && extra_warnings)
> cp_warning ("address requested for `%D', which is declared `register'",
> x);
> put_var_into_stack (x);
> TREE_ADDRESSABLE (x) = 1;
> return 1;
>
> The related RTL code is
>
> (set (reg:QI 23)
> (mem/s:QI (plus:SI (reg/v/u:SI 22)
> (const_int 4))))
>
> That is done on purpose since the x86 pattern doesn't allow memory
> to memory move. put_var_into_stack () calls put_reg_into_stack ()
> which turns
>
> (reg:QI 23)
>
> into
>
> (mem:QI (plus:SI (reg:SI 18)
> (const_int -2)))
>
> Now we get
>
> (set (mem:QI (plus:SI (reg:SI 18)
> (const_int -2)))
> (mem/s:QI (plus:SI (reg/v/u:SI 22)
> (const_int 4))))
>
> It is not a valid x86 pattern. I have no idea if it can be fixed
> easily. Maybe i386.md can be modified to fix it.
>
> Thanks.
>
>
>
> --
> H.J. Lu (hjl@gnu.org)
> ---
> typedef unsigned long int pthread_t;
> class JTCThreadId
> {
> public:
> JTCThreadId();
> operator pthread_t() const;
> };
> class JTCRecursiveMutex
> {
> int count_;
> JTCThreadId owner_;
> public:
> JTCThreadId _JTC_getId() const;
> };
> JTCThreadId
> JTCRecursiveMutex::_JTC_getId() const
> {
> JTCThreadId id = (count_ > 0) ? owner_ : JTCThreadId();
> return id;
> }
>
Here is a kludge. Matthew, please let me know if it works for you.
I hope someone will provide a real fix.
Thanks.
--
H.J. Lu (hjl@gnu.org)
----
Sat Dec 12 19:08:53 1998 H.J. Lu (hjl@gnu.org)
* config/i386/i386.h (TARGET_MOVE): Allow memory->memory move
if optimize == 0.
--- ../../../import/egcs/gcc/config/i386/i386.h Mon Jul 27 09:56:45 1998
+++ config/i386/i386.h Sat Dec 12 19:11:29 1998
@@ -148,7 +148,9 @@
#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
/* Hack macros for tuning code generation */
-#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */
+
+/* Don't generate memory->memory */
+#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0 || optimize == 0)
#define TARGET_PSEUDO ((target_flags & MASK_NO_PSEUDO) == 0) /* Move op's args into pseudos */
#define TARGET_386 (ix86_cpu == PROCESSOR_I386)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3
[not found] <no.id>
1998-12-12 19:15 ` Problem with put_reg_into_stack H.J. Lu
@ 1999-08-06 12:06 ` John David Anglin
1999-08-25 0:38 ` Jeffrey A Law
1999-08-31 22:41 ` John David Anglin
2000-04-28 13:32 ` g++-mike-eh8-C test failure John David Anglin
` (161 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 1999-08-06 12:06 UTC (permalink / raw)
To: John David Anglin; +Cc: egcs-bugs, gcc-patches
Here is a fix for the internal compiler error on the vax:
* calls.c (emit_call_1): Use call_pop/call_value_pop for all values
of n_popped when call/call_value are not defined.
--- calls.c.orig Fri Aug 6 13:57:19 1999
+++ calls.c Fri Aug 6 13:57:21 1999
@@ -405,7 +405,12 @@
#ifndef ACCUMULATE_OUTGOING_ARGS
#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)
- if (HAVE_call_pop && HAVE_call_value_pop && n_popped > 0)
+#if defined (HAVE_call) && defined (HAVE_call_value)
+ if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
+ && n_popped > 0)
+#else
+ if (HAVE_call_pop && HAVE_call_value_pop)
+#endif
{
rtx n_pop = GEN_INT (n_popped);
rtx pat;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3
1999-08-06 12:06 ` Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3 John David Anglin
@ 1999-08-25 0:38 ` Jeffrey A Law
1999-08-31 22:41 ` Jeffrey A Law
1999-08-31 22:41 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jeffrey A Law @ 1999-08-25 0:38 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message < 199908061906.PAA25799@hiauly1.hia.nrc.ca >you write:
> Here is a fix for the internal compiler error on the vax:
>
> * calls.c (emit_call_1): Use call_pop/call_value_pop for all values
> of n_popped when call/call_value are not defined.
I added some comments to clarify what the code was trying to do and installed
your fix.
Thanks,
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3
1999-08-25 0:38 ` Jeffrey A Law
@ 1999-08-31 22:41 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 1999-08-31 22:41 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message < 199908061906.PAA25799@hiauly1.hia.nrc.ca >you write:
> Here is a fix for the internal compiler error on the vax:
>
> * calls.c (emit_call_1): Use call_pop/call_value_pop for all values
> of n_popped when call/call_value are not defined.
I added some comments to clarify what the code was trying to do and installed
your fix.
Thanks,
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3
1999-08-06 12:06 ` Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3 John David Anglin
1999-08-25 0:38 ` Jeffrey A Law
@ 1999-08-31 22:41 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 1999-08-31 22:41 UTC (permalink / raw)
To: John David Anglin; +Cc: egcs-bugs, gcc-patches
Here is a fix for the internal compiler error on the vax:
* calls.c (emit_call_1): Use call_pop/call_value_pop for all values
of n_popped when call/call_value are not defined.
--- calls.c.orig Fri Aug 6 13:57:19 1999
+++ calls.c Fri Aug 6 13:57:21 1999
@@ -405,7 +405,12 @@
#ifndef ACCUMULATE_OUTGOING_ARGS
#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)
- if (HAVE_call_pop && HAVE_call_value_pop && n_popped > 0)
+#if defined (HAVE_call) && defined (HAVE_call_value)
+ if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
+ && n_popped > 0)
+#else
+ if (HAVE_call_pop && HAVE_call_value_pop)
+#endif
{
rtx n_pop = GEN_INT (n_popped);
rtx pat;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
[not found] <no.id>
1998-12-12 19:15 ` Problem with put_reg_into_stack H.J. Lu
1999-08-06 12:06 ` Internal compiler error in `emit_call_1' - vax-dec-ultrix4.3 John David Anglin
@ 2000-04-28 13:32 ` John David Anglin
2000-04-28 15:41 ` John David Anglin
2000-05-18 11:19 ` VAX Ultrix bootstrap failure: Cannot allocate 4072 bytes John David Anglin
` (160 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-04-28 13:32 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, law, gcc-patches, egcs-bugs
> > But all calls to eh_context_static should be through other functions in
> > libgcc which are not static, like __get_eh_info. Can you do backtraces so
> > we can see where the two copies are being called from?
>
> I added verbose output to the linker to try to find where things go wrong.
> It appears trouble starts when __main.o is loaded from libgcc.a to resolve
> __main. This pulls in tinfo2.o, _ctors.o, _exit.o, tinfo.o, _eh.o,
> lib2funcs.o, opdel.o and exception.o from libgcc.a (see below). __main
> is the only symbol imported in eh8.s which is not in libstdc++.sl.
Changed my mind. The problem appears to be caused by the selection of
tinfo2.o in libgcc.a to resolve "char type_info node" (__tic).
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-04-28 13:32 ` g++-mike-eh8-C test failure John David Anglin
@ 2000-04-28 15:41 ` John David Anglin
2000-04-30 8:47 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-04-28 15:41 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, law, gcc-patches, egcs-bugs
> Changed my mind. The problem appears to be caused by the selection of
> tinfo2.o in libgcc.a to resolve "char type_info node" (__tic).
After much testing, it appears that the hpux linker prefers to resolve DATA
symbols from archive libraries even when a shared library with the symbol
preceeds the archive library in the command. It only seems to resolve DATA
symbols from shared libraries when all symbols are explicitly exported
with "-E" or when no archive library contains the symbol. Yuck!
It looks like the global DATA symbols that reside in both libstdc++.sl
and libgcc.a should only be in one or the other (probably libgcc.a).
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-04-28 15:41 ` John David Anglin
@ 2000-04-30 8:47 ` John David Anglin
2000-05-02 9:30 ` Jeffrey A Law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-04-30 8:47 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, law, gcc-patches, egcs-bugs
After all this grief with duplicate routines, I decided to change the
hpux configuration for libstdc++ so that the standard libraries are not
linked into libstdc++.sl. This resolves the problem.
I reran the tests. There was one new failure with "-threads":
FAIL: g++.law/profile1.C (test for excess errors)
However, this is expected since "-pg" and "-threads" are not compatible
(there are no profiling libraries for DCE threads). Of course, nobody
will get this far unless the configure patch for hpux threads gets
installed.
Regarding the installed location of libstdc++, there is a problem
under hpux when both shared and archive libraries are installed. For
the shared_archive or archive_shared linker preference mechanism to
work, both the archive and shared libraries must be in the same
directory. The archive version of libstdc++ is installed in
the compiler installation director as a link to a versioned archive
library in ${prefix}/lib (e.g., libstdc++.a.2.10.0). The shared
version is installed with no versioning in ${prefix}/lib. The
compiler location is searched first. As a result, the archive
version is found first and always selected.
My solution is to remove the link to the archive library in the
compiler directory, version the shared library, and add links in
${prefix}/lib to the versioned libraries. For example,
289 (hiauly1)dave> ll libstdc*
lrwxr-xr-x 1 bin bin 18 Apr 30 11:01 libstdc++.a -> libstdc++.a.2.10.0
-rw-r--r-- 1 bin bin 577896 Apr 30 10:40 libstdc++.a.2.10.0
lrwxr-xr-x 1 bin bin 19 Apr 30 11:01 libstdc++.sl -> libstdc++.sl.2.10.0
-r-xr-xr-x 1 bin bin 605244 Apr 30 10:40 libstdc++.sl.2.10.0
I did the same in ${prefix}/lib/threads.
This allows removing the version specific compiler stuff without affecting
previously linked apps. Any thoughts on this?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
--- hpux.ml.orig Sun Aug 30 17:18:44 1998
+++ hpux.ml Fri Apr 28 19:23:06 2000
@@ -3,4 +3,4 @@
SHLIB = libstdc++.sl
LIBS = $(ARLIB) $(ARLINK) $(SHLIB)
DEPLIBS = ../$(SHLIB)
-SHFLAGS = $(PICFLAG)
+SHFLAGS = -nostdlib $(PICFLAG)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-04-30 8:47 ` John David Anglin
@ 2000-05-02 9:30 ` Jeffrey A Law
2000-05-02 11:08 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jeffrey A Law @ 2000-05-02 9:30 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, gcc-patches, egcs-bugs
In message <200004301546.LAA19936@hiauly1.hia.nrc.ca>you write:
> After all this grief with duplicate routines, I decided to change the
> hpux configuration for libstdc++ so that the standard libraries are not
> linked into libstdc++.sl. This resolves the problem.
And just adds a new set of problems. Consider if the library needs something
like __muldi3 -- you won't have it anymore after your change because you're
not linking in libgcc.
Basically you've just exchanged one set of problems for an even worse set
of problems.
You might want to read the thread about a shared libgcc since most of the
issues being discussed in that thread directly apply to the issues you're
trying to resolve.
> Regarding the installed location of libstdc++, there is a problem
> under hpux when both shared and archive libraries are installed. For
> the shared_archive or archive_shared linker preference mechanism to
> work, both the archive and shared libraries must be in the same
> directory. The archive version of libstdc++ is installed in
> the compiler installation director as a link to a versioned archive
> library in ${prefix}/lib (e.g., libstdc++.a.2.10.0). The shared
> version is installed with no versioning in ${prefix}/lib. The
> compiler location is searched first. As a result, the archive
> version is found first and always selected.
>
> My solution is to remove the link to the archive library in the
> compiler directory, version the shared library, and add links in
> ${prefix}/lib to the versioned libraries. For example,
Ultimately, I think we're going to want all the libraries in $prefix/lib
with none in the gcc-lib directory. This is one of the changes necessary
to make a shared libgcc work in a reasonable manner.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 9:30 ` Jeffrey A Law
@ 2000-05-02 11:08 ` John David Anglin
2000-05-02 11:17 ` Jeffrey A Law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-02 11:08 UTC (permalink / raw)
To: law; +Cc: jason, gcc-patches, egcs-bugs
> In message <200004301546.LAA19936@hiauly1.hia.nrc.ca>you write:
> > After all this grief with duplicate routines, I decided to change the
> > hpux configuration for libstdc++ so that the standard libraries are not
> > linked into libstdc++.sl. This resolves the problem.
> And just adds a new set of problems. Consider if the library needs something
> like __muldi3 -- you won't have it anymore after your change because you're
> not linking in libgcc.
>
> Basically you've just exchanged one set of problems for an even worse set
> of problems.
No. "-nostdlib" is only used when building the shared varsion of libstdc++.
When an app is linked with libstdc++, libgcc is normally included twice in
the link (eg., without threads -lgcc -lc -lgcc is automatically included).
With the change, I didn't encounter any link problems using the shared
version of libstdc++ included with the gcc-2.95 branch except for the
one case mentioned which involved threads and profiling. I am fairly
certain if __muldi3 weren't being linked in from libgcc properly,
something would have gone wrong in running the testsuite. The results
with a shared libstdc++ were equivalent to that with the archive version.
Thus, I don't see the worse set of problems that you describe with the
hpux 10.20 linker. Have you a specific example that I can test?
NB: I have installed the longjmp patch to pa.md which is now in the main
branch but not the 2.95 branch, and a configure patch re DCE thread selection
which fixes linking problems when DCE threads are installed. Thus, some
of the problems previously observed may be fixed.
The situation here is specific to the hpux som linker and its handling
of global data in shared libraries. If libstdc++ is linked with libgcc
when it is built, this has the unfortunate side effect of linking static
procedures into a final app twice, once from libstdc++ and once from
libgcc. Both get used. Which one is selected depends on the calling
path. If the routine has data which shouldn't be duplicated, disaster
ensues. In the particalur case studied, it was the global data symbol
"__tic" which caused tinfo2.o to be loaded from libgcc rather than
libstdc++.
Possible solutions as I see it are:
1) Get HP to fix their linker. Doesn't seem likely.
2) Hack libstdc++ so that global data is only accessed in procedures
with global scope. This is possible but more complicated than
3 below.
3) Don't link the shared version of libstdc++ with libgcc when it
is built. I know there were problems on other systems (alpha?)
when this was done. This needs to be looked into further under
hpux but if you check the configuration files for libstdc++ you
will see that openbsd uses the -nostdlib option when building
the shared version of libstdc++.
In summary, with the above mentioned patches installed in the gcc-2.95 branch,
I find that the shared libstdc++ v2 is working equivalently to the archive
version.
The situation with the main branch is now under investigation. However, it
looks like there are other problems which need resolution first.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 11:08 ` John David Anglin
@ 2000-05-02 11:17 ` Jeffrey A Law
2000-05-02 13:02 ` John David Anglin
2000-05-08 11:10 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-05-02 11:17 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, gcc-patches, egcs-bugs
In message < 200005021808.OAA18067@hiauly1.hia.nrc.ca >you write:
> No. "-nostdlib" is only used when building the shared varsion of libstdc++
And that is precisely the problem. That change is _wrong_, no ifs ands or
butts about it.
> When an app is linked with libstdc++, libgcc is normally included twice in
> the link (eg., without threads -lgcc -lc -lgcc is automatically included).
> With the change, I didn't encounter any link problems using the shared
> version of libstdc++ included with the gcc-2.95 branch except for the
> one case mentioned which involved threads and profiling.
Consider a shared library that does not appear on the link line, but which
is loaded explicitly by the application.
If the shared library references __muldi3, but the main application and
libraries on the link line for the application do not, then no __main will
be linked into the final executable.
So when you do a shl_load to suck in the shared library we'll have an
undefined reference to __muldi3 and we'll lose badly.
I am fairly
> certain if __muldi3 weren't being linked in from libgcc properly,
> something would have gone wrong in running the testsuite. The results
> with a shared libstdc++ were equivalent to that with the archive version.
> Thus, I don't see the worse set of problems that you describe with the
> hpux 10.20 linker. Have you a specific example that I can test?
See above.
Never assume that just because something passes the testsuite that it is
correct. There are numerous things the testsuite does not check.
> 1) Get HP to fix their linker. Doesn't seem likely.
>
> 2) Hack libstdc++ so that global data is only accessed in procedures
> with global scope. This is possible but more complicated than
> 3 below.
>
> 3) Don't link the shared version of libstdc++ with libgcc when it
> is built. I know there were problems on other systems (alpha?)
> when this was done. This needs to be looked into further under
> hpux but if you check the configuration files for libstdc++ you
> will see that openbsd uses the -nostdlib option when building
> the shared version of libstdc++.
4. Build a shared libgcc and have it referenced by either the main program
or the library. Which is precisely what we're discussing in another thread.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 11:17 ` Jeffrey A Law
@ 2000-05-02 13:02 ` John David Anglin
2000-05-02 18:44 ` Jason Merrill
2000-05-08 11:10 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-02 13:02 UTC (permalink / raw)
To: law; +Cc: jason, gcc-patches, egcs-bugs
> Consider a shared library that does not appear on the link line, but which
> is loaded explicitly by the application.
>
> If the shared library references __muldi3, but the main application and
> libraries on the link line for the application do not, then no __main will
> be linked into the final executable.
>
> So when you do a shl_load to suck in the shared library we'll have an
> undefined reference to __muldi3 and we'll lose badly.
But if the shared library is complete, we may end up with duplicate code
for __muldi3 and lose anyway. The HP linker is apparently too dumb to
detect this duplication and I have to wonder if shl_load would do much
better.
I doubt the current link command actually produces a complete libstdc++.
I think -lm is needed. There is no shared pa1.1 version of libm under
10.20. So it is possible that there could be problems with duplicating
code here.
Do we really need libstdc++ to work with dlopen/shl_load? If somebody
does, presumably they could build a special dynamically loadable version
and hack libgcc to remove the duplication. They could also define a
table of necessary libgcc routines that the app needs to run. I am
sure somebody could figure out a scheme to do this automatically.
I would argue that there is a simple fix that works with the standard
dynamic loader and thus it should be implemented. I don't think it is
a big issue to tell people about the restrictions of the implementation.
It's definitely a step up from not working at all. We seem to be trying
to run before we can walk.
> 4. Build a shared libgcc and have it referenced by either the main program
> or the library. Which is precisely what we're discussing in another thread.
Building a shared libgcc is a good idea on its own. However, it might
not resolve this problem. There still might be duplication of procedures
and problems with libraries that don't have a shared implementation.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 13:02 ` John David Anglin
@ 2000-05-02 18:44 ` Jason Merrill
2000-05-03 10:43 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jason Merrill @ 2000-05-02 18:44 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches, egcs-bugs
>>>>> John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
> But if the shared library is complete, we may end up with duplicate code
> for __muldi3 and lose anyway. The HP linker is apparently too dumb to
> detect this duplication and I have to wonder if shl_load would do much
> better.
Yes, that's why we want to make libgcc its own shared library, so that
there's only one copy.
> Do we really need libstdc++ to work with dlopen/shl_load?
Yes. The folks that initially paid us to make shared libraries work rely
on that functionality.
>> 4. Build a shared libgcc and have it referenced by either the main
>> program or the library. Which is precisely what we're discussing in
>> another thread.
> Building a shared libgcc is a good idea on its own. However, it might
> not resolve this problem. There still might be duplication of procedures
> and problems with libraries that don't have a shared implementation.
Why would there be duplication?
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 18:44 ` Jason Merrill
@ 2000-05-03 10:43 ` John David Anglin
2000-05-03 15:49 ` Jason Merrill
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-03 10:43 UTC (permalink / raw)
To: Jason Merrill; +Cc: law, gcc-patches, egcs-bugs
> > Building a shared libgcc is a good idea on its own. However, it might
> > not resolve this problem. There still might be duplication of procedures
> > and problems with libraries that don't have a shared implementation.
>
> Why would there be duplication?
This is what the HP-UX Linker and Libraries Online User Guide says about the
subject:
Summary of Mixing Shared and Archive Libraries
Applications that depend on shared libraries should not use archive libraries
to satisfy symbol imports in a shared library. This suggests that only a
shared version of libc should be used in applications using shared
libraries. If an archive version of a dependent library must be used, all of its
definitions should be explicitly exported with the -E or +e options to the
linker to avoid multiple definitions.
Providers of shared libraries should make every effort to prevent these
kinds of problems. In particular, if a shared library provider allows
unsatisfied symbols to be satisfied by an archive version of libc, the
application that uses the library may fail if the shared library is later
updated and any new libc dependencies are introduced. New dependencies in
shared libraries can be satisfied by maintaining accurate dependency lists.
However, this can lead to multiple occurrences of the same definition in an
application if the definitions are not explicitly exported.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-03 10:43 ` John David Anglin
@ 2000-05-03 15:49 ` Jason Merrill
2000-05-03 17:27 ` John David Anglin
2000-05-05 15:12 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Jason Merrill @ 2000-05-03 15:49 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches, egcs-bugs
>>>>> John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>> > Building a shared libgcc is a good idea on its own. However, it
>> > might not resolve this problem. There still might be duplication of
>> > procedures and problems with libraries that don't have a shared
>> > implementation.
>>
>> Why would there be duplication?
> This is what the HP-UX Linker and Libraries Online User Guide says about
> the subject:
> Summary of Mixing Shared and Archive Libraries
> Applications that depend on shared libraries should not use archive
> libraries to satisfy symbol imports in a shared library.
Yes, absolutely. That's why we're talking about libgcc.sl. Are you
worried about symbols from libm?
> This suggests that only a shared version of libc should be used in
> applications using shared libraries. If an archive version of a
> dependent library must be used, all of its definitions should be
> explicitly exported with the -E or +e options to the linker to avoid
> multiple definitions.
Which suggests that libstdc++.sl should be built with -E.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-03 15:49 ` Jason Merrill
@ 2000-05-03 17:27 ` John David Anglin
2000-05-05 15:12 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-03 17:27 UTC (permalink / raw)
To: Jason Merrill; +Cc: law, gcc-patches, egcs-bugs
> > Applications that depend on shared libraries should not use archive
> > libraries to satisfy symbol imports in a shared library.
>
> Yes, absolutely. That's why we're talking about libgcc.sl. Are you
> worried about symbols from libm?
I looked at that again. It appears this isn't a problem since the pa1.1
archive version of libm is only used when the link is !shared.
> > This suggests that only a shared version of libc should be used in
> > applications using shared libraries. If an archive version of a
> > dependent library must be used, all of its definitions should be
> > explicitly exported with the -E or +e options to the linker to avoid
> > multiple definitions.
>
> Which suggests that libstdc++.sl should be built with -E.
It's worth a try. Possibly, this might cause libstdc++.sl to better
advertise the symbols that it depends on from libgcc.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-03 15:49 ` Jason Merrill
2000-05-03 17:27 ` John David Anglin
@ 2000-05-05 15:12 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-05 15:12 UTC (permalink / raw)
To: Jason Merrill; +Cc: law, gcc-patches, egcs-bugs
> Yes, absolutely. That's why we're talking about libgcc.sl. Are you
> worried about symbols from libm?
>
> > This suggests that only a shared version of libc should be used in
> > applications using shared libraries. If an archive version of a
> > dependent library must be used, all of its definitions should be
> > explicitly exported with the -E or +e options to the linker to avoid
> > multiple definitions.
>
> Which suggests that libstdc++.sl should be built with -E.
Tried it. It doesn't resolve the problem. According to other documentation,
-E is for exporting symbols from main programs. +e can be used for exporting
symbols from shared libraries but it hides all the symbols which aren't
explicitly exported.
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: g++-mike-eh8-C test failure
2000-05-02 11:17 ` Jeffrey A Law
2000-05-02 13:02 ` John David Anglin
@ 2000-05-08 11:10 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-08 11:10 UTC (permalink / raw)
To: law; +Cc: jason, gcc-patches, egcs-bugs
> 4. Build a shared libgcc and have it referenced by either the main program
> or the library. Which is precisely what we're discussing in another thread.
I hacked the gcc Makefile to build a shared version of libgcc under hpux
10.20. This was relatively simple to do since all the modules in libgcc
for this target are already PIC. I did have to change the "-BstageN/"
stuff to "-B$(objdir)/stageN/" so that the compiler would work outside
the gcc build directory. This resolves the g++-mike-eh8-C and other
related failures in the g++ testsuite. There were no test regressions
that I could see for any of the other testsuites.
My hacks certainly aren't ready for prime time but they suggest a possible
way to proceed. There are issues such as versioning and the installation
process which I haven't given much thought to. Typically, hpux applications
need to be relinked with the installed library before installation.
There is also the question as to whether the dependence of libgcc.sl on
libc should be explicit or not. The same issue applies to libstdc++.
For most targets, an explicit dependence is specified for libm but not
libc.
I would highly encourage trying to get the build process modified to support
building a shared version of libgcc for the next release. I am really unhappy
about linking the archive version of libgcc into the shared version libstdc++.
The are a couple of problems that I have noted in the lib and link specs
for pa1.1 machines under hpux 10.20. The -L libraries for -p and -pg
should preceed the -L specs for the pa1.1 libraries in the link spec.
Under 10.20, libc_r.sl is just a link to libc in /usr/lib. There is no
archive version of libc_r. I don't know about other releases of hpux 10,
but I think this suggests that "-lc" could be used as the lib spec for all
!shared cases. If libc_r and libc differ on other releases, then libc_r
will still have to be specified for thread usage. There are subtle issues
regarding which libc is used with a shared libgcc if the dependence on
libc is explicit.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure: Cannot allocate 4072 bytes
[not found] <no.id>
` (2 preceding siblings ...)
2000-04-28 13:32 ` g++-mike-eh8-C test failure John David Anglin
@ 2000-05-18 11:19 ` John David Anglin
2000-05-18 15:48 ` Jeffrey A Law
2000-05-22 9:45 ` VAX Ultrix bootstrap failure: cc: -o would overwrite John David Anglin
` (159 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-18 11:19 UTC (permalink / raw)
To: John David Anglin; +Cc: egcs-bugs, gcc-patches
> stage1/xgcc -Bstage1/ -B/usr/local/vax-dec-ultrix4.3/bin/ -c -DIN_GCC -W -Wall -Wtraditional -pedantic -Wwrite-strings -g -O2 -W -Wall -DHAVE_CONFIG_H -I. -I../../gcc -I../../gcc/config -I../../gcc/../include ../../gcc/stmt.c
>
> Cannot allocate 4072 bytes
Here is a patch to libiberty/xmalloc.c for review and installation.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-05-18 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* xmalloc.c: Include config.h for HAVE_SBRK definition.
--- libiberty/xmalloc.c.orig Sat Oct 2 21:55:59 1999
+++ libiberty/xmalloc.c Thu May 18 13:18:17 2000
@@ -17,6 +17,9 @@
not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include "ansidecl.h"
#include "libiberty.h"
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure: Cannot allocate 4072 bytes
2000-05-18 11:19 ` VAX Ultrix bootstrap failure: Cannot allocate 4072 bytes John David Anglin
@ 2000-05-18 15:48 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-05-18 15:48 UTC (permalink / raw)
To: John David Anglin; +Cc: egcs-bugs, gcc-patches
In message < 200005181819.OAA23824@hiauly1.hia.nrc.ca >you write:
> > stage1/xgcc -Bstage1/ -B/usr/local/vax-dec-ultrix4.3/bin/ -c -DIN_GCC
> -W -Wall -Wtraditional -pedantic -Wwrite-strings -g -O2 -W -Wall -DHAVE_C
> ONFIG_H -I. -I../../gcc -I../../gcc/config -I../../gcc/../include ../../
> gcc/stmt.c
> >
> > Cannot allocate 4072 bytes
>
> Here is a patch to libiberty/xmalloc.c for review and installation.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
>
> 2000-05-18 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * xmalloc.c: Include config.h for HAVE_SBRK definition.
Thanks. Installed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure: cc: -o would overwrite
[not found] <no.id>
` (3 preceding siblings ...)
2000-05-18 11:19 ` VAX Ultrix bootstrap failure: Cannot allocate 4072 bytes John David Anglin
@ 2000-05-22 9:45 ` John David Anglin
2000-05-22 17:22 ` John David Anglin
` (158 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-22 9:45 UTC (permalink / raw)
To: John David Anglin; +Cc: law, egcs-bugs, gcc-patches
The following patch corrects configure.in so that the proper compiler variable
is tested when checking whether to set NO_MINUS_C_MINUS_O to yes. Note that
the ${ac_cc} substition has to be done first.
It also adds a test to see if ${CC-cc} supports -Wno-long-long.
If gcc is being used for stage1, the stage1_warn_cflags are set to
" -W -Wall -Wtraditional -pedantic -Wwrite-strings" when gcc doesn't
support -Wno-long-long, and to $(WARN_CFLAGS) when it does.
Please review.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-05-22 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* configure.in: Evaluate the correct variable to test and check for
-Wno-long-long support.
--- configure.in.orig Thu May 18 19:41:11 2000
+++ configure.in Mon May 22 12:07:32 2000
@@ -322,18 +322,32 @@
# Find the native compiler
AC_PROG_CC
AC_PROG_CC_C_O
-if test $ac_cv_prog_cc_${ac_cc}_c_o = no; then
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then
NO_MINUS_C_MINUS_O=yes
fi
AC_SUBST(NO_MINUS_C_MINUS_O)
gcc_AC_C_LONG_DOUBLE
+AC_MSG_CHECKING(whether ${CC-cc} accepts -Wno-long-long)
+echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -Wno-long-long -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_no_long_long=yes
+else
+ ac_cv_prog_cc_no_long_long=no
+fi
+rm -f conftest*
+echo "$ac_t"$ac_cv_prog_cc_no_long_long 1>&6
+
# If the native compiler is GCC, we can enable warnings even in stage1.
# That's useful for people building cross-compilers, or just running a
# quick `make'.
if test "x$GCC" = "xyes"; then
- stage1_warn_cflags='$(WARN_CFLAGS)'
+ if test $ac_cv_prog_cc_no_long_long = yes; then
+ stage1_warn_cflags='$(WARN_CFLAGS)'
+ else
+ stage1_warn_cflags=" -W -Wall -Wtraditional -pedantic -Wwrite-strings"
+ fi
else
stage1_warn_cflags=""
fi
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure: cc: -o would overwrite
[not found] <no.id>
` (4 preceding siblings ...)
2000-05-22 9:45 ` VAX Ultrix bootstrap failure: cc: -o would overwrite John David Anglin
@ 2000-05-22 17:22 ` John David Anglin
2000-05-24 10:32 ` VAX Ultrix bootstrap failure with gcc-2.96 John David Anglin
` (157 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-22 17:22 UTC (permalink / raw)
To: John David Anglin; +Cc: ghazi, egcs-bugs, gcc-patches, law
Scratch the last. It isn't correct.
>
> > This causes us to maintain the warning flag list in two places, one in
> > Makefile.in and one in configure.in. A better scheme would be to use
> > "sed" to remove -Wno-long-long from WARN_CFLAGS when gcc doesn't
> > support it. (Look at LOOSE_CFLAGS in gcc/Makefile.in for an example.)
>
> The sed trick didn't work. It resulted in multiple commands nested
> in backquotes. As a compromise, I reverted to the patch enclosed.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> --- configure.in.orig Thu May 18 19:41:11 2000
> +++ configure.in Mon May 22 19:51:24 2000
> @@ -322,18 +322,32 @@
> # Find the native compiler
> AC_PROG_CC
> AC_PROG_CC_C_O
> -if test $ac_cv_prog_cc_${ac_cc}_c_o = no; then
> +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then
> NO_MINUS_C_MINUS_O=yes
> fi
> AC_SUBST(NO_MINUS_C_MINUS_O)
>
> gcc_AC_C_LONG_DOUBLE
>
> +AC_MSG_CHECKING(whether ${CC-cc} accepts -Wno-long-long)
> +echo 'void f(){}' > conftest.c
> +if test -z "`${CC-cc} -Wno-long-long -c conftest.c 2>&1`"; then
> + ac_cv_prog_cc_no_long_long=yes
> +else
> + ac_cv_prog_cc_no_long_long=no
> +fi
> +rm -f conftest*
> +echo "$ac_t"$ac_cv_prog_cc_no_long_long 1>&6
> +
> # If the native compiler is GCC, we can enable warnings even in stage1.
> # That's useful for people building cross-compilers, or just running a
> # quick `make'.
> if test "x$GCC" = "xyes"; then
> - stage1_warn_cflags='$(WARN_CFLAGS)'
> + if test $ac_cv_prog_cc_no_long_long = yes; then
> + stage1_warn_cflags='$(WARN_CFLAGS) -Wno-long-long'
> + else
> + stage1_warn_cflags='$(WARN_CFLAGS)'
> + fi
> else
> stage1_warn_cflags=""
> fi
> --- Makefile.in.orig Fri May 19 23:02:45 2000
> +++ Makefile.in Mon May 22 19:49:28 2000
> @@ -67,7 +67,8 @@
> # (And for stage 1 if the native compiler is GCC.) It is
> # separate from BOOT_CFLAGS because people tend to override optimization
> # flags and we'd like them to still have warnings turned on. They are free
> -# to explicitly turn warnings off if they wish.
> +# to explicitly turn warnings off if they wish. -Wno-long-long is added
> +# by configure to WARN_CFLAGS if the compiler used for stage1 supports it.
> # LOOSE_CFLAGS are the CFLAGS to use when compiling something which is only
> # compiled with gcc, such as libgcc and the frontends other than C.
> # XCFLAGS is used for most compilations but not when using the GCC just built.
> @@ -76,7 +77,7 @@
> TCFLAGS =
> CFLAGS = -g @stage1_warn_cflags@
> BOOT_CFLAGS = -O2 $(CFLAGS)
> -WARN_CFLAGS = -W -Wall -Wtraditional -pedantic -Wno-long-long -Wwrite-strings
> +WARN_CFLAGS = -W -Wall -Wtraditional -pedantic -Wwrite-strings
> LOOSE_CFLAGS = `echo $(CFLAGS)|sed -e 's/-pedantic//g' -e 's/-Wtraditional//g'`
> # These exists to be overridden by the x-* and t-* files, respectively.
> X_CFLAGS =
>
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
[not found] <no.id>
` (5 preceding siblings ...)
2000-05-22 17:22 ` John David Anglin
@ 2000-05-24 10:32 ` John David Anglin
2000-05-24 11:37 ` Zack Weinberg
[not found] ` <200005272138.RAA08789@hiauly1.hia.nrc.ca>
` (156 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-24 10:32 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, egcs-bugs
> cc1: Invalid option `-Wno-long-long'
> In file included from ../../gcc/cppmain.c:25:
> ../../gcc/cpplib.h:189: warning: ANSI C does not support `long long'
After several false starts, I think the following patch is a reasonable
approach to fixing the problem. The definition of the warning CFLAGS
for stage 1 and 2 is moved to configure. The configure code could be
easily modified to support more option tests if that is needed at some
point in the future.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-05-24 J. David Anglin <dave@hiauly.hia.nrc.ca>
* configure.in: Check for -Wno-long-long option support and improve
handling of warning CFLAGS for stages 1 and 2.
* Makefile.in (WARN_CFLAGS): Move definition to configure.in.
* configure: Regenerate.
--- configure.in.orig Wed May 24 12:11:28 2000
+++ configure.in Wed May 24 12:48:20 2000
@@ -329,15 +329,30 @@
gcc_AC_C_LONG_DOUBLE
+AC_MSG_CHECKING(whether ${CC-cc} accepts -Wno-long-long)
+echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -Wno-long-long -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_no_long_long=yes
+else
+ ac_cv_prog_cc_no_long_long=no
+fi
+rm -f conftest*
+echo "$ac_t"$ac_cv_prog_cc_no_long_long 1>&6
+
# If the native compiler is GCC, we can enable warnings even in stage1.
# That's useful for people building cross-compilers, or just running a
# quick `make'.
+stage1_warn_cflags=" -W -Wall -Wtraditional -pedantic -Wwrite-strings"
+stage2_warn_cflags="$stage1_warn_cflags -Wno-long-long"
if test "x$GCC" = "xyes"; then
- stage1_warn_cflags='$(WARN_CFLAGS)'
+ if test $ac_cv_prog_cc_no_long_long = yes; then
+ stage1_warn_cflags="$stage1_warn_cflags -Wno-long-long"
+ fi
else
stage1_warn_cflags=""
fi
AC_SUBST(stage1_warn_cflags)
+AC_SUBST(stage2_warn_cflags)
AC_PROG_MAKE_SET
--- Makefile.in.orig Sun May 21 14:10:51 2000
+++ Makefile.in Wed May 24 12:48:21 2000
@@ -76,7 +76,7 @@
TCFLAGS =
CFLAGS = -g @stage1_warn_cflags@
BOOT_CFLAGS = -O2 $(CFLAGS)
-WARN_CFLAGS = -W -Wall -Wtraditional -pedantic -Wno-long-long -Wwrite-strings
+WARN_CFLAGS = @stage2_warn_cflags@
LOOSE_CFLAGS = `echo $(CFLAGS)|sed -e 's/-pedantic//g' -e 's/-Wtraditional//g'`
# These exists to be overridden by the x-* and t-* files, respectively.
X_CFLAGS =
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-24 10:32 ` VAX Ultrix bootstrap failure with gcc-2.96 John David Anglin
@ 2000-05-24 11:37 ` Zack Weinberg
2000-05-24 13:08 ` John David Anglin
2000-05-24 14:09 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Zack Weinberg @ 2000-05-24 11:37 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, egcs-bugs
On Wed, May 24, 2000 at 01:25:09PM -0400, John David Anglin wrote:
> > cc1: Invalid option `-Wno-long-long'
> > In file included from ../../gcc/cppmain.c:25:
> > ../../gcc/cpplib.h:189: warning: ANSI C does not support `long long'
>
> After several false starts, I think the following patch is a reasonable
> approach to fixing the problem. The definition of the warning CFLAGS
> for stage 1 and 2 is moved to configure. The configure code could be
> easily modified to support more option tests if that is needed at some
> point in the future.
You might want to turn off -pedantic if -Wno-long-long is not
available, since you will get floods of warnings about long long
otherwise.
Could you move the definition of LOOSE_CFLAGS into configure as well?
This would reduce the number of times sed is executed during the
build.
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-24 11:37 ` Zack Weinberg
@ 2000-05-24 13:08 ` John David Anglin
2000-05-25 18:31 ` Zack Weinberg
2000-05-24 14:09 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-24 13:08 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-patches, egcs-bugs
> You might want to turn off -pedantic if -Wno-long-long is not
> available, since you will get floods of warnings about long long
> otherwise.
You get ~61 warnings. I also get a whole bunch of `$' in identifier
messages which are also annoying. I don't think -pedantic provides
a whole lot of useful information.
> Could you move the definition of LOOSE_CFLAGS into configure as well?
> This would reduce the number of times sed is executed during the
> build.
I didn't do this because -pedantic and -traditional are filtered out
even when the user overrides CFLAGS. If there is agreement that
this behaviour is not required, I will change the patch to also
provide a default for LOOSE_CFLAGS.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-24 13:08 ` John David Anglin
@ 2000-05-25 18:31 ` Zack Weinberg
2000-05-25 19:21 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Zack Weinberg @ 2000-05-25 18:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, egcs-bugs
On Wed, May 24, 2000 at 04:08:47PM -0400, John David Anglin wrote:
> > You might want to turn off -pedantic if -Wno-long-long is not
> > available, since you will get floods of warnings about long long
> > otherwise.
>
> You get ~61 warnings. I also get a whole bunch of `$' in identifier
> messages which are also annoying. I don't think -pedantic provides
> a whole lot of useful information.
It did catch some real bugs, so I'm not complaining. What are the
$ in identifier messages complaining about? It's probably another
warning that should be turned off in system headers, or something like
that.
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-25 18:31 ` Zack Weinberg
@ 2000-05-25 19:21 ` John David Anglin
2000-05-25 19:35 ` Zack Weinberg
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-25 19:21 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-patches, egcs-bugs
> It did catch some real bugs, so I'm not complaining. What are the
> $ in identifier messages complaining about? It's probably another
> warning that should be turned off in system headers, or something like
> that.
The $ in identifier messages are complaining about lines like
#if defined(__GFLOAT) || CC$gfloat
which occur in limits.h (syslimits.h) and math.h in the gcc include
directory. The identifier CC$gfloat is something the VAX ANSI C
compiler defines. Probably, this should be nuked when the includes
are fixed. It obviously isn't needed in the gcc include directory.
Another small related issue is that gcc should define __GFLOAT
in addition to GFLOAT when the -mg option is used. I have edited
my specs file to do this.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-25 19:21 ` John David Anglin
@ 2000-05-25 19:35 ` Zack Weinberg
2000-05-25 20:05 ` John David Anglin
2000-06-02 10:31 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Zack Weinberg @ 2000-05-25 19:35 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gcc-bugs
On Thu, May 25, 2000 at 10:20:54PM -0400, John David Anglin wrote:
> > It did catch some real bugs, so I'm not complaining. What are the
> > $ in identifier messages complaining about? It's probably another
> > warning that should be turned off in system headers, or something like
> > that.
>
> The $ in identifier messages are complaining about lines like
>
> #if defined(__GFLOAT) || CC$gfloat
>
> which occur in limits.h (syslimits.h) and math.h in the gcc include
> directory. The identifier CC$gfloat is something the VAX ANSI C
> compiler defines. Probably, this should be nuked when the includes
> are fixed. It obviously isn't needed in the gcc include directory.
I agree. Could you come up with an entry for inclhack.def? It will
be easier for you since you have access to the header files. I'll
guess at an appropriate pattern:
fix = {
hackname = vax_math_ifdefs;
files = limits.h;
files = math.h;
select = "^#if.*||[ \t]+CC$[a-z]+";
sed = "/^#if/s/||[ \t][ \t]*CC$[a-z][a-z]*//g";
};
This will undoubtedly need refinement to do the right thing in all cases.
> Another small related issue is that gcc should define __GFLOAT
> in addition to GFLOAT when the -mg option is used. I have edited
> my specs file to do this.
Patch for config/vax/*.h, please?
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-25 19:35 ` Zack Weinberg
@ 2000-05-25 20:05 ` John David Anglin
2000-05-25 20:33 ` Zack Weinberg
2000-06-02 10:31 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-25 20:05 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-patches, gcc-bugs
> > Another small related issue is that gcc should define __GFLOAT
> > in addition to GFLOAT when the -mg option is used. I have edited
> > my specs file to do this.
>
> Patch for config/vax/*.h, please?
See below.
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-05025 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* vax.h (CPP_SPEC): Define __GFLOAT and GFLOAT when -mg is specified.
--- vax.h.orig Sun Feb 27 20:41:06 2000
+++ vax.h Thu May 25 22:54:07 2000
@@ -26,7 +26,7 @@
/* If using g-format floating point, alter math.h. */
-#define CPP_SPEC "%{mg:-DGFLOAT}"
+#define CPP_SPEC "%{mg:-DGFLOAT -D__GFLOAT}"
/* Choose proper libraries depending on float format.
Note that there are no profiling libraries for g-format.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-25 20:05 ` John David Anglin
@ 2000-05-25 20:33 ` Zack Weinberg
0 siblings, 0 replies; 521+ messages in thread
From: Zack Weinberg @ 2000-05-25 20:33 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gcc-bugs
On Thu, May 25, 2000 at 11:05:14PM -0400, John David Anglin wrote:
> > > Another small related issue is that gcc should define __GFLOAT
> > > in addition to GFLOAT when the -mg option is used. I have edited
> > > my specs file to do this.
> >
> > Patch for config/vax/*.h, please?
>
> See below.
...
> +#define CPP_SPEC "%{mg:-DGFLOAT -D__GFLOAT}"
Thanks - I wasn't sure if this was the only place affected. It needs
an additional test to get rid of -DGFLOAT in -ansi mode:
#define CPP_SPEC "%{mg:%{!ansi:-DGFLOAT} -D__GFLOAT}"
I will apply your patch with this change.
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-25 19:35 ` Zack Weinberg
2000-05-25 20:05 ` John David Anglin
@ 2000-06-02 10:31 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-06-02 10:31 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-patches, gcc-bugs
> > The $ in identifier messages are complaining about lines like
> >
> > #if defined(__GFLOAT) || CC$gfloat
> >
> > which occur in limits.h (syslimits.h) and math.h in the gcc include
> > directory. The identifier CC$gfloat is something the VAX ANSI C
> > compiler defines. Probably, this should be nuked when the includes
> > are fixed. It obviously isn't needed in the gcc include directory.
>
> I agree. Could you come up with an entry for inclhack.def? It will
> be easier for you since you have access to the header files. I'll
> guess at an appropriate pattern:
>
> fix = {
> hackname = vax_math_ifdefs;
> files = limits.h;
> files = math.h;
> select = "^#if.*||[ \t]+CC$[a-z]+";
> sed = "/^#if/s/||[ \t][ \t]*CC$[a-z][a-z]*//g";
> };
>
> This will undoubtedly need refinement to do the right thing in all cases.
Here is a patch for the above and also a number of other include hacks
which I have found over the years. I have tried to ensure that the additions
will not conflict with headers on other systems. In some cases, it is
possible select is overly restrictive.
The VAX Ultrix version of float.h contains the identifier CC$gfloat. However,
float.h is replaced by a version generated by enquire. The enquire version
doesn't contain GFLOAT support. I will try to build a GFLOAT version
of enquire and merge the two if possible. It should be a good test of
the GFLOAT capability of gcc.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
--- sys-protos.h.orig Wed Dec 16 15:58:24 1998
+++ sys-protos.h Fri Jun 2 13:00:45 2000
@@ -445,7 +445,11 @@
extern struct group * getgrent(void);
extern struct group * getgrgid(gid_t);
extern struct group * getgrnam(const char *);
+#ifdef bsd4_2 /* ??? */
+extern int getgroups(int, int *);
+#else
extern int getgroups(int, gid_t *);
+#endif
extern struct hostent * gethostbyaddr(/* ??? */);
extern struct hostent * gethostbyname(/* ??? */);
extern struct hostent * gethostent(/* ??? */);
--- fixinc/inclhack.def.orig Fri Jun 2 10:43:12 2000
+++ fixinc/inclhack.def Fri Jun 2 13:07:36 2000
@@ -517,6 +517,65 @@
/*
+ * The VAX Ultrix 4.3 file limits.h is a symbolic link to sys/limits.h.
+ * Replace limits.h with a file that includes sys/limits.h.
+ */
+fix = {
+ hackname = AAB_ultrix_limits;
+ files = limits.h;
+ mach = "vax-*-ultrix*";
+ replace =
+'/* @(#)limits.h */
+/* This file was generated by fixincludes */
+\#ifndef _LIMITS_INCLUDED
+\#define _LIMITS_INCLUDED
+\#include <sys/limits.h>
+\#endif /* _LIMITS_INCLUDED */
+';
+};
+
+
+/*
+ * The VAX ULTRIX 4.3 version of memory.h duplicates definitions
+ * present in strings.h. Replace memory.h with a file that includes
+ * strings.h to prevent problems from multiple inclusion.
+ */
+fix = {
+ hackname = AAB_ultrix_memory;
+ files = memory.h;
+ mach = "vax-*-ultrix*";
+ replace =
+'/* @(#)memory.h */
+/* This file was generated by fixincludes */
+\#ifndef _MEMORY_INCLUDED
+\#define _MEMORY_INCLUDED
+\#include <strings.h>
+\#endif /* _MEMORY_INCLUDED */
+';
+};
+
+
+/*
+ * The VAX Ultrix 4.3 file string.h is a symbolic link to strings.h.
+ * Replace string.h link with a file that includes strings.h to prevent
+ * problems from multiple inclusion.
+ */
+fix = {
+ hackname = AAB_ultrix_string;
+ files = string.h;
+ mach = "vax-*-ultrix*";
+ replace =
+'/* @(#)string.h */
+/* This file was generated by fixincludes */
+\#ifndef _STRING_INCLUDED
+\#define _STRING_INCLUDED
+\#include <strings.h>
+\#endif /* _STRING_INCLUDED */
+';
+};
+
+
+/*
* sys/wait.h on AIX 3.2.5 puts the declaration of wait3 before the
* definition of struct rusage, so the prototype added by fixproto fails.
*/
@@ -1495,7 +1554,9 @@
fix = {
hackname = nested_ultrix;
files = rpc/svc.h;
+ files = sys/ioctl.h;
sed = "s@^\\( \\*\tint protocol; \\)/\\*@\\1*/ /*@";
+ sed = "/^\\/\\* #define SIOCSCREEN/s@/\\* screend@*//* screend@";
};
@@ -2695,6 +2756,24 @@
/*
+ * Add missing prototype for lstat and define for S_ISLNK
+ * in Ultrix V4.3 sys/stat.h.
+ */
+fix = {
+ hackname = ultrix_stat;
+ files = sys/stat.h;
+ select = "@\\(#\\)stat\\.h.*6\\.1.*\\(ULTRIX\\)";
+ sed = "/^#define[ \t]S_IFPORT[ \t]*S_IFIFO$/a\\\n"
+ "\\\n"
+ "/* macro to test for symbolic link */\\\n"
+ "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\\\n"
+ "\n";
+ sed = "/^[ \t]*fstat(),$/a\\\n"
+ "\tlstat(),\n";
+};
+
+
+/*
* Check for superfluous `static' (in Ultrix 4.2)
* On Ultrix 4.3, includes of other files (r3_cpu.h,r4_cpu.h) is broken.
*/
@@ -2709,6 +2788,21 @@
/*
+ * Add once-only latch to Ultrix V4.3 strings.h.
+ */
+fix = {
+ hackname = ultrix_strings;
+ files = strings.h;
+ select = "@\\(#\\)strings\\.h.*6\\.1.*\\(ULTRIX\\)";
+ sed = "/^#ifndef[ \t]_SIZE_T_$/i\\\n"
+ "#ifndef _STRINGS_INCLUDED\\\n"
+ "#define _STRINGS_INCLUDED\n";
+ sed = "/^#endif.*__STDC__.*\\/$/a\\\n"
+ "#endif /* _STRINGS_INCLUDED */\n";
+};
+
+
+/*
* Fix multiple defines for NULL. Sometimes, we stumble into \r\n
* terminated lines, so accommodate these. Test both ways.
*/
@@ -2791,6 +2885,19 @@
};
+/*
+ * Strip "|| CC$gfloat" from VAX Ultrix math headers.
+ */
+fix = {
+ hackname = vax_ultrix_math_ifdef;
+ files = float.h;
+ files = math.h;
+ files = sys/limits.h;
+ select = "^#if.*\\|\\|[ \t]+CC\\$[a-z]+";
+ sed = "/^#if/s/||[ \t][ \t]*CC$[a-z][a-z]*//";
+};
+
+
/*
* Make VxWorks header which is almost gcc ready fully gcc ready.
*/
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-24 11:37 ` Zack Weinberg
2000-05-24 13:08 ` John David Anglin
@ 2000-05-24 14:09 ` John David Anglin
2000-05-24 18:50 ` Jeffrey A Law
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-05-24 14:09 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-patches, gcc-bugs
> You might want to turn off -pedantic if -Wno-long-long is not
> available, since you will get floods of warnings about long long
> otherwise.
Patch revised to only use -pedantic during stage 1 if the -Wno-long-long
option is supported.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-05-24 J. David Anglin <dave@hiauly.hia.nrc.ca>
* configure.in: Check for -Wno-long-long option support and improve
handling of warning CFLAGS for stages 1 and 2.
* Makefile.in (WARN_CFLAGS): Move definition to configure.in.
* configure: Regenerate.
--- configure.in.orig Wed May 24 12:11:28 2000
+++ configure.in Wed May 24 16:59:05 2000
@@ -329,15 +329,30 @@
gcc_AC_C_LONG_DOUBLE
+AC_MSG_CHECKING(whether ${CC-cc} accepts -Wno-long-long)
+echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -Wno-long-long -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_no_long_long=yes
+else
+ ac_cv_prog_cc_no_long_long=no
+fi
+rm -f conftest*
+echo "$ac_t"$ac_cv_prog_cc_no_long_long 1>&6
+
# If the native compiler is GCC, we can enable warnings even in stage1.
# That's useful for people building cross-compilers, or just running a
# quick `make'.
+stage1_warn_cflags=" -W -Wall -Wtraditional -Wwrite-strings"
+stage2_warn_cflags="$stage1_warn_cflags -pedantic -Wno-long-long"
if test "x$GCC" = "xyes"; then
- stage1_warn_cflags='$(WARN_CFLAGS)'
+ if test $ac_cv_prog_cc_no_long_long = yes; then
+ stage1_warn_cflags="$stage1_warn_cflags -pedantic -Wno-long-long"
+ fi
else
stage1_warn_cflags=""
fi
AC_SUBST(stage1_warn_cflags)
+AC_SUBST(stage2_warn_cflags)
AC_PROG_MAKE_SET
--- Makefile.in.orig Sun May 21 14:10:51 2000
+++ Makefile.in Wed May 24 12:48:21 2000
@@ -76,7 +76,7 @@
TCFLAGS =
CFLAGS = -g @stage1_warn_cflags@
BOOT_CFLAGS = -O2 $(CFLAGS)
-WARN_CFLAGS = -W -Wall -Wtraditional -pedantic -Wno-long-long -Wwrite-strings
+WARN_CFLAGS = @stage2_warn_cflags@
LOOSE_CFLAGS = `echo $(CFLAGS)|sed -e 's/-pedantic//g' -e 's/-Wtraditional//g'`
# These exists to be overridden by the x-* and t-* files, respectively.
X_CFLAGS =
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
2000-05-24 14:09 ` John David Anglin
@ 2000-05-24 18:50 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-05-24 18:50 UTC (permalink / raw)
To: John David Anglin; +Cc: Zack Weinberg, gcc-patches, gcc-bugs
In message < 200005242109.RAA11597@hiauly1.hia.nrc.ca >you write:
> > You might want to turn off -pedantic if -Wno-long-long is not
> > available, since you will get floods of warnings about long long
> > otherwise.
>
> Patch revised to only use -pedantic during stage 1 if the -Wno-long-long
> option is supported.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2000-05-24 J. David Anglin <dave@hiauly.hia.nrc.ca>
>
> * configure.in: Check for -Wno-long-long option support and improve
> handling of warning CFLAGS for stages 1 and 2.
> * Makefile.in (WARN_CFLAGS): Move definition to configure.in.
> * configure: Regenerate.
Thanks. Installed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
[parent not found: <200005272138.RAA08789@hiauly1.hia.nrc.ca>]
* Re: VAX Ultrix bootstrap with gcc-2.96 20000519: genrecog failure
[not found] ` <200005272138.RAA08789@hiauly1.hia.nrc.ca>
@ 2000-05-27 20:19 ` Richard Henderson
2000-05-28 11:00 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2000-05-27 20:19 UTC (permalink / raw)
To: John David Anglin; +Cc: zack, gcc-bugs, gcc-patches
On Sat, May 27, 2000 at 05:38:48PM -0400, John David Anglin wrote:
> In looking at function.c (expand_function_end), I can't see how struct
> returns every worked in this situation:
The code in this area has changed quite a bit over the past year.
It's possible that it didn't work before the changes, or that it
worked by accident, or that I really did mess up.
> The movq is generated by line 6673 of function.c. However, doesn't
> something need to be done to get it into current_function_return_rtx?
I don't think it's supposed to. Looking at where that value gets
loaded up, it appears that diddle_return_value isn't handling this
case correctly.
I've given i386 and sparc64 output (to pick two other styles of struct
return at random) a quick glance, and nothing appears to be broken by
this change; I'll wait for a complete bootstrap and test cycle to be sure.
r~
* function.c (diddle_return_value): A pcc-style struct return
returns a pointer.
Index: function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.199
diff -c -p -d -r1.199 function.c
*** function.c 2000/05/27 20:10:38 1.199
--- function.c 2000/05/28 02:50:35
*************** diddle_return_value (doit, arg)
*** 6319,6332 ****
void *arg;
{
rtx outgoing = current_function_return_rtx;
if (! outgoing)
return;
! if (GET_CODE (outgoing) == REG
! && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
{
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
#ifdef FUNCTION_OUTGOING_VALUE
outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
#else
--- 6319,6343 ----
void *arg;
{
rtx outgoing = current_function_return_rtx;
+ int pcc;
if (! outgoing)
return;
! pcc = (current_function_returns_struct
! || current_function_returns_pcc_struct);
!
! if ((GET_CODE (outgoing) == REG
! && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
! || pcc)
{
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+
+ /* A PCC-style return returns a pointer to the memory in which
+ the structure is stored. */
+ if (pcc)
+ type = build_pointer_type (type);
+
#ifdef FUNCTION_OUTGOING_VALUE
outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
#else
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap with gcc-2.96 20000519: genrecog failure
2000-05-27 20:19 ` VAX Ultrix bootstrap with gcc-2.96 20000519: genrecog failure Richard Henderson
@ 2000-05-28 11:00 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-05-28 11:00 UTC (permalink / raw)
To: Richard Henderson; +Cc: zack, gcc-bugs, gcc-patches
The patch fixed the missing return value in my test program. Hopefully,
it will allow the build to complete.
Thanks,
Dave
>
> On Sat, May 27, 2000 at 05:38:48PM -0400, John David Anglin wrote:
> > In looking at function.c (expand_function_end), I can't see how struct
> > returns every worked in this situation:
>
> The code in this area has changed quite a bit over the past year.
> It's possible that it didn't work before the changes, or that it
> worked by accident, or that I really did mess up.
>
> > The movq is generated by line 6673 of function.c. However, doesn't
> > something need to be done to get it into current_function_return_rtx?
>
> I don't think it's supposed to. Looking at where that value gets
> loaded up, it appears that diddle_return_value isn't handling this
> case correctly.
>
> I've given i386 and sparc64 output (to pick two other styles of struct
> return at random) a quick glance, and nothing appears to be broken by
> this change; I'll wait for a complete bootstrap and test cycle to be sure.
>
>
> r~
>
>
> * function.c (diddle_return_value): A pcc-style struct return
> returns a pointer.
>
> Index: function.c
> ===================================================================
> RCS file: /cvs/gcc/egcs/gcc/function.c,v
> retrieving revision 1.199
> diff -c -p -d -r1.199 function.c
> *** function.c 2000/05/27 20:10:38 1.199
> --- function.c 2000/05/28 02:50:35
> *************** diddle_return_value (doit, arg)
> *** 6319,6332 ****
> void *arg;
> {
> rtx outgoing = current_function_return_rtx;
>
> if (! outgoing)
> return;
>
> ! if (GET_CODE (outgoing) == REG
> ! && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
> {
> tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
> #ifdef FUNCTION_OUTGOING_VALUE
> outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
> #else
> --- 6319,6343 ----
> void *arg;
> {
> rtx outgoing = current_function_return_rtx;
> + int pcc;
>
> if (! outgoing)
> return;
>
> ! pcc = (current_function_returns_struct
> ! || current_function_returns_pcc_struct);
> !
> ! if ((GET_CODE (outgoing) == REG
> ! && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
> ! || pcc)
> {
> tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
> +
> + /* A PCC-style return returns a pointer to the memory in which
> + the structure is stored. */
> + if (pcc)
> + type = build_pointer_type (type);
> +
> #ifdef FUNCTION_OUTGOING_VALUE
> outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
> #else
>
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
[not found] <no.id>
` (7 preceding siblings ...)
[not found] ` <200005272138.RAA08789@hiauly1.hia.nrc.ca>
@ 2000-06-02 12:15 ` John David Anglin
2000-06-02 13:09 ` John David Anglin
2000-06-12 8:18 ` Evaluation order of &&s in ||, in macro INDEX_TERM_P, in vax.h John David Anglin
` (154 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-06-02 12:15 UTC (permalink / raw)
To: John David Anglin; +Cc: zack, gcc-patches, gcc-bugs
> The VAX Ultrix version of float.h contains the identifier CC$gfloat. However,
> float.h is replaced by a version generated by enquire. The enquire version
> doesn't contain GFLOAT support. I will try to build a GFLOAT version
> of enquire and merge the two if possible. It should be a good test of
> the GFLOAT capability of gcc.
"-mg" didn't work. It looks like the format of the TARGET_SWITCHES
macro needs updating in vax.h. This is the current definition:
#define TARGET_SWITCHES \
{ {"unix", 1}, \
{"gnu", -1}, \
{"vaxc-alignment", 2}, \
{"g", 4}, \
{"g-float", 4}, \
{"d", -4}, \
{"d-float", -4}, \
{ "", TARGET_DEFAULT}}
Other machines have a third comment field for each switch.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Evaluation order of &&s in ||, in macro INDEX_TERM_P, in vax.h
[not found] <no.id>
` (8 preceding siblings ...)
2000-06-02 12:15 ` VAX Ultrix bootstrap failure with gcc-2.96 John David Anglin
@ 2000-06-12 8:18 ` John David Anglin
2000-06-13 8:55 ` Jeffrey A Law
2000-06-20 9:55 ` VAX Ultrix bootstrap failure with gcc-2.96 John David Anglin
` (153 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-06-12 8:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The following patch to vax.h squashes a few warnings about &&s in ||,
> and might slightly improve the code generated by the INDEX_TERM_P macro.
Revised the patch to squelch signed/unsigned warnings from comparision.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-06-12 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* vax.h (INDEX_TERM_P): Define evaluation order of &&'s in || and
cast to squelch signed/unsigned warnings.
--- vax.h.orig Fri May 26 13:10:48 2000
+++ vax.h Mon Jun 12 11:10:46 2000
@@ -731,15 +731,15 @@
: (GET_CODE (PROD) == MULT \
&& \
(xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \
- ((GET_CODE (xfoo0) == CONST_INT \
- && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \
- && GET_CODE (xfoo1) == REG \
- && REG_OK_FOR_INDEX_P (xfoo1)) \
- || \
- (GET_CODE (xfoo1) == CONST_INT \
- && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \
- && GET_CODE (xfoo0) == REG \
- && REG_OK_FOR_INDEX_P (xfoo0))))))
+ ((((GET_CODE (xfoo0) == CONST_INT \
+ && GET_CODE (xfoo1) == REG) \
+ && INTVAL (xfoo0) == (int)GET_MODE_SIZE (MODE)) \
+ && REG_OK_FOR_INDEX_P (xfoo1)) \
+ || \
+ (((GET_CODE (xfoo1) == CONST_INT \
+ && GET_CODE (xfoo0) == REG) \
+ && INTVAL (xfoo1) == (int)GET_MODE_SIZE (MODE)) \
+ && REG_OK_FOR_INDEX_P (xfoo0))))))
/* Go to ADDR if X is the sum of a register
and a valid index term for mode MODE. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Evaluation order of &&s in ||, in macro INDEX_TERM_P, in vax.h
2000-06-12 8:18 ` Evaluation order of &&s in ||, in macro INDEX_TERM_P, in vax.h John David Anglin
@ 2000-06-13 8:55 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-06-13 8:55 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message < 200006121518.LAA09064@hiauly1.hia.nrc.ca >you write:
> > The following patch to vax.h squashes a few warnings about &&s in ||,
> > and might slightly improve the code generated by the INDEX_TERM_P macro.
>
> Revised the patch to squelch signed/unsigned warnings from comparision.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2000-06-12 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * vax.h (INDEX_TERM_P): Define evaluation order of &&'s in || and
> cast to squelch signed/unsigned warnings.
Thanks. Installed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: VAX Ultrix bootstrap failure with gcc-2.96
[not found] <no.id>
` (9 preceding siblings ...)
2000-06-12 8:18 ` Evaluation order of &&s in ||, in macro INDEX_TERM_P, in vax.h John David Anglin
@ 2000-06-20 9:55 ` John David Anglin
2000-06-20 11:13 ` Bruce Korb
2000-06-29 9:50 ` collect2: ld terminated with signal 10 [Bus error] John David Anglin
` (152 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-06-20 9:55 UTC (permalink / raw)
To: John David Anglin; +Cc: ghazi, bkorb, gcc-patches
I have run a complete bootstrap cycle with this patch under hpux 10.20.
Please review for installation.
Dave
>
> > Yes, I understand the namespace pollution issue. I think the solution
> > that Dave is working on will not leave GETGROUPS_T in unistd.h, but I
> > have yet to actually see it. :-)
>
> Here is the patch for review.
>
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2000-06-16 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * Makefile.in (TARGET_GETGROUPS_T): New configuration variable.
> * configure.in (TARGET_GETGROUPS_T): Evaluate.
> * sys-protos.h (getgroups): Use TARGET_GETGROUPS_T for array type
> of second argument of getgroups.
> * configure, config.in: Rebuilt.
>
> --- Makefile.in.orig Thu Jun 15 19:15:07 2000
> +++ Makefile.in Thu Jun 15 19:26:43 2000
> @@ -130,6 +130,9 @@
> [ -f $(RANLIB) ] \
> || [ -f /usr/bin/ranlib -o -f /bin/ranlib ]
>
> +# Substitution type for target's getgroups 2nd arg.
> +TARGET_GETGROUPS_T = @TARGET_GETGROUPS_T@
> +
> # Compiler to use for compiling libgcc1.a.
> # OLDCC should not be the GNU C compiler,
> # since that would compile typical libgcc1.a functions such as mulsi3
> @@ -1839,7 +1842,8 @@
> SYSCALLS.c.X: $(srcdir)/sys-types.h $(srcdir)/sys-protos.h $(GCC_PASSES) \
> stmp-int-hdrs
> -rm -f SYSCALLS.c tmp-SYSCALLS.s
> - cat $(srcdir)/sys-types.h $(srcdir)/sys-protos.h > SYSCALLS.c
> + sed -e s/TARGET_GETGROUPS_T/$(TARGET_GETGROUPS_T)/ \
> + $(srcdir)/sys-types.h $(srcdir)/sys-protos.h > SYSCALLS.c
> $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
> -aux-info $@ -S -o tmp-SYSCALLS.s SYSCALLS.c
> -rm -f SYSCALLS.c tmp-SYSCALLS.s
> @@ -1996,7 +2000,8 @@
> $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/scan.c
>
> xsys-protos.h: $(GCC_PASSES) $(srcdir)/sys-protos.h deduced.h gen-protos Makefile
> - cat deduced.h $(srcdir)/sys-protos.h > tmp-fixtmp.c
> + sed -e s/TARGET_GETGROUPS_T/$(TARGET_GETGROUPS_T)/ \
> + deduced.h $(srcdir)/sys-protos.h > tmp-fixtmp.c
> mv tmp-fixtmp.c fixtmp.c
> $(GCC_FOR_TARGET) fixtmp.c -w -U__SIZE_TYPE__ -U__PTRDIFF_TYPE__ -U__WCHAR_TYPE__ -E \
> | sed -e 's/ / /g' -e 's/ *(/ (/g' -e 's/ [ ]*/ /g' -e 's/( )/()/' \
> --- configure.in.orig Thu Jun 15 18:24:15 2000
> +++ configure.in Thu Jun 15 21:06:05 2000
> @@ -480,6 +480,26 @@
>
> AC_CHECK_TYPE(ssize_t, int)
>
> +# Try to determine the array type of the second argument of getgroups
> +# for the target system (int or gid_t).
> +AC_TYPE_GETGROUPS
> +if test "${target}" = "${build}"; then
> + TARGET_GETGROUPS_T=$ac_cv_type_getgroups
> +else
> + case "${target}" in
> + # This condition may need some tweaking. It should include all
> + # targets where the array type of the second argument of getgroups
> + # is int and the type of gid_t is not equivalent to int.
> + *-*-sunos* | *-*-ultrix*)
> + TARGET_GETGROUPS_T=int
> + ;;
> + *)
> + TARGET_GETGROUPS_T=gid_t
> + ;;
> + esac
> +fi
> +AC_SUBST(TARGET_GETGROUPS_T)
> +
> gcc_AC_FUNC_VFPRINTF_DOPRNT
> gcc_AC_FUNC_PRINTF_PTR
>
> --- sys-protos.h.orig Thu Jun 15 00:01:55 2000
> +++ sys-protos.h Thu Jun 15 19:43:49 2000
> @@ -445,7 +445,7 @@
> extern struct group * getgrent(void);
> extern struct group * getgrgid(gid_t);
> extern struct group * getgrnam(const char *);
> -extern int getgroups(int, gid_t *);
> +extern int getgroups(int, TARGET_GETGROUPS_T []);
> extern struct hostent * gethostbyaddr(/* ??? */);
> extern struct hostent * gethostbyname(/* ??? */);
> extern struct hostent * gethostent(/* ??? */);
>
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: collect2: ld terminated with signal 10 [Bus error]
[not found] <no.id>
` (10 preceding siblings ...)
2000-06-20 9:55 ` VAX Ultrix bootstrap failure with gcc-2.96 John David Anglin
@ 2000-06-29 9:50 ` John David Anglin
2000-06-30 11:13 ` Jeffrey A Law
2000-08-30 18:03 ` Patches: Re: libio testsuite: timeout compiling tFile.cc John David Anglin
` (151 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-06-29 9:50 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
>
> With todays CVS and binutils 2.10.90, the following occurs executing the
> libio hounddog.exp under hppa1.1-hp-hpux10.20:
>
> Running ../../../../libio/testsuite/libio.tests/hounddog.exp ...
> Executing on host: /xxx/gnu/gcc-2.96/objdir/gcc/xgcc -B/xxx/gnu/gcc-2.96/objdir/gcc/ ../../../../libio/testsuite/../tests/hounddog.cc -O3 -I.. -I../../../../libio/testsuite/.. -nostdinc++ -I/xxx/gnu/gcc-2.96/libstdc++ -I/xxx/gnu/gcc-2.96/libstdc++/stl -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/threads/libstdc++ -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/threads/libiberty -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/threads/libiberty -g -lstdc++ -liberty -lm -threads -o /xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/libio/testsuite/hounddog (timeout = 300)
> <command line>: warning: The C standard requires whitespace after #define __STDC_EXT__
> collect2: ld terminated with signal 10 [Bus error]
> /usr/ccs/bin/ld: Unsatisfied symbols:
> bad_typeid virtual table(data)
Here is a patch to fix the problem related the above unsatisfied symbol.
Under hpux, weak (sdef) data symbols need to be .EXPORT'd or else they
are local. The code in varasm.c implicitly assumes that weak symbols
are global.
With this patch, weak symbol support now works under hpux 10.20. Yeah!
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-06-27 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* pa/som.h (ASM_WEAKEN_LABEL): Export weak data symbols so that they
have global scope.
--- som.h.orig Tue Jun 27 12:57:31 2000
+++ som.h Tue Jun 27 13:14:04 2000
@@ -384,6 +384,14 @@
/* This is how we tell the assembler that a symbol is weak. */
#define ASM_WEAKEN_LABEL(FILE,NAME) \
- do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
- fputc ('\n', FILE); } while (0)
+ do { fputs ("\t.weak\t", FILE); \
+ assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); \
+ if (! FUNCTION_NAME_P (NAME)) \
+ { \
+ fputs ("\t.EXPORT ", FILE); \
+ assemble_name (FILE, NAME); \
+ fputs (",DATA\n", FILE); \
+ } \
+ } while (0)
#endif
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: collect2: ld terminated with signal 10 [Bus error]
2000-06-29 9:50 ` collect2: ld terminated with signal 10 [Bus error] John David Anglin
@ 2000-06-30 11:13 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-06-30 11:13 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
In message < 200006291650.MAA20413@hiauly1.hia.nrc.ca >you write:
> >
> > With todays CVS and binutils 2.10.90, the following occurs executing the
> > libio hounddog.exp under hppa1.1-hp-hpux10.20:
> >
> > Running ../../../../libio/testsuite/libio.tests/hounddog.exp ...
> > Executing on host: /xxx/gnu/gcc-2.96/objdir/gcc/xgcc -B/xxx/gnu/gcc-2.96/
> objdir/gcc/ ../../../../libio/testsuite/../tests/hounddog.cc -O3 -I.. -I..
> /../../../libio/testsuite/.. -nostdinc++ -I/xxx/gnu/gcc-2.96/libstdc++ -I/
> xxx/gnu/gcc-2.96/libstdc++/stl -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10
> .20/threads/libstdc++ -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/threa
> ds/libiberty -L/xxx/gnu/gcc-2.96/objdir/hppa1.1-hp-hpux10.20/threads/libib
> erty -g -lstdc++ -liberty -lm -threads -o /xxx/gnu/gcc-2.96/objdir/hppa1.1
> -hp-hpux10.20/libio/testsuite/hounddog (timeout = 300)
> > <command line>: warning: The C standard requires whitespace after #define
> __STDC_EXT__
> > collect2: ld terminated with signal 10 [Bus error]
> > /usr/ccs/bin/ld: Unsatisfied symbols:
> > bad_typeid virtual table(data)
>
> Here is a patch to fix the problem related the above unsatisfied symbol.
> Under hpux, weak (sdef) data symbols need to be .EXPORT'd or else they
> are local. The code in varasm.c implicitly assumes that weak symbols
> are global.
>
> With this patch, weak symbol support now works under hpux 10.20. Yeah!
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2000-06-27 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa/som.h (ASM_WEAKEN_LABEL): Export weak data symbols so that they
> have global scope.
Thanks. Installed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Patches: Re: libio testsuite: timeout compiling tFile.cc
[not found] <no.id>
` (11 preceding siblings ...)
2000-06-29 9:50 ` collect2: ld terminated with signal 10 [Bus error] John David Anglin
@ 2000-08-30 18:03 ` John David Anglin
2000-09-01 13:29 ` Patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS 20000816 John David Anglin
` (150 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-08-30 18:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
Here are patches that allow the libio testsuite to run successfully under
hpux 10.20 on a slow machine. Please review.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-08-30 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* lib/libio.exp: Don't inline functions to allow libio tests to work
in a reasonable time on machines that are slow or have small memories.
--- lib/libio.exp.orig Wed Jun 23 08:10:00 1999
+++ lib/libio.exp Wed Aug 30 19:55:23 2000
@@ -57,7 +57,7 @@
set args ""
set ld_library_path ""
- lappend args "additional_flags=-O3";
+ lappend args "additional_flags=-O3 -fno-inline";
lappend args "additional_flags=-I.. -I$srcdir/.."
lappend args "additional_flags=$wrap_compile_flags";
lappend args "libs=$wrapper_file";
2000-08-30 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* tfformat.c: Don't include stdlib.h for exit if TEST_LIBIO or
__cplusplus are defined.
--- tfformat.c.orig Tue May 23 17:33:18 2000
+++ tfformat.c Wed Aug 30 20:23:16 2000
@@ -1,15 +1,18 @@
#ifdef TEST_LIBIO
#include <iostdio.h>
+extern void exit ();
#else
#ifdef __cplusplus
#include <strstream.h>
+extern "C" {
+ extern void exit (int);
+}
#else
#include <stdio.h>
+#include <stdlib.h> /* for exit */
#endif
#endif /* !TEST_LIBIO */
-#include <stdlib.h> /* for exit */
-
/* Tests taken from Cygnus C library. */
typedef struct
^ permalink raw reply [flat|nested] 521+ messages in thread
* Patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS 20000816
[not found] <no.id>
` (12 preceding siblings ...)
2000-08-30 18:03 ` Patches: Re: libio testsuite: timeout compiling tFile.cc John David Anglin
@ 2000-09-01 13:29 ` John David Anglin
2000-09-01 22:22 ` Ovidiu Predescu
2000-09-08 10:29 ` Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code) John David Anglin
` (149 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-01 13:29 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> === objc Summary for unix/-threads ===
>
> # of expected passes 22
> # of unexpected failures 22
The enclosed patch corrects the problem. There are now no objc failures
under hpux 10.20. The patch code is similar to that used for posix
threads.
The file libobjc/thr-dce.c contains a similar set of functions as gthr-dce.h.
The code therein incorrectly passes `&(mutex->backend)'. I didn't fix
thr-dce.c since it doesn't appear to be used anymore.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-08-31 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* gthr-dce.h (__gthread_objc_mutex_allocate): Create a pthread_mutex_t
object before calling pthread_mutex_init.
--- gthr-dce.h.orig Fri Aug 4 13:25:19 2000
+++ gthr-dce.h Thu Aug 31 14:10:37 2000
@@ -274,10 +274,18 @@
static inline int
__gthread_objc_mutex_allocate(objc_mutex_t mutex)
{
- if (__gthread_active_p ()
- && pthread_mutex_init((pthread_mutex_t *)mutex->backend,
+ if (__gthread_active_p ())
+ {
+ mutex->backend = objc_malloc(sizeof(pthread_mutex_t));
+
+ if (pthread_mutex_init((pthread_mutex_t *)mutex->backend,
pthread_mutexattr_default))
- return -1;
+ {
+ objc_free(mutex->backend);
+ mutex->backend = NULL;
+ return -1;
+ }
+ }
return 0;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS 20000816
2000-09-01 13:29 ` Patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS 20000816 John David Anglin
@ 2000-09-01 22:22 ` Ovidiu Predescu
2000-09-05 11:25 ` Another patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Ovidiu Predescu @ 2000-09-01 22:22 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
Thanks, I applied it!
Regards,
Ovidiu
--
Ovidiu Predescu <ovidiu@cup.hp.com>
http://orion.nsr.hp.com/ (inside HP's firewall only)
http://www.geocities.com/SiliconValley/Monitor/7464/
On Fri, 1 Sep 2000 16:29:22 -0400 (EDT), "John David Anglin"
<dave@hiauly1.hia.nrc.ca> wrote:
> > === objc Summary for unix/-threads ===
> >
> > # of expected passes 22
> > # of unexpected failures 22
>
> The enclosed patch corrects the problem. There are now no objc failures
> under hpux 10.20. The patch code is similar to that used for posix
> threads.
>
> The file libobjc/thr-dce.c contains a similar set of functions as gthr-dce.h.
> The code therein incorrectly passes `&(mutex->backend)'. I didn't fix
> thr-dce.c since it doesn't appear to be used anymore.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2000-08-31 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * gthr-dce.h (__gthread_objc_mutex_allocate): Create a pthread_mutex_t
> object before calling pthread_mutex_init.
>
> --- gthr-dce.h.orig Fri Aug 4 13:25:19 2000
> +++ gthr-dce.h Thu Aug 31 14:10:37 2000
> @@ -274,10 +274,18 @@
> static inline int
> __gthread_objc_mutex_allocate(objc_mutex_t mutex)
> {
> - if (__gthread_active_p ()
> - && pthread_mutex_init((pthread_mutex_t *)mutex->backend,
> + if (__gthread_active_p ())
> + {
> + mutex->backend = objc_malloc(sizeof(pthread_mutex_t));
> +
> + if (pthread_mutex_init((pthread_mutex_t *)mutex->backend,
> pthread_mutexattr_default))
> - return -1;
> + {
> + objc_free(mutex->backend);
> + mutex->backend = NULL;
> + return -1;
> + }
> + }
>
> return 0;
> }
>
--
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.2 (GNU/Linux)
Comment: Exmh version 2.2 06/23/2000
iD8DBQE5sI5k1cM8Hy0YC5kRAu5RAJ9Xj8+qMBYtjj6CNNVYt0hzmCmuyACfc1rZ
VpfOHd+uUpamKcm0g4ALdeI=
=z0QG
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 521+ messages in thread
* Another patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS
2000-09-01 22:22 ` Ovidiu Predescu
@ 2000-09-05 11:25 ` John David Anglin
2000-09-06 0:01 ` Ovidiu Predescu
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-05 11:25 UTC (permalink / raw)
To: Ovidiu Predescu; +Cc: gcc-bugs, gcc-patches
This is the complement to the previous patch. Tested with bootstrap
and check.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-09-02 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* gthr-dce.h (__gthread_objc_mutex_deallocate): Free mutex->backend.
--- gthr-dce.h.orig Fri Sep 1 19:17:41 2000
+++ gthr-dce.h Sat Sep 2 14:37:18 2000
@@ -294,9 +294,14 @@
static inline int
__gthread_objc_mutex_deallocate(objc_mutex_t mutex)
{
- if (__gthread_active_p ()
- && pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
- return -1;
+ if (__gthread_active_p ())
+ {
+ if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
+ return -1;
+
+ objc_free(mutex->backend);
+ mutex->backend = NULL;
+ }
return 0;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Another patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS
2000-09-05 11:25 ` Another patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS John David Anglin
@ 2000-09-06 0:01 ` Ovidiu Predescu
0 siblings, 0 replies; 521+ messages in thread
From: Ovidiu Predescu @ 2000-09-06 0:01 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
Thanks, I applied it.
Ovidiu
On Tue, 5 Sep 2000 14:21:18 -0400 (EDT), "John David Anglin"
<dave@hiauly1.hia.nrc.ca> wrote:
> This is the complement to the previous patch. Tested with bootstrap
> and check.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2000-09-02 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * gthr-dce.h (__gthread_objc_mutex_deallocate): Free mutex->backend.
>
> --- gthr-dce.h.orig Fri Sep 1 19:17:41 2000
> +++ gthr-dce.h Sat Sep 2 14:37:18 2000
> @@ -294,9 +294,14 @@
> static inline int
> __gthread_objc_mutex_deallocate(objc_mutex_t mutex)
> {
> - if (__gthread_active_p ()
> - && pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
> - return -1;
> + if (__gthread_active_p ())
> + {
> + if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
> + return -1;
> +
> + objc_free(mutex->backend);
> + mutex->backend = NULL;
> + }
>
> return 0;
> }
>
--
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.2 (GNU/Linux)
Comment: Exmh version 2.2 06/23/2000
iD8DBQE5tetU1cM8Hy0YC5kRArO+AKCj68G4yhGrbZ1nVyCzY9HZGiiMiACgnE7p
XKeE7VP9Aw8Ny3VpjnX3WFk=
=+soU
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code)
[not found] <no.id>
` (13 preceding siblings ...)
2000-09-01 13:29 ` Patch: Re: objc FAILs under hpux/-threads with gcc-2.96 CVS 20000816 John David Anglin
@ 2000-09-08 10:29 ` John David Anglin
2000-09-08 10:38 ` Zack Weinberg
2000-09-08 17:15 ` Segmentation fault building libg++ without named returns John David Anglin
` (148 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-08 10:29 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> With todays cvs source, the following build error occured under hpux 10.20:
>
> ../stage1/xgcc -B../stage1/ -B/usr/local/hppa1.1-hp-hpux10.20/bin/ -DIN_GCC -g -O3 -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -W -Wall -o ../cc1plus \
> call.o decl.o errfn.o expr.o pt.o typeck2.o class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o except.o friend.o init.o method.o search.o semantics.o tree.o xref.o repo.o dump.o optimize.o mangle.o ../c-common.o ../c-pragma.o ../c-semantics.o ../c-lex.o ../toplev.o ../libbackend.a ../intl/libintl.a ../../libiberty/libiberty.a
> /usr/ccs/bin/ld: Unsatisfied symbols:
> cpp_register_pragma (code)
> cpp_register_pragma_space (code)
Here is an untested patch for review.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-09-08 J. David Anglin <dave@hiauly1.hia.nrc.ca>
lex.c (init_cp_pragma): Don't call cpp_register_pragma or
cpp_register_pragma_space if HANDLE_GENERIC_PRAGMAS is not defined.
--- lex.c.orig Thu Sep 7 12:43:48 2000
+++ lex.c Fri Sep 8 13:17:57 2000
@@ -681,6 +681,7 @@
static void
init_cp_pragma ()
{
+#ifdef HANDLE_GENERIC_PRAGMAS
#if USE_CPPLIB
#define pfile &parse_in
#else
@@ -697,6 +698,7 @@
cpp_register_pragma (pfile, "GCC", "interface", handle_pragma_interface);
cpp_register_pragma (pfile, "GCC", "implementation",
handle_pragma_implementation);
+#endif /* HANDLE_GENERIC_PRAGMAS */
}
const char *
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code)
2000-09-08 10:29 ` Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code) John David Anglin
@ 2000-09-08 10:38 ` Zack Weinberg
2000-09-08 10:43 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Zack Weinberg @ 2000-09-08 10:38 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
On Fri, Sep 08, 2000 at 01:29:13PM -0400, John David Anglin wrote:
...
> 2000-09-08 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> lex.c (init_cp_pragma): Don't call cpp_register_pragma or
> cpp_register_pragma_space if HANDLE_GENERIC_PRAGMAS is not defined.
This is not right. #pragma [GCC] interface and implementation need to
work irrespective of the value of HANDLE_GENERIC_PRAGMAS. The right
fix is to adjust c-pragma.c so that the registry and dispatch routines
don't depend on HANDLE_GENERIC_PRAGMAS, and c-lex.c so that the
dispatch routine does get called. I'll try to generate a patch.
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code)
2000-09-08 10:38 ` Zack Weinberg
@ 2000-09-08 10:43 ` John David Anglin
2000-09-08 11:02 ` Zack Weinberg
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-08 10:43 UTC (permalink / raw)
To: Zack Weinberg; +Cc: gcc-bugs, gcc-patches
> > 2000-09-08 J. David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > lex.c (init_cp_pragma): Don't call cpp_register_pragma or
> > cpp_register_pragma_space if HANDLE_GENERIC_PRAGMAS is not defined.
>
> This is not right. #pragma [GCC] interface and implementation need to
> work irrespective of the value of HANDLE_GENERIC_PRAGMAS. The right
> fix is to adjust c-pragma.c so that the registry and dispatch routines
> don't depend on HANDLE_GENERIC_PRAGMAS, and c-lex.c so that the
> dispatch routine does get called. I'll try to generate a patch.
Sound like this wan't right either:
2000-09-07 Richard Henderson <rth@cygnus.com>
* c-lex.c (process_directive): If not HANDLE_GENERIC_PRAGMAS,
do not call dispatch_pragma.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code)
2000-09-08 10:43 ` John David Anglin
@ 2000-09-08 11:02 ` Zack Weinberg
0 siblings, 0 replies; 521+ messages in thread
From: Zack Weinberg @ 2000-09-08 11:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
On Fri, Sep 08, 2000 at 01:43:16PM -0400, John David Anglin wrote:
> > > 2000-09-08 J. David Anglin <dave@hiauly1.hia.nrc.ca>
> > >
> > > lex.c (init_cp_pragma): Don't call cpp_register_pragma or
> > > cpp_register_pragma_space if HANDLE_GENERIC_PRAGMAS is not defined.
> >
> > This is not right. #pragma [GCC] interface and implementation need to
> > work irrespective of the value of HANDLE_GENERIC_PRAGMAS. The right
> > fix is to adjust c-pragma.c so that the registry and dispatch routines
> > don't depend on HANDLE_GENERIC_PRAGMAS, and c-lex.c so that the
> > dispatch routine does get called. I'll try to generate a patch.
>
> Sound like this wan't right either:
>
> 2000-09-07 Richard Henderson <rth@cygnus.com>
>
> * c-lex.c (process_directive): If not HANDLE_GENERIC_PRAGMAS,
> do not call dispatch_pragma.
No, it isn't. I believe the following is the correct patch; I can
build a cross-compiler to hpux10 with it. Please give it a spin.
zw
* c-pragma.c: Don't elide entire file if !HANDLE_GENERIC_PRAGMAS.
* c-pragma.h: Don't define HANDLE_GENERIC_PRAGMAS. Always
prototype init_pragma, prototype dispatch_pragma if !USE_CPPLIB,
never define init_pragma to nothing.
* c-lex.c (process_directive): Revert previous change - always
call dispatch_pragma.
===================================================================
Index: c-pragma.c
--- c-pragma.c 2000/09/07 22:24:31 1.35
+++ c-pragma.c 2000/09/08 17:59:14
@@ -32,8 +32,6 @@ Boston, MA 02111-1307, USA. */
#include "c-lex.h"
#include "tm_p.h"
-#ifdef HANDLE_GENERIC_PRAGMAS
-
#if USE_CPPLIB
extern cpp_reader parse_in;
#else
@@ -438,10 +436,11 @@ dispatch_pragma ()
void
init_pragma ()
{
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
#if !USE_CPPLIB
- cpp_reader *pfile = 0;
+ pfile = 0;
#else
- cpp_reader *pfile = &parse_in;
+ pfile = &parse_in;
#endif
#ifdef HANDLE_PRAGMA_PACK
@@ -450,7 +449,6 @@ init_pragma ()
#ifdef HANDLE_PRAGMA_WEAK
cpp_register_pragma (pfile, 0, "weak", handle_pragma_weak);
#endif
-
#ifdef REGISTER_TARGET_PRAGMAS
REGISTER_TARGET_PRAGMAS (pfile);
#endif
@@ -460,5 +458,3 @@ init_pragma ()
mark_align_stack);
#endif
}
-
-#endif /* HANDLE_GENERIC_PRAGMAS */
===================================================================
Index: c-pragma.h
--- c-pragma.h 2000/09/07 22:24:31 1.16
+++ c-pragma.h 2000/09/08 17:59:14
@@ -57,25 +57,11 @@ extern struct weak_syms * weak_decls;
extern int add_weak PARAMS ((const char *, const char *));
#endif /* HANDLE_PRAGMA_WEAK */
-
-/* Define HANDLE_GENERIC_PRAGMAS if any kind of front-end pragma
- parsing is to be done. The code in GCC's generic C source files
- will only look for the definition of this constant. They will
- ignore definitions of HANDLE_PRAGMA_PACK and so on. */
-#if defined HANDLE_PRAGMA_PACK || defined HANDLE_PRAGMA_WEAK \
- || defined REGISTER_TARGET_PRAGMAS
-#define HANDLE_GENERIC_PRAGMAS
-#endif
-
-#ifdef HANDLE_GENERIC_PRAGMAS
extern void init_pragma PARAMS ((void));
-# if !USE_CPPLIB
+/* If cpplib is in use, it handles dispatch. */
+#if !USE_CPPLIB
extern void dispatch_pragma PARAMS ((void));
-# endif
-
-#else
-# define init_pragma()
#endif
/* Duplicate prototypes for the register_pragma stuff and the typedef for
===================================================================
Index: c-lex.c
--- c-lex.c 2000/09/08 01:38:08 1.99
+++ c-lex.c 2000/09/08 17:59:14
@@ -457,9 +457,7 @@ process_directive ()
if (!strcmp (name, "pragma"))
{
-#ifdef HANDLE_GENERIC_PRAGMAS
dispatch_pragma ();
-#endif
goto skipline;
}
else if (!strcmp (name, "define"))
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
[not found] <no.id>
` (14 preceding siblings ...)
2000-09-08 10:29 ` Unsatisfied symbols: cpp_register_pragma (code), cpp_register_pragma_space (code) John David Anglin
@ 2000-09-08 17:15 ` John David Anglin
2000-09-08 23:06 ` John David Anglin
2000-09-11 14:25 ` John David Anglin
` (147 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-08 17:15 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
The enclosed patch works around the previous problem. However, the are still
problems which appear unrelated to this patch.
The tFix test fails. Not sure what is going on here but for most of the
other classes there seems to be weak definitions for the class constructors,
etc. Here is the log:
spawn /home/dave/gnu/gcc-2.96/objdir/gcc/xgcc -B/home/dave/gnu/gcc-2.96/objdir/gcc/ ../../../../libg++/testsuite/libg++.tests/../../tests/tFix.cc libtest.a -L/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu//libg++ -I.. -I../../../../libg++ -I. -I/home/dave/gnu/gcc-2.96/libg++ -I/home/dave/gnu/gcc-2.96/libg++/src -I/home/dave/gnu/gcc-2.96/libstdc++ -I/home/dave/gnu/gcc-2.96/libstdc++/stl -I/home/dave/gnu/gcc-2.96/libio -I/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu/libio -L/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu//libg++ -L/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu//libstdc++ -L/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu//libiberty -L/home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu/libio -lg++ -lstdc++ -lm -o /home/dave/gnu/gcc-2.96/objdir/i686-pc-linux-gnu/libg++/testsuite/tFix
/tmp/ccPgMFw1.o: In function `check(char const *, Fix)':
/tmp/ccPgMFw1.o(.text+0x3e): undefined reference to `operator<<(ostream &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x59): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x6b): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o: In function `checkb(char const *, Fix)':
/tmp/ccPgMFw1.o(.text+0x1f0): undefined reference to `length(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x232): undefined reference to `operator<<(ostream &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x26e): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x280): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o: In function `main':
/tmp/ccPgMFw1.o(.text+0x2f8): undefined reference to `Fix::Fix(void)'
/tmp/ccPgMFw1.o(.text+0x30b): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x335): undefined reference to `Fix::Fix(double)'
/tmp/ccPgMFw1.o(.text+0x348): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x371): undefined reference to `Fix::Fix(int, double)'
/tmp/ccPgMFw1.o(.text+0x384): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x3b0): undefined reference to `Fix::Fix(int, double)'
/tmp/ccPgMFw1.o(.text+0x3c3): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x3ea): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x3fd): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x42b): undefined reference to `Fix::operator=(double)'
/tmp/ccPgMFw1.o(.text+0x456): undefined reference to `Fix::operator=(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x481): undefined reference to `Fix::operator=(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x4ac): undefined reference to `Fix::operator=(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x4da): undefined reference to `Fix::operator=(double)'
/tmp/ccPgMFw1.o(.text+0x501): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x528): undefined reference to `operator==(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x550): undefined reference to `Fix::operator=(double)'
/tmp/ccPgMFw1.o(.text+0x561): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x574): undefined reference to `operator==(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x595): undefined reference to `operator!=(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x5b6): undefined reference to `operator>(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x5d7): undefined reference to `operator<=(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x5fc): undefined reference to `Fix::operator=(double)'
/tmp/ccPgMFw1.o(.text+0x60d): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x68f): undefined reference to `Fix::operator+(void)'
/tmp/ccPgMFw1.o(.text+0x69c): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x6c3): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0x6ee): undefined reference to `operator+(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x719): undefined reference to `operator-(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x744): undefined reference to `operator*(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x76d): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x796): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x7c8): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0x7da): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x7ff): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x81d): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0x82f): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x854): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x869): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x892): undefined reference to `operator%(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x8bb): undefined reference to `operator%(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x8e6): undefined reference to `operator/(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0x90f): undefined reference to `operator<<(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x941): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0x953): undefined reference to `operator>>(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0x978): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0x994): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0x9a9): undefined reference to `abs(Fix)'
/tmp/ccPgMFw1.o(.text+0x9d9): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0x9ee): undefined reference to `abs(Fix)'
/tmp/ccPgMFw1.o(.text+0xa14): undefined reference to `sgn(Fix const &)'
/tmp/ccPgMFw1.o(.text+0xa3b): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0xa47): undefined reference to `sgn(Fix const &)'
/tmp/ccPgMFw1.o(.text+0xa66): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xaa3): undefined reference to `Fix::Fix(double)'
/tmp/ccPgMFw1.o(.text+0xad1): undefined reference to `Fix::Fix(double)'
/tmp/ccPgMFw1.o(.text+0xae7): undefined reference to `Fix::Fix(Fix const &)'
/tmp/ccPgMFw1.o(.text+0xb18): undefined reference to `operator/(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xb51): undefined reference to `Fix::Fix(double)'
/tmp/ccPgMFw1.o(.text+0xb6a): undefined reference to `operator/(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xb95): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xbb0): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0xc06): undefined reference to `operator+(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xc43): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0xc58): undefined reference to `operator-(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xc83): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xc9b): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0xcf1): undefined reference to `operator+(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xd2e): undefined reference to `Fix::operator-(void)'
/tmp/ccPgMFw1.o(.text+0xd43): undefined reference to `operator-(Fix const &, Fix const &)'
/tmp/ccPgMFw1.o(.text+0xd6e): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xd86): undefined reference to `operator*(Fix const &, int)'
/tmp/ccPgMFw1.o(.text+0xdae): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xdbf): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xdd0): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xde1): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xdf2): undefined reference to `Fix::~Fix(void)'
/tmp/ccPgMFw1.o(.text+0xe03): more undefined references to `Fix::~Fix(void)' follow
collect2: ld returned 1 exit status
compiler exited with status 1
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-09-08 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* BitSet.cc, BitString.cc, BitString.h, Integer.cc, Integer.h,
Rational.cc, Rational.h, String.cc, String.h: Don't use named returns.
--- libg++-2.8.1.3-20000816/libg++/src/BitSet.cc Thu Dec 17 09:34:11 1998
+++ libg++-2.8.1.3-20000908/libg++/src/BitSet.cc Fri Sep 8 16:17:10 2000
@@ -924,62 +924,6 @@
return r;
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-BitSet atoBitSet(const char* s, char f, char t, char star) return r
-{
- unsigned int sl = strlen(s);
- if (sl != 0)
- {
- r.rep = BitSetresize(r.rep, sl / BITSETBITS + 1);
- _BS_word* rs = r.rep->s;
- _BS_word a = 0;
- _BS_word m = 1;
- char lastch = 0;
- unsigned int i = 0;
- unsigned int l = 1;
- for(;;)
- {
- char ch = s[i];
- if (ch == t)
- a |= m;
- else if (ch == star)
- {
- if ((r.rep->virt = (lastch == t)))
- *rs = a | ~(m - 1);
- else
- *rs = a;
- break;
- }
- else if (ch != f)
- {
- *rs = a;
- break;
- }
- lastch = ch;
- if (++i == sl)
- {
- *rs = a;
- break;
- }
- else if (i % BITSETBITS == 0)
- {
- *rs++ = a;
- a = 0;
- m = 1;
- ++l;
- }
- else
- m <<= 1;
- }
- r.rep->len = l;
- trim(r.rep);
- }
- return;
-}
-
-#else
-
BitSet atoBitSet(const char* s, char f, char t, char star)
{
BitSet r;
@@ -1033,8 +977,6 @@
return r;
}
-#endif
-
ostream& operator << (ostream& s, const BitSet& x)
{
if (s.opfx())
--- libg++-2.8.1.3-20000816/libg++/src/BitString.cc Thu May 25 00:31:32 2000
+++ libg++-2.8.1.3-20000908/libg++/src/BitString.cc Fri Sep 8 16:30:11 2000
@@ -1258,23 +1258,10 @@
return _substr(first, rep->len - first);
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-#define RETURN(r) return
-#define RETURNS(r) return r;
-#define RETURN_OBJECT(TYPE, NAME) /* nothing */
-#define USE_UNSIGNED 1 /* probably correct */
-#else /* _G_NO_NRV */
-#define RETURN(r) return r
-#define RETURNS(r) /* nothing */
-#define RETURN_OBJECT(TYPE, NAME) TYPE NAME;
-#define USE_UNSIGNED 0 /* probably old bug */
-#endif
-
BitString
common_prefix (const BitString& x, const BitString& y, _G_int32_t startpos)
- RETURNS(r)
{
- RETURN_OBJECT(BitString, r);
+ BitString r;
_G_uint32_t xl = x.rep->len;
_G_uint32_t yl = y.rep->len;
@@ -1288,7 +1275,7 @@
startx = starty = startpos;
if (startx >= xl || starty >= yl)
- RETURN(r);
+ return r;
const _BS_word* xs = &(x.rep->s[BitStr_index(startx)]);
_BS_word a = *xs++;
@@ -1310,15 +1297,14 @@
b = *ys++;
}
r.rep = BStr_alloc(0, x.rep->s, startx, xp, xp - startx);
- RETURN(r);
+ return r;
}
BitString
common_suffix (const BitString& x, const BitString& y, _G_int32_t startpos)
- RETURNS(r)
{
- RETURN_OBJECT(BitString, r);
+ BitString r;
_G_uint32_t xl = x.rep->len;
_G_uint32_t yl = y.rep->len;
@@ -1332,7 +1318,7 @@
startx = starty = startpos;
if (startx >= xl || starty >= yl)
- RETURN(r);
+ return r;
const _BS_word* xs = &(x.rep->s[BitStr_index(startx)]);
_BS_word a = *xs--;
@@ -1354,13 +1340,12 @@
b = *ys--;
}
r.rep = BStr_alloc(0, x.rep->s, xp+1, startx+1, startx - xp);
- RETURN(r);
+ return r;
}
BitString reverse (const BitString& x)
- RETURNS(r)
{
- RETURN_OBJECT(BitString, r);
+ BitString r;
_G_uint32_t yl = x.rep->len;
BitStrRep* y = BStr_resize(0, yl);
if (yl > 0)
@@ -1390,14 +1375,13 @@
}
}
r.rep = y;
- RETURN(r);
+ return r;
}
BitString
atoBitString (const char* s, char f, char t)
- RETURNS(res)
{
- RETURN_OBJECT(BitString, res);
+ BitString res;
_G_uint32_t sl = strlen(s);
BitStrRep* r = BStr_resize(0, sl);
if (sl != 0)
@@ -1435,14 +1419,13 @@
r = BStr_resize(r, rl);
}
res.rep = r;
- RETURN(res);
+ return res;
}
BitPattern
atoBitPattern (const char* s, char f,char t,char x)
- RETURNS(r)
{
- RETURN_OBJECT(BitPattern, r);
+ BitPattern r;
_G_uint32_t sl = strlen(s);
if (sl != 0)
{
@@ -1494,7 +1477,7 @@
r.pattern.rep = BStr_resize(r.pattern.rep, rl);
r.mask.rep = BStr_resize(r.mask.rep, rl);
}
- RETURN(r);
+ return r;
}
extern AllocRing _libgxx_fmtq;
--- libg++-2.8.1.3-20000816/libg++/src/Integer.cc Thu May 25 00:31:32 2000
+++ libg++-2.8.1.3-20000908/libg++/src/Integer.cc Fri Sep 8 16:32:53 2000
@@ -1907,41 +1907,6 @@
return dest;
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-Integer sqrt(const Integer& x) return r(x)
-{
- int s = sign(x);
- if (s < 0) x.error("Attempted square root of negative Integer");
- if (s != 0)
- {
- r >>= (lg(x) / 2); // get close
- Integer q;
- div(x, r, q);
- while (q < r)
- {
- r += q;
- r >>= 1;
- div(x, r, q);
- }
- }
- return;
-}
-
-Integer lcm(const Integer& x, const Integer& y) return r
-{
- if (!x.initialized() || !y.initialized())
- x.error("operation on uninitialized Integer");
- Integer g;
- if (sign(x) == 0 || sign(y) == 0)
- g = 1;
- else
- g = gcd(x, y);
- div(x, g, r);
- mul(r, y, r);
-}
-
-#else
Integer sqrt(const Integer& x)
{
Integer r(x);
@@ -1977,10 +1942,6 @@
return r;
}
-#endif
-
-
-
IntRep* atoIntRep(const char* s, int base)
{
int sl = strlen(s);
--- libg++-2.8.1.3-20000816/libg++/src/Rational.cc Sat Jun 24 12:45:36 1995
+++ libg++-2.8.1.3-20000908/libg++/src/Rational.cc Fri Sep 8 16:35:23 2000
@@ -193,78 +193,6 @@
return pow(x, yy);
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-Rational operator - (const Rational& x) return r(x)
-{
- r.negate();
-}
-
-Rational abs(const Rational& x) return r(x)
-{
- if (sign(r.num) < 0) r.negate();
-}
-
-
-Rational sqr(const Rational& x) return r
-{
- mul(x.num, x.num, r.num);
- mul(x.den, x.den, r.den);
- r.normalize();
-}
-
-Integer floor(const Rational& x) return q
-{
- Integer r;
- divide(x.num, x.den, q, r);
- if (sign(x.num) < 0 && sign(r) != 0) --q;
-}
-
-Integer ceil(const Rational& x) return q
-{
- Integer r;
- divide(x.num, x.den, q, r);
- if (sign(x.num) >= 0 && sign(r) != 0) ++q;
-}
-
-Integer round(const Rational& x) return q
-{
- Integer r;
- divide(x.num, x.den, q, r);
- r <<= 1;
- if (ucompare(r, x.den) >= 0)
- {
- if (sign(x.num) >= 0)
- ++q;
- else
- --q;
- }
-}
-
-// power: no need to normalize since num & den already relatively prime
-
-Rational pow(const Rational& x, long y) return r
-{
- if (y >= 0)
- {
- pow(x.num, y, r.num);
- pow(x.den, y, r.den);
- }
- else
- {
- y = -y;
- pow(x.num, y, r.den);
- pow(x.den, y, r.num);
- if (sign(r.den) < 0)
- {
- r.num.negate();
- r.den.negate();
- }
- }
-}
-
-#else
-
Rational operator - (const Rational& x)
{
Rational r(x); r.negate(); return r;
@@ -343,8 +271,6 @@
return r;
}
-#endif
-
ostream& operator << (ostream& s, const Rational& y)
{
if (y.denominator() == 1L)
--- libg++-2.8.1.3-20000816/libg++/src/Rational.h Sat Jun 24 12:45:37 1995
+++ libg++-2.8.1.3-20000908/libg++/src/Rational.h Fri Sep 8 16:11:56 2000
@@ -242,30 +242,6 @@
}
#endif
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-inline Rational operator + (const Rational& x, const Rational& y) return r
-{
- add(x, y, r);
-}
-
-inline Rational operator - (const Rational& x, const Rational& y) return r
-{
- sub(x, y, r);
-}
-
-inline Rational operator * (const Rational& x, const Rational& y) return r
-{
- mul(x, y, r);
-}
-
-inline Rational operator / (const Rational& x, const Rational& y) return r
-{
- div(x, y, r);
-}
-
-#else /* NO_NRV */
-
inline Rational operator + (const Rational& x, const Rational& y)
{
Rational r; add(x, y, r); return r;
@@ -285,6 +261,5 @@
{
Rational r; div(x, y, r); return r;
}
-#endif
#endif
--- libg++-2.8.1.3-20000816/libg++/src/String.cc Thu Dec 17 09:34:11 1998
+++ libg++-2.8.1.3-20000908/libg++/src/String.cc Fri Sep 8 16:38:56 2000
@@ -966,19 +966,9 @@
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-#define RETURN(r) return
-#define RETURNS(r) return r;
-#define RETURN_OBJECT(TYPE, NAME) /* nothing */
-#else /* _G_NO_NRV */
-#define RETURN(r) return r
-#define RETURNS(r) /* nothing */
-#define RETURN_OBJECT(TYPE, NAME) TYPE NAME;
-#endif
-
-String join(String src[], int n, const String& separator) RETURNS(x)
+String join(String src[], int n, const String& separator)
{
- RETURN_OBJECT(String,x)
+ String x;
String sep = separator;
int xlen = 0;
int i;
@@ -998,7 +988,7 @@
j += sep.length();
}
ncopy0(src[i].chars(), &(x.rep->s[j]), src[i].length());
- RETURN(x);
+ return x;
}
/*
@@ -1078,58 +1068,6 @@
return dest;
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-String replicate(char c, int n) return w;
-{
- w.rep = Sresize(w.rep, n);
- char* p = w.rep->s;
- while (n-- > 0) *p++ = c;
- *p = 0;
-}
-
-String replicate(const String& y, int n) return w
-{
- int len = y.length();
- w.rep = Sresize(w.rep, n * len);
- char* p = w.rep->s;
- while (n-- > 0)
- {
- ncopy(y.chars(), p, len);
- p += len;
- }
- *p = 0;
-}
-
-String common_prefix(const String& x, const String& y, int startpos) return r;
-{
- const char* xchars = x.chars();
- const char* ychars = y.chars();
- const char* xs = &(xchars[startpos]);
- const char* ss = xs;
- const char* topx = &(xchars[x.length()]);
- const char* ys = &(ychars[startpos]);
- const char* topy = &(ychars[y.length()]);
- int l;
- for (l = 0; xs < topx && ys < topy && *xs++ == *ys++; ++l);
- r.rep = Salloc(r.rep, ss, l, l);
-}
-
-String common_suffix(const String& x, const String& y, int startpos) return r;
-{
- const char* xchars = x.chars();
- const char* ychars = y.chars();
- const char* xs = &(xchars[x.length() + startpos]);
- const char* botx = xchars;
- const char* ys = &(ychars[y.length() + startpos]);
- const char* boty = ychars;
- int l;
- for (l = 0; xs >= botx && ys >= boty && *xs == *ys ; --xs, --ys, ++l);
- r.rep = Salloc(r.rep, ++xs, l, l);
-}
-
-#else
-
String replicate(char c, int n)
{
String w;
@@ -1186,8 +1124,6 @@
return r;
}
-#endif
-
// IO
istream& operator>>(istream& s, String& x)
--- libg++-2.8.1.3-20000816/libg++/src/String.h Sat Jun 24 12:45:38 1995
+++ libg++-2.8.1.3-20000908/libg++/src/String.h Fri Sep 8 16:15:43 2000
@@ -696,80 +696,6 @@
// constructive concatenation
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-inline String operator + (const String& x, const String& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const String& x, const SubString& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const String& x, const char* y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const String& x, char y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const SubString& x, const String& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const SubString& x, const SubString& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const SubString& x, const char* y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const SubString& x, char y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const char* x, const String& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String operator + (const char* x, const SubString& y) return r;
-{
- cat(x, y, r);
-}
-
-inline String reverse(const String& x) return r;
-{
- r.rep = Sreverse(x.rep, r.rep);
-}
-
-inline String upcase(const String& x) return r;
-{
- r.rep = Supcase(x.rep, r.rep);
-}
-
-inline String downcase(const String& x) return r;
-{
- r.rep = Sdowncase(x.rep, r.rep);
-}
-
-inline String capitalize(const String& x) return r;
-{
- r.rep = Scapitalize(x.rep, r.rep);
-}
-
-#else /* NO_NRV */
-
inline String operator + (const String& x, const String& y)
{
String r; cat(x, y, r); return r;
@@ -840,8 +766,6 @@
String r; r.rep = Scapitalize(x.rep, r.rep); return r;
}
-#endif
-
// prepend
inline void String::prepend(const String& y)
--- libg++-2.8.1.3-20000816/libg++/src/BitString.h Thu May 25 00:31:32 2000
+++ libg++-2.8.1.3-20000908/libg++/src/BitString.h Fri Sep 8 18:26:14 2000
@@ -499,68 +499,19 @@
::complement(*this, *this);
}
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-inline BitString operator & (const BitString& x, const BitString& y) return r
-{
- and_f(x, y, r);
-}
-
-inline BitString operator | (const BitString& x, const BitString& y) return r
-{
- or_f(x, y, r);
-}
-
-inline BitString operator ^ (const BitString& x, const BitString& y) return r
-{
- xor_f(x, y, r);
-}
-
-inline BitString operator << (const BitString& x, _G_int32_t y) return r
-{
- lshift(x, y, r);
-}
-
-inline BitString operator >> (const BitString& x, _G_int32_t y) return r
-{
- rshift(x, y, r);
-}
-
-inline BitString operator - (const BitString& x, const BitString& y) return r
-{
- diff(x, y, r);
-}
-
-inline BitString operator + (const BitString& x, const BitString& y) return r
-{
- cat(x, y, r);
-}
-
-inline BitString operator + (const BitString& x, _G_uint32_t y) return r
-{
- cat(x, y, r);
-}
-
-inline BitString operator ~ (const BitString& x) return r
-{
- complement(x, r);
-}
-
-#else /* NO_NRV */
-
inline BitString operator & (const BitString& x, const BitString& y)
{
- BitString r; and(x, y, r); return r;
+ BitString r; and_f(x, y, r); return r;
}
inline BitString operator | (const BitString& x, const BitString& y)
{
- BitString r; or(x, y, r); return r;
+ BitString r; or_f(x, y, r); return r;
}
inline BitString operator ^ (const BitString& x, const BitString& y)
{
- BitString r; xor(x, y, r); return r;
+ BitString r; xor_f(x, y, r); return r;
}
inline BitString operator << (const BitString& x, _G_int32_t y)
@@ -593,8 +544,6 @@
BitString r; complement(x, r); return r;
}
-#endif
-
// status, matching
inline _G_int32_t BitString::length() const
--- libg++-2.8.1.3-20000816/libg++/src/Integer.h Thu May 25 00:31:32 2000
+++ libg++-2.8.1.3-20000908/libg++/src/Integer.h Fri Sep 8 18:18:53 2000
@@ -761,187 +761,6 @@
// constructive operations
-#if defined(__GNUG__) && !defined(_G_NO_NRV)
-
-inline Integer operator + (const Integer& x, const Integer& y) return r
-{
- add(x, y, r);
-}
-
-inline Integer operator + (const Integer& x, long y) return r
-{
- add(x, y, r);
-}
-
-inline Integer operator + (long x, const Integer& y) return r
-{
- add(x, y, r);
-}
-
-inline Integer operator - (const Integer& x, const Integer& y) return r
-{
- sub(x, y, r);
-}
-
-inline Integer operator - (const Integer& x, long y) return r
-{
- sub(x, y, r);
-}
-
-inline Integer operator - (long x, const Integer& y) return r
-{
- sub(x, y, r);
-}
-
-inline Integer operator * (const Integer& x, const Integer& y) return r
-{
- mul(x, y, r);
-}
-
-inline Integer operator * (const Integer& x, long y) return r
-{
- mul(x, y, r);
-}
-
-inline Integer operator * (long x, const Integer& y) return r
-{
- mul(x, y, r);
-}
-
-inline Integer sqr(const Integer& x) return r
-{
- mul(x, x, r);
-}
-
-inline Integer operator & (const Integer& x, const Integer& y) return r
-{
- r.rep = bitop(x.rep, y.rep, r.rep, '&');
-}
-
-inline Integer operator & (const Integer& x, long y) return r
-{
- r.rep = bitop(x.rep, y, r.rep, '&');
-}
-
-inline Integer operator & (long x, const Integer& y) return r
-{
- r.rep = bitop(y.rep, x, r.rep, '&');
-}
-
-inline Integer operator | (const Integer& x, const Integer& y) return r
-{
- r.rep = bitop(x.rep, y.rep, r.rep, '|');
-}
-
-inline Integer operator | (const Integer& x, long y) return r
-{
- r.rep = bitop(x.rep, y, r.rep, '|');
-}
-
-inline Integer operator | (long x, const Integer& y) return r
-{
- r.rep = bitop(y.rep, x, r.rep, '|');
-}
-
-inline Integer operator ^ (const Integer& x, const Integer& y) return r
-{
- r.rep = bitop(x.rep, y.rep, r.rep, '^');
-}
-
-inline Integer operator ^ (const Integer& x, long y) return r
-{
- r.rep = bitop (x.rep, y, r.rep, '^');
-}
-
-inline Integer operator ^ (long x, const Integer& y) return r
-{
- r.rep = bitop (y.rep, x, r.rep, '^');
-}
-
-inline Integer operator / (const Integer& x, const Integer& y) return r
-{
- div(x, y, r);
-}
-
-inline Integer operator / (const Integer& x, long y) return r
-{
- div(x, y, r);
-}
-
-inline Integer operator % (const Integer& x, const Integer& y) return r
-{
- mod(x, y, r);
-}
-
-inline Integer operator % (const Integer& x, long y) return r
-{
- mod(x, y, r);
-}
-
-inline Integer operator << (const Integer& x, const Integer& y) return r
-{
- lshift(x, y, r);
-}
-
-inline Integer operator << (const Integer& x, long y) return r
-{
- lshift(x, y, r);
-}
-
-inline Integer operator >> (const Integer& x, const Integer& y) return r;
-{
- rshift(x, y, r);
-}
-
-inline Integer operator >> (const Integer& x, long y) return r
-{
- rshift(x, y, r);
-}
-
-inline Integer pow(const Integer& x, long y) return r
-{
- pow(x, y, r);
-}
-
-inline Integer Ipow(long x, long y) return r(x)
-{
- pow(r, y, r);
-}
-
-inline Integer pow(const Integer& x, const Integer& y) return r
-{
- pow(x, y, r);
-}
-
-
-
-inline Integer abs(const Integer& x) return r
-{
- abs(x, r);
-}
-
-inline Integer operator - (const Integer& x) return r
-{
- negate(x, r);
-}
-
-inline Integer operator ~ (const Integer& x) return r
-{
- complement(x, r);
-}
-
-inline Integer atoI(const char* s, int base) return r
-{
- r.rep = atoIntRep(s, base);
-}
-
-inline Integer gcd(const Integer& x, const Integer& y) return r
-{
- r.rep = gcd(x.rep, y.rep);
-}
-
-#else /* NO_NRV */
-
inline Integer operator + (const Integer& x, const Integer& y)
{
Integer r; add(x, y, r); return r;
@@ -994,32 +813,32 @@
inline Integer operator & (const Integer& x, const Integer& y)
{
- Integer r; and(x, y, r); return r;
+ Integer r; r.rep = bitop(x.rep, y.rep, r.rep, '&'); return r;
}
inline Integer operator & (const Integer& x, long y)
{
- Integer r; and(x, y, r); return r;
+ Integer r; r.rep = bitop(x.rep, y, r.rep, '&'); return r;
}
inline Integer operator & (long x, const Integer& y)
{
- Integer r; and(x, y, r); return r;
+ Integer r; r.rep = bitop(y.rep, x, r.rep, '&'); return r;
}
inline Integer operator | (const Integer& x, const Integer& y)
{
- Integer r; or(x, y, r); return r;
+ Integer r; r.rep = bitop(x.rep, y.rep, r.rep, '|'); return r;
}
inline Integer operator | (const Integer& x, long y)
{
- Integer r; or(x, y, r); return r;
+ Integer r; r.rep = bitop(x.rep, y, r.rep, '|'); return r;
}
inline Integer operator | (long x, const Integer& y)
{
- Integer r; or(x, y, r); return r;
+ Integer r; r.rep = bitop(y.rep, x, r.rep, '|'); return r;
}
inline Integer operator ^ (const Integer& x, const Integer& y)
@@ -1119,8 +938,6 @@
Integer r; r.rep = gcd(x.rep, y.rep); return r;
}
-#endif /* NO_NRV */
-
inline Integer& Integer::operator %= (const Integer& y)
{
*this = *this % y; // mod(*this, y, *this) doesn't work.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
2000-09-08 17:15 ` Segmentation fault building libg++ without named returns John David Anglin
@ 2000-09-08 23:06 ` John David Anglin
2000-09-09 6:14 ` Manfred Hollstein
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-08 23:06 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> The tFix test fails. Not sure what is going on here but for most of the
> other classes there seems to be weak definitions for the class constructors,
> etc. Here is the log:
The failure doesn't occur under hpux 10.20 (only i686 linux). As noted
before, there aren't any weak symbol defines in Fix.o when built under
i686 linux. For example,
hpux:
U strstreambuf::~strstreambuf(void)
00000000 W Fix::~Fix(void)
4000000c D Fix::Rep_0
40000014 D Fix::Rep_m1
linux:
U strstreambuf::~strstreambuf(void)
0000000c D Fix::Rep_0
00000014 D Fix::Rep_m1
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
2000-09-08 23:06 ` John David Anglin
@ 2000-09-09 6:14 ` Manfred Hollstein
2000-09-09 15:06 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Manfred Hollstein @ 2000-09-09 6:14 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1564 bytes --]
Hi John,
Thanks for the patch you sent with your previous email; I observed the
same failures when Mark installed his patch to warn about using named
return values. I took a differend approach than you, i.e. instead of
removing the code completely, I used the opposite logic with a flag
_G_USE_NRV as opposed to the former _G_NO_NRV; I've attached that
patch to this email.
Regarding the missing weak symbols, I'm pretty much at a loss;
building Fix.cc and Rational.cc doesn't generate all required weak
symbols as it did before; even worse, using a reduced test case
doesn't fail to generate those symbols... I'll dig further and keep
you informed.
Cheers.
l8er
manfred
On Saturday, 9 September 2000, 02:06:54 -0400, dave@hiauly1.hia.nrc.ca wrote:
> > The tFix test fails. Not sure what is going on here but for most of the
> > other classes there seems to be weak definitions for the class constructors,
> > etc. Here is the log:
>
> The failure doesn't occur under hpux 10.20 (only i686 linux). As noted
> before, there aren't any weak symbol defines in Fix.o when built under
> i686 linux. For example,
>
> hpux:
> U strstreambuf::~strstreambuf(void)
> 00000000 W Fix::~Fix(void)
> 4000000c D Fix::Rep_0
> 40000014 D Fix::Rep_m1
>
> linux:
> U strstreambuf::~strstreambuf(void)
> 0000000c D Fix::Rep_0
> 00000014 D Fix::Rep_m1
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
[-- Attachment #2: libg++-2.8.1.3-20000907.diff.gz --]
[-- Type: application/x-gzip, Size: 2914 bytes --]
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
2000-09-09 6:14 ` Manfred Hollstein
@ 2000-09-09 15:06 ` John David Anglin
2000-09-10 2:55 ` Manfred Hollstein
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-09 15:06 UTC (permalink / raw)
To: manfred.h; +Cc: gcc-bugs, gcc-patches
> Thanks for the patch you sent with your previous email; I observed the
> same failures when Mark installed his patch to warn about using named
> return values. I took a differend approach than you, i.e. instead of
> removing the code completely, I used the opposite logic with a flag
> _G_USE_NRV as opposed to the former _G_NO_NRV; I've attached that
> patch to this email.
I tend to think the code should be removed. There were essentially two
sets with the "same" code. However, the unused branch which didn't use
named returns had rotted a bit. Apparently, `and', `or' and `xor' are
c++ diagraphs and can't be used.
> Regarding the missing weak symbols, I'm pretty much at a loss;
> building Fix.cc and Rational.cc doesn't generate all required weak
> symbols as it did before; even worse, using a reduced test case
> doesn't fail to generate those symbols... I'll dig further and keep
> you informed.
I don't have any time this weekend to work on it but I think a first
step would be to dump the assembly code for Fix.cc and see what is
happening with respect to the week definitions. Then, looking at the
rtl may help to pinpoint where things are going wrong. It's a fairly
recent change to the compiler that has caused the problem.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
2000-09-09 15:06 ` John David Anglin
@ 2000-09-10 2:55 ` Manfred Hollstein
2000-09-11 13:35 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Manfred Hollstein @ 2000-09-10 2:55 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
On Saturday, 9 September 2000, 18:06:51 -0400, dave@hiauly1.hia.nrc.ca wrote:
> > Thanks for the patch you sent with your previous email; I observed the
> > same failures when Mark installed his patch to warn about using named
> > return values. I took a differend approach than you, i.e. instead of
> > removing the code completely, I used the opposite logic with a flag
> > _G_USE_NRV as opposed to the former _G_NO_NRV; I've attached that
> > patch to this email.
>
> I tend to think the code should be removed. There were essentially two
> sets with the "same" code.
I agree; however, I'll keep the code for some time, at least until it's
working again with the current gcc versions.... and until I've checked
the _NO_NRV code works with older compilers, too.
> However, the unused branch which didn't use
> named returns had rotted a bit. Apparently, `and', `or' and `xor' are
> c++ diagraphs and can't be used.
Yup, my fix included patches for this also.
> > Regarding the missing weak symbols, I'm pretty much at a loss;
> > building Fix.cc and Rational.cc doesn't generate all required weak
> > symbols as it did before; even worse, using a reduced test case
> > doesn't fail to generate those symbols... I'll dig further and keep
> > you informed.
>
> I don't have any time this weekend to work on it but I think a first
> step would be to dump the assembly code for Fix.cc and see what is
> happening with respect to the week definitions.
I did already, they aren't even emitted...
> Then, looking at the
> rtl may help to pinpoint where things are going wrong. It's a fairly
> recent change to the compiler that has caused the problem.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
Cheers, manfred.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
2000-09-10 2:55 ` Manfred Hollstein
@ 2000-09-11 13:35 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-09-11 13:35 UTC (permalink / raw)
To: manfred.h; +Cc: gcc-bugs, gcc-patches
> > > Regarding the missing weak symbols, I'm pretty much at a loss;
> > > building Fix.cc and Rational.cc doesn't generate all required weak
> > > symbols as it did before; even worse, using a reduced test case
> > > doesn't fail to generate those symbols... I'll dig further and keep
> > > you informed.
> >
> > I don't have any time this weekend to work on it but I think a first
> > step would be to dump the assembly code for Fix.cc and see what is
> > happening with respect to the week definitions.
>
> I did already, they aren't even emitted...
Using your patch, I rebuilt Fix.o and Rational.o without optimisation. With
no optimisation for these two modules, the weak symbols are there and the
testsuite has no failures.
Comparing the rtl, the rtl generated without optimisation has lots of calls
to Fix::~Fix(void) and the following code is in the assembler output:
.weak _._3Fix
.type _._3Fix,@function
_._3Fix:
The rtl at -O3 has no calls to Fix::~Fix(void), even in Fix.cc.00.rtl.
There is also no definition for Fix::~Fix(void) in the assemble output.
Things work ok under hpux 10.20. Thus, the problem is in some way related
to the i386 linux configuration.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Segmentation fault building libg++ without named returns
[not found] <no.id>
` (15 preceding siblings ...)
2000-09-08 17:15 ` Segmentation fault building libg++ without named returns John David Anglin
@ 2000-09-11 14:25 ` John David Anglin
2000-09-14 5:45 ` libg++-2.8.1.3-20000914.diff.gz (was: Re: Segmentation fault building libg++ without named returns) Manfred Hollstein
2000-09-22 11:06 ` Patch: Include WARN_CFLAGS in CFLAGS passed for building fixinc.sh John David Anglin
` (146 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-09-11 14:25 UTC (permalink / raw)
To: John David Anglin; +Cc: manfred.h, gcc-bugs, gcc-patches
> The rtl at -O3 has no calls to Fix::~Fix(void), even in Fix.cc.00.rtl.
> There is also no definition for Fix::~Fix(void) in the assemble output.
If I specify `-fno-inline', the weak defines are output at -O3 in the
implementation object module. It seems a runtime callable version of
an inline function is not being output when the function isn't static.
For modules which include Fix.h but don't have `#pragma implementation',
it appears the functions defined in the interface are not being inlined
and a runtime callable version must exist.
I tried `-fkeep-inline-functions' but this results in the following errors:
In file included from /usr/include/math.h:348,
from ../../../../libstdc++/cmath:7,
from ../../../../libg++/src/builtin.h:33,
from ../../../../libg++/src/Fix.h:15,
from ../../../../libg++/src/Fix.cc:25:
/usr/include/bits/mathinline.h:583: output number 0 not directly addressable
...
This is the define that causes the problem in mathinline.h:
#define __lrint_code \
long int __lrintres; \
__asm__ __volatile__ \
("fistpl %0" \
: "=m" (__lrintres) : "t" (__x) : "st"); \
return __lrintres
__MATH_INLINE long int
lrintf (float __x)
{
__lrint_code;
}
...
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* libg++-2.8.1.3-20000914.diff.gz (was: Re: Segmentation fault building libg++ without named returns)
2000-09-11 14:25 ` John David Anglin
@ 2000-09-14 5:45 ` Manfred Hollstein
2000-09-21 9:50 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Manfred Hollstein @ 2000-09-14 5:45 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 962 bytes --]
On Monday, 11 September 2000, 17:25:11 -0400, dave@hiauly1.hia.nrc.ca wrote:
> > The rtl at -O3 has no calls to Fix::~Fix(void), even in Fix.cc.00.rtl.
> > There is also no definition for Fix::~Fix(void) in the assemble output.
>
> If I specify `-fno-inline', the weak defines are output at -O3 in the
> implementation object module. It seems a runtime callable version of
> an inline function is not being output when the function isn't static.
> For modules which include Fix.h but don't have `#pragma implementation',
> it appears the functions defined in the interface are not being inlined
> and a runtime callable version must exist.
Your analysis is correct and is similar to my observations. Since I
don't have enough time to fix this properly, I came up with the hack
to use -O0 on ia32-linux. I've attached the patch which supersedes the
former version -20000907; "make bootstrap check" ran successfully using
this patch.
Cheers.
l8er
manfred
[-- Attachment #2: libg++-2.8.1.3-20000914.diff.gz --]
[-- Type: application/x-gzip, Size: 3065 bytes --]
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: libg++-2.8.1.3-20000914.diff.gz (was: Re: Segmentation fault building libg++ without named returns)
2000-09-14 5:45 ` libg++-2.8.1.3-20000914.diff.gz (was: Re: Segmentation fault building libg++ without named returns) Manfred Hollstein
@ 2000-09-21 9:50 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-09-21 9:50 UTC (permalink / raw)
To: manfred.h; +Cc: gcc-patches
> On Monday, 11 September 2000, 17:25:11 -0400, dave@hiauly1.hia.nrc.ca wrote:
>
> > > The rtl at -O3 has no calls to Fix::~Fix(void), even in Fix.cc.00.rtl.
> > > There is also no definition for Fix::~Fix(void) in the assemble output.
> >
> > If I specify `-fno-inline', the weak defines are output at -O3 in the
> > implementation object module. It seems a runtime callable version of
> > an inline function is not being output when the function isn't static.
> > For modules which include Fix.h but don't have `#pragma implementation',
> > it appears the functions defined in the interface are not being inlined
> > and a runtime callable version must exist.
>
> Your analysis is correct and is similar to my observations. Since I
> don't have enough time to fix this properly, I came up with the hack
> to use -O0 on ia32-linux. I've attached the patch which supersedes the
> former version -20000907; "make bootstrap check" ran successfully using
> this patch.
I have found that the problem is in some way related to math inlines. If
the build is done with __NO_MATH_INLINES defined, then Fix.o contains all
the required weak defines. There are no testsuite failures with your
version -20000907 if I add -D__NO_MATH_INLINES to CXXFLAGS in the Makefile's.
The math inlines are output at optimisations above O0. If the preprocessing
is done at -O0 and the compilation at -O3, the weak defines are there. The
other way around doesn't work.
I have been poking around in cc1plus trying to find why the weak defines
aren't getting output when the math inlines are present. If somebody more
familiar with code can suggest some places to look, it would be helpful.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Include WARN_CFLAGS in CFLAGS passed for building fixinc.sh
[not found] <no.id>
` (16 preceding siblings ...)
2000-09-11 14:25 ` John David Anglin
@ 2000-09-22 11:06 ` John David Anglin
2000-09-29 11:12 ` PATCH: Re: libio compilation problem John David Anglin
` (145 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-09-22 11:06 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> I noticed that Greg McGary's recent patch didn't include WARN_CFLAGS
> in the CFLAGS passed to mkfixinc.sh. I think these should be passed
> as well.
This patch hasn't been reviewed yet. Although passing WARN_CFLAGS to
mkfixinc.sh isn't very important at this time, I think there should be
consistency in the passing the flags to the various sub-makes.
I revamped the CFLAGS handling so that different flags could be used for
the initial compilations which might be done with a native compiler. The
Makefile variables WARN1_CFLAGS and WARN2_CFLAGS are set by configure.
Currently, they are used for warning options and a compiler dependent
option on the vax. Potentially, this method could be used to supply
compiler options on many other platforms.
I also noticed yesterday that the method of handling WARN_CFLAGS didn't
get updated for bootstrap4. Thus, I have updated the original patch.
I have tested the patch with a complete bootstrap through to stage4
under i686 linux.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-09-21 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* Makefile.in (fixinc.sh): Include WARN_CFLAGS in exported CFLAGS.
(stage_f): Pass WARN_CFLAGS separately as in stage_c and stage_e.
--- Makefile.in.orig Tue Sep 19 13:01:29 2000
+++ Makefile.in Thu Sep 21 15:01:25 2000
@@ -1964,7 +1964,7 @@
$(FIXINCSRCDIR)/server.c $(FIXINCSRCDIR)/gnu-regex.h \
$(FIXINCSRCDIR)/server.h $(FIXINCSRCDIR)/inclhack.def specs.ready
MAKE="$(MAKE)"; srcdir=`cd $(srcdir)/fixinc; pwd` ; \
- CC="$(CC)"; CFLAGS="$(CFLAGS)"; LDFLAGS="$(LDFLAGS)"; \
+ CC="$(CC)"; CFLAGS="$(CFLAGS) $(WARN_CFLAGS)"; LDFLAGS="$(LDFLAGS)"; \
export MAKE srcdir CC CFLAGS LDFLAGS; \
cd ./fixinc; $(SHELL) $${srcdir}/mkfixinc.sh $(target)
@@ -2792,7 +2792,7 @@
# For bootstrap4:
stage_f: stage_e
- +$(MAKE) CC="stage3/xgcc$(exeext) -B$(build_tooldir)/bin/ -Bstage3/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage3/ LANGUAGES="$(LANGUAGES)"
+ +$(MAKE) CC="stage3/xgcc$(exeext) -B$(build_tooldir)/bin/ -Bstage3/" CFLAGS="$(BOOT_CFLAGS)" WARN_CFLAGS="$(WARN2_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage3/ LANGUAGES="$(LANGUAGES)"
touch stage_f
# Additional steps for *-lean targets:
^ permalink raw reply [flat|nested] 521+ messages in thread
* PATCH: Re: libio compilation problem
[not found] <no.id>
` (17 preceding siblings ...)
2000-09-22 11:06 ` Patch: Include WARN_CFLAGS in CFLAGS passed for building fixinc.sh John David Anglin
@ 2000-09-29 11:12 ` John David Anglin
2000-10-16 13:21 ` PATCH: Upgrade floating comparisons on PA to support unordered operands John David Anglin
` (144 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-09-29 11:12 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> The following errors occur compiling libio/genops.c under vax-ultrix:
>
> /usr/local/src/gnu/gcc-2.96/objdir/gcc/xgcc -B/usr/local/src/gnu/gcc-2.96/objdir
> /gcc/ -B/usr/local/vax-dec-ultrix4.3/bin/ -c -O3 -I. -I../../../libio ../../../
> libio/genops.c
> ../../../libio/genops.c:472: conflicting types for `_IO_default_seekpos'
> ../../../libio/libioP.h:349: previous declaration of `_IO_default_seekpos'
> ../../../libio/genops.c:556: conflicting types for `_IO_default_seekoff'
> ../../../libio/libioP.h:348: previous declaration of `_IO_default_seekoff'
> ../../../libio/genops.c:887: conflicting types for `_IO_default_seek'
> ../../../libio/libioP.h:358: previous declaration of `_IO_default_seek'
The enclosed patch changes the implementation to match the interface
specification defined in libioP.h. It compiles under vax-dec-ultrix4.3
and I have done a complete make check under i686 linux.
In the 64 bit version of _IO_file_fopen, there is an extra parameter `tbd'
which is not used in the implementation. I don't have any documentation
as to what it's for. Possibly, somebody should check that libio works
ok with 64 bits and figure out if tbd is needed or just a mistake.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-09-29 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* fileops.c (_IO_file_fopen): Change implementation to match
prototype in libioP.h.
(_IO_file_seekoff): Likewise.
(_IO_file_seek): Likewise.
genops.c (_IO_default_seekpos): Likewise.
(_IO_default_seekoff): Likewise.
(_IO_default_seek): Likewise.
ioseekoff.c (_IO_seekoff): Likewise.
ioseekpos.c (_IO_seekpos): Likewise.
strops.c (_IO_str_seekoff): Likewise.
libioP.h: Always check that _G_IO_IO_FILE_VERSION is defined before
testing version.
--- fileops.c.orig Mon Apr 12 14:27:49 1999
+++ fileops.c Fri Sep 29 11:07:29 2000
@@ -155,11 +155,20 @@
_IO_default_finish (fp, 0);
}
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_FILE *
+_IO_file_fopen (fp, filename, mode, tbd)
+ _IO_FILE *fp;
+ const char *filename;
+ const char *mode;
+ int tbd;
+#else
_IO_FILE *
_IO_file_fopen (fp, filename, mode)
_IO_FILE *fp;
const char *filename;
const char *mode;
+#endif
{
int oflags = 0, omode;
int read_write, fdesc;
@@ -419,14 +428,27 @@
return retval;
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
+_IO_file_seekoff (fp, offset, dir, mode)
+ _IO_FILE *fp;
+ _IO_off64_t offset;
+ int dir;
+ int mode;
+#else
+_IO_off_t
_IO_file_seekoff (fp, offset, dir, mode)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
int mode;
+#endif
{
- _IO_pos_t result;
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+ _IO_off64_t result;
+#else
+ _IO_off_t result;
+#endif
_IO_off_t delta, new_offset;
long count;
/* POSIX.1 8.2.3.7 says that after a call the fflush() the file
@@ -587,11 +609,19 @@
return read (fp->_fileno, buf, size);
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
+_IO_file_seek (fp, offset, dir)
+ _IO_FILE *fp;
+ _IO_off64_t offset;
+ int dir;
+#else
+_IO_off_t
_IO_file_seek (fp, offset, dir)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
+#endif
{
return lseek (fp->_fileno, offset, dir);
}
--- genops.c.orig Thu Mar 4 19:19:08 1999
+++ genops.c Thu Sep 28 22:24:25 2000
@@ -467,13 +467,21 @@
return fp;
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
_IO_default_seekpos (fp, pos, mode)
_IO_FILE *fp;
- _IO_pos_t pos;
+ _IO_off64_t pos;
int mode;
+#else
+_IO_off_t
+_IO_default_seekpos (fp, pos, mode)
+ _IO_FILE *fp;
+ _IO_off_t pos;
+ int mode;
+#endif
{
- return _IO_SEEKOFF (fp, _IO_pos_as_off (pos), 0, mode);
+ return _IO_SEEKOFF (fp, pos, 0, mode);
}
int
@@ -551,12 +559,21 @@
_IO_un_link (fp);
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
+_IO_default_seekoff (fp, offset, dir, mode)
+ _IO_FILE *fp;
+ _IO_off64_t offset;
+ int dir;
+ int mode;
+#else
+_IO_off_t
_IO_default_seekoff (fp, offset, dir, mode)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
int mode;
+#endif
{
return _IO_pos_BAD;
}
@@ -882,11 +899,19 @@
return (unsigned char) *fp->_IO_read_ptr;
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
+_IO_default_seek (fp, offset, dir)
+ _IO_FILE *fp;
+ _IO_off64_t offset;
+ int dir;
+#else
+_IO_off_t
_IO_default_seek (fp, offset, dir)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
+#endif
{
return _IO_pos_BAD;
}
--- ioseekoff.c.orig Tue Sep 16 12:00:21 1997
+++ ioseekoff.c Thu Sep 28 22:30:27 2000
@@ -25,14 +25,27 @@
#include <libioP.h>
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
+_IO_seekoff (fp, offset, dir, mode)
+ _IO_FILE *fp;
+ _IO_off64_t offset;
+ int dir;
+ int mode;
+#else
+_IO_off_t
_IO_seekoff (fp, offset, dir, mode)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
int mode;
+#endif
{
- _IO_pos_t retval;
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+ _IO_off64_t retval;
+#else
+ _IO_off_t retval;
+#endif
/* If we have a backup buffer, get rid of it, since the __seekoff
callback may not know to do the right thing about it.
--- ioseekpos.c.orig Tue Sep 16 12:00:23 1997
+++ ioseekpos.c Thu Sep 28 22:33:42 2000
@@ -25,13 +25,25 @@
#include <libioP.h>
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
_IO_seekpos (fp, pos, mode)
_IO_FILE *fp;
- _IO_pos_t pos;
+ _IO_off64_t pos;
int mode;
+#else
+_IO_off_t
+_IO_seekpos (fp, pos, mode)
+ _IO_FILE *fp;
+ _IO_off_t pos;
+ int mode;
+#endif
{
- _IO_pos_t retval;
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+ _IO_off64_t retval;
+#else
+ _IO_off_t retval;
+#endif
/* If we have a backup buffer, get rid of it, since the __seekoff
callback may not know to do the right thing about it.
--- strops.c.orig Fri May 22 16:40:02 1998
+++ strops.c Thu Sep 28 22:56:35 2000
@@ -205,15 +205,28 @@
- fp->_IO_read_base);
}
-_IO_pos_t
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+_IO_off64_t
_IO_str_seekoff (fp, offset, dir, mode)
_IO_FILE *fp;
_IO_off_t offset;
int dir;
int mode;
+#else
+_IO_off_t
+_IO_str_seekoff (fp, offset, dir, mode)
+ _IO_FILE *fp;
+ _IO_off_t offset;
+ int dir;
+ int mode;
+#endif
{
_IO_ssize_t cur_size = _IO_str_count (fp);
- _IO_pos_t new_pos = EOF;
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
+ _IO_off64_t new_pos = EOF;
+#else
+ _IO_off_t new_pos = EOF;
+#endif
/* Move the get pointer, if requested. */
if (mode & _IOS_INPUT)
--- libioP.h.orig Fri Jun 30 11:25:33 2000
+++ libioP.h Fri Sep 29 10:55:40 2000
@@ -233,7 +233,7 @@
typedef int (*_IO_stat_t) __PMT ((_IO_FILE *, void *));
#define _IO_SYSSTAT(FP, BUF) JUMP1 (__stat, FP, BUF)
-#if _G_IO_IO_FILE_VERSION == 0x20001
+#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
/* The 'showmany' hook can be used to get an image how much input is
available. In many cases the answer will be 0 which means unknown
but some cases one can provide real information. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Upgrade floating comparisons on PA to support unordered operands
[not found] <no.id>
` (18 preceding siblings ...)
2000-09-29 11:12 ` PATCH: Re: libio compilation problem John David Anglin
@ 2000-10-16 13:21 ` John David Anglin
2000-11-09 9:40 ` testcase for hppa64 gcc bug John David Anglin
` (143 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-10-16 13:21 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> In testing this patch, I examined two other ieee tests which fail on the
> PA port. A fix for the hugeval tests under 10.20 will be sent separately.
> The mzero2 tests still fail because the insns negdf2 and negsf2 are
> implemented as a subtract from +0, since no fneg instruction is available
> on the PA. The problem is that, under the ieee standard, (+0.) - (+0.) = +0.
Actually, PA2.0 machines do have fneg. However, it behaves identically to
fsub: fneg (+0.) yields +0. Thus, it works as a subtract from +0. rather
than xor'ing the sign bit. Look's like a little bug in the HP floating
point implementation.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
[not found] <no.id>
` (19 preceding siblings ...)
2000-10-16 13:21 ` PATCH: Upgrade floating comparisons on PA to support unordered operands John David Anglin
@ 2000-11-09 9:40 ` John David Anglin
2000-11-09 16:17 ` Alan Modra
2000-12-05 20:11 ` Jeffrey A Law
2000-11-25 17:39 ` PATCH: Re: ../../../libio/stream.cc:60: Internal error: Segmentation fault John David Anglin
` (142 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2000-11-09 9:40 UTC (permalink / raw)
To: John David Anglin; +Cc: alan, gcc-bugs, gcc-patches, parisc-linux, law
> > So I went down the path of trying to fix things properly by defining
> > ELIMINABLE_REGS and so on, but I ended in a maze of twisty little passages
> > labelled "Unrecognizable instruction", like this one:
> >
> > /src/parisc/gcc/gcc/libgcc2.c: In function `__moddi3':
> > /src/parisc/gcc/gcc/libgcc2.c:601: Unrecognizable insn:
> > (insn 1289 209 1298 (set (reg:SI 50 %fr22)
> > (subreg:SI (plus:DI (reg:DI 30 %r30)
> > (const_int -272 [0xfffffef0])) 0)) -1 (nil)
> > (nil))
> > /src/parisc/gcc/gcc/libgcc2.c:601: Internal compiler error in
> > extract_insn, at recog.c:2134
>
> I am making progress in trying to make the arg_pointer register eliminable.
> I have fixed the above problem. What was happening was that reload_as_needed
> was incorrectly trying to eliminate the return from millicode calls which
> is also register r29. I have figured out how to hide it from reload with
> unspec.
>
> However, the compiler is now too good at eliminating the arg_pointer. At
> -O3, it completely eliminates the arg_pointer. However, as I read the ABI,
> the call must always set the arg_pointer before calls.
For the record, here is my final patch regarding making the arg_pointer
eliminable for TARGET_64BIT. I think the code it generates is correct but
it hasn't been extensively tested. However, I don't recommend it for
installation since in comparing the assembler code generated with and
without elimination for a couple of test cases, I didn't observe any
significant improvement in the code with the patch. Possibly, the patch
implicitly disables elimination when the arg_pointer is needed.
I do find that Alan Modra's ARG_POINTER_INVARIANT patch needs to be installed
to get correct code with his test case.
There is one part of the patch below which I think needs to be installed.
That is
(call, call_value): Always USE the arg_pointer for TARGET_64BIT.
The use for the arg_pointer needs to be pulled out of the `if (flag_pic)'.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-11-07 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa-linux64.h (ARG_POINTER_INVARIANT): Define even when the
arg_pointer is being eliminated.
(ELIMINABLE_REGS): Enable elimination of the arg_pointer.
(INITIAL_ELIMINATION_OFFSET): Revise offsets for arg_pointer.
* pa.md (mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
canonicalize_funcptr_for_compare): Put "(reg:SI 26)" inside
unspec to prevent elimination.
(call, call_value): Always USE the arg_pointer for TARGET_64BIT.
Use the new addmovdi3 insn to load the arg_pointer register.
(addmovdi3 and mov_from_r29_si): New insn and expand which prevent
r29 from being eliminated in call setups and millicode returns.
--- pa-linux64.h.orig Tue Oct 31 18:38:24 2000
+++ pa-linux64.h Tue Nov 7 12:17:12 2000
@@ -209,21 +209,18 @@
that grow to lower addresses. What fun. */
#undef ARGS_GROW_DOWNWARD
#undef ARG_POINTER_REGNUM
-#define ARG_POINTER_INVARIANT 0
#define ARG_POINTER_REGNUM 29
+#define ARG_POINTER_INVARIANT 0
#undef STATIC_CHAIN_REGNUM
#define STATIC_CHAIN_REGNUM 31
-#if 1
-#define ARG_POINTER_INVARIANT 0
-#else
-/* If defined, this macro specifies a table of register pairs used to eliminate
- unneeded registers that point into the stack frame. */
+/* If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. */
#define ELIMINABLE_REGS \
{ \
- {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
}
@@ -240,19 +237,18 @@
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do \
{ \
- int fsize; \
+ int fsize = compute_frame_size (get_frame_size (), 0); \
\
if ((TO) == FRAME_POINTER_REGNUM \
&& (FROM) == ARG_POINTER_REGNUM) \
{ \
- (OFFSET) = - current_function_pretend_args_size - 16; \
+ (OFFSET) = fsize + 48 - current_function_outgoing_args_size; \
break; \
} \
\
if ((TO) != STACK_POINTER_REGNUM) \
abort (); \
\
- fsize = compute_frame_size (get_frame_size (), 0); \
switch (FROM) \
{ \
case FRAME_POINTER_REGNUM: \
@@ -260,14 +256,13 @@
break; \
\
case ARG_POINTER_REGNUM: \
- (OFFSET) = - fsize - current_function_pretend_args_size - 16; \
+ (OFFSET) = 48 - current_function_outgoing_args_size; \
break; \
\
default: \
abort (); \
} \
} while (0)
-#endif
#undef SELECT_RTX_SECTION
#define SELECT_RTX_SECTION(MODE,RTX) \
--- pa.md.orig Tue Nov 7 13:50:34 2000
+++ pa.md.work Wed Nov 8 14:06:05 2000
@@ -3993,7 +3993,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4139,7 +4139,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4197,7 +4197,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4255,7 +4255,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4310,7 +4310,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -5785,9 +5785,9 @@
op = XEXP (operands[0], 0);
if (TARGET_64BIT)
- emit_move_insn (arg_pointer_rtx,
- gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
- GEN_INT (64)));
+ emit_insn (gen_addmovdi3 (arg_pointer_rtx,
+ virtual_outgoing_args_rtx,
+ GEN_INT (64)));
/* Use two different patterns for calls to explicitly named functions
and calls through function pointers. This is necessary as these two
@@ -5809,13 +5809,14 @@
call_insn = emit_call_insn (gen_call_internal_reg (operands[1]));
}
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM_SAVED));
- if (TARGET_64BIT)
- use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
/* After each call we must restore the PIC register, even if it
doesn't appear to be used.
@@ -5961,9 +5962,9 @@
op = XEXP (operands[1], 0);
if (TARGET_64BIT)
- emit_move_insn (arg_pointer_rtx,
- gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
- GEN_INT (64)));
+ emit_insn (gen_addmovdi3 (arg_pointer_rtx,
+ virtual_outgoing_args_rtx,
+ GEN_INT (64)));
/* Use two different patterns for calls to explicitly named functions
and calls through function pointers. This is necessary as these two
@@ -5989,6 +5990,10 @@
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
operands[2]));
}
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
@@ -7124,7 +7129,7 @@
(clobber (reg:SI 22))
(clobber (reg:SI 31))])
(set (match_operand:SI 0 "register_operand" "")
- (reg:SI 29))]
+ (unspec:SI [(reg:SI 29)] 0))]
"! TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && !TARGET_ELF32"
"
{
@@ -7236,3 +7241,48 @@
emit_insn (gen_blockage ());
DONE;
}")
+
+;; For TARGET_64BIT, the arg_pointer register is also used for millicode
+;; returns. The ABI requires that the arg_pointer be set for all calls.
+;; When the arg_pointer is made an eliminable register, eliminate_regs
+;; will eliminate the arg_pointer register from the function call setup and
+;; millicode returns unless the arg_pointer is hidden in a use, clobber or
+;; unspec.
+
+;; This is for loading the arg_pointer in function calls.
+(define_insn "addmovdi3"
+ [(set (unspec:DI [(match_operand:DI 0 "register_operand" "=r,r")] 0)
+ (plus:DI (match_operand:DI 1 "register_operand" "r,r")
+ (match_operand 2 "const_int_operand" "J,i")))
+ (set (match_dup 0) (match_dup 0))]
+ "TARGET_64BIT"
+ "@
+ ldo %2(%1),%0
+ ldil L'%G2,%0\;add,l %0,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "pa_combine_type" "addmove,none")
+ (set_attr "length" "4,8")])
+
+;; This is for millicode return.
+(define_expand "mov_from_r29_si"
+ [(set (match_operand:SI 0 "" "")
+ (unspec:SI [(reg:SI 29)] 0))]
+ ""
+ "
+{
+ if (!TARGET_64BIT)
+ {
+ rtx tmp = gen_rtx_REG (SImode, 29);
+ emit_insn (gen_movsi (operands[0], tmp));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(reg:SI 29)] 0))]
+ ""
+ "copy %%r29,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
2000-11-09 9:40 ` testcase for hppa64 gcc bug John David Anglin
@ 2000-11-09 16:17 ` Alan Modra
2000-12-05 20:11 ` Jeffrey A Law
1 sibling, 0 replies; 521+ messages in thread
From: Alan Modra @ 2000-11-09 16:17 UTC (permalink / raw)
To: gcc-patches
On Thu, 9 Nov 2000, John David Anglin wrote:
> I do find that Alan Modra's ARG_POINTER_INVARIANT patch needs to be installed
> to get correct code with his test case.
<Nag mode>This patch is identical in concept to this one
2000-10-24 Richard Henderson <rth@cygnus.com>
* rtlanal.c (rtx_unstable_p, rtx_varies_p): Don't consider pic
register stable if PIC_OFFSET_TABLE_REG_CALL_CLOBBERED.
Can someone please take a look at the patch?
http://gcc.gnu.org/ml/gcc-patches/2000-10/msg01028.html
<\Nag mode>
If it helps, I'm quite willing to negate the logic, and turn
ARG_POINTER_INVARIANT into ARG_POINTER_REG_CALL_CLOBBERED. I hadn't seen
Richard's patch when I made mine.
Alan Modra
--
Linuxcare. Support for the Revolution.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
2000-11-09 9:40 ` testcase for hppa64 gcc bug John David Anglin
2000-11-09 16:17 ` Alan Modra
@ 2000-12-05 20:11 ` Jeffrey A Law
2000-12-05 20:15 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jeffrey A Law @ 2000-12-05 20:11 UTC (permalink / raw)
To: John David Anglin; +Cc: alan, gcc-bugs, gcc-patches, parisc-linux
In message <200011091739.MAA07483@hiauly1.hia.nrc.ca>you write:
> For the record, here is my final patch regarding making the arg_pointer
> eliminable for TARGET_64BIT. I think the code it generates is correct but
> it hasn't been extensively tested. However, I don't recommend it for
> installation since in comparing the assembler code generated with and
> without elimination for a couple of test cases, I didn't observe any
> significant improvement in the code with the patch. Possibly, the patch
> implicitly disables elimination when the arg_pointer is needed.
>
> I do find that Alan Modra's ARG_POINTER_INVARIANT patch needs to be install
> ed
> to get correct code with his test case.
>
> There is one part of the patch below which I think needs to be installed.
> That is
>
> (call, call_value): Always USE the arg_pointer for TARGET_64BIT.
>
> The use for the arg_pointer needs to be pulled out of the `if (flag_pic)'.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2000-11-07 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa-linux64.h (ARG_POINTER_INVARIANT): Define even when the
> arg_pointer is being eliminated.
> (ELIMINABLE_REGS): Enable elimination of the arg_pointer.
> (INITIAL_ELIMINATION_OFFSET): Revise offsets for arg_pointer.
> * pa.md (mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
> canonicalize_funcptr_for_compare): Put "(reg:SI 26)" inside
> unspec to prevent elimination.
> (call, call_value): Always USE the arg_pointer for TARGET_64BIT.
> Use the new addmovdi3 insn to load the arg_pointer register.
> (addmovdi3 and mov_from_r29_si): New insn and expand which prevent
> r29 from being eliminated in call setups and millicode returns.
I haven't followed this discussion too closely. Is this patch still needed
after some of the recent changes in how we compute liveness for the argument
pointer?
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
2000-12-05 20:11 ` Jeffrey A Law
@ 2000-12-05 20:15 ` John David Anglin
2000-12-05 21:28 ` Alan Modra
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-12-05 20:15 UTC (permalink / raw)
To: law; +Cc: alan, gcc-bugs, gcc-patches, parisc-linux
> > 2000-11-07 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * pa-linux64.h (ARG_POINTER_INVARIANT): Define even when the
> > arg_pointer is being eliminated.
> > (ELIMINABLE_REGS): Enable elimination of the arg_pointer.
> > (INITIAL_ELIMINATION_OFFSET): Revise offsets for arg_pointer.
> > * pa.md (mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
> > canonicalize_funcptr_for_compare): Put "(reg:SI 26)" inside
> > unspec to prevent elimination.
> > (call, call_value): Always USE the arg_pointer for TARGET_64BIT.
> > Use the new addmovdi3 insn to load the arg_pointer register.
> > (addmovdi3 and mov_from_r29_si): New insn and expand which prevent
> > r29 from being eliminated in call setups and millicode returns.
> I haven't followed this discussion too closely. Is this patch still needed
> after some of the recent changes in how we compute liveness for the argument
> pointer?
I think this needs to be reexamined. Allan's ARG_POINTER_INVARIANT patch
might not be needed now.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
2000-12-05 20:15 ` John David Anglin
@ 2000-12-05 21:28 ` Alan Modra
2001-01-31 17:17 ` Jeffrey A Law
0 siblings, 1 reply; 521+ messages in thread
From: Alan Modra @ 2000-12-05 21:28 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-bugs, gcc-patches, parisc-linux
On Tue, 5 Dec 2000, John David Anglin wrote:
> > > 2000-11-07 John David Anglin <dave@hiauly1.hia.nrc.ca>
> > >
> > > * pa-linux64.h (ARG_POINTER_INVARIANT): Define even when the
> > > arg_pointer is being eliminated.
> > > (ELIMINABLE_REGS): Enable elimination of the arg_pointer.
> > > (INITIAL_ELIMINATION_OFFSET): Revise offsets for arg_pointer.
> > > * pa.md (mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
> > > canonicalize_funcptr_for_compare): Put "(reg:SI 26)" inside
> > > unspec to prevent elimination.
> > > (call, call_value): Always USE the arg_pointer for TARGET_64BIT.
> > > Use the new addmovdi3 insn to load the arg_pointer register.
> > > (addmovdi3 and mov_from_r29_si): New insn and expand which prevent
> > > r29 from being eliminated in call setups and millicode returns.
> > I haven't followed this discussion too closely. Is this patch still needed
> > after some of the recent changes in how we compute liveness for the argument
> > pointer?
>
> I think this needs to be reexamined. Allan's ARG_POINTER_INVARIANT patch
> might not be needed now.
It's still needed. The problem is that gcc thinks the arg pointer is
unchanged from the entry value to a function, even when the arg pointer
needs to be set to call other functions.
Actually, given the nature of the problem, I'm inclined to think that all
targets that use an arg pointer should probably define
ARG_POINTER_INVARIANT = 0. Or equivalently, don't apply my
ARG_POINTER_INVARIANT patch and simply remove tests for arg_pointer_rtx in
rtx_unstable_p, rtx_varies_p, rtx_addr_can_trap_p, function_invariant_p,
loop_invariant_p, and possibly other places I've missed.
Here's the testcase again:
extern void abort(void);
char p;
int f1 (char **);
int f2 (char *, char **);
char *f3 (char *a, char *b)
{
char *c = 0;
if (f1 (&b) != 0)
goto out;
/* hppa64 passes bogus value for b */
f2 (b, &c);
out:
return c;
}
int f1 (char **x)
{
if (*x != &p)
abort ();
return 0;
}
int f2 (char *a, char **b)
{
if (a != &p)
abort ();
*b += 1;
return 0;
}
int main (void)
{
if (f3 (0, &p) != (char *) 0 + 1)
abort ();
return 0;
}
Results of compiling with -O2 -S for hppa64-hpux11-gcc built from CVS
of less that an hour ago.
.LEVEL 2.0w
gcc2_compiled.:
.IMPORT f1,ENTRY
.IMPORT f2,ENTRY
.text
.align 8
.EXPORT f3,ENTRY
f3
.PROC
.CALLINFO FRAME=128,CALLS,SAVE_RP,ENTRY_GR=3
.ENTRY
std %r2,-16(%r30)
ldo -56(%r29),%r26 ! r26 = &b = r29 - 56
ldo 128(%r30),%r30
std %r4,-104(%r30)
copy %r27,%r4
std %r25,-56(%r29)
ldo -16(%r30),%r29
b,l f1,%r2
std %r0,-120(%r30)
ldo -16(%r30),%r29 ! arg pointer set to current frame
ldo -120(%r30),%r25
cmpib,= 0,%r28,L$0005
copy %r4,%r27
L$0004
ldd -120(%r30),%r28
L$0006
ldd -144(%r30),%r2
ldd -104(%r30),%r4
bve (%r2)
ldo -128(%r30),%r30
L$0005
ldo -64(%r29),%r29 ! r29 = curr_r30 - 16 - 64
b,l f2,%r2
ldd 8(%r29),%r26 ! try to load b from r29 - 56, but
! gcc misses fact that r29 has changed
b L$0006
ldd -120(%r30),%r28
.EXIT
.PROCEND
[snip]
--
Linuxcare. Support for the Revolution.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: testcase for hppa64 gcc bug
2000-12-05 21:28 ` Alan Modra
@ 2001-01-31 17:17 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2001-01-31 17:17 UTC (permalink / raw)
To: Alan Modra; +Cc: John David Anglin, gcc-bugs, gcc-patches, parisc-linux
In message <Pine.LNX.4.21.0012061607530.16721-100000@front.linuxcare.com.au>y
ou write:
> > I think this needs to be reexamined. Allan's ARG_POINTER_INVARIANT patch
> > might not be needed now.
>
> It's still needed. The problem is that gcc thinks the arg pointer is
> unchanged from the entry value to a function, even when the arg pointer
> needs to be set to call other functions.
But the incoming argument pointer should have been copied into a pseudo at
the start of the function and the new pseudo used to address incoming args.
That's the real problem here I think.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* PATCH: Re: ../../../libio/stream.cc:60: Internal error: Segmentation fault.
[not found] <no.id>
` (20 preceding siblings ...)
2000-11-09 9:40 ` testcase for hppa64 gcc bug John David Anglin
@ 2000-11-25 17:39 ` John David Anglin
2000-11-25 17:40 ` John David Anglin
2000-11-30 12:16 ` PATCH: HUGE_VAL should be Infinity John David Anglin
` (141 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-11-25 17:39 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> Program received signal SIGSEGV, Segmentation fault.
> 0x81df1aa in do_compare_and_jump (exp=0x40536de0, signed_code=GT,
> unsigned_code=GTU, if_false_label=0x40533e80, if_true_label=0x0)
> at ../../gcc/expr.c:10066
> 10066 > GET_MODE_BITSIZE (TREE_TYPE (TREE_OPERAND (exp, 1))))))
> (gdb) disass 0x81df1aa 0x81df1b0
> Dump of assembler code from 0x81df1aa to 0x81df1b0:
> 0x81df1aa <do_compare_and_jump+842>: mov 0x843d520(,%eax,4),%eax
> End of assembler dump.
> (gdb) info reg eax
> eax 0x40155400 1075139584
>
> I think one of the changes in the last week has caused this.
The enclosed patch appears to fix the problem. The bootstrap and check
now completes under i686 linux. However, there are a huge number of
failures in g++ related tests. For example,
spawn /home/dave/gnu/gcc-2.97/objdir/gcc/testsuite/../g++ -B/home/dave/gnu/gcc-2
.97/objdir/gcc/testsuite/../ /home/dave/gnu/gcc-2.97/gcc/testsuite/g++.old-deja/
g++.brendan/copy3.C -I/home/dave/gnu/gcc-2.97/libstdc++ -I/home/dave/gnu/gcc-2.9
7/libstdc++/stl -fmessage-length=0 -ansi -pedantic-errors -Wno-long-long -I/home
/dave/gnu/gcc-2.97/libio -I/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libi
o -lstdc++ -L/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++ -L/home
/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libiberty -lm -pthread -o /home/dav
e/gnu/gcc-2.97/objdir/gcc/testsuite/g++-brendan-copy3-C
/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++/libstdc++.a(exceptio
n.o): In function `_ZNK9exception4whatEv':
/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ex
ception.cc:403: undefined reference to `__cxa_bad_typeid'
/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++/libstdc++.a(tinfo2.o
): In function `_ZNK10__cxxabiv117__pbase_type_info10__do_catchEPK9type_infoPPvj
':
/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ti
nfo2.cc:176: undefined reference to `__cxa_bad_typeid'
/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ti
nfo2.cc:176: undefined reference to `__cxa_bad_typeid'
collect2: ld returned 1 exit status
Please review for installation.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ../../../libio/stream.cc:60: Internal error: Segmentation fault.
2000-11-25 17:39 ` PATCH: Re: ../../../libio/stream.cc:60: Internal error: Segmentation fault John David Anglin
@ 2000-11-25 17:40 ` John David Anglin
2000-11-29 21:48 ` Jeffrey A Law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-11-25 17:40 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
>
> > Program received signal SIGSEGV, Segmentation fault.
> > 0x81df1aa in do_compare_and_jump (exp=0x40536de0, signed_code=GT,
> > unsigned_code=GTU, if_false_label=0x40533e80, if_true_label=0x0)
> > at ../../gcc/expr.c:10066
> > 10066 > GET_MODE_BITSIZE (TREE_TYPE (TREE_OPERAND (exp, 1))))))
> > (gdb) disass 0x81df1aa 0x81df1b0
> > Dump of assembler code from 0x81df1aa to 0x81df1b0:
> > 0x81df1aa <do_compare_and_jump+842>: mov 0x843d520(,%eax,4),%eax
> > End of assembler dump.
> > (gdb) info reg eax
> > eax 0x40155400 1075139584
> >
> > I think one of the changes in the last week has caused this.
>
> The enclosed patch appears to fix the problem. The bootstrap and check
> now completes under i686 linux. However, there are a huge number of
> failures in g++ related tests. For example,
>
> spawn /home/dave/gnu/gcc-2.97/objdir/gcc/testsuite/../g++ -B/home/dave/gnu/gcc-2
> .97/objdir/gcc/testsuite/../ /home/dave/gnu/gcc-2.97/gcc/testsuite/g++.old-deja/
> g++.brendan/copy3.C -I/home/dave/gnu/gcc-2.97/libstdc++ -I/home/dave/gnu/gcc-2.9
> 7/libstdc++/stl -fmessage-length=0 -ansi -pedantic-errors -Wno-long-long -I/home
> /dave/gnu/gcc-2.97/libio -I/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libi
> o -lstdc++ -L/home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++ -L/home
> /dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libiberty -lm -pthread -o /home/dav
> e/gnu/gcc-2.97/objdir/gcc/testsuite/g++-brendan-copy3-C
> /home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++/libstdc++.a(exceptio
> n.o): In function `_ZNK9exception4whatEv':
> /home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ex
> ception.cc:403: undefined reference to `__cxa_bad_typeid'
> /home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu//libstdc++/libstdc++.a(tinfo2.o
> ): In function `_ZNK10__cxxabiv117__pbase_type_info10__do_catchEPK9type_infoPPvj
> ':
> /home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ti
> nfo2.cc:176: undefined reference to `__cxa_bad_typeid'
> /home/dave/gnu/gcc-2.97/objdir/i686-pc-linux-gnu/libstdc++/../../../libstdc++/ti
> nfo2.cc:176: undefined reference to `__cxa_bad_typeid'
> collect2: ld returned 1 exit status
>
> Please review for installation.
Oops!
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-11-25 John David Anglin <dave@hiauly1.hia.nrc.ca>
* expr.c (do_compare_and_jump): Add missing TYPE_MODE in statement.
--- expr.c.orig Sat Nov 25 17:33:17 2000
+++ expr.c Sat Nov 25 20:22:18 2000
@@ -10063,7 +10063,8 @@
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
|| (GET_MODE_BITSIZE (mode)
- > GET_MODE_BITSIZE (TREE_TYPE (TREE_OPERAND (exp, 1))))))
+ > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
+ 1)))))))
{
/* op0 might have been replaced by promoted constant, in which
case the type of second argument should be used. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
[not found] <no.id>
` (21 preceding siblings ...)
2000-11-25 17:39 ` PATCH: Re: ../../../libio/stream.cc:60: Internal error: Segmentation fault John David Anglin
@ 2000-11-30 12:16 ` John David Anglin
2000-12-03 21:14 ` Jeffrey A Law
2000-12-18 14:18 ` Revised patch: Re: PATCH 1: Re: BOOTSTRAP FAILURE: segementation fault in genattrtab John David Anglin
` (140 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2000-11-30 12:16 UTC (permalink / raw)
To: John David Anglin; +Cc: law, meissner, gcc-patches
> > Nyet. Recent HP chips (all PA2.0 variants) have fneg which provides an
> > ieee compliant negation.
>
> Wrong. I tried fneg on a C200 and again negation of +0. yielded +0. The
> behaviour was identical to that of the 735. Thus, I don't believe that
> all the new PA2.0 chips provide an ieee compliant negation. HP is usually
> pretty good about this kind of thing which was why I wondered if there
> was some debate about the standard.
I retested this and it appears that I made a mistake in my original testing.
The fneg instruction on PA2.0 gear does negate +0. correctly. Thus, there
is only a problem with PA1.0 and PA1.1 hardware which uses fsub. The HP
compiler doesn't have the problem since it multiplies by -1. instead.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
2000-11-30 12:16 ` PATCH: HUGE_VAL should be Infinity John David Anglin
@ 2000-12-03 21:14 ` Jeffrey A Law
2000-12-04 10:52 ` Michael Meissner
0 siblings, 1 reply; 521+ messages in thread
From: Jeffrey A Law @ 2000-12-03 21:14 UTC (permalink / raw)
To: John David Anglin; +Cc: meissner, gcc-patches
In message <200011302016.PAA28575@hiauly1.hia.nrc.ca>you write:
> The fneg instruction on PA2.0 gear does negate +0. correctly. Thus, there
> is only a problem with PA1.0 and PA1.1 hardware which uses fsub. The HP
> compiler doesn't have the problem since it multiplies by -1. instead.
I think there was a case where that's not 100% valid either, though I think
it would be closer to conforming behavior than fsub.
FWIW, it may be the case that PA1.0 had fneg -- I don't have my manuals
handy, but there were a few instructions in PA1.0 that got removed.
But I'm 100% certain fneg is available for PA2.0 and it does the right
thing (I already checked it some time ago).
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
2000-12-03 21:14 ` Jeffrey A Law
@ 2000-12-04 10:52 ` Michael Meissner
2000-12-04 11:25 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Michael Meissner @ 2000-12-04 10:52 UTC (permalink / raw)
To: law; +Cc: John David Anglin, meissner, gcc-patches
On Thu, Nov 30, 2000 at 11:19:21PM -0700, Jeffrey A Law wrote:
>
> In message <200011302016.PAA28575@hiauly1.hia.nrc.ca>you write:
> > The fneg instruction on PA2.0 gear does negate +0. correctly. Thus, there
> > is only a problem with PA1.0 and PA1.1 hardware which uses fsub. The HP
> > compiler doesn't have the problem since it multiplies by -1. instead.
> I think there was a case where that's not 100% valid either, though I think
> it would be closer to conforming behavior than fsub.
>
> FWIW, it may be the case that PA1.0 had fneg -- I don't have my manuals
> handy, but there were a few instructions in PA1.0 that got removed.
FWIW, FNEG is not in my 1989 manual, which I think is PA1.1.
> But I'm 100% certain fneg is available for PA2.0 and it does the right
> thing (I already checked it some time ago).
>
> jeff
--
Michael Meissner, Red Hat, Inc.
PMB 198, 174 Littleton Road #3, Westford, Massachusetts 01886, USA
Work: meissner@redhat.com phone: +1 978-486-9304
Non-work: meissner@spectacle-pond.org fax: +1 978-692-4482
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
2000-12-04 10:52 ` Michael Meissner
@ 2000-12-04 11:25 ` John David Anglin
2000-12-04 11:35 ` Jeffrey A Law
2000-12-06 18:05 ` Jeffrey A Law
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2000-12-04 11:25 UTC (permalink / raw)
To: Michael Meissner; +Cc: law, meissner, gcc-patches
> On Thu, Nov 30, 2000 at 11:19:21PM -0700, Jeffrey A Law wrote:
> >
> > In message <200011302016.PAA28575@hiauly1.hia.nrc.ca>you write:
> > > The fneg instruction on PA2.0 gear does negate +0. correctly. Thus, there
> > > is only a problem with PA1.0 and PA1.1 hardware which uses fsub. The HP
> > > compiler doesn't have the problem since it multiplies by -1. instead.
> > I think there was a case where that's not 100% valid either, though I think
> > it would be closer to conforming behavior than fsub.
> >
> > FWIW, it may be the case that PA1.0 had fneg -- I don't have my manuals
> > handy, but there were a few instructions in PA1.0 that got removed.
>
> FWIW, FNEG is not in my 1989 manual, which I think is PA1.1.
Last week, I had concluded that hpux 10.20 emulates fneg on my PA1.1 machine
(a 735).
I am planning to implement ieee compatible negdf2 and negsf2 insns for
PA1.X machines. It looked like multiplaction by -1 would be the most
efficient implementation since twiddling the sign bit of a floating
pointer register appears to involve copying to a general register via
memory and back again. Multiplaction also looks simpler. If Jeff can
recall whether or not there are corner effects with the multiplication
method it would be useful.
I have separated out a patch to make the hugeval test an expected failure
under HP-UX 9 and 10. As far as I can seen, there is no way to fix this
problem under these OS's because their math libraries are inconsistent
with the current IEEE definition of HUGE_VAL.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-11-30 J. David Anglin <dave@hiauly1.hia.nrc.ca>
* hugeval.x: New. Execution is expected to fail under hpux 9.X
and 10.X because HUGE_VAL is DBL_MAX instead of +Infinity.
--- gcc.c-torture/execute/ieee/hugeval.x.orig Wed Oct 18 13:51:17 2000
+++ gcc.c-torture/execute/ieee/hugeval.x Wed Oct 18 15:01:21 2000
@@ -0,0 +1,10 @@
+# This test fails under hpux 9.X and 10.X because HUGE_VAL is DBL_MAX
+# instead of +Infinity.
+
+global target_triplet
+if { [istarget "hppa*-*-hpux9*"] || [istarget "hppa*-*-hpux10*"] } {
+ set torture_execute_xfail "$target_triplet"
+}
+
+return 0
+
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
2000-12-04 11:25 ` John David Anglin
@ 2000-12-04 11:35 ` Jeffrey A Law
2000-12-06 18:05 ` Jeffrey A Law
1 sibling, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-12-04 11:35 UTC (permalink / raw)
To: John David Anglin; +Cc: Michael Meissner, gcc-patches
In message < 200012041925.OAA06848@hiauly1.hia.nrc.ca >you write:
> I am planning to implement ieee compatible negdf2 and negsf2 insns for
> PA1.X machines. It looked like multiplaction by -1 would be the most
> efficient implementation since twiddling the sign bit of a floating
> pointer register appears to involve copying to a general register via
> memory and back again. Multiplaction also looks simpler. If Jeff can
> recall whether or not there are corner effects with the multiplication
> method it would be useful.
Found it. fneg is non-arithmetic and does not cause an invalid operation
exception when a NaN is negated.
fmul is arithmetic and will cause exceptions. Basically using any kind
of arithmetic insn to implement fneg loses in some form or another.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: HUGE_VAL should be Infinity
2000-12-04 11:25 ` John David Anglin
2000-12-04 11:35 ` Jeffrey A Law
@ 2000-12-06 18:05 ` Jeffrey A Law
1 sibling, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2000-12-06 18:05 UTC (permalink / raw)
To: John David Anglin; +Cc: Michael Meissner, gcc-patches
In message < 200012041925.OAA06848@hiauly1.hia.nrc.ca >you write:
> 2000-11-30 J. David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * hugeval.x: New. Execution is expected to fail under hpux 9.X
> and 10.X because HUGE_VAL is DBL_MAX instead of +Infinity.
Thanks. Installed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Revised patch: Re: PATCH 1: Re: BOOTSTRAP FAILURE: segementation fault in genattrtab
[not found] <no.id>
` (22 preceding siblings ...)
2000-11-30 12:16 ` PATCH: HUGE_VAL should be Infinity John David Anglin
@ 2000-12-18 14:18 ` John David Anglin
2000-12-20 19:56 ` V3 PATCH: Some complex<> cleanup (1/2) Robert Lipe
` (139 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2000-12-18 14:18 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-bugs, gcc-patches
> Here is a revised patch. Tested with a bootstrap and check under hpux
> 10.20. Please review and install if OK.
With the same three patches used in the bootstrap and check done yesterday
< http://gcc.gnu.org/ml/gcc-patches/2000-12/msg00882.html >, plus the above
patch and CVS source from 20001217, I reran another bootstrap and check. The
results are here: < http://gcc.gnu.org/ml/gcc-testresults/2000-12/msg00195.html >.
There is one additional regression (g++.jason/2371.C) but all ports seem
to have started failing this test.
My assessment of the above patch is that is is not essential at the moment
but I am concerned that the REG_POINTER flag may be invalid for eliminated
registers after reload without it. Thus, either the patch should be applied
or some comment added to this effect. The register rename pass calls
gen_rtx_REG after reload.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
[not found] <no.id>
` (23 preceding siblings ...)
2000-12-18 14:18 ` Revised patch: Re: PATCH 1: Re: BOOTSTRAP FAILURE: segementation fault in genattrtab John David Anglin
@ 2000-12-20 19:56 ` Robert Lipe
2000-12-20 20:09 ` Benjamin Kosnik
2000-12-20 20:14 ` Gabriel Dos Reis
2000-12-28 22:29 ` problem with target builtin functions Herman ten Brugge
` (138 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: Robert Lipe @ 2000-12-20 19:56 UTC (permalink / raw)
To: Gabriel Dos Reis; +Cc: gcc-patches, libstdc++
Gabriel Dos Reis wrote:
> This patch removes special casing of std::sqrt(const complex<T>&)
> implementation. Hopefully, some of the problems reported in
>
> http://gcc.gnu.org/ml/gcc-bugs/2000-12/msg00158.html
>
> should go away.
Thank you. libmath now compiles for me on my system with C99 vendor
headers. I can see nothing int he ChangeLogs to make me suspect this
or any other recent, but after removing my various kludges and doing an
update in libstdc++-v3/ I now have a new error:
[ ... ]
Making all in libio
make[2]: Nothing to be done for `all'.
Making all in libmath
make[2]: Nothing to be done for `all'.
Making all in libsupc++
make[2]: Nothing to be done for `all'.
Making all in src
make[2]: *** No rule to make target `limitsMEMBERS.cc', needed by `limitsMEMBERS
.lo'. Stop.
It looks like this is supposed to be a generated file, but I don't see
anything obvious in Makefile* or configure* that generates it.
Thanx!
RJL
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
2000-12-20 19:56 ` V3 PATCH: Some complex<> cleanup (1/2) Robert Lipe
@ 2000-12-20 20:09 ` Benjamin Kosnik
2000-12-20 21:24 ` Robert Lipe
2000-12-20 21:59 ` Robert Lipe
2000-12-20 20:14 ` Gabriel Dos Reis
1 sibling, 2 replies; 521+ messages in thread
From: Benjamin Kosnik @ 2000-12-20 20:09 UTC (permalink / raw)
To: Robert Lipe; +Cc: Gabriel Dos Reis, gcc-patches, libstdc++
> Thank you. libmath now compiles for me on my system with C99 vendor
> headers. I can see nothing int he ChangeLogs to make me suspect this
> or any other recent, but after removing my various kludges and doing an
this part is good!
thanks Gaby.
> update in libstdc++-v3/ I now have a new error:
>
> [ ... ]
> Making all in libio
> make[2]: Nothing to be done for `all'.
> Making all in libmath
> make[2]: Nothing to be done for `all'.
> Making all in libsupc++
> make[2]: Nothing to be done for `all'.
> Making all in src
> make[2]: *** No rule to make target `limitsMEMBERS.cc', needed by `limitsMEMBERS
> .lo'. Stop.
... better, but now quite there yet..
> It looks like this is supposed to be a generated file, but I don't see
> anything obvious in Makefile* or configure* that generates it.
generated at configure time, by mknumeric_limits. What you can do is
rm stamp-limits
./config.status --recheck
in your build libstdc++-v3 directory. (Does stamp-limits exist?)
Look at the output from this, the very end part should look like this:
running mknumeric_limits
/mnt/hd/ahimsa/bld-x86-gcc-libio/i686-pc-linux-gnu/libstdc++-v3/../../gcc/g++ -B/mnt/hd/ahimsa/bld-x86-gcc-libio/i686-pc-linux-gnu/libstdc++-v3/../../gcc/ -I/mnt/hd/ahimsa/bld-x86-gcc-libio/i686-pc-linux-gnu/libstdc++-v3/include -o /mnt/hd/ahimsa/bld-x86-gcc-libio/i686-pc-linux-gnu/libstdc++-v3/src/gen-num-limits /mnt/hd/bliss/src.gcc/libstdc++-v3/src/gen-num-limits.cc -nodefaultlibs -lgcc -lc
It's probable that this doesn't end nicely for you.
Can you do this and post what you find?
thanks,
benjamin
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
2000-12-20 20:09 ` Benjamin Kosnik
@ 2000-12-20 21:24 ` Robert Lipe
2000-12-20 21:59 ` Robert Lipe
1 sibling, 0 replies; 521+ messages in thread
From: Robert Lipe @ 2000-12-20 21:24 UTC (permalink / raw)
To: Benjamin Kosnik; +Cc: Gabriel Dos Reis, gcc-patches, libstdc++
> > make[2]: *** No rule to make target `limitsMEMBERS.cc', needed by `limitsMEMBERS.lo'. Stop
>
> > It looks like this is supposed to be a generated file, but I don't see
> > anything obvious in Makefile* or configure* that generates it.
>
> generated at configure time, by mknumeric_limits. What you can do is
>
> rm stamp-limits
> ./config.status --recheck
I had suspected a configure-ish problem and had both run a config.status
--recheck and later (and rather therapeutically) a rm -r lib*v3 followed
by a manual configure invocation of lib*v3. Neither changed the
symptoms I observed.
So I removed my objdir, updated my whole src tree, fixed a syntax error
in haifa and then crashed into the new ICE in combine. I will try the
prompt suggestions from you and Gaby when the tree works again (sigh)
and get the results out.
Thanx for the fast help!
RJL
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
2000-12-20 20:09 ` Benjamin Kosnik
2000-12-20 21:24 ` Robert Lipe
@ 2000-12-20 21:59 ` Robert Lipe
2000-12-20 22:08 ` Benjamin Kosnik
1 sibling, 1 reply; 521+ messages in thread
From: Robert Lipe @ 2000-12-20 21:59 UTC (permalink / raw)
To: Benjamin Kosnik; +Cc: Gabriel Dos Reis, gcc-patches, libstdc++
Allrighty, after tweaks to gcc/Makefile to use -O0 when building
libgcc2, I'm back in the game, but this is my last message for the day.
> > make[2]: *** No rule to make target `limitsMEMBERS.cc', needed by `limitsMEMBERS
> > .lo'. Stop.
>
>
> > It looks like this is supposed to be a generated file, but I don't see
> > anything obvious in Makefile* or configure* that generates it.
>
> generated at configure time, by mknumeric_limits. What you can do is
>
> rm stamp-limits
> ./config.status --recheck
>
> in your build libstdc++-v3 directory. (Does stamp-limits exist?)
Yes, stamp-limits exists, though it becomes clearer now that it probably
should not. :-)
checking <ctype> for Solaris 2.6,7,8... no
checking <ctype> for Solaris 2.5.1... yes
checking for strtof... (cached) yes
checking for strtold declaration... no
checking for unistd.h... (cached) yes
checking for getpagesize... (cached) yes
checking for working mmap... (cached) no
updating cache ../config.cache
checking for locale.h... (cached) yes
checking for LC_MESSAGES... (cached) yes
checking for interface version number... v3
checking for --with-gxx-include-dir... no
checking for --enable-version-specific-runtime-libs... no
checking for /play/tmp/7/i686-pc-udk/libstdc++-v3/include
creating ./config.status
running mkc++config
running mknumeric_limits
/play/tmp/7/i686-pc-udk/libstdc++-v3/../../gcc/g++ -B/play/tmp/7/i686-pc-udk/lib
stdc++-v3/../../gcc/ -I/play/tmp/7/i686-pc-udk/libstdc++-v3/include -o /pla
y/tmp/7/i686-pc-udk/libstdc++-v3/src/gen-num-limits /play/egcs/libstdc++-v3/src/
gen-num-limits.cc -nodefaultlibs -lgcc -lc
In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:52:
/play/tmp/7/gcc/include/stdio.h:402:42: cstdio: No such file or directory
In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:53:
/play/tmp/7/gcc/include/signal.h:140:43: csignal: No such file or directory
In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:54:
/play/tmp/7/gcc/include/setjmp.h:75:43: csetjmp: No such file or directory
In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:55:
/play/tmp/7/gcc/include/math.h:786:41: cmath: No such file or directory
gen-num-limits failed to build, exiting.
Chasing this backwards, I can see the vendor <stdio.h> ends with:
#ifdef __cplusplus
}
#ifndef _CFRONT_3_0
#include <cstdio> /* for namespace std */
#endif
#endif /*__cplusplus*/
#endif /*_STDIO_H*/
Since we are C++ and we aren't CFRONT, we look for <cstdio>. There
isn't one in libstdc++-v3 and the g++ we just built doesn't know where
to find the vendor one (/udk/usr/include/CC). Where should we be
finding this? Should we be getting the ones from the above dir? Should
we perhaps be fixincluding this away? It's easy to swing it either way;
I just need help deciding which way is the Right Way.
Since the compilation failed, shouldn't we 'exit 1' somewhere and NOT
create the stamp file?
RJL
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
2000-12-20 21:59 ` Robert Lipe
@ 2000-12-20 22:08 ` Benjamin Kosnik
0 siblings, 0 replies; 521+ messages in thread
From: Benjamin Kosnik @ 2000-12-20 22:08 UTC (permalink / raw)
To: Robert Lipe; +Cc: Gabriel Dos Reis, gcc-patches, libstdc++
> Yes, stamp-limits exists, though it becomes clearer now that it probably
> should not. :-)
yep. It should not.
> checking <ctype> for Solaris 2.6,7,8... no
> checking <ctype> for Solaris 2.5.1... yes
> checking for strtof... (cached) yes
> checking for strtold declaration... no
> checking for unistd.h... (cached) yes
> checking for getpagesize... (cached) yes
> checking for working mmap... (cached) no
> updating cache ../config.cache
> checking for locale.h... (cached) yes
> checking for LC_MESSAGES... (cached) yes
> checking for interface version number... v3
> checking for --with-gxx-include-dir... no
> checking for --enable-version-specific-runtime-libs... no
> checking for /play/tmp/7/i686-pc-udk/libstdc++-v3/include
> creating ./config.status
> running mkc++config
> running mknumeric_limits
> /play/tmp/7/i686-pc-udk/libstdc++-v3/../../gcc/g++ -B/play/tmp/7/i686-pc-udk/lib
> stdc++-v3/../../gcc/ -I/play/tmp/7/i686-pc-udk/libstdc++-v3/include -o /pla
> y/tmp/7/i686-pc-udk/libstdc++-v3/src/gen-num-limits /play/egcs/libstdc++-v3/src/
> gen-num-limits.cc -nodefaultlibs -lgcc -lc
> In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:52:
> /play/tmp/7/gcc/include/stdio.h:402:42: cstdio: No such file or directory
> In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:53:
> /play/tmp/7/gcc/include/signal.h:140:43: csignal: No such file or directory
> In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:54:
> /play/tmp/7/gcc/include/setjmp.h:75:43: csetjmp: No such file or directory
> In file included from /play/egcs/libstdc++-v3/src/gen-num-limits.cc:55:
> /play/tmp/7/gcc/include/math.h:786:41: cmath: No such file or directory
> gen-num-limits failed to build, exiting.
>
Interesting. Thanks, this is very helpful. Includes like <cstdio> are in
include/std/
If you're up for it, you may want to add that include path to the compile
line above and see where that gets you.....
> Chasing this backwards, I can see the vendor <stdio.h> ends with:
>
> #ifdef __cplusplus
> }
> #ifndef _CFRONT_3_0
> #include <cstdio> /* for namespace std */
> #endif
> #endif /*__cplusplus*/
>
> #endif /*_STDIO_H*/
psycho.......... so what you could do is try adding it as above, or try
to add
#define _CFRONT_3_0 1
in a config/os/unixware/bits/os_defines.h
Anyway.
> Since we are C++ and we aren't CFRONT, we look for <cstdio>. There
> isn't one in libstdc++-v3 and the g++ we just built doesn't know where
> to find the vendor one (/udk/usr/include/CC). Where should we be
> finding this? Should we be getting the ones from the above dir? Should
> we perhaps be fixincluding this away? It's easy to swing it either way;
> I just need help deciding which way is the Right Way.
ugh. So they have one? I would prefer that we just fixinclude this.
> Since the compilation failed, shouldn't we 'exit 1' somewhere and NOT
> create the stamp file?
definitely. There's already been some mail about it. 'stamp-limits' was a
step in the right direction, but it only checks for the generation of
(bld)/include/bits/std_limits.h, blah blah blah....we should error out
sooner.
-benjamin
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: V3 PATCH: Some complex<> cleanup (1/2)
2000-12-20 19:56 ` V3 PATCH: Some complex<> cleanup (1/2) Robert Lipe
2000-12-20 20:09 ` Benjamin Kosnik
@ 2000-12-20 20:14 ` Gabriel Dos Reis
1 sibling, 0 replies; 521+ messages in thread
From: Gabriel Dos Reis @ 2000-12-20 20:14 UTC (permalink / raw)
To: Robert Lipe; +Cc: Gabriel Dos Reis, gcc-patches, libstdc++
Robert Lipe <robertl@sco.com> writes:
| Gabriel Dos Reis wrote:
|
| > This patch removes special casing of std::sqrt(const complex<T>&)
| > implementation. Hopefully, some of the problems reported in
| >
| > http://gcc.gnu.org/ml/gcc-bugs/2000-12/msg00158.html
| >
| > should go away.
|
| Thank you. libmath now compiles for me on my system with C99 vendor
| headers. I can see nothing int he ChangeLogs to make me suspect this
| or any other recent, but after removing my various kludges and doing an
| update in libstdc++-v3/ I now have a new error:
|
| [ ... ]
| Making all in libio
| make[2]: Nothing to be done for `all'.
| Making all in libmath
| make[2]: Nothing to be done for `all'.
| Making all in libsupc++
| make[2]: Nothing to be done for `all'.
| Making all in src
| make[2]: *** No rule to make target `limitsMEMBERS.cc', needed by `limitsMEMBERS
| .lo'. Stop.
Hmm... Usually this means something unfriendly went on at configure
time. Please, could you tell me whether something was wrong during
configuration?
| It looks like this is supposed to be a generated file, but I don't see
| anything obvious in Makefile* or configure* that generates it.
limitsMEMBERS.cc is generated by a shell (mknumeric_limits) script at
configure time.
-- Gaby
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: problem with target builtin functions
[not found] <no.id>
` (24 preceding siblings ...)
2000-12-20 19:56 ` V3 PATCH: Some complex<> cleanup (1/2) Robert Lipe
@ 2000-12-28 22:29 ` Herman ten Brugge
2001-01-14 14:39 ` PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when John David Anglin
` (137 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: Herman ten Brugge @ 2000-12-28 22:29 UTC (permalink / raw)
To: gcc-patches
Hello,
Some weeks ago I sent a patch that cured a problem with target builtin
functions. See:
http://gcc.gnu.org/ml/gcc-patches/2000-12/msg00596.html
I did mention that I did not test this on the arm and ia64 target. I have
done this now and the patch works also for both targets.
The testcase that fails for the ia64 is (compile with g++):
int a(int *c, int d);
int b(int *c, int d);
int a(int *c, int d) { return 0; }
int b(int *c, int d) { return a(c,d); }
The testcase that fails for the arm is:
void a(char *c);
void b(char *c);
void a(char *c) { ; }
void b(char *c) { a(c); }
The c-decl.c part of the patch can also be replaced by the patch from
"Joseph S. Myers". See:
http://gcc.gnu.org/ml/gcc-patches/2000-12/msg00082.html
This patch also calls MD_INIT_BUILTINS after creating void_list_node.
Herman.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when
[not found] <no.id>
` (25 preceding siblings ...)
2000-12-28 22:29 ` problem with target builtin functions Herman ten Brugge
@ 2001-01-14 14:39 ` John David Anglin
2001-01-14 17:00 ` Alan Modra
2001-01-23 8:32 ` pa.md bugfix John David Anglin
` (136 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-01-14 14:39 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
> > > This patch is not fully tested because I have not been able to complete
> > > a successful PIC bootstrap for other unrelated reasons. However, I know
> > > it corrects the ICE warning and I believe the PIC_OFFSET_TABLE_REGNUM_SAVED
> > > register should be a call used register as per the documentation of call
> > > used registers because it is a fixed register when PIC code is being
> > > generated.
> > >
> > > Dave
> > > --
> > > J. David Anglin dave.anglin@nrc.ca
> > > National Research Council of Canada (613) 990-0752 (FAX: 952-6
> > > 605)
> > >
> > > 2000-12-02 John David Anglin <dave@hiauly1.hia.nrc.ca>
> > >
> > > * pa32-regs.h (CONDITIONAL_REGISTER_USAGE): When generating pic code,
> > > PIC_OFFSET_TABLE_REGNUM_SAVED is a call_used register.
> > > * pa64-regs.h (CONDITIONAL_REGISTER_USAGE): Likewise.
> > Well, this patch is obviously correct, so I installed it.
>
> Oops, there is a problem. The PIC_OFFSET_TABLE_REGNUM_SAVED register
> must be call used under all conditions since non PIC code has to be able
> to call PIC code.
On further thought, the PIC_OFFSET_TABLE_REGNUM_SAVED can't be a call used
register since this will break the run-time ABI. I think this means that
it can't be a fixed register as well. Need a different solution.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when
2001-01-14 14:39 ` PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when John David Anglin
@ 2001-01-14 17:00 ` Alan Modra
2001-01-14 17:31 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Alan Modra @ 2001-01-14 17:00 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
On Sun, 14 Jan 2001, John David Anglin wrote:
> > > > * pa32-regs.h (CONDITIONAL_REGISTER_USAGE): When generating pic code,
> > > > PIC_OFFSET_TABLE_REGNUM_SAVED is a call_used register.
> > > > * pa64-regs.h (CONDITIONAL_REGISTER_USAGE): Likewise.
> > > Well, this patch is obviously correct, so I installed it.
> >
> > Oops, there is a problem. The PIC_OFFSET_TABLE_REGNUM_SAVED register
> > must be call used under all conditions since non PIC code has to be able
> > to call PIC code.
>
> On further thought, the PIC_OFFSET_TABLE_REGNUM_SAVED can't be a call used
> register since this will break the run-time ABI. I think this means that
> it can't be a fixed register as well. Need a different solution.
Why will that break the ABI? New code will just assume that r4 isn't
preserved over calls, but it's no problem if in fact r4 is preserved. It
would only be a problem if you were trying to make r4 call preserved when
before it was call used.
Alan Modra
--
Linuxcare. Support for the Revolution.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when
2001-01-14 17:00 ` Alan Modra
@ 2001-01-14 17:31 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-01-14 17:31 UTC (permalink / raw)
To: Alan Modra; +Cc: law, gcc-patches
> > > Oops, there is a problem. The PIC_OFFSET_TABLE_REGNUM_SAVED register
> > > must be call used under all conditions since non PIC code has to be able
> > > to call PIC code.
> >
> > On further thought, the PIC_OFFSET_TABLE_REGNUM_SAVED can't be a call used
> > register since this will break the run-time ABI. I think this means that
> > it can't be a fixed register as well. Need a different solution.
>
> Why will that break the ABI? New code will just assume that r4 isn't
> preserved over calls, but it's no problem if in fact r4 is preserved. It
If we make r4 call used, it isn't saved by the callee. That's how I
noticed that there was a problem in the first place. However, when r4
isn't call used, reload sometimes messes up. I need to go back and look
at why. However, I haven't had much luck with my builds lately.
It seems overkill to have both the caller and callee save r4.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: pa.md bugfix
[not found] <no.id>
` (26 preceding siblings ...)
2001-01-14 14:39 ` PATCH: PIC_OFFSET_TABLE_REGNUM_SAVED should be call used when John David Anglin
@ 2001-01-23 8:32 ` John David Anglin
2001-01-24 17:32 ` John David Anglin
` (135 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-01-23 8:32 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
> There is one issue and one potential optimisation that I can see with respect
> to this patch.
>
> > + ;; This can only be used in a leaf function, so we do
> > + ;; not need to use the PIC register.
> > (define_insn "return"
>
> This may not be correct. The ABI indicates that the PIC register must
> be correctly set when the function returns. This enables a correct return
> via a stub from a shared library. If +O3 is used, rename registers may
> use the PIC register if we don't have a use in the return. Remember,
> the PIC register is not a fixed register any more.
Hit self on head. It is fixed and as a result register rename won't
touch it.
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: pa.md bugfix
[not found] <no.id>
` (27 preceding siblings ...)
2001-01-23 8:32 ` pa.md bugfix John David Anglin
@ 2001-01-24 17:32 ` John David Anglin
2001-01-27 13:46 ` John David Anglin
2001-02-15 11:33 ` [PATCH] Re: REG_DEAD/REG_EQUIV problem John David Anglin
` (134 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-01-24 17:32 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches, gcc-bugs
> There is a problem with the patch with respect rename registers, although not
> not the one I thought would occur. It relates to having the use for r19
> present in the return for non PIC code. This causes a failure in
> verify_local_live_at_start.
This patch fixes the problem and regains the use of the PIC register in
non PIC code. I didn't try to fix the 64 bit mode problem that you
mentioned. I presume this applies to r2 as well.
I have now done a complete bootstrap under 10.20 with this patch and
this one < http://gcc.gnu.org/ml/gcc-patches/2001-01/msg01785.html >
which I previously warned as being untested. I did do several bootstraps
with it when it included EPILOGUE_USES.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-01-24 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.md (return): Revise comment.
(return_internal): Don't use PIC register.
(return_internal_pic): New pattern. Use PIC register.
(epilogue): Generate return_internal or return_internal_pic depending
on mode.
--- pa.md.save Wed Jan 24 13:27:15 2001
+++ pa.md Wed Jan 24 13:42:49 2001
@@ -5467,7 +5467,7 @@
;; Unconditional and other jump instructions.
;; This can only be used in a leaf function, so we do
-;; not need to use the PIC register.
+;; not need to use the PIC register for PIC mode.
(define_insn "return"
[(return)
(use (reg:SI 2))
@@ -5482,17 +5482,29 @@
[(set_attr "type" "branch")
(set_attr "length" "4")])
-;; Use a different pattern for functions which have non-trivial
-;; epilogues so as not to confuse jump and reorg.
-;;
-;; We use the PIC register to ensure it's restored after a
-;; call in PIC mode. This can be non-optimal for non-PIC
-;; code but the real world cost should be unmeasurable.
+;; Use a different return pattern for functions which have
+;; non-trivial epilogues so as not to confuse jump and reorg.
+;; This is for non PIC mode.
(define_insn "return_internal"
[(return)
- (use (match_operand:SI 0 "register_operand" "r"))
(use (reg:SI 2))
(const_int 1)]
+ ""
+ "*
+{
+ if (TARGET_PA_20)
+ return \"bve%* (%%r2)\";
+ return \"bv%* %%r0(%%r2)\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;; We use the PIC register to ensure it's restored after a
+;; call in PIC mode.
+(define_insn "return_internal_pic"
+ [(return)
+ (use (match_operand:SI 0 "register_operand" "r"))
+ (use (reg:SI 2))]
"true_regnum (operands[0]) == PIC_OFFSET_TABLE_REGNUM"
"*
{
@@ -5525,14 +5537,17 @@
/* Try to use the trivial return first. Else use the full
epilogue. */
if (hppa_can_use_return_insn_p ())
- emit_jump_insn (gen_return ());
+ emit_jump_insn (gen_return ());
else
{
rtx x;
hppa_expand_epilogue ();
- x = gen_return_internal (gen_rtx_REG (word_mode,
- PIC_OFFSET_TABLE_REGNUM));
+ if (flag_pic)
+ x = gen_return_internal_pic (gen_rtx_REG (word_mode,
+ PIC_OFFSET_TABLE_REGNUM));
+ else
+ x = gen_return_internal ();
emit_jump_insn (x);
}
DONE;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: pa.md bugfix
2001-01-24 17:32 ` John David Anglin
@ 2001-01-27 13:46 ` John David Anglin
2001-01-29 21:18 ` Jeffrey A Law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-01-27 13:46 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches, gcc-bugs
> > There is a problem with the patch with respect rename registers, although not
> > not the one I thought would occur. It relates to having the use for r19
> > present in the return for non PIC code. This causes a failure in
> > verify_local_live_at_start.
Here is a revised patch which should apply correctly with the current
source. Bootstrapped and checked under hpux 10.20.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-01-27 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.md (return): Revise comment for trivial return.
(return_internal): Non-trivial return pattern for non-PIC code.
(return_internal_pic): Non-trivial return pattern for PIC code.
It uses the PIC register to ensure it is restored after
function calls.
(epilogue): Generate appropriate return for PIC and non-PIC code.
--- pa.md.orig Sat Jan 27 00:21:51 2001
+++ pa.md Sat Jan 27 01:09:39 2001
@@ -5467,7 +5467,7 @@
;; Unconditional and other jump instructions.
;; This can only be used in a leaf function, so we do
-;; not need to use the PIC register.
+;; not need to use the PIC register when generating PIC code.
(define_insn "return"
[(return)
(use (reg:SI 2))
@@ -5482,17 +5482,28 @@
[(set_attr "type" "branch")
(set_attr "length" "4")])
-;; Use a different pattern for functions which have non-trivial
+;; Emit a different pattern for functions which have non-trivial
;; epilogues so as not to confuse jump and reorg.
-;;
-;; We use the PIC register to ensure it's restored after a
-;; call in PIC mode. This can be non-optimal for non-PIC
-;; code but the real world cost should be unmeasurable.
(define_insn "return_internal"
[(return)
- (use (match_operand 0 "register_operand" "r"))
(use (reg:SI 2))
(const_int 1)]
+ ""
+ "*
+{
+ if (TARGET_PA_20)
+ return \"bve%* (%%r2)\";
+ return \"bv%* %%r0(%%r2)\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;; Use the PIC register to ensure it's restored after a
+;; call in PIC mode.
+(define_insn "return_internal_pic"
+ [(return)
+ (use (match_operand 0 "register_operand" "r"))
+ (use (reg:SI 2))]
"true_regnum (operands[0]) == PIC_OFFSET_TABLE_REGNUM"
"*
{
@@ -5531,8 +5542,11 @@
rtx x;
hppa_expand_epilogue ();
- x = gen_return_internal (gen_rtx_REG (word_mode,
- PIC_OFFSET_TABLE_REGNUM));
+ if (flag_pic)
+ x = gen_return_internal_pic (gen_rtx_REG (word_mode,
+ PIC_OFFSET_TABLE_REGNUM));
+ else
+ x = gen_return_internal ();
emit_jump_insn (x);
}
DONE;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: pa.md bugfix
2001-01-27 13:46 ` John David Anglin
@ 2001-01-29 21:18 ` Jeffrey A Law
0 siblings, 0 replies; 521+ messages in thread
From: Jeffrey A Law @ 2001-01-29 21:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gcc-bugs
In message < 200101272145.QAA24380@hiauly1.hia.nrc.ca >you write:
> Here is a revised patch which should apply correctly with the current
> source. Bootstrapped and checked under hpux 10.20.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2001-01-27 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa.md (return): Revise comment for trivial return.
> (return_internal): Non-trivial return pattern for non-PIC code.
> (return_internal_pic): Non-trivial return pattern for PIC code.
> It uses the PIC register to ensure it is restored after
> function calls.
> (epilogue): Generate appropriate return for PIC and non-PIC code.
Thanks. I installed this with a minor change. Specifically
return_internal verifies that flag_pic is zero and return_internal_pic
verifies that flag_pic is nonzero.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Re: REG_DEAD/REG_EQUIV problem.
[not found] <no.id>
` (28 preceding siblings ...)
2001-01-24 17:32 ` John David Anglin
@ 2001-02-15 11:33 ` John David Anglin
2001-02-16 17:10 ` John David Anglin
2001-03-01 17:31 ` Enum related fixes for gcc build with native cc on vax ultrix John David Anglin
` (133 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-02-15 11:33 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gcc-bugs, alan
>
> > On Thu, 1 Feb 2001, Alan Modra wrote:
> >
> > > (insn 17 15 21 (set (reg/v:DI 69)
> > > (mem/u:DI (lo_sum:DI (reg:DI 70)
> > > (unspec:DI[
> > > (symbol_ref/v/f:DI ("*L$C0001"))
> > > ] 0)) 0)) 83 {*pa.md:2368} (insn_list 15 (nil))
> > > (expr_list:REG_EQUIV (mem/u:DI (lo_sum:DI (reg:DI 70)
> > > (unspec:DI[
> > > (symbol_ref/v/f:DI ("*L$C0001"))
> > > ] 0)) 0)
> > > (expr_list:REG_DEAD (reg:DI 70)
> > > (nil))))
> >
> > Whee, maybe I'll be a gcc hacker one day.
> >
> > This fixes the problem for me. I've no idea whether it's the ideal
> > solution - it may well be possible and desirable to prevent these
> > conflicting notes being issued.
> >
> > gcc/ChangeLog
> > * rtlanal.c (reg_death_note_p): New function.
> > (reg_mentioned_dies): New function.
> > * rtl.h (reg_mentioned_dies): Declare.
> > * reload1.c (reload): Don't set reg_equiv_memory_loc for an insn
> > that references memory via a reg that dies.
I am not certain this is totally sufficient. I think it is possible for this
type of situation to occur:
(set (reg: A) (plus (reg: PIC) (high:SI (symbol_ref:SI ("X")))))
(set (reg: B) (mem/u:SI (lo_sum:SI (reg/f: A) (unspec:SI[(symbol_ref:SI ("X")]))))
(set (reg: C) (mem/u:SI (lo_sum:SI (reg/f: A) (unspec:SI[(symbol_ref:SI ("X")]))))
(expr_list:REG_DEAD (reg: A) (nil))
...
(set (reg: D) (reg: B))
The last set may be in a different basic block than the one in which B is set.
Reload may try to substitute the MEM for B. It won't notice that the register
mentioned in the MEM is dead.
It would appear that we need to check whether any registers mentioned in
the MEM are still alive at the point where D is set before substituting.
I have a modified patch which stops the generation of the REG_EQUIV note
in local-alloc (see below). However, it won't work if the above situation
can occur.
There is also a problem with the above MEM being incorrectly substuted
into the insn at line 2099 of pa.md during reload. I believe this is because
the Q constraint is relaxed during reload:
/* Subroutine for EXTRA_CONSTRAINT.
Return 1 iff OP is a pseudo which did not get a hard register and
we are running the reload pass. */
#define IS_RELOADING_PSEUDO_P(OP) \
((reload_in_progress \
&& GET_CODE (OP) == REG \
&& REGNO (OP) >= FIRST_PSEUDO_REGISTER \
&& reg_renumber [REGNO (OP)] < 0))
/* Optional extra constraints for this machine. Borrowed from sparc.h.
For the HPPA, `Q' means that this is a memory operand but not a
symbolic memory operand. Note that an unassigned pseudo register
is such a memory operand. Needed because reload will generate
these things in insns and then not re-recognize the insns, causing
constrain_operands to fail.
`R' is used for scaled indexed addresses.
`S' is the constant 31.
`T' is for fp loads and stores. */
#define EXTRA_CONSTRAINT(OP, C) \
((C) == 'Q' ? \
(IS_RELOADING_PSEUDO_P (OP) \
|| (GET_CODE (OP) == MEM \
&& (memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
|| reload_in_progress) \
&& ! symbolic_memory_operand (OP, VOIDmode) \
&& !(GET_CODE (XEXP (OP, 0)) == PLUS \
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT))))\
: ((C) == 'R' ? \
(GET_CODE (OP) == MEM \
&& GET_CODE (XEXP (OP, 0)) == PLUS \
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT \
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT) \
&& (move_operand (OP, GET_MODE (OP)) \
|| memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
|| reload_in_progress)) \
I have modified symbolic_memory_operand to detect pic symbolic references
and would like to get rid of the reload_in_progress stuff in EXTRA_CONSTRAINT.
This seems bogus to me and an attempt to work around some kind of reload
bug. Maybe Jeff can recall why it is there?
A simple way to avoid the problem is to turn off the unchanging bit in
pic MEMs. This prevents the REG_EQUIV notes from being generated. I have
done a complete build with the unchanging bit off. There are two testsuite
failures that I don't think are present in non PIC builds and checks. These
are gcc.c-torture/compile/900313-1.c and gcc.c-torture/execute/941014-1.c:
Executing on host: /xxx/gnu/gcc-2.97/objdir/gcc/xgcc -B/xxx/gnu/gcc-2.97/objdir/gcc/ /xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c -w -O0 -c -fPIC -o /xxx/gnu/gcc-2.97/objdir/gcc/testsuite/900313-1.o (timeout = -1)
/xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c: In function `main':
/xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c:7: Insn does not satisfy its constraints:
(insn 104 55 107 (set (reg:SI 111)
(reg:SI 1 %r1)) 69 {*pa.md:2099} (nil)
(nil))
/xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c:7: confused by earlier errors, bailing out
I will try to figure out why SI 111 didn't get a hard register.
Comments?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-02-13 John David Anglin <dave@hiauly1.hia.nrc.ca>
* local-alloc.c (update_equiv_regs): Don't change a REG_EQUAL
note to REG_EQUIV note if the MEM contains a reference to a
register which dies in the insn.
* rtlanal.c (reg_death_note_p): New function.
(reg_mentioned_dies): New function.
* rtl.h (reg_mentioned_dies): Declare.
--- local-alloc.c.orig Fri Feb 2 00:54:57 2001
+++ local-alloc.c Tue Feb 13 17:42:12 2001
@@ -822,6 +822,7 @@
rtx set;
rtx dest, src;
int regno;
+ int mem_is_dead = 0;
if (GET_CODE (insn) == NOTE)
{
@@ -956,9 +957,19 @@
reg_equiv[regno].init_insns
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv[regno].init_insns);
+ /* Make sure that a MEM doesn't use a register that dies in
+ this insn. */
+ if (GET_CODE (src) == MEM)
+ {
+ rtx death = find_reg_note (insn, REG_DEAD, NULL_RTX);
+ if (death)
+ if (reg_mentioned_dies (src, death))
+ mem_is_dead = 1;
+ }
+
/* If this register is known to be equal to a constant, record that
it is always equivalent to the constant. */
- if (note && ! rtx_varies_p (XEXP (note, 0), 0))
+ if (note && ! mem_is_dead && ! rtx_varies_p (XEXP (note, 0), 0))
PUT_MODE (note, (enum machine_mode) REG_EQUIV);
/* If this insn introduces a "constant" register, decrease the priority
--- rtl.h.orig Sun Jan 7 13:39:19 2001
+++ rtl.h Mon Feb 12 15:08:06 2001
@@ -1403,6 +1403,7 @@
extern int computed_jump_p PARAMS ((rtx));
typedef int (*rtx_function) PARAMS ((rtx *, void *));
extern int for_each_rtx PARAMS ((rtx *, rtx_function, void *));
+extern int reg_mentioned_dies PARAMS ((rtx, rtx));
extern rtx regno_use_in PARAMS ((unsigned int, rtx));
extern int auto_inc_p PARAMS ((rtx));
extern void remove_node_from_expr_list PARAMS ((rtx, rtx *));
--- rtlanal.c.orig Thu Feb 8 14:05:50 2001
+++ rtlanal.c Mon Feb 12 15:08:06 2001
@@ -27,6 +27,7 @@
static void set_of_1 PARAMS ((rtx, rtx, void *));
static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int reg_death_note_p PARAMS ((rtx *, void *));
/* Forward declarations */
static int computed_jump_p_1 PARAMS ((rtx));
@@ -2327,6 +2328,34 @@
return 0;
}
+/* Predicate function for reg_mentioned_dies. */
+
+static int
+reg_death_note_p (reg, notes)
+ rtx *reg;
+ void *notes;
+{
+ rtx link;
+
+ if (GET_CODE (*reg) != REG)
+ return 0;
+
+ for (link = (rtx) notes; link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_DEAD && *reg == XEXP (link, 0))
+ return 1;
+ return 0;
+}
+
+/* Return 1 if any register found in INSN has a REG_DEAD note in NOTES. */
+
+int
+reg_mentioned_dies (insn, notes)
+ rtx insn;
+ rtx notes;
+{
+ return for_each_rtx (&insn, reg_death_note_p, notes);
+}
+
/* Searches X for any reference to REGNO, returning the rtx of the
reference found if any. Otherwise, returns NULL_RTX. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Re: REG_DEAD/REG_EQUIV problem.
2001-02-15 11:33 ` [PATCH] Re: REG_DEAD/REG_EQUIV problem John David Anglin
@ 2001-02-16 17:10 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-02-16 17:10 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gcc-bugs, alan
Following up on this,
> Executing on host: /xxx/gnu/gcc-2.97/objdir/gcc/xgcc -B/xxx/gnu/gcc-2.97/objdir/gcc/ /xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c -w -O0 -c -fPIC -o /xxx/gnu/gcc-2.97/objdir/gcc/testsuite/900313-1.o (timeout = -1)
> /xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c: In function `main':
> /xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c:7: Insn does not satisfy its constraints:
> (insn 104 55 107 (set (reg:SI 111)
> (reg:SI 1 %r1)) 69 {*pa.md:2099} (nil)
> (nil))
> /xxx/gnu/gcc-2.97/gcc/testsuite/gcc.c-torture/compile/900313-1.c:7: confused by earlier errors, bailing out
it appears that reload is behaving rather strangely. The following test
program will trigger the fault:
main ()
{
alloca ((int) &main);;
}
Here is the crucial rtl from lreg:
(insn 13 8 15 (set (reg:SI 97)
(plus:SI (reg:SI 19 %r19)
(high:SI (symbol_ref/u:SI ("*L$C0000"))))) 80 {*pa.md:2326} (nil)
(nil))
(insn 15 13 16 (set (reg:SI 97)
(mem:SI (lo_sum:SI (reg:SI 97)
(unspec:SI[
(symbol_ref/u:SI ("*L$C0000"))
] 0)) 0)) 82 {*pa.md:2352} (nil)
(nil))
(insn 16 15 18 (set (reg:SI 96)
(reg:SI 97)) 69 {*pa.md:2099} (nil)
(expr_list:REG_DEAD (reg:SI 97)
(nil)))
(insn 18 16 20 (set (reg:SI 97)
(mem:SI (reg:SI 96) 0)) 69 {*pa.md:2099} (nil)
(expr_list:REG_DEAD (reg:SI 96)
(nil)))
(insn 20 18 21 (set (reg:SI 96)
(reg:SI 97)) 69 {*pa.md:2099} (nil)
(expr_list:REG_DEAD (reg:SI 97)
(nil)))
For some reason not obvious to me, the reloads are not done properly for
insns 18 and 20. In paricular, SI 97 isn't eliminated. The rtl from the
greg pass is below. Any thoughts on what is going wrong?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
;; Function main
Spilling for insn 13.
Using reg 1 for reload 0
Spilling for insn 15.
Using reg 20 for reload 1
Spilling for insn 16.
Using reg 20 for reload 0
Using reg 20 for reload 1
Spilling for insn 18.
Using reg 20 for reload 0
Using reg 20 for reload 1
Spilling for insn 20.
Using reg 20 for reload 0
Using reg 20 for reload 1
Spilling for insn 21.
Using reg 20 for reload 1
Spilling for insn 22.
Using reg 21 for reload 0
Reloads for insn # 13
Reload 0: reload_out (SI) = (reg:SI 97)
R1_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 97)
reload_reg_rtx: (reg:SI 1 %r1)
Reloads for insn # 15
Reload 0: GENERAL_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 97)
Reload 1: reload_in (SI) = (reg:SI 97)
reload_out (SI) = (reg:SI 97)
GENERAL_REGS, RELOAD_OTHER (opnum = 1)
reload_in_reg: (reg:SI 97)
reload_out_reg: (reg:SI 97)
reload_reg_rtx: (reg:SI 20 %r20)
Reloads for insn # 16
Reload 0: reload_out (SI) = (reg:SI 96)
GENERAL_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 96)
reload_reg_rtx: (reg:SI 21 %r21)
Reload 1: reload_in (SI) = (reg:SI 97)
GENERAL_REGS, RELOAD_FOR_INPUT (opnum = 1)
reload_in_reg: (reg:SI 97)
reload_reg_rtx: (reg:SI 21 %r21)
Reloads for insn # 18
Reload 0: reload_in (SI) = (reg:SI 96)
GENERAL_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 1)
reload_in_reg: (reg:SI 96)
reload_reg_rtx: (reg:SI 1 %r1)
Reload 1: reload_out (SI) = (reg:SI 97)
GENERAL_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 97)
reload_reg_rtx: (reg:SI 1 %r1)
Reloads for insn # 20
Reload 0: reload_out (SI) = (reg:SI 96)
GENERAL_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 96)
reload_reg_rtx: (reg:SI 20 %r20)
Reload 1: reload_in (SI) = (reg:SI 97)
GENERAL_REGS, RELOAD_FOR_INPUT (opnum = 1)
reload_in_reg: (reg:SI 97)
reload_reg_rtx: (reg:SI 20 %r20)
Reloads for insn # 21
Reload 0: GENERAL_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:SI 96)
Reload 1: reload_in (SI) = (reg:SI 96)
reload_out (SI) = (reg:SI 96)
GENERAL_REGS, RELOAD_OTHER (opnum = 1)
reload_in_reg: (reg:SI 96)
reload_out_reg: (reg:SI 96)
reload_reg_rtx: (reg:SI 21 %r21)
Reloads for insn # 22
Reload 0: reload_in (SI) = (reg:SI 96)
GENERAL_REGS, RELOAD_FOR_INPUT (opnum = 1)
reload_in_reg: (reg:SI 96)
reload_reg_rtx: (reg:SI 1 %r1)
;; Register dispositions:
94 in 4 95 in 20 98 in 20 99 in 20 100 in 20
;; Hard regs used: 1 2 3 4 19 20 21 28 30
(note 2 0 42 NOTE_INSN_DELETED -1347440721)
;; Start of basic block 0, registers live: 3 [%r3] 19 [%r19] 30 [%r30]
(note 42 2 5 [bb 0] NOTE_INSN_BASIC_BLOCK -1347440721)
(insn 5 42 3 (set (reg:SI 4 %r4 [94])
(reg:SI 19 %r19)) 69 {*pa.md:2099} (nil)
(nil))
(note 3 5 6 NOTE_INSN_FUNCTION_BEG -1347440721)
(call_insn 6 3 8 (parallel[
(call (mem:SI (symbol_ref:SI ("@__main")) 0)
(const_int 16 [0x10]))
(clobber (reg:SI 2 %r2))
(use (const_int 0 [0x0]))
] ) 270 {call_internal_symref} (nil)
(expr_list:REG_EH_REGION (const_int 0 [0x0])
(nil))
(expr_list (use (reg:SI 19 %r19))
(nil)))
(insn 8 6 13 (set (reg:SI 19 %r19)
(reg:SI 4 %r4 [94])) 69 {*pa.md:2099} (nil)
(nil))
(insn 13 8 46 (set (reg:SI 1 %r1)
(plus:SI (reg:SI 19 %r19)
(high:SI (symbol_ref/u:SI ("*L$C0000"))))) 80 {*pa.md:2326} (nil)
(nil))
(insn 46 13 49 (set (mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 12 [0xc])) 0)
(reg:SI 1 %r1)) 69 {*pa.md:2099} (nil)
(nil))
(insn 49 46 15 (set (reg:SI 20 %r20)
(mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 12 [0xc])) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 15 49 52 (set (reg:SI 20 %r20)
(mem:SI (lo_sum:SI (reg:SI 20 %r20)
(unspec:SI[
(symbol_ref/u:SI ("*L$C0000"))
] 0)) 0)) 82 {*pa.md:2352} (nil)
(nil))
(insn 52 15 58 (set (mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 12 [0xc])) 0)
(reg:SI 20 %r20)) 69 {*pa.md:2099} (nil)
(nil))
(insn 58 52 16 (set (reg:SI 21 %r21)
(mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 12 [0xc])) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 16 58 55 (set (reg:SI 21 %r21)
(reg:SI 21 %r21)) 69 {*pa.md:2099} (nil)
(nil))
(insn 55 16 61 (set (mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)
(reg:SI 21 %r21)) 69 {*pa.md:2099} (nil)
(nil))
(insn 61 55 18 (set (reg:SI 1 %r1)
(mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 18 61 64 (set (reg:SI 1 %r1)
(mem:SI (reg:SI 1 %r1) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 64 18 70 (set (reg:SI 97)
(reg:SI 1 %r1)) 69 {*pa.md:2099} (nil)
(nil))
(insn 70 64 20 (set (reg:SI 20 %r20)
(reg:SI 97)) 69 {*pa.md:2099} (nil)
(nil))
(insn 20 70 67 (set (reg:SI 20 %r20)
(reg:SI 20 %r20)) 69 {*pa.md:2099} (nil)
(nil))
(insn 67 20 73 (set (mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)
(reg:SI 20 %r20)) 69 {*pa.md:2099} (nil)
(nil))
(insn 73 67 21 (set (reg:SI 21 %r21)
(mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 21 73 76 (set (reg:SI 21 %r21)
(plus:SI (reg:SI 21 %r21)
(const_int 7 [0x7]))) 169 {addsi3} (nil)
(nil))
(insn 76 21 79 (set (mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)
(reg:SI 21 %r21)) 69 {*pa.md:2099} (nil)
(nil))
(insn 79 76 22 (set (reg:SI 1 %r1)
(mem:SI (plus:SI (reg/f:SI 3 %r3)
(const_int 8 [0x8])) 0)) 69 {*pa.md:2099} (nil)
(nil))
(insn 22 79 23 (set (reg:SI 20 %r20 [95])
(plus:SI (reg:SI 1 %r1)
(const_int 7 [0x7]))) 169 {addsi3} (nil)
(nil))
(insn 23 22 25 (set (reg:SI 20 %r20 [98])
(lshiftrt:SI (reg:SI 20 %r20 [95])
(const_int 3 [0x3]))) 256 {lshrsi3} (nil)
(expr_list:REG_EQUAL (udiv:SI (reg:SI 20 %r20 [95])
(const_int 8 [0x8]))
(nil)))
(insn 25 23 27 (set (reg:SI 20 %r20 [99])
(reg:SI 20 %r20 [98])) 69 {*pa.md:2099} (nil)
(nil))
(insn 27 25 30 (set (reg:SI 20 %r20 [100])
(ashift:SI (reg:SI 20 %r20 [99])
(const_int 3 [0x3]))) 242 {*pa.md:5111} (nil)
(expr_list:REG_EQUAL (mult:SI (reg:SI 20 %r20 [98])
(const_int 8 [0x8]))
(nil)))
(insn 30 27 37 (set (reg/f:SI 30 %r30)
(plus:SI (reg/f:SI 30 %r30)
(reg:SI 20 %r20 [100]))) 169 {addsi3} (nil)
(nil))
(note 37 30 39 NOTE_INSN_FUNCTION_END -1347440721)
(insn 39 37 41 (clobber (reg/i:SI 28 %r28)) -1 (nil)
(nil))
(insn 41 39 43 (use (reg/i:SI 28 %r28)) -1 (nil)
(nil))
;; End of basic block 0, registers live:
3 [%r3] 19 [%r19] 28 [%r28] 30 [%r30]
(note 43 41 0 NOTE_INSN_DELETED -1347440721)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Enum related fixes for gcc build with native cc on vax ultrix
[not found] <no.id>
` (29 preceding siblings ...)
2001-02-15 11:33 ` [PATCH] Re: REG_DEAD/REG_EQUIV problem John David Anglin
@ 2001-03-01 17:31 ` John David Anglin
2001-03-01 17:51 ` Richard Henderson
2001-03-04 10:11 ` cpplib: basename () fix John David Anglin
` (132 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-03-01 17:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The patch has been bootstrapped under vax ultrix, and a complete bootstrap
> check has been done under i686 linux.
>
> Please review.
Some of this is now complete. I enclose what remains to be OK'd. In
my original post, I inadvertantly omitted the required changes to toplev.c.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-02-19 John David Anglin <dave@hiauly1.hia.nrc.ca>
* print-rtl.c (print_rtx): Cast enums to int for comparison.
* c-decl.c (grokdeclarator): Cast enums to int for comparison and
shifts.
* c-format.c (C_STD_VER): Cast to int for comparisons.
(check_function_format): Cast various enums to int for &.
(maybe_read_dollar_number): Likewise.
(check_format_info): Likewise.
(check_format_info_main): Likewise.
* function.c (purge_addressof_1): Revise to avoid using &= with enum
result.
* expr.c (emit_move_insn_1): Cast enums to unsigned int for comparison.
(safe_from_p): Likewise.
* varasm.c (const_hash): Cast enum to int for %.
* emit-rtl.c (init_emit_once): Use int loop variable to work around
pcc enum problems with < and ++ operators.
* regclass.c (init_reg_sets_1): Cast enums for comparison.
(choose_hard_reg_mode): Use unsigned int to iterate over CCmodes.
(regclass_init): Change enum class to int to iterate over reg_classes.
* genrecog.c (merge_trees): Cast enums for comparison.
* rtl.h (GET_CODE): Cast to enum rtx_code.
(PUT_CODE): Cast to ENUM_BITFIELD(rtx_code).
(GET_MODE): Cast to enum machine_mode.
(PUT_MODE): Cast to ENUM_BITFIELD(machine_mode).
(GET_NOTE_INSN_NAME): Cast enum to int.
* tree.h (TREE_CODE): Cast to enum tree_code.
(TREE_SET_CODE): Cast VALUE to ENUM_BITFIELD(tree_code).
* simplify-rtx.c (hash_rtx): Cast enums to unsigned unt.
* timevar.c (timevar_print): Change loop variable id from enum to
unsigned int.
* fixinc/fixincl.c (VLEVEL): Cast enums in comparison to unsigned int.
* fixinc/fixlib.h (bool_t): Add identifier `boolean' in typedef.
* fixinc/server.c (read_pipe_timeout): Use enum boolean instead of
bool_t in declaration because pcc can't combine volatile with typedef
types.
* config/i386/i386.md: Use PUT_MODE for mode assignment.
* toplev.c (compile_file): Cast enum DFI to int.
(decode_d_option): Likewise.
--- print-rtl.c.orig Fri Jan 5 18:30:02 2001
+++ print-rtl.c Mon Feb 19 12:32:23 2001
@@ -364,8 +364,8 @@
/* Print NOTE_INSN names rather than integer codes. */
case 'n':
- if (XINT (in_rtx, i) >= NOTE_INSN_BIAS
- && XINT (in_rtx, i) < NOTE_INSN_MAX)
+ if (XINT (in_rtx, i) >= (int) NOTE_INSN_BIAS
+ && XINT (in_rtx, i) < (int) NOTE_INSN_MAX)
fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i)));
else
fprintf (outfile, " %d", XINT (in_rtx, i));
--- c-decl.c.orig Fri Feb 16 17:17:22 2001
+++ c-decl.c Mon Feb 19 12:30:57 2001
@@ -3915,9 +3915,9 @@
if (TREE_CODE (id) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (id))
{
enum rid i = C_RID_CODE (id);
- if (i <= RID_LAST_MODIFIER)
+ if ((int) i <= (int) RID_LAST_MODIFIER)
{
- if (i == RID_LONG && specbits & (1<<i))
+ if (i == RID_LONG && specbits & (1 << (int) i))
{
if (longlong)
error ("`long long long' is too long for GCC");
@@ -3929,9 +3929,9 @@
longlong = 1;
}
}
- else if (specbits & (1 << i))
+ else if (specbits & (1 << (int) i))
pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
- specbits |= 1 << i;
+ specbits |= 1 << (int) i;
goto found;
}
}
--- c-format.c.orig Mon Feb 19 13:31:22 2001
+++ c-format.c Mon Feb 19 13:49:00 2001
@@ -476,11 +476,11 @@
or inheriting from, for the purpose of format features supported. */
#define CPLUSPLUS_STD_VER STD_C89
/* The C standard version we are checking formats against when pedantic. */
-#define C_STD_VER (c_language == clk_cplusplus \
+#define C_STD_VER ((int)(c_language == clk_cplusplus \
? CPLUSPLUS_STD_VER \
: (flag_isoc99 \
? STD_C99 \
- : (flag_isoc94 ? STD_C94 : STD_C89)))
+ : (flag_isoc94 ? STD_C94 : STD_C89))))
/* The name to give to the standard version we are warning about when
pedantic. FEATURE_VER is the version in which the feature warned out
appeared, which is higher than C_STD_VER. */
@@ -1105,7 +1105,8 @@
/* Yup; check it. */
check_format_info (status, info, params);
if (warn_missing_format_attribute && info->first_arg_num == 0
- && (format_types[info->format_type].flags & FMT_FLAG_ARG_CONVERT))
+ && (format_types[info->format_type].flags
+ & (int) FMT_FLAG_ARG_CONVERT))
{
function_format_info *info2;
for (info2 = function_format_list; info2; info2 = info2->next)
@@ -1298,7 +1299,7 @@
nalloc - dollar_arguments_alloc);
dollar_arguments_alloc = nalloc;
}
- if (!(fki->flags & FMT_FLAG_DOLLAR_MULTIPLE)
+ if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
&& dollar_arguments_used[argnum - 1] == 1)
{
dollar_arguments_used[argnum - 1] = 2;
@@ -1434,7 +1435,7 @@
/* Functions taking a va_list normally pass a non-literal format
string. These functions typically are declared with
first_arg_num == 0, so avoid warning in those cases. */
- if (!(format_types[info->format_type].flags & FMT_FLAG_ARG_CONVERT))
+ if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
{
/* For strftime-like formats, warn for not checking the format
string; but there are no arguments to check. */
@@ -1746,7 +1747,7 @@
}
flag_chars[0] = 0;
- if ((fki->flags & FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
+ if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
{
/* Possibly read a $ operand number at the start of the format.
If one was previously used, one is required here. If one
@@ -1867,7 +1868,7 @@
++format_chars;
}
if (found_width && !non_zero_width_char &&
- (fki->flags & FMT_FLAG_ZERO_WIDTH_BAD))
+ (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
status_warning (status, "zero width in %s format",
fki->name);
if (found_width)
@@ -1954,7 +1955,7 @@
}
else
{
- if (!(fki->flags & FMT_FLAG_EMPTY_PREC_OK)
+ if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
&& !ISDIGIT (*format_chars))
status_warning (status, "empty precision in %s format",
fki->name);
@@ -2025,7 +2026,7 @@
}
/* Handle the scanf allocation kludge. */
- if (fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
+ if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
{
if (*format_chars == 'a' && !flag_isoc99)
{
@@ -2043,7 +2044,8 @@
format_char = *format_chars;
if (format_char == 0
- || (!(fki->flags & FMT_FLAG_FANCY_PERCENT_OK) && format_char == '%'))
+ || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
+ && format_char == '%'))
{
status_warning (status, "conversion lacks type at end of format");
continue;
@@ -2109,7 +2111,7 @@
flag_chars[i - d] = 0;
}
- if ((fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
+ if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
&& strchr (flag_chars, 'a') != 0)
aflag = 1;
@@ -2190,7 +2192,7 @@
wanted_type = 0;
wanted_type_name = 0;
- if (fki->flags & FMT_FLAG_ARG_CONVERT)
+ if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
{
wanted_type = (fci->types[length_chars_val].type
? *fci->types[length_chars_val].type : 0);
--- function.c.orig Fri Feb 16 17:17:29 2001
+++ function.c Wed Feb 28 16:14:35 2001
@@ -2996,9 +2996,10 @@
memory. */
if (code == SET)
{
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
- return result;
+ if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
+ && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
+ return true;
+ return false;
}
else if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
@@ -3230,9 +3231,10 @@
}
else if (code == SET)
{
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
- return result;
+ if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
+ && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
+ return true;
+ return false;
}
/* Scan all subexpressions. */
@@ -3240,10 +3242,19 @@
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
{
if (*fmt == 'e')
- result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
+ {
+ if (result == true
+ && purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht) == false)
+ result = false;
+ }
else if (*fmt == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
+ {
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (result == true
+ && purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht)
+ == false)
+ result = false;
+ }
}
return result;
--- expr.c.orig Sun Feb 4 17:43:59 2001
+++ expr.c Wed Feb 28 16:54:19 2001
@@ -2766,7 +2766,7 @@
enum mode_class class = GET_MODE_CLASS (mode);
unsigned int i;
- if (mode >= MAX_MACHINE_MODE)
+ if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
abort ();
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -5766,7 +5766,8 @@
/* If this is a language-specific tree code, it may require
special handling. */
- if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+ if ((unsigned int) TREE_CODE (exp)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
&& lang_safe_from_p
&& !(*lang_safe_from_p) (x, exp))
return 0;
--- varasm.c.orig Sun Feb 4 03:29:46 2001
+++ varasm.c Mon Feb 19 22:17:35 2001
@@ -2431,7 +2431,7 @@
default:
/* A language specific constant. Just hash the code. */
- return code % MAX_HASH_TABLE;
+ return (int) code % MAX_HASH_TABLE;
}
/* Compute hashing function */
--- emit-rtl.c.orig Sun Feb 4 17:43:58 2001
+++ emit-rtl.c Tue Feb 20 00:09:00 2001
@@ -4139,9 +4139,9 @@
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
}
- for (mode = CCmode; mode < MAX_MACHINE_MODE; ++mode)
- if (GET_MODE_CLASS (mode) == MODE_CC)
- const_tiny_rtx[0][(int) mode] = const0_rtx;
+ for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
+ if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
+ const_tiny_rtx[0][i] = const0_rtx;
const_tiny_rtx[0][(int) BImode] = const0_rtx;
if (STORE_FLAG_VALUE == 1)
--- regclass.c.orig Mon Feb 19 16:49:40 2001
+++ regclass.c Tue Feb 27 16:11:58 2001
@@ -430,7 +430,7 @@
}
memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
- for (m = 0; m < MAX_MACHINE_MODE; m++)
+ for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
for (i = 0; i < N_REG_CLASSES; i++)
if (CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
@@ -445,7 +445,7 @@
/* Initialize the move cost table. Find every subset of each class
and take the maximum cost of moving any subset to any other. */
- for (m = 0; m < MAX_MACHINE_MODE; m++)
+ for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
if (allocatable_regs_of_mode [m])
{
for (i = 0; i < N_REG_CLASSES; i++)
@@ -631,6 +631,7 @@
unsigned int regno ATTRIBUTE_UNUSED;
unsigned int nregs;
{
+ unsigned int /* enum machine_mode */ m;
enum machine_mode found_mode = VOIDmode, mode;
/* We first look for the largest integer mode that can be validly
@@ -658,10 +659,13 @@
return found_mode;
/* Iterate over all of the CCmodes. */
- for (mode = CCmode; mode < NUM_MACHINE_MODES; ++mode)
- if (HARD_REGNO_NREGS (regno, mode) == nregs
- && HARD_REGNO_MODE_OK (regno, mode))
- return mode;
+ for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m)
+ {
+ mode = (enum machine_mode) m;
+ if (HARD_REGNO_NREGS (regno, mode) == nregs
+ && HARD_REGNO_MODE_OK (regno, mode))
+ return mode;
+ }
/* We can't find a mode valid for this register. */
return VOIDmode;
@@ -859,22 +863,23 @@
int i;
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
- enum reg_class class;
+ int /* enum reg_class */ class;
if (REG_N_REFS (i))
{
fprintf (dump, " Register %i costs:", i);
- for (class = 0; class < N_REG_CLASSES; class++)
- if (contains_reg_of_mode [class][PSEUDO_REGNO_MODE (i)]
+ for (class = 0; class < (int) N_REG_CLASSES; class++)
+ if (contains_reg_of_mode [(enum reg_class) class][PSEUDO_REGNO_MODE (i)]
#ifdef FORBIDDEN_INC_DEC_CLASSES
- && (!in_inc_dec[i] || !forbidden_inc_dec_class[class])
+ && (!in_inc_dec[i]
+ || !forbidden_inc_dec_class[(enum reg_class) class])
#endif
#ifdef CLASS_CANNOT_CHANGE_MODE
&& (!REGNO_REG_SET_P (reg_changes_mode, i)
- || class_can_change_mode [class])
+ || class_can_change_mode [(enum reg_class) class])
#endif
)
- fprintf (dump, " %s:%i", reg_class_names[(int) class],
- costs[i].cost[class]);
+ fprintf (dump, " %s:%i", reg_class_names[class],
+ costs[i].cost[(enum reg_class) class]);
fprintf (dump, " MEM:%i\n", costs[i].mem_cost);
}
}
--- genrecog.c.orig Sun Jan 14 15:35:06 2001
+++ genrecog.c Tue Feb 20 14:34:17 2001
@@ -1432,7 +1432,7 @@
how expensive/important the test is. Given that the tests
are also ordered within the list, examining the first is
sufficient. */
- if (add->tests->type < old->tests->type)
+ if ((int) add->tests->type < (int) old->tests->type)
insert_before = old;
}
--- rtl.h.orig Sun Feb 18 23:52:53 2001
+++ rtl.h Tue Feb 20 15:38:54 2001
@@ -184,11 +184,11 @@
/* Define macros to access the `code' field of the rtx. */
-#define GET_CODE(RTX) ((RTX)->code)
-#define PUT_CODE(RTX, CODE) ((RTX)->code = (CODE))
+#define GET_CODE(RTX) ((enum rtx_code) (RTX)->code)
+#define PUT_CODE(RTX, CODE) ((RTX)->code = (ENUM_BITFIELD(rtx_code)) (CODE))
-#define GET_MODE(RTX) ((RTX)->mode)
-#define PUT_MODE(RTX, MODE) ((RTX)->mode = (MODE))
+#define GET_MODE(RTX) ((enum machine_mode) (RTX)->mode)
+#define PUT_MODE(RTX, MODE) ((RTX)->mode = (ENUM_BITFIELD(machine_mode)) (MODE))
#define RTX_INTEGRATED_P(RTX) ((RTX)->integrated)
#define RTX_UNCHANGING_P(RTX) ((RTX)->unchanging)
@@ -702,7 +702,7 @@
extern const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS];
#define GET_NOTE_INSN_NAME(NOTE_CODE) \
- (note_insn_name[(NOTE_CODE) - NOTE_INSN_BIAS])
+ (note_insn_name[(NOTE_CODE) - (int) NOTE_INSN_BIAS])
/* The name of a label, in case it corresponds to an explicit label
in the input source code. */
--- tree.h.orig Fri Feb 16 17:17:38 2001
+++ tree.h Wed Feb 21 10:53:19 2001
@@ -274,7 +274,8 @@
/* The tree-code says what kind of node it is.
Codes are defined in tree.def. */
#define TREE_CODE(NODE) ((enum tree_code) (NODE)->common.code)
-#define TREE_SET_CODE(NODE, VALUE) ((NODE)->common.code = (int) (VALUE))
+#define TREE_SET_CODE(NODE, VALUE) \
+((NODE)->common.code = (ENUM_BITFIELD(tree_code)) (VALUE))
/* When checking is enabled, errors will be generated if a tree node
is accessed incorrectly. The macros abort with a fatal error. */
--- simplify-rtx.c.orig Tue Feb 6 07:39:15 2001
+++ simplify-rtx.c Wed Feb 21 10:49:42 2001
@@ -2640,7 +2640,7 @@
case CONST_INT:
hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + INTVAL (x);
- return hash ? hash : CONST_INT;
+ return hash ? hash : (unsigned int) CONST_INT;
case CONST_DOUBLE:
/* This is like the general case, except that it only counts
@@ -2652,18 +2652,18 @@
else
hash += ((unsigned) CONST_DOUBLE_LOW (x)
+ (unsigned) CONST_DOUBLE_HIGH (x));
- return hash ? hash : CONST_DOUBLE;
+ return hash ? hash : (unsigned int) CONST_DOUBLE;
/* Assume there is only one rtx object for any given label. */
case LABEL_REF:
hash
+= ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
- return hash ? hash : LABEL_REF;
+ return hash ? hash : (unsigned int) LABEL_REF;
case SYMBOL_REF:
hash
+= ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
- return hash ? hash : SYMBOL_REF;
+ return hash ? hash : (unsigned int) SYMBOL_REF;
case PRE_DEC:
case PRE_INC:
@@ -2737,7 +2737,7 @@
abort ();
}
- return hash ? hash : 1 + GET_CODE (x);
+ return hash ? hash : 1 + (unsigned int) GET_CODE (x);
}
/* Create a new value structure for VALUE and initialize it. The mode of the
--- timevar.c.orig Wed Sep 6 03:02:40 2000
+++ timevar.c Wed Feb 21 14:01:41 2001
@@ -401,7 +401,7 @@
{
/* Only print stuff if we have some sort of time information. */
#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME)
- timevar_id_t id;
+ unsigned int /* timevar_id_t */ id;
struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed;
struct timevar_time_def now;
@@ -426,13 +426,13 @@
start_time = now;
fprintf (fp, _("\nExecution times (seconds)\n"));
- for (id = 0; id < TIMEVAR_LAST; ++id)
+ for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
{
- struct timevar_def *tv = &timevars[id];
+ struct timevar_def *tv = &timevars[(timevar_id_t) id];
/* Don't print the total execution time here; that goes at the
end. */
- if (id == TV_TOTAL)
+ if ((timevar_id_t) id == TV_TOTAL)
continue;
/* Don't print timing variables that were never used. */
--- fixinc/fixincl.c.orig Tue Feb 6 17:17:08 2001
+++ fixinc/fixincl.c Wed Feb 21 15:47:24 2001
@@ -67,7 +67,7 @@
te_verbose verbose_level = VERB_PROGRESS;
int have_tty = 0;
-#define VLEVEL(l) (verbose_level >= l)
+#define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
#define NOT_SILENT VLEVEL(VERB_FIXES)
pid_t process_chain_head = (pid_t) -1;
--- fixinc/fixlib.h.orig Wed Dec 13 15:07:46 2000
+++ fixinc/fixlib.h Wed Feb 21 17:54:05 2001
@@ -88,7 +88,7 @@
#define IGNORE_ARG(a) ((void)(a))
-typedef enum
+typedef enum boolean
{
BOOL_FALSE, BOOL_TRUE
} t_bool;
--- fixinc/server.c.orig Wed Feb 21 17:54:28 2001
+++ fixinc/server.c Wed Feb 21 17:55:11 2001
@@ -57,7 +57,7 @@
# define volatile
#endif
-STATIC volatile t_bool read_pipe_timeout;
+STATIC volatile enum boolean read_pipe_timeout;
STATIC pid_t server_master_pid = NOPROCESS;
tSCC* def_args[] =
--- config/i386/i386.md.orig Mon Feb 26 19:43:06 2001
+++ config/i386/i386.md Tue Feb 27 18:46:45 2001
@@ -11784,7 +11784,7 @@
operands[1] = gen_lowpart (SImode, operands[1]);
if (GET_CODE (operands[3]) != ASHIFT)
operands[2] = gen_lowpart (SImode, operands[2]);
- GET_MODE (operands[3]) = SImode;")
+ PUT_MODE (operands[3], SImode);")
(define_split
[(set (reg 17)
--- toplev.c.orig Wed Feb 21 18:19:38 2001
+++ toplev.c Thu Mar 1 17:20:43 2001
@@ -2520,7 +2520,7 @@
{
int i;
- for (i = 0; i < DFI_MAX; ++i)
+ for (i = 0; i < (int) DFI_MAX; ++i)
if (dump_file[i].initialized && dump_file[i].graph_dump_p)
{
char seq[16];
@@ -4014,7 +4014,7 @@
switch (c = *arg++)
{
case 'a':
- for (i = 0; i < DFI_MAX; ++i)
+ for (i = 0; i < (int) DFI_MAX; ++i)
dump_file[i].enabled = 1;
break;
case 'A':
@@ -4045,7 +4045,7 @@
default:
matched = 0;
- for (i = 0; i < DFI_MAX; ++i)
+ for (i = 0; i < (int) DFI_MAX; ++i)
if (c == dump_file[i].debug_switch)
{
dump_file[i].enabled = 1;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Enum related fixes for gcc build with native cc on vax ultrix
2001-03-01 17:31 ` Enum related fixes for gcc build with native cc on vax ultrix John David Anglin
@ 2001-03-01 17:51 ` Richard Henderson
2001-03-02 15:47 ` John David Anglin
2001-03-04 10:28 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2001-03-01 17:51 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Thu, Mar 01, 2001 at 08:31:12PM -0500, John David Anglin wrote:
> - if (i == RID_LONG && specbits & (1<<i))
> + if (i == RID_LONG && specbits & (1 << (int) i))
Parenthesis error around "&" vs "&&". It was broken before, but...
> - result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
> - result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
> - return result;
> + if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
> + && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
> + return true;
> + return false;
Eh? Perhaps this gets fixed with Zack's boolean cleanup patch.
> -typedef enum
> +typedef enum boolean
Wait for Zack's commit to kill this.
Otherwise it's ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Enum related fixes for gcc build with native cc on vax ultrix
2001-03-01 17:51 ` Richard Henderson
@ 2001-03-02 15:47 ` John David Anglin
2001-03-04 10:28 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-02 15:47 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, bkorb
> > - result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
> > - result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
> > - return result;
> > + if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
> > + && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
> > + return true;
> > + return false;
>
> Eh? Perhaps this gets fixed with Zack's boolean cleanup patch.
Yes, I believe that this is fixed in the main but not the branch. Zack
is not going to patch the branch. If the `Eh' applies to the code, I
believe that the code rework is correct to the best of my knowledge
given my understanding of the constant representations for the enums
true and false (see hash.h) but I could be wrong.
> > -typedef enum
> > +typedef enum boolean
>
> Wait for Zack's commit to kill this.
Zack's commit didn't kill this and he doesn't want to touch it, so I
have copied Bruce Korb.
So, this is what remains to be approved to get vax ultrix bootstrapping
again with the native compiler:
1) For the 3.0 branch,
2001-02-19 John David Anglin <dave@hiauly1.hia.nrc.ca>
* function.c (purge_addressof_1): Revise to avoid using &= with enum
result.
--- function.c.orig Fri Feb 16 17:17:29 2001
+++ function.c Wed Feb 28 16:14:35 2001
@@ -2996,9 +2996,10 @@
memory. */
if (code == SET)
{
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
- return result;
+ if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
+ && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
+ return true;
+ return false;
}
else if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
@@ -3230,9 +3231,10 @@
}
else if (code == SET)
{
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
- return result;
+ if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
+ && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
+ return true;
+ return false;
}
/* Scan all subexpressions. */
@@ -3240,10 +3242,19 @@
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
{
if (*fmt == 'e')
- result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
+ {
+ if (result == true
+ && purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht) == false)
+ result = false;
+ }
else if (*fmt == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
+ {
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (result == true
+ && purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht)
+ == false)
+ result = false;
+ }
}
return result;
2) For the main and the branch,
2001-02-19 John David Anglin <dave@hiauly1.hia.nrc.ca>
* fixinc/fixlib.h (bool_t): Add identifier `boolean' in typedef.
* fixinc/server.c (read_pipe_timeout): Use enum boolean instead of
bool_t in declaration because pcc can't combine volatile with typedef
types.
--- fixinc/fixlib.h.orig Wed Dec 13 15:07:46 2000
+++ fixinc/fixlib.h Wed Feb 21 17:54:05 2001
@@ -88,7 +88,7 @@
#define IGNORE_ARG(a) ((void)(a))
-typedef enum
+typedef enum boolean
{
BOOL_FALSE, BOOL_TRUE
} t_bool;
--- fixinc/server.c.orig Wed Feb 21 17:54:28 2001
+++ fixinc/server.c Wed Feb 21 17:55:11 2001
@@ -57,7 +57,7 @@
# define volatile
#endif
-STATIC volatile t_bool read_pipe_timeout;
+STATIC volatile enum boolean read_pipe_timeout;
STATIC pid_t server_master_pid = NOPROCESS;
tSCC* def_args[] =
3) The trivial fix to cplus-dem.c in libiberty for the main and branch,
2001-02-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cplus-dem.c (main): Cast enum style to int.
--- cplus-dem.c.orig Sun Feb 18 14:06:37 2001
+++ cplus-dem.c Wed Feb 21 21:38:12 2001
@@ -5148,7 +5148,7 @@
skip_first = i;
mbuffer[i] = 0;
- flags |= style;
+ flags |= (int) style;
result = cplus_demangle (mbuffer + skip_first, flags);
if (result)
{
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Enum related fixes for gcc build with native cc on vax ultrix
2001-03-01 17:51 ` Richard Henderson
2001-03-02 15:47 ` John David Anglin
@ 2001-03-04 10:28 ` John David Anglin
2001-03-04 11:20 ` Richard Henderson
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-03-04 10:28 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches
> > - result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
> > - result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
> > - return result;
> > + if (purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht) == true
> > + && purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht) == true)
> > + return true;
> > + return false;
>
> Eh? Perhaps this gets fixed with Zack's boolean cleanup patch.
On thinking more about the patch to function.c, this fix is less invasive.
Bootstrap checked under i686 linux with no regressions. OK for the 3.0
branch?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-03-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* function.c (purge_addressof_1): Change type of function
purge_addressof_1 from boolean to int. Change local variable
`result' to int, and false and true to 0 and 1, respectively.
--- function.c.orig Sat Mar 3 14:06:57 2001
+++ function.c Sun Mar 4 12:03:57 2001
@@ -294,8 +294,8 @@
static void emit_return_into_block PARAMS ((basic_block, rtx));
#endif
static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
- struct hash_table *));
+static int purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
+ struct hash_table *));
static void purge_single_hard_subreg_set PARAMS ((rtx));
#ifdef HAVE_epilogue
static void keep_stack_depressed PARAMS ((rtx));
@@ -2969,7 +2969,7 @@
the stack. If the function returns FALSE then the replacement could not
be made. */
-static boolean
+static /* boolean */ int
purge_addressof_1 (loc, insn, force, store, ht)
rtx *loc;
rtx insn;
@@ -2980,14 +2980,14 @@
RTX_CODE code;
int i, j;
const char *fmt;
- boolean result = true;
+ int /*boolean */ result = /* true */ 1;
/* Re-start here to avoid recursion in common cases. */
restart:
x = *loc;
if (x == 0)
- return true;
+ return 1;
code = GET_CODE (x);
@@ -3010,7 +3010,7 @@
if (validate_change (insn, loc, sub, 0)
|| validate_replace_rtx (x, sub, insn))
- return true;
+ return 1;
start_sequence ();
sub = force_operand (sub, NULL_RTX);
@@ -3021,7 +3021,7 @@
insns = gen_sequence ();
end_sequence ();
emit_insn_before (insns, insn);
- return true;
+ return 1;
}
else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
@@ -3055,7 +3055,7 @@
if (rtx_equal_p (x, XEXP (tem, 0)))
{
*loc = XEXP (XEXP (tem, 1), 0);
- return true;
+ return 1;
}
/* See comment for purge_addressof_replacements. */
@@ -3095,7 +3095,7 @@
z = gen_lowpart (GET_MODE (x), z);
*loc = z;
- return true;
+ return 1;
}
/* Sometimes we may not be able to find the replacement. For
@@ -3105,7 +3105,7 @@
generate an example of this siutation. Rather than complain
we return false, which will prompt our caller to remove the
offending note. */
- return false;
+ return /* false */ 0;
}
size_x = GET_MODE_BITSIZE (GET_MODE (x));
@@ -3191,7 +3191,7 @@
purge_bitfield_addressof_replacements));
/* We replaced with a reg -- all done. */
- return true;
+ return 1;
}
}
@@ -3209,13 +3209,13 @@
if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
{
XEXP (XEXP (tem, 1), 0) = sub;
- return true;
+ return 1;
}
purge_addressof_replacements
= gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
gen_rtx_EXPR_LIST (VOIDmode, sub,
purge_addressof_replacements));
- return true;
+ return 1;
}
goto restart;
}
@@ -3226,7 +3226,7 @@
else if (code == ADDRESSOF)
{
put_addressof_into_stack (x, ht);
- return true;
+ return 1;
}
else if (code == SET)
{
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
[not found] <no.id>
` (30 preceding siblings ...)
2001-03-01 17:31 ` Enum related fixes for gcc build with native cc on vax ultrix John David Anglin
@ 2001-03-04 10:11 ` John David Anglin
2001-03-04 17:11 ` Enum fix to cplus-dem.c for gcc build with native cc on vax ultrix John David Anglin
` (131 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-04 10:11 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, neil
> Remember the lengthy discussion about basename variants. This wouldn't
> have happened with my libiberty basename patch. I thought it had been
> submitted but ...
On further looking, I see that I did in fact send the patch:
< http://gcc.gnu.org/ml/gcc-patches/2001-02/msg01548.html >.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Enum fix to cplus-dem.c for gcc build with native cc on vax ultrix
[not found] <no.id>
` (31 preceding siblings ...)
2001-03-04 10:11 ` cpplib: basename () fix John David Anglin
@ 2001-03-04 17:11 ` John David Anglin
2001-03-06 10:07 ` cpplib: basename () fix John David Anglin
` (130 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-04 17:11 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
This is the last of the enum fixes for the ultrix native compiler. I am
going to checkin under the obvious rule.
>
> Please review.
>
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2001-02-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * cplus-dem.c (main): Cast enum style to int.
>
> --- cplus-dem.c.orig Sun Feb 18 14:06:37 2001
> +++ cplus-dem.c Wed Feb 21 21:38:12 2001
> @@ -5148,7 +5148,7 @@
> skip_first = i;
>
> mbuffer[i] = 0;
> - flags |= style;
> + flags |= (int) style;
> result = cplus_demangle (mbuffer + skip_first, flags);
> if (result)
> {
>
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
[not found] <no.id>
` (32 preceding siblings ...)
2001-03-04 17:11 ` Enum fix to cplus-dem.c for gcc build with native cc on vax ultrix John David Anglin
@ 2001-03-06 10:07 ` John David Anglin
2001-03-06 10:29 ` DJ Delorie
2001-03-06 10:32 ` Zack Weinberg
2001-03-06 14:46 ` Patch for wrong number of arguments in call to smallest_mode_for_size John David Anglin
` (129 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-06 10:07 UTC (permalink / raw)
To: John David Anglin; +Cc: neil, dj, gcc-patches
> I just noticed that Zack in "x-files must die: alloca" has revamped the
> handling of alloca. I want to look carefully at what he has done. See
> < http://gcc.gnu.org/ml/gcc-patches/2001-03/msg00194.html >. Possibly, we
In looking at this patch, I see that Zack uses AC_TRY_RUN to determine
the stack direction for C alloca in libiberty_AC_FUNC_C_ALLOCA. The test
runs at exactly the same spot that I wanted to put the basename functionality
check.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
2001-03-06 10:07 ` cpplib: basename () fix John David Anglin
@ 2001-03-06 10:29 ` DJ Delorie
2001-03-06 10:32 ` Zack Weinberg
1 sibling, 0 replies; 521+ messages in thread
From: DJ Delorie @ 2001-03-06 10:29 UTC (permalink / raw)
To: dave; +Cc: zackw, gcc-patches
> In looking at this patch, I see that Zack uses AC_TRY_RUN to determine
> the stack direction for C alloca in libiberty_AC_FUNC_C_ALLOCA. The test
> runs at exactly the same spot that I wanted to put the basename functionality
> check.
Hmmm, that would break too then. Zack?
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
2001-03-06 10:07 ` cpplib: basename () fix John David Anglin
2001-03-06 10:29 ` DJ Delorie
@ 2001-03-06 10:32 ` Zack Weinberg
2001-03-06 10:52 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Zack Weinberg @ 2001-03-06 10:32 UTC (permalink / raw)
To: John David Anglin; +Cc: neil, dj, gcc-patches
On Tue, Mar 06, 2001 at 01:07:12PM -0500, John David Anglin wrote:
> > I just noticed that Zack in "x-files must die: alloca" has revamped the
> > handling of alloca. I want to look carefully at what he has done. See
> > < http://gcc.gnu.org/ml/gcc-patches/2001-03/msg00194.html >. Possibly, we
>
> In looking at this patch, I see that Zack uses AC_TRY_RUN to determine
> the stack direction for C alloca in libiberty_AC_FUNC_C_ALLOCA. The test
> runs at exactly the same spot that I wanted to put the basename functionality
> check.
The AC_TRY_RUN in the alloca logic has a fallback in the case we're
cross compiling (it postpones the test to run time).
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
2001-03-06 10:32 ` Zack Weinberg
@ 2001-03-06 10:52 ` John David Anglin
2001-03-06 11:16 ` DJ Delorie
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-03-06 10:52 UTC (permalink / raw)
To: Zack Weinberg; +Cc: neil, dj, gcc-patches
> On Tue, Mar 06, 2001 at 01:07:12PM -0500, John David Anglin wrote:
> > > I just noticed that Zack in "x-files must die: alloca" has revamped the
> > > handling of alloca. I want to look carefully at what he has done. See
> > > < http://gcc.gnu.org/ml/gcc-patches/2001-03/msg00194.html >. Possibly, we
> >
> > In looking at this patch, I see that Zack uses AC_TRY_RUN to determine
> > the stack direction for C alloca in libiberty_AC_FUNC_C_ALLOCA. The test
> > runs at exactly the same spot that I wanted to put the basename functionality
> > check.
>
> The AC_TRY_RUN in the alloca logic has a fallback in the case we're
> cross compiling (it postpones the test to run time).
In the basename case, we don't need a fallback because we just use the
libiberty version when cross compiling (ie., test fails) unless the
runtime environment explicitly excludes it from the list of funcs to
check.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: cpplib: basename () fix
2001-03-06 10:52 ` John David Anglin
@ 2001-03-06 11:16 ` DJ Delorie
0 siblings, 0 replies; 521+ messages in thread
From: DJ Delorie @ 2001-03-06 11:16 UTC (permalink / raw)
To: dave; +Cc: gcc-patches
> In the basename case, we don't need a fallback because we just use the
> libiberty version when cross compiling (ie., test fails) unless the
> runtime environment explicitly excludes it from the list of funcs to
> check.
And I say again, we might as well just always build and include our
own basename then. Alloca is different in that, even when we build
our own, it must know something about the runtime environment just to
function properly. However, it is equipped to defer that test until
runtime. We can't defer linking basename or not until after runtime.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch for wrong number of arguments in call to smallest_mode_for_size.
[not found] <no.id>
` (33 preceding siblings ...)
2001-03-06 10:07 ` cpplib: basename () fix John David Anglin
@ 2001-03-06 14:46 ` John David Anglin
2001-03-16 21:50 ` Patch to rtx_varies_p to improve pic code on PA John David Anglin
` (128 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-06 14:46 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> This patch may fix a bootstrap failure compiling under hpux 10.20 with
> the 3.0 branch and todays source. There is another more serious problem
Wrong branch. It should be 3.1.
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch to rtx_varies_p to improve pic code on PA
[not found] <no.id>
` (34 preceding siblings ...)
2001-03-06 14:46 ` Patch for wrong number of arguments in call to smallest_mode_for_size John David Anglin
@ 2001-03-16 21:50 ` John David Anglin
2001-04-05 13:41 ` f/ansify.c uses ANSI features John David Anglin
` (127 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-03-16 21:50 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2001-03-09 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * explow.c (stabilize): Call rtx_varies_p instead of rtx_unstable_p.
> * regmove.c (stable_and_no_regs_but_for_p): Likewise.
> * rtlanal.c (rtx_varies_p): Treat an unchanging register operand as
> constant for alias analysis. Treat the pic offset table register as
> constant even when PIC_OFFSET_TABLE_REG_CALL_CLOBBERED is defined.
> Update comments.
In looking at test results with and without this patch, I see that that the
patch does in fact eliminate at least one failing test case under i686
linux. For example, compare these results:
< http://gcc.gnu.org/ml/gcc-testresults/2001-03/msg00243.html >
and
< http://gcc.gnu.org/ml/gcc-testresults/2001-03/msg00245.html >.
I don't see any failures of 20001226-1.c with the patch installed.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: f/ansify.c uses ANSI features
[not found] <no.id>
` (35 preceding siblings ...)
2001-03-16 21:50 ` Patch to rtx_varies_p to improve pic code on PA John David Anglin
@ 2001-04-05 13:41 ` John David Anglin
2001-04-12 21:08 ` Sign extension of type with precision of 0 causes fault in force_fit_type John David Anglin
` (126 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-04-05 13:41 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> I have enclosed an untested patch for discussion/review.
This is better. It squelches a couple of warnings when compiled with
`-Wstrict-prototypes -Wmissing-prototypes'.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-04-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
* ansify.c (die_unless): Provide definition suitable for cpp that
doesn't have ANSI # stringizing operator.
(die, main): Prototype and don't use ANSI declaration style.
--- ansify.c.orig Tue Aug 29 17:39:48 2000
+++ ansify.c Thu Apr 5 16:30:43 2001
@@ -22,6 +22,7 @@
#include "hconfig.h"
#include "system.h"
+#ifdef HAVE_STRINGIZE
#define die_unless(c) \
do if (!(c)) \
{ \
@@ -29,15 +30,30 @@
die (); \
} \
while(0)
+#else
+#define die_unless(c) \
+ do if (!(c)) \
+ { \
+ fprintf (stderr, "%s:%lu: %s\n", argv[1], lineno, "c"); \
+ die (); \
+ } \
+ while(0)
+#endif
+
+static void ATTRIBUTE_NORETURN die PARAMS ((void));
static void ATTRIBUTE_NORETURN
-die (void)
+die ()
{
exit (1);
}
+extern int main PARAMS ((int, const char *const *));
+
int
-main(int argc, char **argv)
+main (argc, argv)
+ int argc;
+ const char *const *argv;
{
int c;
static unsigned long lineno = 1;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Sign extension of type with precision of 0 causes fault in force_fit_type
[not found] <no.id>
` (36 preceding siblings ...)
2001-04-05 13:41 ` f/ansify.c uses ANSI features John David Anglin
@ 2001-04-12 21:08 ` John David Anglin
2001-04-14 14:20 ` Where's the axe? Can't walk_tree John David Anglin
` (125 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-04-12 21:08 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
>
> The following error occured in my latest build under vax ultrix:
>
> /xxx/gnu/gcc-3.0/objdir/gcc/xgcc -B/xxx/gnu/gcc-3.0/objdir/gcc/ -nostdinc++ -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src/.libs -B/usr/local/vax-dec-ultrix4.3/bin/ -B/usr/local/vax-dec-ultrix4.3/lib/ -isystem /usr/local/vax-dec-ultrix4.3/include -nostdinc++ -I../../../../libstdc++-v3/include -I../../../../libstdc++-v3/include/std -I../../../../libstdc++-v3/include/c_std -I../include -I../../../../libstdc++-v3/libsupc++ -I../libio -I../../../../libstdc++-v3/libio -I../../../../libstdc++-v3/libmath -g -O2 -fno-implicit-templates -Wall -Wno-format -W -Wwrite-strings -Winline -fdiagnostics-show-location=once -g -c limitsMEMBERS.cc -o limitsMEMBERS.o
> In file included from limitsMEMBERS.cc:37:
> ../include/bits/std_limits.h:56: Internal error: Illegal instruction
Here is a patch for review to fix the above problem. The problem
arises because the initial type of each value is changed to enumtype
prior to min_precision being called. The precision of enumtype is
zero at that point. The call to min_precision requires that the
precision for the value be set correctly if the value is negative.
I have revised the code so that the calls to min_precision now
occur before the type of value is changed. I have checked that
it resolves the internal error on the vax and done a complete
bootstrap check with no regressions under i686 linux.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-04-12 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cp/decl.c (finish_enum): Revise calculation of precision needed
for enumeration types.
--- decl.c.orig Thu Apr 12 12:35:11 2001
+++ decl.c Thu Apr 12 17:02:07 2001
@@ -12923,8 +12923,11 @@
finish_enum (enumtype)
tree enumtype;
{
- register tree minnode = NULL_TREE, maxnode = NULL_TREE;
- /* Calculate the maximum value of any enumerator in this type. */
+ unsigned int precision = 1;
+ int unsignedp = 1;
+
+ /* Calculate the maximum precision needed for any enumerator in
+ this type assuming the values are unsigned. */
tree values = TYPE_VALUES (enumtype);
if (values)
@@ -12954,6 +12957,11 @@
value = DECL_INITIAL (decl);
if (value && !processing_template_decl)
{
+ precision = MAX (precision, min_precision (value, 1));
+
+ if (unsignedp && tree_int_cst_sgn (value) < 0)
+ unsignedp = 0;
+
/* Set the TREE_TYPE for the VALUE as well. That's so
that when we call decl_constant_value we get an
entity of the right type (but with the constant
@@ -12962,18 +12970,8 @@
reason to do that when processing_template_decl.
And, if the expression is something like a
TEMPLATE_PARM_INDEX or a CAST_EXPR doing so will
- wreak havoc on the intended type of the expression.
-
- Of course, there's also no point in trying to compute
- minimum or maximum values if we're in a template. */
+ wreak havoc on the intended type of the expression. */
TREE_TYPE (value) = enumtype;
-
- if (!minnode)
- minnode = maxnode = value;
- else if (tree_int_cst_lt (maxnode, value))
- maxnode = value;
- else if (tree_int_cst_lt (value, minnode))
- minnode = value;
}
if (processing_template_decl)
@@ -12987,8 +12985,6 @@
TREE_VALUE (pair) = value;
}
}
- else
- maxnode = minnode = integer_zero_node;
TYPE_VALUES (enumtype) = nreverse (values);
@@ -13000,11 +12996,11 @@
}
else
{
- int unsignedp = tree_int_cst_sgn (minnode) >= 0;
- int lowprec = min_precision (minnode, unsignedp);
- int highprec = min_precision (maxnode, unsignedp);
- int precision = MAX (lowprec, highprec);
tree tem;
+
+ if (!unsignedp)
+ /* Need signed type with one bit more. */
+ precision += 1;
TYPE_SIZE (enumtype) = NULL_TREE;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Where's the axe? Can't walk_tree.
[not found] <no.id>
` (37 preceding siblings ...)
2001-04-12 21:08 ` Sign extension of type with precision of 0 causes fault in force_fit_type John David Anglin
@ 2001-04-14 14:20 ` John David Anglin
2001-04-23 17:02 ` .stabs statements refer to symbol not in source John David Anglin
2001-04-21 19:33 ` C++ Issue on GCC 3.0 branch John David Anglin
` (124 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-04-14 14:20 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
I have enclosed a patch for review. It has been bootstrap tested under
i686 linux with PCC_STATIC_STRUCT_RETURN defined in linux.h. The build
of libstdc++-v3 under vax ultrix goes much further than ever before
but there are still problems:
/xxx/gnu/gcc-3.0/objdir/gcc/xgcc -B/xxx/gnu/gcc-3.0/objdir/gcc/ -nostdinc++ -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src/.libs -B/usr/local/vax-dec-ultrix4.3/bin/ -B/usr/local/vax-dec-ultrix4.3/lib/ -isystem /usr/local/vax-dec-ultrix4.3/include -nostdinc++ -I../../../../libstdc++-v3/include -I../../../../libstdc++-v3/include/std -I../../../../libstdc++-v3/include/c_std -I../include -I../../../../libstdc++-v3/libsupc++ -I../libio -I../../../../libstdc++-v3/libio -I../../../../libstdc++-v3/libmath -g -O2 -fno-implicit-templates -Wall -Wno-format -W -Wwrite-strings -Winline -fdiagnostics-show-location=once -g -c ../../../../libstdc++-v3/src/misc-inst.cc -o misc-inst.o
../../../../libstdc++-v3/include/bits/basic_string.h: In function
`std::basic_istream<_CharT, _Traits>&
std::operator>>(std::basic_istream<_CharT, _Traits>&,
std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits =
std::char_traits<char>, _Alloc = std::allocator<char>]':
../../../../libstdc++-v3/src/misc-inst.cc:189: instantiated from here
../../../../libstdc++-v3/include/bits/basic_string.h:1133: warning: comparison
between signed and unsigned integer expressions
/usr/tmp/ccsCMPtL.s: Assembler messages:
/usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol __n:V28
/usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol __n:
V28
/usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol
/usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol
make[4]: *** [misc-inst.lo] Error 1
The problem causing the infinite recursion was the call to build_aggr_init
in simplify_aggr_init_exprs_r. It converted the just built call_expr back
to an expression containing another aggr_init_expr.
>
> The following error occurs compiling cinst.cc under vax ultrix 4.3:
>
> /xxx/gnu/gcc-2.97/objdir/gcc/g++ -B/xxx/gnu/gcc-2.97/objdir/gcc/ -nostdinc++ -isystem /xxx/gnu/gcc-2.97/libstdc++ -isystem /xxx/gnu/gcc-2.97/libstdc++/std -isystem /xxx/gnu/gcc-2.97/libstdc++/stl -isystem /xxx/gnu/gcc-2.97/libio -isystem /xxx/gnu/gcc-2.97/objdir/vax-dec-ultrix4.3/libio -L/xxx/gnu/gcc-2.97/objdir/vax-dec-ultrix4.3/libstdc++ -B/usr/local/vax-dec-ultrix4.3/bin/ -B/usr/local/vax-dec-ultrix4.3/lib/ -isystem /usr/local/vax-dec-ultrix4.3/include -c -O3 -fno-implicit-templates -I../../../libstdc++ -I../../../libstdc++/stl -I../libio -I../../../libstdc++/../libio -I../../../libstdc++/../include -I../../../libstdc++/../gcc -nostdinc++ -DF `for N in MAIN ADDCC ADDCF ADDFC SUBCC SUBCF SUBFC MULCC MULCF MULFC DIVCC DIVCF DIVFC PLUS MINUS EQCC EQCF EQFC NECC NECF NEFC ABS ARG POLAR CONJ NORM COS COSH EXP LOG POWCC POWCF POWCI POWFC SIN SINH SQRT; do echo " -D${N}"; done` \
> ../../../libstdc++/cinst.cc -o fcomplex.o
> ../libio/_G_config.h:85: warning: badly nested C headers from preprocessor
> ../../../libstdc++/cmath:6: warning: badly nested C headers from preprocessor
> g++: Internal error: Illegal instruction (program cc1plus)
> Please submit a full bug report.
> See <URL: http://www.gnu.org/software/gcc/bugs.html > for instructions.
> make[1]: *** [bigstmp-complx] Error 1
> make[1]: Leaving directory `/xxx/gnu/gcc-2.97/objdir/vax-dec-ultrix4.3/libstdc++'
> make: *** [all-target-libstdc++] Error 2
> Wed Nov 29 07:51:59 EST 2000
>
> The internal error is caused by cc1plus exceeding the maximum stack size.
> It occurs processing the header fcomplex.h for the function
> const complex<float> operator+(const complex<float>&, float). For some
> reason, the recursive calls to walk the tree lead to infinite recursion:
>
> (gdb) bt -10
> #18906 0xe9d66 in walk_tree (tp=0x3ffbd4,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0,
> htab=0x308700, 3180288, 1) at ../../gcc/cp/tree.c:1286
> #18907 0xe9d66 in walk_tree (tp=0x3ffbf0,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0, htab=0x308700)
> at ../../gcc/cp/tree.c:1286
> #18908 0xe9d66 in walk_tree (tp=0x3fd160,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0, htab=0x308700)
> at ../../gcc/cp/tree.c:1286
> #18909 0xe9da3 in walk_tree (tp=0x3fd150,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0, htab=0x308700)
> at ../../gcc/cp/tree.c:1307
> #18910 0xe9d66 in walk_tree (tp=0x3dbb80,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0, htab=0x308700)
> at ../../gcc/cp/tree.c:1286
> #18911 0xed91c in walk_tree_without_duplicates (tp=0x3dbb80,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0)
> at ../../gcc/cp/tree.c:1444
> #18912 0xe4559 in expand_body (fn=0x3e0000, 4063232)
> at ../../gcc/cp/semantics.c:2332
> #18913 0xa1c60 in yyparse () at /usr/local/share/bison.simple:2162
> #18914 0x11b41e in compile_file (name=0x7fffc1cd "fcomplex.ii")
> at ../../gcc/toplev.c:2361
> #18915 0x120802 in main (argc=4, argv=0x7fffc0c0, 2147467476)
> at ../../gcc/toplev.c:4843
>
> (gdb) frame 18911
> #18911 0xed91c in walk_tree_without_duplicates (tp=0x3dbb80,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0)
> at ../../gcc/cp/tree.c:1444
> 1444 result = walk_tree (tp, func, data, htab);
> (gdb) p debug_tree (*tp)
> <compound_stmt 003fd140 tree_1 tree_2
> arg 0 <scope_stmt 003fd160 tree_0 tree_1
> chain <return_stmt 003ffbe0 tree_1
> arg 0 <init_expr 003ffbc0 type <record_type 00344800 complex<float>>
> side-effects arg 0 <result_decl 003fc380>
> arg 1 <target_expr 003ff940 type <record_type 00344800 complex<float>>
> side-effects addressable arg 0 <var_decl 00400000>
> arg 1 <compound_expr 00400bc0 type <record_type 00344800 complex<float>>
> side-effects
> arg 0 <stmt_expr 00400ba0 type <record_type 00344800 complex<float>>
> side-effects used arg 0 <compound_stmt 004008a0>> arg 1 <var_decl 00400000>>>>
> chain <scope_stmt 00400800 tree_1>>>>
> $3 = void
>
> At frame #5, we have
>
> (gdb) frame 5
> #5 0xe97ca in walk_tree (tp=0xa52854,
> func=0xe40ac <simplify_aggr_init_exprs_r>, data=0x0, htab=0x308700)
> at ../../gcc/cp/tree.c:1251
> 1251 result = (*func) (tp, &walk_subtrees, data);
> (gdb) p debug_tree (*tp)
> <aggr_init_expr 00a52820
> type <record_type 00344800 complex<float> needs-constructing type_1 type_5 DI
> size <integer_cst 002d2c00 constant 64>
> unit size <integer_cst 002d2c20 constant 8>
> align 32 symtab 0 alias set -1
> fields <field_decl 003db380 re type <real_type 002d4600 float>
> private nonlocal decl_3 SF file ../../../libstdc++/std/fcomplex.h line 51
> size <integer_cst 002d2c40 constant 32>
> unit size <integer_cst 002d2c80 constant 4>
> align 32 offset_align 32
> offset <integer_cst 002d2ea0 constant 0>
> bit offset <integer_cst 002d2ec0 constant 0> context <record_type 00344800 complex<float>> arguments <integer_cst 002d2ea0 0> chain <field_decl 003dc800 im>>
> needs-constructor X() X(constX&) this=(X&) n_parents 0 use_template=2 vtable-needs-writing
> member-functions <tree_vec 003e9380
> elt 0 <overload 003cc370>
> elt 2 <function_decl 003e9280 operator=>
> elt 3 <function_decl 003d8900 operator+=>
> elt 4 <function_decl 003d8b80 operator-=>
> elt 5 <function_decl 003d9a00 operator*=>
> elt 6 <function_decl 003da880 operator/=>
> elt 7 <function_decl 003daa80 real>
> elt 8 <function_decl 003db200 imag>>
> pointer_to_this <pointer_type 00344880> reference_to_this <reference_type 003d7a00> chain <type_decl 00344900 complex<float>>>
> side-effects
> arg 0 <addr_expr 003ff8e0
> type <pointer_type 003feb80 type <function_type 003df380>
> unsigned SI size <integer_cst 002d2c40 32> unit size <integer_cst 002d2c80 4>
> align 32 symtab 0 alias set -1>
> readonly
> arg 0 <function_decl 003fea00 operator+ type <function_type 003df380>
> readonly used public external inline QI file ../../../libstdc++/std/complext.h line 160
> frame_size 0 arguments <parm_decl 003fea80 x> initial <block 0036c920>
> template-info 003ff0e0
> (mem:QI (symbol_ref:SI ("__pl__H1Zf_RCt7complex1ZX01X01_t7complex1ZX01")) 0)>>
> arg 1 <tree_list 003ff280
> value <nop_expr 003ff260 type <reference_type 003d7b00>
> readonly
> arg 0 <convert_expr 003ff240 type <pointer_type 003dab80>
> readonly arg 0 <parm_decl 003df280 x>>>
> chain <tree_list 003ff2a0 value <parm_decl 003df300 y>>>
> arg 2 <var_decl 00a4fb00 type <record_type 00344800 complex<float>>
> used DI file ../../../libstdc++/std/fcomplex.h line 60 size <integer_cst 002d2c00 64> unit size <integer_cst 002d2c20 8>
> align 32>>
> $4 = void
>
> Debugging this is a real maize. Let me know if anyone has any clues or
> suggestions.
>
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-04-13 John David Anglin <dave@hiauly1.hia.nrc.ca>
* semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND to flags
in call to build_aggr_init to prevent conversion of CALL_EXPR back
to a AGGR_INIT_EXPR. This prevents infinite recursion when
PCC_STATIC_STRUCT_RETURN is defined. Save flag_access_control
across call to build_aggr_init.
--- semantics.c.orig Thu Apr 12 12:35:13 2001
+++ semantics.c Fri Apr 13 21:27:06 2001
@@ -2237,10 +2237,11 @@
#ifdef PCC_STATIC_STRUCT_RETURN
if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
{
- int old_ac;
+ int old_ac = flag_access_control;
flag_access_control = 0;
- call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+ call_expr = build_aggr_init (slot, call_expr,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* .stabs statements refer to symbol not in source
2001-04-14 14:20 ` Where's the axe? Can't walk_tree John David Anglin
@ 2001-04-23 17:02 ` John David Anglin
2001-04-23 17:57 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-04-23 17:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
This is a follow up to the following problem:
> /xxx/gnu/gcc-3.0/objdir/gcc/xgcc -B/xxx/gnu/gcc-3.0/objdir/gcc/ -nostdinc++ -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src -L/xxx/gnu/gcc-3.0/objdir/vax-dec-ultrix4.3/libstdc++-v3/src/.libs -B/usr/local/vax-dec-ultrix4.3/bin/ -B/usr/local/vax-dec-ultrix4.3/lib/ -isystem /usr/local/vax-dec-ultrix4.3/include -nostdinc++ -I../../../../libstdc++-v3/include -I../../../../libstdc++-v3/include/std -I../../../../libstdc++-v3/include/c_std -I../include -I../../../../libstdc++-v3/libsupc++ -I../libio -I../../../../libstdc++-v3/libio -I../../../../libstdc++-v3/libmath -g -O2 -fno-implicit-templates -Wall -Wno-format -W -Wwrite-strings -Winline -fdiagnostics-show-location=once -g -c ../../../../libstdc++-v3/src/misc-inst.cc -o misc-inst.o
> ../../../../libstdc++-v3/include/bits/basic_string.h: In function
> `std::basic_istream<_CharT, _Traits>&
> std::operator>>(std::basic_istream<_CharT, _Traits>&,
> std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits =
> std::char_traits<char>, _Alloc = std::allocator<char>]':
> ../../../../libstdc++-v3/src/misc-inst.cc:189: instantiated from here
> ../../../../libstdc++-v3/include/bits/basic_string.h:1133: warning: comparison
> between signed and unsigned integer expressions
> /usr/tmp/ccsCMPtL.s: Assembler messages:
> /usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol __n:V28
> /usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol __n:
> V28
> /usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol
> /usr/tmp/ccsCMPtL.s:45114: Error: Attempt to get value of unresolved symbol
> make[4]: *** [misc-inst.lo] Error 1
The unresolved symbol occurs twice in .stabs statements. The file assembles
without problem if I remove the two statements:
--- misc-inst.s.orig Sun Apr 22 17:13:23 2001
+++ misc-inst.s Sun Apr 22 17:45:09 2001
@@ -41589,7 +41589,6 @@
.stabs "__cerb:1282",128,0,1169,-2
.stabn 192,0,0,LBB3073
.data
- .stabs "__n:V28",38,0,1173,__ZNSs4_Rep11_S_max_sizeE
.stabs "__idelim:r1",64,0,1175,7
.stabs "__sb:r1121",64,0,1176,6
.stabs "__c:r1",64,0,1177,2
@@ -41608,7 +41607,6 @@
.stabn 192,0,0,LBB3117
.stabn 224,0,0,LBE3117
.stabn 224,0,0,LBE3116
- .stabs "__n:V28",38,0,1173,__ZNSs4_Rep11_S_max_sizeE
.stabs "__idelim:r1",64,0,1175,7
.stabs "__sb:r1121",64,0,1176,6
.stabs "__c:r1",64,0,1177,2
Does anyone have suggestions as to where to look to find out why these
are being generated. I imagine the symbol has been optimized away.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: .stabs statements refer to symbol not in source
2001-04-23 17:02 ` .stabs statements refer to symbol not in source John David Anglin
@ 2001-04-23 17:57 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-04-23 17:57 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> The unresolved symbol occurs twice in .stabs statements. The file assembles
> without problem if I remove the two statements:
>
> --- misc-inst.s.orig Sun Apr 22 17:13:23 2001
> +++ misc-inst.s Sun Apr 22 17:45:09 2001
> @@ -41589,7 +41589,6 @@
> .stabs "__cerb:1282",128,0,1169,-2
> .stabn 192,0,0,LBB3073
> .data
> - .stabs "__n:V28",38,0,1173,__ZNSs4_Rep11_S_max_sizeE
> .stabs "__idelim:r1",64,0,1175,7
> .stabs "__sb:r1121",64,0,1176,6
> .stabs "__c:r1",64,0,1177,2
> @@ -41608,7 +41607,6 @@
> .stabn 192,0,0,LBB3117
> .stabn 224,0,0,LBE3117
> .stabn 224,0,0,LBE3116
> - .stabs "__n:V28",38,0,1173,__ZNSs4_Rep11_S_max_sizeE
> .stabs "__idelim:r1",64,0,1175,7
> .stabs "__sb:r1121",64,0,1176,6
> .stabs "__c:r1",64,0,1177,2
These definitions come from the template at line 1155 of istream.tcc.
It is easy to see from the template code why __n could be optimized away.
Is this an assembler or compiler bug?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
[not found] <no.id>
` (38 preceding siblings ...)
2001-04-14 14:20 ` Where's the axe? Can't walk_tree John David Anglin
@ 2001-04-21 19:33 ` John David Anglin
2001-04-23 2:18 ` Bernd Schmidt
2001-04-25 10:26 ` Mark Mitchell
2001-05-03 9:57 ` PATCH: Re: jartool.c:539: undefined reference to `strdup' John David Anglin
` (123 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-04-21 19:33 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, law, gcc-patches, gcc
> 2001-04-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * builtins.c (expand_builtin_setjmp_setup): Set nonlocal flag in label.
Close but no cigar. This one actually bootstraps with no regressions under
i686 linux. However, I think it only addresses the symptom of the problem.
There must be a label uses problem somewhere. In any event, the testcase
for duplicate symbols will compile with the patch installed.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-04-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* builtins.c (expand_builtin_setjmp): Mark next_lab as used.
--- builtins.c.orig Wed Feb 7 05:24:22 2001
+++ builtins.c Sat Apr 21 20:18:59 2001
@@ -617,6 +617,7 @@
buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
next_lab = gen_label_rtx ();
+ LABEL_PRESERVE_P (next_lab) = 1;
cont_lab = gen_label_rtx ();
expand_builtin_setjmp_setup (buf_addr, next_lab);
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-21 19:33 ` C++ Issue on GCC 3.0 branch John David Anglin
@ 2001-04-23 2:18 ` Bernd Schmidt
2001-04-23 7:51 ` law
2001-04-25 10:26 ` Mark Mitchell
1 sibling, 1 reply; 521+ messages in thread
From: Bernd Schmidt @ 2001-04-23 2:18 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, law, gcc-patches, gcc
On Sat, 21 Apr 2001, John David Anglin wrote:
> > 2001-04-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * builtins.c (expand_builtin_setjmp_setup): Set nonlocal flag in label.
>
> Close but no cigar. This one actually bootstraps with no regressions under
> i686 linux. However, I think it only addresses the symptom of the problem.
> There must be a label uses problem somewhere. In any event, the testcase
> for duplicate symbols will compile with the patch installed.
You might want to look at the patches I installed on the 2.95 branch after
2.95.3. This sounds like it's exactly the same problem.
Bernd
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-23 2:18 ` Bernd Schmidt
@ 2001-04-23 7:51 ` law
2001-04-23 7:55 ` Bernd Schmidt
2001-04-23 7:56 ` Bernd Schmidt
0 siblings, 2 replies; 521+ messages in thread
From: law @ 2001-04-23 7:51 UTC (permalink / raw)
To: Bernd Schmidt; +Cc: John David Anglin, mark, gcc-patches, gcc
In message <Pine.LNX.4.33.0104231017340.7552-100000@host140.cambridge.redhat.
com>you write:
> > There must be a label uses problem somewhere. In any event, the testcase
> > for duplicate symbols will compile with the patch installed.
>
> You might want to look at the patches I installed on the 2.95 branch after
> 2.95.3. This sounds like it's exactly the same problem.
Are you referring to this patch?
2001-03-28 Bernd Schmidt <bernds@redhat.com>
* flow.c (propagate_block): When trying to delete a case vector, cope
if its label has LABEL_PRESERVE_P set.
* jump.c (jump_optimize_1): Move call to delete_barrier_successors to
a point where JUMP_LABELS and LABEL_NUSES are set up properly.
(delete_barrier_successors): If deleting a table jump, delete the case
vector as well.
* varasm.c (force_const_mem): If we have a label, set LABEL_PRESERVE_P
so it won't get deleted.
Just want to be sure before I install it locally and fire off my tests.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-23 7:51 ` law
@ 2001-04-23 7:55 ` Bernd Schmidt
2001-04-23 7:56 ` Bernd Schmidt
1 sibling, 0 replies; 521+ messages in thread
From: Bernd Schmidt @ 2001-04-23 7:55 UTC (permalink / raw)
To: law; +Cc: John David Anglin, mark, gcc-patches, gcc
On Mon, 23 Apr 2001 law@redhat.com wrote:
> In message <Pine.LNX.4.33.0104231017340.7552-100000@host140.cambridge.redhat.
> com>you write:
> > > There must be a label uses problem somewhere. In any event, the testcase
> > > for duplicate symbols will compile with the patch installed.
> >
> > You might want to look at the patches I installed on the 2.95 branch after
> > 2.95.3. This sounds like it's exactly the same problem.
> Are you referring to this patch?
>
> 2001-03-28 Bernd Schmidt <bernds@redhat.com>
>
> * flow.c (propagate_block): When trying to delete a case vector, cope
> if its label has LABEL_PRESERVE_P set.
> * jump.c (jump_optimize_1): Move call to delete_barrier_successors to
> a point where JUMP_LABELS and LABEL_NUSES are set up properly.
> (delete_barrier_successors): If deleting a table jump, delete the case
> vector as well.
> * varasm.c (force_const_mem): If we have a label, set LABEL_PRESERVE_P
> so it won't get deleted.
Yes.
Bernd
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-23 7:51 ` law
2001-04-23 7:55 ` Bernd Schmidt
@ 2001-04-23 7:56 ` Bernd Schmidt
2001-04-23 8:14 ` law
1 sibling, 1 reply; 521+ messages in thread
From: Bernd Schmidt @ 2001-04-23 7:56 UTC (permalink / raw)
To: law; +Cc: John David Anglin, mark, gcc-patches, gcc
On Mon, 23 Apr 2001 law@redhat.com wrote:
> 2001-03-28 Bernd Schmidt <bernds@redhat.com>
>
> * flow.c (propagate_block): When trying to delete a case vector, cope
> if its label has LABEL_PRESERVE_P set.
> * jump.c (jump_optimize_1): Move call to delete_barrier_successors to
> a point where JUMP_LABELS and LABEL_NUSES are set up properly.
> (delete_barrier_successors): If deleting a table jump, delete the case
> vector as well.
> * varasm.c (force_const_mem): If we have a label, set LABEL_PRESERVE_P
> so it won't get deleted.
Just remembered; this also needs the followup
2001-03-30 Bernd Schmidt <bernds@redhat.com>
* jump.c (delete_barrier_successors): Fix error in last change.
Bernd
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-23 7:56 ` Bernd Schmidt
@ 2001-04-23 8:14 ` law
0 siblings, 0 replies; 521+ messages in thread
From: law @ 2001-04-23 8:14 UTC (permalink / raw)
To: Bernd Schmidt; +Cc: John David Anglin, mark, gcc-patches, gcc
In message <Pine.LNX.4.33.0104231556040.7552-100000@host140.cambridge.redhat.
com>you write:
> Just remembered; this also needs the followup
>
> 2001-03-30 Bernd Schmidt <bernds@redhat.com>
>
> * jump.c (delete_barrier_successors): Fix error in last change.
OK. Thanks. I'll give the set a whirl on my PAs :-)
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-21 19:33 ` C++ Issue on GCC 3.0 branch John David Anglin
2001-04-23 2:18 ` Bernd Schmidt
@ 2001-04-25 10:26 ` Mark Mitchell
2001-04-25 14:04 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2001-04-25 10:26 UTC (permalink / raw)
To: dave; +Cc: law, gcc-patches, gcc
2001-04-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* builtins.c (expand_builtin_setjmp): Mark next_lab as used.
--- builtins.c.orig Wed Feb 7 05:24:22 2001
+++ builtins.c Sat Apr 21 20:18:59 2001
@@ -617,6 +617,7 @@
buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
next_lab = gen_label_rtx ();
+ LABEL_PRESERVE_P (next_lab) = 1;
cont_lab = gen_label_rtx ();
expand_builtin_setjmp_setup (buf_addr, next_lab);
Even with this workaround patch I still get a crash using a cross
compiler, so I guess I'll have to wait for Jeff's reworking of Bernd's
patch.
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-25 10:26 ` Mark Mitchell
@ 2001-04-25 14:04 ` John David Anglin
2001-04-25 17:31 ` Mark Mitchell
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-04-25 14:04 UTC (permalink / raw)
To: Mark Mitchell; +Cc: law, gcc-patches, gcc
> 2001-04-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * builtins.c (expand_builtin_setjmp): Mark next_lab as used.
>
> --- builtins.c.orig Wed Feb 7 05:24:22 2001
> +++ builtins.c Sat Apr 21 20:18:59 2001
> @@ -617,6 +617,7 @@
> buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
>
> next_lab = gen_label_rtx ();
> + LABEL_PRESERVE_P (next_lab) = 1;
> cont_lab = gen_label_rtx ();
>
> expand_builtin_setjmp_setup (buf_addr, next_lab);
>
> Even with this workaround patch I still get a crash using a cross
> compiler, so I guess I'll have to wait for Jeff's reworking of Bernd's
> patch.
Strange. I just tried it again with the 3.0 source from a few hours
ago with no problems. The above patch was the only source change.
I just configured with `--with-gnu-as --target=hppa1.1-hp-hpux10.20' and
did a make. CFLAGS were the default `-g -O2'. My build gcc was 3.0
20010421 (prerelease).
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-25 14:04 ` John David Anglin
@ 2001-04-25 17:31 ` Mark Mitchell
2001-04-26 8:32 ` John David Anglin
2001-04-26 10:02 ` law
0 siblings, 2 replies; 521+ messages in thread
From: Mark Mitchell @ 2001-04-25 17:31 UTC (permalink / raw)
To: dave; +Cc: law, gcc-patches, gcc
After making Dave work hard sending me lots of information, it turns
out that his original patch is exactly the right thing.
I checked in the attached, on both the mainline and the branch;
hopefully it will remove the duplicate symbols on HPUX.
Tested on i686-pc-linux-gnu, and by looking at the .s output for
Dave's testcase.
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2001-04-25 Mark Mitchell <mark@codesourcery.com>
* optimize.c (maybe_clone_body): Copy TREE_PUBLIC before emitting
the clone.
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/optimize.c,v
retrieving revision 1.51.2.13
diff -c -p -r1.51.2.13 optimize.c
*** optimize.c 2001/04/25 00:12:47 1.51.2.13
--- optimize.c 2001/04/26 00:28:07
*************** maybe_clone_body (fn)
*** 1051,1056 ****
--- 1051,1057 ----
DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
+ TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
/* Start processing the function. */
push_to_top_level ();
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-25 17:31 ` Mark Mitchell
@ 2001-04-26 8:32 ` John David Anglin
2001-04-26 10:25 ` Mark Mitchell
2001-04-26 10:02 ` law
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-04-26 8:32 UTC (permalink / raw)
To: Mark Mitchell; +Cc: law, gcc-patches, gcc
Mark,
> After making Dave work hard sending me lots of information, it turns
> out that his original patch is exactly the right thing.
>
> I checked in the attached, on both the mainline and the branch;
> hopefully it will remove the duplicate symbols on HPUX.
While I am certain that the patch eliminates the duplicate symbols, I
am still concerned that assemble_external is being called with TREE_PUBLIC
and DECL_EXTERNAL set for the type declarations. This causes .IMPORT
statements to be generated for the symbols under hpux. While this appears
harmless under HPUX, I am not sure it would be under all circumstances.
It seemed to me that when there is no weak support these declarations
should not be external. I remember there was some discussion of this
under AIX back in January.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-26 8:32 ` John David Anglin
@ 2001-04-26 10:25 ` Mark Mitchell
0 siblings, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2001-04-26 10:25 UTC (permalink / raw)
To: dave; +Cc: law, gcc-patches, gcc
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
John> While I am certain that the patch eliminates the duplicate
John> symbols, I am still concerned that assemble_external is
John> being called with TREE_PUBLIC and DECL_EXTERNAL set for the
John> type declarations. This causes .IMPORT statements to be
Yes, that's why I asked about this.
There's a basic problem here; both the C and C++ front-ends call
assemble_external in a way that is inconsistent with the
assemble_external documentation.
In particular, ASM_OUTPUT_EXTERNAL is documented as used when
something is
A C statement (sans semicolon) to output to the stdio stream
STREAM any text necessary for declaring the name of an external
symbol named NAME which is referenced in this compilation but not
defined. The value of DECL is the tree node for the declaration.
You can't know this until the end of the translation unit. But, we
compile a function-at-a-time, so if we see:
extern void f();
void g() { f(); }
void f() {}
we call this macro for `f'.
It's even more extreme in C++ because we don't make up our minds about
the linkages of some functions until very late in the game. (See the
tricks played with DECL_NOT_REALLY_EXTERN.) That's all really pretty
grotesque, but it's not easy to fix, and it's been that way for a long
time, so I'm guessing most systems deal with it OK.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ Issue on GCC 3.0 branch
2001-04-25 17:31 ` Mark Mitchell
2001-04-26 8:32 ` John David Anglin
@ 2001-04-26 10:02 ` law
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2001-04-26 10:02 UTC (permalink / raw)
To: Mark Mitchell; +Cc: dave, gcc-patches, gcc
In message < 20010425173144F.mitchell@codesourcery.com >you write:
>
> After making Dave work hard sending me lots of information, it turns
> out that his original patch is exactly the right thing.
>
> I checked in the attached, on both the mainline and the branch;
> hopefully it will remove the duplicate symbols on HPUX.
>
> Tested on i686-pc-linux-gnu, and by looking at the .s output for
> Dave's testcase.
Noted. I'm testing hpux PA32 with it now.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* PATCH: Re: jartool.c:539: undefined reference to `strdup'
[not found] <no.id>
` (39 preceding siblings ...)
2001-04-21 19:33 ` C++ Issue on GCC 3.0 branch John David Anglin
@ 2001-05-03 9:57 ` John David Anglin
2001-05-03 10:13 ` Alexandre Oliva
2001-05-11 18:32 ` Disappearing labels fix John David Anglin
` (122 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-05-03 9:57 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> It can be worked around by linking with libiberty.a or adding a version of
> strdup to jartool.c.
OK for branch and main?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-05-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* jartool.c (strdup): New function.
--- jartool.c.orig Thu Dec 28 16:47:37 2000
+++ jartool.c Thu May 3 12:26:57 2001
@@ -223,6 +223,7 @@
int make_manifest(int, const char*);
static void init_args(char **, int);
static char *get_next_arg (void);
+static char *strdup (char*);
/* global variables */
ub1 file_header[30];
@@ -1825,4 +1826,15 @@
");
exit(1);
+}
+
+static char *
+strdup(s)
+ char *s;
+{
+ char *result = (char*)malloc(strlen(s) + 1);
+ if (result == (char*)0)
+ return (char*)0;
+ strcpy(result, s);
+ return result;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 9:57 ` PATCH: Re: jartool.c:539: undefined reference to `strdup' John David Anglin
@ 2001-05-03 10:13 ` Alexandre Oliva
2001-05-03 10:37 ` John David Anglin
` (2 more replies)
0 siblings, 3 replies; 521+ messages in thread
From: Alexandre Oliva @ 2001-05-03 10:13 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
On May 3, 2001, "John David Anglin" <dave@hiauly1.hia.nrc.ca> wrote:
> OK for branch and main?
I don't think so. strdup() is sometimes defined as a macro, and
sometimes it's declared to take a const char *. Better check for it
and define it only if it's not present, or go for libiberty, which I
think would be a better idea.
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 10:13 ` Alexandre Oliva
@ 2001-05-03 10:37 ` John David Anglin
2001-05-03 10:53 ` Alexandre Oliva
2001-05-03 10:43 ` Tom Tromey
2001-05-03 11:26 ` John David Anglin
2 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-05-03 10:37 UTC (permalink / raw)
To: Alexandre Oliva; +Cc: gcc-bugs, gcc-patches
> I don't think so. strdup() is sometimes defined as a macro, and
> sometimes it's declared to take a const char *. Better check for it
> and define it only if it's not present, or go for libiberty, which I
> think would be a better idea.
I think the simplest thing then is to rename `strdup' so there is no
conflict. It doesn't seem to make much sense to use libiberty just
for this one function. The configure stuff doesn't check for any other
functions or declarations.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 10:37 ` John David Anglin
@ 2001-05-03 10:53 ` Alexandre Oliva
0 siblings, 0 replies; 521+ messages in thread
From: Alexandre Oliva @ 2001-05-03 10:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
On May 3, 2001, "John David Anglin" <dave@hiauly1.hia.nrc.ca> wrote:
> It doesn't seem to make much sense to use libiberty just
> for this one function.
Perhaps we'll eventually find out about other portability problems in
other platforms. There's no reason not to link libiberty in, after
all.
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 10:13 ` Alexandre Oliva
2001-05-03 10:37 ` John David Anglin
@ 2001-05-03 10:43 ` Tom Tromey
2001-05-03 11:26 ` John David Anglin
2 siblings, 0 replies; 521+ messages in thread
From: Tom Tromey @ 2001-05-03 10:43 UTC (permalink / raw)
To: Alexandre Oliva; +Cc: John David Anglin, gcc-bugs, gcc-patches
>>>>> "Alexandre" == Alexandre Oliva <aoliva@redhat.com> writes:
Alexandre> Better check for it and define it only if it's not present,
Alexandre> or go for libiberty, which I think would be a better idea.
I also think using libiberty is best, now that Per has established
that we can't contact the fastjar maintainer.
Does this really belong on the branch? I'm inclined to say no. It is
pretty late, and I doubt that we'd want to accept the changes to make
java work on this target at this point. java support is the only
reason to build fastjar.
Tom
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 10:13 ` Alexandre Oliva
2001-05-03 10:37 ` John David Anglin
2001-05-03 10:43 ` Tom Tromey
@ 2001-05-03 11:26 ` John David Anglin
2001-05-03 13:22 ` Tom Tromey
2 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-05-03 11:26 UTC (permalink / raw)
To: Alexandre Oliva; +Cc: gcc-bugs, gcc-patches
> I don't think so. strdup() is sometimes defined as a macro, and
> sometimes it's declared to take a const char *. Better check for it
> and define it only if it's not present, or go for libiberty, which I
> think would be a better idea.
Here is a revised patch. Guaranteed to build and run under vax-dec-ultrix4.3.
As I see it, using strdup from libiberty is something to be avoided because
there is no declaration for it in libiberty.h. Gcc doesn't use it. It
uses xstrdup. However, it has a somewhat different behavior if malloc
fails (admittedly unlikely in this case). If you want to link against
libiberty, probably jartool.c should include libiberty.h and use xstrdup.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-05-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* jartool.c (jt_strdup): New function.
(get_next_arg): Use jt_strdup instead of strdup.
--- jartool.c.orig Thu Dec 28 16:47:37 2000
+++ jartool.c Thu May 3 13:41:22 2001
@@ -223,6 +223,7 @@
int make_manifest(int, const char*);
static void init_args(char **, int);
static char *get_next_arg (void);
+static char *jt_strdup (char*);
/* global variables */
ub1 file_header[30];
@@ -536,7 +537,7 @@
if (pos)
{
s [pos] = '\0';
- return strdup (s);
+ return jt_strdup (s);
}
else
return NULL;
@@ -1825,4 +1826,15 @@
");
exit(1);
+}
+
+static char *
+jt_strdup(s)
+ char *s;
+{
+ char *result = (char*)malloc(strlen(s) + 1);
+ if (result == (char*)0)
+ return (char*)0;
+ strcpy(result, s);
+ return result;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 11:26 ` John David Anglin
@ 2001-05-03 13:22 ` Tom Tromey
2001-05-03 15:10 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Tom Tromey @ 2001-05-03 13:22 UTC (permalink / raw)
To: John David Anglin; +Cc: Alexandre Oliva, gcc-bugs, gcc-patches
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
John> 2001-05-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
John> * jartool.c (jt_strdup): New function.
John> (get_next_arg): Use jt_strdup instead of strdup.
This is fine. Please check it in.
Thanks,
Tom
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: jartool.c:539: undefined reference to `strdup'
2001-05-03 13:22 ` Tom Tromey
@ 2001-05-03 15:10 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-05-03 15:10 UTC (permalink / raw)
To: tromey; +Cc: aoliva, gcc-bugs, gcc-patches
> >>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>
> John> 2001-05-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
> John> * jartool.c (jt_strdup): New function.
> John> (get_next_arg): Use jt_strdup instead of strdup.
>
> This is fine. Please check it in.
Done on the main but not on the branch as per your previous comments.
I am guessing that a fairly recent change to configure in the top level
directory now causes fastjar to build again. Since it doesn't build on
the branch as it stands under vax-dec-ultrix4.3, should noconfigdirs be
changed to reflect this?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Disappearing labels fix
[not found] <no.id>
` (40 preceding siblings ...)
2001-05-03 9:57 ` PATCH: Re: jartool.c:539: undefined reference to `strdup' John David Anglin
@ 2001-05-11 18:32 ` John David Anglin
2001-05-18 8:58 ` John David Anglin
2001-05-14 10:18 ` PATCH: Fix toplev.c breakage on PA after eh merge John David Anglin
` (121 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-05-11 18:32 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
> I thought that I would try g++ version 3.0 20010503 (prerelease) on a
> real world application and ran immediately into the disappearing label
> problem building groff-1.16.1:
Tried again with today's patch. There are now more missing labels than
before:
/xxx/gnu/gcc-3.0/objdir/gcc/g++ -B/xxx/gnu/gcc-3.0/objdir/gcc/ -O3 -s -o troff e
nv.o node.o input.o div.o symbol.o dictionary.o reg.o number.o majorminor.o /xxx
/gnu/groff-1.16.1/objdir/src/libs/libgroff/libgroff.a -lm
/usr/ccs/bin/ld: Unsatisfied symbols:
L$38329 (data)
L$38590 (data)
L$38405 (data)
L$38438 (data)
L$38481 (data)
L$38601 (data)
L$38557 (data)
L$38546 (data)
L$38362 (data)
L$38360 (data)
L$38364 (data)
L$38449 (data)
L$38512 (data)
L$38516 (data)
L$38394 (data)
L$38514 (data)
collect2: ld returned 1 exit status
I get a bunch of undefined labels when I compile the enclosed preprocessed
source under hpux 10.20 at `-O3'.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
begin 644 input.ii.gz
M'XL(`$AR_#H``^V]:WL;-Y(H_%V_HJW9V*0L.2+E6Z38\\JVDOB,+7ME>W:S
MC@^G13:ECLEF3S<IV?$HO_U%5>%2N#6;E#,[^YS5,Q.S@4*A`!0*A4*A\*>D
MWTLVO_WTZ=.W9\7BV[-J-A[O].[T[M_I?5M7PV_A^]LY_C<ORL7\SG"XN?&G
MI&T9_.^=\\VD)PKU^RN6<BL:#G?V[NQ^.SO]=917\"EH&DX6H^S;>C[*9UA/
ML@>E[JY8;&^EJM+JS-1U=V_5<GL;\\]E-LK&R6!PNL@G\[P87*2#25[/18I`
M,U2?!T#6O17;TA<5X!\U:5%7!N9S#7#UYVEM&M!?M8^I@O8=)BJ%!O,JV_89
M+[H7:=`@+^8._OM+X<P8#,_3*A%9#P>BNU7BHJCSLR(;4>["S:[/9]4<"O7N
M!TM1_L(#$`GP_[U^L!3D+G2V6VB<UO/&8@K@3\G#^^V;+^N#?Z?I)ZL"E;4P
M>1N&K,FL.(-2Y;P*DH7Y"P,@!F^WO_JP#":9:-=#JCP^/$$PV7.#<0,&U7LA
M(#W,A)W&,H###'<8D-,116(1$L.`Z"5_-*`(@G$JEJ,P4&+@[M]K/W":;<2X
M*P3]MO*8S_=^=,;[(JRMC'3QXU\"?^Y\&&471/O==<3<'B'EB!=FILWD5'+K
M5@(CF<Y&F8()0Q23O/C(05SZQ^6L5MW_8#UQZS2`8]8-"#=Q7)]./@X+S4#?
MK3/^'@$>^C`5"DKH$)J!6R^BX4$,H%[:`^-\PGJ@MW?_JU#@5=#<!_8P].X]
M^*K=T&84RGP4Y&25/[E<!G&V)'^Q)']N\A5(`*JN\]^R^*#BI!L,ZGR^9&(.
M!L."S5X'#!?%>3[-I%Q<2W#MA<6V:@"H5]=@=X_3AI/9\*/3'J_[/F:?"81C
ML-?'P6"!/PXL((5@,!BEHQ%J"BP7U_<MT:>!/%.ROA2<&.EQ73;1.$)@6CB'
M><GH0G4VG!6C.M8?&K":Y%.]_'UWK34DB)N1:9I*[)DP+@T-!RE-`_CGH&&\
M%@,Y7"$0U!-``PAGD_(W@'\:RD>+2P(:ZJ<VG.;SAXT8!$#OO@VA1U+D[?5]
M;JL]I(2K]G%IV2%1.8-!7)EH[K1R);<G(:[7,B1ALL1I`VK527G^N0X@L,>A
MM!G?;H#$DYXU<0P-)_S7HT7)/;,0A#J[+M,A51#*+:O9W&V!ECXC4I="LE9,
M1A=G/:\60R$3J&.JY(MI8_6^]^$@N4JV9-Y!J-S?%^E(%,(&7Z23]WTL`JF>
MV!*-6H07#&*8H<RVLZB>27J:301-7]QE22^+IY-!51X$T^M8^OO>@P^1K!H:
MK[-&L\7I)*.<\?N['R255XHN9XQ)"H^F@VE6UX)3#@*"3]66D@3]4[+W<.U%
M2.%$S4!(,XGQ[MXUU$A/BQT-IFG]$?'>_2KJJ1Q:@;C.8&159ZNJQ+_U0$B*
M^GVGT^GOWGW8O2U^P*H]&W<D3#?92AYVNSN];O?;2%[7C..5K`P;\7#W6KI=
M]FF>546R^713D/ZGY%YK$UH8W=4JNS[;L.10LO=P95N>/RA?^*Q`^3HWL\%>
M5(2V(>1%0^YI6F>!;*7DC"?I6:RTR,TGV8OF[)\P^RKYX?F+HZ!P^Y_7F$C=
MBW%6C,H&B"*[C!`HJZBG`LG[A\GM_A9*,2-(+V;Y"%`L"K%*2.%]E0R@4_^3
MMH3]=?C*#(:4H:(*;JQM;2VPL$J6!^)$H_+9Z?L/!ZHM,@^&NLJFLXNL(Q30
M>B[[J'L0`BO2J0VVG305HM3YM!3E.AK$13L6&X$ZZR"1P?SQ1&ALX7P<#2&I
MQ&A)@.TD6I&`N_`!MR%O6^YR0M67%1A!32FK^7?NW`F5J8=I$2D2+B$K:0%)
MJ-L`*IR!D8H5"2!O4VY\ELV'X1&B<@!0=ZP.CX]WN1#(EL/4#IU1X#AQ*E=@
MZ``K!6EGI(<&;CFQ``(UB-_AW-J=>B[,HL`VV-584)0JIAH(QU!;U#"5LUKS
M)5G<PAU<VZ!$8*0``8UG958T2X=`H2I;4HRU6,C![]:4KG;3LH^Z8>JX`;G2
M(5'E)>-Y-IDT2*`JN\R+40/`<)*E5595#5(.-+*&W*J:14IC!24!./TM=*4'
MJQ[S:5U+HB?!F(B!2D<=6OV4M#3_VH1Y92^K?*X6CJ4H5K%KQ$<9=(P:I+VU
MM#?,4M0KS/*`A.S=;ZO\A@FA@1B*W]-\U+`"BCE;S,*C*Z?)"&<)\JDWQGL/
MVQ\5.V,<4CL*L6F6JL=@8'0?JTFS<IY69WY+1+I@Q&"ZF"#!=/&_`Z-?V8)9
MY,DV8ZVRZ>\_A`6+V^U"0:MXMXO-S&Y;:WF<L019E_&)*J3YY;+EH$'?H<1R
M-4DJU:Q,ZEE-Q5;9[,:[X"*DK3@N!H&&7S2K4LO+-VHT?GG1V'O7F[]4:T`G
M:M'6!A6P35-EK>U:Z@D49#&Q1P$3>Q99F(QNO020J7`&LKTNQPNU4]BDHNZ2
MU59CC]<95:T,^)+V@.[@T]5>B5C2U4R;6`+)EV4#VFY]#JW.;H>MA`F!QU`>
MU<\&&*HE#F66PQ;<"Z*X!1C(Y-@`"QG1^A`YM+6.&!_F*6ZU_Y3<7]D+:F_C
MRO-D:N,)UP\X-0QA=6?N:[NQ_#W;.N8N^M"+>9U.BL4TLHN!W/(\C>8.BWDU
MB>:.\K-\'LT]J]+R/)H[F5UFL;U53BM&/'=1#..Y>+@0S5V494.]GYJ:-)\U
M$3V?<=2PB,5'C9?U6!'A#EK`]$/:,(ZVL\OTBB_*^CP?SY=4,II=%A).S(@&
M)@QP53W,\VA'\=P_)=\]7`4S9I(TX*>'P=$\G:3%1UU/[UY#1;Z!>I7)VTI0
M")9F?J*][U8MM^>9PEOO'PP*MY.FV70X+9W%([24!)4+@;D8IO.(OA-=Z;&8
MKG6%PD22H!D-G^N0.RP_!ZF--R]28&E%D6X)=T=S;T3*S":3]H6DUB#*?1I7
MT_6:=%XY]?D33P.7I]7'5?="HMAJE8C_K5''?/9Q)1X@&XT2(ZW/,=U9YW,Q
M\%8;)@Z4U+VD2@1T:[^8T-`[;0H89AG699LM;:#DTH+L="90?.)LI4F$]U:6
MMO'.C_>^W37@K==Z/QJ6M)J51HO2.Z_9\/0V,QM68G`E%](Z6T>>%,L+-LCT
M8C)81XY1L?:K`2SC:RQ[5YY7\+JZ.7CKJ54<_EJZ)+LN^`J-]&I^$,F.N3QS
M*@+%.4AKK^F>JQYQ+,;[>KTK'JCN+$?N$9F?91=9,7>NIS2!<7?(?`8BY>PB
MG=#NB"0!*<IU+I*URUJBCHAUCCHHOY(8G+L`=/:N*@ZA%SE@E,W'GP\".:"Z
MSE2&JD'GBJ]%9JK'.J372VBL[?:+"2;V`!H7C@1W0$G>//_QZ*^#XU?'1\FC
MI+?MY8C_'A^^$,E7:-9W-7]_Z()$&0:$%E)_S:>:$-P*3`="Y!S8*=.\<%+.
M9XO*!1JEG]VDF5ON<Y:ZY2[]<I_])+&UK8DOL`?N+VN>:IU(JLMLR+DAD?Z]
MR?R"VJK3R?E7\`@F7QVXO*6QX0](T^YE$B*'G$K6J-"ZI?,Y,'E6"98Z:`*2
M+'?%N5SR$;K\HO.5J>;IBU=/_S)X?OS7PQ?/GPDVVMUVLDZ.#E^\??[283'*
M^^OSD[?O#E^(K+Z;]?KD%5IY'B5W3=;)6\!TLBM2'WJI/:CA_L95HLFT?7%C
M#HS8>>I"P-UE#.QVFY0IB?/G#K8/H89]P3@?^8Q@K:&E2B*U+QM8"<-$B7;4
M8U"_S8K,<2&:_P9S<#'/ZLNL9KY$,D],#2AH4":^W^1@^'DXL:2.W??G^4$D
M9S*38H\PJ)L*38L@-^RIO7'OP5*1I,O(,[11/AX#0(?&<%N.9??`T\_D($\_
M(K@1;5MQ6(;84GXMC2^MAPA'ND\S7G5&:>!M[/;FSZ`ZFZY<1$RK=-*RE-;?
MJ2MM_<W5ZD+M_%.RMQNZK^A-1M4/=!V!_E4>%`()6F+;C3\N_//?U.:(RN^%
M+B>&.$X>X_T&3E;@'QS0YV'B$)VB#NH7):K<3E`".:0K$XHS'\5*A:NL7K4L
M2<IAE:5SNUZMF<!H2GD:=D*CS%$VR>8T#ZK@+H)R5"]).+DALSJ*+7U;VYZ,
MM?\"1:)5G[E5KUAX=I%5U:)H:&*1%K-ZDF5E)S+RX3$1+/F@W2+EFV+8W(UL
MK]PI^#!TPS,V!?5J"FL)=P;GS19*UB0_.Y>>VTLG5\(6%<0_&#`7[7O!J\-^
M5]B'3C2&9#OVEEEFRG#.-'FQ``]BX?8(%SBJUFB4Z?P\(`<`28K2NA9RI<LT
M1[M9`#$;B_[M.(4%5;2GZ3)/#;MQDVPX[RCA#$E;[C]!LHA+[O6;-G6^K3D=
M_1I8W@RQ@4H\5N(K638?I7/?_S7FE0+``]><PO#))IO.LMG`='.,?B\==:NP
MM26XFG(P<@^K9N-\LN1H5QDF[]UO(1\"78*>/[+7KO"D9_GZ*QOY,1\879B+
M7*7D6CHNSRC$YERJEKC%\HP/]@:S?W]=VTV[,UPA9GBXD+;W8G5!*X`"7'4'
M95+>]GOPQY(^R4_7.552Y0)'R!L;-J,,!L4$KP<.@.4"]\:"%Q'^OI@Y>X<J
MFTK=?I1?.)>X/!3:_\+&HY,-LHG$)CBWO=.D;KTM*N16()W/QIY<\<39?)8W
MN:EH4@7@I`E05HHG$ZZS#?T;18UEO%,@*A,Z.;'W6AK#8@44V/EI,0IY*Y-?
M/^8N.9P5@N=3+@\C.EO=A+"%T"%<[`Q(R+"LN%CF+"3DUSR;-BP4`FJ2"UF-
ME)W6'518NLD7P67SA4#2&3W>[?YYM+\S.A`BTF8%Y#[X;R?F2400\$_'>!RI
M7[&1G0`=$2`\N#UU3T@:C//3T_GL<MBYQ$D\7\&J?SF<SZ:G>ALG$82/%J>G
M-=12KUB-+"T*0E6U<S+'<,5/A,=5IDZ#0]E_KV?5/.IC!<T4'-AP!-Z5AT#M
M?=@CT@71I:>*FL@YW6F=I=7PO,69O->(9$DK0M6)O;W8T75LC+$C1`X;@1&[
M1`3RCC)AD6_OLV5WH25?LOG'['/3G$>PB0`XN_NPX]YB>_\A(6*^6W^U<"U'
M(/%$5?:@.D"9!/+(\4O@M/]U1?A)(Q$(,ET.4K2OU0A[`0^%?1`'RU:=92V1
M2P?`@'"',!DK:T=L=^S70[<\1$U.OP1`UW!N=]'HA:M,:^\&D6VW=LI8WOLN
M99:K?B!3:_FQ(\O+-&?';+V0`4"!M#]2#.TD%)9K'RF&++PV\GO-K6"]Q+5?
M1ZS1M7,HU5$;Q!B`^-4IR39F=M'V&3_LL!Z&;)/+.K?*ZMFB&O)CW]!^CX.U
M'Z=0/W%,?1.GKTV%:X8!7-:>^#FQ?1[>;]><O77[;P`15_+YX'0V^LQ]`>0F
MAG+YZ1!%:*%_A@MV`9MG3--/Q"FX(=YKUX:'H4E@MT%1M8!8#?'CI&HQ6.AS
MG0A`30#V;DRD"]*KN@YDY)3N)8_"R74P>9H7XXF[!\1:?PVF%_5E6@:P%Z=@
MNO8S8'T.9N2SX7F@VOJLYI*6I5?#BQ`Y8K%+)X&&%1?#^C*0G%,Z,4*OOWR(
M`W(L<=>MLLIG53[_++<I(Z7`V5#$)9:-5#+.E@=>AY!JD>>CQFEAHZ:9$D3-
MP2W+&BL$BT#(:\7K'92ZH>ENKQ??+5\O@BM&8OZ\-6&O8Y:"4)^JV`/+JKU"
M7FB&O-9R&I3N_F(=\#T1W+UD53)`UR0R-$`&^2J.1$'=I"4J(9#<\,(-4-=;
MAAFB:VM,D29S_/)/>Q`-AK.1=9#_YOG@W]\=O0,/C1WFO2&2W[TY.H'4GI6*
M/AJV$XA(/7SS\_'3YZ\L!Q"1_/+HS8__+H#W-JZTUM1V0/="DL!OG>>J($%L
MIQT40KGMI:53H4N\1*%@<U#MTB6RI`N&SB/'--MBCF5<(ZC[1U)E,!#_^ON+
M9=A7KLU#+&M?--6N_JX$X,=\,ED.N3(=THUNGLX7=3M"WCS_\>F+9W%8@"E'
MZ3SU03"KF@W]G*5TJY@S$&\MC'B<+K@"TQHS]<"X81CDF>EI6@2`KF0T'N9^
MA"'HH/T66XNFIZ/WO=T/!QOHAPCS1'GD+)EM>^Y$^[+.+/K?F7(M.OZGS!05
MD[/-9/F7FBU7R<>!/2\B[KE+M8HBNQ1@2_:P!LB)/L47,Z$[#^SNP.91SON'
M*E[<5:)@T24CI%CRZJZC=]P-:98&>;A3INGP/"\$;'J1(0LW63["P"L\$>"I
M7F&,*P0A]Y2M1HS>YB36(F_$Q^5@=#H9X!:6VQS4J6(M('8/@LF]<'(_G+P7
M3KX;3KX73KX?3GX03GX83OXNTIQ8,R/M[$4:VHNTM!=I:B_2UEZDL;U(:WN1
MYO8B[>U'VMN/C6NDO?U(>_N1]O8C[>U'VMN/M+<?:6\_TMZ]2'OW>B"(^3Q0
M+N"AR2+FOC]94/L`7##3#OSD[-,P*^>]:$X_FK,7S;D;S;D7S;D?S7D0R+D[
MX'[6+'GB[FEPQH:A[X6A[X>A[X>A'X2A'X2A'X:A'X:AOPM#?Q>&[NV&P45Z
M&+X7@>]%X/L1^'X$?B\"OQ>!CPQJ+S*JO<BP]B+CVHL,;"\RLKW(T/8B8]N+
M#&XO,KJ]R/#V(N/;CXQO/S*^_<CX]B/CVX^,;S\ROOW(^/8CX]N/C&\_,K[]
MR/CV(^/;CXQO/S*^_<CX]B/CVX^,;S\ROOW(^/8CX[L7&=^]R/CN1<9WC\87
MUPV]),A0U??<&V^ME;$J.[M_%R^@W&VI_^VYI%59G547V>A]?^L^!K&]4GCU
MQ:90M7M]?MDFU\]8,'PLXC<'.*OL+G+S>+=:B,MH,9$5*W56[374MM=0[FY#
MN;L-Y>XUE+O74.Y^0[G[#>4>-)1[T%#N84.YAPWEOFLH]UU#.6<E]#(;2C8R
M3)QC1&:_J62_J603V_2:^*;7Q#B])L[I-;%.KXEW>DW,TVOBGEX3^_2:^*?7
MQ$"])@[J-;%0KXF'^DT\U&_BH7X3#_6;>*C?Q$/].`^EU5F<AS"SH62\3LQL
M*!EO)V8VE(SW+69:):V7?^K!R)'-?G93Z2J;[S:61X`E&'K+,/0:,=3-+:B;
M6R!6DN;Z$:`)P]"3<B&`)@SE</;WP3G$^6M"8Z":<=6M<-6M<(D:YVD^64X7
M0BVEJP6NN@6NH2=O0P!+,'RW#,-W2S"X$BT$L`3#,KYQI9L/T%^&H=^,H5R@
M?MF,10$USD)7ZPKD-Y=O[D[(;R[?W)FUJY]Z^<U="?G-Y?>6E-];4KZ9I6M7
M`_7R[R\I?W])^0=+RC]8PHO+IL.RV?!P2?F'2\HOF]#+YK.KY88`EF!8-AM=
MO=4':&:BH:>_^A.^>1HBP!(,RV1K?YEL[3>S(@(TZP2T$>V_O_\A#C6;C(8?
MZ\4T#E%DEQ+B2FU]H_9>`$^K:G;I'C^C9NN9!9PGMJ2B$$CS;;=B+QE(\^VU
M8@\82'L82/LND,:/.$RBWQ#83(420VWIA1K3"[6F%VI.+]2>7JA!O5"+^J$6
M]4,MZOLM`JT]E!B$]'&"&MVD)#<KP,W*;9/JVJR6-JN<+33)%@IB"[VOA3K7
MK*HUJV'-*E:S^M2L&BU7>1KUF49EI5$3:50S&G6(1@6A<?5O7-H;U^W&1;EQ
MQ6U>39M7RN95L'F%:UZ]FE>F>.ZTK,<+L;*=G2^#F<PNEX',+L9D569+C[R;
M[-UN:&U4-@"A(\M)>L9\>ZQZ$_W;$WVE+0/(#THGJ#_[3%5\BJ^#$%1N+.CB
M,R_F]O7:*Z2T=-SL\5:3R/@TJ][?W=JS[-.2(M%O7O"U979TTQ72:@YUW+_K
MTZV5!P#88ZR)Y%[FX)XF?NIJI*=,R-O7=F9IOAQ/;H'.0A`>315.J98W[XFV
M>:I.N'4=C,9D.IP5\^R3>8A;7TP1S+$X'0SGG^;^-9#!8"'+88#PX0!>E+<"
MF&G7(LP67Q2-A0$083(?/@[H-DM(,].U&4H,X8E`H+[L/@+,92I4271D"L]&
M`4.QBD:#T\\0E$=BVH]):%%`*:<T`OM\%?8[#XA8G&KZ!),L6)]'(FFZ3F![
MH>`I!@CX.?*N]]D@G<^F^5#RXW(\+%IE.IQSGT<]\]VY+R_F@_`9Z&)=>7E#
M.;PY$6;<JQ`.FO.T&$VRJLLO\Z,KG<S0PZD9312R>0S;G[)90C=D=IN=[IPN
M0,[DTLZ:D*X/N-B1%)*7=7W!FQ+1^BY8>$;9'_5%N#>PQ@O9:"O);7+,V9V3
MX%U4083\]JZ@!(O0N)I@#$!3MQN)WU^E>9VQJ/HM.L,J#[ZN[)9DH`91.IN6
M\\\0D4TS0S"P0WXV%MC:P*6CD0W64/DHF[2&S>MI-CW-5%RA5F5H-@6N-ID)
M:D(3L;0P-O"Y!8ZQ\#$REO5,O:C+K!AY#8C4)D#SXLSN;_![;2&&7%QPN0@D
MB5>U^,<2,_!OF!RXD#C"N[G+<"3P8TFHN$A$-@S]M(@,YM\7V2(C?@:O\VV5
M7C151A59`8KQDHB,3-!J2GES^;0>#=SY#)$M_-GL3\CRS)Z2(3@E.SNN++68
M529U+5'J\/]D3HA4?Y/>@&CDSS"E.)QPE7VA+N$K,=0/WJ$+]9G7;<0RM@@,
M]YE'S/EL,EH&4X$P608$[%(MA2K3!9.\_;U08.;8E%,^X*B#6^$:'`#1%RA-
M`B"2#+&@S6>A@'ARL;/8X2(2,5'T.^=52G*7'C>ZJ-*'!97XR$\T;LV9P4U]
M=:^%BG"%VOVRN;>:I_K=X';!U07O!F^Q-M>*$)]K"-_"JELBAIM=[<=5:EVC
MC[E!:3AOLXHY0G^I/F:58W(=3P?9R-GQ0%KM&E,AT37$BK1A(*V>^&"31:`2
M/ZD$9>_*(ECJTP^;IY4<L>]:RALS$S",[F":U\/`716<6J)!-*#^7E7F<UTT
MF,]51_-'.VV-?D`*11PNFPE(/]N)VP*`\#1*E!J(@]EKS.U'<]/J[/U=8Q&X
M,DN2TZ/QVV%VG]?TKU^AM7D64"P$0;S63]>NUFP9`681(DPK+T!5SJF*!=\,
M+7AZ__JISN-4L^UMB%H8%;P-",K?@;?/LXAEAT1$ZA(9&)@KOG%`=]N2.WLN
M=]0-]^J\,:T_^<!7HC^P7R*L.@16K3FONO@MH2C@Z_'4'LM>,/*)<_7^7FB\
MS=5_*V2_Z9[7@]?/GVWSSQ_M[S?VYSO[TP%^:G\>OG@A1&@^@KH'CLF/!Y$#
M-5_H21).Q8FPS`AZ.QF,/&S%0B`.@"1GA;G4-QTMHU3D=J`CS"YMDZ@'116<
M@#%IE.T_7`KY5.ASH\6TW`\(0`?T;59-1<(^L]=?0?*!;5'YNBUY,Y^54.GR
ME@"D$-4<$LA[8ZP1_;OMW^N5`;E,J`&W=AZV\"/$;2P[[4)J33^V`@;$\_GG
M>C)CX=[[*[P8'@L&APIT>O]N.-:G2^WD_MTT$C6-`++AQ;Q#UYQD[!"@G$4I
M#I8:KU7JS"L5(QZ5ZVPNU@J(@Z;#A%JQT/RPI4[Y*BWFY3R\(94AL><UQ--O
M`H$X@Q`Y.QBY-%PQ/28;JYG,@!?A$(=VW7F1SU%CL,*<;D<"7;JEQ0Z+"L=H
M-9'U9E,WD&J0ZR2H>;V@U_[!=,;.4L)`E$<9$4-5!KT',?+8M6](FE6CT\G'
MVDZLIW[:>3CI?&2G+4)EQZ'$1;#J<3#U8Y:5PQF]9'+%5JG8"8TM_P3*WC;^
MTZ=_]N@?M6NYPB$8T.PYB$0L*2]'#;>796[X-5])'40+O!RQ(9$3Y7(`$^7`
M3Z8"[,2#+%27=E"",Y5ZQE,UDO0LA'HXFTZS8A[(.<M$1P?2!=\%4NOS;&+O
MX/`T#NI=C'*'-RAU/#E3ZT[PO1+931A?\5*TM+,PD:X:844O^I$F[[F;/#U2
M'!V%*2Y&Y:7HE%!8Y%!]$5`5X=0"^%-RW[5*<$*4&CMP>23,(C$."0YZ=$PB
M0^*=,SAM'^O&A]\V=YH"?54OZU<7>LFPN^!ICC8\:&:[`L@JP3=67?BQ(9\]
M7=[S#"MZ-*\P+.&ZVE3K&`T89<4(I)9!XW4I+:B`"63$EK"!RJFH%S*N,;1M
M0RN$MDL:C8Q5&;+/L*KXN$EYJZ1-XK=.BGH,UK9B9\FQL:IR)WQ)3\P:^:,X
MRPYB/B@PBBO+D`J%R!(YD[R>O_\0RI=OV"92\2$N6SD6LW9M<-`/)B-45MDZ
MV*![ND7'ZQ<]"Q>-QH%'V=.)PU#<Z#V(J(]JE1?`W#_1HR*BQ)X3N%PA\(M(
M_7\^@\==`2P.M)!05MC^1IQIR&YOD*4VJE!CIMET5GV>IF7@^-=5$-6/D'#&
M#1PHT_91#0=A0R=?,H@_?_"GY.[N&F&?\>'7AW_@"QR.A.M_MWI=;F5N*565
M>NEC0[Z"VK+`ABOE@@];;R06K^>#^6R0:A:PLL8Z3PWJ5>LV4`:%T5:-L5]7
M;EG2U96#D;(#\;$#4;'M)/&_`^TQ!:5FQ<87IPN4/H7[F!0=B=7G%GAJJ`]\
MFE'I1<$PXLD`"@]#1\7RA3_:4B/811",T348H`E(X*Z[!WZ%`YAP2VI=I>JF
M^I?`6_T+!8&TQG+8N00G!C+:O,&LF'QNT\:5&[I6:Z_5Y'"[-VC];C5IU,J]
ML:$G/1QW6%(66`4JR87>6L&[5&J)@+I6>8DH9W)PK_&Q;9\\4H\_S:<EA%I3
MAB689^6C7;4.E&(Q'.>?(`$('LT&"WBWY>.CGB"50``#F`$GQKX"?"):-"L>
M[=*F;A79B1T#+@=EE0D&&Z.QWWZ]#;J)2Y]\,LG.4OEBTCP5BQLH91OLB1D%
MD1?E8HYPR+##+@H:^>;,,'G\*-E-;MX,(1Q^("WN?N-RX[2E]5AB@&6N;Z]<
M;K5X<79]/.KK.L3NM=P^^=3"=@%/@J#'L"C\>UZ6J>C4G?-2_&_QJ;=[I[_[
M+>!LIN#:R$+;(;>J/6]'M>X8?%NF53IEF-MN#WC1ZX4)W&O[(`NOLMFCP6E4
M-&Z@UX*`IX6`K69M0@:N0IM80CA]L9@Q#LJ]MN;=Y3WEOYZPU_;UN_;#4)?,
M1V7OX=KX][P!-.PN*=C[*A.9(UM)E,A7&=80?;+*EH],N>4>K*8.@-/T*LL@
M+7ARJ_;Z.43HOM.[V[OW7?_^O;U[#[][\-U>?^_AW?MT^'#M[5:,FK2NLTKO
M&_IW5RJS0<]OX:?0!@;C5&@:(^[&9I[AD8LUEA!J!A7"13K[5%:D?@"$71)4
M%UK#\W'2N0&@7=3MO$JI+,)+<TS_#^NT47:1RV=C6N\<=1FMV;!F4B:]DKW&
M;A<[%=Y<*A;E("U&`_7"7U)`U_.'-.&1T-JH5_B9@`L3**GPN]B6B9_4C\]=
M%Q[_.RBS2NA;\)X'WSBD]3#/![/%'!0QVKEQD]NB%&H?7`'@`!QB#D<AT`:O
M[`6\03%9D)\52S^/I,.1(;;,5[IC@S2L,S,7&OG'*;&^<M5O''"7L#Y_3``2
M!Z>+?"+VX<F7Y.F;H[>#)^^>OWC[_!B/#H83,4L02NSG2R%H\N$^;+O!-Y=L
M$/"+8V&I[H$[2]4&+Y9-6_VL2L&/M=NQ0+K$ZV01`6IN*LA_/%(58;*NR(*P
M<2&6<95G!;"\:N`@Q\=OQ6[K0FQ3]I5)YN)]_]Z]Y'8/3;AZEE30^BM[`P%(
M]O=C+1`;"6H#WTY<R#V#0D.$VXA<\M6.!,K""PX'!MW6_#RO$9\2$(!O6*>3
M\CP]<!+%-,HJ-W$RN_031_D9](R=^"F8BA[`;F*Y*(8>9#HI(%J``UGEA0=Y
M5J7EN9LX+.;5!$U"Z3P?NL.(UGR919O%?)ZGD[S.1@<.&R,\CF8R8&RP;$=Z
M+>$_G*:EEA&M]N2RA)RTXH-/VI>'KT.35D#9DQ;,QS0_X!?'TG[^)<[4U;/L
M_8?ELPQJ]&:9C8]--W=ZB=+7G%X.Z39&MP'.SE_C4GP(W3N<.A.&$N74<IA3
MM;XM<RIXQ9RF]^09^!_#G%E5I=79:IJ)+B-YC[ZQH>3ZF!R]?/WVY^WDS=N3
MY\<_;B=/?SH\V4Z>'[\]^O%(_'CVZMV3%T?)%7I_$),9AU+++$9G%:B7T$\:
M*OJM7OZ4/B6)Z4PBB+A?_O:6)Y5.S*N_7:[6&<H,+S^I<CV3\*Y<A\T;^7:\
MR#.I5T9QD5V&Q0;T83+)F:&JJ+AU&A,V4Q*(Q'D3XFR(I8+C;ENNOV:Y/:<<
M&?G6T$S;<^VL6IEIL8C5R>-TGDX&E_G\')^70%489$?'W5*`%=1L.1KOE?D=
M)=',JFDZ7ZG@ZB/ZM49X*9[`B+OL.ZO^MV?7P+.L9R_3JLB+L__MVS7P+.M;
ME`=+)>Y:S5RK3>M-N__)#9#<W6+56Y/9UN2M5@T)66K*:G8&1F8ZKV;6AN&B
MJK)B/J"I>1`JJT#47*:;/&O8>U`M4X(#M"Y4MO[C\.1X`+J9:,HNO@V(*<?O
M7C[!YP)W^SKMR<G1X5\@Z:Y.>G;TXOE+++FKTXY>8#&3\.;IX8LC+&?23@Z/
M?SRB@@SPY^.WA_])I4WJL^=4UJ2\/'PJBS*$1S_*@B;M[>$3693!/?_QI[>B
M*8=/5?4<\?,W;X2RJA"9C.?'K]^]5;A84T737AL\K"6O)?Z^G?[#JV.#AJ'_
MT>#8I5`MQ`+`(]245V\/L5][#_`/-TIS/5/XL#K.4AMQ#FYD^J\%2O<ZVFY>
M\"CVSG#80@]DI>K/T]/9I)T].E1,[F'HFV_6>$]NX9'O@;V3P[3!`C=R@0P5
M+DBA0T0Z_!(#IZ!-"MS9_YA-#5%HGWO3XGX^NP3VP,V(A.I:>W=TA#M/ZW.^
M0^$&@.31HPZ5C`'<"`!8H@IN"Q;SVJTAKP?%8C*Q-T&VK)-=?_SNQ0LA!EX^
M>?7"F`(H;W]?-2O93^K.+FS5KRQS@8)3].KV)&7`4E"+]B;EG?I@"98;2[#<
M\+#87:[P\:[G&!Q/0`N3Q0<2C]O)%C6QQC@CX/7#+A:4[10@PW0N6[TM<<A0
M!W_H-![E>!\ZK3[KJ7Q_G:+*:TS,Z=DP3W6D)=F^6N_-M_"9<`:&S'4AF"OY
M<K5A#&L&>R!ID,_E_(`Z3'JR!;_U'.#3.%"XPPK>U":%LTR-@XGQM"7MT"X=
M6+TZPE`(E&22=I(Y''M`M`R6-DXAC(33$8F1=EAKE2'_D@$DU!!M&R$B)[/9
MQT6I:*\5[1>/=GT@]]!/95?9=':1=33_.;;%0"?RCIF=_IK)VT30$=5PML"K
M,H9X@B`Q>9%7\T4Z27ZW$O&@<C0:5-DX$TK8,&/I1)V=Y=8^"#".EQ/C'Y,^
MLI@GCJ#C94592?:.PTQ^>8>E1XV$:!Y0V&TN**:F]T;9&#:K.L=0)/[EG8S7
M#R68X%N`5(6R2X[1XA95%YXM3O*T[O!"&@4B]#DKWL-RZ6(2-@Z[O\^[O"Y9
MI\]*R]`\RN\@J`#IJ#D^*^6)=&MM9CV9>WZ!Y[+MSB^#Y23OT+>>;P7G%,J3
MDX=^XW^EA@+EYN!$J(&DUO!;5LUXJ9M:%[FMS@!E1A!H)P0D1UIY%O"S[(NF
MP^R6)2]TT8NE9;5B==NF4VGP2\G6"':^,H)`"4L3_/:Z]7D(E.AH+K:U;C'F
M7=*RB=^OVD2K].-KE?[^T?4JOU[Q1]<K?F-I<78&(D?JK[L@5DF0G#<(DG,F
M(\[7$B3G,4%RSEKG`NV$@.PN..?BX'P501(I*;6S3_$2GO@XMSM\*;'>[/]:
M"-J*C[7K\Q"$Y8!;;&O=8DQ\M&SB]ZLV,2@^UBO]_:/K57Z]XH^N5_S&TN),
M?,B1^FGWP+W7,Y!ZAA0P6]N.*T"=>U=7!E*BG*]09&DM6@\HJ^QBH()+KEKQ
MMFJIA67#6N[V][6>)3:QA6LAH?(*U$A)KH@66Y:[G&U+4$6U.+5*&BM"*QTG
MN0E"T4GY+-V<Z!NWI(*=$@P&5=TIDMN/DL]W"N;]5#55N'/]"G>N66$`O<#Z
M*-GY%,?:H&<UM4&B$HB_19+C9(9PDM=G<V=\^RAIW15;:]:QM5(=B-'KD%"O
MMZVC00-LU_G)]XG3_0UJ84N4CQM1.KIB6S(?-=.Y%M+'S4@?K87T43/2&VLA
MO6&0VNQU4XNYR$[3,!C*(WLB&V_,)4AWXDAWEB(]5^)>:<-Q<:]`8^+^/"[N
M5=&6XKY9)^7#<NX,R_EZXKY9!5VKPF9QO[S")>C7D/O+&Q.7^\TZLR>3HV0W
MR?UF!;M]'4TR.:B-&[G?NOM7EONK='Y+N;\2RI9R?S4R6\K]U0AM*?=70MI6
M[J^$-"#WU5Y?R;N(86`UN1]#NA-'VE;N+S<Q^-,`A0^5*^Z((@*8+!$->M92
MDVA$M[UF-0'[:8N*X#]B8*.5+;.Q1+H,7&]%!5N?HH@YW@A:60QQ(2:W=#D3
M>?5`K]$2CU5:-G;;N46UG3SHJW."QEL%USXGR(J+=KZV7ID-'=[WMVQ0I<59
MIFU[T[Q01KII^HF?1(UGQ1S=(;@W!L.P1:$=`QX9!0+4"F_)S8<:*]D"S2="
MXC!HJZ$8#DKI\"0<AU$H1^I7*H4Y(>AJO,P;;J9L!QX"@>/_P#03:<1FU_9%
M)(UA?Y^U3^B$9<A)@D&'2$S&M<5W)<CA<7VG=`5Q`,^-1CPWEN+QN]?"T%PR
M6.1;=IOO2@>3$6R95[."0B=NR%DO$@=XOPD>')N?=Q@0GDHS,+SQU`(L`T<-
M`=D27KX6UQ+Z/)V,VQ11C18\="!]`,5/Z?^7O#U\,CA^=7RTC;]>'/WPEGX]
M/3I^"[<TX#=ZS+%;1E"\AJC%.#7%%\5AS=/)`"*?':C$*BOI\2]*-;-0(Z#9
M8CYE\T8"/A4=MVTHA?\XP+2.&F+(L/B[@QQGDF;T2"%=C:H99'&!,>'34T55
M.:NU%6Y+`9HZ]!5!YC;@EK::0XJQZB2ZI,4<(6`RS"OP[5,G])BI#8,O#T]^
M?$Z>FX=/Q5@-7AW3U<!E<,='_PDNB'W#&E`A1`\[4`G%#)[<DQ^G599^Q-FE
MDW#FC=-I/OFLT^1[1.J*+LQ2S3&<)Y7H'RVFT\\'9M5%PR:4&DRRXFQ^SK+"
MJ5A@GL\G@3PWV8@E+*4<9$PR=YFILK\OLAH8EZ=BP7`6QH,YS_*S\[F55$_2
M8FZ5APJ+F4HR7ZQ#P5D8(&7O.GDF&1U]<-YS4AR9P[/2T:^+>CZ8XMA*`G(*
M^YJKX#KPG@_Y"VF2L?,#F4.HJ<)LO=96T`4#J"8??S99E@$<[M_#HPQ`(#YA
MH/,;LK`H1!UJ*A_-M]OB9+AIG+OR8B3#Z\I4+P%"',TJ]/K066@\@;<L0IE*
M$4WAC4,?75K!<0`^1V&X5](O-(Q15B&]-A^9=-WETNN$`AO-J[0TPZQ2!LHA
M"J=[LD4SUIE>-B$R"Q<:(2+GZ<3F1)VDNTN)`G@1H%)+@Y2]XE=MJH=TY=IH
M]<@I+6Q.FA+`EOA6KO*XUNEV9:GHGD$A^5X).UFC^+)3);C*X$[ZXSPCQSE)
M!WY;E)B^(V!#.DTW2,*NTE,&B(BE"S3#;)35IF(4G+E0:*H18^%:`*8J]`'S
M^)T*;LH+;$HZA,FJ'R^DGO'R51_)9GCYO*F$0J@3IQFL4EB6#QR..F5SO4K1
M+'.0P>H,PLNHEW#TI)0@]L3B.=/%9)Z7$RW.BIG*T:RM^^+\<WF>%2G%_E#=
M@#,5,XA)=3$W`S<GNFD<E[S]'LRC_M-<-!/2H,[IU>O`:BD$OTR4LY@B.+?2
M3;:,WH$3C6Z",07(5-.A@5.JC`LCLXN14D_FJ6`!6$?TAORBWK9%KA<XC\L)
MCPA<F[]*-<'*-K3_J"A5YZ>3SP/48*CQM.Q68EII9WFCWR1;P_/9K,X&)HGU
MH1K9S.U<ZG&<HRSU$D3LHO3202^4S_=0JIJ+'W&?A_-(*\+;:IK!&SR*8$J"
M=0)E-(:MLYQR+8]Z%2+3N>@N)&TUFV@Q9^>*B41]YH(9,2EGAYB<8K45JK4$
MV4BXLL===WFRO"_B[%2$\LZ!F&H]*S]'RT@''U0GQ:[WB_:I1/TRN3(@\GHV
M*Z2G)"]HYBD65H'@'6#]A4HW0=*@H5>`HX5P'T8$".HJAC8`X8J)51Y7V388
MD(.5.4"W#[[O!"P9V`:C$0,";DZPRIM^!;!8#<HB8@$;%3I,GJ-B6V69HFV-
M&-._?7C4PCUPTLT1^MP,"S<`6%T)/<%Q2`4,0P[8&CI"XV\+GO1VB[K3F1(,
M*H6IZ$[U\%0O\TS#1%H8O617Z_0`V';*RR.]=#E$K&ZV[_(RM;3B'1S,KS]F
ME_Z4T=F*`Z(`HZP,X&?*;+CN)@!N8F'CZIJ#P&3O,+S9B5ESQ.S/;&A_`V<5
M"^SO7"8.&(4<B@,0C'"&*F9DHFAJ%LX8:!@QVQF@&,6K-ZX)!`=-;!+LN>!I
M<J%LK;;%,U'9\\;9T^T:(4C#L^O@&V,[)[`]=@1V:,/-!R^\(\?.96H$S@'4
M(\QZS30'P>6@SW/=D^LMN+FKLC.A;F85MZ(IC0;T3J;]*.F8\_L_.I5I`":#
MQ&,H2QGC[50^Z\.9).2]O!";N7JO[DG>*-Q18<^SS15;ZF4\0M226+EQ7HC%
MV$TMLDNGD^G1>>Q)J8K0ME/K>%I5Q&&D<;,S4.USQE=GNMJ9HW_F0H'(AV(&
MB'WMT,P]V?34NN9$<]EJ@CM'V?K';)8^'*BBC0!&(V@$"ZD05@&^W;`V59"]
MH;U/$<Q?LG@NE\)NGEF4>:K0G<,9M+@'"\2R2)3XZ98@\;/#6B&':%`>.9BO
M@GJYL8[C"H+5W4'MA$-H:U8(J3)>!4;*6BQXCFO&"`X!&0X"66108,+:Z@)C
M+(J@5D:F2+;95$JF#A*GH6((]'(71^,M;.U`9>=%8;%BK<_1[MN;7C*+A[[B
M^[CAHA+?!U8(D')6#D0BE+22%_4YII.HWS`'I0PC#I2\$YAJ84CQ[)DH`7'4
MM?W&:==KQ1"5V^A1-DX7$W/JP6./5FE10YS[@;*"#N3AQ@KWE]<[E)?#LO+!
MO"FGP[QB?W6V3H[^_=W1F[>#']X=/WW=Q8&C,QR,NJV_)(*!V/AC!IPVH_W!
M7+LU]@@7V+YQ*X?P8O917]ZLNPEZ%QH@J@0.Q32&*Y<80X-'W1>!RFJ9[1;@
MDX`4*J:W^X1JEI=8)YF9NJ9]7OU;C,_\.[8*W+HLK)_X$>6%[@-RQCF?XP.S
MI.T<2[)5NHNJ"2UCC*SF>$'9_TU_L5'\G?VFGX28ZKYITDW8R$<!$%HA2UBL
M.W[T/9[KZD+^L`5XA8?B8ZLYM(Y9A:P[P*1/L(N_SM)\+@04PV\M18M36=H'
M<%Q#K)Y0_FNF8_A%.2WI:!64XUR[$A)!1OE%,P#T8C.$V`$T`\"FKQ%`RMTE
MM=`4LP)=;#MS=6RDD#FJ]DZ6!0SQAH)!0SFT$_P/F*JLNMFU)0KY^>`/E=9`
MS,KWK&4A-?7U>E_34;IMN*5<WZ"+ZYKRE0H5H<5^J,Y_6"5H>W82.ZXQ>91M
MVX5*N9/1HM*H,!:<N>G45=XIG"#II?+3SZ]_.H+H3,^>O3C:5I]/7KT[?G9X
M\K-.>'[\T_,GS[FKBAU6/,>@WG&W!J,0X[&YYQT17`EQE.PJ9`9LB\)\2FEG
M$]%2>>:F(EH`"9D\"[2RYD+(%3*%+P/(!.:0P.SR12G]90X:U+D+,P<$-I/#
M;7MR&+\7U/1*VD7ID!FF"I4D)R+8[;VEG)_7V*74V;@0G\,J+^?^!M4&C&UC
M;:A)-IY'=[Q.S<;N*#/P6)%.9OV,:5:=2:7/LBHHQ<9Q:PBTV`P5,]KXVI%&
M@4\HS?5MPVEN'&:WA/;O46B.;F$F!3#7UF$%+(S6EUIH&4JQB-7:2AEJC>R5
M;#*VUFH+!G@.SK&K3`7-H%D?P@>P#)LC:&SL5I9E\!-"R\JLC:F%]P<)#(JY
MZPD/IRFF@-B$&SW/[BYY6H\.G('N)^,2L5!N3S4?>EQEV6\9-TNJ;'Z&B4<+
M^EL[U2'W;7.&;AD_TT)>@9XM>JYM66G=RHN"&[?XY$+L=;!O)KE\L9)&?DO_
M"(PY6R]<(ZW/^G3DC":^7!\DJDPC::4%6G_[2&9BMDS2LM9S:/*Y`>A\5N6_
MB47!!Y/B1RNFO'BN7CUC/!:9=&9%Z9B?;O-@69(MHU,MK^?GQ/_>RA;B2;@:
M-I`.04W%K.7&E\:,Z9WFUQ#_1[;#74HL?TD<98)@SM%0<G^?1@^NR0D)ZGI%
M,Q"U.BK((@0IUSO*H3",6LT<V.)1][^O=>#"S:>6UK/8?%6;E,(X!RG'"94%
M9C1T3K&T.?#3,VJ0\<`BCM";1:E!F)V=`]G!.&B)O9[KTX@BNW0+F,,L/F[N
M?I/-R+`,-:0;3<BG6CTH@']E-9L+9LI&)DP(7?>B&_09]JW!)CE.OE1,=$H!
MQ:(MNN#&(T,IN&3QXOWCC)EU?N2<+'N+0Y-6$5D!0LN(7D78/GG)I%YO!5EK
M;0BN"?Y:T&H-:+MFM^5(PWB7LXKKX8;[6-H7F^N<(JU8+%;&`O<9K,V0KM[F
M1:$WBL&FNWU"&]!0F59M7U)T21>T%S+_,WD[*@MX[$=OO]@@VR^84`R45+L*
M3\2%N][3GU9G-TT$8*8H]L$F:'=F8Z=<TBH;(8M"^4]J&1ZQT[EDI$6,;/9D
MB5U,C4A.%_QSN1BOL'%;=\Z8EEA85VJ,7_+Z[8ENN:[?T//I#'<+$54CJ%RP
MN&2LM)(IN>>]"<U&-5,D=+=9%ZPCW@-VE#]N-20Q07X8P8ZR4K]X.I17,MY)
MT>6NU=X\QB!K<'X30\1XGK>P@=N7#*W7_+@E:95V*4XG'_IPL^2P?&);#:N%
MIK`W@L-E_/Y)=`)P_5!VQ>\,6;#=$1;_ZGK/15./7"SI$5-8CWBP1]ITR,62
M#EE3+C08(IO,B\:VN"ZKX3EXI&-9$&D-I:\%V.PSBHC)]BI@:R,1N^8*Q_IE
MBC=_&MK!KK4&"X2VT*O1'K&ZKM$D9JR),'N(P9U2DN`S.D/XW<W]P[<KT>/@
MJ,%[11,ZLYOX1P?9:'G7,2'*+"M17!UGH_-[`VCKWKS^BGF-R>9)("H2/.=8
M40`%)L(2&VNCG78%XW'8<!IC.N]$J?G,:NG1UPHG&[6C1K4Y0*&L959D%BA>
M="3X.'R,+IMRR&5``'VC\).Z!LC"R-NXI%]),'4=N4+.H!H;9]^P56XUW>%4
M#/W'+&)87:4;."+9!W[2VAT@47WMUM=E-H3`#Y'6DSP1_W5H)8MQ,\42$H^F
M`X!.C%2O'"P.8?Q\;V*H#S@E_=%&-^W3<5&F><75[W.NMN&1",$X]I,JO8SU
M/-J<R,8%N%BD@]^0).6W<:!Q)UO2&X(I9JH"]`W8UH#2K&>'KOG=0*^NA_[1
M7>UZ#TEYERKIPGP?\FW/,\@6\MFG'-R9N$.1%W1%T<8<D*1^T--[`@C<1#^K
M#,13`+A[8#D:NOD:`=J[`KD;ZF8)W#6340/H#FS7')&QY6!_?S4OG^[&ODSI
M[':WC9L1?KF>11WX#^QWX&2ME.=GW",,#S%&63UDKF)H!86;.OJ2"038LI\F
M$NL=>S>J:[N94>%Z_EE&4"K8@T:LCKP>G,UF5A\5-@254@`A''@K.[U(\PF:
MM'%Z\-M-GO>;&]RIZP6&=D,^,(=</B&^J"F-''TV*">+FOY3GPN8A>7MR@K:
MA[^_1W-H.E:B95FEM+,R/5/N_S[L6-1][OO^*#QZGX32W7EV/%2&9#K>"E#*
MM0D0IV=4DW5>`I]FXUEE+IFG8]'=X2I/,W!\AU92=##QHYB9*^FL]<'BV@0=
M)#CD?>OAD7R);<<;&.&N69BW(9/@ZZ]=[7VOWURCE^/R$J[!3:<I'"<;!V4N
M:>?GF12]`?Z5(0.DA!2]I>[<8.>`"%'SB$=UDS=EU2HEI+".3@+OG9/S7>PV
M^Y0N\!@\W//W=Y[>-4C%G,#WAN#R=B[OB-F1UBZ$5CX"%WXS_^7*85WNI?>,
MO)K_E/0?_L%^_F<K.XY2&>TB?];HHA_RJ,#KJ/)658@U\:([1*+O1#V6\F)8
M9>PV/\\;9?$\NKNG\@.N=;AIG6!,$WR;&%?C9$PG>)>>IY%_8PT+A2MF;;*U
M!T"2%D`9ND=SG_LSP\ZEQ[RL##M5BG4UKU*(G*P2FE*P-FHRMD2QNN4T(CJ0
MD\)P=980D(1'+S1J;0>B:50;1T?=6;1'A:/D.8I/P_QIO(.DW5=H<+A46_W+
M.QWZ698NYY5U[LC*<B^R,!?%*+)<_/V;(?+V&?CB\\LA7!!#70:,/Z@F#RB@
MMZ`I2GAYP"3`OOM#!1@ZT:TLPE2I=H'J:'4U]ELHS$^/8>VP_:<<!5<-TP4%
ML9+'X3D6H\")Z`JHGTY.DK>O_@*.Z(=/_X(/_F[SQ",(N_?VY/`U3X4P?/S[
MV;N7+W_F"4<O7[^U$XZ?>5CHV6&>HCW@GSU_>OCVE57'<PCE>/+N]5LK\>WA
MB^=/!T]?G9P</7W[_-4QSWQQ=/CLZ,1.^4$^FLQ37QZ>_(6>1N:IQT?_\>+Y
ML05X_.J9_8VO2Q\]\_KC]>&/1X.C_R-(LML@+X182>8A9Y[L#<2;UT=/GQ^^
ML)-.1`MYRMO#)];GR>&Q0'1R=&Q5>?3J!_RZP@".5DA+X`QIM6&_Z:<,.HG\
MR*X[>5$I70#<*)G/LIH-L]IR(?F8E^R,8#:.>)_A]L7XC*%H/L_GEB,9P:`]
MA&'AU[XA0=_]S_%B&-PG,]^GZ?"C@U%L7/,IW*%"$0FO5%M>,3)JC\9N=@:\
MEC&X[%AHZ0*TDXA:9P8B=,:("E^%ST/7L/@`<(`;(0!'=D@[AC$*J/@S'7(I
M^?LBKUC0*4C$"*$S;]MNC!OZ[FRB+C)_]'W_R(81NYX/NVFP)\L=Z(9S#9PX
M2MXH$XK*\*/2/^020RT6_S5)4IJJ"_VA]OF0\+3Q,G"[[V9(=#K1\:WXHC<\
MSX8?!].\KN&6G76_VEH;Q?S0\2UXAHR_H,+6FDO*RB(GEQ+/.D'1`@2+SFLU
M7/!AO/;A:Z!CD3F[>7G)7()66;V8S-L\,B7^S<[D')+%UL:N](*FYZ@"]9%"
M9[\^)95$<$^?X?UG3[50#ZQM<)Y4ATUH56-V*&1YX+?]?<W//)HSKKN/'MFK
MC!L46B*0LR1>')>):&$I!IN*XZ(20:"%+R+(QTDG4#G%T)'8>ZAC3.J,)^Y&
MT%NR>TD3DW_\PTD62UT$KR5^XWC9XAA!9$OB.":^V@<?4$>&D4A!Q,91@2*1
M_#D9"C4^UFVX/L8QB,4]4E"N4O&BJ,5%"O/E*X[!Z%<1--:*%\?#E*+8(,,*
MWC"X4>Y0JWU3(T!MC!1GRD$<@]:D(TC\Q3R.RU6))4J(S5L/T@HWNG]*]G;_
MX!?M5W\U@<IP']E:/6#/%^_1;$#^KBA(R1T"UW\.)'X,-`JI#1J4&&KZP/9N
MM#9+[HF-LF:SO'/!F(/+%"P`T[3Z&'#-A62(U3.1D5)U_=HOUS/@,YNT@?:M
M-5\Q9*GZLZ*)+C5?2P):&+`#I>0I31"<9HKRR-;Q\/'HQH0OI:(4\300?-*<
M/9@[._Y0NK$KG0'EA=VQIJ+V=5<_3"V&Z]&MI(U--I*-"QJ`])B3RLBO'$WO
MJ"#1G:Y3O[*&F-)8M=)$+FP+D6VLA^#];L%E=OT&&[XQ,=F7Q2D.AYF`VN9D
M3W/IAB//S7VG`3U+;8K9K+0S8+"]^!T#=QZ:UW!_=P'8IO6/CA*\='HU0;*3
MX!6FD3V%(@QL&?>:64R#AMG*9#>S$K&1>KY#%*7W-N"'OBQH>EC+94N`!\C;
MEBAL_':,!&5!$[NG["*;+.=8O?^F+8"U);>B:J,/F)WLGZ@QKJ?(_Y`EED9Y
MB^^<%3"IU"I,1)[7;Y%@^ECH#&PX/;\R#-B/^8%FQ-)1Q84=*.3Q"8;6$#QI
M%#U:R19K;#-YZT8]Q1#HY_\W9AP/P&H&TPIXR<;87:@8PWA%)!_Q(LOF-9IC
MS'1!$[KI3C9KS^%]J5:@53:=75B@P;Q!JET>K>)TZ`T0;IQ0/7^\AM.LLD+*
M,L;UP"4_6_`NMSNRC^?0\:[`R1(3>&91(V2GZ#8:KY;<#=[)Q]>3K,M$IVF.
MFJ16$%QKXMIQOBUX"]#$_[2,:)QS_X!5`C!IJ8E$.3)4D&4/O66_\T7XED@4
M7]KJPW*&BPISN$$H^Y1+?SVX5,XR1K,B`S>[@=1Q6):A4`E,[DB3@0.1AI!V
M`F5/JDN,G&7/&3O:7BGD9[400!2HCT9!2+P2"-+3!8`7A9\NX2&0H&LQEJP%
MWA:+C.7J/&DW-#)]@")1>_B0X\@D+3YJLZ-MMQ1#72S$A!>]!OTJF5YL0]MN
M#M?;ABK3ZLI[458PJ-!JFRV>L[%'^&!V6Z$)Y)LK,E8B>^M#0V$YO;[:.K!C
MQ91^FPZVY8&M;`C]#HB=3)[RJHA\$`%.I1=T:DA&*;84Z@"0HEO894XX,:1C
MPJ/C9V\&;^!)M>.G1R!%:&%^<G)T^)?!DZ,?7IU`:I^G'O[P]NA$)-ZEQ%=_
M/3IY<?CZS>"G5R?/_^O5\=O#%R]^%MD/G6SQ[]OG3V5F[[X\O#(&.Y&Z)^M1
M9W`BZ?Y=3+DZL,G&<B\.WQ[1$W%.&C]HTXG\/--`OCTY>OOTI\,G+R*E7%/-
MAJ3%4F45$YD@D5S*(Q<UWI?)F^X!6)GA.P3#M)"O8I!F%\I!=[*&\RR;T=R[
M!D/M.^O#&:9TE@8/041WJVTD/I1]_,*F%J[RGB,'!^"NL-XR3C':&Z@*S&:Z
M%J]0J3&.`&K:I,@`G!1XD5]GD;_/=*9&3=)\GJ.WKISGKK)BJRC.B8LY+L7O
M3):6?$J^-?A;._=XIX2,L4,'8O!+!CB>9.\_'$0P#$X_VZ1R$ZH"VM^/,#HW
MI>*@)3?#<L<US@8P\_G5B-<(K#A6?^:%4')IV@:7G*MQ5"B"XY@<$1/"8\G]
M.*;HN8O"TW#B8K`8Y@NA4-*>E[?YB["$YKZUUIU7L\79N5!"K&HZ89CDYLWD
M1G"I9#O3/R>[[&L_8=5WXZ="-LF^&.74^:I`.ZQ<Z')\7$-@#UK+W:%$$)%]
MR9!0T<`\`J^CV(BR=<U^2!H5IJ92,4GYAX^DJ*1CJPU=:VP#A%EC+*6TW1HI
MKSF5J!;&>B`LT/59K$ZS3F#1T@LGL%+YT5#TJJI[5GO%:E>"WAD#*?(9V9WD
M9C%-NO1>]UY;+[@55/Z\&$X6H^Q;<%INI^L[)=QPX#\(D3]X^NKER\/C9X.?
MQ']>')UTK3VW[<O>,BZ@C4"N5?QQV8]B_9,6/)Z,ET>GV;S*AW8&FK3JP3`=
MGAO[)5[8_!)6R5\\_W$P'AM='+]SHX7C]\0HX`2?&Y6;$B:H9BOM>8.=6SE7
M1&&5S8NZHW<\.BNO!Y[?%?`/W8[2\-(!0S]X8<&:MU%:`-/K2.U@^4L^#6#.
M#5B_D0`$8VJR>MMF]]=OI@'NT$;)I6]\_X49<VO!/&>IF'.9I[3Y-W#;=44D
MCFS+?@Q=[&U7%)<?!`V>E2F).LHN\B'88P0\6*_L,0@]Q1+V`L_!GP?\KA2(
MV=C3!>C)+*5K4AUO%B=;7&J24L[O6<B[)@-]H6DPRBL+39E*R[0L]L/S%T?)
MUJR,O=^P+7]CP9*71#/4C%THL^T3<#=O/I/+*\?J0<J'2A5L;M\?"0E(%`<U
MWM[Z6,PN"R1!7;09D`VIZ@1%*^]NLO/7#CWG%(N>I8"N[22!A=&<%9KT,BVS
M*IIA#E]8SFE^=I;5,IBUE8.:0-]-%.R++PLZZ7-]S\BIMZ[U[26WJ8N:`@=A
MW@"..XC7>2?QH=M"EJ*A5<'.0V!X&;`1Q#RSS<C9PK8=F+B3;)^NI(VY;*M7
M,%$A_A9"Z=Q4*CM0"5>L2@PMOD$ZL$UBZ.W",+-%$*#U$G,^$!TV8I_6P^"J
MZQ(V>\R7FO4J=303BV:6Z!?,O456A@+72V[CA$B:)H)\-!16YN0O1R?'HM";
MG\`/":Q%S_\++&/W=O?4\JI.:H0*6GWF$I2&S^L@YDZ-9P:F7)%=#ICTA0NR
M1E[J>I8N6BE>,'6E!@ZV*:O*]1GRR60F^N+<$2ODM0-A,"`JNW58/!7L,N]X
M(@)G&[E7LW5$+R.6\X*T7ZOAH-ZBX;"$H$QK&^79T^G2ZFSMLB`-J"'T#$G7
M<5#REAZ]6H*X[P27H2NTL>_]<0IWG:75\!P6H=74;JN<BJF`:0-(-/>\ML1*
M:=NJ\0;F)+/"T+&B5A=EQ<4%7."WGMF8BQ%.*_(9^YV7M)C.+-CN6HU@30NT
M7ISU"-S]XT8`-XFK#P`OIOW6V0"0)PS\Q`;<^[H-F)W^*GK5(DALOFK5A+UU
M7H_::-MCX#3R:;7>4D7<*H;#G;T[NZHYXM,P^.?Z6]@34)N2O:77OSSJ5`<N
MZLK""B+0(.W=;0#9BZ(8B5TZ(ZUWKP%+7X#0W[5;W[8*%P[.82&8P^BS0DB.
M%(G<"T,V?'[1PG<$[]HF\+@4>'JJU+R846I.SSS1'_BC4++R3*$_L')\I`S\
M:7*T,"+=I88[KG56762C7AN@_H%/9V41"I$_,%GI,O2'MAU,3^$G;QA!@VK:
M"\%/X_#]$/PP#K]GDN%Z"Z2?3C[:A(J$(1C+*',V_%@'^D4B+=/1_MYN/#\=
M3O9#W2JSP:%$:*6]0)\6V1Q[U1]_D6.QP&`P+#07#`N+#:R\2F:R7'@-76/%
M!]1UIA[Y<4TWYP+CGJ43FTB?;T[3.K-9TX?!H<$O%9Q=0N8CJDC\H!R==::R
MSBB+#?9>?V"PWGV_]P&KOM(W9ILF\I^2[QXV"J4$(_["BK/Y=%/,64T3<W<8
MGHL&.ZLJS=/N@0<\_>BNT8W`XWP\BT%[X&.@F\[EF+"16H`-BI`V7K>($&][
M3;)V3PV"1"M%TV*:UA\[FD@0^\UR/_&:01V*[7`:R\$F[=IP__YJM4^%WAT>
MS6V:"83VNZ5=`P;D?J,^&UA'P^O*6`BHB5F?7*[6V;%%U"G?"ZUO2Y'X*_%>
M$QJ:7OU&<O:^_C+MU-^[MU9;!V-8")Q5/-%K..;J%9SDVF1`8M-.NSR'HT>5
M2DOEA%RUW$3<)QB95Z+$FPQ*+?!0I/7NM>CUWG>[S:WF3*\%6^+-!2RA#_JW
MDSMW[IBI:(E`L32X<]&6:A8X[$5\TZ3"#],F-+M<^F&"]=R&NOS7&/0E-`%]
MAE@4N>!]QO=Q@!@_N2CNAKC21[/>O+@;XA"#W"BPH;:"+L6:ZG:OSK\>B7X7
M*KR2.HLWQ3"Z2PBCPTQ+2#Q=C)EJ+97$U%$19;+@4)U^=<#5#9M=L;+@B9I3
M,2TY=Q_$B06>O=?,(6Q\EFD?:`#@7HHNY>D0PQ&$SO)\+29H/'"!9I?NS$6M
M;9LTM%"1R:S.`N1)*Y;X/<U'G6"-$F0A=B(Q$*AAM"@CS1<Y?=M/R<[//F7#
M2=-1J91(P7)ACFA1L%RSX$70<D-I[S_$"H7M/:I46RP>S4VE<*LU!H.,`!CS
M`7#X5Q]I#2_5^&XG%'$OI-\*0"'"%V5-*&E/X-6ND4YF9WG1@3GBUXRFWCJ=
MSS]'6`<VT0WCY)(G%_$ZRSX2<9C`FKWA]Y#NH#;3LTS%-%"-\3+STH0G=*JJ
MJ3\3]6#*-DF-QHZNIBUD02U&0TS+V+P7V27DER0>R@`8J3@U[$1'L::)7"%@
M.HM`<7MW/<FRLL.30DPI)*UBR2`M\^$9D%W%!,I\6)O\<*.HOP1CJ5`:8>9;
M%!Z'Q<?NLI)A\103>D,(.M\RG<)9V:SN2R=I-0UVG]M%XUGUT1HL`T`34O1@
M=N8,**M5PRRB,!I/'$VI0'`PEL&T0!.'T10S@F%CXZ[RP>ZVF&)6"KW_S.<J
MD9Y553`]I^-8+UW\[R#`58)*D2,Y!>M,F*2/SV?)9S`WA$K#RUL\%M;+&WB,
M=(9J-@L<!R5^!PVKSZ6[C6@N)V_0RX(`]/[^W0_;808F&\GG8M@)9NN%`TZ\
ME]!+I[Y#/<$#V14>F"]90X+MJ2_3TXX]T?6$YZ-QO]5H6*W;DF&0+<.;170Z
M"BU]WMH<L#Z1<HB\X^B$H:VET)R+8:K$&BZ7P;VBAK,I4@5@BQ>R\`28TEF[
MPIJ$OP!]GB[7!2!(Q8I30R]^7(*!RV$KN>+BN>!B&0[!5EP,T(U$8HCQ^YBV
M"-&I)6;.")TGZ&TPJ7<Y@+@,"\CS63TW\M2?"!(A@-$T<CDP#`\7OGCUP<XZ
MXZI)`U`=A]&RXI)M3$(T@:5HS$PHBF\W(FV>M-AB1<3&5@TC&!=(@M>J3*ML
MSHXM`*KU+DE`1/JB0(V,MM!914M&-=B%I8JA4[99;IB*A53J.)C87O="5OV8
MV%,A5F`369]GDTE(T33[D)&KC8?YSBUW'MS`A/A33/9^)ZXW@IJQG-+S?)2M
M2"KYQ.1*[-DE7<:R*A/;*)R!`6JP<R<^`_"M"1P:B4G0B7"_S71FNMMF_5B+
M:JM'PPJYYN?:Y?VXT8+@W0G@S`-K$BP9-]I]P*:T:5LE;]<N!!04V`Y#(8&7
M:3ESQ438=("@X^6[S,C&)3Q0X,=6S<]!7<A'^HKLO=V62[$G;>5`[IDE[-[]
M%DO85>@TPS:E+8L?%71FV%LGU&Y;IXYB5EA^'7?7N5A,?Y9U4/FJ,ZL&],^#
ME2\Q;$C7-?7R!7CH\H=#6MVSYD[%>),['&C5"15`/.=&LM"5\MLM&MYR3JYF
M9U4Z10]3BO/#PF.2D@,7R^!F#V5S-]IT^'$.T=M8]H9$R\+PLXS0S;_^O?L?
M\*:$Q@LA5>&^/!R,BL*=_S@\H6!X_\!?=.V+?N.M-OJ)MW#I)_AK=BU2\^(\
M/\WG`[%MG%6UUQ*QB9_!%7U)*A\*L2F!B-B2)E<8<<B1X*0&4%X?N!.7Y`@L
MJKSURR^W-"IY\4;'(!B0^ZJ=:Z[CAX!P$PFNE?,<W^S0@X.&"^O--"NK7I1B
M]:EK/W<C9^[./)W52'[]Y6<,G[(EG>?)5='VEQ>LBT==.!:VE.7BSOLC2%$J
MK<Z2FP)U-BWGGP>4\-]3E`VK'!F<_')XU6T#^UF&N0XM*H/3ZRNR,3BZ*[84
M3'KURTCS2\'9^SX#%?C=E(H6@RB#+FZ(?9L)J3:K!O*RFXS++C.\`HI?,)2R
M$^15+;5M067P5[\$3@\@UT2/E1=K\FUV3W1K6-IE<0AQ3Z0LQ/80,VJ"`YSC
MJPAB217JC9L+$3M*D&U.0`UY+D9!BR&V=(KA0^QO^;C37'"@3G.E#/^DTN@Y
MSF,F:TV%8*&1%'Q]@/'(G[\ZAFG;NW?``$SD=\R[S_-4-'?,><!S>"Q4R.WO
M'OB5RJ"WF-\+Y!^^?'UT\N;P^!E"]`,0[XZ?"8BG%'%BM[\7`'ER2`3<#>0]
M?7[R]-W+'UX<_2>"W`N`F%"F"'(_`,*BE"+,@QB:?W_WZBV"[(5Z@]`8F%"/
M4&@)S`YUQY/#XQ\Q,]010\P)=0,N_WNAUHO^?TIQ-G;W0DVGH+R0^^"`<]7;
MYV]?'*DP]S3^5I.?OGK]\P"<K6T8J\GLFG@`M!_F8QJ!7:N5+P[?O!WX#!EJ
M+XT!5?K3T9OG;PCT/AK/=E<.KKIAPC"999_=W=6Q6[OR(!Z#*\\^WAGB:U,8
M%%.=T-.:N7F:CJ0.D>AKBIO:)A#2+A)4_C%7161V`565``R@&C",SPI$?B5U
M4`D*VR=JH%UV-U20;@@XHNZ+%7F.9SGO>X4RY0I@!9^7X:UX91@<WKF)0<Q@
MWVZG9U(B>9G,=$4U13-D]ZKX,T-"%9]8U/',$LY$O53))34/^;5K1PM%&_M2
M&)M,#`E0X=5*5F@@%MK)Q,=.8>^'+)Z)=0E-7IBD.^@Q"BB>E-HZJ*>D>2TU
MK\7?A3=BQSX074^[';K)X5B?FRFKS_/Q7':'BSBO!Z=P`R>M/OL#E*M+IAB;
M;,DPY;7<CCE05ZAK\R':WW<Y?&,_$3R'SQ%F](.>'73+>5-#@;EZ!D078/QH
M14[8Z74/8J6(45N#6[W'2WG!S=V2;"Z75DG1_.1[[(7DSSA-;]].]FEVE42(
M)5U4]2;B9Z/4<0;<#%5/#96\DY_#NPL*1QRWNEDTUF_#T6TP(UO,;3%U:1$%
M`KC_F5N0\B$!&2DN4?<,G[S[0=\M[/4IV)0MJTX7X_<*"IV^9?PV\#?J\BM7
M5H."DXCO[N"-.JN`EL&>F+/%VPH215/+!(="L41<F&YKE`H'9LB5H02?RN,M
MPXGB]<S8>?JP4%<68::.R\Y83%0:Z$Y/_%2CVQD7XDN.;4=`;ULC2].:E($.
MW`_<WX_='>Y"(!.!+KD!`\*UB!OFJ4,5L\1YY!"2#-#.8_[R(E!(RL"5UQ'N
MD".MFI64.N`4DOFZ7>,2U)O.S<$@GYV^W_W0)2([9-04__*LG<<#LCS<?)3\
MWMF%O[N[R3\2_-47[29K.H8[`>2R9PEE256/2P.$Z6.6+L660[/F!RYW>C%H
ME\D<WJB=?DHT-XBY1+>A19<D8_A%+*,BM7#64(J4;*'^G&L5*V._EY'LRWX,
M*,/JHRXD>F[?CE'CZDPB70@<0U@9`()FE\EM+;L`Y/(<'NGLE"#8-2^#10M,
M@3L[,%;`"D.1]%A4+00_K=9;*D<M`P,8"$$"I$M.AY8-D>?$0J5F!%HX3;[H
MCNQ,+.-F]]P9:EAEVT,S([T2EFS*$B3PC4*.KPLGW_0V41X`D@.M@&N%?JL4
MM#ZB=]HL"F_]4MSJ,L]<I\O9E2A&O]+QKZ0*C_,@>0P#H7!E;#0T<]#2R17_
M)FA:Y76\((^CF%[P=09.LD1X9"2E7V-DKD^IZO0AR&+#9(L"SDH[0R']*:"'
M[,EA;%*ZRV*R_.JY'35"BI52+J`T>:7RI+Y$:XT"@O)8"2-82&!1J>?5<%KJ
M=-&C.YMR2XKTF'H$KLWOU?5KZN_'FP=<U%JP7,6Q!%1HV6!K/NTIJXI>4=_\
MIK?_37_?*`7[R3=[R=^^Z8G)LVE66K7\6GVHA.>?DTWY9-BF&-!-*+,970RB
MJH9\''12L,5-<283\6,C9JZ[-&MVT^O$I`B(>TL%+?(),RYN>'MA2_^UK:F6
M&L>#G6AMSCV_ZKA;3;MH?!OJU"!WM`<>26WU1AY78KFJR)OA*)O!K$$ZF?C9
M+91-^Y!IQ%XHYSEZ.YH47A[$\K#WHSQ7!F,/`N@>I*VJ6Q2C=_M1.?#90\NF
M$1G-^:QT*L.*7'SP>G5]/FC@+@FAF,S?'2LC-[+O_OX<A=I-F\_-CE)"(3'F
MV,O.@S;"^KJ[NWL0V)1*,-9Y7"\DS+<A1/G.8]<@$-[E&H2J$XK2"5X(R&BG
MBS]A3>["?E=ER$VOZ4RFS5J5^!VNZAJ+KNP<'+CZ%M9`"F)IJ5!R=<.7V+"M
M?*.LY)E9Y%1!'!]G@$)JF,M/V92(D4(11QGK56^&)-3U.SOT,<HFV3Q+1#FK
M;K\;;4I9CRKI.IH-A)"$%ZDDUPBVV4[N/NQOKVH&YNL^LY.$V2%@6EG*!H8)
M]'R)\P"KH&GLC7C_?V3DF\?]WN[]KS/N\JB0C8LMS'%@<!45>K]CO8IA\`0^
M(C$-\8=+-*CW8+T&!0;*&QHU%C1Z<NP$'.YNU:`%FQ+4'W*F7.4%TT*I<Y42
M>_LVC=AC6J]`C:4?CQ7\.)VGD\XF;0I(\2&([-,PRT9"*>P(E?`4#L0%63!A
M1"LF,Z$^J[93&PUG4MOR(J1T;7D+AU1TDESMD6QXQ(B34O;H@=@CBVFGC/*0
M*GNYJWE<))@3`H>Y19ZNEG/C;J3WN<YA)(1'IB:N%4EZ*RN2J8)"'UB9`62;
M2HLDJ00V4F-Z:G>]3F*:IF.9#JW^?'<&'IN7Y/NPO<)&;.U^M0BP*F?UJ:J<
MAO9:<("[X[*V.MJ@2F\O-[5!;;A*#+7L$BX$ZDVQ<;II&,%OL/BPM/!F<DD9
M7[-O`U5Y(Q_?`.J]IK'K7W.0K;K<O>PZH^H9)\N@==*E=:MD$@GU:Z1<),-<
MLY7MA``Z(K/K-HDE$A50?^TTY"M*<1+66T@1K**VQ9HJ!PA&E[]Y"':DV:[%
M1WCK*W25MCT;Z1E6D.00P1_5R["J#%<S<A2G@!3V&RXWAMJT5TA=(L]J90:6
MMCI8$=TFV_X-,=V1X20U_*MKA5=:;AU8+7@,"\?.#DLBFMQ]MNH:(W:4GQN?
M0&'9A#-I/`']1AUN]#^0[3#H4&%F"^'6S\>(%MN/T.]R4^D-<.;0+XY3H'N1
M@L]%=V6G`<`G%<\;3/[3.V)`0,=0,!&F5V8]92.N*K0_R3!?2K:`N0OCEECO
MFPIM4WNJH!EL7*J!E[XMP[2X11%/T)*WGWS3W]Q.'"3UO")PK)Q;UJUYX@D^
MF/46*FU&X_VA.I_T%,;NJJMN:)\=V`?=X._+B]6,&E0H*WU`MRJ"`^XZTX+C
MGF!3VYW4,JMKGUO2#0GK93X?GHNM&DVW82H&"O8=^TB5ZWZ["4XQL[&TD`NU
M6KH5065JG.2R<NN7W5NDUH_3Q62^;\:P\<A$[NX4*7"N88J:HX[0N.$V(.#S
MN/E+L4DC1R@3Q"C1S_G'[FZ/?Y[>BO3"-[TDK^%]!%+E\$9WDMJ]$3;!1YPL
M]9F"TWE7&X[Q/^`^/+^<$4)_X/4Y/D5M@U^['Q0C!/E%L:P$O?$(25&B&%)[
MRQ$8%``L4:CQ533L>I,0LOHZBS5=OB,!QU*Q3D#!%N9\C`8U4%:\F%WN0'57
MBG3?_Z`3MB#TS"-,5[JL^(DNO_CT@4K,%>41"TF;/ALZ#GRR'V$<H'[SDHA<
MHMY_4*>FC'G80^)J>5:X\N1VTJ<3/@JS[]7T2-;$SA*I_:`3T0WPWOVM_@>M
M@R?3;#H4,D5`;6/1;8/]@.,P/;:EXTQ>*6'.#SE5OT,\:JJ;M=$EY[W"'*5)
MHFDF:^M18H7B5+TK"]OT7MGC=>O#+5@R8YP%((P'`V8LX+C\]NT/ZF3W2L[5
M7$^&R.C0D-HLXXMLN($0$M3+&,:>?2E-/^_,5[U%UU'Y0>94N`A!>`XO6;@:
MY=70,_"XK3+#U;EEP34(4;O<>QSF&\Y=&1^7+XNT+"$19\GBH?I"P:H$?WO)
MEQ?#*L-K&?BD)JL6+0@BNURE,T/ZP"XM@XC+2.YP-]/2V;G55&1)CQ.*VPZ*
MGH\B4G+'*;G3ONA[IFQX`VV\,.Q6M1E]-:?TK(=/"\_7Y`^M$ZH+5G!V(]_-
M%OI8#JX/C=9\_[!IY*Y2]GT,>R$Q=2B):IOXP<[,Q7UCC:*OU#XE5+&[Q.&9
M`_<C%RHW__Q>RPF7*H\,?IQ!\T)-"WMB:$2LG@,#=6OSEH(C5S6OK4P?AS_9
MVDZP7R1LEW2S`F62XS\"?P?A)B(]?_HCZ3$D!-VG&$W*,<B:%XK&?],T&CYI
M1ZU9D@2YX<ENZ+M1N[M8F>?>8>-*@^]!131O_>O0K"X+MB$[79$=S!Y%;)?X
MF&7K(5(WBCBJHVNA.N*HBFN,"EETA_%ABJ^^-T76&@,GKV56F1@\$-C#-B-X
M]J_#>,ZUTC;4S]?EO[G%?7_]U^F$\&79-GWQ2[%B9S0NM_92&96UR;4F&][G
MX^C^<2UT3PY/.++_>RUDYK(FQ_GE6CC-[4Z.\^I:.-EU4([T;]<G%.^&<IR_
MW/H*E'I8=ZZ%E*ZH<GR#:^$S5WPYSN&U<%H:U(UKLOCQCQS;GZ^%35W#YAAO
M7@NCOD/-47:_`MNP2[(<]9WU4%LC\LVUR)-WEI7Y@EFLF1K+M/ON&FN,NP7B
MMB\7R-M(D(N^OOY:S`IZIK(4!;(1;:1QHZ?OD^$74.F\O<QO;D71!!ZKIVTD
M[BBE6XN\Q`AEK7?FT>@**R<5H>TU.SC&!U*U?^8\3L7^/D,#CQ5#<U0WXL:B
M$^^(K:XHL?.8S.:\^H;JB#)>S684>A,1-R!KV;E)T16#-NP4K@,67=#:3KZ[
M?V\=IRLD#CLN3B*-)F\OF%7CA`^-GT,#5H\KQ#]4B?BQ\S@MRPP>V^.>,SUN
MO:#P.#/YYFY7A\2@YH@,I^X0"'M/V,&J@FW(0!IVL=E%5L'6Z:-B`PIO5*L'
M)4R^9+)9(6W13@Z:TJ`4.S6USU#UR?='&&>$=6_TFQ-9=)]4![):]EB76)X=
MO7C^4C#*-*]KB$T$M\;@7XP]DELW_ID"*'5/$VPIEU?[E96PH_;H*`9S4[ED
M+K!0+2JA\.X\QJ,WQBRYI:061CN=%3N/64\KAQZBQ>XE=@HT*SB3Z"$[K83(
MS>;A\9*9<K!.U6#QY*\R4G_4P'B<</TZ5CPR_5?@EU/!+VJ86S++:>':0T<S
M^2ZN\;QPF,7E@M4.#_%<,!U9L2L0PVQJ![1P3*YV$_X;)K^L4!]3Z6Z':\)N
M8#!!2]MSKLB%R1LJ<(C.-YTF#?6\RWK.P)H\.(M192D47V_WNY4?./7DR6]9
MI9<>Y!(5IN]""H_18CK]K$7'5^6A_V6-CW?`?6H^P_[%QZ,[-T77=QVO'W53
MDWH?G"^JLP686T1*\LLO_[6IY8$1.]S?#%#*[B(`\A&KU,.+--KBO]Q'3,!H
MOS_I^%:0C[K#H\`EAHU(NA6D.FU0P,2!4LU`7X*.,JFA8!>D]+.2KI9O5'H9
MC_&CYDTI7'E<R'E0H>>$N22MJM:;LG#+*D:%:,;\8V<N(XW(@6`EP^HIPS?_
M2+W*2><(FGIV?I[76IOEA>)[COE'VG3PZFB7`?WM;#.L+O#W%29[TS1!=E8'
M>D:HR!"S!8N^??67H^/!T<O7;W^6G27!?Y?PM'6@8W=XTL!%Z'3\AD`_[0@Y
M-14U#,6/H?CW0JC+\SOBO^+W*(=L\5]%P?P._`/U;-A31B#!4",8N!.2_DSS
MA,9.M(.Y%TN29B5I&8\\LIQ6).2X"'0>K%,O'>F)UL%/T3#\N*`GX$7;\%/\
MB\PO6H??],J<0S&XWLE.E@($'ZY7:QAS!,Q-["6[`(@VJY`MW"5;V(Z8'AVH
M,4DLI,$0V<0?TA`;*J-1^J6T<=@I1[29"`\C)3"M`9(#H#VV*'CBI\!B)F>4
ME/9PSAP\3M3N_:@_+CO,Y:XO,F)N`2</$\Q6%AQU=CMD7C*VGR,.".^5HU<_
MN):;`UXT%FANWP+B$>VL'"^6W3Z/.F]1(@$,-=!MPV$C=2;^8J1Y!J`1CXK5
M&.LDF=V(PXND9Y#5F1"!8FF3`8ZS7[,A.&RCTL=1A$M;I'"0YB99!C^%+9SJ
MU$%6ZL'SXV?/GQZVK`?GI%.+E>;.QE?/C@Q>G%NPYN&<I[W2^70&+J-R095;
M*5CH"$9JKI[=,41<YA"6Q<89L]M@9,TZFPE53,Y)SYQIEWIR>.)0PE+:=5"T
M5XI4:(R7:W2..3IR:/,SKDGB>3H9KT^GE-^&%NMLD4.:@RNG17Z&TR+WR*N9
M(G:8Y504R'&EG7L0UER5.>(*-<G*\!;+HZ?/#U^P<0)]0/I3;9ZEFZTZGYV&
M!9NZ/@5I2PI(*#F5VXDKU;O3KEISPN94[6>L5/UBTJ[^H5/M,%+;\^.W1R<G
M[UZ_;8,4SN4\0622'-1,!6B#7!W3.16XR5)@A*W<"L16R`*TV2+()<N</35(
M"WT(Z!#LI3M5/WOW\N7/[><..Q(,SJ!`?CMQR]\RL$TV4<+,C0^ODB>'3__"
M'!UB"))8^19E?YG'"K\]?+*D:!$KZKA^1(JK>R\!!"^.#L6$;BR_:XIRAO1/
MLGI[=[];+WZ`)HUO]-&:3TNH:ZM0?VC`*NR)DHBB8N\/N[V"=NX\3]W]*WCR
M%?OM7%6`/^(Y&T_C=#3XKB(=ZYQ!._C@=8NV&P)^98'1[FMF>H/2Y.:IL,:V
M5-KS&_MEJORIXL[>@=9Y*T2`Y]INW4+7UM(Q!'6+!\0.3Y*_L8:A;AOQL@GX
MV=@%/`\:WX?&+L"]8WS_&!O6]7SQW2-L>,OQ(23%.+`EQ`AT]Y:S<#5JNJ/\
M+)\'M-N&R1(:BG]$Z'MB9H7K/&8#NFYA"O[;F!1\_O;PQ?.G`]&O)V*+J9UM
M8@1N1\5Q>*V:9&.XL)Q.\N%@.*LJC"_>8KVZ&6F?X\#CN_"$.-)SSO&=G=SN
M5FY,OB.3#6F[*"GHWT.\LRA0(\&G<6@SU'JCNR(7;;+JM8=[>Y?[@,^]\;K7
MYJM'KE/\LO79\@9:T2C%'/M7;9+ER:I)Q^8YBUV<(I\J^&M2-9F7OZT[\'OK
M30ZY\MS(OXNNLQT__F)JE;9(,K2Z[OS_!.*DP_XJ]*6A^1-WWB$U;_WY<LBJ
M`YX2LC^Y[1RK1Y#;^DH(^:G;%N[9L3;)PX@\&MI@3UV=Q7^SAX]H;$"=P5I9
MI[DU6G'9N(B:`N$YHNZW_24JS3.WT_VWZ'B[;Q2CMLU=/C199&@R&^S(!5MB
M4;PU;IZTRSS\J:41%W^OS?8!:,DS=$2NFH6/@-@NZD[]05+>ONW(`[QU6*.6
MU-DJG;H#M4.!K=(&4WP`\8`@$+QU[\!;7P+PZ7R6=SC5W?8BZ>QK]'[LAD7;
MBR9+:#QG-&)UWGMA-S]M)[>FMUI/[C8&WT]+YN)/#E5AHGZ[M9WPB2XCR0@Y
M7\Y$Y\B);Q'.QY<.$++\['QN$118F3\&]W$-]V+6D8HO#T_^0M&WFSMGHHFA
M[Q<1-C-^:3K`D#?2^ITWZ%"EHDUN)7^&(=]/;EW<ZFXG-^ME$Q_%!+MTKO[J
MQ-RP!E*L&C:K!8:-/JT<LT:3L6"IXUSMS2!=ITV;X4SL!.++[:1H%A!FN6DH
M%3,PNE?P[/'RKM<%E*O6-^Q64K?8-;MBZMZS6R)`CI<+D(MTL@V/:[05(/A&
MZ=&S%HK2+*`H<:_EM1?D,FZZ/#DZ?-9<N+J.YK+CJRY+A.4)J\YQZ0YV-Y6J
MG7$S+S?>_!05F9B_1%:^:2.[=YNE<CU)BZ5".6HACG1STV9@?FM))R^^\I@N
M54<OVBW,%]=>F"]669C_^L_<!08OCJZR)[RT9X:^0A$L3$4^_;.Z/?LTKU)D
MAG8]_Y\!4<?N==C=^Q6W)C__<[<0_G.X^-2&\R2N58&Z5Y-@*-#Y3+[YZW/=
MU+7>6%'SV!'9Y',R/Z]FB[-SM)`KHFPU)4`\/QEAWBHX2#3*6]/VJDZS%O%;
M9%RXB[1I.U7$:XHH0YZG[LC3AYQ.=*X_>%<?.!G#/*`D!CI2Z7EG[6Y(F`K.
MBM85Q%I\5CAX6QY>+1NP_PI,8.Y>[VP@1EY#KC>/OT1,#+XWBWN%.V0>#Q2P
MCET#DO6]*UFC$86PA_1*$@LAQ/HJNIIXX]YLAFIR#>#V%N95J4"](\JPQZ:V
ME=^Z8VU'K$L*U-/;R:9[*I?D9Z+J;)2<9F*G3Z\P.9R.54?"*@ZY)KFD/?PM
M+.X6SAR6PQ[+6MK<4`[$5DPP>L66SDLQTP36,M;1?5X"=V_2;9G!R<&S0(%I
ME(>T!6QM*:PBZ`C-/:'Y.)K[F/%NN!'N!N7"W)''ZZ(*=>>!(='73C`\F5B.
M9*#:5OT3#,*DSR#IJV=]]:VO/>OKKO5US_JZ;WT]L+X>6E_?65^WK:\=Z^M;
MZVO+^OK&^OK>^GIL?3VROFY:7_O65\?ZZEI?YLH]<"\.@YHF1D6``*>+FL]&
M"+&;I+50$/`ZCWV/:#M1L5S5E.(SP!,8G-5HWG'V%=)]WV5_Z3;(TMX>/G%2
M+'=(IVU^R[[I-;2&2Q(G/NON\HGCW04!WF<(B>WI\IF._7;W@Q$627@V:$\D
MJ][-%.-+X]$H\VEPA(*923J\W*V_R2`Z.L3<T'SW*>3<+0:RQZ/0F>N6%.>1
M585N8#:)?_OEEYNW7))(\GN`F0?H>E][1;[QBFCG/P]VZ,.Z)_Q>F6^],N0;
MY8[#1"SA\&A@;!!<;UM6Q1>O"F,A]8`_>L`6[^L`!G3UPX.5$XQ3+F\CM5Q'
M@(9CCP;/Q9=!7WG0049&)O8A_<4/87&K$>]MLEYYI)0>*5*4<.3S]#2.F+E_
M>MAO^&S^Z@<;BGLD;7K2Q`H3:0B:IF="6J`TV61QQTU@<'[CR+Y+9%X+<"*[
MVQH@L_[:%Y1"`<^-.AN*>FZ"G@L5,!CSW+U!*G8G]![+!B/$!T(9&XF&3N_C
M0<1;.I966B90!GO:O,I&3&M;>IF6[(2J''6,I;F^?/[FS?/C']D%6Q-B5T?*
M5755</*"Y]JL/L%EIC[K@0U8E!*Z7F\M'7(Y-2$TW8O"5X%;9ZJZ!AH.=).7
M/PB@5U,_%KI4U5-S*W=S6X9-,$SV%7O6QB+)PB<TLT\ENE*)7;*@[YM>5Q#B
M]6;78K?&XOO)7$Q,2!%:@Z0J@M)A2;#$!MC2L&)3C^LO-93J&X=-]IU*L\9W
MP\E$1S.99W57.**]C&0?;2`9Q.B:C0PX[$^RR*;7B4U/3$P7+0T?=K2>HJ,&
MT+/E4=9GY7I-Y=QP\P8;OV1I[PV=P['8F#K:KQ6CUR"S[$H!-+HC'73!8-U7
MG(4EH/W>!T-GCYP!\8>OW=W5/RALO@Q7W_O?</4^66N&J^_HJ/)F6G";&X_'
MH%[3\4.L^%'GE[-OF'DI0$-\%KFCS%$YT^KZ$>E)=?B4SP=X`T&]'@T)N'AE
M(Z5[S&?E*)>'=_KZJJ'X!KQ]@Q9Y;!*SU"D"X3WJ,U%-6G9LV&ZHSY-$/CD]
M8&Z<9CB4L7B<P^NQ.(2A*$91'$"!:$Y6U4*TRP?M1K,"#J,D::%VXV5=/5!R
MJ;,#FVD!^\6_!+R->\CDBJ1`BXA$'?D6,HQIUR(&!9/Z`HF&EXDG67$&-N;M
MI+=*9S1=26[J`"#;*M+YPXC$MW'$)K-8E.02(3@4GW-"4QMCXX9GIO23S=)&
MPI@\).&-=L2FA]D':$91<\;B:7E"PIX8"+U<=3I)BX_DG,-1N<GM,'+-"V99
M"=/-H.)J5[`"U[C.)VRP@-U+O";30G14L$<$`JI<P+F\M\=Q4G!5]8#(LNP\
M\66_7.$?%%A]Q8CFQ]`T`O+<V:\W2+3[0'$Y$^KQZ>3S0%K<QWFE9A6>.^;,
M#":?>,/)0;L'!HXG"(M*9*)-&<'H(0XI^$0#\8*?$;#-55KR7\>7<M6G73>`
M&+]0B+^AJSH4R8(Q5.AUJV&7:[WLZ!`^09C,X:#__7`H=0+]"$>N;CS0@:JJ
M%IIA///1S*`0[^^C8>+%X5LGT(!LUJV$!\T.E6*6NS:!84,HPK:ZQJ"K5[15
MH5Z1S;:;:W8%/*R<>K%"E4GK89X+WN3NR_I9"/X0E1^0U3\;AQ$&&_%\YAN:
MDK]]T[^UJ9'!WR9LFAB;L"-UY]0J?EYEPT&K_`?HC,ZOFC!D8:+0#Q0?N/R"
M*W.U&,Y-XD!H0A@HZXN:]>KFH@^RI6)?7>&+USQRK`:F7O[=^4:!)Y]EIET_
MJOHU:7HFGE0Y*UDD6+4Z,60R3I]\)>7*`OO=A;,?D]3:::!AYOUII7`%WH0T
MST"6)"3,&Z^&5-TD*U`4/5]NO:SJOE:MGTL.D*?>(/6R4"UPGY.&!'4!E1I2
MDC+@T(J=[;_R+2_G]G?7BS,;;8#]D#?O6FP\^:X@T;*C$5R=:[)`LQ!!J\K@
M9)R>-`H$2,,`CZ##@I>;N39FEQ/+9,G,$LQ!;9R;]3&H+U@K)2U&2JDCWPE$
MKM1$*ZBM11H^SH4ORS:1IRK0T/H]7U<2Q*NE&1C2(&VFP_8.!!KZU%OUV42A
M#3P15"_*L@+$DA%W[64+35/Z[$JN$_(,S#V(XJX\3J3J<[5/-3M=W!`*TF[>
MM,1D!V"-VPQT4C6CTWT+#LR=-F@QHQW3@)=Q[KP1@%+,HC4=;+`RUOM&)&%<
M.Q7*<6YB$3_GVO)D@<5U/-XQ<:<01^=3?YZK=U0'U(B<@>^93.,WXGE,X0O5
M[=1!FVZ76*=/'<XT?VIX()8D:6"VGG7^P7%XBHV/HEYQ-+IXN(SLNEX%G:^2
M(#_;'0=_#3V,F'%>6C<;0L$$8N^+6+1[)UA\+LJ9UOVG#"0IT79+O1GDA)`S
M?T/K;=N;KC,;=TQR[^NZ^;:"R*J0$IGO`6:+N9"JG?"VP/8\XDU?#;O;&/,4
MVC!R&]F&=^[R^O,D5C%>"OXJ;.8$J/)8S-K+H6FDRBYH@XWRJ%J4&/[&ND,=
M6Z1-/]L7@Y2X-Z$5329;Z]9JH!/@CS50&M3!NQ=V)/[\#TD=M8KRDGP:TJER
M*+0@8LSG$[=]MC3"\H$`A*RWM-ZQ%,^R.(ARL#1W1;%N\`"(GFLA5UE!5^T]
MO&8@F8@3?:/\;<4,UI[;YO4U)*?#TJO.&.^R58':A7<YSI.U"NXV<:S\=-?&
M%CI-2)OQ@]K;6)OG=G`!0?,KA;H5_W7(5#TUFG'KN)\/V@)Y@#?%,+&B3VS)
MGG'%;LME.BJGG./'(,H5I93V0+$=/@+R6GL&_3$,C$,_VGDL]SXW0<NP.55M
MO!&0]P&EQ+HAVIMZ8*E\=QG*ZW=V*&(ID^!BUY`7BXP=&"C#_@IU^$%>30WV
MINX.FAR@GYDP<Q>]=DSD!(2U^<.IU=A&.$=(*UM=+JI\MJCAL`#)E=[$(S'R
MX'-Q8]-9S[W1<=M(IJ0_)?W^@P<KOP*P<C,4;Y&Z-(`G;4!F@;2RY&2@6YW5
M[8LS)HX[@MS#+\%ISGAO6"N8(MD5U=C&NJP6@F9^FG"%#RGT]W;OK]R%[CTF
ML&[8*1T9O%Q>7_(+F)M,OHE'0FNL':EI#'YX=_ST=5*6$/2[[)2EK`0-(+I0
M7EP(]NK01IJP0^0$?5Z$1E*TQYY.9M)TFA6+:?(E>?/\OXY@JO0?TG&E;:6H
MWT.^=GN0Q;7EU*0I.Z=)V=_GN1"3'09H5])/QER$@&<0K"#_.E5:7YUO;+I\
M9LE_R`OT`'7P>+!15OF%V+#L>PW;*N<5`W<;>"YDMYLV3W.\43"N<IC5U`(Z
M)#M'IU@ODZ+>Z%->UD/0&ME!U##1/X(BC(DOR,%_`2D%R1<5FXXSQ7G'<`LQ
M%+1,Q%8K,+Z\:E^"OV1"V#JLY@V:^ECMJI,Y+V-/:O])`QL:K80=*T$+[6CG
M1!6E:_<2:@,1*'I+`@A]@FBTUDA<T07,8PV4W$XX=P)C,T<KA%'/7P3J2Q0Q
M!E)E>*28$PQ@L]NWE=NYZ![P.V'OW,E70)`,VO^KD9%1()'G^)-VZMT0FAK.
M-Y\:[!T+>TXHW'AA5:[-U^9JZ08HJ=$C+FT:9J1I8-E(%[K7=P]"0Q\86J^(
M-S*F(#.SA_B6KN[,4[TRH='-Q*3`T5!^NXD,R6E6GMNWL?#!!CL;P6_YX(>L
MDHT2UFHW<==ZS4X7TL/#GNF1!SN*1SP\A@P\U8%3$H;Q=Y<.FN3L,1I`:*T9
MG!$L&8W"8+8HS#*`?#R<''`N30K\YE@Z8N"I)"IH.+96+?1F"QVL`6=MR-7S
M=[YVXNS&48'=XLY.IP1KM4#:3;[7'E_FX.5*8W&1W/`?]9D-Y9GL=G)3G4R(
MGZ#[%#.MRZL<PX4$8%2-1,XYE6).^2Q:R">:E(:;4UP(.M,[I9#[J@KQJ7["
M\H#5B#1)T+::VB(%?[@]1)VA.D@*(%4?4>*^66*HP1=1`)<@B6$37PS?RN-!
MG2&0X)0S/6D:BN)2=:AJZP'O4]5<QO5;^M4;%$>R<4V+C[&[#-5!X=V'#]<\
M*,0^,`Z'ZIC3%:8()[IG<D>)(JA:CIWD+GM&T)I=RN=?).2!7N8BW6UW.-'#
M7G,B$JSG*F_?5ET:[D)+FOL!D/OW=O?^W^NZ7?)F$\N"3BJ:>Q/<K538$/(H
MJRI,`T?U336?E<N;W1[^)9^08H?M-FRL%[DZ>`I`HC%J2?&U9/#X+:5BH]Z-
M`L2FC%0[=W8*T+9VN[X&A@@:]2^DX[0,*5:Z=KT/E$XQI%P=:/'F<+/RC.':
MACM0(_6DDMY_4N,L7=AQ1RGY"32,)/9O+<=R=@H&C\$H'\(BDE:?M:*4X+U@
MM2TT`%V28&Z8C`K937G[LGX&-'?P,:%Z.^E0?<G65O=F-=6KDYF</-P<3-%[
MO75-RRPL1S7UXW+@(F'ZF?/T+WA%QO?S$3AW'O/9<.`5AI<Z[5$8CR=@[^G<
M'`SRV>G[_H=NT$DRJ*N:E^5HV=?I>O+`?W&.L)M*Y[/+`>VP1TJ;EL9=[;V(
M&K9>H^P)IO*UNJ1F$6Q/9V0/VM]@Q^#8')MPW,MJY<O-M!?M;3ML8X*RF45W
M85[J>G>`+B)$E]DRE%GVT3@S6;J12+"KV=I.R'M%;T/@PNZ\DH;>*WR-V*)Z
M?W^E9I@F@(HD@#KP>AL;F@ZH3'Q<:#--VE(/\J:=6GJ@2/538&%*!-WF@1R^
M=T;!!(`D8<S&&06%S"AX!DFMS!%>SA[FM#2*(S?06H6US6IYWTE_8HW5X/0Q
M\DY2::PC59)6OWH'K,^,1Y)'$V>B@ODB\?JZ3%4FV1VBQ@R%69.E](6#7C-!
MW>5*MM3H%"T6G\#24[HC1Z%(*=[U[BV^PA4Z0*EHLUPZS*N3P?5$CH7\+UP"
MHG1L\<[.`6^NWDL$VYLE\>:I/LB2'5')8\(N;\7)>K5$DJ2P1:9,OD_TN:RC
M.N/2ZZRP>%0/_D?P8;_=Q!Y)MH=:F^=+M8I''FD=ZH[WH619G%ZL&<0].]#.
MG41RA-HE2+4AQL8D]M@%O^OSX1(<K5F5<RKC3MVP>*-<Z4T7(6D%#X6<<?\L
M60^;M%(*?!A0-M=O,+Q^G!C4$83(-%L^MTL0C"J0XI7O"*DV);E)/MU6@FHG
MYB?H=09;FC3AO"I]\8OI,/O?]/?-FB;T&5Y@.T80TXV8A+4O^D6"YYG*]\%)
M&_RQA3)D+7FPIH6T*NM`R<;CHNCRN<;*^1K8%7NJE]]=:M2IG'EQFM;TK+1U
M^8GSUK8R5EH*S^]V`:1'VB2=2K<"EZLX?F54HJL<&QL6Y/Y^O&!M**.E%DX/
MU:,.K)'O!02>EZA;CP).Z"[;LDUZ4R-[(C.?P#C2?NY0Y3:?OR0+E_X0E]%Y
MIV(.#MJ.$3LA"13TQX;LSB%0>=T.3Y6>O'CU]"\@XN_3J9*\:!(B;6M<960M
MU*KCEK)'0?=V,*3BW"B6.I-ZH$-%>.WZ3"MTI`7W]O2AUK68*-B:0*+0C%03
M2<$AL10]"5A<X,EQD3D;=P)88*/W8&]W?5O,#4VP-G>R%H2JA*>BU27@
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
<8G:1LKLDRZD.\Z.$1V9<T?70_O_-2Q+DE:`#`&B]
`
end
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Disappearing labels fix
2001-05-11 18:32 ` Disappearing labels fix John David Anglin
@ 2001-05-18 8:58 ` John David Anglin
2001-05-18 9:07 ` law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-05-18 8:58 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
> > I thought that I would try g++ version 3.0 20010503 (prerelease) on a
> > real world application and ran immediately into the disappearing label
> > problem building groff-1.16.1:
>
> Tried again with today's patch. There are now more missing labels than
> before:
Your latest disappearing label patch has fixed the problem building groff.
Thanks,
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Disappearing labels fix
2001-05-18 8:58 ` John David Anglin
@ 2001-05-18 9:07 ` law
0 siblings, 0 replies; 521+ messages in thread
From: law @ 2001-05-18 9:07 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message < 200105181558.LAA14748@hiauly1.hia.nrc.ca >you write:
> > > I thought that I would try g++ version 3.0 20010503 (prerelease) on a
> > > real world application and ran immediately into the disappearing label
> > > problem building groff-1.16.1:
> >
> > Tried again with today's patch. There are now more missing labels than
> > before:
>
> Your latest disappearing label patch has fixed the problem building groff.
Great. Thanks for following-up on this.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix toplev.c breakage on PA after eh merge
[not found] <no.id>
` (41 preceding siblings ...)
2001-05-11 18:32 ` Disappearing labels fix John David Anglin
@ 2001-05-14 10:18 ` John David Anglin
2001-05-16 13:27 ` PATCH (revised): " John David Anglin
` (120 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-05-14 10:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> Here is a possible fix for the problem noted here:
Just noticed that there appears to be more stuff related to the assembler
file that needs possibly move up. Should init_decl_processing () be
generating external declarations at this point?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH (revised): Fix toplev.c breakage on PA after eh merge
[not found] <no.id>
` (42 preceding siblings ...)
2001-05-14 10:18 ` PATCH: Fix toplev.c breakage on PA after eh merge John David Anglin
@ 2001-05-16 13:27 ` John David Anglin
2001-06-04 10:53 ` PATCH: fix argument promotion John David Anglin
` (119 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-05-16 13:27 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches
> 2001-05-15 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * toplev.c: Include dwarf2asm.h.
> * Makefile.in (toplev.o): Add dwarf2asm.h to dependency list.
This is no longer needed. An equivalent patch was installed by
Andreas Jaeger.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: fix argument promotion
[not found] <no.id>
` (43 preceding siblings ...)
2001-05-16 13:27 ` PATCH (revised): " John David Anglin
@ 2001-06-04 10:53 ` John David Anglin
2001-06-09 9:37 ` [v3] build failure from automated checker John David Anglin
` (118 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-06-04 10:53 UTC (permalink / raw)
To: John David Anglin; +Cc: jsm28, gcc-patches
> #include <stdbool.h>
>
> int f (int a, int b, int c, _Bool d, _Bool e, _Bool f, char g)
> {
> if (g != 1 || d != true || e != true || f != true) abort ();
> return a + b + c;
> }
>
> main ()
> {
> exit (f (1, 2, -3, true, true, true, '\001'));
> }
>
The above code exposes the bug in the existing C compiler because cc1
currently promotes boolean types before a call but doesn't demote
them in the callee. The test passes with cc1plus because it isn't
promoting or demoting booleans at all. If anybody has a brilliant
idea on how to test for this let me know.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
[not found] <no.id>
` (44 preceding siblings ...)
2001-06-04 10:53 ` PATCH: fix argument promotion John David Anglin
@ 2001-06-09 9:37 ` John David Anglin
2001-06-09 11:44 ` Benjamin Kosnik
2001-06-09 21:21 ` PATCH: gthr-dce.h update for v3 thread compatibility John David Anglin
` (117 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-06-09 9:37 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, bkoz
And another one:
/xxx/gnu/gcc-3.0/objdir/gcc/xgcc -B/xxx/gnu/gcc-3.0/objdir/gcc/ -nostdinc++ -L/xxx/gnu/gcc-3.0/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/src -L/xxx/gnu/gcc-3.0/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/src/.libs -B/usr/local/hppa1.1-hp-hpux10.20/bin/ -B/usr/local/hppa1.1-hp-hpux10.20/lib/ -isystem /usr/local/hppa1.1-hp-hpux10.20/include -nostdinc++ -I../../../../libstdc++-v3/include -I../../../../libstdc++-v3/include/std -I../../../../libstdc++-v3/include/c_std -I../include -I../../../../libstdc++-v3/libsupc++ -I../libio -I../../../../libstdc++-v3/libio -I../../../../libstdc++-v3/libmath -g -O2 -fno-implicit-templates -Wall -Wno-format -W -Wwrite-strings -Winline -fdiagnostics-show-location=once -g -c ../../../../libstdc++-v3/src/complex_io.cc -fPIC -DPIC -o .libs/complex_io.o
In file included from ../../../../libstdc++-v3/include/bits/std_complex.h:43,
from ../../../../libstdc++-v3/src/complex_io.cc:30:
../../../../libstdc++-v3/include/c_std/bits/std_cmath.h: In function `double std::pow(double, int)':
../../../../libstdc++-v3/include/c_std/bits/std_cmath.h:419: `double std::pow(double, int)' conflicts with previous using declaration `double pow(double, int)'
I see this in /xxx/gnu/gcc-3.0/objdir/gcc/include/math.h:
extern "C" {
...
extern double pow(double, double);
}
inline double pow(double __d,int __expon) {
return pow(__d,(double)__expon);
}
Thoughts on fixing this? For the moment, I just commented out the
definition in std_cmath.h.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 9:37 ` [v3] build failure from automated checker John David Anglin
@ 2001-06-09 11:44 ` Benjamin Kosnik
2001-06-09 11:55 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Benjamin Kosnik @ 2001-06-09 11:44 UTC (permalink / raw)
To: John David Anglin; +Cc: John David Anglin, gcc-patches
I don't know what this is.
> ../../../../libstdc++-v3/include/c_std/bits/std_cmath.h: In function `double std::pow(double, int)':
> ../../../../libstdc++-v3/include/c_std/bits/std_cmath.h:419: `double std::pow(double, int)' conflicts with previous using declaration `double pow(double, int)'
>
> I see this in /xxx/gnu/gcc-3.0/objdir/gcc/include/math.h:
>
> extern "C" {
> ...
> inline double pow(double __d,int __expon) {
> return pow(__d,(double)__expon);
> }
I don't think the above is in C99
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 11:44 ` Benjamin Kosnik
@ 2001-06-09 11:55 ` John David Anglin
2001-06-09 12:00 ` Benjamin Kosnik
2001-06-09 16:57 ` Gabriel Dos Reis
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-06-09 11:55 UTC (permalink / raw)
To: Benjamin Kosnik; +Cc: gcc-patches
> > extern "C" {
> > ...
Missed
# ifdef __cplusplus
}
> > inline double pow(double __d,int __expon) {
> > return pow(__d,(double)__expon);
> > }
extern "C" {
#else
...
>
> I don't think the above is in C99
HPUX 10.20 is definitely not C99 conformant. Should the above inline
be removed with fixincl or can you do something with the v3 configuration?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 11:55 ` John David Anglin
@ 2001-06-09 12:00 ` Benjamin Kosnik
2001-06-13 16:04 ` John David Anglin
2001-06-09 16:57 ` Gabriel Dos Reis
1 sibling, 1 reply; 521+ messages in thread
From: Benjamin Kosnik @ 2001-06-09 12:00 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> HPUX 10.20 is definitely not C99 conformant. Should the above inline
> be removed with fixincl or can you do something with the v3 configuration?
fixincl please
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 12:00 ` Benjamin Kosnik
@ 2001-06-13 16:04 ` John David Anglin
2001-06-13 20:22 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-06-13 16:04 UTC (permalink / raw)
To: Benjamin Kosnik; +Cc: gcc-patches, bkorb, mark
> > HPUX 10.20 is definitely not C99 conformant. Should the above inline
> > be removed with fixincl or can you do something with the v3 configuration?
>
> fixincl please
Here is a first crack at a hack to fix the problem for review. I have
checked that it blows away the inline. It's a bit of a pain to to
develop hacks for hpux because of haven't yet been able to build
autogen 5 on it.
Probably, Bruce will have to install it.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-06-13 John David Anglin <dave@hiauly1.hia.nrc.ca>
* inclhack.def (hpux10_cpp_pow_inline): New hack.
--- inclhack.def.orig Sat Jun 9 16:12:03 2001
+++ inclhack.def Wed Jun 13 18:42:01 2001
@@ -1119,6 +1119,33 @@
/*
+ * Delete C++ double pow (double, int) inline function from HP-UX 10
+ * math.h to prevent clash with define in c_std/bits/std_cmath.h.
+ */
+fix = {
+ hackname = hpux10_cpp_pow_inline;
+ files = math.h;
+ select = "^# +ifdef +__cplusplus\n +}\n +inline +double +pow"
+ "\\(double +__d,int +__expon\\) +{\n[ \t]+return +pow"
+ "\\(__d,\\(double\\)__expon\\);\n +}\n +extern"
+ ' +"C"'
+ " +{\n#else\n# +endif";
+ c_fix = format;
+ c_fix_arg = "";
+
+ test_text =
+ "# ifdef __cplusplus\n"
+ " }\n"
+ " inline double pow(double __d,int __expon) {\n"
+ "\t return pow(__d,(double)__expon);\n"
+ " }\n"
+ ' extern "C"' " {\n"
+ "#else\n"
+ "# endif";
+};
+
+
+/*
* Keep HP-UX 11 from stomping on C++ math namespace
* with defines for fabsf.
*/
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 16:04 ` John David Anglin
@ 2001-06-13 20:22 ` Alexandre Oliva
2001-06-13 20:49 ` Bruce Korb
2001-06-13 20:52 ` Bruce Korb
0 siblings, 2 replies; 521+ messages in thread
From: Alexandre Oliva @ 2001-06-13 20:22 UTC (permalink / raw)
To: John David Anglin; +Cc: Benjamin Kosnik, gcc-patches, bkorb, mark
On Jun 13, 2001, "John David Anglin" <dave@hiauly1.hia.nrc.ca> wrote:
>> > HPUX 10.20 is definitely not C99 conformant. Should the above inline
>> > be removed with fixincl or can you do something with the v3 configuration?
>>
>> fixincl please
> Here is a first crack at a hack to fix the problem for review. I have
> checked that it blows away the inline. It's a bit of a pain to to
> develop hacks for hpux because of haven't yet been able to build
> autogen 5 on it.
I've got autogen 5 running on a different platform, so I'll be testing
your changes momentarily. Thanks!
Mark, if it fixes the problem, may I go ahead and check it in the
branch?
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 20:22 ` Alexandre Oliva
@ 2001-06-13 20:49 ` Bruce Korb
2001-06-13 21:41 ` Mark Mitchell
2001-06-13 20:52 ` Bruce Korb
1 sibling, 1 reply; 521+ messages in thread
From: Bruce Korb @ 2001-06-13 20:49 UTC (permalink / raw)
To: Alexandre Oliva
Cc: John David Anglin, Benjamin Kosnik, gcc-patches, bkorb, mark
Alexandre Oliva wrote:
>
> On Jun 13, 2001, "John David Anglin" <dave@hiauly1.hia.nrc.ca> wrote:
>
> >> > HPUX 10.20 is definitely not C99 conformant. Should the above inline
> >> > be removed with fixincl or can you do something with the v3 configuration?
> >>
> >> fixincl please
>
> > Here is a first crack at a hack to fix the problem for review. I have
> > checked that it blows away the inline. It's a bit of a pain to to
> > develop hacks for hpux because of haven't yet been able to build
> > autogen 5 on it.
>
> I've got autogen 5 running on a different platform, so I'll be testing
> your changes momentarily. Thanks!
>
> Mark, if it fixes the problem, may I go ahead and check it in the
> branch?
I'll have it in mainline momentarily. If it checks out there, I would
add it to 3.0. The patch is extremely precise (i.e. unlikely
to hit innocent bystanders).
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 20:49 ` Bruce Korb
@ 2001-06-13 21:41 ` Mark Mitchell
2001-06-13 23:03 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2001-06-13 21:41 UTC (permalink / raw)
To: Bruce Korb, Alexandre Oliva
Cc: John David Anglin, Benjamin Kosnik, gcc-patches, bkorb
> I'll have it in mainline momentarily. If it checks out there, I would
> add it to 3.0. The patch is extremely precise (i.e. unlikely
> to hit innocent bystanders).
OK. Apply it on the branch, too, then, if you would.
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 21:41 ` Mark Mitchell
@ 2001-06-13 23:03 ` Alexandre Oliva
0 siblings, 0 replies; 521+ messages in thread
From: Alexandre Oliva @ 2001-06-13 23:03 UTC (permalink / raw)
To: Mark Mitchell
Cc: Bruce Korb, John David Anglin, Benjamin Kosnik, gcc-patches, bkorb
On Jun 14, 2001, Mark Mitchell <mark@codesourcery.com> wrote:
>> I'll have it in mainline momentarily. If it checks out there, I would
>> add it to 3.0. The patch is extremely precise (i.e. unlikely
>> to hit innocent bystanders).
> OK. Apply it on the branch, too, then, if you would.
I've gone ahead and checked it in.
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 20:22 ` Alexandre Oliva
2001-06-13 20:49 ` Bruce Korb
@ 2001-06-13 20:52 ` Bruce Korb
2001-06-13 21:23 ` Alexandre Oliva
1 sibling, 1 reply; 521+ messages in thread
From: Bruce Korb @ 2001-06-13 20:52 UTC (permalink / raw)
To: Alexandre Oliva
Cc: John David Anglin, Benjamin Kosnik, gcc-patches, bkorb, mark
Alexandre Oliva wrote:
> I've got autogen 5 running on a different platform, so I'll be testing
> your changes momentarily. Thanks!
>
> Mark, if it fixes the problem, may I go ahead and check it in the
> branch?
Patch is now applied on mainline. I'll leave it to you-all
to apply to 3.0, since I cannot test HPUX. :-)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-13 20:52 ` Bruce Korb
@ 2001-06-13 21:23 ` Alexandre Oliva
0 siblings, 0 replies; 521+ messages in thread
From: Alexandre Oliva @ 2001-06-13 21:23 UTC (permalink / raw)
To: Bruce Korb; +Cc: John David Anglin, Benjamin Kosnik, gcc-patches, bkorb, mark
On Jun 14, 2001, Bruce Korb <bkorb@pacbell.net> wrote:
> Alexandre Oliva wrote:
>> I've got autogen 5 running on a different platform, so I'll be testing
>> your changes momentarily. Thanks!
>>
>> Mark, if it fixes the problem, may I go ahead and check it in the
>> branch?
> Patch is now applied on mainline. I'll leave it to you-all
> to apply to 3.0, since I cannot test HPUX. :-)
I've just verified that libstdc++-v3 builds successfully on HP-UX
10.20 with the patch. Mark, ok to install it in the branch?
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 11:55 ` John David Anglin
2001-06-09 12:00 ` Benjamin Kosnik
@ 2001-06-09 16:57 ` Gabriel Dos Reis
2001-06-09 21:34 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Gabriel Dos Reis @ 2001-06-09 16:57 UTC (permalink / raw)
To: John David Anglin; +Cc: Benjamin Kosnik, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
| > > extern "C" {
| > > ...
|
| Missed
|
| # ifdef __cplusplus
| }
| > > inline double pow(double __d,int __expon) {
| > > return pow(__d,(double)__expon);
| > > }
| extern "C" {
| #else
| ...
| >
| > I don't think the above is in C99
|
| HPUX 10.20 is definitely not C99 conformant. Should the above inline
| be removed with fixincl or can you do something with the v3 configuration?
I would prefer the above be removed.
Thanks,
-- Gaby
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [v3] build failure from automated checker.....
2001-06-09 16:57 ` Gabriel Dos Reis
@ 2001-06-09 21:34 ` John David Anglin
2001-06-09 23:22 ` Benjamin Kosnik
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-06-09 21:34 UTC (permalink / raw)
To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches
> | HPUX 10.20 is definitely not C99 conformant. Should the above inline
> | be removed with fixincl or can you do something with the v3 configuration?
>
> I would prefer the above be removed.
I am away tomorrow and part of Monday. So I can't look at it until after
then. Unfortunately, the problem breaks the build.
Here is the exact code from the header:
extern double pow(double, double);
# ifdef __cplusplus
}
inline double pow(double __d,int __expon) {
return pow(__d,(double)__expon);
}
extern "C" {
#else
# endif
extern double sqrt(double);
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: gthr-dce.h update for v3 thread compatibility
[not found] <no.id>
` (45 preceding siblings ...)
2001-06-09 9:37 ` [v3] build failure from automated checker John David Anglin
@ 2001-06-09 21:21 ` John David Anglin
2001-06-14 18:38 ` PATCH: Fix invalid loader fixups from shared libobjc with John David Anglin
` (116 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-06-09 21:21 UTC (permalink / raw)
To: John David Anglin; +Cc: rittle, gcc-patches
This is the gthr-dce.h update for the main.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
Index: gthr-dce.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gthr-dce.h,v
retrieving revision 1.11
diff -c -3 -p -r1.11 gthr-dce.h
*** gthr-dce.h 2001/05/30 22:38:43 1.11
--- gthr-dce.h 2001/06/09 20:00:31
*************** typedef pthread_once_t __gthread_once_t;
*** 48,55 ****
typedef pthread_mutex_t __gthread_mutex_t;
#define __GTHREAD_ONCE_INIT pthread_once_init
- /* Howto define __GTHREAD_MUTEX_INIT? */
#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
#pragma weak pthread_once
--- 48,56 ----
typedef pthread_mutex_t __gthread_mutex_t;
#define __GTHREAD_ONCE_INIT pthread_once_init
+ #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
+
#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
#pragma weak pthread_once
*************** typedef pthread_mutex_t __gthread_mutex_
*** 59,65 ****
#pragma weak pthread_getspecific
#pragma weak pthread_setspecific
#pragma weak pthread_create
!
#pragma weak pthread_mutex_lock
#pragma weak pthread_mutex_trylock
#pragma weak pthread_mutex_unlock
--- 60,66 ----
#pragma weak pthread_getspecific
#pragma weak pthread_setspecific
#pragma weak pthread_create
! #pragma weak pthread_mutex_init
#pragma weak pthread_mutex_lock
#pragma weak pthread_mutex_trylock
#pragma weak pthread_mutex_unlock
*************** typedef pthread_mutex_t __gthread_mutex_
*** 73,79 ****
#pragma weak pthread_cond_wait
#pragma weak pthread_exit
#pragma weak pthread_getunique_np
- #pragma weak pthread_mutex_init
#pragma weak pthread_mutex_destroy
#pragma weak pthread_self
#pragma weak pthread_yield
--- 74,79 ----
*************** __gthread_key_dtor (UNUSED (__gthread_ke
*** 424,443 ****
return 0;
}
- #if defined (__PTHREAD_LIBRARY_VERSION_1) && __PTHREAD_LIBRARY_VERSION_1 >= 1
- static inline int
- __gthread_key_delete (__gthread_key_t key)
- {
- return pthread_key_delete (key);
- }
- #else
static inline int
__gthread_key_delete (UNUSED (__gthread_key_t key))
{
/* Operation is not supported. */
return -1;
}
- #endif
static inline void *
__gthread_getspecific (__gthread_key_t key)
--- 424,435 ----
*************** static inline int
*** 453,458 ****
--- 445,457 ----
__gthread_setspecific (__gthread_key_t key, const void *ptr)
{
return pthread_setspecific (key, (void *) ptr);
+ }
+
+ static inline void
+ __gthread_mutex_init_function (__gthread_mutex_t *mutex)
+ {
+ if (__gthread_active_p ())
+ pthread_mutex_init (mutex, pthread_mutexattr_default);
}
static inline int
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix invalid loader fixups from shared libobjc with
[not found] <no.id>
` (46 preceding siblings ...)
2001-06-09 21:21 ` PATCH: gthr-dce.h update for v3 thread compatibility John David Anglin
@ 2001-06-14 18:38 ` John David Anglin
2001-07-10 13:33 ` LO_SUM still breaking rs6000, revert patch? John David Anglin
` (115 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-06-14 18:38 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, shebs, law, gcc-patches
> a similar nature. The new issue is the install location for libobjc
> which appears wrong to me.
I am afraid there are more problems with the install than just the location.
Multilib versions are not being installed. Not sure if they are even being
built. Should know in a while:-(
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: LO_SUM still breaking rs6000, revert patch?
[not found] <no.id>
` (47 preceding siblings ...)
2001-06-14 18:38 ` PATCH: Fix invalid loader fixups from shared libobjc with John David Anglin
@ 2001-07-10 13:33 ` John David Anglin
2001-08-09 14:46 ` ../../gcc/java/class.c:1882: `JCR_SECTION_NAME' undeclared in emit_register_classes John David Anglin
` (114 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-07-10 13:33 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, geoffk, law, kenner
> I am guessing but I think the LO_SUM changes have also broken the PA port.
> See < http://gcc.gnu.org/ml/gcc-patches/2001-07/msg00652.html > for more
> details. I haven't tried todays change yet.
On further investigation, it appears the PA failure is very similar to what
you describe here < http://gcc.gnu.org/ml/gcc-patches/2001-07/msg00659.html >.
This is the rtl that causes the problem:
(insn 61 78 80 (set (mem/f:DI (lo_sum:SI (reg/f:SI 1 %r1 [103])
(symbol_ref:SI ("ffedata_storage_size_"))) 27)
(reg:DI 28 %r28 [118])) 119 {*pa.md:3094} (insn_list 194 (insn_list 57 (insn_list:REG_DEP_ANTI 76 (nil))))
(expr_list:REG_DEAD (reg:DI 28 %r28 [118])
(expr_list:REG_DEAD (reg/f:SI 1 %r1 [103])
(nil))))
The code is trying to move a double and is trying to find a temporary
address register which it can increment to move the second part of the
double. formerly, this situation only occured with PLUS.
I have attached the preprocessed source.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
begin 644 data.i.gz
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
M:[	&.D]TA3\.SN98V-)+N^J(NUE;]Y*YIER<&B]_(`L3L[>0&,4+11&F9A
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
MM=]E)@5N2]IJS=%J3G<PR6+M9B1==QU9N+ZL#\R4#Q^'[K!@B4X=&;CC3
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
M9O"-(:=.$&R>4O8M>]'FL^J3?A5"R@/)"$SM2BR.`C.3MQ%1=?DB0F;&9-
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
M9`/(#J+EL!MVW1!;4<*)&DS:8'`NC1_"J-QK\@@0*HL8-3`'$C,V=+_'Z
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
86;HK[F:EDL/#MV_S=>O_!Q6_S0T7&@0`
`
end
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: ../../gcc/java/class.c:1882: `JCR_SECTION_NAME' undeclared in emit_register_classes
[not found] <no.id>
` (48 preceding siblings ...)
2001-07-10 13:33 ` LO_SUM still breaking rs6000, revert patch? John David Anglin
@ 2001-08-09 14:46 ` John David Anglin
2001-08-09 16:13 ` Richard Henderson
2001-08-09 15:12 ` Simple returns are broken in gcc 3.X John David Anglin
` (113 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-08-09 14:46 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, gcc-patches
> The following bootstrap error occurs with mainline under hppa1.1-hp-hpux10.20:
>
> stage1/xgcc -Bstage1/ -B/usr/local/hppa1.1-hp-hpux10.20/bin/ -c -DIN_GCC -g -O2 -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -DHAVE_CONFIG_H -I. -Ijava -I../../gcc -I../../gcc/java -I../../gcc/config -I../../gcc/../include ../../gcc/java/class.c -o java/class.o
> ../../gcc/java/class.c: In function `emit_register_classes':
> ../../gcc/java/class.c:1882: `JCR_SECTION_NAME' undeclared (first use in this function)
> ../../gcc/java/class.c:1882: (Each undeclared identifier is reported only once
> ../../gcc/java/class.c:1882: for each function it appears in.)
> make[2]: *** [java/class.o] Error 1
This patch fixes the problem. Compile checked on hppa1.1-hp-hpux10.20 and
bootstrap and regression tested on i686-pc-linux-gnu.
OK for main?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-08-09 John David Anglin <dave@hiauly1.hia.nrc.ca>
* defaults.h (JCR_SECTION_NAME): Don't conditionalize definition.
--- defaults.h.orig Thu Aug 9 12:49:01 2001
+++ defaults.h Thu Aug 9 12:54:45 2001
@@ -217,14 +217,12 @@
#endif
#endif
-/* If we have named section and we support weak symbols, then use the
- .jcr section for recording java classes which need to be registered
- at program start-up time. */
-#if defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
+/* Provide default .jcr section name for recording java classes which need
+ to be registered at program start-up. This is only used if we support
+ named sections and weak symbols. */
#ifndef JCR_SECTION_NAME
#define JCR_SECTION_NAME ".jcr"
#endif
-#endif
/* If we have no definition for UNIQUE_SECTION, but do have the
ability to generate arbitrary sections, construct something
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Simple returns are broken in gcc 3.X
[not found] <no.id>
` (49 preceding siblings ...)
2001-08-09 14:46 ` ../../gcc/java/class.c:1882: `JCR_SECTION_NAME' undeclared in emit_register_classes John David Anglin
@ 2001-08-09 15:12 ` John David Anglin
2001-08-09 15:48 ` Richard Henderson
2001-08-22 8:50 ` fix execute/20010518-2.c John David Anglin
` (112 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-08-09 15:12 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches
> In looking into why g++ didn't work for vax-dec-ultrix4.3, I have found
> that simple returns are broken. Compiling this small test program
>
> static char *
> srealloc (char *p, char *q, int i)
> {
> if (i == 0)
> return p;
> else
> return q;
> }
>
> yields
>
> #NO_APP
> .text
> .align 1
> __Z8sreallocPcS_i:
> .word 0x0
> subl2 $12,sp
> tstl 12(ap)
> jneq L2
> ret
> L2:
> ret
This patch fixes the above problem by always forcing a "goto" return.
The patch only affects the vax since it is the only remaining port that
doesn't define an epilogue and allows the expansion of simple returns
prior to reload. This patch changes the vax port to use the same
code patch for return generation as all others. As a side benefit, the
change also fixes function instrumentation on the vax.
The above behavior is a regression versus previous gcc versions since
g++ was functional on the vax in version 2.8.1.
Full bootstrap has been done with vax-dec-ultrix4.3 with 3.0 branch.
Bootstrap and regression checked with 3.0 branch on hppa1.1-hp-hpux10.20
and i686-pc-linux-gnu. Bootstrap and regression checked with 3.1
mainline on i686-pc-linux-gnu.
OK for main? I would like it on the branch as well but there are a
couple of other patches needed before C++ will be fully functional
on the vax. Thus, it can wait until after 3.0.1 is released.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-08-09 John David Anglin <dave@hiauly1.hia.nrc.ca>
* stmt.c (expand_null_return_1): Remove code to generate simple returns
and "use_goto" argument.
(expand_null_return, expand_value_return): Update all callers.
* function.c (expand_function_end): Remove code to generate simple
return.
* config/vax/vax.md (epilogue): New expander for function return.
* doc/md.texi (epilogue): Remove "if defined".
--- stmt.c.orig Tue Jul 31 10:22:56 2001
+++ stmt.c Wed Aug 1 15:52:05 2001
@@ -403,7 +403,7 @@
static void expand_nl_goto_receivers PARAMS ((struct nesting *));
static void fixup_gotos PARAMS ((struct nesting *, rtx, tree,
rtx, int));
-static void expand_null_return_1 PARAMS ((rtx, int));
+static void expand_null_return_1 PARAMS ((rtx));
static void expand_value_return PARAMS ((rtx));
static int tail_recursion_args PARAMS ((tree, tree));
static void expand_cleanups PARAMS ((tree, tree, int, int));
@@ -2863,7 +2863,6 @@
void
expand_null_return ()
{
- struct nesting *block = block_stack;
rtx last_insn = get_last_insn ();
/* If this function was declared to return a value, but we
@@ -2871,13 +2870,7 @@
propogated live to the rest of the function. */
clobber_return_register ();
- /* Does any pending block have cleanups? */
- while (block && block->data.block.cleanups == 0)
- block = block->next;
-
- /* If yes, use a goto to return, since that runs cleanups. */
-
- expand_null_return_1 (last_insn, block != 0);
+ expand_null_return_1 (last_insn);
}
/* Generate RTL to return from the current function, with value VAL. */
@@ -2886,7 +2879,6 @@
expand_value_return (val)
rtx val;
{
- struct nesting *block = block_stack;
rtx last_insn = get_last_insn ();
rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
@@ -2913,27 +2905,15 @@
emit_move_insn (return_reg, val);
}
- /* Does any pending block have cleanups? */
-
- while (block && block->data.block.cleanups == 0)
- block = block->next;
-
- /* If yes, use a goto to return, since that runs cleanups.
- Use LAST_INSN to put cleanups *before* the move insn emitted above. */
-
- expand_null_return_1 (last_insn, block != 0);
+ expand_null_return_1 (last_insn);
}
/* Output a return with no value. If LAST_INSN is nonzero,
- pretend that the return takes place after LAST_INSN.
- If USE_GOTO is nonzero then don't use a return instruction;
- go to the return label instead. This causes any cleanups
- of pending blocks to be executed normally. */
+ pretend that the return takes place after LAST_INSN. */
static void
-expand_null_return_1 (last_insn, use_goto)
+expand_null_return_1 (last_insn)
rtx last_insn;
- int use_goto;
{
rtx end_label = cleanup_label ? cleanup_label : return_label;
@@ -2941,27 +2921,8 @@
do_pending_stack_adjust ();
last_expr_type = 0;
- /* PCC-struct return always uses an epilogue. */
- if (current_function_returns_pcc_struct || use_goto)
- {
- if (end_label == 0)
- end_label = return_label = gen_label_rtx ();
- expand_goto_internal (NULL_TREE, end_label, last_insn);
- return;
- }
-
- /* Otherwise output a simple return-insn if one is available,
- unless it won't do the job. */
-#ifdef HAVE_return
- if (HAVE_return && use_goto == 0 && cleanup_label == 0)
- {
- emit_jump_insn (gen_return ());
- emit_barrier ();
- return;
- }
-#endif
-
- /* Otherwise jump to the epilogue. */
+ if (end_label == 0)
+ end_label = return_label = gen_label_rtx ();
expand_goto_internal (NULL_TREE, end_label, last_insn);
}
\f
--- function.c.orig Sat Jun 9 15:22:26 2001
+++ function.c Wed Aug 1 12:40:23 2001
@@ -6949,18 +6949,6 @@
instead of using the general framework. */
use_return_register ();
- /* Output a return insn if we are using one.
- Otherwise, let the rtl chain end here, to drop through
- into the epilogue. */
-
-#ifdef HAVE_return
- if (HAVE_return)
- {
- emit_jump_insn (gen_return ());
- emit_barrier ();
- }
-#endif
-
/* Fix up any gotos that jumped out to the outermost
binding level of the function.
Must follow emitting RETURN_LABEL. */
--- config/vax/vax.md.orig Sun Jan 14 04:08:51 2001
+++ config/vax/vax.md Tue Jul 31 22:08:45 2001
@@ -1926,6 +1926,15 @@
""
"ret")
+(define_expand "epilogue"
+ [(return)]
+ ""
+ "
+{
+ emit_jump_insn (gen_return ());
+ DONE;
+}")
+
(define_insn "nop"
[(const_int 0)]
""
--- doc/md.texi.orig Thu Jun 14 18:54:21 2001
+++ doc/md.texi Thu Aug 9 12:24:04 2001
@@ -2859,7 +2859,7 @@
@cindex @code{epilogue} instruction pattern
@item @samp{epilogue}
-This pattern, if defined, emits RTL for exit from a function. The function
+This pattern emits RTL for exit from a function. The function
exit is responsible for deallocating the stack frame, restoring callee saved
registers and emitting the return instruction.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Simple returns are broken in gcc 3.X
2001-08-09 15:12 ` Simple returns are broken in gcc 3.X John David Anglin
@ 2001-08-09 15:48 ` Richard Henderson
0 siblings, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2001-08-09 15:48 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches
On Thu, Aug 09, 2001 at 06:12:04PM -0400, John David Anglin wrote:
> * stmt.c (expand_null_return_1): Remove code to generate simple returns
> and "use_goto" argument.
> (expand_null_return, expand_value_return): Update all callers.
> * function.c (expand_function_end): Remove code to generate simple
> return.
> * config/vax/vax.md (epilogue): New expander for function return.
> * doc/md.texi (epilogue): Remove "if defined".
Ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix execute/20010518-2.c
[not found] <no.id>
` (50 preceding siblings ...)
2001-08-09 15:12 ` Simple returns are broken in gcc 3.X John David Anglin
@ 2001-08-22 8:50 ` John David Anglin
2001-08-23 22:55 ` John David Anglin
` (111 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-08-22 8:50 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches
> will support this but again there is the problem of turning this support
> off when gas isn't used. In a brief look at toplev.c, it didn't look
> like setting DWARF2_DEBUGGING_INFO to zero would do it.
Forget about this. The function override_options in pa.c turns off
debugging when gas isn't used.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix execute/20010518-2.c
[not found] <no.id>
` (51 preceding siblings ...)
2001-08-22 8:50 ` fix execute/20010518-2.c John David Anglin
@ 2001-08-23 22:55 ` John David Anglin
2001-08-23 22:57 ` Richard Henderson
2001-09-05 22:59 ` CVS Problem: java/parse.c and java/parse-scan.c deleted John David Anglin
` (110 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-08-23 22:55 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches
> I am currently testing the following change to the PA config together
> with the patch you sent. It will take a couple of days to run with and
> without gas.
New problem: HP as doesn't like undefined symbols without corresponding
.IMPORT directive:
/xxx/gnu/gcc-3.1/objdir/gcc/xgcc -B/xxx/gnu/gcc-3.1/objdir/gcc/ -nostdinc++ -L/xxx/gnu/gcc-3.1/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/src -L/xxx/gnu/gcc-3.1/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/src/.libs -B/usr/local/hppa1.1-hp-hpux10.20/bin/ -B/usr/local/hppa1.1-hp-hpux10.20/lib/ -isystem /usr/local/hppa1.1-hp-hpux10.20/include -I../../../../libstdc++-v3/../gcc -I../../../../libstdc++-v3/../include -I/xxx/gnu/gcc-3.1/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/include/hppa1.1-hp-hpux10.20 -I/xxx/gnu/gcc-3.1/objdir/hppa1.1-hp-hpux10.20/libstdc++-v3/include -I../../../../libstdc++-v3/libsupc++ -O2 -fno-implicit-templates -Wall -Wno-format -W -Wwrite-strings -Winline -fdiagnostics-show-location=once -g -c ../../../../libstdc++-v3/libsupc++/eh_aux_runtime.cc -fPIC -DPIC -o eh_aux_runtime.o
cc1plus: warning: -g is only supported when using GAS on this processor,
cc1plus: warning: -g option disabled.
as: error 7403: undefined label - _ZTVN10__cxxabiv120__si_class_type_infoE (7403)
Gas will assemble the file without problem. The demangled symbol is:
U vtable for __cxxabiv1::__si_class_type_info
We have the following references in the assembler file:
.SPACE $PRIVATE$
.SUBSPA $DATA$
.stabs "__ti_0:S79=xs__si_class_type_info_pseudo:",38,0,56,_ZTISt10bad_typeid
.align 4
_ZTISt10bad_typeid
.word _ZTVN10__cxxabiv120__si_class_type_infoE+8
.word _ZTSSt10bad_typeid
.word _ZTISt9exception
.stabs "__ti_1:S79",38,0,56,_ZTISt8bad_cast
.align 4
_ZTISt8bad_cast
.word _ZTVN10__cxxabiv120__si_class_type_infoE+8
.word _ZTSSt8bad_cast
.word _ZTISt9exception
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix execute/20010518-2.c
2001-08-23 22:55 ` John David Anglin
@ 2001-08-23 22:57 ` Richard Henderson
2001-08-26 14:28 ` as: error 7403: undefined label - _ZTVN10__cxxabiv120__si_class_type_infoE [was Re: fix execute/20010518-2.c] John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2001-08-23 22:57 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Fri, Aug 24, 2001 at 01:55:41AM -0400, John David Anglin wrote:
> New problem: HP as doesn't like undefined symbols without corresponding
> .IMPORT directive:
We're probably missing calls to assemble_external in
output_function_exception_table.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* as: error 7403: undefined label - _ZTVN10__cxxabiv120__si_class_type_infoE [was Re: fix execute/20010518-2.c]
2001-08-23 22:57 ` Richard Henderson
@ 2001-08-26 14:28 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-08-26 14:28 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, gcc-bugs
> On Fri, Aug 24, 2001 at 01:55:41AM -0400, John David Anglin wrote:
> > New problem: HP as doesn't like undefined symbols without corresponding
> > .IMPORT directive:
>
> We're probably missing calls to assemble_external in
> output_function_exception_table.
I don't think the problem is in output_function_exception_table. This
small program demonstrates the problem.
namespace std
{
class exception
{
public:
exception() throw() { }
virtual ~exception() throw();
};
class bad_typeid : public exception
{
public:
bad_typeid () throw() { }
virtual ~bad_typeid () throw();
};
}
extern "C" void __cxa_bad_typeid ();
extern "C" void
__cxa_bad_typeid ()
{
throw std::bad_typeid();
}
In the assembler output from both hppa1.1-hp-hpux10.20 and i686-pc-linux-gnu,
the symbol _ZTVN10__cxxabiv120__si_class_type_infoE is not defined. However,
GAS doesn't care that there is no .weak or .global statement for it.
A work around is to include <cxxabi.h>. If this is the correct solution,
then a lot of code needs fixing.
On i686, the symbol looked OK to me after finish_vtable_vardecl. Still
trying to figure out why assemble_external isn't being called.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: CVS Problem: java/parse.c and java/parse-scan.c deleted
[not found] <no.id>
` (52 preceding siblings ...)
2001-08-23 22:55 ` John David Anglin
@ 2001-09-05 22:59 ` John David Anglin
2001-09-22 11:35 ` PATCH: pass outgoing float arguments in both floating and general registers in indirect calls using 32 bit ABI John David Anglin
` (109 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-09-05 22:59 UTC (permalink / raw)
To: John David Anglin; +Cc: David.Billinghurst, gcc-bugs, gcc-patches
> > Probably by http://gcc.gnu.org/ml/gcc-patches/2001-09/msg00119.html
>
> I wonder if gcc_update should check to see if a file exists before
> touching it?
This prints a warning if a dependent file doesn't exist. OK?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-09-06 John David Anglin <dave@hiauly1.hia.nrc.ca>
* gcc_update (touch_files): Print warning if file does not exist.
--- gcc_update.orig Wed Sep 5 10:50:35 2001
+++ gcc_update Thu Sep 6 01:36:21 2001
@@ -114,6 +114,9 @@
files_and_dependencies | sed 's, .*, \\,' >> Makefile.$$
echo ':' >> Makefile.$$
echo ' @for f in $?; do test -f $$f || exit 0; done; \' >> Makefile.$$
+ echo ' if [ ! -f $@ ] ; then \' >> Makefile.$$
+ echo ' echo Warning: $@ does not exist. 1>&2; \' >> Makefile.$$
+ echo ' fi; \' >> Makefile.$$
echo ' echo Touching $@...; \' >> Makefile.$$
echo ' echo Touching $@... 1>&2; \' >> Makefile.$$
echo ' touch $@' >> Makefile.$$
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: pass outgoing float arguments in both floating and general registers in indirect calls using 32 bit ABI
[not found] <no.id>
` (53 preceding siblings ...)
2001-09-05 22:59 ` CVS Problem: java/parse.c and java/parse-scan.c deleted John David Anglin
@ 2001-09-22 11:35 ` John David Anglin
2001-09-24 8:47 ` law
2001-09-24 14:19 ` tiny tree.c update John David Anglin
` (108 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-09-22 11:35 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> Floating arguments should be passed in both general and floating registers
> in indirect ($$dyncall) calls in the 32 bit ABI when using the HP assembler.
> The reason is there is no way to specify argument locations in static
> functions when the HP assembler is used. The ABI requires that arguments
> in indirect calls be passed in general registers. However, the default
> location is in the floating registers and this is where a static function
> expects floating arguments. This change makes gcc consist in its behaviour
> with the HP compiler.
>
> Bootstrap checked with both gnu and HP assembler on hppa1.1-hp-hpux10.20.
>
> OK?
>
Oops.
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-09-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.c (function_arg): Pass floating arguments in both general and
floating registers in indirect (dynamic) calls when generating code
for the 32 bit ABI and the HP assembler.
--- pa.c.orig Wed Aug 22 13:32:28 2001
+++ pa.c Wed Sep 5 15:48:47 2001
@@ -7145,22 +7145,30 @@
gen_rtx_REG (DImode, gpr_reg_base),
GEN_INT (8))));
}
- /* Determine if the register needs to be passed in both general and
+ /* Determine if the argument needs to be passed in both general and
floating point registers. */
- if ((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
- /* If we are doing soft-float with portable runtime, then there
- is no need to worry about FP regs. */
- && ! TARGET_SOFT_FLOAT
- /* The parameter must be some kind of float, else we can just
- pass it in integer registers. */
- && FLOAT_MODE_P (mode)
- /* The target function must not have a prototype. */
- && cum->nargs_prototype <= 0
- /* libcalls do not need to pass items in both FP and general
- registers. */
- && type != NULL_TREE
- /* All this hair applies to outgoing args only. */
- && !incoming)
+ if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
+ /* If we are doing soft-float with portable runtime, then there
+ is no need to worry about FP regs. */
+ && ! TARGET_SOFT_FLOAT
+ /* The parameter must be some kind of float, else we can just
+ pass it in integer registers. */
+ && FLOAT_MODE_P (mode)
+ /* The target function must not have a prototype. */
+ && cum->nargs_prototype <= 0
+ /* libcalls do not need to pass items in both FP and general
+ registers. */
+ && type != NULL_TREE
+ /* All this hair applies to outgoing args only. */
+ && ! incoming)
+ /* Also pass outgoing floating arguments in both registers in indirect
+ calls with the 32 bit ABI and the HP assembler since there is no
+ way to the specify argument locations in static functions. */
+ || (! TARGET_64BIT
+ && ! TARGET_GAS
+ && ! incoming
+ && cum->indirect
+ && FLOAT_MODE_P (mode)))
{
retval
= gen_rtx_PARALLEL
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: pass outgoing float arguments in both floating and general registers in indirect calls using 32 bit ABI
2001-09-22 11:35 ` PATCH: pass outgoing float arguments in both floating and general registers in indirect calls using 32 bit ABI John David Anglin
@ 2001-09-24 8:47 ` law
0 siblings, 0 replies; 521+ messages in thread
From: law @ 2001-09-24 8:47 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message < 200109221835.f8MIZcnS023564@hiauly1.hia.nrc.ca >you write:
> > Floating arguments should be passed in both general and floating register
> s
> > in indirect ($$dyncall) calls in the 32 bit ABI when using the HP assembl
> er.
> > The reason is there is no way to specify argument locations in static
> > functions when the HP assembler is used. The ABI requires that arguments
> > in indirect calls be passed in general registers. However, the default
> > location is in the floating registers and this is where a static function
> > expects floating arguments. This change makes gcc consist in its behavio
> ur
> > with the HP compiler.
> >
> > Bootstrap checked with both gnu and HP assembler on hppa1.1-hp-hpux10.20.
> >
> > OK?
> >
>
> Oops.
>
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6
> 605)
>
> 2001-09-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa.c (function_arg): Pass floating arguments in both general and
> floating registers in indirect (dynamic) calls when generating code
> for the 32 bit ABI and the HP assembler.
This is fine. Please install.
Thanks,
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: tiny tree.c update
[not found] <no.id>
` (54 preceding siblings ...)
2001-09-22 11:35 ` PATCH: pass outgoing float arguments in both floating and general registers in indirect calls using 32 bit ABI John David Anglin
@ 2001-09-24 14:19 ` John David Anglin
2001-09-25 5:35 ` Jan Hubicka
2001-10-03 12:08 ` PATCH: Check all insns in fallthru to see if label is mentioned John David Anglin
` (107 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-09-24 14:19 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jh, rth
> I got back to working on the vax port on the mainline last weekend. Your
> "tiny tree.c update" breaks the build on the vax in fixup_unsigned_type.
> It partially reverted:
>
> Thu Oct 8 05:56:00 1998 Jeffrey A Law (law@cygnus.com)
>
> * c-common.c (type_for_mode): Only return TItype nodes when
> HOST_BITS_PER_WIDE_INT is >= 64 bits.
> * c-decl.c (intTI_type_node, unsigned_intTI_type_node): Only declare
> when HOST_BITS_PER_WIDE_INT is >= 64 bits.
> (init_decl_processing): Only create TItype nodes when
> HOST_BITS_PER_WIDE_INT is >= 64 bits.
> * c-tree.h (intTI_type_node, unsigned_intTI_type_node): Only declare
> when HOST_BITS_PER_WIDE_INT is >= 64 bits.
I'm sorry. The correct patch that got reverted was:
Wed May 17 18:06:12 2000 John David Anglin <dave@hiauly1.hia.nrc.ca>
* mklibgcc.in Add missing -DL$name when compiling modules in libgcc1.c.
* tree.c (build_common_tree_nodes): Do not build TI nodes unless
HOST_BITS_PER_WIDE_INT is >= 64.
The early patch was I believe the first fix.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: tiny tree.c update
2001-09-24 14:19 ` tiny tree.c update John David Anglin
@ 2001-09-25 5:35 ` Jan Hubicka
2001-09-25 6:54 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2001-09-25 5:35 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jh, rth
> > I got back to working on the vax port on the mainline last weekend. Your
> > "tiny tree.c update" breaks the build on the vax in fixup_unsigned_type.
> > It partially reverted:
> >
> > Thu Oct 8 05:56:00 1998 Jeffrey A Law (law@cygnus.com)
> >
> > * c-common.c (type_for_mode): Only return TItype nodes when
> > HOST_BITS_PER_WIDE_INT is >= 64 bits.
> > * c-decl.c (intTI_type_node, unsigned_intTI_type_node): Only declare
> > when HOST_BITS_PER_WIDE_INT is >= 64 bits.
> > (init_decl_processing): Only create TItype nodes when
> > HOST_BITS_PER_WIDE_INT is >= 64 bits.
> > * c-tree.h (intTI_type_node, unsigned_intTI_type_node): Only declare
> > when HOST_BITS_PER_WIDE_INT is >= 64 bits.
>
> I'm sorry. The correct patch that got reverted was:
>
> Wed May 17 18:06:12 2000 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * mklibgcc.in Add missing -DL$name when compiling modules in libgcc1.c.
>
> * tree.c (build_common_tree_nodes): Do not build TI nodes unless
> HOST_BITS_PER_WIDE_INT is >= 64.
>
> The early patch was I believe the first fix.
We need the TImodes for SSE on i386, that is 32bit. The trick is that we don't do
any computation in that mode so everything "works" even when the compiler is not
able to repreent the constants.
Can you describe the VAX problem in more detail?
Honza
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: tiny tree.c update
2001-09-25 5:35 ` Jan Hubicka
@ 2001-09-25 6:54 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-09-25 6:54 UTC (permalink / raw)
To: Jan Hubicka; +Cc: gcc-patches, jh, rth
> Can you describe the VAX problem in more detail?
The vax "ext" instructions generate illegal instruction faults
when the shift treated as unsigned is > 32 or when the position
specifier (again unsigned) is > 31.
The following code in fixup_unsigned_type causes problems when TI
nodes are built on the vax:
TYPE_MAX_VALUE (type)
= build_int_2 (precision - HOST_BITS_PER_WIDE_INT >= 0
? -1 : ((HOST_WIDE_INT) 1 << precision) - 1,
precision - HOST_BITS_PER_WIDE_INT > 0
? ((unsigned HOST_WIDE_INT) ~0
>> (HOST_BITS_PER_WIDE_INT
- (precision - HOST_BITS_PER_WIDE_INT)))
: 0);
The right shift in the above evaluates to -64 when HOST_BITS_PER_WIDE_INT
is 32: 32 - (128 - 32). The behaviour of the right shift operator is
undefined when the shift specified is negative and on the vax it
generates an illegal insn trap.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Check all insns in fallthru to see if label is mentioned
[not found] <no.id>
` (55 preceding siblings ...)
2001-09-24 14:19 ` tiny tree.c update John David Anglin
@ 2001-10-03 12:08 ` John David Anglin
2001-12-04 17:46 ` Richard Henderson
2001-10-31 10:39 ` PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA John David Anglin
` (106 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-10-03 12:08 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2001-10-01 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * cfgcleanup.c (label_mentioned_p): New function.
> (try_optimize_cfg): Use it.
In the continuing saga of trying to get the vax bootstrap to work on
the main, I found that the above patch exposes what appears to be a
bug in rtx_equal_p. It currently may call strcmp with one or both
arguments being null pointers. This happens with "code_label" rtx's.
The strcmp function on i686-pc-linux-gnu apparently is not prepared to
handle null pointers and generates a segmentation fault. My original
testing of the patch was on hppa1.1-hp-hpux10.20. Its strcmp treats
null pointers the same as pointers to empty strings.
I have updated the patch to fix this problem. Bootstrapped and checked
on i686-pc-linux-gnu.
OK?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-10-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cfgcleanup.c (label_mentioned_p): New function.
(try_optimize_cfg): Use it.
* rtl.c (rtx_equal_p): Check for null pointers when comparing rtx
strings.
--- cfgcleanup.c.orig Fri Sep 21 18:29:23 2001
+++ cfgcleanup.c Fri Sep 28 16:09:38 2001
@@ -52,6 +52,7 @@
rtx *, rtx *));
static bool delete_unreachable_blocks PARAMS ((void));
+static bool label_mentioned_p PARAMS ((rtx, rtx));
static bool tail_recursion_label_p PARAMS ((rtx));
static void merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
basic_block));
@@ -248,6 +249,22 @@
return changed;
}
\f
+/* Return true if LABEL is mentioned in any insn from INSN up to
+ but not including the label. */
+
+static bool
+label_mentioned_p (label, insn)
+ rtx label, insn;
+{
+ rtx x;
+
+ for (x = insn; x != label; x = NEXT_INSN (x))
+ if (reg_mentioned_p (label, x))
+ return true;
+
+ return false;
+}
+
/* Return true if LABEL is used for tail recursion. */
static bool
@@ -1096,7 +1113,7 @@
/* If previous block ends with condjump jumping to next BB,
we can't delete the label. */
&& (b->pred->src == ENTRY_BLOCK_PTR
- || !reg_mentioned_p (b->head, b->pred->src->end)))
+ || !label_mentioned_p (b->head, b->pred->src->end)))
{
rtx label = b->head;
b->head = NEXT_INSN (b->head);
--- rtl.c.orig Wed Aug 22 11:33:57 2001
+++ rtl.c Wed Oct 3 11:34:19 2001
@@ -650,7 +650,9 @@
case 'S':
case 's':
- if (strcmp (XSTR (x, i), XSTR (y, i)))
+ if ((XSTR (x, i) || XSTR (y, i))
+ && (! XSTR (x, i) || ! XSTR (y, i)
+ || strcmp (XSTR (x, i), XSTR (y, i))))
return 0;
break;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Check all insns in fallthru to see if label is mentioned
2001-10-03 12:08 ` PATCH: Check all insns in fallthru to see if label is mentioned John David Anglin
@ 2001-12-04 17:46 ` Richard Henderson
2001-12-08 9:23 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2001-12-04 17:46 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, hiller
On Wed, Oct 03, 2001 at 03:08:12PM -0400, John David Anglin wrote:
> * cfgcleanup.c (label_mentioned_p): New function.
> (try_optimize_cfg): Use it.
Rather than search, this check ought to be
&& (!(mode & CLEANUP_PRE_SIBCALL)
|| !tail_recursion_label_p (b->head))
- /* If previous block ends with condjump jumping to next BB,
- we can't delete the label. */
- && (b->pred->src == ENTRY_BLOCK_PTR
- || !reg_mentioned_p (b->head, b->pred->src->end)))
+ /* If the previous block ends with a branch to this block,
+ we can't delete the label. Normally this is a condjump
+ that is yet to be simplified, but if CASE_DROPS_THRU,
+ this can be a tablejump with some element going to the
+ same place as the default (fallthru). */
+ && (b->pred->src == ENTRY_BLOCK_PTR
+ || GET_CODE (b->pred->src->end) != JUMP_INSN
+ || ! label_is_jump_target_p (b->head, b->pred->src->end)))
/* Return true if LABEL is a target of JUMP_INSN. This applies only
to non-complex jumps. That is, direct unconditional, conditional,
and tablejumps, but not computed jumps or returns. It also does
not apply to the fallthru case of a conditional jump. */
bool
label_is_jump_target_p (label, jump_insn)
rtx label, jump_insn;
{
rtx tmp = JUMP_LABEL (jump_insn);
if (label == tmp)
return true;
if (tmp != NULL_RTX
&& (tmp = NEXT_INSN (tmp)) != NULL_RTX
&& GET_CODE (tmp) == JUMP_INSN
&& (tmp = PATTERN (tmp),
GET_CODE (tmp) == ADDR_VEC
|| GET_CODE (tmp) == ADDR_DIFF_VEC))
{
rtvec vec = XVEC (tmp, GET_CODE (tmp) == ADDR_DIFF_VEC);
int i, veclen = GET_NUM_ELEM (vec);
for (i = 0; i < veclen; ++i)
if (XEXP (RTVEC_ELT (vec, i), 0) == label)
return true;
}
return false;
}
> * rtl.c (rtx_equal_p): Check for null pointers when comparing rtx
> strings.
The cfgcleanup thing aside, this is ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Check all insns in fallthru to see if label is mentioned
2001-12-04 17:46 ` Richard Henderson
@ 2001-12-08 9:23 ` John David Anglin
2001-12-09 16:12 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-12-08 9:23 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, hiller
> > On Wed, Oct 03, 2001 at 03:08:12PM -0400, John David Anglin wrote:
> > > * cfgcleanup.c (label_mentioned_p): New function.
> > > (try_optimize_cfg): Use it.
> >
>
> Rather than search, this check ought to be
I reworked your comments into a patch for cfgcleanup.c. The only change
is the addition of `static' to the declaration of label_is_jump_target_p.
I have tested with a complete bootstrap and check under hppa2.0w-hp-hpux11.11.
There might be two regressions:
FAIL: gcc.c-torture/execute/strct-pack-1.c execution, -O2
FAIL: gcc.c-torture/execute/strct-pack-1.c execution, -Os
These started failing in execution at some point after Dec. 1. It will
be a few days before I can examine these in more detail.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-08 Richard Henderson <rth@redhat.com>
* cfgcleanup.c (label_is_jump_target_p): New function.
(try_optimize_cfg): Use label_is_jump_target_p to check if label is
target of a JUMP_INSN from the preceding block.
--- cfgcleanup.c.orig Thu Nov 15 14:55:33 2001
+++ cfgcleanup.c Thu Dec 6 11:06:42 2001
@@ -69,6 +69,7 @@
rtx *, rtx *));
static bool delete_unreachable_blocks PARAMS ((void));
+static bool label_is_jump_target_p PARAMS ((rtx, rtx));
static bool tail_recursion_label_p PARAMS ((rtx));
static void merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
basic_block));
@@ -291,6 +292,38 @@
return changed;
}
\f
+/* Return true if LABEL is a target of JUMP_INSN. This applies only
+ to non-complex jumps. That is, direct unconditional, conditional,
+ and tablejumps, but not computed jumps or returns. It also does
+ not apply to the fallthru case of a conditional jump. */
+
+static bool
+label_is_jump_target_p (label, jump_insn)
+ rtx label, jump_insn;
+{
+ rtx tmp = JUMP_LABEL (jump_insn);
+
+ if (label == tmp)
+ return true;
+
+ if (tmp != NULL_RTX
+ && (tmp = NEXT_INSN (tmp)) != NULL_RTX
+ && GET_CODE (tmp) == JUMP_INSN
+ && (tmp = PATTERN (tmp),
+ GET_CODE (tmp) == ADDR_VEC
+ || GET_CODE (tmp) == ADDR_DIFF_VEC))
+ {
+ rtvec vec = XVEC (tmp, GET_CODE (tmp) == ADDR_DIFF_VEC);
+ int i, veclen = GET_NUM_ELEM (vec);
+
+ for (i = 0; i < veclen; ++i)
+ if (XEXP (RTVEC_ELT (vec, i), 0) == label)
+ return true;
+ }
+
+ return false;
+}
+
/* Return true if LABEL is used for tail recursion. */
static bool
@@ -1162,10 +1195,14 @@
&& GET_CODE (b->head) == CODE_LABEL
&& (!(mode & CLEANUP_PRE_SIBCALL)
|| !tail_recursion_label_p (b->head))
- /* If previous block ends with condjump jumping to next BB,
- we can't delete the label. */
+ /* If the previous block ends with a branch to this block,
+ we can't delete the label. Normally this is a condjump
+ that is yet to be simplified, but if CASE_DROPS_THRU,
+ this can be a tablejump with some element going to the
+ same place as the default (fallthru). */
&& (b->pred->src == ENTRY_BLOCK_PTR
- || !reg_mentioned_p (b->head, b->pred->src->end)))
+ || GET_CODE (b->pred->src->end) != JUMP_INSN
+ || ! label_is_jump_target_p (b->head, b->pred->src->end)))
{
rtx label = b->head;
b->head = NEXT_INSN (b->head);
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA
[not found] <no.id>
` (56 preceding siblings ...)
2001-10-03 12:08 ` PATCH: Check all insns in fallthru to see if label is mentioned John David Anglin
@ 2001-10-31 10:39 ` John David Anglin
2001-11-09 16:21 ` law
2001-11-13 15:03 ` Last alignment change for MEM tracking John David Anglin
` (105 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-10-31 10:39 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2001-10-29 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa.c (emit_move_sequence): Use cint_ok_for_move to check whether a
> constant can be loaded in a single instruction to a register. When
> loading immediate constants, use PLUS instead of HIGH/LO_SUM. Handle
> both zero and one extension of "32-bit" constants on 64-bit hosts.
> * pa.h (LEGITIMATE_CONSTANT_P): Accept constants that can be built
> with ldil/ldo/depdi instruction sequence on 64-bit hosts.
> * pa.md: New addmove pattern for adding constant_int to HImode
> register and moving result to HImode register. Remove HImode HIGH
> and LO_SUM patterns.
After thinking more about the above patch, I realized that it was trivial
to extend the range of constants handled by 64-bits hosts compiling for
TARGET_64BIT. This changes the previous patch to take advantage of the
full im5 format used for immediates by the depdi instruction. Checked
on hppa1.1-hp-hpux10.20 but not on 64-bit host/target.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-10-31 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.c (emit_move_sequence): Use cint_ok_for_move to check whether a
constant can be loaded in a single instruction to a register. When
loading immediate constants, use PLUS instead of HIGH/LO_SUM. Use
depdi for insertion of most significant 32-bits on 64-bit hosts.
* pa.h (LEGITIMATE_CONSTANT_P): Accept constants that can be built
with ldil/ldo/depdi instruction sequence on 64-bit hosts.
* pa.md: New addmove pattern for adding constant_int to HImode
register and moving result to HImode register. Remove HImode HIGH
and LO_SUM patterns.
--- pa.c.orig Sun Oct 28 16:24:36 2001
+++ pa.c Wed Oct 31 11:24:25 2001
@@ -1394,7 +1394,8 @@
else if (register_operand (operand0, mode))
{
if (register_operand (operand1, mode)
- || (GET_CODE (operand1) == CONST_INT && INT_14_BITS (operand1))
+ || (GET_CODE (operand1) == CONST_INT
+ && cint_ok_for_move (INTVAL (operand1)))
|| (operand1 == CONST0_RTX (mode))
|| (GET_CODE (operand1) == HIGH
&& !symbolic_operand (XEXP (operand1, 0), VOIDmode))
@@ -1596,8 +1597,8 @@
else if (GET_CODE (operand1) != CONST_INT
|| ! cint_ok_for_move (INTVAL (operand1)))
{
+ rtx extend = NULL_RTX;
rtx temp;
- int need_zero_extend = 0;
if (TARGET_64BIT && GET_CODE (operand1) == CONST_INT
&& HOST_BITS_PER_WIDE_INT > 32
@@ -1606,15 +1607,18 @@
HOST_WIDE_INT val = INTVAL (operand1);
HOST_WIDE_INT nval;
- /* If the value is the same after a 32->64bit sign
- extension, then we can use it as-is. Else we will
- need to sign extend the constant from 32->64bits
- then zero extend the result from 32->64bits. */
+ /* Extract the low order 32 bits of the value and sign extend.
+ If the new value is the same as the original value, we can
+ can use the original value as-is. If the new value is
+ different, we use it and insert the most-significant 32-bits
+ of the original value into the final result. */
nval = ((val & (((HOST_WIDE_INT) 2 << 31) - 1))
^ ((HOST_WIDE_INT) 1 << 31)) - ((HOST_WIDE_INT) 1 << 31);
if (val != nval)
{
- need_zero_extend = 1;
+#if HOST_BITS_PER_WIDE_INT > 32
+ extend = GEN_INT (val >> 32);
+#endif
operand1 = GEN_INT (nval);
}
}
@@ -1624,19 +1628,44 @@
else
temp = gen_reg_rtx (mode);
- emit_insn (gen_rtx_SET (VOIDmode, temp,
- gen_rtx_HIGH (mode, operand1)));
- operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
- emit_move_insn (operands[0], operands[1]);
+ if (GET_CODE (operand1) == CONST_INT)
+ {
+ /* Directly break constant into low and high parts. This
+ provides better optimization opportunities because various
+ passes recognize constants split with PLUS but not LO_SUM.
+ We use a 14-bit signed low part except when the addition
+ of 0x4000 to the high part might change the sign of the
+ high part. */
+ HOST_WIDE_INT value = INTVAL (operand1);
+ HOST_WIDE_INT low = value & 0x3fff;
+ HOST_WIDE_INT high = value & ~ 0x3fff;
+
+ if (low >= 0x2000)
+ {
+ if (high == 0x7fffc000 || (mode == HImode && high == 0x4000))
+ high += 0x2000;
+ else
+ high += 0x4000;
+ }
+
+ low = value - high;
- if (need_zero_extend)
+ emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (high)));
+ operands[1] = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+ }
+ else
{
- emit_insn (gen_zero_extendsidi2 (operands[0],
- gen_rtx_SUBREG (SImode,
- operands[0],
- 0)));
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_HIGH (mode, operand1)));
+ operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
}
+ emit_move_insn (operands[0], operands[1]);
+
+ if (extend != NULL_RTX)
+ emit_insn (gen_insv (operands[0], GEN_INT (32), const0_rtx,
+ extend));
+
return 1;
}
}
--- pa.h.orig Mon Sep 24 12:18:02 2001
+++ pa.h Tue Oct 30 10:33:39 2001
@@ -1106,8 +1106,8 @@
&& !(TARGET_64BIT && GET_CODE (X) == CONST_DOUBLE) \
&& !(TARGET_64BIT && GET_CODE (X) == CONST_INT \
&& !(HOST_BITS_PER_WIDE_INT <= 32 \
- || (INTVAL (X) >= (HOST_WIDE_INT) -1 << 31 \
- && INTVAL (X) < (HOST_WIDE_INT) 1 << 32) \
+ || (INTVAL (X) >= (HOST_WIDE_INT) -32 << 31 \
+ && INTVAL (X) < (HOST_WIDE_INT) 32 << 31) \
|| cint_ok_for_move (INTVAL (X)))) \
&& !function_label_operand (X, VOIDmode))
--- pa.md.orig Sat Jul 14 20:54:21 2001
+++ pa.md Fri Oct 26 16:03:12 2001
@@ -2604,19 +2604,12 @@
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
- (high:HI (match_operand 1 "const_int_operand" "")))]
+ (plus:HI (match_operand:HI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "J")))]
""
- "ldil L'%G1,%0"
- [(set_attr "type" "move")
- (set_attr "length" "4")])
-
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r")
- (lo_sum:HI (match_operand:HI 1 "register_operand" "r")
- (match_operand 2 "const_int_operand" "")))]
- ""
- "ldo R'%G2(%1),%0"
- [(set_attr "type" "move")
+ "ldo %2(%1),%0"
+ [(set_attr "type" "binary")
+ (set_attr "pa_combine_type" "addmove")
(set_attr "length" "4")])
(define_expand "movqi"
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA
2001-10-31 10:39 ` PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA John David Anglin
@ 2001-11-09 16:21 ` law
2001-11-13 5:27 ` law
2001-11-13 15:03 ` law
0 siblings, 2 replies; 521+ messages in thread
From: law @ 2001-11-09 16:21 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> > 2001-10-29 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * pa.c (emit_move_sequence): Use cint_ok_for_move to check whether a
> > constant can be loaded in a single instruction to a register. When
> > loading immediate constants, use PLUS instead of HIGH/LO_SUM. Handle
> > both zero and one extension of "32-bit" constants on 64-bit hosts.
> > * pa.h (LEGITIMATE_CONSTANT_P): Accept constants that can be built
> > with ldil/ldo/depdi instruction sequence on 64-bit hosts.
> > * pa.md: New addmove pattern for adding constant_int to HImode
> > register and moving result to HImode register. Remove HImode HIGH
> > and LO_SUM patterns.
>
> After thinking more about the above patch, I realized that it was trivial
> to extend the range of constants handled by 64-bits hosts compiling for
> TARGET_64BIT. This changes the previous patch to take advantage of the
> full im5 format used for immediates by the depdi instruction. Checked
> on hppa1.1-hp-hpux10.20 but not on 64-bit host/target.
This seems to be working fine for PA64 too. I went ahead and installed it.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA
2001-11-09 16:21 ` law
@ 2001-11-13 5:27 ` law
2001-11-13 15:03 ` law
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2001-11-13 5:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> > 2001-10-29 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * pa.c (emit_move_sequence): Use cint_ok_for_move to check whether a
> > constant can be loaded in a single instruction to a register. When
> > loading immediate constants, use PLUS instead of HIGH/LO_SUM. Handle
> > both zero and one extension of "32-bit" constants on 64-bit hosts.
> > * pa.h (LEGITIMATE_CONSTANT_P): Accept constants that can be built
> > with ldil/ldo/depdi instruction sequence on 64-bit hosts.
> > * pa.md: New addmove pattern for adding constant_int to HImode
> > register and moving result to HImode register. Remove HImode HIGH
> > and LO_SUM patterns.
>
> After thinking more about the above patch, I realized that it was trivial
> to extend the range of constants handled by 64-bits hosts compiling for
> TARGET_64BIT. This changes the previous patch to take advantage of the
> full im5 format used for immediates by the depdi instruction. Checked
> on hppa1.1-hp-hpux10.20 but not on 64-bit host/target.
This seems to be working fine for PA64 too. I went ahead and installed it.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA
2001-11-09 16:21 ` law
2001-11-13 5:27 ` law
@ 2001-11-13 15:03 ` law
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2001-11-13 15:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> > 2001-10-29 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * pa.c (emit_move_sequence): Use cint_ok_for_move to check whether a
> > constant can be loaded in a single instruction to a register. When
> > loading immediate constants, use PLUS instead of HIGH/LO_SUM. Handle
> > both zero and one extension of "32-bit" constants on 64-bit hosts.
> > * pa.h (LEGITIMATE_CONSTANT_P): Accept constants that can be built
> > with ldil/ldo/depdi instruction sequence on 64-bit hosts.
> > * pa.md: New addmove pattern for adding constant_int to HImode
> > register and moving result to HImode register. Remove HImode HIGH
> > and LO_SUM patterns.
>
> After thinking more about the above patch, I realized that it was trivial
> to extend the range of constants handled by 64-bits hosts compiling for
> TARGET_64BIT. This changes the previous patch to take advantage of the
> full im5 format used for immediates by the depdi instruction. Checked
> on hppa1.1-hp-hpux10.20 but not on 64-bit host/target.
This seems to be working fine for PA64 too. I went ahead and installed it.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Last alignment change for MEM tracking
[not found] <no.id>
` (57 preceding siblings ...)
2001-10-31 10:39 ` PATCH: Use PLUS instead of HIGH/LO_SUM for large constants - take 2 for PA John David Anglin
@ 2001-11-13 15:03 ` John David Anglin
2001-11-21 16:04 ` C++ pcc struct return fix John David Anglin
` (104 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-11-13 15:03 UTC (permalink / raw)
To: John David Anglin; +Cc: kenner, gcc-patches
> Can I just add the definition for "Zero_Cost_Exceptions" to "system.ads" in
> the gcc directory from the installed system.ads?
>
> Zero_Cost_Exceptions : constant Boolean := False;
This gets me a little further:
gcc -c -g -mdisable-indexing -W -Wall -gnatpg -gnata -I- -I. -I../../../gcc/ad
a ../../../gcc/ada/atree.adb
atree.adb:36:01: warning: unrecognized pragma "Style_Checks"
make[3]: *** [atree.o] Error 1
Do I need to update the installed ada to 3.13p first? This looks more like
an error than a warning.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
[not found] <no.id>
` (58 preceding siblings ...)
2001-11-13 15:03 ` Last alignment change for MEM tracking John David Anglin
@ 2001-11-21 16:04 ` John David Anglin
2001-11-30 19:36 ` John David Anglin
2001-12-03 2:52 ` Jason Merrill
2001-12-01 11:48 ` HPUX 11 "size_t" fixinc problems John David Anglin
` (103 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-11-21 16:04 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
> --- semantics.c.orig Wed Apr 18 13:51:48 2001
> +++ semantics.c Wed Apr 18 18:16:58 2001
Oops, forgot description:
2001-11-30 John David Anglin <dave@hiauly1.hia.nrc.ca>
* semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
call to build_aggr_init.
--- semantics.c.orig Wed Apr 18 13:51:48 2001
+++ semantics.c Wed Apr 18 18:16:58 2001
@@ -2240,7 +2240,8 @@
int old_ac = flag_access_control;
flag_access_control = 0;
- call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+ call_expr = build_aggr_init (slot, call_expr,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-11-21 16:04 ` C++ pcc struct return fix John David Anglin
@ 2001-11-30 19:36 ` John David Anglin
2001-12-03 2:52 ` Jason Merrill
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-11-30 19:36 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
> --- semantics.c.orig Wed Apr 18 13:51:48 2001
> +++ semantics.c Wed Apr 18 18:16:58 2001
Oops, forgot description:
2001-11-30 John David Anglin <dave@hiauly1.hia.nrc.ca>
* semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
call to build_aggr_init.
--- semantics.c.orig Wed Apr 18 13:51:48 2001
+++ semantics.c Wed Apr 18 18:16:58 2001
@@ -2240,7 +2240,8 @@
int old_ac = flag_access_control;
flag_access_control = 0;
- call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+ call_expr = build_aggr_init (slot, call_expr,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-11-21 16:04 ` C++ pcc struct return fix John David Anglin
2001-11-30 19:36 ` John David Anglin
@ 2001-12-03 2:52 ` Jason Merrill
2001-12-03 8:40 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jason Merrill @ 2001-12-03 2:52 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
> * semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
> call to build_aggr_init.
DIRECT_BIND is for binding temporaries to reference variables; I'm not sure
why this would have any effect on your problem. Perhaps rather than call
build_aggr_init here, we should be doing an explicit constructor call as in
ocp_convert.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 2:52 ` Jason Merrill
@ 2001-12-03 8:40 ` John David Anglin
2001-12-03 8:52 ` Mark Mitchell
2001-12-03 10:41 ` Jason Merrill
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-03 8:40 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, mark
> >>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>
> > * semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
> > call to build_aggr_init.
>
> DIRECT_BIND is for binding temporaries to reference variables; I'm not sure
> why this would have any effect on your problem. Perhaps rather than call
> build_aggr_init here, we should be doing an explicit constructor call as in
> ocp_convert.
It is a while since I looked at this problem but roughly what happens is
that build_aggr_init calls ocp_convert which calls simplify_aggr_init_exprs_r
which calls build_aggr_init which calls ... Look at expand_default_init.
I think this is why DIRECT_BIND has an affect.
I do know that the code generated for function returning a struct seemed
reasonable when DIRECT_BIND was added to the flags in the call.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 8:40 ` John David Anglin
@ 2001-12-03 8:52 ` Mark Mitchell
2001-12-03 15:19 ` John David Anglin
2001-12-03 10:41 ` Jason Merrill
1 sibling, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2001-12-03 8:52 UTC (permalink / raw)
To: John David Anglin, Jason Merrill; +Cc: gcc-patches
--On Monday, December 03, 2001 11:40:08 AM -0500 John David Anglin
<dave@hiauly1.hia.nrc.ca> wrote:
>> >>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>>
>> > * semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
>> > call to build_aggr_init.
>>
>> DIRECT_BIND is for binding temporaries to reference variables; I'm not
>> sure why this would have any effect on your problem. Perhaps rather
>> than call build_aggr_init here, we should be doing an explicit
>> constructor call as in ocp_convert.
Since this patch only affects PCC platforms, and since there are so few,
this patch is OK with me for 3.0.3 if Jason becomes convinced.
A test case would probably help.
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 8:52 ` Mark Mitchell
@ 2001-12-03 15:19 ` John David Anglin
2001-12-07 11:30 ` Mark Mitchell
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-12-03 15:19 UTC (permalink / raw)
To: Mark Mitchell; +Cc: jason, gcc-patches
> A test case would probably help.
What about this? It's "obviously" a good test because it FAILs on
hppa2.0w-hp-hpux11.11 with the current mainline. On the PA with main,
struct blah function foo are missing in the assembler output for some
reason. It passes on the PA with 3.0.2.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* g++.dg/init/struct-ret1.C: New file.
// { dg-do run }
struct blah { int a[6]; };
inline struct blah foo()
{
struct blah r = { { 12, 24, 36, 48, 60, 72 } };
return r;
}
int
main()
{
struct blah x = foo();
if (x.a[0] != 12 || x.a[1] != 24 || x.a[2] != 36 || x.a[3] != 48
|| x.a[4] != 60 || x.a[5] != 72)
return 1;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 15:19 ` John David Anglin
@ 2001-12-07 11:30 ` Mark Mitchell
2001-12-07 20:55 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2001-12-07 11:30 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, gcc-patches
--On Monday, December 03, 2001 06:19:10 PM -0500 John David Anglin
<dave@hiauly1.hia.nrc.ca> wrote:
>> A test case would probably help.
>
> What about this? It's "obviously" a good test because it FAILs on
> hppa2.0w-hp-hpux11.11 with the current mainline. On the PA with main,
> struct blah function foo are missing in the assembler output for some
> reason. It passes on the PA with 3.0.2.
Good.
Did we ever reach resolution on this issue?
In particular, did we get a patch approved for the mainline? For
the 3.0 branch? Is there a patch that needs review, but that hasn't
been reviewed? (If so, send it to me, and I will review it.)
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-07 11:30 ` Mark Mitchell
@ 2001-12-07 20:55 ` John David Anglin
2001-12-08 3:04 ` Jason Merrill
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-12-07 20:55 UTC (permalink / raw)
To: Mark Mitchell; +Cc: jason, gcc-patches
> Did we ever reach resolution on this issue?
No.
> In particular, did we get a patch approved for the mainline? For
> the 3.0 branch? Is there a patch that needs review, but that hasn't
> been reviewed? (If so, send it to me, and I will review it.)
Jason approved the patch to semantics.c but asked that the comment
about DIRECT_BIND in cp-tree.h reflect this usage. So, I sent this
update.
<http://gcc.gnu.org/ml/gcc-patches/2001-12/msg00209.html>,
Is this OK? Jason didn't say anything about the branch in his response.
Personally, the reason that I would like this on the branch is that
it takes about half the memory to build as the main, and thus is
better suited to machines with small amounts of memory. However,
getting it in 3.0.3 isn't an urgent priority, particularly if a
3.0.4 is planned.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-07 20:55 ` John David Anglin
@ 2001-12-08 3:04 ` Jason Merrill
2001-12-08 9:12 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jason Merrill @ 2001-12-08 3:04 UTC (permalink / raw)
To: John David Anglin; +Cc: Mark Mitchell, gcc-patches
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>> Did we ever reach resolution on this issue?
> No.
>> In particular, did we get a patch approved for the mainline? For
>> the 3.0 branch? Is there a patch that needs review, but that hasn't
>> been reviewed? (If so, send it to me, and I will review it.)
> Jason approved the patch to semantics.c but asked that the comment
> about DIRECT_BIND in cp-tree.h reflect this usage. So, I sent this
> update.
> <http://gcc.gnu.org/ml/gcc-patches/2001-12/msg00209.html>,
I would say "It also forces direct-initialization in cases where other
parts of the compiler have already generated a temporary, such as reference
initialization and the catch parameter."
Thanks.
> Is this OK? Jason didn't say anything about the branch in his response.
It's also OK for the branch.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-08 3:04 ` Jason Merrill
@ 2001-12-08 9:12 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-08 9:12 UTC (permalink / raw)
To: Jason Merrill; +Cc: mark, gcc-patches
> >>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>
> >> Did we ever reach resolution on this issue?
> > No.
The only issue remaining in this thread is the testcase. Is this OK for
the main? There is no change in the test from what I sent previously.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-08 John David Anglin <dave@hiauly1.hia.nrc.ca>
* g++.dg/init/struct-ret1.C: New file.
--- /dev/null Sat Dec 8 11:40:02 2001
+++ g++.dg/init/struct-ret1.C Tue Dec 4 14:15:38 2001
@@ -0,0 +1,19 @@
+// { dg-do run }
+
+struct blah { int a[6]; };
+
+inline struct blah foo()
+{
+ struct blah r = { { 12, 24, 36, 48, 60, 72 } };
+ return r;
+}
+
+int
+main()
+{
+ struct blah x = foo();
+
+ if (x.a[0] != 12 || x.a[1] != 24 || x.a[2] != 36 || x.a[3] != 48
+ || x.a[4] != 60 || x.a[5] != 72)
+ return 1;
+}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 8:40 ` John David Anglin
2001-12-03 8:52 ` Mark Mitchell
@ 2001-12-03 10:41 ` Jason Merrill
2001-12-03 11:54 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jason Merrill @ 2001-12-03 10:41 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>> >>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>>
>> > * semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
>> > call to build_aggr_init.
>>
>> DIRECT_BIND is for binding temporaries to reference variables; I'm not sure
>> why this would have any effect on your problem. Perhaps rather than call
>> build_aggr_init here, we should be doing an explicit constructor call as in
>> ocp_convert.
> It is a while since I looked at this problem but roughly what happens is
> that build_aggr_init calls ocp_convert which calls simplify_aggr_init_exprs_r
> which calls build_aggr_init which calls ... Look at expand_default_init.
> I think this is why DIRECT_BIND has an affect.
OK, it looks like initialize_handler_parm is already using DIRECT_BIND this
way, so it's just a documentation issue. This patch is OK for trunk and
branch; please also adjust the comment about DIRECT_BIND in cp-tree.h to
reflect this usage.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ pcc struct return fix
2001-12-03 10:41 ` Jason Merrill
@ 2001-12-03 11:54 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-03 11:54 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, mark
> OK, it looks like initialize_handler_parm is already using DIRECT_BIND this
> way, so it's just a documentation issue. This patch is OK for trunk and
> branch; please also adjust the comment about DIRECT_BIND in cp-tree.h to
> reflect this usage.
How does this look?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* semantics.c (simplify_aggr_init_exprs_r): Add DIRECT_BIND flag in
call to build_aggr_init.
* cp-tree.h (DIRECT_BIND): Document new use of DIRECT_BIND.
--- semantics.c.orig Wed Apr 18 13:51:48 2001
+++ semantics.c Wed Apr 18 18:16:58 2001
@@ -2240,7 +2240,8 @@
int old_ac = flag_access_control;
flag_access_control = 0;
- call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+ call_expr = build_aggr_init (slot, call_expr,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
--- cp-tree.h.save Mon Dec 3 13:26:15 2001
+++ cp-tree.h Mon Dec 3 14:01:31 2001
@@ -3309,7 +3309,9 @@
LOOKUP_ONLYCONVERTING means that non-conversion constructors are not tried.
DIRECT_BIND means that if a temporary is created, it should be created so
that it lives as long as the current variable bindings; otherwise it
- only lives until the end of the complete-expression.
+ only lives until the end of the complete-expression. It indicates in
+ reference initialization and in catching an exception that we don't
+ need a new constructor.
LOOKUP_SPECULATIVELY means return NULL_TREE if we cannot find what we are
after. Note, LOOKUP_COMPLAIN is checked and error messages printed
before LOOKUP_SPECULATIVELY is checked.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HPUX 11 "size_t" fixinc problems
[not found] <no.id>
` (59 preceding siblings ...)
2001-11-21 16:04 ` C++ pcc struct return fix John David Anglin
@ 2001-12-01 11:48 ` John David Anglin
2001-12-03 10:37 ` Bruce Korb
2001-12-03 14:20 ` Unreviewed C++ patch for PA (HP assembler) John David Anglin
` (102 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2001-12-01 11:48 UTC (permalink / raw)
To: John David Anglin; +Cc: bkorb, dave.anglin, gcc-patches
> > I guess the ``__va__list'' will protect my system.
>
> An underscore could be added before "size_t" in the select for additional
> protection.
I have run this through complete bootstraps and checks on hppa2.0w-hp-hpux11.00
and hppa2.0w-hp-hpux11.11 with no regressions.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-01 John David Anglin <dave@hiauly1.hia.nrc.ca>
* inclhack.def (AAA_time): Delete.
(hpux_size_t): Revise select and fix for HP-UX 11.11.
(hpux11_vsnprintf): Likewise.
--- inclhack.def.orig Thu Sep 13 12:05:12 2001
+++ inclhack.def Fri Nov 30 15:53:00 2001
@@ -94,16 +94,6 @@
};
-/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_time;
- files = sys/time.h;
- select = '11.0 and later representation of ki time';
- replace; /* empty replacement -> no fixing the file */
-};
-
/* And now, the real fixes, replacement text fixes first: */
/*
@@ -1222,12 +1212,11 @@
*/
fix = {
hackname = hpux11_size_t;
- mach = "*-hp-hpux*";
- select = "^#define __size_t size_t";
+ mach = "*-hp-hpux11*";
+ select = "__size_t";
c_fix = format;
c_fix_arg = "_hpux_size_t";
- c_fix_arg = "__size_t";
test_text =
"#define __size_t size_t\n"
@@ -1264,17 +1253,17 @@
/*
- * Fix hpux 11.00 broken vsnprintf declaration
+ * Fix hpux 11.00 broken vsnprintf declaration.
*/
fix = {
hackname = hpux11_vsnprintf;
files = stdio.h;
- select = 'extern int vsnprintf\(char \*, __size_t, const char \*,'
+ select = 'extern int vsnprintf\(char \*, .*_size_t, const char \*,'
' __va__list\);';
c_fix = format;
- c_fix_arg = "extern int vsnprintf(char *, __size_t, const char *,"
- " __va_list);";
+ c_fix_arg = __va_list;
+ c_fix_arg = __va__list;
test_text = 'extern int vsnprintf(char *, __size_t, const char *,'
' __va__list);';
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HPUX 11 "size_t" fixinc problems
2001-12-01 11:48 ` HPUX 11 "size_t" fixinc problems John David Anglin
@ 2001-12-03 10:37 ` Bruce Korb
2001-12-17 12:39 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Bruce Korb @ 2001-12-03 10:37 UTC (permalink / raw)
To: John David Anglin; +Cc: dave.anglin, gcc-patches, gcc
John David Anglin wrote:
> I have run this through complete bootstraps and checks on hppa2.0w-hp-hpux11.00
> and hppa2.0w-hp-hpux11.11 with no regressions.
>
> Dave
> --- inclhack.def.orig Thu Sep 13 12:05:12 2001
> +++ inclhack.def Fri Nov 30 15:53:00 2001
> @@ -94,16 +94,6 @@
> };
>
>
> -/*
> - * Purge some HP-UX 11 files that are only broken after they are "fixed".
> - */
> -fix = {
> - hackname = AAA_time;
> - files = sys/time.h;
> - select = '11.0 and later representation of ki time';
> - replace; /* empty replacement -> no fixing the file */
> -};
> -
> /* And now, the real fixes, replacement text fixes first: */
Hi Dave,
Excellent. I applied this to the 3.0 branch before Friday's freeze.
I intend to apply a slightly different one to the main line,
barring complaints. On the theory that all of the "empty replacement"
fixes are really fixes for the broken fixincludes script, my
_guess_ is that they are not needed any more because my version
doesn't make mistakes. ;-)
Therefore, it is my intention to remove all the empty replacement
non-fixes and wait to see what problems arise. (I don't have
enough of a variety of systems to do it any other way.) So, I
have also posted this to the GCC list.
SO EVERYONE BE ADVISED: I am removing the protection many headers
used to have against mis-fixes from fixincludes. I will put them
back only if the fixincl program cannot be fixed itself.
Um, just to be clear: mainline only, not 3.0 branch.
Cheers,
Bruce
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HPUX 11 "size_t" fixinc problems
2001-12-03 10:37 ` Bruce Korb
@ 2001-12-17 12:39 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-17 12:39 UTC (permalink / raw)
To: Bruce Korb; +Cc: dave.anglin, gcc-patches, gcc
> Excellent. I applied this to the 3.0 branch before Friday's freeze.
> I intend to apply a slightly different one to the main line,
> barring complaints. On the theory that all of the "empty replacement"
> fixes are really fixes for the broken fixincludes script, my
> _guess_ is that they are not needed any more because my version
> doesn't make mistakes. ;-)
I have tested the following under hpux 11.00 and 11.11. No fixes were
applied to any of the sys/ki*.h headers in either case. So, I am happy
with the removal of the the AAA_ki* fixes on the main.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-17 John David Anglin <dave@hiauly1.hia.nrc.ca>
* inclhack.def (AAA_ki, AAA_ki_calls, AAA_ki_defs, AAA_ki_iface,
AAA_time): Delete.
(hpux_size_t): Revise select and fix for HP-UX 11.11.
(hpux11_vsnprintf): Likewise.
--- inclhack.def.orig Thu Dec 6 21:55:49 2001
+++ inclhack.def Sun Dec 16 12:51:08 2001
@@ -39,50 +39,6 @@
/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_ki;
- files = sys/ki.h;
- select = '11.00 HP-UX LP64';
- replace; /* empty replacement -> no fixing the file */
-};
-
-
-/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_ki_calls;
- files = sys/ki_calls.h;
- select = 'kthread_create_caller_t';
- replace; /* empty replacement -> no fixing the file */
-};
-
-
-/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_ki_defs;
- files = sys/ki_defs.h;
- select = 'Kernel Instrumentation Definitions';
- replace; /* empty replacement -> no fixing the file */
-};
-
-
-/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_ki_iface;
- files = sys/ki_iface.h;
- select = 'These definitions are for HP Internal developers';
- replace; /* empty replacement -> no fixing the file */
-};
-
-
-/*
* Tru64 UNIX V4.0F/V5.1 <standards.h> defines _NO_PROTO and _NONSTD_TYPES
* correctly for GCC, but strict_ansi_not breaks it.
*/
@@ -94,16 +50,6 @@
};
-/*
- * Purge some HP-UX 11 files that are only broken after they are "fixed".
- */
-fix = {
- hackname = AAA_time;
- files = sys/time.h;
- select = '11.0 and later representation of ki time';
- replace; /* empty replacement -> no fixing the file */
-};
-
/* And now, the real fixes, replacement text fixes first: */
/*
@@ -1222,12 +1168,11 @@
*/
fix = {
hackname = hpux11_size_t;
- mach = "*-hp-hpux*";
- select = "^#define __size_t size_t";
+ mach = "*-hp-hpux11*";
+ select = "__size_t";
c_fix = format;
c_fix_arg = "_hpux_size_t";
- c_fix_arg = "__size_t";
test_text =
"#define __size_t size_t\n"
@@ -1264,17 +1209,17 @@
/*
- * Fix hpux 11.00 broken vsnprintf declaration
+ * Fix hpux 11.00 broken vsnprintf declaration.
*/
fix = {
hackname = hpux11_vsnprintf;
files = stdio.h;
- select = 'extern int vsnprintf\(char \*, __size_t, const char \*,'
+ select = 'extern int vsnprintf\(char \*, .*_size_t, const char \*,'
' __va__list\);';
c_fix = format;
- c_fix_arg = "extern int vsnprintf(char *, __size_t, const char *,"
- " __va_list);";
+ c_fix_arg = __va_list;
+ c_fix_arg = __va__list;
test_text = 'extern int vsnprintf(char *, __size_t, const char *,'
' __va__list);';
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
[not found] <no.id>
` (60 preceding siblings ...)
2001-12-01 11:48 ` HPUX 11 "size_t" fixinc problems John David Anglin
@ 2001-12-03 14:20 ` John David Anglin
2001-12-03 14:49 ` Benjamin Kosnik
2001-12-04 8:25 ` Jason Merrill
2001-12-09 14:55 ` PATCH: Check all insns in fallthru to see if label is mentioned John David Anglin
` (101 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-03 14:20 UTC (permalink / raw)
To: John David Anglin; +Cc: jason, gcc-patches, mark, libstdc++
> > 2001-12-03 Jason Merrill <jason@redhat.com>
> >
> > * rtti.c (create_pseudo_type_info): Set CLASSTYPE_INTERFACE_ONLY
> > on the __*_type_info type if we haven't seen a definition.
>
> Yes, it does. The libstdc++ test results with the HP assembler appear
> identical to that obtained with the GNU assembler. I should have g++
> results in an hour or so.
The difference between the g++ testsuite results with the gnu and HP
assemblers is now much less than when I first looked at it a few months
ago. There are now only two additional FAILs with the HP assembler:
Executing on host: /xxx/gnu/gcc-3.1/objdir/gcc/testsuite/../g++ -B/xxx/gnu/gcc-3.1/objdir/gcc/testsuite/../ -nostdinc++ -I/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11/libstdc++-v3/include/hppa2.0w-hp-hpux11.11 -I/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11/libstdc++-v3/include -I/xxx/gnu/gcc-3.1/libstdc++-v3/libsupc++ -I/xxx/gnu/gcc-3.1/libstdc++-v3/libio -I/xxx/gnu/gcc-3.1/libstdc++-v3/include/backward -I/xxx/gnu/gcc-3.1/libstdc++-v3/testsuite -fmessage-length=0 -ansi -pedantic-errors -Wno-long-long -c -o /xxx/gnu/gcc-3.1/objdir/gcc/testsuite/union1.o /xxx/gnu/gcc-3.1/gcc/testsuite/g++.old-deja/g++.brendan/union1.C (timeout = 300)
as: error 7403: undefined label - _ZZ4hashdE5asint (7403)
compiler exited with status 1
output is:
as: error 7403: undefined label - _ZZ4hashdE5asint (7403)
Executing on host: /xxx/gnu/gcc-3.1/objdir/gcc/testsuite/../g++ -B/xxx/gnu/gcc-3.1/objdir/gcc/testsuite/../ /xxx/gnu/gcc-3.1/gcc/testsuite/g++.old-deja/g++.jason/template31.C -nostdinc++ -I/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11/libstdc++-v3/include/hppa2.0w-hp-hpux11.11 -I/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11/libstdc++-v3/include -I/xxx/gnu/gcc-3.1/libstdc++-v3/libsupc++ -I/xxx/gnu/gcc-3.1/libstdc++-v3/libio -I/xxx/gnu/gcc-3.1/libstdc++-v3/include/backward -I/xxx/gnu/gcc-3.1/libstdc++-v3/testsuite -fmessage-length=0 -ansi -pedantic-errors -Wno-long-long -L/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs -L/xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libiberty -lstdc++ -lm -o /xxx/gnu/gcc-3.1/objdir/gcc/testsuite/g++-jason-template31-C.exe (timeout = 300)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__malloc_alloc_oom_handler" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::_S_oom_malloc(unsigned long)" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::_S_oom_realloc(void*, unsigned long)" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::allocate(unsigned long)" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::deallocate(void*, unsigned long)" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::reallocate(void*, unsigned long, unsigned long)" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__set_malloc_handler(void (*)())" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
/usr/ccs/bin/ld: Found 7 duplicate symbol(s)
collect2: ld returned 1 exit status
Possibly, the smaller difference is because libtool didn't think it
could build shared libraries on the test system:
checking if libtool supports shared libraries... no
checking whether to build shared libraries... no
I'll have to figure out why libtool didn't build a shared libstdc++.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-03 14:20 ` Unreviewed C++ patch for PA (HP assembler) John David Anglin
@ 2001-12-03 14:49 ` Benjamin Kosnik
2001-12-04 8:25 ` Jason Merrill
1 sibling, 0 replies; 521+ messages in thread
From: Benjamin Kosnik @ 2001-12-03 14:49 UTC (permalink / raw)
To: John David Anglin; +Cc: John David Anglin, jason, gcc-patches, mark, libstdc++
John can you try this please?
2001-12-03 Benjamin Kosnik <bkoz@redhat.com>
* src/string-inst.cc: Add static data member instantiations.
Index: src/string-inst.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/src/string-inst.cc,v
retrieving revision 1.19
diff -c -p -r1.19 string-inst.cc
*** string-inst.cc 2001/10/31 08:27:20 1.19
--- string-inst.cc 2001/12/03 22:48:06
*************** namespace std
*** 46,51 ****
--- 46,52 ----
typedef basic_string<C> S;
template class basic_string<C>;
+ template const C S::_Rep::_S_terminal;
template S::size_type S::_Rep::_S_max_size;
template S operator+(const C*, const S&)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-03 14:20 ` Unreviewed C++ patch for PA (HP assembler) John David Anglin
2001-12-03 14:49 ` Benjamin Kosnik
@ 2001-12-04 8:25 ` Jason Merrill
2001-12-04 9:18 ` John David Anglin
2001-12-08 9:29 ` John David Anglin
1 sibling, 2 replies; 521+ messages in thread
From: Jason Merrill @ 2001-12-04 8:25 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark, libstdc++
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
> The difference between the g++ testsuite results with the gnu and HP
> assemblers is now much less than when I first looked at it a few months
> ago. There are now only two additional FAILs with the HP assembler:
> g++.brendan/union1.C
> as: error 7403: undefined label - _ZZ4hashdE5asint (7403)
Hmm, this is a target-independent bug that is only caught on the PA because
of assembler pedanticism. I'll make the test linkable so the failure shows
up on other targets, too.
> g++.jason/template31.C
> /usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__malloc_alloc_oom_handler" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
Try removing the explicit instantiations from the testcase.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-04 8:25 ` Jason Merrill
@ 2001-12-04 9:18 ` John David Anglin
2001-12-08 9:29 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-04 9:18 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, mark, libstdc++
> > g++.jason/template31.C
> > /usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__malloc_alloc_oom_handler" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
>
> Try removing the explicit instantiations from the testcase.
That does the trick.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* g++.old-deja/g++.jason/template31.C: Remove template for class
std::__malloc_alloc_template<0>.
--- template31.C.orig Wed Jul 25 08:06:20 2001
+++ template31.C Tue Dec 4 12:03:43 2001
@@ -37,7 +37,6 @@
std::exit(0);
}
-template class std::__malloc_alloc_template<0>;
#ifndef __USE_MALLOC
template class std::__default_alloc_template<false, 0>;
#endif
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-04 8:25 ` Jason Merrill
2001-12-04 9:18 ` John David Anglin
@ 2001-12-08 9:29 ` John David Anglin
2001-12-09 19:25 ` Jason Merrill
2001-12-09 19:27 ` Phil Edwards
1 sibling, 2 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-08 9:29 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, mark, libstdc++
> > g++.jason/template31.C
> > /usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__malloc_alloc_oom_handler" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
>
> Try removing the explicit instantiations from the testcase.
Is this revision OK for the main? It fixes the problem on hppa2.0w-hp-hpux11.11
with the HP assembler.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2001-12-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* g++.old-deja/g++.jason/template31.C: Remove template for class
std::__malloc_alloc_template<0>.
--- template31.C.orig Wed Jul 25 08:06:20 2001
+++ template31.C Tue Dec 4 12:03:43 2001
@@ -37,7 +37,6 @@
std::exit(0);
}
-template class std::__malloc_alloc_template<0>;
#ifndef __USE_MALLOC
template class std::__default_alloc_template<false, 0>;
#endif
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-08 9:29 ` John David Anglin
@ 2001-12-09 19:25 ` Jason Merrill
2001-12-09 19:27 ` Phil Edwards
1 sibling, 0 replies; 521+ messages in thread
From: Jason Merrill @ 2001-12-09 19:25 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark, libstdc++
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
> -template class std::__malloc_alloc_template<0>;
> #ifndef __USE_MALLOC
> template class std::__default_alloc_template<false, 0>;
> #endif
I'd remove the other explicit instantiation, too. If that doesn't break
things for you, go ahead and check it in on the trunk.
Jason
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed C++ patch for PA (HP assembler)
2001-12-08 9:29 ` John David Anglin
2001-12-09 19:25 ` Jason Merrill
@ 2001-12-09 19:27 ` Phil Edwards
1 sibling, 0 replies; 521+ messages in thread
From: Phil Edwards @ 2001-12-09 19:27 UTC (permalink / raw)
To: John David Anglin; +Cc: Jason Merrill, gcc-patches, mark, libstdc++
On Sat, Dec 08, 2001 at 12:28:02PM -0500, John David Anglin wrote:
> > > g++.jason/template31.C
> > > /usr/ccs/bin/ld: Duplicate symbol "std::__malloc_alloc_template<0>::__malloc_alloc_oom_handler" in files /var/tmp//cc8IHMur.o and /xxx/gnu/gcc-3.1/objdir/hppa2.0w-hp-hpux11.11//libstdc++-v3/src/.libs/libstdc++.a(stl-inst.o)
> >
> > Try removing the explicit instantiations from the testcase.
>
> Is this revision OK for the main? It fixes the problem on hppa2.0w-hp-hpux11.11
> with the HP assembler.
This should be okay; we need to be testing library instantiations in the
library testsuite anyhow, rather than in the compiler testsuite. (I have
a larval-stage testcase for allocators, but we need to finish deciding
what to do with allocator design first, before any of it will be of use.)
Jason or Mark will need to approve the change.
Phil
--
If ye love wealth greater than liberty, the tranquility of servitude greater
than the animating contest for freedom, go home and leave us in peace. We seek
not your counsel, nor your arms. Crouch down and lick the hand that feeds you;
and may posterity forget that ye were our countrymen. - Samuel Adams
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Check all insns in fallthru to see if label is mentioned
[not found] <no.id>
` (61 preceding siblings ...)
2001-12-03 14:20 ` Unreviewed C++ patch for PA (HP assembler) John David Anglin
@ 2001-12-09 14:55 ` John David Anglin
2002-01-08 20:57 ` fix aix -fcprop-register miscompilation John David Anglin
` (100 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2001-12-09 14:55 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches, hiller
> There might be two regressions:
>
> FAIL: gcc.c-torture/execute/strct-pack-1.c execution, -O2
> FAIL: gcc.c-torture/execute/strct-pack-1.c execution, -Os
>
> These started failing in execution at some point after Dec. 1. It will
> be a few days before I can examine these in more detail.
It is my guess that these failures are due to the "enhanced structure
offset tracking" patch.
In the -O2 assembler output, we have
ldi 1,%r20
.stabn 68,0,20,L$M7-main
L$M7:
ldw -120(%r30),%r21
<manipulation of r21 deleted>
sth %r20,-120(%r30)
.stabn 68,0,20,L$M11-main
L$M11:
stw %r22,-112(%r30)
stw %r21,-120(%r30)
The halfword store of r20 gets moved downward, after the load of r21.
This occurs in the ce2 pass.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix aix -fcprop-register miscompilation
[not found] <no.id>
` (62 preceding siblings ...)
2001-12-09 14:55 ` PATCH: Check all insns in fallthru to see if label is mentioned John David Anglin
@ 2002-01-08 20:57 ` John David Anglin
2002-01-10 9:33 ` PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix) John David Anglin
` (99 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-01-08 20:57 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches
> > * regrename.c (copy_value): Ignore overlapping copies.
>
> This seems to fix 950704-1.c at -O1. I will have the complete test results
Bootstrapped and checked. Test results with the above patch are identical
to those from yesterday.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix)
[not found] <no.id>
` (63 preceding siblings ...)
2002-01-08 20:57 ` fix aix -fcprop-register miscompilation John David Anglin
@ 2002-01-10 9:33 ` John David Anglin
2002-01-10 16:38 ` John David Anglin
2002-01-15 15:35 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 John David Anglin
` (98 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-10 9:33 UTC (permalink / raw)
To: John David Anglin; +Cc: rittle, gcc-patches, toon
> No, I don't think this is it. I have looked at the preprocessed output
> from backspace.c. There isn't a prototype at all for fseeko in the
> output. This appears to be because _LARGEFILE_SOURCE is not defined.
I added a define for _LARGEFILE_SOURCE in libI77/config.h. Rebuilding
the library and rerunning the g77 testsuite, I find that this fixes the
io0.f, io1.f and u77-test.f FAILS. This only leaves the FAIL of
20001201.f on hppa2.0w-hp-hpux11.11.
Toon, do you want me to try and fix configure to provide this define
when necessary?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix)
2002-01-10 9:33 ` PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix) John David Anglin
@ 2002-01-10 16:38 ` John David Anglin
2002-01-14 15:33 ` Toon Moene
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-10 16:38 UTC (permalink / raw)
To: John David Anglin; +Cc: rittle, gcc-patches, toon
> > No, I don't think this is it. I have looked at the preprocessed output
> > from backspace.c. There isn't a prototype at all for fseeko in the
> > output. This appears to be because _LARGEFILE_SOURCE is not defined.
>
> I added a define for _LARGEFILE_SOURCE in libI77/config.h. Rebuilding
> the library and rerunning the g77 testsuite, I find that this fixes the
> io0.f, io1.f and u77-test.f FAILS. This only leaves the FAIL of
> 20001201.f on hppa2.0w-hp-hpux11.11.
Here is a patch. Fixes the above with no regressions. Toon would
you apply if ok so that configure and config.in are rebuilt with your
favorite versions of autoconf and autoheader?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-10 John David Anglin <dave@hiauly1.hia.nrc.ca>
* libI77/configure.in (_LARGEFILE_SOURCE): AC_DEFINE.
* libI77/configure: Rebuilt.
* libI77/config.h.in: Rebuilt.
--- libI77/configure.in.orig Sun Sep 30 18:06:22 2001
+++ libI77/configure.in Thu Jan 10 14:40:28 2002
@@ -31,6 +31,7 @@
# The following is needed by Solaris2.5.1 so that struct timeval is declared.
AC_DEFINE(__EXTENSIONS__, 1, [Solaris extensions])
AC_DEFINE(_FILE_OFFSET_BITS, 64, [Get 64-bit file size support])
+AC_DEFINE(_LARGEFILE_SOURCE, 1, [Define for HP-UX ftello and fseeko extension.])
dnl Checks for programs.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix)
2002-01-10 16:38 ` John David Anglin
@ 2002-01-14 15:33 ` Toon Moene
0 siblings, 0 replies; 521+ messages in thread
From: Toon Moene @ 2002-01-14 15:33 UTC (permalink / raw)
To: John David Anglin; +Cc: rittle, gcc-patches
John David Anglin wrote:
> Here is a patch. Fixes the above with no regressions. Toon would
> you apply if ok so that configure and config.in are rebuilt with your
> favorite versions of autoconf and autoheader?
> 2002-01-10 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * libI77/configure.in (_LARGEFILE_SOURCE): AC_DEFINE.
> * libI77/configure: Rebuilt.
> * libI77/config.h.in: Rebuilt.
Applied with the obvious date change to the ChangeLog. Make bootstrap
(C and Fortran only), checked (Fortran only) and installed on
i686-pc-linux-gnu (Debian GNU/Linux 2.2).
Sorry for the delay - I was away from home for the USENIX/FREENIX 2002
program committee meeting in Durham last week.
Thanks !
--
Toon Moene - mailto:toon@moene.indiv.nluug.nl - phoneto: +31 346 214290
Saturnushof 14, 3738 XG Maartensdijk, The Netherlands
Maintainer, GNU Fortran 77: http://gcc.gnu.org/onlinedocs/g77_news.html
Join GNU Fortran 95: http://g95.sourceforge.net/ (under construction)
^ permalink raw reply [flat|nested] 521+ messages in thread
* PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
[not found] <no.id>
` (64 preceding siblings ...)
2002-01-10 9:33 ` PATCH: more portable way to fix g77.f-torture/execute/io1.f (was Re: [PATCH] alias.c find_base_value fix) John David Anglin
@ 2002-01-15 15:35 ` John David Anglin
2002-01-15 19:31 ` Richard Henderson
2002-01-16 8:53 ` Jan Hubicka
2002-01-21 13:02 ` Fix ld_library_path in g77.exp for hppa64-hp-hpux11.X John David Anglin
` (97 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2002-01-15 15:35 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, jh, rth, gcc-patches
> The ICE occurs in verify_flow_info when it encounters a barrier. It appears
> that case insn's are being incorrectly simplified in the cse2 pass. This
> is the rtl from loop:
The ICE occurs because the original conditional jump gets converted to
an unconditional jump and a barrier is added after the jump. However,
the jump table data still remains in the rtl for the block. This
confuses the edge analysis into thinking that the block falls thru
and we have an inconsistent configuration.
This patch fixes the problem by deleting the jump table data when a
conditional or computed jump is converted to an unconditional jump.
I have verified that the patch fixes the original problem observed
under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
won't finish until sometime next month.
Bootstrap checked with no regressions on i686-pc-linux-gnu and
hppa2.0w-hp-hpux11.11.
OK to install?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-14 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cse.c (cse_insn): Delete jump table data when a conditional or
computed jump is converted to an unconditional jump.
--- cse.c.orig Mon Jan 14 12:24:57 2002
+++ cse.c Mon Jan 14 17:48:32 2002
@@ -5767,9 +5767,19 @@
be a conditional or computed branch. */
else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
{
- /* Now emit a BARRIER after the unconditional jump. */
- if (NEXT_INSN (insn) == 0
- || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+ rtx next = NEXT_INSN (insn);
+ rtx tmp;
+
+ /* Delete jump table data if present. */
+ if (next != NULL_RTX
+ && LABEL_P (next)
+ && (tmp = NEXT_INSN (next)) != NULL_RTX
+ && JUMP_TABLE_DATA_P (tmp))
+ delete_insn (tmp);
+
+ /* Now emit a BARRIER after the unconditional jump. */
+ if (next == NULL_RTX
+ || GET_CODE (next) != BARRIER)
emit_barrier_after (insn);
/* We reemit the jump in as many cases as possible just in
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-15 15:35 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 John David Anglin
@ 2002-01-15 19:31 ` Richard Henderson
2002-01-15 20:27 ` John David Anglin
2002-02-04 16:04 ` John David Anglin
2002-01-16 8:53 ` Jan Hubicka
1 sibling, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2002-01-15 19:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, jh, gcc-patches
On Tue, Jan 15, 2002 at 06:16:14PM -0500, John David Anglin wrote:
> This patch fixes the problem by deleting the jump table data when a
> conditional or computed jump is converted to an unconditional jump.
> I have verified that the patch fixes the original problem observed
> under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
> won't finish until sometime next month.
This is extremely delicate. It is not uncommon for there to
be references remaining to the jump table that won't be deleted
until later dead code elimination.
I'm therefore uncomfortable with simply removing it like this.
I'm not sure what to suggest as an alternative though...
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-15 19:31 ` Richard Henderson
@ 2002-01-15 20:27 ` John David Anglin
2002-02-04 16:04 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-01-15 20:27 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-bugs, jh, gcc-patches
> On Tue, Jan 15, 2002 at 06:16:14PM -0500, John David Anglin wrote:
> > This patch fixes the problem by deleting the jump table data when a
> > conditional or computed jump is converted to an unconditional jump.
> > I have verified that the patch fixes the original problem observed
> > under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
> > won't finish until sometime next month.
>
> This is extremely delicate. It is not uncommon for there to
> be references remaining to the jump table that won't be deleted
> until later dead code elimination.
>
> I'm therefore uncomfortable with simply removing it like this.
> I'm not sure what to suggest as an alternative though...
I suspect the problem is specific to the VAX. The VAX is the only
port that defines CASE_DROPS_THROUGH. When the VAX casesi jump is
folded, the PC's value in the casesi insn is replaced by a LABEL_REF
pointing to the CODE_LABEL before the jump table which unfortunately
is in the current block. Then, at a later point, the barrier is added
in cse_insn creating the invalid configuration.
I tried moving delete_trivially_dead_insns up before cleanup_cfg in
toplev.c but that didn't remove the jump table. I tried removing the
jump insn. That failed at a different point in verify_flow_info.
It might be possible to make that approach work but I suspect that
you would have the same misgivings.
I could wrap the code to delete the jump table in an #ifdef
CASE_DROPS_THROUGH if that would make you more comfortable.
The other options that I can see are: changing verify_flow_info
to allow the barrier in this situation if CASE_DROPS_THROUGH,
or not emitting the barrier in cse_main.
As an aside, I noticed that gcc can't simplify a switch statement
when its expression evaluates to a value in the range of the switch.
This is because a MEM is used to access the jump table. Probably
not a big deal, but the HP compiler can do it.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-15 19:31 ` Richard Henderson
2002-01-15 20:27 ` John David Anglin
@ 2002-02-04 16:04 ` John David Anglin
2002-02-04 16:31 ` Richard Henderson
2002-02-04 18:01 ` law
1 sibling, 2 replies; 521+ messages in thread
From: John David Anglin @ 2002-02-04 16:04 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-bugs, jh, gcc-patches
> On Tue, Jan 15, 2002 at 06:16:14PM -0500, John David Anglin wrote:
> > This patch fixes the problem by deleting the jump table data when a
> > conditional or computed jump is converted to an unconditional jump.
> > I have verified that the patch fixes the original problem observed
> > under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
> > won't finish until sometime next month.
>
> This is extremely delicate. It is not uncommon for there to
> be references remaining to the jump table that won't be deleted
> until later dead code elimination.
>
> I'm therefore uncomfortable with simply removing it like this.
> I'm not sure what to suggest as an alternative though...
Does this look better? The patch no longer removes the jump table.
It simply changes the branch destination to a new label following
the jump table when it detects that the target of the jump is the
following insn. The subsequent flow analysis deletes the unused jump
table. This should only happen on the vax.
Tested on vax-dec-ultrix4.3 and various PA builds for the last month.
OK?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-16 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cse.c (cse_insn): Fix the destination of unconditional jumps to an
immediately following code label, followed by jump table data.
--- cse.c.orig Wed Jan 16 12:28:28 2002
+++ cse.c Wed Jan 16 16:50:26 2002
@@ -5767,9 +5767,30 @@
be a conditional or computed branch. */
else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
{
- /* Now emit a BARRIER after the unconditional jump. */
- if (NEXT_INSN (insn) == 0
- || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+ rtx next = NEXT_INSN (insn);
+ rtx tmp;
+
+ /* If there is jump table data after the jump and its destination
+ is now the code label preceding the jump table, change the
+ destination to a new label after the jump table. This kludge
+ is needed on the VAX because fold_rtx uses the label before
+ the jump table in folding a case insn. */
+ if (next != NULL_RTX
+ && LABEL_P (next)
+ && (tmp = NEXT_INSN (next)) != NULL_RTX
+ && JUMP_TABLE_DATA_P (tmp)
+ && XEXP (src, 0) == next)
+ {
+ rtx label = gen_label_rtx ();
+ emit_label_after (label, tmp);
+ XEXP (src, 0) = label;
+ --LABEL_NUSES (next);
+ ++LABEL_NUSES (label);
+ }
+
+ /* Now emit a BARRIER after the unconditional jump. */
+ if (next == NULL_RTX
+ || GET_CODE (next) != BARRIER)
emit_barrier_after (insn);
/* We reemit the jump in as many cases as possible just in
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 16:04 ` John David Anglin
@ 2002-02-04 16:31 ` Richard Henderson
2002-02-04 17:39 ` law
2002-02-04 18:01 ` law
1 sibling, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-02-04 16:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, jh, gcc-patches, law
On Mon, Feb 04, 2002 at 06:37:13PM -0500, John David Anglin wrote:
> Does this look better? The patch no longer removes the jump table...
Grr. Jeff, we need a decision on how we're going to handle
this across the board.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 16:31 ` Richard Henderson
@ 2002-02-04 17:39 ` law
2002-02-04 18:23 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2002-02-04 17:39 UTC (permalink / raw)
To: Richard Henderson; +Cc: John David Anglin, gcc-bugs, jh, gcc-patches
In message <20020204161620.B19052@redhat.com>, Richard Henderson writes:
> On Mon, Feb 04, 2002 at 06:37:13PM -0500, John David Anglin wrote:
> > Does this look better? The patch no longer removes the jump table...
>
> Grr. Jeff, we need a decision on how we're going to handle
> this across the board.
Agreed. As I mentioned, I'm extremely tempted to burn tonight and
get rid of having a separate insn for the ADDR_VEC/ADDR_DIFF_VEC.
Thoughts?
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 17:39 ` law
@ 2002-02-04 18:23 ` Richard Henderson
2002-02-04 21:21 ` law
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-02-04 18:23 UTC (permalink / raw)
To: law; +Cc: John David Anglin, gcc-bugs, jh, gcc-patches
On Mon, Feb 04, 2002 at 05:35:52PM -0700, law@redhat.com wrote:
> Agreed. As I mentioned, I'm extremely tempted to burn tonight and
> get rid of having a separate insn for the ADDR_VEC/ADDR_DIFF_VEC.
>
> Thoughts?
If you can make it work, I'm all for it.
BTW, another edge case you should consider in doing this is
s390, which dumps the tablejump label into the constant pool.
I don't think there's an integrated sim for that one, but
perhaps faking it via "ln -s /bin/true s390-linux-run" and
checking that the execute tests compile is a good enough
sanity check.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 18:23 ` Richard Henderson
@ 2002-02-04 21:21 ` law
2002-02-04 22:10 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on John David Anglin
2002-02-05 0:33 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 Richard Henderson
0 siblings, 2 replies; 521+ messages in thread
From: law @ 2002-02-04 21:21 UTC (permalink / raw)
To: Richard Henderson; +Cc: John David Anglin, gcc-bugs, jh, gcc-patches
In message <20020204164731.A19099@redhat.com>, Richard Henderson writes:
> On Mon, Feb 04, 2002 at 05:35:52PM -0700, law@redhat.com wrote:
> > Agreed. As I mentioned, I'm extremely tempted to burn tonight and
> > get rid of having a separate insn for the ADDR_VEC/ADDR_DIFF_VEC.
> >
> > Thoughts?
>
> If you can make it work, I'm all for it.
The only thing that makes it even a mildly interesting problem is the ports
that want to use the label before the tablejump for computations.
Attaching the jump table to the tablejump isn't all that difficult, but we
still have the fun and exciting job of dealing with that peksy code label --
with the downside that without the separate ADDR_VEC/ADDR_DIFF_VEC, it's
less clear that the label is "special".
What we could do in the short term is to delete the jump table when we
optimize the jump, but leave the CODE_LABEL alone. That deals with the
immediate problem of needing to get unused jump tables out of the insn
stream. By leaving the CODE_LABEL in the stream we avoid dangling
references in normal insns which used that label for computations.
I believe John's patch as well as mine could be easily adapted to such
a scheme.
--
Looking into the future, we need some way to have those pesky computation
insns reference a widget which is attached (along with the jump table) to
the tablejump insn. [ The widget is a magic code label, of course. ]
By having all 3 key items (tablejump, jump table and magic code label) in a
single insn we avoid all the mess of knowing that magic items follow table
jumps which must be kept in specific orders, and we avoid having random crud
existing between basic blocks.
When doing final assembly output, we would first emit the jump, then emit
the magic label (if any), then the jump table (if any).
When we optimize a tablejump into a simple jump, we zero out the attached jump
table and emit the magic label into the insn stream as a normal CODE_LABEL (at
which point it behaves like any CODE_LABEL which is not referenced by a jumping
insn).
> BTW, another edge case you should consider in doing this is
> s390, which dumps the tablejump label into the constant pool.
> I don't think there's an integrated sim for that one, but
> perhaps faking it via "ln -s /bin/true s390-linux-run" and
> checking that the execute tests compile is a good enough
> sanity check.
I think we'd want to largely treat the s390 like the other ports; with the
caveat that we dump the table into the constant pool relatively late in
the compilation process. ie, I'd like to present the optimizers with
a common model for dealing with tablejumps.
Thoughts?
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-04 21:21 ` law
@ 2002-02-04 22:10 ` John David Anglin
2002-02-05 0:06 ` law
2002-02-05 6:01 ` Jan Hubicka
2002-02-05 0:33 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 Richard Henderson
1 sibling, 2 replies; 521+ messages in thread
From: John David Anglin @ 2002-02-04 22:10 UTC (permalink / raw)
To: law; +Cc: rth, gcc-bugs, jh, gcc-patches
> What we could do in the short term is to delete the jump table when we
> optimize the jump, but leave the CODE_LABEL alone. That deals with the
> immediate problem of needing to get unused jump tables out of the insn
> stream. By leaving the CODE_LABEL in the stream we avoid dangling
> references in normal insns which used that label for computations.
That's what my first patch did. However, Honza pointed out that it
is valid for a case pattern to appear to use the jump table but in
fact do an indirect branch using a pointer. If you kill the jump
table, then you need to kill the jumps first and they are difficult
to locate. However, this does not apply to the VAX and I believe
the jump table can be safely deleted.
My current proposal essentially creates for the VAX the same situation
as we currently have on the PA (ie., the jump table remains around
until removed by dead code analysis). Obviously, not as nice as
your suggestion below but it seems to work.
The situations where a switch gets folded are relatively rare. Loop
unrolling is where I first noted the problem. Thus, unless you are
aware of other bugs affected by this problem, I would defer a better
fix until after 3.1 branches.
The current patch only affects the VAX because it is the only port
that defines CASE_DROPS_THROUGH, and thereby the only port where the
case insn is folded to a jump directed to the label before the jump table.
Thus, I don't believe patch will affect any other port.
> Looking into the future, we need some way to have those pesky computation
> insns reference a widget which is attached (along with the jump table) to
> the tablejump insn. [ The widget is a magic code label, of course. ]
>
> By having all 3 key items (tablejump, jump table and magic code label) in a
> single insn we avoid all the mess of knowing that magic items follow table
> jumps which must be kept in specific orders, and we avoid having random crud
> existing between basic blocks.
Sounds wonderful. In thinking about this, it became clear that separating
these components was just asking for trouble.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-04 22:10 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on John David Anglin
@ 2002-02-05 0:06 ` law
2002-02-05 7:34 ` Jan Hubicka
2002-02-05 6:01 ` Jan Hubicka
1 sibling, 1 reply; 521+ messages in thread
From: law @ 2002-02-05 0:06 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-bugs, jh, gcc-patches
In message <200202050510.g155AIxr021739@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> That's what my first patch did. However, Honza pointed out that it
> is valid for a case pattern to appear to use the jump table but in
> fact do an indirect branch using a pointer. If you kill the jump
> table, then you need to kill the jumps first and they are difficult
> to locate. However, this does not apply to the VAX and I believe
> the jump table can be safely deleted.
It seems to me that we do in fact kill the jumps first in cse.c and
cfgrtl.c, so I'm not sure I understand Honza's objection.
In fact, what I'm proposing is the set of actions to perform when we
transform any jump which uses a jump table into a simple jump -- regardless
of whether or not the jump is implemented as casesi, tablejump or a special
indirect jump.
The cases where my proposed rules can all be identified by the following code
(assuming INSN is the original jump):
if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
&& (tmp = NEXT_INSN (tmp)) != NULL_RTX
&& GET_CODE (tmp) == JUMP_INSN
&& (GET_CODE (PATTERN (tmp)) == ADDR_VEC
|| GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
Furthermore, other insns don't reference the jump table -- they reference
the CODE_LABEL before the jump table. That's the whole point behind leaving
the CODE_LABEL in the insn stream. So I have a real hard time seeing why
it is unsafe to remove the jump table at the same time we convert its
associated tablejump/casesi into a simple jump.
Maybe I'm just being dense.
> My current proposal essentially creates for the VAX the same situation
> as we currently have on the PA (ie., the jump table remains around
> until removed by dead code analysis). Obviously, not as nice as
> your suggestion below but it seems to work.
It'll break. It's just a matter of getting into the right parts of
the compiler. The most problematical areas are going to the hunks of code
that iterate over the insn stream without regards for basic block boundaries.
We've already run into cases where these unattached jump tables have caused
such code to core dump. See:
http://gcc.gnu.org/ml/gcc/2001-11/msg01355.html
While I marginally agree with the change that was installed -- it's safe, but
it needlessly caused the loop optimizer to give up on a loop -- all because
it had an unused jump table lying around in the middle of it.
It turns out that code was relatively easy to fix, but I have little
confidence that the rest of our compiler is ready to deal with a random,
unattached jump table, or with a jump table which references deleted
labels.
Before we switched to rely heavily on the cfg simplifier such cases were
caught and fixed by running the jump optimizer after any pass which might
have modified a jump. One of the first things the jump optimizer did was
remove code between a BARRIER and the next CODE_LABEL. That had the effect
of removing these unattached jump tables from the insn stream before the
other optimizers had the chance to trip over them.
> The situations where a switch gets folded are relatively rare.
I agree. However the amount of code that is prepared to deal with this
situation is rather vast -- particularly when you consider how we relied
upon the old jump optimizer to always clean up this turd before we moved
into the next optimization pass.
> Loop
> unrolling is where I first noted the problem. Thus, unless you are
> aware of other bugs affected by this problem, I would defer a better
> fix until after 3.1 branches.
I ran into it just trying to bootstrap the compiler. :(
> The current patch only affects the VAX because it is the only port
> that defines CASE_DROPS_THROUGH, and thereby the only port where the
> case insn is folded to a jump directed to the label before the jump table.
> Thus, I don't believe patch will affect any other port.
True, but the underlying issue (unattached jump tables in the stream) affects
more than just the VAX.
> > By having all 3 key items (tablejump, jump table and magic code label) in
> a
> > single insn we avoid all the mess of knowing that magic items follow table
> > jumps which must be kept in specific orders, and we avoid having random cr
> ud
> > existing between basic blocks.
>
> Sounds wonderful. In thinking about this, it became clear that separating
> these components was just asking for trouble.
Agreed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-05 0:06 ` law
@ 2002-02-05 7:34 ` Jan Hubicka
2002-02-05 8:50 ` law
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2002-02-05 7:34 UTC (permalink / raw)
To: law; +Cc: John David Anglin, rth, gcc-bugs, jh, gcc-patches
> Furthermore, other insns don't reference the jump table -- they reference
> the CODE_LABEL before the jump table. That's the whole point behind leaving
> the CODE_LABEL in the insn stream. So I have a real hard time seeing why
> it is unsafe to remove the jump table at the same time we convert its
> associated tablejump/casesi into a simple jump.
Because the label before jumptable is special by the fact that it is not
in code segment for most cases. By removing the following jumptable you
convert special code_label to not special code_label and create invalid
CFG. Sick, I know.
You must remove it and convert to NOTE_DELETED_LABEL as code labels other than
tablejump are prohibited outside basic block. In case we keep the instructions
to compute address in the stream by the accident, we result in accesing code
segment for no putpose.
> Before we switched to rely heavily on the cfg simplifier such cases were
> caught and fixed by running the jump optimizer after any pass which might
This is not correct - it is easy to construct testcases where the jumptable
has been left in the stream with the old jump optimizer.
THey has been removed just in "majority of cases".
Honza
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-05 7:34 ` Jan Hubicka
@ 2002-02-05 8:50 ` law
2002-02-05 10:40 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2002-02-05 8:50 UTC (permalink / raw)
To: Jan Hubicka; +Cc: John David Anglin, rth, gcc-bugs, gcc-patches
In message <20020205124632.GS17128@atrey.karlin.mff.cuni.cz>, Jan Hubicka
write
s:
> Because the label before jumptable is special by the fact that it is not
> in code segment for most cases. By removing the following jumptable you
> convert special code_label to not special code_label and create invalid
> CFG. Sick, I know.
No, it doesn't create an invalid CFG if it does, then the CFG was broken to
begin with.
Let's look at the cases.
First, let's assume we don't optimize the tablejump at all. By convention the
magic label as well as the jump table are defined as being outside any defined
basic blocks. ie, they exist between basic blocks, much like barriers.
Now let's assume we have an optimizable tablejump and we remove the jump
table, twiddle the tablejump, but leave the magic code label alone.
The vast majority of the time twiddling the tablejump will either directly
or indirectly (via dead code elimination) cause all the references to the
magic code label to be removed. Once the last reference has been removed,
the code label itself gets removed. Clearly if it's not in the stream,
then it's not going to cause a problem.
However, there is a period of time where the label is in the stream, but
this should not cause significant problems. If you look at the insns we
will be left with after transforming the tablejump and removing the
jump table we'll have something like this:
simplejump
barrier
magic code label
[ Optional barrier, which I believe we want to eliminate if it's still
in the stream. ]
normal code label for whatever real code followed the jump table
We effectively have consecutive labels, which can and should be
combined. Even if they are not combined, what we have is a label which
is not the target of a branch, but which is referenced by computation
insns. Such labels have well defined semantics, both in terms of how
the CFG is constructed (they have no effect) and in terms of how they
can move around in the insn stream.
> You must remove it and convert to NOTE_DELETED_LABEL as code labels other
> than tablejump are prohibited outside basic block. In case we keep the
> instructions to compute address in the stream by the accident, we result
> in accesing code segment for no putpose.
I don't think this is necessary. Though if it would make you feel better,
we can convert the label into a NOTE_DELETED_LABEL.
99.9% of the time the computation insns are going to be deleted by dead
code elimination. That 0.1% of the time all they'll do is compute an
address that will never be used, just like if we take the address of a
label using GCC's address-of-a-label extension.
> This is not correct - it is easy to construct testcases where the jumptable
> has been left in the stream with the old jump optimizer.
> THey has been removed just in "majority of cases".
Sorry, based on my knowledge of how jump.c works I don't believe you. I'd
like to see an example of when the old jump optimizer would leave an
jump table in the stream.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-05 8:50 ` law
@ 2002-02-05 10:40 ` Jan Hubicka
0 siblings, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2002-02-05 10:40 UTC (permalink / raw)
To: law; +Cc: Jan Hubicka, John David Anglin, rth, gcc-bugs, gcc-patches
> We effectively have consecutive labels, which can and should be
> combined. Even if they are not combined, what we have is a label which
This is the problem. We do have CODE_LABEL outside basic block.
Our definition of CFG is that CODE_LABELs (except for magical ones)
appears in the head of basic block. There can not be multiple labels
in single basic block and there can not be labels outside basic blocks.
Combining labels is handled by creating empty basic block and elliminating
them subsequently.
We are targetting to situation where there is nothing outside basic block,
as sane ILs should have. That means eliminating of jumptables and majority
of INSN_NOTES so we are relativly far from that goal. I am working on
the INSN_NOTES slowly anyway.
> is not the target of a branch, but which is referenced by computation
> insns. Such labels have well defined semantics, both in terms of how
> the CFG is constructed (they have no effect) and in terms of how they
> can move around in the insn stream.
>
>
> > You must remove it and convert to NOTE_DELETED_LABEL as code labels other
> > than tablejump are prohibited outside basic block. In case we keep the
> > instructions to compute address in the stream by the accident, we result
> > in accesing code segment for no putpose.
> I don't think this is necessary. Though if it would make you feel better,
> we can convert the label into a NOTE_DELETED_LABEL.
Yes, otherwise verify_flow_info will abort, at least.
You got that right in your patch by using delete_insn_chain that cares
converison to DELETED_LABEL thats why it worked for you.
>
> 99.9% of the time the computation insns are going to be deleted by dead
> code elimination. That 0.1% of the time all they'll do is compute an
> address that will never be used, just like if we take the address of a
It will be used - we will read from it and throw away the value.
The actual read from code segment may be problem, so we need to ensure that
we eliminate the insns in 100%. ALso some ports allow different MEM expresisons
to code segment and to data segment and they actually do test CODE_LABEL
to magickness so we may result in invalid insn.
I believe that this is easy to do - just lets prohibit simplification of
jumptables after reload so flow will always do the action.
> label using GCC's address-of-a-label extension.
>
> > This is not correct - it is easy to construct testcases where the jumptable
> > has been left in the stream with the old jump optimizer.
> > THey has been removed just in "majority of cases".
> Sorry, based on my knowledge of how jump.c works I don't believe you. I'd
> like to see an example of when the old jump optimizer would leave an
> jump table in the stream.
One of testcases has been invariant jumptable in the loop. THe compuation
has been then moved outside loop and jump lost track when killing
the dead code.
Honza
>
> jeff
>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on
2002-02-04 22:10 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on John David Anglin
2002-02-05 0:06 ` law
@ 2002-02-05 6:01 ` Jan Hubicka
1 sibling, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2002-02-05 6:01 UTC (permalink / raw)
To: John David Anglin; +Cc: law, rth, gcc-bugs, jh, gcc-patches
> > Looking into the future, we need some way to have those pesky computation
> > insns reference a widget which is attached (along with the jump table) to
> > the tablejump insn. [ The widget is a magic code label, of course. ]
> >
> > By having all 3 key items (tablejump, jump table and magic code label) in a
> > single insn we avoid all the mess of knowing that magic items follow table
> > jumps which must be kept in specific orders, and we avoid having random crud
> > existing between basic blocks.
>
> Sounds wonderful. In thinking about this, it became clear that separating
> these components was just asking for trouble.
As mentioned in the other thread, I've tested the idea on cfg branch by
just removing the jumptables+labels from insn stream after it is constructed
and re-emitting them before final and it worked just fine for i386/mips
w/o modification of config directory.
Honza
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 21:21 ` law
2002-02-04 22:10 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on John David Anglin
@ 2002-02-05 0:33 ` Richard Henderson
2002-02-05 0:11 ` law
2002-02-05 7:08 ` Jan Hubicka
1 sibling, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2002-02-05 0:33 UTC (permalink / raw)
To: law; +Cc: John David Anglin, gcc-bugs, jh, gcc-patches
On Mon, Feb 04, 2002 at 08:29:58PM -0700, law@redhat.com wrote:
> What we could do in the short term is to delete the jump table when we
> optimize the jump, but leave the CODE_LABEL alone. That deals with the
> immediate problem of needing to get unused jump tables out of the insn
> stream. By leaving the CODE_LABEL in the stream we avoid dangling
> references in normal insns which used that label for computations.
If we're going to dream, I think using CODE_LABEL at all for this
is incorrect. Except for a couple of oddballs it isn't a label to
code at all -- it's a label to .rodata. And for those Harvard ports
that have different representations for code and data pointers,
having both use a LABEL_REF causes problems.
So we should have a TABLEJUMP_REF that references the jump table,
and if for some reason the jump table gets optimized away without
optimizing out the references, we can emit a zero instead.
Or simply have a pass just before final that removes such refs.
> I think we'd want to largely treat the s390 like the other ports; with the
> caveat that we dump the table into the constant pool relatively late in
> the compilation process. ie, I'd like to present the optimizers with
> a common model for dealing with tablejumps.
It doesn't seem unreasonable to treat the entire table jump as a
unit during early optimization. You'd want to lower early enough
to move address computation out of loops when possible, but otherwise
there's little that can actually be simplified wrt other code.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-05 0:33 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 Richard Henderson
@ 2002-02-05 0:11 ` law
2002-02-05 7:08 ` Jan Hubicka
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2002-02-05 0:11 UTC (permalink / raw)
To: Richard Henderson; +Cc: John David Anglin, gcc-bugs, jh, gcc-patches
In message <20020204215518.A19374@redhat.com>, Richard Henderson writes:
> If we're going to dream, I think using CODE_LABEL at all for this
> is incorrect. Except for a couple of oddballs it isn't a label to
> code at all -- it's a label to .rodata. And for those Harvard ports
> that have different representations for code and data pointers,
> having both use a LABEL_REF causes problems.
I agree completely. In fact, the lame notion that it was a CODE_LABEL
caused me more frustration than I care to remember when I was playing
with rewriting the jump table support for the PA a few years ago.
> So we should have a TABLEJUMP_REF that references the jump table,
> and if for some reason the jump table gets optimized away without
> optimizing out the references, we can emit a zero instead.
Sure. I've got no problem with this.
> It doesn't seem unreasonable to treat the entire table jump as a
> unit during early optimization. You'd want to lower early enough
> to move address computation out of loops when possible, but otherwise
> there's little that can actually be simplified wrt other code.
It seems to me the address computation can be broken out without breaking
up the jump, table & TABLEJUMP_REF into their separate components. We would
just expand
(set (reg) (TABLEJUMP_REF x))
Into whatever components the target needs. It seems we can do that, but
still keep the rest of the stuff as a unit until final assembly output.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-05 0:33 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 Richard Henderson
2002-02-05 0:11 ` law
@ 2002-02-05 7:08 ` Jan Hubicka
2002-02-05 7:58 ` law
2002-02-05 9:32 ` Richard Henderson
1 sibling, 2 replies; 521+ messages in thread
From: Jan Hubicka @ 2002-02-05 7:08 UTC (permalink / raw)
To: Richard Henderson, law, John David Anglin, gcc-bugs, jh, gcc-patches
> On Mon, Feb 04, 2002 at 08:29:58PM -0700, law@redhat.com wrote:
> > What we could do in the short term is to delete the jump table when we
> > optimize the jump, but leave the CODE_LABEL alone. That deals with the
> > immediate problem of needing to get unused jump tables out of the insn
> > stream. By leaving the CODE_LABEL in the stream we avoid dangling
> > references in normal insns which used that label for computations.
>
> If we're going to dream, I think using CODE_LABEL at all for this
> is incorrect. Except for a couple of oddballs it isn't a label to
> code at all -- it's a label to .rodata. And for those Harvard ports
> that have different representations for code and data pointers,
> having both use a LABEL_REF causes problems.
>
> So we should have a TABLEJUMP_REF that references the jump table,
> and if for some reason the jump table gets optimized away without
> optimizing out the references, we can emit a zero instead.
Perhaps using symbol_ref is just fine. For calls we also do use
symbol refs to addresses inside code segment.
>
> Or simply have a pass just before final that removes such refs.
>
> > I think we'd want to largely treat the s390 like the other ports; with the
> > caveat that we dump the table into the constant pool relatively late in
> > the compilation process. ie, I'd like to present the optimizers with
> > a common model for dealing with tablejumps.
>
> It doesn't seem unreasonable to treat the entire table jump as a
> unit during early optimization. You'd want to lower early enough
> to move address computation out of loops when possible, but otherwise
> there's little that can actually be simplified wrt other code.
This IMO well fits the midlevel/lowlevel RTL design. In my eyes the "final"
midRTL lowering should be followed by PRE to move invariants out of the loop,
so we will not lose optimization opurtunities and get the advnatage of
possibility to duplicate jumptables, that is important for superblock
formation. See for instance the interpreter in libjava, that do contain huge
switch for each instruction that is ifdefed out and replaced by indirect jumps
to avoid one jump instruction per simulation cycle. With tracer compiler will
be able to do the trick automagically.
Honza
>
>
> r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-05 7:08 ` Jan Hubicka
@ 2002-02-05 7:58 ` law
2002-02-05 9:32 ` Richard Henderson
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2002-02-05 7:58 UTC (permalink / raw)
To: Jan Hubicka; +Cc: Richard Henderson, John David Anglin, gcc-bugs, gcc-patches
In message <20020205124050.GR17128@atrey.karlin.mff.cuni.cz>, Jan Hubicka write
s:
> > On Mon, Feb 04, 2002 at 08:29:58PM -0700, law@redhat.com wrote:
> > > What we could do in the short term is to delete the jump table when we
> > > optimize the jump, but leave the CODE_LABEL alone. That deals with the
> > > immediate problem of needing to get unused jump tables out of the insn
> > > stream. By leaving the CODE_LABEL in the stream we avoid dangling
> > > references in normal insns which used that label for computations.
> >
> > If we're going to dream, I think using CODE_LABEL at all for this
> > is incorrect. Except for a couple of oddballs it isn't a label to
> > code at all -- it's a label to .rodata. And for those Harvard ports
> > that have different representations for code and data pointers,
> > having both use a LABEL_REF causes problems.
> >
> > So we should have a TABLEJUMP_REF that references the jump table,
> > and if for some reason the jump table gets optimized away without
> > optimizing out the references, we can emit a zero instead.
>
> Perhaps using symbol_ref is just fine. For calls we also do use
> symbol refs to addresses inside code segment.
No. I really prefer Richard's idea of creating a new _REF node. Why?
Because LABEL_REF implies a label in the code segment and SYMBOL_REF
implies a label outside the code segment. For the label before a jump
table, we don't know where it'll end up. Some ports put the table in
the code segment, others in readonly data, others in r/w data.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-05 7:08 ` Jan Hubicka
2002-02-05 7:58 ` law
@ 2002-02-05 9:32 ` Richard Henderson
2002-02-05 10:52 ` Jan Hubicka
1 sibling, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-02-05 9:32 UTC (permalink / raw)
To: Jan Hubicka; +Cc: law, John David Anglin, gcc-bugs, gcc-patches
On Tue, Feb 05, 2002 at 01:40:50PM +0100, Jan Hubicka wrote:
> Perhaps using symbol_ref is just fine. For calls we also do use
> symbol refs to addresses inside code segment.
And on thouse troublesome ports we have ENCODE_SECTION_INFO
to set e.g. SYMBOL_REF_FLAG to indicate a code segment address.
From whence would you call ENCODE_SECTION_INFO from this?
Of course, don't get me started on how SYMBOL_REF should be
cleaned up as well.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-05 9:32 ` Richard Henderson
@ 2002-02-05 10:52 ` Jan Hubicka
0 siblings, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2002-02-05 10:52 UTC (permalink / raw)
To: Richard Henderson, Jan Hubicka, law, John David Anglin, gcc-bugs,
gcc-patches
> On Tue, Feb 05, 2002 at 01:40:50PM +0100, Jan Hubicka wrote:
> > Perhaps using symbol_ref is just fine. For calls we also do use
> > symbol refs to addresses inside code segment.
>
> And on thouse troublesome ports we have ENCODE_SECTION_INFO
> to set e.g. SYMBOL_REF_FLAG to indicate a code segment address.
> >From whence would you call ENCODE_SECTION_INFO from this?
>
> Of course, don't get me started on how SYMBOL_REF should be
> cleaned up as well.
Perhaps instead of generating many *_REF beasts, we should use
one with flags specifying the segment _REF is in. We partly do that
for SYMBOL_REF and static storage anyway.
But this is another involved topic :(
Honza
>
>
> r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-02-04 16:04 ` John David Anglin
2002-02-04 16:31 ` Richard Henderson
@ 2002-02-04 18:01 ` law
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2002-02-04 18:01 UTC (permalink / raw)
To: John David Anglin; +Cc: Richard Henderson, gcc-bugs, jh, gcc-patches
In message <200202042337.g14NbDAV020955@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> > On Tue, Jan 15, 2002 at 06:16:14PM -0500, John David Anglin wrote:
> > > This patch fixes the problem by deleting the jump table data when a
> > > conditional or computed jump is converted to an unconditional jump.
> > > I have verified that the patch fixes the original problem observed
> > > under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
> > > won't finish until sometime next month.
> >
> > This is extremely delicate. It is not uncommon for there to
> > be references remaining to the jump table that won't be deleted
> > until later dead code elimination.
> >
> > I'm therefore uncomfortable with simply removing it like this.
> > I'm not sure what to suggest as an alternative though...
>
> Does this look better? The patch no longer removes the jump table.
> It simply changes the branch destination to a new label following
> the jump table when it detects that the target of the jump is the
> following insn. The subsequent flow analysis deletes the unused jump
> table. This should only happen on the vax.
>
> Tested on vax-dec-ultrix4.3 and various PA builds for the last month.
>
> OK?
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-66
> 05)
>
> 2002-01-16 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * cse.c (cse_insn): Fix the destination of unconditional jumps to an
> immediately following code label, followed by jump table data.
I hate to interject myself into this conversation, but I think Richard is
wrong here.
If we convert a tablejump into a simpler jump, then we should (if at all
possible) remove the associated jump table. Numerous unpleasant problems
arise if we leave an unreferenced jump table in the insn stream.
Or maybe we just bite the bullet right now, today and attach the jump
table to the jump itself. I realize that we're rather late in the gcc-3.1
process, but we've clearly got a problem that needs to be addressed and
the various attempts at addressing it within the existing framework have
inevitably caused problems. That tells me we need to fix the underlying
framework.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-15 15:35 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 John David Anglin
2002-01-15 19:31 ` Richard Henderson
@ 2002-01-16 8:53 ` Jan Hubicka
2002-01-16 9:09 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2002-01-16 8:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-bugs, jh, rth, gcc-patches
> > The ICE occurs in verify_flow_info when it encounters a barrier. It appears
> > that case insn's are being incorrectly simplified in the cse2 pass. This
> > is the rtl from loop:
>
> The ICE occurs because the original conditional jump gets converted to
> an unconditional jump and a barrier is added after the jump. However,
> the jump table data still remains in the rtl for the block. This
> confuses the edge analysis into thinking that the block falls thru
> and we have an inconsistent configuration.
This is bit dangerous, as at some targets, the instructions to compute
jump destination may remain in the insn stream until after liveness analysis
that should zap them as dead.
They should not reference deleted label, so maximally one can convert it
into NOTE_INSN_DELETED_LABEL.
My approach in the cfg is to keep the tables around and sweep them once done
with CSE, but I guess it is easier to zap them to NOTE_INSN_DELETED_LABEL instead.
I plan to do that move on the cfg branch.
In your case all you need is to use delete_insn_chain for the two insns that
cares to create the note instead.
Honza
>
> This patch fixes the problem by deleting the jump table data when a
> conditional or computed jump is converted to an unconditional jump.
> I have verified that the patch fixes the original problem observed
> under vax-dec-ultrix4.3. A new vax bootstrap is underway but it
> won't finish until sometime next month.
>
> Bootstrap checked with no regressions on i686-pc-linux-gnu and
> hppa2.0w-hp-hpux11.11.
>
> OK to install?
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2002-01-14 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * cse.c (cse_insn): Delete jump table data when a conditional or
> computed jump is converted to an unconditional jump.
>
> --- cse.c.orig Mon Jan 14 12:24:57 2002
> +++ cse.c Mon Jan 14 17:48:32 2002
> @@ -5767,9 +5767,19 @@
> be a conditional or computed branch. */
> else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
> {
> - /* Now emit a BARRIER after the unconditional jump. */
> - if (NEXT_INSN (insn) == 0
> - || GET_CODE (NEXT_INSN (insn)) != BARRIER)
> + rtx next = NEXT_INSN (insn);
> + rtx tmp;
> +
> + /* Delete jump table data if present. */
> + if (next != NULL_RTX
> + && LABEL_P (next)
> + && (tmp = NEXT_INSN (next)) != NULL_RTX
> + && JUMP_TABLE_DATA_P (tmp))
> + delete_insn (tmp);
> +
> + /* Now emit a BARRIER after the unconditional jump. */
> + if (next == NULL_RTX
> + || GET_CODE (next) != BARRIER)
> emit_barrier_after (insn);
>
> /* We reemit the jump in as many cases as possible just in
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-16 8:53 ` Jan Hubicka
@ 2002-01-16 9:09 ` John David Anglin
2002-01-16 9:58 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-16 9:09 UTC (permalink / raw)
To: Jan Hubicka; +Cc: gcc-bugs, jh, rth, gcc-patches
> My approach in the cfg is to keep the tables around and sweep them once done
> with CSE, but I guess it is easier to zap them to NOTE_INSN_DELETED_LABEL instead.
> I plan to do that move on the cfg branch.
>
> In your case all you need is to use delete_insn_chain for the two insns that
> cares to create the note instead.
We have
(jump (pc) (label_ref 1))
(code_label 1)
(jump_insn (addr_diff_vec:HI (label_ref: 1)
...
You are suggesting deleting first two with NOTE_INSN_DELETED_LABEL?
Of course, this would be done only when the jump goes to the next insn.
This still leaves the jump table in live code which I don't like.
Another alternative might be to add a code_label after the jump table
and add a new jump before the first jump. This should make the three
insn dead. Would this be safer?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3
2002-01-16 9:09 ` John David Anglin
@ 2002-01-16 9:58 ` Jan Hubicka
0 siblings, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2002-01-16 9:58 UTC (permalink / raw)
To: John David Anglin; +Cc: Jan Hubicka, gcc-bugs, rth, gcc-patches
> > My approach in the cfg is to keep the tables around and sweep them once done
> > with CSE, but I guess it is easier to zap them to NOTE_INSN_DELETED_LABEL instead.
> > I plan to do that move on the cfg branch.
> >
> > In your case all you need is to use delete_insn_chain for the two insns that
> > cares to create the note instead.
>
> We have
>
> (jump (pc) (label_ref 1))
>
> (code_label 1)
>
> (jump_insn (addr_diff_vec:HI (label_ref: 1)
> ...
>
> You are suggesting deleting first two with NOTE_INSN_DELETED_LABEL?
> Of course, this would be done only when the jump goes to the next insn.
> This still leaves the jump table in live code which I don't like.
No, just remove the second two using remove_insn_chain call - that should
turn label to NOTE_INSN_DELETED_LABEL if it is still referenced and remove
the jumptable - that should be what you are looking for.
>
> Another alternative might be to add a code_label after the jump table
> and add a new jump before the first jump. This should make the three
> insn dead. Would this be safer?
That should work too, but it is bit complex.
Honza
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix ld_library_path in g77.exp for hppa64-hp-hpux11.X
[not found] <no.id>
` (65 preceding siblings ...)
2002-01-15 15:35 ` PATCH: Re: ICE in 920624-1.c with -O3 -funroll-loops on vax-dec-ultrix4.3 John David Anglin
@ 2002-01-21 13:02 ` John David Anglin
2002-01-21 15:22 ` Fix predicate in decrement_and_branch_until_zero pattern on PA John David Anglin
` (96 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-01-21 13:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, toon
>
> HP-UX shared libraries usually end in '.sl'. The patch removes the check
> for libg2c.so before appending the path for for it to ld_library_path.
> See similar code in g++.exp. This patch fixes several hundred FAILs on
> hppa64-hp-hpux11.X in running the g77 testsuite.
>
> OK to install?
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
And the patch!
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* lib/g77.exp (g77_link_flags): Remove check for libg2c.so in setting
ld_library_path.
--- g77.exp.orig Mon Nov 19 23:03:52 2001
+++ g77.exp Sun Jan 20 19:09:46 2002
@@ -83,9 +83,7 @@
if { $gccpath != "" } {
if [file exists "${gccpath}/libf2c/.libs/libg2c.a"] {
append flags "-L${gccpath}/libf2c/.libs "
- if [file exists "${gccpath}/libf2c/.libs/libg2c.so"] {
- append ld_library_path ":${gccpath}/libf2c/.libs"
- }
+ append ld_library_path ":${gccpath}/libf2c/.libs"
}
if [file exists "${gccpath}/libf2c/libfrtbegin.a"] {
append flags "-L${gccpath}/libf2c "
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
[not found] <no.id>
` (66 preceding siblings ...)
2002-01-21 13:02 ` Fix ld_library_path in g77.exp for hppa64-hp-hpux11.X John David Anglin
@ 2002-01-21 15:22 ` John David Anglin
2002-01-21 15:24 ` Richard Henderson
2002-01-22 23:30 ` PATCH: Fix loop.c for targets without HAVE_prefetch John David Anglin
` (95 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-21 15:22 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches, law
> > Ok, "preferred" was the wrong word, since it's overloaded in
> > this instance. Nevertheless all alternatives are punished,
> > which seems wrong.
>
> I will try removing the '!' from the 'm' alternative.
I have applied the following to address Richard's concerns about punishing
all alternatives and my concerns about allowing non register operands before
reload. The patch updates the movb patterns in a manner similar to that
for decrement_and_branch_until_zero as it is my belief that they might
also be rerecognized after reload. Booted and checked with no regressions
on hppa2.0w-hp-hpux11.x, hppa1.1-hp-hpux10.20, hppa64-hp-hpux11.x.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa-protos.h (reg_before_reload_operand): New function prototype.
* pa.c (reg_before_reload_operand): New function implementation.
* pa.md (decrement_and_branch_until_zero, movb): Use it. Change "!*m"
contraints to "*m".
--- pa-protos.h.orig Sun Nov 11 12:45:02 2001
+++ pa-protos.h Thu Jan 10 21:48:40 2002
@@ -83,6 +83,7 @@
extern int arith32_operand PARAMS ((rtx, enum machine_mode));
extern int uint32_operand PARAMS ((rtx, enum machine_mode));
extern int reg_or_nonsymb_mem_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_before_reload_operand PARAMS ((rtx, enum machine_mode));
extern int reg_or_0_operand PARAMS ((rtx, enum machine_mode));
extern int reg_or_0_or_nonsymb_mem_operand PARAMS ((rtx, enum machine_mode));
extern int pre_cint_operand PARAMS ((rtx, enum machine_mode));
--- pa.c.orig Tue Jan 8 11:09:41 2002
+++ pa.c Thu Jan 10 22:37:02 2002
@@ -364,6 +364,28 @@
return 0;
}
+/* Return 1 if the operand is a register operand or a non-symbolic memory
+ operand after reload. This predicate is used for branch patterns that
+ internally handle register reloading. We need to accept non-symbolic
+ memory operands after reload to ensure that the pattern is still valid
+ if reload didn't find a hard register for the operand. */
+
+int
+reg_before_reload_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (register_operand (op, mode))
+ return 1;
+
+ if (reload_completed
+ && memory_operand (op, mode)
+ && ! symbolic_memory_operand (op, mode))
+ return 1;
+
+ return 0;
+}
+
/* Accept any constant that can be moved in one instructions into a
general register. */
int
--- pa.md.orig Wed Jan 9 16:04:49 2002
+++ pa.md Thu Jan 10 21:51:28 2002
@@ -6589,7 +6589,7 @@
(if_then_else
(match_operator 2 "comparison_operator"
[(plus:SI
- (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "+!r,!*f,!*m")
+ (match_operand:SI 0 "reg_before_reload_operand" "+!r,!*f,*m")
(match_operand:SI 1 "int5_operand" "L,L,L"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
@@ -6646,7 +6646,7 @@
[(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
- (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
+ (set (match_operand:SI 0 "reg_before_reload_operand" "=!r,!*f,*m,!*q")
(match_dup 1))]
""
"* return output_movb (operands, insn, which_alternative, 0); "
@@ -6692,7 +6692,7 @@
[(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
(pc)
(label_ref (match_operand 3 "" ""))))
- (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
+ (set (match_operand:SI 0 "reg_before_reload_operand" "=!r,!*f,*m,!*q")
(match_dup 1))]
""
"* return output_movb (operands, insn, which_alternative, 1); "
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 15:22 ` Fix predicate in decrement_and_branch_until_zero pattern on PA John David Anglin
@ 2002-01-21 15:24 ` Richard Henderson
2002-01-21 15:29 ` law
2002-01-21 15:32 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2002-01-21 15:24 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
On Mon, Jan 21, 2002 at 06:20:27PM -0500, John David Anglin wrote:
> * pa.md (decrement_and_branch_until_zero, movb): Use it. Change "!*m"
> contraints to "*m".
I think this is exactly wrong, and that you should be preferring r.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 15:24 ` Richard Henderson
@ 2002-01-21 15:29 ` law
2002-01-21 16:24 ` Richard Henderson
2002-01-21 15:32 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: law @ 2002-01-21 15:29 UTC (permalink / raw)
To: Richard Henderson; +Cc: John David Anglin, gcc-patches
In message <20020121152334.E19469@redhat.com>, Richard Henderson writes:
> On Mon, Jan 21, 2002 at 06:20:27PM -0500, John David Anglin wrote:
> > * pa.md (decrement_and_branch_until_zero, movb): Use it. Change "!*m"
> > contraints to "*m".
>
> I think this is exactly wrong, and that you should be preferring r.
Are you sure? Remember, we have to prefer memory operands for outputs during
reloading because this is a jump insn.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 15:29 ` law
@ 2002-01-21 16:24 ` Richard Henderson
0 siblings, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2002-01-21 16:24 UTC (permalink / raw)
To: law; +Cc: John David Anglin, gcc-patches
On Mon, Jan 21, 2002 at 04:24:25PM -0700, law@redhat.com wrote:
> Are you sure? Remember, we have to prefer memory operands for outputs during
> reloading because this is a jump insn.
No, we just have to handle them. We don't have to prefer them.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 15:24 ` Richard Henderson
2002-01-21 15:29 ` law
@ 2002-01-21 15:32 ` John David Anglin
2002-01-21 16:27 ` Richard Henderson
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-21 15:32 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, law
> On Mon, Jan 21, 2002 at 06:20:27PM -0500, John David Anglin wrote:
> > * pa.md (decrement_and_branch_until_zero, movb): Use it. Change "!*m"
> > contraints to "*m".
>
> I think this is exactly wrong, and that you should be preferring r.
Isn't 'r' still preferred if a reload isn't needed? The predicate
ensures that the operand is always a register operand before reload.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 15:32 ` John David Anglin
@ 2002-01-21 16:27 ` Richard Henderson
2002-01-21 21:58 ` John David Anglin
2002-01-21 22:48 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2002-01-21 16:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
On Mon, Jan 21, 2002 at 06:29:42PM -0500, John David Anglin wrote:
> Isn't 'r' still preferred if a reload isn't needed? The predicate
> ensures that the operand is always a register operand before reload.
Sorry, "penalized" not "preferred". "r" is preferred because of
lack of "*", but should also not be penalized with "!".
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 16:27 ` Richard Henderson
@ 2002-01-21 21:58 ` John David Anglin
2002-01-21 22:21 ` Richard Henderson
2002-01-21 22:48 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-21 21:58 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, law
> On Mon, Jan 21, 2002 at 06:29:42PM -0500, John David Anglin wrote:
> > Isn't 'r' still preferred if a reload isn't needed? The predicate
> > ensures that the operand is always a register operand before reload.
>
> Sorry, "penalized" not "preferred". "r" is preferred because of
> lack of "*", but should also not be penalized with "!".
It was my understanding that "!" was used with "r" to prevent an
output reload. The documentation states:
Disparage severely the alternative that the @samp{!} appears in.
This alternative can still be used if it fits without reloading,
but if reloading is needed, some other alternative will be used.
We want to suppress reload from creating an output reload for the
insns using these patterns because they are for jump insns that only
can have one machine insn in the delay slot. The output code
for theses patterns is supposed to handle any necessary reloads
itself. If "!" is removed from the "r" constraint and added to
the "m" constrain, then it appears reload will choose the "r"
alternative with whatever reloads are needed rather than the "m"
alternative with no reloads. This would be wrong and cause
incorrect code to be generated.
The goal in writing the constraint was to only penalize "r" if
a reload was needed. We want the "r" alternative selected if no
reload is required. Otherwise, we want "m" selected. We don't
want any reloads for "m" either but I don't think this happens
when you start with a register operand. How do we express this?
If "!" always severely disparages an alternative, then probably
the "!" should be put back on the "m" alternative so that all
alternatives are equally disparaged. However, reload then
may be left with no alternative to select if you believe the
documentation.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Fix predicate in decrement_and_branch_until_zero pattern on PA
2002-01-21 16:27 ` Richard Henderson
2002-01-21 21:58 ` John David Anglin
@ 2002-01-21 22:48 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-01-21 22:48 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches, law
> On Mon, Jan 21, 2002 at 06:29:42PM -0500, John David Anglin wrote:
> > Isn't 'r' still preferred if a reload isn't needed? The predicate
> > ensures that the operand is always a register operand before reload.
>
> Sorry, "penalized" not "preferred". "r" is preferred because of
> lack of "*", but should also not be penalized with "!".
The following simple program compiled at -O2 on the PA with the current
mainline code uses the decrement_and_branch_until_zero pattern.
main ()
{
int i;
int j=0;
for (i =0; i < 10; i++) j=j+1;
exit (j);
}
The loop variable after combine ends up in a register (%r19) and not a
memory location. Thus, the interpretation that "!" always severely
disparages an alternative is not correct.
On a different subject, I don't know why the loop wasn't eliminated
as the compiler determined the final result for j.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix loop.c for targets without HAVE_prefetch
[not found] <no.id>
` (67 preceding siblings ...)
2002-01-21 15:22 ` Fix predicate in decrement_and_branch_until_zero pattern on PA John David Anglin
@ 2002-01-22 23:30 ` John David Anglin
2002-01-23 12:15 ` H . J . Lu
2002-01-28 9:28 ` gcc failed to bootstrap on Linux/mipsel John David Anglin
` (94 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-22 23:30 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, hjl
> > This patch
> >
> > http://gcc.gnu.org/ml/gcc-patches/2002-01/msg01393.html
causes a new warning when PREFETCH_NOT_ALWAYS is 0:
../../gcc/gcc/loop.c:3573: warning: `check_store' defined but not used
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix loop.c for targets without HAVE_prefetch
2002-01-22 23:30 ` PATCH: Fix loop.c for targets without HAVE_prefetch John David Anglin
@ 2002-01-23 12:15 ` H . J . Lu
0 siblings, 0 replies; 521+ messages in thread
From: H . J . Lu @ 2002-01-23 12:15 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Wed, Jan 23, 2002 at 12:23:45AM -0500, John David Anglin wrote:
> > > This patch
> > >
> > > http://gcc.gnu.org/ml/gcc-patches/2002-01/msg01393.html
>
> causes a new warning when PREFETCH_NOT_ALWAYS is 0:
>
> ../../gcc/gcc/loop.c:3573: warning: `check_store' defined but not used
>
Here is a new patch.
H.J.
----
2002-01-23 H.J. Lu (hjl@gnu.org)
* loop.c (HAVE_prefetch): Don't define if not defined.
(CODE_FOR_prefetch): Removed.
(gen_prefetch): Removed.
(check_store): Define only if HAVE_prefetch is
defined.
(emit_prefetch_instructions): Likewise.
(rtx_equal_for_prefetch_p): Likewise.
(remove_constant_addition): Likewise.
--- gcc/loop.c.prefetch Wed Jan 23 09:00:37 2002
+++ gcc/loop.c Wed Jan 23 12:08:49 2002
@@ -63,11 +63,6 @@ Software Foundation, 59 Temple Place - S
#ifndef PREFETCH_BLOCK
#define PREFETCH_BLOCK 32
#endif
-#ifndef HAVE_prefetch
-#define HAVE_prefetch 0
-#define CODE_FOR_prefetch 0
-#define gen_prefetch(a,b,c) (abort(), NULL_RTX)
-#endif
/* Give up the prefetch optimizations once we exceed a given threshhold.
It is unlikely that we would be able to optimize something in a loop
@@ -352,7 +347,6 @@ static rtx loop_insn_sink_or_swim PARAMS
static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
static void loop_delete_insns PARAMS ((rtx, rtx));
-static HOST_WIDE_INT remove_constant_addition PARAMS ((rtx *));
void debug_ivs PARAMS ((const struct loop *));
void debug_iv_class PARAMS ((const struct iv_class *));
void debug_biv PARAMS ((const struct induction *));
@@ -3566,6 +3560,8 @@ struct check_store_data
int mem_write;
};
+#ifdef HAVE_prefetch
+static HOST_WIDE_INT remove_constant_addition PARAMS ((rtx *));
static void check_store PARAMS ((rtx, rtx, void *));
static void emit_prefetch_instructions PARAMS ((struct loop *));
static int rtx_equal_for_prefetch_p PARAMS ((rtx, rtx));
@@ -4069,6 +4065,7 @@ emit_prefetch_instructions (loop)
return;
}
+#endif
\f
/* A "basic induction variable" or biv is a pseudo reg that is set
(within this loop) only by incrementing or decrementing it. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
[not found] <no.id>
` (68 preceding siblings ...)
2002-01-22 23:30 ` PATCH: Fix loop.c for targets without HAVE_prefetch John David Anglin
@ 2002-01-28 9:28 ` John David Anglin
2002-01-28 11:10 ` Richard Henderson
2002-02-04 13:02 ` Define _GNU_SOURCE in unwind-dw2-fde-glibc.c John David Anglin
` (93 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-28 9:28 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
> > for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> > if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
> > && rtx_varies_p (gen_rtx_REG (Pmode, i), /*for_alias=*/1))
I see the problem. The comment for the above is incorrect:
/* Invalidate all hard registers clobbered by calls. With one exception:
a call-clobbered PIC register is still function-invariant for our
purposes, since we can hoist any PIC calculations out of the loop.
Thus the call to rtx_varies_p. */
You can hoist any insns involving the PIC register except those
that set it.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 9:28 ` gcc failed to bootstrap on Linux/mipsel John David Anglin
@ 2002-01-28 11:10 ` Richard Henderson
2002-01-28 11:18 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-01-28 11:10 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
On Mon, Jan 28, 2002 at 12:04:49PM -0500, John David Anglin wrote:
> > > for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> > > if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
> > > && rtx_varies_p (gen_rtx_REG (Pmode, i), /*for_alias=*/1))
>
> I see the problem. The comment for the above is incorrect:
>
> /* Invalidate all hard registers clobbered by calls. With one exception:
> a call-clobbered PIC register is still function-invariant for our
> purposes, since we can hoist any PIC calculations out of the loop.
> Thus the call to rtx_varies_p. */
>
> You can hoist any insns involving the PIC register except those
> that set it.
Bugger all. Well, I guess we'll just have to do for_alias=0
for now. I don't think we can fix this properly for 3.1.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 11:10 ` Richard Henderson
@ 2002-01-28 11:18 ` John David Anglin
2002-01-28 11:19 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-28 11:18 UTC (permalink / raw)
To: Richard Henderson; +Cc: geoffk, gcc-patches
> > You can hoist any insns involving the PIC register except those
> > that set it.
>
> Bugger all. Well, I guess we'll just have to do for_alias=0
> for now. I don't think we can fix this properly for 3.1.
Is this obviously wrong? I'm trying it now.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-28 John David Anglin <dave@hiauly1.hia.nrc.ca>
* loop.c (scan_loop): Don't hoist insns that set the pic offset table
register if PIC_OFFSET_TABLE_REG_CALL_CLOBBERED is defined and we are
generating PIC code.
--- loop.c.orig Fri Jan 25 00:04:25 2002
+++ loop.c Mon Jan 28 13:49:58 2002
@@ -762,6 +762,9 @@
if (GET_CODE (p) == INSN
&& (set = single_set (p))
&& GET_CODE (SET_DEST (set)) == REG
+#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+ && (! flag_pic || SET_DEST (set) != pic_offset_table_rtx)
+#endif
&& ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
{
int tem1 = 0;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 11:18 ` John David Anglin
@ 2002-01-28 11:19 ` Richard Henderson
2002-01-28 11:39 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-01-28 11:19 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
On Mon, Jan 28, 2002 at 02:12:40PM -0500, John David Anglin wrote:
> +#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
> + && (! flag_pic || SET_DEST (set) != pic_offset_table_rtx)
> +#endif
Well flag_pic definitely shouldn't be here. ia64 for instance
uses pic_offset_table_rtx all the time.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 11:19 ` Richard Henderson
@ 2002-01-28 11:39 ` John David Anglin
2002-01-28 12:07 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-28 11:39 UTC (permalink / raw)
To: Richard Henderson; +Cc: geoffk, gcc-patches
> On Mon, Jan 28, 2002 at 02:12:40PM -0500, John David Anglin wrote:
> > +#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
> > + && (! flag_pic || SET_DEST (set) != pic_offset_table_rtx)
> > +#endif
>
> Well flag_pic definitely shouldn't be here. ia64 for instance
> uses pic_offset_table_rtx all the time.
What about testing to see if the PIC_OFFSET_TABLE_REGNUM isn't a fixed
register?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 11:39 ` John David Anglin
@ 2002-01-28 12:07 ` Richard Henderson
2002-01-28 16:04 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2002-01-28 12:07 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
On Mon, Jan 28, 2002 at 02:31:51PM -0500, John David Anglin wrote:
> What about testing to see if the PIC_OFFSET_TABLE_REGNUM isn't a fixed
> register?
I guess that would be ok. Actualy, should change gen_reg_RTX
to check that and have loop test vs pic_offset_table_rtx.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 12:07 ` Richard Henderson
@ 2002-01-28 16:04 ` John David Anglin
2002-01-28 17:00 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-01-28 16:04 UTC (permalink / raw)
To: Richard Henderson; +Cc: geoffk, gcc-patches
> > What about testing to see if the PIC_OFFSET_TABLE_REGNUM isn't a fixed
> > register?
>
> I guess that would be ok. Actualy, should change gen_reg_RTX
> to check that and have loop test vs pic_offset_table_rtx.
This fixes cxa_vec.C and several hundred objc failures. Tested on
hppa2.0w-hp-hpux11.11.
OK?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-01-28 John David Anglin <dave@hiauly1.hia.nrc.ca>
* emit-rtl.c (gen_rtx_REG): Check that the PIC_OFFSET_TABLE_REGNUM
is a fixed register before returning pic_offset_table_rtx.
* loop.c (scan_loop): Don't hoist insns that set pic_offset_table_rtx
when PIC_OFFSET_TABLE_REG_CALL_CLOBBERED is defined.
--- emit-rtl.c.orig Mon Jan 28 12:11:37 2002
+++ emit-rtl.c Mon Jan 28 15:06:47 2002
@@ -411,7 +411,8 @@
if (regno == RETURN_ADDRESS_POINTER_REGNUM)
return return_address_pointer_rtx;
#endif
- if (regno == PIC_OFFSET_TABLE_REGNUM)
+ if (regno == PIC_OFFSET_TABLE_REGNUM
+ && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
return pic_offset_table_rtx;
if (regno == STACK_POINTER_REGNUM)
return stack_pointer_rtx;
--- loop.c.orig Fri Jan 25 00:04:25 2002
+++ loop.c Mon Jan 28 15:00:03 2002
@@ -762,6 +762,9 @@
if (GET_CODE (p) == INSN
&& (set = single_set (p))
&& GET_CODE (SET_DEST (set)) == REG
+#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+ && SET_DEST (set) != pic_offset_table_rtx
+#endif
&& ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
{
int tem1 = 0;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc failed to bootstrap on Linux/mipsel
2002-01-28 16:04 ` John David Anglin
@ 2002-01-28 17:00 ` Richard Henderson
0 siblings, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2002-01-28 17:00 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
On Mon, Jan 28, 2002 at 06:56:56PM -0500, John David Anglin wrote:
> * emit-rtl.c (gen_rtx_REG): Check that the PIC_OFFSET_TABLE_REGNUM
> is a fixed register before returning pic_offset_table_rtx.
> * loop.c (scan_loop): Don't hoist insns that set pic_offset_table_rtx
> when PIC_OFFSET_TABLE_REG_CALL_CLOBBERED is defined.
Ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Define _GNU_SOURCE in unwind-dw2-fde-glibc.c
[not found] <no.id>
` (69 preceding siblings ...)
2002-01-28 9:28 ` gcc failed to bootstrap on Linux/mipsel John David Anglin
@ 2002-02-04 13:02 ` John David Anglin
2002-02-04 13:43 ` Richard Henderson
2002-02-05 21:17 ` Add missing predicate to PREDICATE_CODES on PA John David Anglin
` (92 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-04 13:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> I had a problem building unwind-dw2-fde-glibc.c under hppa-linux. The
> header <link.h> needs _USE_GNU defined to define:
Argh!
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-02-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* unwind-dw2-fde-glibc.c: Define _GNU_SOURCE if not defined.
--- unwind-dw2-fde-glibc.c.orig Thu Jan 10 18:11:48 2002
+++ unwind-dw2-fde-glibc.c Thu Jan 24 15:10:08 2002
@@ -29,6 +29,10 @@
segment and dl_iterate_phdr to avoid register/deregister calls at
DSO load/unload. */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
#include "auto-host.h" /* For HAVE_LD_EH_FRAME_HDR. */
#include "tconfig.h"
#include <stddef.h>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Add missing predicate to PREDICATE_CODES on PA
[not found] <no.id>
` (70 preceding siblings ...)
2002-02-04 13:02 ` Define _GNU_SOURCE in unwind-dw2-fde-glibc.c John David Anglin
@ 2002-02-05 21:17 ` John David Anglin
2002-02-05 23:20 ` Graham Stott
2002-02-16 16:12 ` Don't use lib2funcs.asm " John David Anglin
` (91 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-05 21:17 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> This eliminates a few warnings compiling pa.c. Tested on hppa2.0w-hp-hpux11.11.
Did it again!
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-02-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.h (PREDICATE_CODES): Add reg_before_reload_operand.
Index: config/pa/pa.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.h,v
retrieving revision 1.135
diff -c -3 -p -r1.135 pa.h
*** config/pa/pa.h 4 Feb 2002 21:37:14 -0000 1.135
--- config/pa/pa.h 5 Feb 2002 22:34:45 -0000
*************** while (0)
*** 1925,1930 ****
--- 1925,1931 ----
CONST_DOUBLE, CONST, HIGH, CONSTANT_P_RTX}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"symbolic_memory_operand", {SUBREG, MEM}}, \
+ {"reg_before_reload_operand", {SUBREG, MEM}}, \
{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
{"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, MEM, CONST_INT, \
CONST_DOUBLE}}, \
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Add missing predicate to PREDICATE_CODES on PA
2002-02-05 21:17 ` Add missing predicate to PREDICATE_CODES on PA John David Anglin
@ 2002-02-05 23:20 ` Graham Stott
2002-02-06 9:06 ` John David Anglin
2002-02-10 12:30 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Graham Stott @ 2002-02-05 23:20 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
John,
John David Anglin wrote:
>
> > This eliminates a few warnings compiling pa.c. Tested on hppa2.0w-hp-hpux11.11.
>
> Did it again!
>
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2002-02-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa.h (PREDICATE_CODES): Add reg_before_reload_operand.
>
> Index: config/pa/pa.h
> ===================================================================
> RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.h,v
> retrieving revision 1.135
> diff -c -3 -p -r1.135 pa.h
> *** config/pa/pa.h 4 Feb 2002 21:37:14 -0000 1.135
> --- config/pa/pa.h 5 Feb 2002 22:34:45 -0000
> *************** while (0)
> *** 1925,1930 ****
> --- 1925,1931 ----
> CONST_DOUBLE, CONST, HIGH, CONSTANT_P_RTX}}, \
> {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
> {"symbolic_memory_operand", {SUBREG, MEM}}, \
> + {"reg_before_reload_operand", {SUBREG, MEM}}, \
> {"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
> {"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, MEM, CONST_INT, \
> CONST_DOUBLE}}, \
I believe reg_before_reload_operand also accepts a REG so I think the list
of rtx codes should also include REG.
Graham
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Add missing predicate to PREDICATE_CODES on PA
2002-02-05 23:20 ` Graham Stott
@ 2002-02-06 9:06 ` John David Anglin
2002-02-10 12:30 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-02-06 9:06 UTC (permalink / raw)
To: Graham Stott; +Cc: gcc-patches
> > {"symbolic_memory_operand", {SUBREG, MEM}}, \
> > + {"reg_before_reload_operand", {SUBREG, MEM}}, \
> I believe reg_before_reload_operand also accepts a REG so I think the list
> of rtx codes should also include REG.
Thanks for noticing this. I did a cut and paste from symbolic_memory_operand
which also has the same problem.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Add missing predicate to PREDICATE_CODES on PA
2002-02-05 23:20 ` Graham Stott
2002-02-06 9:06 ` John David Anglin
@ 2002-02-10 12:30 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-02-10 12:30 UTC (permalink / raw)
To: Graham Stott; +Cc: gcc-patches
> I believe reg_before_reload_operand also accepts a REG so I think the list
> of rtx codes should also include REG.
I changed reg_before_reload_operand to not accept SUBREG codes since
register_operand accepts them before reload. They require an unwanted
reload. The predicate codes for reg_before_reload_operand are now
REG and MEM.
Tested on hppa2.0w-hp-hpux11.11.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-02-10 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.c (reg_before_reload_operand): Don't accept a SUBREG operand.
* pa.h (PREDICATE_CODES): Adjust codes for reg_before_reload_operand.
--- pa.c.orig Fri Feb 8 11:58:09 2002
+++ pa.c Fri Feb 8 12:22:13 2002
@@ -387,6 +387,10 @@
register rtx op;
enum machine_mode mode;
{
+ /* Don't accept a SUBREG since it will need a reload. */
+ if (GET_CODE (op) == SUBREG)
+ return 0;
+
if (register_operand (op, mode))
return 1;
--- pa.h.orig Wed Feb 6 11:27:43 2002
+++ pa.h Fri Feb 8 12:23:27 2002
@@ -1925,7 +1925,7 @@
CONST_DOUBLE, CONST, HIGH, CONSTANT_P_RTX}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"symbolic_memory_operand", {SUBREG, MEM}}, \
- {"reg_before_reload_operand", {SUBREG, MEM}}, \
+ {"reg_before_reload_operand", {REG, MEM}}, \
{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
{"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, MEM, CONST_INT, \
CONST_DOUBLE}}, \
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
[not found] <no.id>
` (71 preceding siblings ...)
2002-02-05 21:17 ` Add missing predicate to PREDICATE_CODES on PA John David Anglin
@ 2002-02-16 16:12 ` John David Anglin
2002-02-16 17:56 ` law
2002-02-18 12:30 ` John David Anglin
` (90 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-16 16:12 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2002-02-16 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa/t-pa (LIB2FUNCS_EXTRA): Don't build lib2funcs.asm.
> * pa/t-pro (LIB2FUNCS_EXTRA): Likewise.
> * som.h (DO_GLOBAL_DTORS_BODY): Delete define.
Revert. It's a gdb hook.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-16 16:12 ` Don't use lib2funcs.asm " John David Anglin
@ 2002-02-16 17:56 ` law
2002-02-16 19:45 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2002-02-16 17:56 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message <200202162232.g1GMW4xp009467@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> > 2002-02-16 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * pa/t-pa (LIB2FUNCS_EXTRA): Don't build lib2funcs.asm.
> > * pa/t-pro (LIB2FUNCS_EXTRA): Likewise.
> > * som.h (DO_GLOBAL_DTORS_BODY): Delete define.
>
> Revert. It's a gdb hook.
Correct. It's needed for inferior function calls.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-16 17:56 ` law
@ 2002-02-16 19:45 ` John David Anglin
2002-02-17 9:02 ` law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-16 19:45 UTC (permalink / raw)
To: law; +Cc: gcc-patches
> Correct. It's needed for inferior function calls.
I had hoped to get rid of it since it's one of those nasty milli routines.
Inferior calls don't seem to work with gdb under hppa-linux if I understand
correctly. For example if I type "p func ()", gdb just crashes. I also
can't step into functions although single stepping does work. So, maybe
this function is needed with linux?
At the moment, I am trying to get frame notes working. I am still trying
to find out how to handle parallels. The suggestion from Olivier Hainque
didn't seem to work. The stack frame adjustment still isn't getting
recorded correctly so it seems. I believe that ARG_POINTER_CFA_OFFSET(FNDECL)
needs to be defined to 0. However, when the context is set for rp,
The address is off by the amount of the stack adjustment (this is for
__cxa_throw).
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-16 19:45 ` John David Anglin
@ 2002-02-17 9:02 ` law
2002-02-17 11:29 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2002-02-17 9:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
In message <200202170051.g1H0p51Z009585@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> > Correct. It's needed for inferior function calls.
>
> I had hoped to get rid of it since it's one of those nasty milli routines.
> Inferior calls don't seem to work with gdb under hppa-linux if I understand
> correctly. For example if I type "p func ()", gdb just crashes. I also
> can't step into functions although single stepping does work. So, maybe
> this function is needed with linux?
It is needed for hpux only, it should not be needed for linux.
It was created because the HP dynamic linker has some sanity checks in it
to verify that a return address is actually within a mapped text segment.
These checks triggered when doing an inferior call from gdb into routines
in shared libraries (such as malloc) because the inferior call trampoline
lives on the stack (so the return address is actually a stack location).
So we created __gcc_plt_call which we arrange to link into every binary
compiled with GCC, thus providing us with a location in a mapped text
segment that we can use for inferior function calls.
hppa-linux's dynamic linker likely doesn't have the silly sanity checks
and thus shouldn't need __gcc_plt_call.
As to why inferior calls don't work -- no clue. You might ask Alan M. how
much GDB stuff was working for PA-linux when he left Linuxcare. I can tell
you that getting inferior calls to work on the PA is a major PITA.
> At the moment, I am trying to get frame notes working. I am still trying
> to find out how to handle parallels. The suggestion from Olivier Hainque
> didn't seem to work. The stack frame adjustment still isn't getting
> recorded correctly so it seems. I believe that ARG_POINTER_CFA_OFFSET(FNDEC
> L)
Hmmm, there is some specific magic to deal with PARALLELS on prologue
insns. I think you set RTX_FRAME_RELATED_P on the PARALLEL and each item
within the PARALLEL. Or something like that. You can probably find an
example in one of the other target config files.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-17 9:02 ` law
@ 2002-02-17 11:29 ` John David Anglin
2002-02-18 3:21 ` Olivier Hainque
2002-02-18 12:18 ` Hans-Peter Nilsson
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2002-02-17 11:29 UTC (permalink / raw)
To: law; +Cc: gcc-patches
> As to why inferior calls don't work -- no clue. You might ask Alan M. how
> much GDB stuff was working for PA-linux when he left Linuxcare. I can tell
> you that getting inferior calls to work on the PA is a major PITA.
It was in a pretty rock state (ie., didn't work at all). I have worked
out a couple of hacks and now I have at least a partially functional gdb.
It's a little better that hppa64-hpux. The most important fix was the
initialization of the register cache. The problem is that it is done before
the arch initialize and the arch needs to be inited for REGISTER_BYTE.
This may be a problem for hppa64-hpux because in a backtrace the
arguments are garbled. Under, hppa64-hpux I have been using the HP
version of gdb64 but it doesn't recognize debug symbols in a gcc compiled
object (it works for a HP compiled object). However, it does do backtraces
and print registers ok.
> > At the moment, I am trying to get frame notes working. I am still trying
> > to find out how to handle parallels. The suggestion from Olivier Hainque
> > didn't seem to work. The stack frame adjustment still isn't getting
> > recorded correctly so it seems. I believe that ARG_POINTER_CFA_OFFSET(FNDEC
> > L)
> Hmmm, there is some specific magic to deal with PARALLELS on prologue
> insns. I think you set RTX_FRAME_RELATED_P on the PARALLEL and each item
> within the PARALLEL. Or something like that. You can probably find an
> example in one of the other target config files.
Yes, looked at dwarf2out.c to see what it expects. I found some more
coding problems with PARALLEL's in the register save code and also that
the EH_RETURN_DATA_REGNO registers need to be saved if the function
calls eh_return. The code still isn't quite right and needs some
reorganization, but my test code now throws. However, there is a
problem in the catch. Another day or two and I think that it will work.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-17 11:29 ` John David Anglin
@ 2002-02-18 3:21 ` Olivier Hainque
2002-02-18 9:26 ` John David Anglin
2002-02-18 12:18 ` Hans-Peter Nilsson
1 sibling, 1 reply; 521+ messages in thread
From: Olivier Hainque @ 2002-02-18 3:21 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
> Yes, looked at dwarf2out.c to see what it expects. I found some more
> coding problems with PARALLEL's in the register save code and also that
> the EH_RETURN_DATA_REGNO registers need to be saved if the function
> calls eh_return.
Indeed. This is part of what we use for pa-hpux that I mentioned was not in
a submittable state yet.
> However, there is a problem in the catch.
It is very likely that what you are seeing is related to some problems we
also "experimented". In the current state of things, we have added an
eh_return pattern to the machine description and a "for_eh_return" argument
to hppa_expand_epilogue.
Below is part of our patch that might well be of interest for your immediate
troubles. This part is not applicable as is but should give an idea of the
kind of things we had to add to get things working (basically, emitting the
stack adjustment and not restoring r2 in eh return epilogue).
I did not include/submit the complete version yet because it still needs
further testing, comments and partial reorg, but if you think it could be
useful to see, I'd be happy to post and discuss it.
Kind Regards,
Olivier
*************** pa_output_function_epilogue (file, size)
*** 3390,3409 ****
}
void
! hppa_expand_epilogue ()
{
rtx tmpreg;
int offset, i;
int merge_sp_adjust_with_load = 0;
int ret_off = 0;
/* We will use this often. */
tmpreg = gen_rtx_REG (word_mode, 1);
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
! if (regs_ever_live [2])
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
--- 3504,3533 ----
}
void
! hppa_expand_epilogue (int for_eh_return)
{
rtx tmpreg;
int offset, i;
int merge_sp_adjust_with_load = 0;
int ret_off = 0;
+ /* Compute the frame sizes now if running for eh_return since expand
+ prologue has not been called yet. */
+ if (for_eh_return)
+ {
+ int size = get_frame_size ();
+
+ local_fsize = adjusted_frame_size_for (size);
+ actual_fsize = compute_frame_size (size, &save_fregs);
+ }
+
/* We will use this often. */
tmpreg = gen_rtx_REG (word_mode, 1);
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
! if ((regs_ever_live [2] || flag_exceptions) && !for_eh_return)
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
*************** hppa_expand_epilogue ()
*** 3524,3531 ****
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
! if (ret_off != 0)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
}
rtx
--- 3686,3703 ----
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
! if (ret_off != 0 && !for_eh_return)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
+
+ /* Emit the stack adjustment for the jump to handler case. */
+ if (for_eh_return)
+ {
+ emit_move_insn
+ (gen_rtx_REG (Pmode, STACK_POINTER_REGNUM),
+ gen_rtx_MINUS (Pmode,
+ gen_rtx_REG (Pmode, STACK_POINTER_REGNUM),
+ EH_RETURN_STACKADJ_RTX));
+ }
}
rtx
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-18 3:21 ` Olivier Hainque
@ 2002-02-18 9:26 ` John David Anglin
2002-02-18 10:23 ` Olivier Hainque
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-18 9:26 UTC (permalink / raw)
To: Olivier Hainque; +Cc: law, gcc-patches
> It is very likely that what you are seeing is related to some problems we
> also "experimented". In the current state of things, we have added an
> eh_return pattern to the machine description and a "for_eh_return" argument
> to hppa_expand_epilogue.
Thanks for the input. The stack adjust was one thing that was missing.
Last night, I arrived at a set of modifications that allow the "stdexceptions"
test in libstdc++ to PASS when linked statically. It still doesn't work
when linked with a shared libstdc++. There were also more issues with the
frame note code and saving and restoring the eh data registers.
I believe that we need an eh_return pattern and use an interspace jump
to return from shared code. I also need to figure out if an eh_return
can return a value. If it can then the data registers need to be revised.
Now on the PA, external calls usually go via a stub. One of the functions
of the stub is to message the outgoing arguments and the return value
so that the caller and callee agree on their location. There could be
a problem with return values because I suspect we bypass the stub on
an eh_return.
I enclosed my latest work. Comments appreciated. I am going to try
to looked at the shared return today.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
Index: config/pa/pa-linux.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-linux.h,v
retrieving revision 1.12
diff -u -3 -p -r1.12 pa-linux.h
--- config/pa/pa-linux.h 15 Feb 2002 19:11:01 -0000 1.12
+++ config/pa/pa-linux.h 18 Feb 2002 04:32:28 -0000
@@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */
#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
#define DWARF2_ASM_LINE_DEBUG_INFO 1
#define DWARF2_UNWIND_INFO 1
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__hppa__ -Dlinux -Asystem=unix -Asystem=posix -Acpu=hppa -Amachine=hppa -Amachine=bigendian"
Index: config/pa/pa.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.md,v
retrieving revision 1.101
diff -u -3 -p -r1.101 pa.md
--- config/pa/pa.md 4 Feb 2002 21:05:25 -0000 1.101
+++ config/pa/pa.md 18 Feb 2002 04:32:29 -0000
@@ -7216,14 +7216,12 @@
;; restore the PIC register.
(define_expand "exception_receiver"
[(const_int 4)]
- "!TARGET_PORTABLE_RUNTIME && flag_pic"
+ "flag_pic"
"
{
- /* Load the PIC register from the stack slot (in our caller's
- frame). */
- emit_move_insn (pic_offset_table_rtx,
- gen_rtx_MEM (SImode,
- plus_constant (stack_pointer_rtx, -32)));
+ /* Restore the PIC register using hppa_pic_save_rtx (). The
+ PIC register is not saved in the frame in 64-bit ABI. */
+ emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
emit_insn (gen_blockage ());
DONE;
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.148
diff -u -3 -p -r1.148 pa.c
--- config/pa/pa.c 12 Feb 2002 15:21:04 -0000 1.148
+++ config/pa/pa.c 18 Feb 2002 04:32:30 -0000
@@ -55,18 +55,6 @@ Boston, MA 02111-1307, USA. */
#endif
#endif
-#if DO_FRAME_NOTES
-#define FRP(INSN) \
- do \
- { \
- rtx insn = INSN; \
- RTX_FRAME_RELATED_P (insn) = 1; \
- } \
- while (0)
-#else
-#define FRP(INSN) INSN
-#endif
-
#ifndef FUNC_BEGIN_PROLOG_LABEL
#define FUNC_BEGIN_PROLOG_LABEL "LFBP"
#endif
@@ -83,6 +71,7 @@ static int compute_movstrsi_length PARAM
static bool pa_assemble_integer PARAMS ((rtx, unsigned int, int));
static void remove_useless_addtr_insns PARAMS ((rtx, int));
static void store_reg PARAMS ((int, int, int));
+static void store_reg_modify PARAMS ((int, int, int));
static void load_reg PARAMS ((int, int, int));
static void set_reg_plus_d PARAMS ((int, int, int));
static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
@@ -2662,7 +2651,7 @@ output_ascii (file, p, size)
fputs ("\"\n\t.STRING \"", file);
chars_output = 0;
}
- fwrite (partial_output, 1, co, file);
+ fwrite (partial_output, 1, (size_t) co, file);
chars_output += co;
co = 0;
}
@@ -2933,6 +2922,50 @@ store_reg (reg, disp, base)
RTX_FRAME_RELATED_P (insn) = 1;
}
+/* Emit RTL to store REG at the memory location specified by BASE and then
+ add MOD to BASE. MOD must be <= 8k. */
+
+static void
+store_reg_modify (base, reg, mod)
+ int base, reg, mod;
+{
+ rtx insn, basereg, srcreg, delta;
+
+ if (! VAL_14_BITS_P (mod))
+ abort ();
+
+ basereg = gen_rtx_REG (Pmode, base);
+ srcreg = gen_rtx_REG (word_mode, reg);
+ delta = GEN_INT (mod);
+
+ insn = emit_insn (gen_post_store (basereg, srcreg, delta));
+ if (DO_FRAME_NOTES)
+ {
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* RTX_FRAME_RELATED_P must be set on each frame related set
+ in a parallel with more than one element. Don't set
+ RTX_FRAME_RELATED_P in the first set if reg is temporary
+ register 1. The effect of this operation is recorded in
+ the initial copy. */
+ if (reg != 1)
+ {
+ RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
+ RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+ }
+ else
+ {
+ /* The first element of a PARALLEL is always processed if it is
+ a SET. Thus, we need an expression list for this case. */
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, basereg,
+ gen_rtx_PLUS (word_mode, basereg, delta)),
+ REG_NOTES (insn));
+ }
+ }
+}
+
/* Emit RTL to set REG to the value specified by BASE+DISP.
Handle case where DISP > 8k by using the add_high_const patterns.
@@ -2981,6 +3014,18 @@ compute_frame_size (size, fregs_live)
of them at the same time. */
fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
+ /* If the current function calls __builtin_eh_return, then we need
+ to allocate stack space for registers that will hold data for
+ the exception handler. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i;
+
+ for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
+ continue;
+ fsize += i * UNITS_PER_WORD;
+ }
+
/* Account for space used by the callee general register saves. */
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
@@ -3108,7 +3153,7 @@ hppa_expand_prologue ()
int size = get_frame_size ();
int merge_sp_adjust_with_store = 0;
int i, offset;
- rtx tmpreg, size_rtx;
+ rtx insn, tmpreg;
gr_saved = 0;
fr_saved = 0;
@@ -3126,7 +3171,6 @@ hppa_expand_prologue ()
/* Compute a few things we will use often. */
tmpreg = gen_rtx_REG (word_mode, 1);
- size_rtx = GEN_INT (actual_fsize);
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp - 20 or sp - 16
@@ -3141,36 +3185,30 @@ hppa_expand_prologue ()
{
/* Copy the old frame pointer temporarily into %r1. Set up the
new stack pointer, then store away the saved old frame pointer
- into the stack at sp+actual_fsize and at the same time update
- the stack pointer by actual_fsize bytes. Two versions, first
+ into the stack at sp and at the same time update the stack
+ pointer by actual_fsize bytes. Two versions, first
handles small (<8k) frames. The second handles large (>=8k)
frames. */
- emit_move_insn (tmpreg, frame_pointer_rtx);
- FRP (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
- if (VAL_14_BITS_P (actual_fsize))
+ insn = emit_move_insn (tmpreg, frame_pointer_rtx);
+ if (DO_FRAME_NOTES)
{
- rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
- size_rtx));
- if (DO_FRAME_NOTES)
- {
- rtvec vec;
- RTX_FRAME_RELATED_P (insn) = 1;
- vec = gen_rtvec (2,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (word_mode,
- stack_pointer_rtx),
- frame_pointer_rtx),
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_PLUS (word_mode,
- stack_pointer_rtx,
- size_rtx)));
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SEQUENCE (VOIDmode, vec),
- REG_NOTES (insn));
- }
- }
+ /* We need to record the frame pointer save here since the
+ new frame pointer is set in the following insn. */
+ RTX_FRAME_RELATED_P (insn) = 1;
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (word_mode, stack_pointer_rtx),
+ frame_pointer_rtx),
+ REG_NOTES (insn));
+ }
+
+ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+ if (DO_FRAME_NOTES)
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ if (VAL_14_BITS_P (actual_fsize))
+ store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
else
{
/* It is incorrect to store the saved frame pointer at *sp,
@@ -3181,32 +3219,12 @@ hppa_expand_prologue ()
finish allocating the new frame. */
int adjust1 = 8192 - 64;
int adjust2 = actual_fsize - adjust1;
- rtx delta = GEN_INT (adjust1);
- rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
- delta));
- if (DO_FRAME_NOTES)
- {
- rtvec vec;
- RTX_FRAME_RELATED_P (insn) = 1;
- vec = gen_rtvec (2,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (word_mode,
- stack_pointer_rtx),
- frame_pointer_rtx),
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_PLUS (word_mode,
- stack_pointer_rtx,
- delta)));
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SEQUENCE (VOIDmode, vec),
- REG_NOTES (insn));
- }
+ store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
adjust2);
}
+
/* Prevent register spills from being scheduled before the
stack pointer is raised. Necessary as we will be storing
registers using the frame pointer as a base register, and
@@ -3236,7 +3254,27 @@ hppa_expand_prologue ()
was done earlier. */
if (frame_pointer_needed)
{
- for (i = 18, offset = local_fsize; i >= 4; i--)
+ offset = local_fsize;
+
+ /* Saving the EH return data registers in the frame is the simplest
+ way to get the frame unwind information emitted. We put them
+ just before the general registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ store_reg (regno, offset, FRAME_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3249,18 +3287,42 @@ hppa_expand_prologue ()
/* No frame pointer needed. */
else
{
- for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+ offset = local_fsize - actual_fsize;
+
+ /* Saving the EH return data registers in the frame is the simplest
+ way to get the frame unwind information emitted. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ /* If merge_sp_adjust_with_store is nonzero, then we can
+ optimize the first save. */
+ if (merge_sp_adjust_with_store)
+ {
+ store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
+ merge_sp_adjust_with_store = 0;
+ }
+ else
+ store_reg (regno, offset, STACK_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
if (merge_sp_adjust_with_store)
{
- rtx delta = GEN_INT (-offset);
+ store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
merge_sp_adjust_with_store = 0;
- FRP (emit_insn (gen_post_store (stack_pointer_rtx,
- gen_rtx_REG (word_mode, i),
- delta)));
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
@@ -3290,12 +3352,20 @@ hppa_expand_prologue ()
/* Floating point register store. */
if (save_fregs)
{
+ rtx base;
+
/* First get the frame or stack pointer to the start of the FP register
save area. */
if (frame_pointer_needed)
- set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+ {
+ set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+ base = frame_pointer_rtx;
+ }
else
- set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ {
+ set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ base = stack_pointer_rtx;
+ }
/* Now actually save the FP registers. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3313,9 +3383,7 @@ hppa_expand_prologue ()
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (DFmode,
- plus_constant (stack_pointer_rtx,
- offset)),
+ gen_rtx_MEM (DFmode, plus_constant (base, offset)),
reg),
REG_NOTES (insn));
}
@@ -3429,7 +3497,26 @@ hppa_expand_epilogue ()
/* General register restores. */
if (frame_pointer_needed)
{
- for (i = 18, offset = local_fsize; i >= 4; i--)
+ offset = local_fsize;
+
+ /* If the current function calls __builtin_eh_return, then we need
+ to restore the saved EH data registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ load_reg (regno, offset, FRAME_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3438,6 +3525,33 @@ hppa_expand_epilogue ()
}
else
{
+ offset = local_fsize - actual_fsize;
+
+ /* If the current function calls __builtin_eh_return, then we need
+ to restore the saved EH data registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ /* Only for the first load.
+ merge_sp_adjust_with_load holds the register load
+ with which we will merge the sp adjustment. */
+ if (merge_sp_adjust_with_load == 0
+ && local_fsize == 0
+ && VAL_14_BITS_P (-actual_fsize))
+ merge_sp_adjust_with_load = regno;
+ else
+ load_reg (regno, offset, STACK_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
@@ -3525,6 +3639,14 @@ hppa_expand_epilogue ()
}
else if (actual_fsize != 0)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
+
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ rtx sa = EH_RETURN_STACKADJ_RTX;
+ emit_insn (Pmode == SImode
+ ? gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
+ : gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
+ }
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-18 9:26 ` John David Anglin
@ 2002-02-18 10:23 ` Olivier Hainque
2002-02-18 10:27 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Olivier Hainque @ 2002-02-18 10:23 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
> Thanks for the input. The stack adjust was one thing that was missing.
A pleasure :) Nice to hear to input has been useful.
> Last night, I arrived at a set of modifications that allow the
> "stdexceptions" test in libstdc++ to PASS when linked statically.
Great !
> It still doesn't work when linked with a shared libstdc++. There were also
> more issues with the frame note code and saving and restoring the eh data
> registers.
>
> I believe that we need an eh_return pattern and use an interspace jump
> to return from shared code. I also need to figure out if an eh_return
> can return a value. If it can then the data registers need to be revised.
> Now on the PA, external calls usually go via a stub. One of the functions
> of the stub is to message the outgoing arguments and the return value
> so that the caller and callee agree on their location. There could be
> a problem with return values because I suspect we bypass the stub on
> an eh_return.
This is indeed not straightforward and is actually what still needs further
work in our setup.
> I am going to try to looked at the shared return today.
OK. Thanks a lot :)
> I enclosed my latest work. Comments appreciated.
I have not been able to read it in very detail yet and will do this shortly.
Something seems surprising at first sight, though :
> @@ -3525,6 +3639,14 @@ hppa_expand_epilogue ()
> }
> else if (actual_fsize != 0)
> set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
> +
> + if (DO_FRAME_NOTES && current_function_calls_eh_return)
> + {
> + rtx sa = EH_RETURN_STACKADJ_RTX;
> + emit_insn (Pmode == SImode
> + ? gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
> + : gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
> + }
>
> /* If we haven't restored %r2 yet (no frame pointer, and a stack
> frame greater than 8k), do so now. */
Isn't this doing the wrong thing in case a function calling
__builtin_eh_return returns through a regular return path (as
_Unwind_RaiseException might do) ?
Avoiding that was the first purpose of introducing an eh_return pattern, but
I may well be missing something.
Thanks for your feedback,
Kind Regards,
Olivier
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-18 10:23 ` Olivier Hainque
@ 2002-02-18 10:27 ` John David Anglin
2002-02-19 2:35 ` Olivier Hainque
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-18 10:27 UTC (permalink / raw)
To: Olivier Hainque; +Cc: law, gcc-patches
> > + if (DO_FRAME_NOTES && current_function_calls_eh_return)
> > + {
> > + rtx sa = EH_RETURN_STACKADJ_RTX;
> > + emit_insn (Pmode == SImode
> > + ? gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
> > + : gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
> > + }
> >
> > /* If we haven't restored %r2 yet (no frame pointer, and a stack
> > frame greater than 8k), do so now. */
>
> Isn't this doing the wrong thing in case a function calling
> __builtin_eh_return returns through a regular return path (as
> _Unwind_RaiseException might do) ?
I will investigate. This code appears in the rs6000 code. I think the answer
must be that sa is 0 in a normal return. In the light of day, this code
appears in the wrong place. In your code, you appear to subtract the stack
adjustment rather than add it.
> Avoiding that was the first purpose of introducing an eh_return pattern, but
> I may well be missing something.
You didn't send you epilogue and eh_return patterns. Could you?
I have integrated your frame size code into the epilogue for testing, although
it is adjusted to match what appears in hppa_expand_prologue and
compute_frame_size.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-18 10:27 ` John David Anglin
@ 2002-02-19 2:35 ` Olivier Hainque
0 siblings, 0 replies; 521+ messages in thread
From: Olivier Hainque @ 2002-02-19 2:35 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
> In your code, you appear to subtract the stack adjustment rather than add
> it.
Humm, right. Need to investigate a bit to see how it could work for you
one way and us the other way.
> I have integrated your frame size code into the epilogue for testing,
> although it is adjusted to match what appears in hppa_expand_prologue and
> compute_frame_size.
OK.
> You didn't send you epilogue and eh_return patterns. Could you?
Sure. For completeness and to avoid ambiguities, below is the whole patch we
currently apply, minus the hpux specific stuff. This is still ongoing work,
and all this is rather new to me, so ... :)
I still need to look at your way of doing things in deeper detail but won't
be able to do this today. BTW, I think it is possible to simplify (factorize)
a significant chunk of the prologue expansion.
Thanks a lot for your feedback and all,
Olivier
*** config/pa/pa.c.gcc Tue Feb 12 09:19:13 2002
--- config/pa/pa.c Tue Feb 12 09:34:15 2002
*************** Boston, MA 02111-1307, USA. */
*** 56,72 ****
#endif
#if DO_FRAME_NOTES
! #define FRP(INSN) \
! do \
! { \
! rtx insn = INSN; \
! RTX_FRAME_RELATED_P (insn) = 1; \
! } \
! while (0)
#else
#define FRP(INSN) INSN
#endif
#ifndef FUNC_BEGIN_PROLOG_LABEL
#define FUNC_BEGIN_PROLOG_LABEL "LFBP"
#endif
--- 56,98 ----
#endif
#if DO_FRAME_NOTES
!
! static rtx mark_frp PARAMS ((rtx, int));
!
! static rtx mark_frp (insn, go_down)
! rtx insn;
! int go_down;
! {
! rtx pattern = PATTERN (insn);
!
! RTX_FRAME_RELATED_P (insn) = 1;
!
! if (go_down
! && (GET_CODE (pattern) == PARALLEL
! || GET_CODE (pattern) == SEQUENCE))
! {
! int par_index;
! int limit = XVECLEN (pattern, 0);
!
! for (par_index = 0; par_index < limit; par_index++)
! {
! rtx x = XVECEXP (pattern, 0, par_index);
! RTX_FRAME_RELATED_P (x) = 1;
! }
! }
!
! return insn;
! }
!
! #define FRP(INSN) mark_frp (INSN, 0)
! #define DEEP_FRP(INSN) mark_frp (INSN, 1)
!
#else
#define FRP(INSN) INSN
+ #define DEEP_FRP(INSN) INSN
#endif
+
#ifndef FUNC_BEGIN_PROLOG_LABEL
#define FUNC_BEGIN_PROLOG_LABEL "LFBP"
#endif
*************** static void pa_output_function_epilogue
*** 89,94 ****
--- 115,123 ----
static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int pa_adjust_priority PARAMS ((rtx, int));
static int pa_issue_rate PARAMS ((void));
+ static int eh_return_data_regs PARAMS ((void));
+ static int adjusted_frame_size_for PARAMS ((int));
+
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
*************** set_reg_plus_d (reg, base, disp)
*** 2963,2968 ****
--- 2992,3025 ----
RTX_FRAME_RELATED_P (insn) = 1;
}
+ /* Compute the number of EH_RETURN data registers available, needed to
+ compute the frame size properly. */
+
+ static int
+ eh_return_data_regs (void)
+ {
+ int reg = 0;
+
+ while (EH_RETURN_DATA_REGNO (reg) != INVALID_REGNUM)
+ reg ++;
+
+ return reg;
+ }
+
+ /* Adjust the frame space required to be able to save the locals, which is
+ the base space necessary for them + the space possibly needed above for
+ the frame pointer and alignment filler. */
+
+ static int
+ adjusted_frame_size_for (int base_size)
+ {
+ return base_size +
+ ((base_size || frame_pointer_needed) ? STARTING_FRAME_OFFSET : 0);
+ }
+
+ /* Compute the space required for a complete frame requiring SIZE for
+ locals and count the number of fp regs live into FREGS_LIVE. */
+
int
compute_frame_size (size, fregs_live)
int size;
*************** compute_frame_size (size, fregs_live)
*** 2970,2982 ****
{
int i, fsize;
! /* Space for frame pointer + filler. If any frame is allocated
! we need to add this in because of STARTING_FRAME_OFFSET.
!
! Similar code also appears in hppa_expand_prologue. Change both
! of them at the same time. */
! fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
!
/* Account for space used by the callee general register saves. */
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
--- 3027,3039 ----
{
int i, fsize;
! /* Adjust the base size to account for a possible frame pointer area. */
! fsize = adjusted_frame_size_for (size);
!
! /* Account for space potentially used for the eh register saves. */
! if (current_function_calls_eh_return)
! fsize += eh_return_data_regs () * UNITS_PER_WORD;
!
/* Account for space used by the callee general register saves. */
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
*************** hppa_expand_prologue ()
*** 3110,3123 ****
fr_saved = 0;
save_fregs = 0;
! /* Allocate space for frame pointer + filler. If any frame is allocated
! we need to add this in because of STARTING_FRAME_OFFSET.
!
! Similar code also appears in compute_frame_size. Change both
! of them at the same time. */
! local_fsize = size + (size || frame_pointer_needed
! ? STARTING_FRAME_OFFSET : 0);
!
actual_fsize = compute_frame_size (size, &save_fregs);
/* Compute a few things we will use often. */
--- 3167,3173 ----
fr_saved = 0;
save_fregs = 0;
! local_fsize = adjusted_frame_size_for (size);
actual_fsize = compute_frame_size (size, &save_fregs);
/* Compute a few things we will use often. */
*************** hppa_expand_prologue ()
*** 3127,3133 ****
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp - 20 or sp - 16
depending on which ABI is in use. */
! if (regs_ever_live[2])
store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
/* Allocate the local frame and set up the frame pointer if needed. */
--- 3177,3183 ----
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp - 20 or sp - 16
depending on which ABI is in use. */
! if (regs_ever_live[2] || flag_exceptions)
store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
/* Allocate the local frame and set up the frame pointer if needed. */
*************** hppa_expand_prologue ()
*** 3232,3238 ****
was done earlier. */
if (frame_pointer_needed)
{
! for (i = 18, offset = local_fsize; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
--- 3282,3309 ----
was done earlier. */
if (frame_pointer_needed)
{
! offset = local_fsize;
!
! /* Save the eh return data registers if necessary. These are supposed to
! be caller-saved so there should be no overlap with the loop below. */
! if (current_function_calls_eh_return)
! {
! for (i = 0; ;i ++)
! {
! unsigned int regno = EH_RETURN_DATA_REGNO(i);
!
! if (regno == INVALID_REGNUM)
! break;
!
! store_reg (regno, offset, FRAME_POINTER_REGNUM);
! offset += UNITS_PER_WORD;
! /* Don't update gr_saved here, since it is there for the
! purpose of the CALLINFO arguments, which only care about
! callee-saved registers. */
! }
! }
!
! for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
*************** hppa_expand_prologue ()
*** 3245,3252 ****
/* No frame pointer needed. */
else
{
! for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
! if (regs_ever_live[i] && ! call_used_regs[i])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
--- 3316,3356 ----
/* No frame pointer needed. */
else
{
! offset = local_fsize - actual_fsize;
!
! /* GCC_EH : ??? Is the merge_sp_adjust stuff correctly handled
! by this addition ? */
! if (current_function_calls_eh_return)
! {
! for (i = 0; ;i ++)
! {
! unsigned int regno = EH_RETURN_DATA_REGNO(i);
!
! if (regno == INVALID_REGNUM)
! break;
!
! if (merge_sp_adjust_with_store)
! {
! rtx delta = GEN_INT (-offset);
! merge_sp_adjust_with_store = 0;
! DEEP_FRP (emit_insn
! (gen_post_store
! (stack_pointer_rtx,
! gen_rtx_REG (word_mode, regno), delta)));
! }
! else
! store_reg (regno, offset, STACK_POINTER_REGNUM);
!
! offset += UNITS_PER_WORD;
! /* Don't update gr_saved here, since it's purpose is the
! CALLINFO arguments, which only care about callee-saved
! registers. */
! }
! }
!
!
! for (i = 18; i >= 3; i--)
! if (regs_ever_live[i] && ! call_used_regs[i])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
*************** hppa_expand_prologue ()
*** 3254,3262 ****
{
rtx delta = GEN_INT (-offset);
merge_sp_adjust_with_store = 0;
! FRP (emit_insn (gen_post_store (stack_pointer_rtx,
! gen_rtx_REG (word_mode, i),
! delta)));
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
--- 3358,3367 ----
{
rtx delta = GEN_INT (-offset);
merge_sp_adjust_with_store = 0;
! DEEP_FRP (emit_insn
! (gen_post_store (stack_pointer_rtx,
! gen_rtx_REG (word_mode, i),
! delta)));
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
*************** hppa_expand_prologue ()
*** 3286,3322 ****
/* Floating point register store. */
if (save_fregs)
{
/* First get the frame or stack pointer to the start of the FP register
! save area. */
if (frame_pointer_needed)
! set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
else
! set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
!
! /* Now actually save the FP registers. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
{
if (regs_ever_live[i]
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
{
! rtx addr, insn, reg;
! addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
! reg = gen_rtx_REG (DFmode, i);
! insn = emit_move_insn (addr, reg);
! if (DO_FRAME_NOTES)
! {
! RTX_FRAME_RELATED_P (insn) = 1;
! REG_NOTES (insn)
! = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
! gen_rtx_SET (VOIDmode,
! gen_rtx_MEM (DFmode,
! plus_constant (stack_pointer_rtx,
! offset)),
! reg),
! REG_NOTES (insn));
! }
! offset += GET_MODE_SIZE (DFmode);
! fr_saved++;
}
}
}
--- 3391,3436 ----
/* Floating point register store. */
if (save_fregs)
{
+ rtx vbase =
+ gen_rtx_REG (word_mode, (frame_pointer_needed
+ ? FRAME_POINTER_REGNUM
+ : STACK_POINTER_REGNUM));
+
/* First get the frame or stack pointer to the start of the FP register
! save area. */
if (frame_pointer_needed)
! set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
else
! set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
!
! /* Now actually save the FP registers. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
{
if (regs_ever_live[i]
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
{
! rtx addr, reg, insn;
!
! addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
! reg = gen_rtx_REG (DFmode, i);
! insn = emit_move_insn (addr, reg);
! fr_saved++;
!
! if (DO_FRAME_NOTES)
! {
! rtx vaddr =
! gen_rtx_MEM (Pmode, plus_constant (vbase, offset));
!
! rtx intent =
! gen_rtx_SET (DFmode, vaddr, reg);
!
! RTX_FRAME_RELATED_P (insn) = 1;
! REG_NOTES (insn) =
! gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
! intent, REG_NOTES (insn));
!
! offset += GET_MODE_SIZE (DFmode);
! }
}
}
}
*************** pa_output_function_epilogue (file, size)
*** 3390,3409 ****
}
void
! hppa_expand_epilogue ()
{
rtx tmpreg;
int offset, i;
int merge_sp_adjust_with_load = 0;
int ret_off = 0;
/* We will use this often. */
tmpreg = gen_rtx_REG (word_mode, 1);
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
! if (regs_ever_live [2])
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
--- 3504,3533 ----
}
void
! hppa_expand_epilogue (int for_eh_return)
{
rtx tmpreg;
int offset, i;
int merge_sp_adjust_with_load = 0;
int ret_off = 0;
+ /* Compute the frame sizes now if running for eh_return since expand
+ prologue has not been called yet. */
+ if (for_eh_return)
+ {
+ int size = get_frame_size ();
+
+ local_fsize = adjusted_frame_size_for (size);
+ actual_fsize = compute_frame_size (size, &save_fregs);
+ }
+
/* We will use this often. */
tmpreg = gen_rtx_REG (word_mode, 1);
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
! if ((regs_ever_live [2] || flag_exceptions) && !for_eh_return)
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
*************** hppa_expand_epilogue ()
*** 3425,3431 ****
/* General register restores. */
if (frame_pointer_needed)
{
! for (i = 18, offset = local_fsize; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
--- 3549,3571 ----
/* General register restores. */
if (frame_pointer_needed)
{
! offset = local_fsize;
!
! if (current_function_calls_eh_return)
! {
! for (i = 0; ;i ++)
! {
! unsigned int regno = EH_RETURN_DATA_REGNO(i);
!
! if (regno == INVALID_REGNUM)
! break;
!
! load_reg (regno, offset, FRAME_POINTER_REGNUM);
! offset += UNITS_PER_WORD;
! }
! }
!
! for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
*************** hppa_expand_epilogue ()
*** 3434,3440 ****
}
else
{
! for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
--- 3574,3602 ----
}
else
{
! offset = local_fsize - actual_fsize;
!
! if (current_function_calls_eh_return)
! {
! for (i = 0; ;i ++)
! {
! unsigned int regno = EH_RETURN_DATA_REGNO(i);
!
! if (regno == INVALID_REGNUM)
! break;
!
! if (merge_sp_adjust_with_load == 0
! && local_fsize == 0
! && VAL_14_BITS_P (-actual_fsize))
! merge_sp_adjust_with_load = i;
! else
! load_reg (regno, offset, STACK_POINTER_REGNUM);
!
! offset += UNITS_PER_WORD;
! }
! }
!
! for (i = 18; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
*************** hppa_expand_epilogue ()
*** 3524,3531 ****
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
! if (ret_off != 0)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
}
rtx
--- 3686,3703 ----
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
! if (ret_off != 0 && !for_eh_return)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
+
+ /* Emit the stack adjustment for the jump to handler case. */
+ if (for_eh_return)
+ {
+ emit_move_insn
+ (gen_rtx_REG (Pmode, STACK_POINTER_REGNUM),
+ gen_rtx_MINUS (Pmode,
+ gen_rtx_REG (Pmode, STACK_POINTER_REGNUM),
+ EH_RETURN_STACKADJ_RTX));
+ }
}
rtx
*** config/pa/pa.md 2001/11/10 00:22:52 1.98
--- config/pa/pa.md 2001/12/05 09:12:30
***************
*** 5578,5584 ****
""
"
{
! hppa_expand_epilogue ();
DONE;
}")
--- 5578,5584 ----
""
"
{
! hppa_expand_epilogue (0);
DONE;
}")
***************
*** 5595,5601 ****
{
rtx x;
! hppa_expand_epilogue ();
if (flag_pic)
x = gen_return_internal_pic (gen_rtx_REG (word_mode,
PIC_OFFSET_TABLE_REGNUM));
--- 5595,5601 ----
{
rtx x;
! hppa_expand_epilogue (0);
if (flag_pic)
x = gen_return_internal_pic (gen_rtx_REG (word_mode,
PIC_OFFSET_TABLE_REGNUM));
***************
*** 5606,5611 ****
--- 5606,5662 ----
DONE;
}")
+ (define_expand "eh_return"
+ [(use (match_operand 0 "register_operand" "r"))
+ (use (match_operand 1 "register_operand" "r"))]
+ ""
+ {
+ rtx sa = operands [0], ra = operands [1];
+
+ if (word_mode == SImode)
+ emit_insn (gen_hppa_eh_return_si (sa, ra));
+ else
+ emit_insn (gen_hppa_eh_return_di (sa, ra));
+
+ emit_barrier ();
+ DONE;
+ })
+
+ (define_insn "hppa_eh_return_si"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "register_operand" "r") ] 5)]
+ "!TARGET_64BIT"
+ "#")
+
+ (define_insn "hppa_eh_return_di"
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "register_operand" "r")] 5)]
+ "TARGET_64BIT"
+ "#")
+
+ (define_split
+ [(unspec_volatile [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")] 5)]
+ "reload_completed"
+ [(const_int 0)]
+ "{
+ rtx x, sa = operands [0], ra = operands [1];
+
+ emit_move_insn (EH_RETURN_STACKADJ_RTX, sa);
+ emit_move_insn (EH_RETURN_HANDLER_RTX, ra);
+ hppa_expand_epilogue (1);
+
+ if (flag_pic)
+ x = gen_return_internal_pic (gen_rtx_REG (word_mode,
+ PIC_OFFSET_TABLE_REGNUM));
+ else
+ x = gen_return_internal ();
+
+ emit_jump_insn (x);
+
+ DONE;
+ }")
+
;; Special because we use the value placed in %r2 by the bl instruction
;; from within its delay slot to set the value for the 2nd parameter to
;; the call.
*** config/pa/pa-protos.h 2001/11/11 17:45:02 1.10
--- config/pa/pa-protos.h 2001/12/05 09:13:07
*************** extern int compute_frame_size PARAMS ((i
*** 138,144 ****
extern int and_mask_p PARAMS ((unsigned HOST_WIDE_INT));
extern int cint_ok_for_move PARAMS ((HOST_WIDE_INT));
extern void hppa_expand_prologue PARAMS ((void));
! extern void hppa_expand_epilogue PARAMS ((void));
extern int hppa_can_use_return_insn_p PARAMS ((void));
extern int ior_mask_p PARAMS ((unsigned HOST_WIDE_INT));
extern void compute_zdepdi_operands PARAMS ((unsigned HOST_WIDE_INT,
--- 138,144 ----
extern int and_mask_p PARAMS ((unsigned HOST_WIDE_INT));
extern int cint_ok_for_move PARAMS ((HOST_WIDE_INT));
extern void hppa_expand_prologue PARAMS ((void));
! extern void hppa_expand_epilogue PARAMS ((int));
extern int hppa_can_use_return_insn_p PARAMS ((void));
extern int ior_mask_p PARAMS ((unsigned HOST_WIDE_INT));
extern void compute_zdepdi_operands PARAMS ((unsigned HOST_WIDE_INT,
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-17 11:29 ` John David Anglin
2002-02-18 3:21 ` Olivier Hainque
@ 2002-02-18 12:18 ` Hans-Peter Nilsson
1 sibling, 0 replies; 521+ messages in thread
From: Hans-Peter Nilsson @ 2002-02-18 12:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Sun, 17 Feb 2002, John David Anglin wrote:
> Yes, looked at dwarf2out.c to see what it expects. I found some more
> coding problems with PARALLEL's in the register save code and also that
> the EH_RETURN_DATA_REGNO registers need to be saved if the function
> calls eh_return.
I've tripped over that last one too. (Mental note: doc update
needed.)
brgds, H-P
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
[not found] <no.id>
` (72 preceding siblings ...)
2002-02-16 16:12 ` Don't use lib2funcs.asm " John David Anglin
@ 2002-02-18 12:30 ` John David Anglin
2002-02-19 2:24 ` Olivier Hainque
2002-03-13 8:34 ` fix for strct-pack-1.c regressions John David Anglin
` (89 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-02-18 12:30 UTC (permalink / raw)
To: John David Anglin; +Cc: hainque, law, gcc-patches
> > Isn't this doing the wrong thing in case a function calling
> > __builtin_eh_return returns through a regular return path (as
> > _Unwind_RaiseException might do) ?
>
> I will investigate. This code appears in the rs6000 code. I think the answer
> must be that sa is 0 in a normal return. In the light of day, this code
Yes, see line 3180 in expand_eh_return in except.c.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Don't use lib2funcs.asm on PA
2002-02-18 12:30 ` John David Anglin
@ 2002-02-19 2:24 ` Olivier Hainque
0 siblings, 0 replies; 521+ messages in thread
From: Olivier Hainque @ 2002-02-19 2:24 UTC (permalink / raw)
To: John David Anglin; +Cc: law, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
> I will investigate. This code appears in the rs6000 code. I think the
> answer must be that sa is 0 in a normal return.
[...]
> Yes, see line 3180 in expand_eh_return in except.c.
Oh, indeed, had forgotten about that. Sorry for the confusion. This bit
in the epilogue deserves a comment I would say :)
Olivier
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix for strct-pack-1.c regressions
[not found] <no.id>
` (73 preceding siblings ...)
2002-02-18 12:30 ` John David Anglin
@ 2002-03-13 8:34 ` John David Anglin
2002-03-28 15:44 ` Letext John David Anglin
` (88 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-03-13 8:34 UTC (permalink / raw)
To: John David Anglin; +Cc: aldyh, gcc-patches, kenner
> > 2002-03-13 Aldy Hernandez <aldyh@redhat.com>
> >
> > * expmed.c (store_bit_field): Reset alias set for memory.
> > (extract_bit_field): Same.
>
> This didn't fix the fails on hppa2.0w-hp-hpux11.11.
I'm wrong. Somehow cvs seems to have downloaded an inconsistent
source tree at my end. The patch entry was in the ChangeLog but
expmed.c was not patched. Looking at this test on a hppa-linux
build that started a little later, the test now passes at -O2 and -Os.
Sorry for the confusion,
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Letext...
[not found] <no.id>
` (74 preceding siblings ...)
2002-03-13 8:34 ` fix for strct-pack-1.c regressions John David Anglin
@ 2002-03-28 15:44 ` John David Anglin
2002-05-08 13:54 ` [PATCH] checking version of rtl flag access macros John David Anglin
` (87 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-03-28 15:44 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rth, gcc-bugs, terra
> The PA linux port suffers from this problem as well, and I presume that the
The following has been applied to the trunk and 3.1 branch. It fixes
the same problem encountered on the sparc. Tested with no regressions
on hppa-unknown-linux-gnu.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-03-28 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa-linux.h (LOCAL_LABEL_PREFIX): Define.
--- pa-linux.h.orig Wed Mar 13 12:02:16 2002
+++ pa-linux.h Thu Mar 28 11:12:52 2002
@@ -148,6 +148,10 @@
} \
while (0)
+/* We want local labels to start with period if made with asm_fprintf. */
+#undef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX "."
+
/* Define these to generate the Linux/ELF/SysV style of internal
labels all the time - i.e. to be compatible with
ASM_GENERATE_INTERNAL_LABEL in <elfos.h>. Compare these with the
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] checking version of rtl flag access macros
[not found] <no.id>
` (75 preceding siblings ...)
2002-03-28 15:44 ` Letext John David Anglin
@ 2002-05-08 13:54 ` John David Anglin
2002-06-03 14:02 ` [PATCH] Jump bypassing and improved cprop (take 2) John David Anglin
` (86 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-05-08 13:54 UTC (permalink / raw)
To: John David Anglin; +Cc: janis187, gcc-patches
> I think that using RTL_FLAG_CHECKn is wrong. It's not an error
> if the rtx is not a JUMP_INSN or a CALL_INSN. However, the result
In looking at dbr_schedule, I see that INSN_ANNULLED_BRANCH_P and
INSN_FROM_TARGET_P apply to any active insn.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
[not found] <no.id>
` (76 preceding siblings ...)
2002-05-08 13:54 ` [PATCH] checking version of rtl flag access macros John David Anglin
@ 2002-06-03 14:02 ` John David Anglin
2002-06-04 6:31 ` law
2002-06-05 14:23 ` Patch: Use tm_defines to configure default scheduling model on PA John David Anglin
` (85 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-03 14:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rth
> By trial and error, I have determined that the following bootstrap failure
> under hppa-linux is a result of this patch:
>
> * rtl.h (CC0_P): New.
> * gcse.c (cprop_jump): Use it with single_set. Tweak dump text.
> (cprop_insn): Allow any mode register; use CC0_P. CSE out single_set.
> (bypass_block): Save old dest block for dump text.
> (bypass_conditional_jumps): Allow any mode register; use CC0_P.
> Allow only true SET insns, not single_set.
>
> ./xgcc -B./ -B/home/dave/opt/gnu/hppa-linux/bin/ -isystem /home/dave/opt/gnu/hppa-linux/include -isystem /home/dave/opt/gnu/hppa-linux/sys-include -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -isystem ./include -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include -g0 -finhibit-size-directive -fno-inline-functions -fno-exceptions -fno-zero-initialized-in-bss \
> -c ../../gcc/gcc/crtstuff.c -DCRT_BEGIN \
> -o crtbegin.o
> ../../gcc/gcc/crtstuff.c: In function `__do_global_dtors_aux':
> ../../gcc/gcc/crtstuff.c:282: internal error: Segmentation fault
I see that this is fixed (just a typo).
What actually started the hunt is the following ICE which is still present:
./xgcc -B./ -B/home/dave/opt/gnu/hppa-linux/bin/ -isystem /home/dave/opt/gnu/hppa-linux/include -isystem /home/dave/opt/gnu/hppa-linux/sys-include -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -isystem ./include -fPIC -DELF=1 -DLINUX=1 -g -DHAVE_GTHR_DEFAULT -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include -DL_muldi3 -c ../../gcc/gcc/libgcc2.c -o libgcc/./_muldi3.o
../../gcc/gcc/libgcc2.c: In function `__muldi3':
../../gcc/gcc/libgcc2.c:367: virtual array insn_addresses[211]: element 229 out of bounds in pa_output_function_prologue, at config/pa/pa.c:3185
The above error occurs on the following line:
total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
INSN_UID (get_last_insn ()) is 229. Something has messed up the size of
the array insn_addresses. This could be the above mentioned patch or some
other subsequent patch.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-03 14:02 ` [PATCH] Jump bypassing and improved cprop (take 2) John David Anglin
@ 2002-06-04 6:31 ` law
2002-06-04 6:45 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2002-06-04 6:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rth
In message <200206032102.g53L2a7l012194@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> > By trial and error, I have determined that the following bootstrap failure
> > under hppa-linux is a result of this patch:
> >
> > * rtl.h (CC0_P): New.
> > * gcse.c (cprop_jump): Use it with single_set. Tweak dump text.
> > (cprop_insn): Allow any mode register; use CC0_P. CSE out single_set.
> > (bypass_block): Save old dest block for dump text.
> > (bypass_conditional_jumps): Allow any mode register; use CC0_P.
> > Allow only true SET insns, not single_set.
> >
> > ./xgcc -B./ -B/home/dave/opt/gnu/hppa-linux/bin/ -isystem /home/dave/opt/g
> nu/hppa-linux/include -isystem /home/dave/opt/gnu/hppa-linux/sys-include -O2
> -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes
> -isystem ./include -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gc
> c/config -I../../gcc/gcc/../include -g0 -finhibit-size-directive -fno-inlin
> e-functions -fno-exceptions -fno-zero-initialized-in-bss \
> > -c ../../gcc/gcc/crtstuff.c -DCRT_BEGIN \
> > -o crtbegin.o
> > ../../gcc/gcc/crtstuff.c: In function `__do_global_dtors_aux':
> > ../../gcc/gcc/crtstuff.c:282: internal error: Segmentation fault
>
> I see that this is fixed (just a typo).
>
> What actually started the hunt is the following ICE which is still present:
>
> ./xgcc -B./ -B/home/dave/opt/gnu/hppa-linux/bin/ -isystem /home/dave/opt/gnu
> /hppa-linux/include -isystem /home/dave/opt/gnu/hppa-linux/sys-include -O2
> -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -
> isystem ./include -fPIC -DELF=1 -DLINUX=1 -g -DHAVE_GTHR_DEFAULT -DIN_LIBGC
> C2 -D__GCC_FLOAT_NOT_NEEDED -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../
> ../gcc/gcc/config -I../../gcc/gcc/../include -DL_muldi3 -c ../../gcc/gcc/li
> bgcc2.c -o libgcc/./_muldi3.o
> ../../gcc/gcc/libgcc2.c: In function `__muldi3':
> ../../gcc/gcc/libgcc2.c:367: virtual array insn_addresses[211]: element 229
> out of bounds in pa_output_function_prologue, at config/pa/pa.c:3185
>
> The above error occurs on the following line:
>
> total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
>
> INSN_UID (get_last_insn ()) is 229. Something has messed up the size of
> the array insn_addresses. This could be the above mentioned patch or some
> other subsequent patch.
I think Jan mentioned that this was his bug and that he was working on it.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-04 6:31 ` law
@ 2002-06-04 6:45 ` Jan Hubicka
2002-06-04 9:09 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2002-06-04 6:45 UTC (permalink / raw)
To: law; +Cc: John David Anglin, gcc-patches, rth
> > The above error occurs on the following line:
> >
> > total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
> >
> > INSN_UID (get_last_insn ()) is 229. Something has messed up the size of
> > the array insn_addresses. This could be the above mentioned patch or some
> > other subsequent patch.
> I think Jan mentioned that this was his bug and that he was working on it.
I was asking for opinion for proper fix on the mailing list.
The problem is that now I delete NOTE_INSN_BLOCK_* notes during the
optimization and re-emit them in final.c when debug output is done.
This makes those notes to not have computed INSN_ADDRESS, that is
de-facto OK, given that note is not an instruction so it does not have
any address.
The code like this can be fixed easilly by finding first/last nonnote
instruction in the chain.
I am not sure whether we want to fix all incarnations in the port
dependent code or find way to iniitialize INSN_ADDRESS that can be done
eighter by moving the re-emit code before shorten_branches that has the
dwawback that existence/nonexistence of notes may result in different
code output on -g/non-g compilation or simply add the gaps into
INSN_ADDRESS array, that is also not so fortunate due to resizing
issues.
What do you think?
Honza
>
> jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-04 6:45 ` Jan Hubicka
@ 2002-06-04 9:09 ` John David Anglin
2002-06-04 9:12 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-04 9:09 UTC (permalink / raw)
To: Jan Hubicka; +Cc: law, gcc-patches, rth
> > > The above error occurs on the following line:
> > >
> > > total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
> > >
> > > INSN_UID (get_last_insn ()) is 229. Something has messed up the size of
> > > the array insn_addresses. This could be the above mentioned patch or some
> The code like this can be fixed easilly by finding first/last nonnote
> instruction in the chain.
I am testing the enclosed patch per your suggestion.
> I am not sure whether we want to fix all incarnations in the port
> dependent code or find way to iniitialize INSN_ADDRESS that can be done
> eighter by moving the re-emit code before shorten_branches that has the
> dwawback that existence/nonexistence of notes may result in different
> code output on -g/non-g compilation or simply add the gaps into
> INSN_ADDRESS array, that is also not so fortunate due to resizing
> issues.
There only appears to be a couple of other ports with similar code to
determine the size of a function. Most other uses of INSN_ADDRESSES
are probably ok. Possibly, the function "get_last_nonnote_insn" could
be put in emit-rtl.c. Then, it wouldn't be too onerous to change all
the ports.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-06-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.c (get_last_nonnote_insn): New function.
(pa_output_function_prologue): Use it.
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.167
diff -u -3 -p -r1.167 pa.c
--- config/pa/pa.c 31 May 2002 18:01:13 -0000 1.167
+++ config/pa/pa.c 4 Jun 2002 15:35:15 -0000
@@ -95,6 +95,7 @@ hppa_fpstore_bypass_p (out_insn, in_insn
#endif
#endif
+static rtx get_last_nonnote_insn PARAMS((void));
static inline rtx force_mode PARAMS ((enum machine_mode, rtx));
static void pa_combine_instructions PARAMS ((rtx));
static int pa_can_combine_p PARAMS ((rtx, rtx, rtx, int, rtx, rtx, rtx));
@@ -3116,6 +3117,24 @@ compute_frame_size (size, fregs_live)
return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
}
+/* Return the last nonnote insn emitted in current sequence or current
+ function. This routine looks inside SEQUENCEs. */
+
+static rtx
+get_last_nonnote_insn ()
+{
+ rtx insn = get_last_insn ();
+
+ while (insn)
+ {
+ insn = previous_insn (insn);
+ if (insn == 0 || GET_CODE (insn) != NOTE)
+ break;
+ }
+
+ return insn;
+}
+
/* Generate the assembly code for function entry. FILE is a stdio
stream to output the code to. SIZE is an int: how many units of
temporary storage to allocate.
@@ -3182,7 +3201,7 @@ pa_output_function_prologue (file, size)
{
unsigned int old_total = total_code_bytes;
- total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
+ total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_nonnote_insn ()));
total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
/* Be prepared to handle overflows. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-04 9:09 ` John David Anglin
@ 2002-06-04 9:12 ` Jan Hubicka
2002-06-05 21:30 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2002-06-04 9:12 UTC (permalink / raw)
To: John David Anglin; +Cc: Jan Hubicka, law, gcc-patches, rth
> > > > The above error occurs on the following line:
> > > >
> > > > total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
> > > >
> > > > INSN_UID (get_last_insn ()) is 229. Something has messed up the size of
> > > > the array insn_addresses. This could be the above mentioned patch or some
>
> > The code like this can be fixed easilly by finding first/last nonnote
> > instruction in the chain.
>
> I am testing the enclosed patch per your suggestion.
>
> > I am not sure whether we want to fix all incarnations in the port
> > dependent code or find way to iniitialize INSN_ADDRESS that can be done
> > eighter by moving the re-emit code before shorten_branches that has the
> > dwawback that existence/nonexistence of notes may result in different
> > code output on -g/non-g compilation or simply add the gaps into
> > INSN_ADDRESS array, that is also not so fortunate due to resizing
> > issues.
>
> There only appears to be a couple of other ports with similar code to
> determine the size of a function. Most other uses of INSN_ADDRESSES
> are probably ok. Possibly, the function "get_last_nonnote_insn" could
> be put in emit-rtl.c. Then, it wouldn't be too onerous to change all
> the ports.
Yes, this looks like sensible approach to me. Thanks for fixing it!
Honza
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
>
> 2002-06-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * pa.c (get_last_nonnote_insn): New function.
> (pa_output_function_prologue): Use it.
>
> Index: config/pa/pa.c
> ===================================================================
> RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
> retrieving revision 1.167
> diff -u -3 -p -r1.167 pa.c
> --- config/pa/pa.c 31 May 2002 18:01:13 -0000 1.167
> +++ config/pa/pa.c 4 Jun 2002 15:35:15 -0000
> @@ -95,6 +95,7 @@ hppa_fpstore_bypass_p (out_insn, in_insn
> #endif
> #endif
>
> +static rtx get_last_nonnote_insn PARAMS((void));
> static inline rtx force_mode PARAMS ((enum machine_mode, rtx));
> static void pa_combine_instructions PARAMS ((rtx));
> static int pa_can_combine_p PARAMS ((rtx, rtx, rtx, int, rtx, rtx, rtx));
> @@ -3116,6 +3117,24 @@ compute_frame_size (size, fregs_live)
> return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
> }
>
> +/* Return the last nonnote insn emitted in current sequence or current
> + function. This routine looks inside SEQUENCEs. */
> +
> +static rtx
> +get_last_nonnote_insn ()
> +{
> + rtx insn = get_last_insn ();
> +
> + while (insn)
> + {
> + insn = previous_insn (insn);
> + if (insn == 0 || GET_CODE (insn) != NOTE)
> + break;
> + }
> +
> + return insn;
> +}
> +
> /* Generate the assembly code for function entry. FILE is a stdio
> stream to output the code to. SIZE is an int: how many units of
> temporary storage to allocate.
> @@ -3182,7 +3201,7 @@ pa_output_function_prologue (file, size)
> {
> unsigned int old_total = total_code_bytes;
>
> - total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
> + total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_nonnote_insn ()));
> total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
>
> /* Be prepared to handle overflows. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-04 9:12 ` Jan Hubicka
@ 2002-06-05 21:30 ` John David Anglin
2002-06-05 23:19 ` law
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-05 21:30 UTC (permalink / raw)
To: Jan Hubicka; +Cc: jh, law, gcc-patches, rth
> > There only appears to be a couple of other ports with similar code to
> > determine the size of a function. Most other uses of INSN_ADDRESSES
> > are probably ok. Possibly, the function "get_last_nonnote_insn" could
> > be put in emit-rtl.c. Then, it wouldn't be too onerous to change all
> > the ports.
>
> Yes, this looks like sensible approach to me. Thanks for fixing it!
This is the fix that I would like to apply to fix the problem of determining
the size of a function under hppa-linux and hppa64-hp-hpux11. I believe
that the patch is functionally equivalent to what I proposed before for
just the PA port. I have moved get_last_nonnote_insn to emit-rtl.c
and created a corresponding get_first_nonnote_insn for the avr port.
There is some question in my mind whether the latter question is actually
necessary but I don't want to second guess the code in avr.c.
Bootstrapped and regression tested under hppa-linux.
OK for mainline?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-06-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* emit-rtl.c (get_first_nonnote_insn, get_last_nonnote_insn): New
functions.
* rtl.h (get_first_nonnote_insn, get_last_nonnote_insn): Declare.
* avr/avr.c (avr_output_function_epilogue): Use above to determine
function size.
* pa/pa.c (pa_output_function_prologue): Likewise.
Index: emit-rtl.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.269
diff -u -3 -p -r1.269 emit-rtl.c
--- emit-rtl.c 3 Jun 2002 01:13:14 -0000 1.269
+++ emit-rtl.c 4 Jun 2002 16:53:47 -0000
@@ -2743,6 +2743,42 @@ get_last_insn_anywhere ()
return 0;
}
+/* Return the first nonnote insn emitted in current sequence or current
+ function. This routine looks inside SEQUENCEs. */
+
+rtx
+get_first_nonnote_insn ()
+{
+ rtx insn = first_insn;
+
+ while (insn)
+ {
+ insn = next_insn (insn);
+ if (insn == 0 || GET_CODE (insn) != NOTE)
+ break;
+ }
+
+ return insn;
+}
+
+/* Return the last nonnote insn emitted in current sequence or current
+ function. This routine looks inside SEQUENCEs. */
+
+rtx
+get_last_nonnote_insn ()
+{
+ rtx insn = last_insn;
+
+ while (insn)
+ {
+ insn = previous_insn (insn);
+ if (insn == 0 || GET_CODE (insn) != NOTE)
+ break;
+ }
+
+ return insn;
+}
+
/* Return a number larger than any instruction's uid in this function. */
int
Index: rtl.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.352
diff -u -3 -p -r1.352 rtl.h
--- rtl.h 2 Jun 2002 21:09:43 -0000 1.352
+++ rtl.h 4 Jun 2002 16:53:48 -0000
@@ -1447,6 +1447,8 @@ extern rtx get_insns PARAMS ((void));
extern const char *get_insn_name PARAMS ((int));
extern rtx get_last_insn PARAMS ((void));
extern rtx get_last_insn_anywhere PARAMS ((void));
+extern rtx get_first_nonnote_insn PARAMS ((void));
+extern rtx get_last_nonnote_insn PARAMS ((void));
extern void start_sequence PARAMS ((void));
extern void push_to_sequence PARAMS ((rtx));
extern void end_sequence PARAMS ((void));
Index: config/avr/avr.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr.c,v
retrieving revision 1.72
diff -u -3 -p -r1.72 avr.c
--- config/avr/avr.c 1 Jun 2002 23:33:47 -0000 1.72
+++ config/avr/avr.c 4 Jun 2002 16:53:48 -0000
@@ -749,8 +749,8 @@ avr_output_function_epilogue (file, size
interrupt_func_p = interrupt_function_p (current_function_decl);
signal_func_p = signal_function_p (current_function_decl);
main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
- function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
- - INSN_ADDRESSES (INSN_UID (get_insns ())));
+ function_size = (INSN_ADDRESSES (INSN_UID (get_last_nonnote_insn ()))
+ - INSN_ADDRESSES (INSN_UID (get_first_nonnote_insn ())));
function_size += jump_tables_size;
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.167
diff -u -3 -p -r1.167 pa.c
--- config/pa/pa.c 31 May 2002 18:01:13 -0000 1.167
+++ config/pa/pa.c 4 Jun 2002 16:53:49 -0000
@@ -3182,7 +3182,7 @@ pa_output_function_prologue (file, size)
{
unsigned int old_total = total_code_bytes;
- total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
+ total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_nonnote_insn ()));
total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
/* Be prepared to handle overflows. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Jump bypassing and improved cprop (take 2)
2002-06-05 21:30 ` John David Anglin
@ 2002-06-05 23:19 ` law
0 siblings, 0 replies; 521+ messages in thread
From: law @ 2002-06-05 23:19 UTC (permalink / raw)
To: John David Anglin; +Cc: Jan Hubicka, gcc-patches, rth
In message <200206060430.g564UHjX021278@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
> > > There only appears to be a couple of other ports with similar code to
> > > determine the size of a function. Most other uses of INSN_ADDRESSES
> > > are probably ok. Possibly, the function "get_last_nonnote_insn" could
> > > be put in emit-rtl.c. Then, it wouldn't be too onerous to change all
> > > the ports.
> >
> > Yes, this looks like sensible approach to me. Thanks for fixing it!
>
> This is the fix that I would like to apply to fix the problem of determining
> the size of a function under hppa-linux and hppa64-hp-hpux11. I believe
> that the patch is functionally equivalent to what I proposed before for
> just the PA port. I have moved get_last_nonnote_insn to emit-rtl.c
> and created a corresponding get_first_nonnote_insn for the avr port.
> There is some question in my mind whether the latter question is actually
> necessary but I don't want to second guess the code in avr.c.
>
> Bootstrapped and regression tested under hppa-linux.
>
> OK for mainline?
>
> Dave
> --
> J. David Anglin dave.anglin@nrc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-66
> 05)
>
> 2002-06-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * emit-rtl.c (get_first_nonnote_insn, get_last_nonnote_insn): New
> functions.
> * rtl.h (get_first_nonnote_insn, get_last_nonnote_insn): Declare.
> * avr/avr.c (avr_output_function_epilogue): Use above to determine
> function size.
> * pa/pa.c (pa_output_function_prologue): Likewise.
This is fine.
Thanks,
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
[not found] <no.id>
` (77 preceding siblings ...)
2002-06-03 14:02 ` [PATCH] Jump bypassing and improved cprop (take 2) John David Anglin
@ 2002-06-05 14:23 ` John David Anglin
2002-06-12 10:03 ` John David Anglin
` (84 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-06-05 14:23 UTC (permalink / raw)
To: John David Anglin; +Cc: neil, zack, gcc-patches, law
> config.gcc into
>
> #ifdef ABC
> #define ABC foo
> #endif
Oops, typo.
#ifndef ABC
#define ABC foo
#endif
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
[not found] <no.id>
` (78 preceding siblings ...)
2002-06-05 14:23 ` Patch: Use tm_defines to configure default scheduling model on PA John David Anglin
@ 2002-06-12 10:03 ` John David Anglin
2002-06-12 10:23 ` DJ Delorie
2002-06-18 16:01 ` [PATCH/RFA] Allow register other than SP for DWARF2 CFA John David Anglin
` (83 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-12 10:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law, dj, aoliva
> 2002-06-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * Makefile.in (tm_defines): New configuration variable.
> (cs-config.h, cs-hconfig.h, cs-tconfig.h): Rename DEFINES to XM_DEFINES.
> Pass tm_defines in TM_DEFINES.
> (cs-tm_p.h): Rename DEFINES to XM_DEFINES. Pass TM_DEFINES.
> * config.gcc (tm_defines): New configuration variable.
> (hppa*-*-* | parisc*-*-*): Use tm_defines instead of pa-700.h and
> pa-7100.h headers. Change hppa1* scheduling default to 7100LC.
> * configure.in: Substitute tm_defines.
> * configure: Rebuilt.
> * mkconfig.sh: Rename DEFINES to XM_DEFINES. Output TM_DEFINES.
> * pa/pa-700.h: Delete file.
> * pa/pa-7100.h: Delete file.
The above patch has not been reviewed. Could one of the build machinery
maintainers review it?
Thanks,
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 10:03 ` John David Anglin
@ 2002-06-12 10:23 ` DJ Delorie
2002-06-12 10:51 ` John David Anglin
2002-06-15 11:04 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: DJ Delorie @ 2002-06-12 10:23 UTC (permalink / raw)
To: dave; +Cc: gcc-patches, law, aoliva
> > 2002-06-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
> >
> > * Makefile.in (tm_defines): New configuration variable.
> > (cs-config.h, cs-hconfig.h, cs-tconfig.h): Rename DEFINES to XM_DEFINES.
> > Pass tm_defines in TM_DEFINES.
> > (cs-tm_p.h): Rename DEFINES to XM_DEFINES. Pass TM_DEFINES.
> > * config.gcc (tm_defines): New configuration variable.
> > (hppa*-*-* | parisc*-*-*): Use tm_defines instead of pa-700.h and
> > pa-7100.h headers. Change hppa1* scheduling default to 7100LC.
> > * configure.in: Substitute tm_defines.
> > * configure: Rebuilt.
> > * mkconfig.sh: Rename DEFINES to XM_DEFINES. Output TM_DEFINES.
> > * pa/pa-700.h: Delete file.
> > * pa/pa-7100.h: Delete file.
>
> The above patch has not been reviewed. Could one of the build machinery
> maintainers review it?
Sorry I missed it, but the subject line was a bit misleading. The
patch is fine. However, the PPC already has a way of selecting the
default CPU (and thus scheduling etc) with a configure option and
config.gcc. Did you look at that mechanism before implementing this
one?
And I predict that at some point in the future, there will be a thread
about how all those defines in config.gcc are cluttering up the
script, and why can't we put them all in target-specific headers?
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 10:23 ` DJ Delorie
@ 2002-06-12 10:51 ` John David Anglin
2002-06-12 11:17 ` DJ Delorie
2002-06-15 11:04 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-12 10:51 UTC (permalink / raw)
To: DJ Delorie; +Cc: gcc-patches, law, aoliva
> Sorry I missed it, but the subject line was a bit misleading. The
> patch is fine. However, the PPC already has a way of selecting the
> default CPU (and thus scheduling etc) with a configure option and
> config.gcc. Did you look at that mechanism before implementing this
> one?
I did but I will look more closely at what ppc has done.
> And I predict that at some point in the future, there will be a thread
> about how all those defines in config.gcc are cluttering up the
> script, and why can't we put them all in target-specific headers?
The goal here was to eliminate small target-specific headers and provide
a mechanism for selecting target options in the configuration process.
At the moment, mkconfig.sh outputs DEFINES after HEADERS. I would
argue that we should output DEFINES first so that they can be used
to select build, host and target options in HEADERS and other code
that includes the various config files. Placing the defines first
allows defaults in the headers to be overriden.
There were a number of comments after I submitted the patch that
indicated the number of target-specific headers in the i386 config
was too large and the inclusion process difficult to follow.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 10:51 ` John David Anglin
@ 2002-06-12 11:17 ` DJ Delorie
2002-06-12 11:47 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: DJ Delorie @ 2002-06-12 11:17 UTC (permalink / raw)
To: dave; +Cc: gcc-patches, law, aoliva
> that includes the various config files. Placing the defines first
> allows defaults in the headers to be overriden.
Placing defines after allows you to redefine something with a simple
undef/define, without the main header needing to know that you're
doing it. There are cases that argue both ways, though.
> There were a number of comments after I submitted the patch that
> indicated the number of target-specific headers in the i386 config
> was too large and the inclusion process difficult to follow.
The complexity has to go somewhere ;)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 11:17 ` DJ Delorie
@ 2002-06-12 11:47 ` John David Anglin
2002-06-12 12:01 ` DJ Delorie
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-06-12 11:47 UTC (permalink / raw)
To: DJ Delorie; +Cc: gcc-patches, law, aoliva
> > that includes the various config files. Placing the defines first
> > allows defaults in the headers to be overriden.
>
> Placing defines after allows you to redefine something with a simple
> undef/define, without the main header needing to know that you're
> doing it. There are cases that argue both ways, though.
How does that work? mkconfig.sh doesn't do undef's.
Although mkconfig.sh could be modified to undef/define when necessary,
I still think it better to put the defines first because the headers
may contain secondary defines based on the identifier that you want
to redefine.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 11:47 ` John David Anglin
@ 2002-06-12 12:01 ` DJ Delorie
2002-06-12 13:01 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: DJ Delorie @ 2002-06-12 12:01 UTC (permalink / raw)
To: dave; +Cc: gcc-patches, law, aoliva
> How does that work? mkconfig.sh doesn't do undef's.
I didn't say it would work, but it's a technique we use elsewhere.
> I still think it better to put the defines first because the headers
> may contain secondary defines based on the identifier that you want
> to redefine.
Consider, for example, this from i386/cygwin.h:
/* For Win32 ABI compatibility */
#undef DEFAULT_PCC_STRUCT_RETURN
#define DEFAULT_PCC_STRUCT_RETURN 0
To do this with defines before includes, you'd need to put a #ifdef
around *every single* define in *every* header file, because you won't
know which will be overridden by targets.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 12:01 ` DJ Delorie
@ 2002-06-12 13:01 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-06-12 13:01 UTC (permalink / raw)
To: DJ Delorie; +Cc: gcc-patches, law, aoliva
> > I still think it better to put the defines first because the headers
> > may contain secondary defines based on the identifier that you want
> > to redefine.
>
> Consider, for example, this from i386/cygwin.h:
>
> /* For Win32 ABI compatibility */
> #undef DEFAULT_PCC_STRUCT_RETURN
> #define DEFAULT_PCC_STRUCT_RETURN 0
>
> To do this with defines before includes, you'd need to put a #ifdef
> around *every single* define in *every* header file, because you won't
> know which will be overridden by targets.
Yes. However, it's not reasonable to define the entire cygwin configuration
in configure. If configure checked how to define DEFAULT_PCC_STRUCT_RETURN
then I would say it has a place in configure, and that there should be
a way independent of include files to override the default define. I
agree that in some cases putting the defines after the headers is simpler
and avoids the ifdef burden, however you loose some flexibility in what
the headers can do.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch: Use tm_defines to configure default scheduling model on PA
2002-06-12 10:23 ` DJ Delorie
2002-06-12 10:51 ` John David Anglin
@ 2002-06-15 11:04 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-06-15 11:04 UTC (permalink / raw)
To: DJ Delorie; +Cc: gcc-patches, law, aoliva
> Sorry I missed it, but the subject line was a bit misleading. The
> patch is fine. However, the PPC already has a way of selecting the
> default CPU (and thus scheduling etc) with a configure option and
> config.gcc. Did you look at that mechanism before implementing this
> one?
The mechanism involves setting flag bits in TARGET_CPU_DEFAULT. This could
be done but then there would be no way for a user to fine tune the default
scheduling model selected by configure except by hacking config.gcc. One
of the goals of the patch was to enable the user to set TARGET_SCHED_DEFAULT
in BOOT_CFLAGS.
TARGET_CPU_DEFAULT involves a collection of miscellaneous flag bits that
get merged in a rather complex manner in the configuration process to produce
the define output at the beginning of the various *config.h files. This
define is not protected by a ifndef so it's not currently possible for
a user to override it in BOOT_CFLAGS.
Setting the PA architecture bits in TARGET_CPU_DEFAULT is currently a problem.
The default is still PA 1.1 even on PA 2.0 machines. I plan to make some
changes in this area in the near future after a bug in GAS affecting level
2.0 code is fixed for elf32.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH/RFA] Allow register other than SP for DWARF2 CFA
[not found] <no.id>
` (79 preceding siblings ...)
2002-06-12 10:03 ` John David Anglin
@ 2002-06-18 16:01 ` John David Anglin
2002-06-24 12:48 ` PATH: inline does not work with -O3 specified Herman ten Brugge
` (82 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-06-18 16:01 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches
> Thanks. I give it a try asap. However, it looks like casesi is
> broken on vax. An abort occurs in stage1 running gengenrtl.
Actually, stage2. We lose the jump table in the bbro pass.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATH: inline does not work with -O3 specified
[not found] <no.id>
` (80 preceding siblings ...)
2002-06-18 16:01 ` [PATCH/RFA] Allow register other than SP for DWARF2 CFA John David Anglin
@ 2002-06-24 12:48 ` Herman ten Brugge
2002-06-30 16:59 ` Michael Hayes
2002-07-11 12:17 ` PATCH: Fix failure of arith-rand-ll.c on hppa 32-bit targets John David Anglin
` (81 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: Herman ten Brugge @ 2002-06-24 12:48 UTC (permalink / raw)
To: gcc-patches
herman wrote :
>
> Hello,
>
> I notieced a problem in the current mainline release. The inlining does not
> work when -O3 specified. The typo is in c-common.c (See patch below).
> I do not have write permission so can not make the change after aproval.
>
Oops. This is wrong. The correct fix is below. I alos forgot to mention
that this did not work for the c4x target.
I do not have write permission so can not make the change after aproval.
Herman.
2002-24-06 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
* c4x.h: (TARGET_CPU_CPP_BUILTINS): Check flag_inline_functions and
flag_inline_trees to enable inlining.
--- c4x.h.org Mon Jun 24 21:37:52 2002
+++ c4x.h Mon Jun 24 21:38:20 2002
@@ -35,7 +35,8 @@
builtin_define ("_BIGMODEL"); \
if (!TARGET_MEMPARM) \
builtin_define ("_REGPARM"); \
- if (flag_inline_functions) \
+ if (flag_inline_functions \
+ || flag_inline_trees) \
builtin_define ("_INLINE"); \
if (TARGET_C3X) \
{ \
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix failure of arith-rand-ll.c on hppa 32-bit targets
[not found] <no.id>
` (81 preceding siblings ...)
2002-06-24 12:48 ` PATH: inline does not work with -O3 specified Herman ten Brugge
@ 2002-07-11 12:17 ` John David Anglin
2002-08-02 22:10 ` [RFA] Fix libsupc++/Makefile.in John David Anglin
` (80 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-07-11 12:17 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> After installing this patch, I realized that the predicate for the adddi3
> expander can be improved rather than forcing constants that don't fit
> into a register.
Here is the patch. Tested on hppa-linux, hppa2.0w-hp-hpux11.11
and hppa64-hp-hpux11.11. Applied to main. A combined version of
this patch and the previous patch has been applied to the 3.1
branch.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-07-11 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.md (adddi3): Change predicate of operand 2 to adddi3_operand
and delete code to force constant to register.
* pa-protos.h (adddi3_operand): Add prototype.
* pa.c (adddi3_operand): New function.
Index: config/pa/pa.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.md,v
retrieving revision 1.108
diff -u -3 -p -r1.108 pa.md
--- config/pa/pa.md 11 Jul 2002 05:04:54 -0000 1.108
+++ config/pa/pa.md 11 Jul 2002 15:57:30 -0000
@@ -3813,15 +3813,9 @@
(define_expand "adddi3"
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "arith_operand" "")))]
+ (match_operand:DI 2 "adddi3_operand" "")))]
""
- "
-{
- if (!TARGET_64BIT
- && GET_CODE (operands[2]) == CONST_INT
- && !VAL_11_BITS_P (INTVAL (operands[2])))
- operands[2] = force_reg (DImode, operands[2]);
-}")
+ "")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
Index: config/pa/pa-protos.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-protos.h,v
retrieving revision 1.14
diff -u -3 -p -r1.14 pa-protos.h
--- config/pa/pa-protos.h 21 Jun 2002 01:37:47 -0000 1.14
+++ config/pa/pa-protos.h 11 Jul 2002 15:57:30 -0000
@@ -63,6 +63,7 @@ extern rtx legitimize_pic_address PARAMS
extern struct rtx_def *gen_cmp_fp PARAMS ((enum rtx_code, rtx, rtx));
extern void hppa_encode_label PARAMS ((rtx));
extern int arith11_operand PARAMS ((rtx, enum machine_mode));
+extern int adddi3_operand PARAMS ((rtx, enum machine_mode));
extern int symbolic_expression_p PARAMS ((rtx));
extern int hppa_address_cost PARAMS ((rtx));
extern int symbolic_memory_operand PARAMS ((rtx, enum machine_mode));
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.171
diff -u -3 -p -r1.171 pa.c
--- config/pa/pa.c 11 Jul 2002 05:04:55 -0000 1.171
+++ config/pa/pa.c 11 Jul 2002 15:57:31 -0000
@@ -578,6 +578,18 @@ arith11_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
}
+/* Return truth value of whether OP can be used as an operand in a
+ adddi3 insn. */
+int
+adddi3_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || (GET_CODE (op) == CONST_INT
+ && (TARGET_64BIT ? INT_14_BITS (op) : INT_11_BITS (op))));
+}
+
/* A constant integer suitable for use in a PRE_MODIFY memory
reference. */
int
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [RFA] Fix libsupc++/Makefile.in
[not found] <no.id>
` (82 preceding siblings ...)
2002-07-11 12:17 ` PATCH: Fix failure of arith-rand-ll.c on hppa 32-bit targets John David Anglin
@ 2002-08-02 22:10 ` John David Anglin
2002-08-02 23:49 ` Neil Booth
2002-08-21 9:31 ` PATCH: fix warning and return value for remove_dup_nonsys_dirs John David Anglin
` (79 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-08-02 22:10 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, neil
> I belive that this patch has broken the v3 build under hppa-linux
> and likely for other hppa ports. This libsupc++ library gets linked
> against the share v3 lib, thus all compilations need to be pic on hppa.
> I believe "-prefer-pic" was part of the C++ flags. So, we now need
> it in the C flags.
Here's a quick fix. Tested on hppa-linux.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-08-02 John David Anglin <dave@hiauly1.hia.nrc.ca>
* libsupc++/Makefile.am (LTCOMPILE): Add LIBSUPCXX_PICFLAGS.
Index: libsupc++/Makefile.am
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/libsupc++/Makefile.am,v
retrieving revision 1.34
diff -u -3 -p -r1.34 Makefile.am
--- libsupc++/Makefile.am 1 Aug 2002 22:16:46 -0000 1.34
+++ libsupc++/Makefile.am 3 Aug 2002 04:29:29 -0000
@@ -126,7 +126,7 @@ dyn-string.o: dyn-string.c
# LTCOMPILE is copied from LTCXXCOMPILE below.
LTCOMPILE = $(LIBTOOL) --tag CC --tag disable-shared --mode=compile $(CC) \
- $(DEFS) $(GCC_INCLUDES) \
+ $(DEFS) $(GCC_INCLUDES) $(LIBSUPCXX_PICFLAGS) \
$(AM_CPPFLAGS) $(CPPFLAGS)
^ permalink raw reply [flat|nested] 521+ messages in thread
* PATCH: fix warning and return value for remove_dup_nonsys_dirs
[not found] <no.id>
` (83 preceding siblings ...)
2002-08-02 22:10 ` [RFA] Fix libsupc++/Makefile.in John David Anglin
@ 2002-08-21 9:31 ` John David Anglin
2002-08-21 10:13 ` Zack Weinberg
2002-08-31 9:24 ` 128 bit floats on PA64 John David Anglin
` (78 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-08-21 9:31 UTC (permalink / raw)
To: John David Anglin; +Cc: neil, zack, nathan, nathan, gcc-patches
> Installed! I suggest waiting a few days to see if the change causes
> any problems before considering the branch. I will work up something
> for the relevant changes.html(s).
I don't know how I missed this. The return value of remove_dup_nonsys_dirs
isn't correct if there are no system directories. The enclosed patch
fixes the problem.
Tested with a bootstrap and check on hppa-linux with no regressions.
OK for main?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-08-21 John David Anglin <dave@hiauly1.hia.nrc.ca>
* cppinit.c (remove_dup_nonsys_dirs): Fix warning and return value.
Index: cppinit.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cppinit.c,v
retrieving revision 1.259
diff -u -3 -p -r1.259 cppinit.c
--- cppinit.c 20 Aug 2002 19:56:29 -0000 1.259
+++ cppinit.c 21 Aug 2002 16:04:16 -0000
@@ -303,12 +303,14 @@ remove_dup_nonsys_dirs (pfile, head_ptr,
struct search_path **head_ptr;
struct search_path *end;
{
- struct search_path *prev, *cur, *other;
+ int sysdir = 0;
+ struct search_path *prev = NULL, *cur, *other;
for (cur = *head_ptr; cur; cur = cur->next)
{
if (cur->sysp)
{
+ sysdir = 1;
for (other = *head_ptr, prev = NULL;
other != end;
other = other ? other->next : *head_ptr)
@@ -326,6 +328,10 @@ remove_dup_nonsys_dirs (pfile, head_ptr,
}
}
}
+
+ if (!sysdir)
+ for (cur = *head_ptr; cur != end; cur = cur->next)
+ prev = cur;
return prev;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: fix warning and return value for remove_dup_nonsys_dirs
2002-08-21 9:31 ` PATCH: fix warning and return value for remove_dup_nonsys_dirs John David Anglin
@ 2002-08-21 10:13 ` Zack Weinberg
0 siblings, 0 replies; 521+ messages in thread
From: Zack Weinberg @ 2002-08-21 10:13 UTC (permalink / raw)
To: John David Anglin; +Cc: neil, nathan, nathan, gcc-patches
On Wed, Aug 21, 2002 at 12:23:50PM -0400, John David Anglin wrote:
> > Installed! I suggest waiting a few days to see if the change causes
> > any problems before considering the branch. I will work up something
> > for the relevant changes.html(s).
>
> I don't know how I missed this. The return value of remove_dup_nonsys_dirs
> isn't correct if there are no system directories. The enclosed patch
> fixes the problem.
>
> Tested with a bootstrap and check on hppa-linux with no regressions.
>
> OK for main?
Yes.
zw
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: 128 bit floats on PA64
[not found] <no.id>
` (84 preceding siblings ...)
2002-08-21 9:31 ` PATCH: fix warning and return value for remove_dup_nonsys_dirs John David Anglin
@ 2002-08-31 9:24 ` John David Anglin
2002-09-23 11:53 ` Patch for PR c/4319 John David Anglin
` (77 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-08-31 9:24 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, law
> The following compiles your test ok. I have a full bootstrap in
> progress. I'm still not completely happy with the comment but
> I think it is more or less explains why we don't want SImode values
> changed to a wider mode.
There is one new testsuite failure. The test execute/20010605-2.c
seg faults in function baz. It looks as if the dp register has been
messed up. We are trying to pass a complex long double.
This is the last part of the baz call:
ldd 112(%r3),%r25
ldd 120(%r3),%r26
ldd 128(%r3),%r27 <== dp clobbered
ldd 136(%r3),%r28
ldo -16(%r30),%r29
b,l baz,%r2
nop
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Patch for PR c/4319
[not found] <no.id>
` (85 preceding siblings ...)
2002-08-31 9:24 ` 128 bit floats on PA64 John David Anglin
@ 2002-09-23 11:53 ` John David Anglin
2002-09-30 21:03 ` PATCH for sibcalls on i386 John David Anglin
` (76 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-09-23 11:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jsm28
> I don't completely understand why I didn't see this earlier but
> gcc.dg/typespec-1.c now fails in over a 100 places on hppa64-hp-hpux11.00.
> I first observed this in a build last night, but 3.2 doesn't warn or
> generate an error for the following as well, even with -pedantic:
>
> char short *x23;
>
> Looking at c-decl.c, I see that explicit_char is 1 for this case, so
> the change that you made doesn't generate an error for "char short".
On further investigation, it appears that grokdeclarator has been
miscompiled. For some reason, when specbits is set, it appears to
be treated as a "long" (i.e., ldd/std are used to load and store the
value). However, when it is tested, it seems to be treated as an
int (i.e., ldw/stw are used). This mixup causes the type checks
to fail.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH for sibcalls on i386
[not found] <no.id>
` (86 preceding siblings ...)
2002-09-23 11:53 ` Patch for PR c/4319 John David Anglin
@ 2002-09-30 21:03 ` John David Anglin
2002-10-21 15:48 ` [PATCH] Inline __udiv_w_sdiv into __divdi3 etc John David Anglin
` (75 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-09-30 21:03 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, hp, gcc-patches
> > the sibcall machinery, and is independent of it. It should
> > not be shut off by FUNCTION_OK_FOR_SIBCALL.
>
> The main difference between the 32-bit ports (e.g., hppa-linux)
> and hppa64-hpux is that calls on hppa64-hpux always pass a pointer
> to the first argument on on the stack (arg8) as one of the arguments.
> Possibly, this is the reason that there is no sibcall.
This appears to be the reason why we don't get recursive tail calls
on hppa64-hpux. sequence_uses_addressof returns nonzero because
current_function_internal_arg_pointer is found. This causes
no_sibcalls_this_function to be set. Thus, I think that all the
sibcall tests need to be xfailed for this target.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Inline __udiv_w_sdiv into __divdi3 etc.
[not found] <no.id>
` (87 preceding siblings ...)
2002-09-30 21:03 ` PATCH for sibcalls on i386 John David Anglin
@ 2002-10-21 15:48 ` John David Anglin
2002-10-24 12:51 ` Reload patch for PA call rewrite John David Anglin
` (74 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-10-21 15:48 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, Ulrich.Weigand, rth
> On hppa-linux, it looks as if this patch causes a bootstrap failure:
>
> > On Mon, Oct 21, 2002 at 10:04:36PM +0200, Ulrich Weigand wrote:
> > > * libgcc2.c: Inline __udiv_w_sdiv when compiling __udivdi3,
> > > __divdi3, __umoddi3, or __moddi3.
> >
> > Ok.
It also fails on hppa64-hp-hpux11.11:
stage1/xgcc -Bstage1/ -B/opt/gnu64/hppa64-hp-hpux11.11/bin/ -g -O2 -mlong-calls -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -DHAVE_CONFIG_H -DGENERATOR_FILE -o genattrtab \
genattrtab.o genautomata.o \
rtl.o read-rtl.o bitmap.o ggc-none.o gensupport.o insn-conditions.o print-rtl1.o errors.o \
varray.o ../libiberty/libiberty.a -lm
ld: Duplicate symbol "__udiv_w_sdiv" in files stage1/libgcc.a[_udivdi3.o] and stage1/libgcc.a[_umoddi3.o]
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Reload patch for PA call rewrite.
[not found] <no.id>
` (88 preceding siblings ...)
2002-10-21 15:48 ` [PATCH] Inline __udiv_w_sdiv into __divdi3 etc John David Anglin
@ 2002-10-24 12:51 ` John David Anglin
2002-10-24 16:26 ` John David Anglin
` (73 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-10-24 12:51 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches, law
> This problem is probably hidden when the arg pointer can be
> eliminated as the stack or frame pointer is used instead. However,
> we can't eliminate it on hppa64 because the outgoing arg pointer in
> a function call is set based on the cumulative size of the outgoing
> args of the callee and this varies from one callee to another.
That should be caller, not callee.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Reload patch for PA call rewrite.
[not found] <no.id>
` (89 preceding siblings ...)
2002-10-24 12:51 ` Reload patch for PA call rewrite John David Anglin
@ 2002-10-24 16:26 ` John David Anglin
2002-10-25 8:54 ` Jeff Law
2002-10-30 19:23 ` Call rewrite for PA John David Anglin
` (72 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-10-24 16:26 UTC (permalink / raw)
To: John David Anglin; +Cc: law, rth, gcc-patches
> I did see a small but consistent improvement in the running time
> of genattrtab with sibcalls enabled. I don't know where this arises
> but I doubt it is from any saving in the call sequence itself.
> There are small differences in how the delay slot is used. For
> regular calls, we use a branch and link, and for sibcalls, we just
> branch. That's the sum of the differences as I see it.
I just rechecked the above. With the only change being the value for
FUNCTION_OK_FOR_SIBCALL, the times for genattrtab on an a500 running
hppa64-hp-hpux11.11 with the call rewrite were 13.24 seconds with
sibcalls and 13.71 seconds without sibcalls, respectively. These
numbers are consistent with what I measured using an earlier version
of the patch. I think the 3 percent improvement is worthwhile.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Reload patch for PA call rewrite.
2002-10-24 16:26 ` John David Anglin
@ 2002-10-25 8:54 ` Jeff Law
2002-10-25 10:10 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jeff Law @ 2002-10-25 8:54 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches
In message <200210242326.g9ONQkob027212@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
>> I did see a small but consistent improvement in the running time
>> of genattrtab with sibcalls enabled. I don't know where this arises
>> but I doubt it is from any saving in the call sequence itself.
>> There are small differences in how the delay slot is used. For
>> regular calls, we use a branch and link, and for sibcalls, we just
>> branch. That's the sum of the differences as I see it.
>
>I just rechecked the above. With the only change being the value for
>FUNCTION_OK_FOR_SIBCALL, the times for genattrtab on an a500 running
>hppa64-hp-hpux11.11 with the call rewrite were 13.24 seconds with
>sibcalls and 13.71 seconds without sibcalls, respectively. These
>numbers are consistent with what I measured using an earlier version
>of the patch. I think the 3 percent improvement is worthwhile.
Definitely worthwhile.
It's possible the improvements are on the return path side -- by returning
to the caller's parent rather than the caller itself, we avoid one hard
to predict branch (the "bv" in the caller) and maybe one easy to predict
branch (branch to the epilogue).
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Reload patch for PA call rewrite.
2002-10-25 8:54 ` Jeff Law
@ 2002-10-25 10:10 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-10-25 10:10 UTC (permalink / raw)
To: law; +Cc: rth, gcc-patches
> It's possible the improvements are on the return path side -- by returning
> to the caller's parent rather than the caller itself, we avoid one hard
> to predict branch (the "bv" in the caller) and maybe one easy to predict
> branch (branch to the epilogue).
Yes, I can see that returns are hard to predict since they are indirect
and we save one with the sibcall. We definitely should implement the BTS
for returns.
I tried the same test on hppa-linux and there wasn't any difference in
the timing with and without sibcalls. I'm going to try 32-bit hpux.
Possibly, there is a linux/hpux difference. Possibly, there is a
difference wrt the P bit in the ITLB between these systems.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Call rewrite for PA
[not found] <no.id>
` (90 preceding siblings ...)
2002-10-24 16:26 ` John David Anglin
@ 2002-10-30 19:23 ` John David Anglin
2002-11-09 15:18 ` C++ PATCH: ABI bug for vcall offsets John David Anglin
` (71 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-10-30 19:23 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, law
The following patch has been applied to the main. It contains everything
but the revised arg pointer handling proposed for hppa64. This patch fixes
a number of bugs in the handling of long calls as previously discussed
and moves the length computation for millicode and regular calls from
pa.md to pa.c.
This version has been tested on hppa64-hp-hpux11.11 and hppa-unknown-linux-gnu.
Applied
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-10-30 John David Anglin <dave@hiauly.hia.nrc.ca>
* pa-linux.h (ASM_OUTPUT_EXTERNAL_LIBCALL): Define.
* pa-protos.h (attr_length_millicode_call, attr_length_call,
pa_init_machine_status): Declare new global functions.
* pa.c (void copy_fp_args, length_fp_args, get_plabel): Declare and
implement new functions.
(attr_length_millicode_call, attr_length_call): Implement.
(total_code_bytes): Change type to long.
(pa_output_function_prologue): Compute total_code_bytes on TARGET_64BIT.
Reset counter if flag_function_sections.
(output_deferred_plabels): Set output alignment to 3 for TARGET_64BIT.
(output_cbranch): Move call to gen_label_rtx.
(output_millicode_call): Rewrite adding long TARGET_64BIT call, expose
delay slot in all variants, shorten pc-relative calls.
(output_call): Rewrite adding long TARGET_64BIT call, improved delay
slot usage and exposure, various new call variants, and shortened
sequences for some variants on TARGET_PA_20.
Miscellaneous format changes.
* pa.h (total_code_bytes): Change type to long.
(MASK_LONG_CALLS, TARGET_LONG_CALLS, TARGET_LONG_ABS_CALL,
TARGET_LONG_PIC_SDIFF_CALL, TARGET_LONG_PIC_PCREL_CALL): Define.
(TARGET_SWITCHES): Add "-mlong-calls" and "-mno-long-calls" options.
(EXTRA_CONSTRAINT, GO_IF_LEGITIMATE_ADDRESS,
LEGITIMIZE_RELOAD_ADDRESS): Don't use long floating point loads and
stores on TARGET_ELF32.
*pa.md (define_delay): Allow insns in delay on TARGET_PORTABLE_RUNTIME.
(unnamed patterns for mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
canonicalize_funcptr_for_compare expanders): Calculate attribute length
attr_length_millicode_call().
(call_internal_symref, call_value_internal_symref): Clobber register 1.
Calculate attribute length using attr_length_call().
(call_internal_reg_64bit, call_value_internal_reg_64bit): Move gp load
to delay slot.
(sibcall, sibcall_value): Rewrite.
(sibcall_internal_symref, sibcall_value_internal_symref): Clobber
register 1. Use attr_length_call().
(sibcall_internal_symref_64bit, sibcall_value_internal_symref_64bit):
New patterns.
(unamed pattern for canonicalize_funcptr_for_compare): Rewrite.
* som.h (MEMBER_TYPE_FORCES_BLK): Define.
* t-pa64 (TARGET_LIBGCC2_CFLAGS): Add "-mlong-calls".
* doc/invoke.texi (mlong-calls): Document.
Index: config/pa/pa-linux.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-linux.h,v
retrieving revision 1.26
diff -u -3 -p -r1.26 pa-linux.h
--- config/pa/pa-linux.h 3 Oct 2002 04:05:54 -0000 1.26
+++ config/pa/pa-linux.h 30 Oct 2002 17:06:37 -0000
@@ -196,6 +196,19 @@ Boston, MA 02111-1307, USA. */
} \
while (0)
+/* As well as globalizing the label, we need to encode the label
+ to ensure a plabel is generated in an indirect call. */
+
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+ do \
+ { \
+ if (!FUNCTION_NAME_P (XSTR (FUN, 0))) \
+ hppa_encode_label (FUN); \
+ (*targetm.asm_out.globalize_label) (FILE, XSTR (FUN, 0)); \
+ } \
+ while (0)
+
/* Linux always uses gas. */
#undef TARGET_GAS
#define TARGET_GAS 1
Index: config/pa/pa-protos.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-protos.h,v
retrieving revision 1.18
diff -u -3 -p -r1.18 pa-protos.h
--- config/pa/pa-protos.h 20 Oct 2002 22:37:12 -0000 1.18
+++ config/pa/pa-protos.h 30 Oct 2002 17:06:37 -0000
@@ -105,6 +105,8 @@ extern int jump_in_call_delay PARAMS ((r
extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
enum machine_mode, rtx));
extern int hppa_fpstore_bypass_p PARAMS ((rtx, rtx));
+extern int attr_length_millicode_call PARAMS ((rtx, int));
+extern int attr_length_call PARAMS ((rtx, int));
/* Declare functions defined in pa.c and used in templates. */
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.184
diff -u -3 -p -r1.184 pa.c
--- config/pa/pa.c 22 Oct 2002 23:05:19 -0000 1.184
+++ config/pa/pa.c 30 Oct 2002 17:06:42 -0000
@@ -121,11 +121,13 @@ static void pa_globalize_label PARAMS ((
ATTRIBUTE_UNUSED;
static void pa_asm_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree));
-
+static void copy_fp_args PARAMS ((rtx)) ATTRIBUTE_UNUSED;
+static int length_fp_args PARAMS ((rtx)) ATTRIBUTE_UNUSED;
+static struct deferred_plabel *get_plabel PARAMS ((const char *))
+ ATTRIBUTE_UNUSED;
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
-
rtx hppa_compare_op0, hppa_compare_op1;
enum cmp_type hppa_branch_type;
@@ -149,12 +151,10 @@ static rtx find_addr_reg PARAMS ((rtx));
/* Keep track of the number of bytes we have output in the CODE subspaces
during this compilation so we'll know when to emit inline long-calls. */
-
-unsigned int total_code_bytes;
+unsigned long total_code_bytes;
/* Variables to handle plabels that we discover are necessary at assembly
output time. They are output after the current function. */
-
struct deferred_plabel GTY(())
{
rtx internal_label;
@@ -3197,14 +3197,14 @@ pa_output_function_prologue (file, size)
fputs ("\n\t.ENTRY\n", file);
/* If we're using GAS and SOM, and not using the portable runtime model,
- then we don't need to accumulate the total number of code bytes. */
+ or function sections, then we don't need to accumulate the total number
+ of code bytes. */
if ((TARGET_GAS && TARGET_SOM && ! TARGET_PORTABLE_RUNTIME)
- /* FIXME: we can't handle long calls for TARGET_64BIT. */
- || TARGET_64BIT)
+ || flag_function_sections)
total_code_bytes = 0;
else if (INSN_ADDRESSES_SET_P ())
{
- unsigned int old_total = total_code_bytes;
+ unsigned long old_total = total_code_bytes;
total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_nonnote_insn ()));
total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
@@ -4726,6 +4726,47 @@ output_global_address (file, x, round_co
output_addr_const (file, x);
}
+static struct deferred_plabel *
+get_plabel (fname)
+ const char *fname;
+{
+ size_t i;
+
+ /* See if we have already put this function on the list of deferred
+ plabels. This list is generally small, so a liner search is not
+ too ugly. If it proves too slow replace it with something faster. */
+ for (i = 0; i < n_deferred_plabels; i++)
+ if (strcmp (fname, deferred_plabels[i].name) == 0)
+ break;
+
+ /* If the deferred plabel list is empty, or this entry was not found
+ on the list, create a new entry on the list. */
+ if (deferred_plabels == NULL || i == n_deferred_plabels)
+ {
+ const char *real_name;
+
+ if (deferred_plabels == 0)
+ deferred_plabels = (struct deferred_plabel *)
+ ggc_alloc (sizeof (struct deferred_plabel));
+ else
+ deferred_plabels = (struct deferred_plabel *)
+ ggc_realloc (deferred_plabels,
+ ((n_deferred_plabels + 1)
+ * sizeof (struct deferred_plabel)));
+
+ i = n_deferred_plabels++;
+ deferred_plabels[i].internal_label = gen_label_rtx ();
+ deferred_plabels[i].name = ggc_strdup (fname);
+
+ /* Gross. We have just implicitly taken the address of this function,
+ mark it as such. */
+ real_name = (*targetm.strip_name_encoding) (fname);
+ TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
+ }
+
+ return &deferred_plabels[i];
+}
+
void
output_deferred_plabels (file)
FILE *file;
@@ -4737,7 +4778,7 @@ output_deferred_plabels (file)
if (n_deferred_plabels)
{
data_section ();
- ASM_OUTPUT_ALIGN (file, 2);
+ ASM_OUTPUT_ALIGN (file, TARGET_64BIT ? 3 : 2);
}
/* Now output the deferred plabels. */
@@ -5323,9 +5364,9 @@ hppa_va_arg (valist, type)
const char *
output_cbranch (operands, nullify, length, negated, insn)
- rtx *operands;
- int nullify, length, negated;
- rtx insn;
+ rtx *operands;
+ int nullify, length, negated;
+ rtx insn;
{
static char buf[100];
int useskip = 0;
@@ -5499,12 +5540,11 @@ output_cbranch (operands, nullify, lengt
xoperands[1] = operands[1];
xoperands[2] = operands[2];
xoperands[3] = operands[3];
- if (TARGET_SOM || ! TARGET_GAS)
- xoperands[4] = gen_label_rtx ();
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
- if (TARGET_SOM || ! TARGET_GAS)
+ if (TARGET_SOM || !TARGET_GAS)
{
+ xoperands[4] = gen_label_rtx ();
output_asm_insn ("addil L'%l0-%l4,%%r1", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[4]));
@@ -5536,10 +5576,10 @@ output_cbranch (operands, nullify, lengt
const char *
output_bb (operands, nullify, length, negated, insn, which)
- rtx *operands ATTRIBUTE_UNUSED;
- int nullify, length, negated;
- rtx insn;
- int which;
+ rtx *operands ATTRIBUTE_UNUSED;
+ int nullify, length, negated;
+ rtx insn;
+ int which;
{
static char buf[100];
int useskip = 0;
@@ -5684,10 +5724,10 @@ output_bb (operands, nullify, length, ne
const char *
output_bvb (operands, nullify, length, negated, insn, which)
- rtx *operands ATTRIBUTE_UNUSED;
- int nullify, length, negated;
- rtx insn;
- int which;
+ rtx *operands ATTRIBUTE_UNUSED;
+ int nullify, length, negated;
+ rtx insn;
+ int which;
{
static char buf[100];
int useskip = 0;
@@ -6043,442 +6083,594 @@ output_movb (operands, insn, which_alter
}
}
+/* Copy any FP arguments in INSN into integer registers. */
+static void
+copy_fp_args (insn)
+ rtx insn;
+{
+ rtx link;
+ rtx xoperands[2];
-/* INSN is a millicode call. It may have an unconditional jump in its delay
- slot.
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ {
+ int arg_mode, regno;
+ rtx use = XEXP (link, 0);
- CALL_DEST is the routine we are calling. */
+ if (! (GET_CODE (use) == USE
+ && GET_CODE (XEXP (use, 0)) == REG
+ && FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
+ continue;
-const char *
-output_millicode_call (insn, call_dest)
- rtx insn;
- rtx call_dest;
-{
- int attr_length = get_attr_length (insn);
- int seq_length = dbr_sequence_length ();
- int distance;
- rtx xoperands[4];
- rtx seq_insn;
+ arg_mode = GET_MODE (XEXP (use, 0));
+ regno = REGNO (XEXP (use, 0));
- xoperands[3] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
+ /* Is it a floating point register? */
+ if (regno >= 32 && regno <= 39)
+ {
+ /* Copy the FP register into an integer register via memory. */
+ if (arg_mode == SFmode)
+ {
+ xoperands[0] = XEXP (use, 0);
+ xoperands[1] = gen_rtx_REG (SImode, 26 - (regno - 32) / 2);
+ output_asm_insn ("{fstws|fstw} %0,-16(%%sr0,%%r30)", xoperands);
+ output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
+ }
+ else
+ {
+ xoperands[0] = XEXP (use, 0);
+ xoperands[1] = gen_rtx_REG (DImode, 25 - (regno - 34) / 2);
+ output_asm_insn ("{fstds|fstd} %0,-16(%%sr0,%%r30)", xoperands);
+ output_asm_insn ("ldw -12(%%sr0,%%r30),%R1", xoperands);
+ output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
+ }
+ }
+ }
+}
+
+/* Compute length of the FP argument copy sequence for INSN. */
+static int
+length_fp_args (insn)
+ rtx insn;
+{
+ int length = 0;
+ rtx link;
- /* Handle common case -- empty delay slot or no jump in the delay slot,
- and we're sure that the branch will reach the beginning of the $CODE$
- subspace. The within reach form of the $$sh_func_adrs call has
- a length of 28 and attribute type of multi. This length is the
- same as the maximum length of an out of reach PIC call to $$div. */
- if ((seq_length == 0
- && (attr_length == 8
- || (attr_length == 28 && get_attr_type (insn) == TYPE_MULTI)))
- || (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
- && attr_length == 4))
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
{
- xoperands[0] = call_dest;
- output_asm_insn ("{bl|b,l} %0,%3%#", xoperands);
- return "";
+ int arg_mode, regno;
+ rtx use = XEXP (link, 0);
+
+ if (! (GET_CODE (use) == USE
+ && GET_CODE (XEXP (use, 0)) == REG
+ && FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
+ continue;
+
+ arg_mode = GET_MODE (XEXP (use, 0));
+ regno = REGNO (XEXP (use, 0));
+
+ /* Is it a floating point register? */
+ if (regno >= 32 && regno <= 39)
+ {
+ if (arg_mode == SFmode)
+ length += 8;
+ else
+ length += 12;
+ }
}
- /* This call may not reach the beginning of the $CODE$ subspace. */
- if (attr_length > 8)
+ return length;
+}
+
+/* We include the delay slot in the returned length as it is better to
+ over estimate the length than to under estimate it. */
+
+int
+attr_length_millicode_call (insn, length)
+ rtx insn;
+ int length;
+{
+ unsigned long distance = total_code_bytes + INSN_ADDRESSES (INSN_UID (insn));
+
+ if (distance < total_code_bytes)
+ distance = -1;
+
+ if (TARGET_64BIT)
{
- int delay_insn_deleted = 0;
+ if (!TARGET_LONG_CALLS && distance < 7600000)
+ return length + 8;
- /* We need to emit an inline long-call branch. */
- if (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
- {
- /* A non-jump insn in the delay slot. By definition we can
- emit this insn before the call. */
- final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
+ return length + 20;
+ }
+ else if (TARGET_PORTABLE_RUNTIME)
+ return length + 24;
+ else
+ {
+ if (!TARGET_LONG_CALLS && distance < 240000)
+ return length + 8;
- /* Now delete the delay insn. */
- PUT_CODE (NEXT_INSN (insn), NOTE);
- NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
- delay_insn_deleted = 1;
- }
+ if (TARGET_LONG_ABS_CALL && !flag_pic)
+ return length + 12;
- /* PIC long millicode call sequence. */
- if (flag_pic)
- {
- xoperands[0] = call_dest;
- if (TARGET_SOM || ! TARGET_GAS)
- xoperands[1] = gen_label_rtx ();
+ return length + 24;
+ }
+}
- /* Get our address + 8 into %r1. */
- output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+/* INSN is a function call. It may have an unconditional jump
+ in its delay slot.
- if (TARGET_SOM || ! TARGET_GAS)
- {
- /* Add %r1 to the offset of our target from the next insn. */
- output_asm_insn ("addil L%%%0-%1,%%r1", xoperands);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xoperands[1]));
- output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
- }
- else
- {
- output_asm_insn ("addil L%%%0-$PIC_pcrel$0+4,%%r1", xoperands);
- output_asm_insn ("ldo R%%%0-$PIC_pcrel$0+8(%%r1),%%r1",
- xoperands);
- }
+ CALL_DEST is the routine we are calling. */
- /* Get the return address into %r31. */
- output_asm_insn ("blr 0,%3", xoperands);
+const char *
+output_millicode_call (insn, call_dest)
+ rtx insn;
+ rtx call_dest;
+{
+ int attr_length = get_attr_length (insn);
+ int seq_length = dbr_sequence_length ();
+ int distance;
+ rtx seq_insn;
+ rtx xoperands[3];
- /* Branch to our target which is in %r1. */
- output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
+ xoperands[0] = call_dest;
+ xoperands[2] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
- /* Empty delay slot. Note this insn gets fetched twice and
- executed once. To be safe we use a nop. */
- output_asm_insn ("nop", xoperands);
+ /* Handle the common case where we are sure that the branch will
+ reach the beginning of the $CODE$ subspace. The within reach
+ form of the $$sh_func_adrs call has a length of 28. Because
+ it has an attribute type of multi, it never has a non-zero
+ sequence length. The length of the $$sh_func_adrs is the same
+ as certain out of reach PIC calls to other routines. */
+ if (!TARGET_LONG_CALLS
+ && ((seq_length == 0
+ && (attr_length == 12
+ || (attr_length == 28 && get_attr_type (insn) == TYPE_MULTI)))
+ || (seq_length != 0 && attr_length == 8)))
+ {
+ output_asm_insn ("{bl|b,l} %0,%2", xoperands);
+ }
+ else
+ {
+ if (TARGET_64BIT)
+ {
+ /* It might seem that one insn could be saved by accessing
+ the millicode function using the linkage table. However,
+ this doesn't work in shared libraries and other dynamically
+ loaded objects. Using a pc-relative sequence also avoids
+ problems related to the implicit use of the gp register. */
+ output_asm_insn ("b,l .+8,%%r1", xoperands);
+ output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
+ output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
+ output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
}
- /* Pure portable runtime doesn't allow be/ble; we also don't have
- PIC support in the assembler/linker, so this sequence is needed. */
else if (TARGET_PORTABLE_RUNTIME)
{
- xoperands[0] = call_dest;
- /* Get the address of our target into %r29. */
- output_asm_insn ("ldil L%%%0,%%r29", xoperands);
- output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
+ /* Pure portable runtime doesn't allow be/ble; we also don't
+ have PIC support in the assembler/linker, so this sequence
+ is needed. */
+
+ /* Get the address of our target into %r1. */
+ output_asm_insn ("ldil L'%0,%%r1", xoperands);
+ output_asm_insn ("ldo R'%0(%%r1),%%r1", xoperands);
/* Get our return address into %r31. */
- output_asm_insn ("blr %%r0,%3", xoperands);
+ output_asm_insn ("{bl|b,l} .+8,%%r31", xoperands);
+ output_asm_insn ("addi 8,%%r31,%%r31", xoperands);
- /* Jump to our target address in %r29. */
- output_asm_insn ("bv,n %%r0(%%r29)", xoperands);
-
- /* Empty delay slot. Note this insn gets fetched twice and
- executed once. To be safe we use a nop. */
- output_asm_insn ("nop", xoperands);
+ /* Jump to our target address in %r1. */
+ output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
- /* If we're allowed to use be/ble instructions, then this is the
- best sequence to use for a long millicode call. */
- else
+ else if (!flag_pic)
{
- xoperands[0] = call_dest;
- output_asm_insn ("ldil L%%%0,%3", xoperands);
+ output_asm_insn ("ldil L'%0,%%r1", xoperands);
if (TARGET_PA_20)
- output_asm_insn ("be,l R%%%0(%%sr4,%3),%%sr0,%%r31", xoperands);
+ output_asm_insn ("be,l R'%0(%%sr4,%%r1),%%sr0,%%r31", xoperands);
else
- output_asm_insn ("ble R%%%0(%%sr4,%3)", xoperands);
- output_asm_insn ("nop", xoperands);
+ output_asm_insn ("ble R'%0(%%sr4,%%r1)", xoperands);
}
-
- /* If we had a jump in the call's delay slot, output it now. */
- if (seq_length != 0 && !delay_insn_deleted)
+ else
{
- xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- output_asm_insn ("b,n %0", xoperands);
+ if (TARGET_SOM || !TARGET_GAS)
+ {
+ /* The HP assembler can generate relocations for the
+ difference of two symbols. GAS can do this for a
+ millicode symbol but not an arbitrary external
+ symbol when generating SOM output. */
+ xoperands[1] = gen_label_rtx ();
+ output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ output_asm_insn ("addi 16,%%r1,%%r31", xoperands);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xoperands[1]));
+ output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
+ output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ output_asm_insn ("addi 16,%%r1,%%r31", xoperands);
+ output_asm_insn ("addil L'%0-$PIC_pcrel$0+8,%%r1", xoperands);
+ output_asm_insn ("ldo R'%0-$PIC_pcrel$0+12(%%r1),%%r1",
+ xoperands);
+ }
- /* Now delete the delay insn. */
- PUT_CODE (NEXT_INSN (insn), NOTE);
- NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+ /* Jump to our target address in %r1. */
+ output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
- return "";
}
- /* This call has an unconditional jump in its delay slot and the
- call is known to reach its target or the beginning of the current
- subspace. */
-
- /* Use the containing sequence insn's address. */
- seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
+ if (seq_length == 0)
+ output_asm_insn ("nop", xoperands);
- distance = INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
- - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
+ /* We are done if there isn't a jump in the delay slot. */
+ if (seq_length == 0 || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
+ return "";
- /* If the branch was too far away, emit a normal call followed
- by a nop, followed by the unconditional branch.
+ /* This call has an unconditional jump in its delay slot. */
+ xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- If the branch is close, then adjust %r2 from within the
- call's delay slot. */
+ /* See if the return address can be adjusted. Use the containing
+ sequence insn's address. */
+ seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
+ distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
+ - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
- xoperands[0] = call_dest;
- xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- if (! VAL_14_BITS_P (distance))
- output_asm_insn ("{bl|b,l} %0,%3\n\tnop\n\tb,n %1", xoperands);
- else
+ if (VAL_14_BITS_P (distance))
{
- xoperands[2] = gen_label_rtx ();
- output_asm_insn ("\n\t{bl|b,l} %0,%3\n\tldo %1-%2(%3),%3",
- xoperands);
+ xoperands[1] = gen_label_rtx ();
+ output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xoperands[2]));
+ CODE_LABEL_NUMBER (xoperands[3]));
}
+ else
+ /* ??? This branch may not reach its target. */
+ output_asm_insn ("nop\n\tb,n %0", xoperands);
/* Delete the jump. */
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+
return "";
}
-/* INSN is either a function call. It may have an unconditional jump
+/* We include the delay slot in the returned length as it is better to
+ over estimate the length than to under estimate it. */
+
+int
+attr_length_call (insn, sibcall)
+ rtx insn;
+ int sibcall;
+{
+ unsigned long distance = total_code_bytes + INSN_ADDRESSES (INSN_UID (insn));
+
+ if (distance < total_code_bytes)
+ distance = -1;
+
+ if (TARGET_64BIT)
+ {
+ if (!TARGET_LONG_CALLS
+ && ((!sibcall && distance < 7600000) || distance < 240000))
+ return 8;
+
+ return (sibcall ? 28 : 24);
+ }
+ else
+ {
+ if (!TARGET_LONG_CALLS
+ && ((TARGET_PA_20 && !sibcall && distance < 7600000)
+ || distance < 240000))
+ return 8;
+
+ if (TARGET_LONG_ABS_CALL && !flag_pic)
+ return 12;
+
+ if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
+ || (TARGET_GAS && TARGET_LONG_PIC_PCREL_CALL))
+ {
+ if (TARGET_PA_20)
+ return 20;
+
+ return 28;
+ }
+ else
+ {
+ int length = 0;
+
+ if (TARGET_SOM)
+ length += length_fp_args (insn);
+
+ if (flag_pic)
+ length += 4;
+
+ if (TARGET_PA_20)
+ return (length + 32);
+
+ if (!sibcall)
+ length += 8;
+
+ return (length + 40);
+ }
+ }
+}
+
+/* INSN is a function call. It may have an unconditional jump
in its delay slot.
CALL_DEST is the routine we are calling. */
const char *
output_call (insn, call_dest, sibcall)
- rtx insn;
- rtx call_dest;
- int sibcall;
+ rtx insn;
+ rtx call_dest;
+ int sibcall;
{
+ int delay_insn_deleted = 0;
+ int delay_slot_filled = 0;
int attr_length = get_attr_length (insn);
int seq_length = dbr_sequence_length ();
- int distance;
- rtx xoperands[4];
- rtx seq_insn;
+ rtx xoperands[2];
+
+ xoperands[0] = call_dest;
- /* Handle common case -- empty delay slot or no jump in the delay slot,
- and we're sure that the branch will reach the beginning of the $CODE$
- subspace. */
- if ((seq_length == 0 && attr_length == 12)
- || (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
- && attr_length == 8))
+ /* Handle the common case where we're sure that the branch will reach
+ the beginning of the $CODE$ subspace. */
+ if (!TARGET_LONG_CALLS
+ && ((seq_length == 0 && attr_length == 12)
+ || (seq_length != 0 && attr_length == 8)))
{
- xoperands[0] = call_dest;
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
- output_asm_insn ("{bl|b,l} %0,%1%#", xoperands);
- return "";
+ output_asm_insn ("{bl|b,l} %0,%1", xoperands);
}
-
- /* This call may not reach the beginning of the $CODE$ subspace. */
- if (attr_length > 12)
+ else
{
- int delay_insn_deleted = 0;
- rtx xoperands[2];
- rtx link;
-
- /* We need to emit an inline long-call branch. Furthermore,
- because we're changing a named function call into an indirect
- function call well after the parameters have been set up, we
- need to make sure any FP args appear in both the integer
- and FP registers. Also, we need move any delay slot insn
- out of the delay slot. And finally, we can't rely on the linker
- being able to fix the call to $$dyncall! -- Yuk!. */
- if (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
- {
- /* A non-jump insn in the delay slot. By definition we can
- emit this insn before the call (and in fact before argument
- relocating. */
- final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
-
- /* Now delete the delay insn. */
- PUT_CODE (NEXT_INSN (insn), NOTE);
- NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
- delay_insn_deleted = 1;
- }
-
- /* Now copy any FP arguments into integer registers. */
- for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
- {
- int arg_mode, regno;
- rtx use = XEXP (link, 0);
- if (! (GET_CODE (use) == USE
- && GET_CODE (XEXP (use, 0)) == REG
- && FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
- continue;
-
- arg_mode = GET_MODE (XEXP (use, 0));
- regno = REGNO (XEXP (use, 0));
- /* Is it a floating point register? */
- if (regno >= 32 && regno <= 39)
- {
- /* Copy from the FP register into an integer register
- (via memory). */
- if (arg_mode == SFmode)
- {
- xoperands[0] = XEXP (use, 0);
- xoperands[1] = gen_rtx_REG (SImode, 26 - (regno - 32) / 2);
- output_asm_insn ("{fstws|fstw} %0,-16(%%sr0,%%r30)",
- xoperands);
- output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
- }
- else
- {
- xoperands[0] = XEXP (use, 0);
- xoperands[1] = gen_rtx_REG (DImode, 25 - (regno - 34) / 2);
- output_asm_insn ("{fstds|fstd} %0,-16(%%sr0,%%r30)",
- xoperands);
- output_asm_insn ("ldw -12(%%sr0,%%r30),%R1", xoperands);
- output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
- }
+ if (TARGET_64BIT)
+ {
+ /* ??? As far as I can tell, the HP linker doesn't support the
+ long pc-relative sequence described in the 64-bit runtime
+ architecture. So, we use a slightly longer indirect call. */
+ struct deferred_plabel *p = get_plabel (XSTR (call_dest, 0));
+
+ xoperands[0] = p->internal_label;
+ xoperands[1] = gen_label_rtx ();
+
+ /* If this isn't a sibcall, we put the load of %r27 into the
+ delay slot. We can't do this in a sibcall as we don't
+ have a second call-clobbered scratch register available. */
+ if (seq_length != 0
+ && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
+ && !sibcall)
+ {
+ final_scan_insn (NEXT_INSN (insn), asm_out_file,
+ optimize, 0, 0);
+
+ /* Now delete the delay insn. */
+ PUT_CODE (NEXT_INSN (insn), NOTE);
+ NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+ delay_insn_deleted = 1;
+ }
+
+ output_asm_insn ("addil LT'%0,%%r27", xoperands);
+ output_asm_insn ("ldd RT'%0(%%r1),%%r1", xoperands);
+ output_asm_insn ("ldd 0(%%r1),%%r1", xoperands);
+
+ if (sibcall)
+ {
+ output_asm_insn ("ldd 24(%%r1),%%r27", xoperands);
+ output_asm_insn ("ldd 16(%%r1),%%r1", xoperands);
+ output_asm_insn ("bve (%%r1)", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("ldd 16(%%r1),%%r2", xoperands);
+ output_asm_insn ("bve,l (%%r2),%%r2", xoperands);
+ output_asm_insn ("ldd 24(%%r1),%%r27", xoperands);
+ delay_slot_filled = 1;
}
}
-
- /* Don't have to worry about TARGET_PORTABLE_RUNTIME here since
- we don't have any direct calls in that case. */
+ else
{
- size_t i;
- const char *name = XSTR (call_dest, 0);
+ int indirect_call = 0;
- /* See if we have already put this function on the list
- of deferred plabels. This list is generally small,
- so a liner search is not too ugly. If it proves too
- slow replace it with something faster. */
- for (i = 0; i < n_deferred_plabels; i++)
- if (strcmp (name, deferred_plabels[i].name) == 0)
- break;
-
- /* If the deferred plabel list is empty, or this entry was
- not found on the list, create a new entry on the list. */
- if (deferred_plabels == NULL || i == n_deferred_plabels)
- {
- const char *real_name;
-
- if (deferred_plabels == 0)
- deferred_plabels = (struct deferred_plabel *)
- ggc_alloc (sizeof (struct deferred_plabel));
+ /* Emit a long call. There are several different sequences
+ of increasing length and complexity. In most cases,
+ they don't allow an instruction in the delay slot. */
+ if (!(TARGET_LONG_ABS_CALL && !flag_pic)
+ && !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
+ && !(TARGET_GAS && TARGET_LONG_PIC_PCREL_CALL))
+ indirect_call = 1;
+
+ if (seq_length != 0
+ && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
+ && !sibcall
+ && (!TARGET_PA_20 || indirect_call))
+ {
+ /* A non-jump insn in the delay slot. By definition we can
+ emit this insn before the call (and in fact before argument
+ relocating. */
+ final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
+
+ /* Now delete the delay insn. */
+ PUT_CODE (NEXT_INSN (insn), NOTE);
+ NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+ delay_insn_deleted = 1;
+ }
+
+ if (TARGET_LONG_ABS_CALL && !flag_pic)
+ {
+ /* This is the best sequence for making long calls in
+ non-pic code. Unfortunately, GNU ld doesn't provide
+ the stub needed for external calls, and GAS's support
+ for this with the SOM linker is buggy. */
+ output_asm_insn ("ldil L'%0,%%r1", xoperands);
+ if (sibcall)
+ output_asm_insn ("be R'%0(%%sr4,%%r1)", xoperands);
else
- deferred_plabels = (struct deferred_plabel *)
- ggc_realloc (deferred_plabels,
- ((n_deferred_plabels + 1)
- * sizeof (struct deferred_plabel)));
-
- i = n_deferred_plabels++;
- deferred_plabels[i].internal_label = gen_label_rtx ();
- deferred_plabels[i].name = ggc_strdup (name);
-
- /* Gross. We have just implicitly taken the address of this
- function, mark it as such. */
- real_name = (*targetm.strip_name_encoding) (name);
- TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
- }
-
- /* We have to load the address of the function using a procedure
- label (plabel). Inline plabels can lose for PIC and other
- cases, so avoid them by creating a 32bit plabel in the data
- segment. */
- if (flag_pic)
- {
- xoperands[0] = deferred_plabels[i].internal_label;
- if (TARGET_SOM || ! TARGET_GAS)
- xoperands[1] = gen_label_rtx ();
-
- output_asm_insn ("addil LT%%%0,%%r19", xoperands);
- output_asm_insn ("ldw RT%%%0(%%r1),%%r22", xoperands);
- output_asm_insn ("ldw 0(%%r22),%%r22", xoperands);
-
- /* Get our address + 8 into %r1. */
- output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ {
+ if (TARGET_PA_20)
+ output_asm_insn ("be,l R'%0(%%sr4,%%r1),%%sr0,%%r31",
+ xoperands);
+ else
+ output_asm_insn ("ble R'%0(%%sr4,%%r1)", xoperands);
- if (TARGET_SOM || ! TARGET_GAS)
+ output_asm_insn ("copy %%r31,%%r2", xoperands);
+ delay_slot_filled = 1;
+ }
+ }
+ else
+ {
+ if (TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
{
- /* Add %r1 to the offset of dyncall from the next insn. */
- output_asm_insn ("addil L%%$$dyncall-%1,%%r1", xoperands);
+ /* The HP assembler and linker can handle relocations
+ for the difference of two symbols. GAS and the HP
+ linker can't do this when one of the symbols is
+ external. */
+ xoperands[1] = gen_label_rtx ();
+ output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
- output_asm_insn ("ldo R%%$$dyncall-%1(%%r1),%%r1", xoperands);
- }
- else
+ output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
+ }
+ else if (TARGET_GAS && TARGET_LONG_PIC_PCREL_CALL)
{
- output_asm_insn ("addil L%%$$dyncall-$PIC_pcrel$0+4,%%r1",
+ /* GAS currently can't generate the relocations that
+ are needed for the SOM linker under HP-UX using this
+ sequence. The GNU linker doesn't generate the stubs
+ that are needed for external calls on TARGET_ELF32
+ with this sequence. For now, we have to use a
+ longer plabel sequence when using GAS. */
+ output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1",
xoperands);
- output_asm_insn ("ldo R%%$$dyncall-$PIC_pcrel$0+8(%%r1),%%r1",
+ output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1",
xoperands);
}
+ else
+ {
+ /* Emit a long plabel-based call sequence. This is
+ essentially an inline implementation of $$dyncall.
+ We don't actually try to call $$dyncall as this is
+ as difficult as calling the function itself. */
+ struct deferred_plabel *p = get_plabel (XSTR (call_dest, 0));
+
+ xoperands[0] = p->internal_label;
+ xoperands[1] = gen_label_rtx ();
+
+ /* Since the call is indirect, FP arguments in registers
+ need to be copied to the general registers. Then, the
+ argument relocation stub will copy them back. */
+ if (TARGET_SOM)
+ copy_fp_args (insn);
- /* Get the return address into %r31. */
- output_asm_insn ("blr %%r0,%%r31", xoperands);
+ if (flag_pic)
+ {
+ output_asm_insn ("addil LT'%0,%%r19", xoperands);
+ output_asm_insn ("ldw RT'%0(%%r1),%%r1", xoperands);
+ output_asm_insn ("ldw 0(%%r1),%%r1", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("addil LR'%0-$global$,%%r27",
+ xoperands);
+ output_asm_insn ("ldw RR'%0-$global$(%%r1),%%r1",
+ xoperands);
+ }
- /* Branch to our target which is in %r1. */
- output_asm_insn ("bv %%r0(%%r1)", xoperands);
+ output_asm_insn ("bb,>=,n %%r1,30,.+16", xoperands);
+ output_asm_insn ("depi 0,31,2,%%r1", xoperands);
+ output_asm_insn ("ldw 4(%%sr0,%%r1),%%r19", xoperands);
+ output_asm_insn ("ldw 0(%%sr0,%%r1),%%r1", xoperands);
- if (sibcall)
- {
- /* This call never returns, so we do not need to fix the
- return pointer. */
- output_asm_insn ("nop", xoperands);
- }
- else
- {
- /* Copy the return address into %r2 also. */
- output_asm_insn ("copy %%r31,%%r2", xoperands);
+ if (!sibcall && !TARGET_PA_20)
+ {
+ output_asm_insn ("{bl|b,l} .+8,%%r2", xoperands);
+ output_asm_insn ("addi 16,%%r2,%%r2", xoperands);
+ }
}
- }
- else
- {
- xoperands[0] = deferred_plabels[i].internal_label;
- /* Get the address of our target into %r22. */
- output_asm_insn ("addil LR%%%0-$global$,%%r27", xoperands);
- output_asm_insn ("ldw RR%%%0-$global$(%%r1),%%r22", xoperands);
-
- /* Get the high part of the address of $dyncall into %r2, then
- add in the low part in the branch instruction. */
- output_asm_insn ("ldil L%%$$dyncall,%%r2", xoperands);
if (TARGET_PA_20)
- output_asm_insn ("be,l R%%$$dyncall(%%sr4,%%r2),%%sr0,%%r31",
- xoperands);
- else
- output_asm_insn ("ble R%%$$dyncall(%%sr4,%%r2)", xoperands);
-
- if (sibcall)
{
- /* This call never returns, so we do not need to fix the
- return pointer. */
- output_asm_insn ("nop", xoperands);
+ if (sibcall)
+ output_asm_insn ("bve (%%r1)", xoperands);
+ else
+ {
+ if (indirect_call)
+ {
+ output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
+ output_asm_insn ("stw %%r2,-24(%%sp)", xoperands);
+ delay_slot_filled = 1;
+ }
+ else
+ output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
+ }
}
else
{
- /* Copy the return address into %r2 also. */
- output_asm_insn ("copy %%r31,%%r2", xoperands);
- }
- }
- }
+ output_asm_insn ("ldsid (%%r1),%%r31\n\tmtsp %%r31,%%sr0",
+ xoperands);
- /* If we had a jump in the call's delay slot, output it now. */
- if (seq_length != 0 && !delay_insn_deleted)
- {
- xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- output_asm_insn ("b,n %0", xoperands);
+ if (sibcall)
+ output_asm_insn ("be 0(%%sr0,%%r1)", xoperands);
+ else
+ {
+ output_asm_insn ("ble 0(%%sr0,%%r1)", xoperands);
- /* Now delete the delay insn. */
- PUT_CODE (NEXT_INSN (insn), NOTE);
- NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+ if (indirect_call)
+ output_asm_insn ("stw %%r31,-24(%%sp)", xoperands);
+ else
+ output_asm_insn ("copy %%r31,%%r2", xoperands);
+ delay_slot_filled = 1;
+ }
+ }
+ }
}
- return "";
}
- /* This call has an unconditional jump in its delay slot and the
- call is known to reach its target or the beginning of the current
- subspace. */
+ if (seq_length == 0 || (delay_insn_deleted && !delay_slot_filled))
+ output_asm_insn ("nop", xoperands);
- /* Use the containing sequence insn's address. */
- seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
+ /* We are done if there isn't a jump in the delay slot. */
+ if (seq_length == 0
+ || delay_insn_deleted
+ || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
+ return "";
- distance = INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
- - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
+ /* A sibcall should never have a branch in the delay slot. */
+ if (sibcall)
+ abort ();
- /* If the branch is too far away, emit a normal call followed
- by a nop, followed by the unconditional branch. If the branch
- is close, then adjust %r2 in the call's delay slot. */
+ /* This call has an unconditional jump in its delay slot. */
+ xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- xoperands[0] = call_dest;
- xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- if (! VAL_14_BITS_P (distance))
- output_asm_insn ("{bl|b,l} %0,%%r2\n\tnop\n\tb,n %1", xoperands);
- else
+ if (!delay_slot_filled)
{
- xoperands[3] = gen_label_rtx ();
- output_asm_insn ("\n\t{bl|b,l} %0,%%r2\n\tldo %1-%3(%%r2),%%r2",
- xoperands);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xoperands[3]));
+ /* See if the return address can be adjusted. Use the containing
+ sequence insn's address. */
+ rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
+ int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
+ - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
+
+ if (VAL_14_BITS_P (distance))
+ {
+ xoperands[1] = gen_label_rtx ();
+ output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xoperands[3]));
+ }
+ else
+ /* ??? This branch may not reach its target. */
+ output_asm_insn ("nop\n\tb,n %0", xoperands);
}
+ else
+ /* ??? This branch may not reach its target. */
+ output_asm_insn ("b,n %0", xoperands);
/* Delete the jump. */
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+
return "";
}
@@ -6580,8 +6772,8 @@ pa_asm_output_mi_thunk (file, thunk_fnde
{
if (! TARGET_64BIT && ! TARGET_PORTABLE_RUNTIME && flag_pic)
{
- fprintf (file, "\taddil LT%%%s,%%r19\n", lab);
- fprintf (file, "\tldw RT%%%s(%%r1),%%r22\n", lab);
+ fprintf (file, "\taddil LT'%s,%%r19\n", lab);
+ fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab);
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
fprintf (file, "\tdepi 0,31,2,%%r22\n");
@@ -6603,13 +6795,13 @@ pa_asm_output_mi_thunk (file, thunk_fnde
{
if (! TARGET_64BIT && ! TARGET_PORTABLE_RUNTIME && flag_pic)
{
- fprintf (file, "\taddil L%%");
+ fprintf (file, "\taddil L'");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta);
- fprintf (file, ",%%r26\n\tldo R%%");
+ fprintf (file, ",%%r26\n\tldo R'");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta);
fprintf (file, "(%%r1),%%r26\n");
- fprintf (file, "\taddil LT%%%s,%%r19\n", lab);
- fprintf (file, "\tldw RT%%%s(%%r1),%%r22\n", lab);
+ fprintf (file, "\taddil LT'%s,%%r19\n", lab);
+ fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab);
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
fprintf (file, "\tdepi 0,31,2,%%r22\n");
@@ -6620,9 +6812,9 @@ pa_asm_output_mi_thunk (file, thunk_fnde
}
else
{
- fprintf (file, "\taddil L%%");
+ fprintf (file, "\taddil L'");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta);
- fprintf (file, ",%%r26\n\tb %s\n\tldo R%%", target_name);
+ fprintf (file, ",%%r26\n\tb %s\n\tldo R'", target_name);
fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta);
fprintf (file, "(%%r1),%%r26\n");
}
@@ -6634,7 +6826,7 @@ pa_asm_output_mi_thunk (file, thunk_fnde
data_section ();
fprintf (file, "\t.align 4\n");
ASM_OUTPUT_INTERNAL_LABEL (file, "LTHN", current_thunk_number);
- fprintf (file, "\t.word P%%%s\n", target_name);
+ fprintf (file, "\t.word P'%s\n", target_name);
function_section (thunk_fndecl);
}
current_thunk_number++;
Index: config/pa/pa.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.h,v
retrieving revision 1.173
diff -u -3 -p -r1.173 pa.h
--- config/pa/pa.h 20 Oct 2002 22:37:12 -0000 1.173
+++ config/pa/pa.h 30 Oct 2002 17:06:44 -0000
@@ -31,7 +31,7 @@ enum cmp_type /* comparison type */
};
/* For long call handling. */
-extern unsigned int total_code_bytes;
+extern unsigned long total_code_bytes;
/* Which processor to schedule for. */
@@ -152,6 +152,12 @@ extern int target_flags;
#define TARGET_GNU_LD (target_flags & MASK_GNU_LD)
#endif
+/* Force generation of long calls. */
+#define MASK_LONG_CALLS 32768
+#ifndef TARGET_LONG_CALLS
+#define TARGET_LONG_CALLS (target_flags & MASK_LONG_CALLS)
+#endif
+
#ifndef TARGET_PA_10
#define TARGET_PA_10 (target_flags & (MASK_PA_11 | MASK_PA_20) == 0)
#endif
@@ -179,6 +185,27 @@ extern int target_flags;
#define TARGET_SOM 0
#endif
+/* The following three defines are potential target switches. The current
+ defines are optimal given the current capabilities of GAS and GNU ld. */
+
+/* Define to a C expression evaluating to true to use long absolute calls.
+ Currently, only the HP assembler and SOM linker support long absolute
+ calls. They are used only in non-pic code. */
+#define TARGET_LONG_ABS_CALL (TARGET_SOM && !TARGET_GAS)
+
+/* Define to a C expression evaluating to true to use long pic symbol
+ difference calls. This is a call variant similar to the long pic
+ pc-relative call. Long pic symbol difference calls are only used with
+ the HP SOM linker. Currently, only the HP assembler supports these
+ calls. GAS doesn't allow an arbritrary difference of two symbols. */
+#define TARGET_LONG_PIC_SDIFF_CALL (!TARGET_GAS)
+
+/* Define to a C expression evaluating to true to use long pic
+ pc-relative calls. Long pic pc-relative calls are only used with
+ GAS. Currently, they are usable for calls within a module but
+ not for external calls. */
+#define TARGET_LONG_PIC_PCREL_CALL 0
+
/* Macro to define tables used to set the flags. This is a
list in braces of target switches with each switch being
{ "NAME", VALUE, "HELP_STRING" }. VALUE is the bits to set,
@@ -237,6 +264,10 @@ extern int target_flags;
N_("Generate code for huge switch statements") }, \
{ "no-big-switch", -MASK_BIG_SWITCH, \
N_("Do not generate code for huge switch statements") }, \
+ { "long-calls", MASK_LONG_CALLS, \
+ N_("Always generate long calls") }, \
+ { "no-long-calls", -MASK_LONG_CALLS, \
+ N_("Generate long calls only when needed") }, \
{ "linker-opt", 0, \
N_("Enable linker optimizations") }, \
SUBTARGET_SWITCHES \
@@ -1193,8 +1224,14 @@ extern int may_call_alloca;
/* Using DFmode forces only short displacements \
to be recognized as valid in reg+d addresses. \
However, this is not necessary for PA2.0 since\
- it has long FP loads/stores. */ \
+ it has long FP loads/stores. \
+ \
+ FIXME: the ELF32 linker clobbers the LSB of \
+ the FP register number in {fldw,fstw} insns. \
+ Thus, we only allow long FP loads/stores on \
+ TARGET_64BIT. */ \
&& memory_address_p ((TARGET_PA_20 \
+ && !TARGET_ELF32 \
? GET_MODE (OP) \
: DFmode), \
XEXP (OP, 0)) \
@@ -1300,7 +1337,7 @@ extern int may_call_alloca;
if (GET_CODE (index) == CONST_INT \
&& ((INT_14_BITS (index) \
&& (TARGET_SOFT_FLOAT \
- || (TARGET_PA_20 \
+ || (TARGET_PA_20 \
&& ((MODE == SFmode \
&& (INTVAL (index) % 4) == 0)\
|| (MODE == DFmode \
@@ -1327,6 +1364,7 @@ extern int may_call_alloca;
/* We can allow symbolic LO_SUM addresses\
for PA2.0. */ \
|| (TARGET_PA_20 \
+ && !TARGET_ELF32 \
&& GET_CODE (XEXP (X, 1)) != CONST_INT)\
|| ((MODE) != SFmode \
&& (MODE) != DFmode))) \
@@ -1340,6 +1378,7 @@ extern int may_call_alloca;
/* We can allow symbolic LO_SUM addresses\
for PA2.0. */ \
|| (TARGET_PA_20 \
+ && !TARGET_ELF32 \
&& GET_CODE (XEXP (X, 1)) != CONST_INT)\
|| ((MODE) != SFmode \
&& (MODE) != DFmode))) \
@@ -1354,7 +1393,7 @@ extern int may_call_alloca;
&& REG_OK_FOR_BASE_P (XEXP (X, 0)) \
&& GET_CODE (XEXP (X, 1)) == UNSPEC \
&& (TARGET_SOFT_FLOAT \
- || TARGET_PA_20 \
+ || (TARGET_PA_20 && !TARGET_ELF32) \
|| ((MODE) != SFmode \
&& (MODE) != DFmode))) \
goto ADDR; \
@@ -1386,7 +1425,7 @@ do { \
rtx new, temp = NULL_RTX; \
\
mask = (GET_MODE_CLASS (MODE) == MODE_FLOAT \
- ? (TARGET_PA_20 ? 0x3fff : 0x1f) : 0x3fff); \
+ ? (TARGET_PA_20 && !TARGET_ELF32 ? 0x3fff : 0x1f) : 0x3fff); \
\
if (optimize \
&& GET_CODE (AD) == PLUS) \
Index: config/pa/pa.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.md,v
retrieving revision 1.113
diff -u -3 -p -r1.113 pa.md
--- config/pa/pa.md 11 Sep 2002 02:45:09 -0000 1.113
+++ config/pa/pa.md 30 Oct 2002 17:06:46 -0000
@@ -105,12 +105,9 @@
(define_delay (eq_attr "type" "call")
[(eq_attr "in_call_delay" "true") (nil) (nil)])
-;; millicode call delay slot description. Note it disallows delay slot
-;; when TARGET_PORTABLE_RUNTIME is true.
+;; Millicode call delay slot description.
(define_delay (eq_attr "type" "milli")
- [(and (eq_attr "in_call_delay" "true")
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (const_int 0)))
- (nil) (nil)])
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
;; Return and other similar instructions.
(define_delay (eq_attr "type" "branch,parallel_branch")
@@ -4089,27 +4086,7 @@
"!TARGET_64BIT"
"* return output_mul_insn (0, insn);"
[(set_attr "type" "milli")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 4)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 24)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 20)]
-
-;; Out of reach, can use ble
- (const_int 12)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_insn ""
[(set (reg:SI 29) (mult:SI (reg:SI 26) (reg:SI 25)))
@@ -4120,7 +4097,7 @@
"TARGET_64BIT"
"* return output_mul_insn (0, insn);"
[(set_attr "type" "milli")
- (set (attr "length") (const_int 4))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_expand "muldi3"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4211,27 +4188,7 @@
"*
return output_div_insn (operands, 0, insn);"
[(set_attr "type" "milli")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 4)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 24)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 20)]
-
-;; Out of reach, can use ble
- (const_int 12)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_insn ""
[(set (reg:SI 29)
@@ -4245,7 +4202,7 @@
"*
return output_div_insn (operands, 0, insn);"
[(set_attr "type" "milli")
- (set (attr "length") (const_int 4))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_expand "udivsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
@@ -4261,6 +4218,7 @@
"
{
operands[3] = gen_reg_rtx (SImode);
+
if (TARGET_64BIT)
{
operands[5] = gen_rtx_REG (SImode, 2);
@@ -4287,27 +4245,7 @@
"*
return output_div_insn (operands, 1, insn);"
[(set_attr "type" "milli")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 4)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 24)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 20)]
-
-;; Out of reach, can use ble
- (const_int 12)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_insn ""
[(set (reg:SI 29)
@@ -4321,7 +4259,7 @@
"*
return output_div_insn (operands, 1, insn);"
[(set_attr "type" "milli")
- (set (attr "length") (const_int 4))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_expand "modsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
@@ -4360,27 +4298,7 @@
"*
return output_mod_insn (0, insn);"
[(set_attr "type" "milli")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 4)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 24)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 20)]
-
-;; Out of reach, can use ble
- (const_int 12)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_insn ""
[(set (reg:SI 29) (mod:SI (reg:SI 26) (reg:SI 25)))
@@ -4393,7 +4311,7 @@
"*
return output_mod_insn (0, insn);"
[(set_attr "type" "milli")
- (set (attr "length") (const_int 4))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_expand "umodsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
@@ -4432,27 +4350,7 @@
"*
return output_mod_insn (1, insn);"
[(set_attr "type" "milli")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 4)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 24)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 20)]
-
-;; Out of reach, can use ble
- (const_int 12)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
(define_insn ""
[(set (reg:SI 29) (umod:SI (reg:SI 26) (reg:SI 25)))
@@ -4465,7 +4363,7 @@
"*
return output_mod_insn (1, insn);"
[(set_attr "type" "milli")
- (set (attr "length") (const_int 4))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 0)"))])
;;- and instructions
;; We define DImode `and` so with DImode `not` we can get
@@ -6036,11 +5934,12 @@
call_insn = emit_call_insn (gen_call_internal_reg (operands[1]));
}
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
- if (TARGET_64BIT)
- use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
/* After each call we must restore the PIC register, even if it
doesn't appear to be used. */
@@ -6052,6 +5951,7 @@
(define_insn "call_internal_symref"
[(call (mem:SI (match_operand 0 "call_operand_address" ""))
(match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
(clobber (reg:SI 2))
(use (const_int 0))]
"! TARGET_PORTABLE_RUNTIME"
@@ -6061,21 +5961,7 @@
return output_call (insn, operands[0], 0);
}"
[(set_attr "type" "call")
- (set (attr "length")
-;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is at most
-;; 8 bytes.
-;;
-;; For long-calls the length will be at most 68 bytes (non-pic)
-;; or 84 bytes (pic). */
-;; Else we have to use a long-call;
- (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (const_int 8)
- (if_then_else (eq (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 68)
- (const_int 84))))])
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 0)"))])
(define_insn "call_internal_reg_64bit"
[(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
@@ -6086,15 +5972,16 @@
"*
{
/* ??? Needs more work. Length computation, split into multiple insns,
- do not use %r22 directly, expose delay slot. */
- return \"ldd 16(%0),%%r2\;ldd 24(%0),%%r27\;bve,l (%%r2),%%r2\;nop\";
+ expose delay slot. */
+ return \"ldd 16(%0),%%r2\;bve,l (%%r2),%%r2\;ldd 24(%0),%%r27\";
}"
[(set_attr "type" "dyncall")
- (set (attr "length") (const_int 16))])
+ (set (attr "length") (const_int 12))])
(define_insn "call_internal_reg"
[(call (mem:SI (reg:SI 22))
(match_operand 0 "" "i"))
+ (clobber (reg:SI 1))
(clobber (reg:SI 2))
(use (const_int 1))]
""
@@ -6218,11 +6105,13 @@
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
operands[2]));
}
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
- if (TARGET_64BIT)
- use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
/* After each call we must restore the PIC register, even if it
doesn't appear to be used. */
@@ -6235,6 +6124,7 @@
[(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand 1 "call_operand_address" ""))
(match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
(clobber (reg:SI 2))
(use (const_int 0))]
;;- Don't use operand 1 for most machines.
@@ -6245,21 +6135,7 @@
return output_call (insn, operands[1], 0);
}"
[(set_attr "type" "call")
- (set (attr "length")
-;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is at most
-;; 8 bytes.
-;;
-;; For long-calls the length will be at most 68 bytes (non-pic)
-;; or 84 bytes (pic). */
-;; Else we have to use a long-call;
- (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (const_int 8)
- (if_then_else (eq (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 68)
- (const_int 84))))])
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 0)"))])
(define_insn "call_value_internal_reg_64bit"
[(set (match_operand 0 "" "=rf")
@@ -6271,16 +6147,17 @@
"*
{
/* ??? Needs more work. Length computation, split into multiple insns,
- do not use %r22 directly, expose delay slot. */
- return \"ldd 16(%1),%%r2\;ldd 24(%1),%%r27\;bve,l (%%r2),%%r2\;nop\";
+ expose delay slot. */
+ return \"ldd 16(%1),%%r2\;bve,l (%%r2),%%r2\;ldd 24(%1),%%r27\";
}"
[(set_attr "type" "dyncall")
- (set (attr "length") (const_int 16))])
+ (set (attr "length") (const_int 12))])
(define_insn "call_value_internal_reg"
[(set (match_operand 0 "" "=rf")
(call (mem:SI (reg:SI 22))
(match_operand 1 "" "i")))
+ (clobber (reg:SI 1))
(clobber (reg:SI 2))
(use (const_int 1))]
""
@@ -6389,10 +6266,9 @@
}")
(define_expand "sibcall"
- [(parallel [(call (match_operand:SI 0 "" "")
- (match_operand 1 "" ""))
- (clobber (reg:SI 0))])]
- "! TARGET_PORTABLE_RUNTIME"
+ [(call (match_operand:SI 0 "" "")
+ (match_operand 1 "" ""))]
+ "!TARGET_PORTABLE_RUNTIME"
"
{
rtx op;
@@ -6400,8 +6276,21 @@
op = XEXP (operands[0], 0);
- /* We do not allow indirect sibling calls. */
- call_insn = emit_call_insn (gen_sibcall_internal_symref (op, operands[1]));
+ if (TARGET_64BIT)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+
+ /* Indirect sibling calls are not allowed. */
+ if (TARGET_64BIT)
+ call_insn = gen_sibcall_internal_symref_64bit (op, operands[1]);
+ else
+ call_insn = gen_sibcall_internal_symref (op, operands[1]);
+
+ call_insn = emit_call_insn (call_insn);
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
if (flag_pic)
{
@@ -6417,38 +6306,39 @@
(define_insn "sibcall_internal_symref"
[(call (mem:SI (match_operand 0 "call_operand_address" ""))
(match_operand 1 "" "i"))
- (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
(use (reg:SI 2))
(use (const_int 0))]
- "! TARGET_PORTABLE_RUNTIME"
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
"*
{
output_arg_descriptor (insn);
return output_call (insn, operands[0], 1);
}"
[(set_attr "type" "call")
- (set (attr "length")
-;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is at most
-;; 8 bytes.
-;;
-;; For long-calls the length will be at most 68 bytes (non-pic)
-;; or 84 bytes (pic). */
-;; Else we have to use a long-call;
- (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (const_int 8)
- (if_then_else (eq (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 68)
- (const_int 84))))])
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 1)"))])
+
+(define_insn "sibcall_internal_symref_64bit"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 27))
+ (use (reg:SI 2))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ output_arg_descriptor (insn);
+ return output_call (insn, operands[0], 1);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 1)"))])
(define_expand "sibcall_value"
- [(parallel [(set (match_operand 0 "" "")
+ [(set (match_operand 0 "" "")
(call (match_operand:SI 1 "" "")
- (match_operand 2 "" "")))
- (clobber (reg:SI 0))])]
- "! TARGET_PORTABLE_RUNTIME"
+ (match_operand 2 "" "")))]
+ "!TARGET_PORTABLE_RUNTIME"
"
{
rtx op;
@@ -6456,10 +6346,24 @@
op = XEXP (operands[1], 0);
- /* We do not allow indirect sibling calls. */
- call_insn = emit_call_insn (gen_sibcall_value_internal_symref (operands[0],
- op,
- operands[2]));
+ if (TARGET_64BIT)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+
+ /* Indirect sibling calls are not allowed. */
+ if (TARGET_64BIT)
+ call_insn
+ = gen_sibcall_value_internal_symref_64bit (operands[0], op, operands[2]);
+ else
+ call_insn
+ = gen_sibcall_value_internal_symref (operands[0], op, operands[2]);
+
+ call_insn = emit_call_insn (call_insn);
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
@@ -6475,32 +6379,34 @@
[(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand 1 "call_operand_address" ""))
(match_operand 2 "" "i")))
- (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
(use (reg:SI 2))
(use (const_int 0))]
- ;;- Don't use operand 1 for most machines.
- "! TARGET_PORTABLE_RUNTIME"
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
"*
{
output_arg_descriptor (insn);
return output_call (insn, operands[1], 1);
}"
[(set_attr "type" "call")
- (set (attr "length")
-;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is at most
-;; 8 bytes.
-;;
-;; For long-calls the length will be at most 68 bytes (non-pic)
-;; or 84 bytes (pic). */
-;; Else we have to use a long-call;
- (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (const_int 8)
- (if_then_else (eq (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 68)
- (const_int 84))))])
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 1)"))])
+
+(define_insn "sibcall_value_internal_symref_64bit"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 27))
+ (use (reg:SI 2))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ output_arg_descriptor (insn);
+ return output_call (insn, operands[1], 1);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length") (symbol_ref "attr_length_call (insn, 1)"))])
(define_insn "nop"
[(const_int 0)]
@@ -7392,6 +7298,12 @@
"!TARGET_64BIT"
"*
{
+ int length = get_attr_length (insn);
+ rtx xoperands[2];
+
+ xoperands[0] = GEN_INT (length - 8);
+ xoperands[1] = GEN_INT (length - 16);
+
/* Must import the magic millicode routine. */
output_asm_insn (\".IMPORT $$sh_func_adrs,MILLICODE\", NULL);
@@ -7400,60 +7312,24 @@
First, copy our input parameter into %r29 just in case we don't
need to call $$sh_func_adrs. */
output_asm_insn (\"copy %%r26,%%r29\", NULL);
+ output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\", NULL);
/* Next, examine the low two bits in %r26, if they aren't 0x2, then
we use %r26 unchanged. */
- if (get_attr_length (insn) == 32)
- output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\;{comib|cmpib},<>,n 2,%%r31,.+24\", NULL);
- else if (get_attr_length (insn) == 40)
- output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\;{comib|cmpib},<>,n 2,%%r31,.+32\", NULL);
- else if (get_attr_length (insn) == 44)
- output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\;{comib|cmpib},<>,n 2,%%r31,.+36\", NULL);
- else
- output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\;{comib|cmpib},<>,n 2,%%r31,.+20\", NULL);
+ output_asm_insn (\"{comib|cmpib},<>,n 2,%%r31,.+%0\", xoperands);
+ output_asm_insn (\"ldi 4096,%%r31\", NULL);
/* Next, compare %r26 with 4096, if %r26 is less than or equal to
- 4096, then we use %r26 unchanged. */
- if (get_attr_length (insn) == 32)
- output_asm_insn (\"ldi 4096,%%r31\;{comb|cmpb},<<,n %%r26,%%r31,.+16\",
- NULL);
- else if (get_attr_length (insn) == 40)
- output_asm_insn (\"ldi 4096,%%r31\;{comb|cmpb},<<,n %%r26,%%r31,.+24\",
- NULL);
- else if (get_attr_length (insn) == 44)
- output_asm_insn (\"ldi 4096,%%r31\;{comb|cmpb},<<,n %%r26,%%r31,.+28\",
- NULL);
- else
- output_asm_insn (\"ldi 4096,%%r31\;{comb|cmpb},<<,n %%r26,%%r31,.+12\",
- NULL);
+ 4096, then again we use %r26 unchanged. */
+ output_asm_insn (\"{comb|cmpb},<<,n %%r26,%%r31,.+%1\", xoperands);
- /* Else call $$sh_func_adrs to extract the function's real add24. */
+ /* Finally, call $$sh_func_adrs to extract the function's real add24. */
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode,
- \"$$sh_func_adrs\"));
+ \"$$sh_func_adrs\"));
}"
[(set_attr "type" "multi")
- (set (attr "length")
- (cond [
-;; Target (or stub) within reach
- (and (lt (plus (symbol_ref "total_code_bytes") (pc))
- (const_int 240000))
- (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0)))
- (const_int 28)
-
-;; Out of reach PIC
- (ne (symbol_ref "flag_pic")
- (const_int 0))
- (const_int 44)
-
-;; Out of reach PORTABLE_RUNTIME
- (ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
- (const_int 0))
- (const_int 40)]
-
-;; Out of reach, can use ble
- (const_int 32)))])
+ (set (attr "length") (symbol_ref "attr_length_millicode_call (insn, 20)"))])
;; On the PA, the PIC register is call clobbered, so it must
;; be saved & restored around calls by the caller. If the call
Index: config/pa/som.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/som.h,v
retrieving revision 1.38
diff -u -3 -p -r1.38 som.h
--- config/pa/som.h 29 Aug 2002 21:16:35 -0000 1.38
+++ config/pa/som.h 30 Oct 2002 17:06:46 -0000
@@ -371,3 +371,7 @@ do { \
on the location of the GCC tool directory. The downside is GCC
cannot be moved after installation using a symlink. */
#define ALWAYS_STRIP_DOTDOT 1
+
+/* Aggregates with a single float or double field should be passed and
+ returned in the general registers. */
+#define MEMBER_TYPE_FORCES_BLK(FIELD, MODE) (MODE==SFmode || MODE==DFmode)
Index: config/pa/t-pa64
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/t-pa64,v
retrieving revision 1.6
diff -u -3 -p -r1.6 t-pa64
--- config/pa/t-pa64 30 Apr 2002 19:47:38 -0000 1.6
+++ config/pa/t-pa64 30 Oct 2002 17:06:46 -0000
@@ -1,4 +1,4 @@
-TARGET_LIBGCC2_CFLAGS = -fPIC -Dpa64=1 -DELF=1
+TARGET_LIBGCC2_CFLAGS = -fPIC -Dpa64=1 -DELF=1 -mlong-calls
LIB2FUNCS_EXTRA=quadlib.c
Index: doc/invoke.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.196
diff -u -3 -p -r1.196 invoke.texi
--- doc/invoke.texi 20 Oct 2002 19:18:30 -0000 1.196
+++ doc/invoke.texi 30 Oct 2002 17:06:48 -0000
@@ -508,7 +508,7 @@ in the following sections.
-march=@var{architecture-type} @gol
-mbig-switch -mdisable-fpregs -mdisable-indexing @gol
-mfast-indirect-calls -mgas -mgnu-ld -mhp-ld @gol
--mjump-in-delay -mlinker-opt @gol
+-mjump-in-delay -mlinker-opt -mlong-calls @gol
-mlong-load-store -mno-big-switch -mno-disable-fpregs @gol
-mno-disable-indexing -mno-fast-indirect-calls -mno-gas @gol
-mno-jump-in-delay -mno-long-load-store @gol
@@ -8093,6 +8093,33 @@ ld. The ld that is called is determined
configure option, gcc's program search path, and finally by the user's
@env{PATH}. The linker used by GCC can be printed using @samp{which
`gcc -print-prog-name=ld`}.
+
+@item -mlong-calls
+@opindex mno-long-calls
+Generate code that uses long call sequences. This ensures that a call
+is always able to reach linker generated stubs. The default is to generate
+long calls only when the distance from the call site to the beginning
+of the function or translation unit, as the case may be, exceeds a
+predefined limit set by the branch type being used. The limits for
+normal calls are 7,600,000 and 240,000 bytes, respectively for the
+PA 2.0 and PA 1.X architectures. Sibcalls are always limited at
+240,000 bytes.
+
+Distances are measured from the beginning of functions when using the
+@option{-ffunction-sections} option, or when using the @option{-mgas}
+and @option{-mno-portable-runtime} options together under HP-UX with
+the SOM linker.
+
+It is normally not desirable to use this option as it will degrade
+performance. However, it may be useful in large applications,
+particularly when partial linking is used to build the application.
+
+The types of long calls used depends on the capabilities of the
+assembler and linker, and the type of code being generated. The
+impact on systems that support long absolute calls, and long pic
+symbol-difference or pc-relative calls should be relatively small.
+However, an indirect call is used on 32-bit ELF systems in pic code
+and it is quite long.
@end table
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ PATCH: ABI bug for vcall offsets
[not found] <no.id>
` (91 preceding siblings ...)
2002-10-30 19:23 ` Call rewrite for PA John David Anglin
@ 2002-11-09 15:18 ` John David Anglin
2002-11-09 15:27 ` John David Anglin
2002-11-10 18:21 ` Mark Mitchell
2002-11-13 13:12 ` gcc-64 20021111 broken on HP-UX 11.00 John David Anglin
` (70 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-09 15:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
> I noticed today a new fail on hppa64-hp-hpux11.11, vthunk3.C. It fails
> scan-assembler _ZTvn4_n20_N1E1bEv. This doesn't seem like the correct
> symbol name to test for on a 64-bit target. I see _ZTvn8_n40_N1E1bEv or
This might also be the reason why
FAIL: g++.dg/abi/vague1.C scan-assembler-not _ZN1AIiE1tE
fails.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ PATCH: ABI bug for vcall offsets
2002-11-09 15:18 ` C++ PATCH: ABI bug for vcall offsets John David Anglin
@ 2002-11-09 15:27 ` John David Anglin
2002-11-10 18:21 ` Mark Mitchell
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-09 15:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
> This might also be the reason why
>
> FAIL: g++.dg/abi/vague1.C scan-assembler-not _ZN1AIiE1tE
No, it's because there is a .IMPORT/.type directive for _ZN1AIiE1tE
in the assembler file. It needs to be XFAILed on HPPA HPUX.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ PATCH: ABI bug for vcall offsets
2002-11-09 15:18 ` C++ PATCH: ABI bug for vcall offsets John David Anglin
2002-11-09 15:27 ` John David Anglin
@ 2002-11-10 18:21 ` Mark Mitchell
2002-11-10 19:42 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2002-11-10 18:21 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
--On Saturday, November 09, 2002 06:18:41 PM -0500 John David Anglin
<dave@hiauly1.hia.nrc.ca> wrote:
>> I noticed today a new fail on hppa64-hp-hpux11.11, vthunk3.C. It fails
>> scan-assembler _ZTvn4_n20_N1E1bEv. This doesn't seem like the correct
>> symbol name to test for on a 64-bit target. I see _ZTvn8_n40_N1E1bEv or
Yes; I should have had an x86-only flag in there. Fixed with the attached
patch, applied on the mainline.
> This might also be the reason why
>
> FAIL: g++.dg/abi/vague1.C scan-assembler-not _ZN1AIiE1tE
No; that looks like something different to me.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2002-11-10 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/vthunk3.C: Run only on x86.
Index: vthunk3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/vthunk3.C,v
retrieving revision 1.1
retrieving revision 1.2
diff -c -5 -p -r1.1 -r1.2
*** vthunk3.C 8 Nov 2002 02:16:48 -0000 1.1
--- vthunk3.C 11 Nov 2002 02:20:37 -0000 1.2
***************
*** 1,6 ****
! // { dg-do compile }
// { dg-options "-fabi-version=0" }
struct A {
virtual void a ();
};
--- 1,6 ----
! // { dg-do compile { target i?86-*-* } }
// { dg-options "-fabi-version=0" }
struct A {
virtual void a ();
};
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: C++ PATCH: ABI bug for vcall offsets
2002-11-10 18:21 ` Mark Mitchell
@ 2002-11-10 19:42 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-10 19:42 UTC (permalink / raw)
To: Mark Mitchell; +Cc: gcc-patches
> > This might also be the reason why
> >
> > FAIL: g++.dg/abi/vague1.C scan-assembler-not _ZN1AIiE1tE
>
> No; that looks like something different to me.
From examination of the assembler output, my understanding of why this
fails on hppa*-*-hpux* is that the symbol occurs in the assembler output
because we define ASM_OUTPUT_EXTERNAL to provide the correct type for
undefined external references. This happens even for symbols that
eventually turn out not to be needed.
The enclosed patch avoids the fail. It's not ideal but I doubt it's
worth the effort to try eliminate references in .import/.type directives.
Ok for main?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-11-10 John David Anglin <dave@hiauly1.hia.nrc.ca>
* g++.dg/abi/vague1.C (dg-final): Return if target is hppa*-*-hpux*.
Index: g++.dg/abi/vague1.C
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/testsuite/g++.dg/abi/vague1.C,v
retrieving revision 1.1
diff -u -3 -p -r1.1 vague1.C
--- g++.dg/abi/vague1.C 15 Mar 2002 09:54:42 -0000 1.1
+++ g++.dg/abi/vague1.C 11 Nov 2002 03:28:39 -0000
@@ -2,7 +2,9 @@
// instantiations.
// Disable debug info so we don't get confused by the symbol name there.
+// The test fails on hppa*-*-hpux* because the symbol _ZN1AIiE1tE is imported.
// { dg-options "-g0" }
+// { dg-final { if { [istarget hppa*-*-hpux*] } { return } } }
// { dg-final { scan-assembler-not "_ZN1AIiE1tE" } }
template <class T> struct A {
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gcc-64 20021111 broken on HP-UX 11.00
[not found] <no.id>
` (92 preceding siblings ...)
2002-11-09 15:18 ` C++ PATCH: ABI bug for vcall offsets John David Anglin
@ 2002-11-13 13:12 ` John David Anglin
2002-11-26 11:28 ` Unreviewed patch John David Anglin
` (69 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-13 13:12 UTC (permalink / raw)
To: John David Anglin; +Cc: h.m.brand, law, gcc, gcc-patches
> > ldd: "gengenrtl" is not a shared executable.
> > collect2: /usr/ccs/bin/ldd returned 1 exit status
>
> I have installed the patch below and it should fix the above problem.
I forgot to say it was tested with both HP and GNU ld on hppa64-hp-hpux11.11.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Unreviewed patch
[not found] <no.id>
` (93 preceding siblings ...)
2002-11-13 13:12 ` gcc-64 20021111 broken on HP-UX 11.00 John David Anglin
@ 2002-11-26 11:28 ` John David Anglin
2002-11-26 15:53 ` PATCH: Fix handling of return values handled in PARALLELs John David Anglin
` (68 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-26 11:28 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, gcc-patches, law
See
<http://gcc.gnu.org/ml/gcc-patches/2002-11/msg00105.html>.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix handling of return values handled in PARALLELs
[not found] <no.id>
` (94 preceding siblings ...)
2002-11-26 11:28 ` Unreviewed patch John David Anglin
@ 2002-11-26 15:53 ` John David Anglin
2002-11-26 17:58 ` Richard Henderson
2002-11-26 19:52 ` clean up some hook routines John David Anglin
` (67 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-11-26 15:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2002-11-26 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * expr.c (gen_group_rtx, emit_group_move): New functions.
> * expr.h (gen_group_rtx, emit_group_move): Prototype.
> * function.c (expand_function_start): Use gen_group_rtx to create a
> PARALLEL rtx to hold the return value when the real return rtx is a
> PARALLEL.
> (expand_function_end): Use emit_group_move to move the return value
> from a PARALLEL to the real return registers.
> * rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
> in PARALLELs.
Oops, I managed to lose the initialization of the first vector component
when the src is NULL. Doesn't affect hppa64-hp-hpux11 as it doesn't use
this feature.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-11-26 John David Anglin <dave@hiauly1.hia.nrc.ca>
* expr.c (gen_group_rtx, emit_group_move): New functions.
* expr.h (gen_group_rtx, emit_group_move): Prototype.
* function.c (expand_function_start): Use gen_group_rtx to create a
PARALLEL rtx to hold the return value when the real return rtx is a
PARALLEL.
(expand_function_end): Use emit_group_move to move the return value
from a PARALLEL to the real return registers.
* rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
in PARALLELs.
Index: expr.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/expr.c,v
retrieving revision 1.493
diff -u -3 -p -r1.493 expr.c
--- expr.c 20 Nov 2002 21:52:58 -0000 1.493
+++ expr.c 26 Nov 2002 23:09:33 -0000
@@ -2203,6 +2203,42 @@ move_block_from_reg (regno, x, nregs, si
}
}
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+ ORIG, where ORIG is a non-consecutive group of registers represented by
+ a PARALLEL. The clone is identical to the original except in that the
+ original set of registers is replaced by a new set of pseudo registers.
+ The new set has the same modes as the original set. */
+
+rtx
+gen_group_rtx (orig)
+ rtx orig;
+{
+ int i, length;
+ rtx *tmps;
+
+ if (GET_CODE (orig) != PARALLEL)
+ abort ();
+
+ length = XVECLEN (orig, 0);
+ tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+ /* Skip a NULL entry in first slot. */
+ i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
+
+ if (i)
+ tmps[0] = 0;
+
+ for (; i < length; i++)
+ {
+ enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+ rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+ tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+ }
+
+ return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
registers represented by a PARALLEL. SSIZE represents the total size of
block SRC in bytes, or -1 if not known. */
@@ -2322,6 +2358,26 @@ emit_group_load (dst, orig_src, ssize)
/* Copy the extracted pieces into the proper (probable) hard regs. */
for (i = start; i < XVECLEN (dst, 0); i++)
emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+}
+
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+ non-consecutive groups of registers, each represented by a PARALLEL. */
+
+void
+emit_group_move (dst, src)
+ rtx dst, src;
+{
+ int i;
+
+ if (GET_CODE (src) != PARALLEL
+ || GET_CODE (dst) != PARALLEL
+ || XVECLEN (src, 0) != XVECLEN (dst, 0))
+ abort ();
+
+ /* Skip first entry if NULL. */
+ for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+ emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+ XEXP (XVECEXP (src, 0, i), 0));
}
/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
Index: expr.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/expr.h,v
retrieving revision 1.123
diff -u -3 -p -r1.123 expr.h
--- expr.h 22 Sep 2002 14:09:31 -0000 1.123
+++ expr.h 26 Nov 2002 23:09:34 -0000
@@ -412,9 +412,16 @@ extern void move_block_to_reg PARAMS ((i
The number of registers to be filled is NREGS. */
extern void move_block_from_reg PARAMS ((int, rtx, int, int));
+/* Generate a non-consecutive group of registers represented by a PARALLEL. */
+extern rtx gen_group_rtx PARAMS ((rtx));
+
/* Load a BLKmode value into non-consecutive registers represented by a
PARALLEL. */
extern void emit_group_load PARAMS ((rtx, rtx, int));
+
+/* Move a non-consecutive group of registers represented by a PARALLEL into
+ a non-consecutive group of registers represented by a PARALLEL. */
+extern void emit_group_move PARAMS ((rtx, rtx));
/* Store a BLKmode value from non-consecutive registers represented by a
PARALLEL. */
Index: function.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/function.c,v
retrieving revision 1.387
diff -u -3 -p -r1.387 function.c
--- function.c 14 Oct 2002 21:19:04 -0000 1.387
+++ function.c 26 Nov 2002 23:09:36 -0000
@@ -6559,18 +6559,17 @@ expand_function_start (subr, parms_have_
subr, 1);
/* Structures that are returned in registers are not aggregate_value_p,
- so we may see a PARALLEL. Don't play pseudo games with this. */
- if (! REG_P (hard_reg))
- SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+ so we may see a PARALLEL or a REG. */
+ if (REG_P (hard_reg))
+ SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+ else if (GET_CODE (hard_reg) == PARALLEL)
+ SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
else
- {
- /* Create the pseudo. */
- SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+ abort ();
- /* Needed because we may need to move this to memory
- in case it's a named return value whose address is taken. */
- DECL_REGISTER (DECL_RESULT (subr)) = 1;
- }
+ /* Set DECL_REGISTER flag so that expand_function_end will copy the
+ result to the real return register(s). */
+ DECL_REGISTER (DECL_RESULT (subr)) = 1;
}
/* Initialize rtx for parameters and local variables.
@@ -6998,8 +6997,16 @@ expand_function_end (filename, line, end
convert_move (real_decl_rtl, decl_rtl, unsignedp);
}
else if (GET_CODE (real_decl_rtl) == PARALLEL)
- emit_group_load (real_decl_rtl, decl_rtl,
- int_size_in_bytes (TREE_TYPE (decl_result)));
+ {
+ /* If expand_function_start has created a PARALLEL for decl_rtl,
+ move the result to the real return registers. Otherwise, do
+ a group load from decl_rtl for a named return. */
+ if (GET_CODE (decl_rtl) == PARALLEL)
+ emit_group_move (real_decl_rtl, decl_rtl);
+ else
+ emit_group_load (real_decl_rtl, decl_rtl,
+ int_size_in_bytes (TREE_TYPE (decl_result)));
+ }
else
emit_move_insn (real_decl_rtl, decl_rtl);
}
Index: rtl.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.374
diff -u -3 -p -r1.374 rtl.h
--- rtl.h 4 Nov 2002 16:57:03 -0000 1.374
+++ rtl.h 26 Nov 2002 23:09:36 -0000
@@ -185,7 +185,7 @@ struct rtx_def GTY((chain_next ("RTX_NEX
has used it as the function. */
unsigned int used : 1;
/* Nonzero if this rtx came from procedure integration.
- 1 in a REG means this reg refers to the return value
+ 1 in a REG or PARALLEL means this rtx refers to the return value
of the current function.
1 in a SYMBOL_REF if the symbol is weak. */
unsigned integrated : 1;
@@ -988,9 +988,10 @@ enum label_kind
#define REGNO(RTX) XCUINT (RTX, 0, REG)
#define ORIGINAL_REGNO(RTX) X0UINT (RTX, 1)
-/* 1 if RTX is a reg that is the current function's return value. */
+/* 1 if RTX is a reg or parallel that is the current function's return
+ value. */
#define REG_FUNCTION_VALUE_P(RTX) \
- (RTL_FLAG_CHECK1("REG_FUNCTION_VALUE_P", (RTX), REG)->integrated)
+ (RTL_FLAG_CHECK2("REG_FUNCTION_VALUE_P", (RTX), REG, PARALLEL)->integrated)
/* 1 if RTX is a reg that corresponds to a variable declared by the user. */
#define REG_USERVAR_P(RTX) \
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix handling of return values handled in PARALLELs
2002-11-26 15:53 ` PATCH: Fix handling of return values handled in PARALLELs John David Anglin
@ 2002-11-26 17:58 ` Richard Henderson
0 siblings, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2002-11-26 17:58 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Tue, Nov 26, 2002 at 06:41:14PM -0500, John David Anglin wrote:
> * expr.c (gen_group_rtx, emit_group_move): New functions.
> * expr.h (gen_group_rtx, emit_group_move): Prototype.
> * function.c (expand_function_start): Use gen_group_rtx to create a
> PARALLEL rtx to hold the return value when the real return rtx is a
> PARALLEL.
> (expand_function_end): Use emit_group_move to move the return value
> from a PARALLEL to the real return registers.
> * rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
> in PARALLELs.
Ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: clean up some hook routines
[not found] <no.id>
` (95 preceding siblings ...)
2002-11-26 15:53 ` PATCH: Fix handling of return values handled in PARALLELs John David Anglin
@ 2002-11-26 19:52 ` John David Anglin
2002-12-04 14:22 ` HP-UX PA long double alignment change John David Anglin
` (66 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-11-26 19:52 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rth
> ../../gcc/gcc/config/pa/pa.c -o pa.o
> ../../gcc/gcc/config/pa/pa.c:206: error: `default_comp_type_attributes' undeclared here (not in a function)
This appears to a problem with the updating of anoncvs@subversions.gnu.org.
Possibly, the problem will disappear at the next update. The changes to
target-def.h aren't there yet.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HP-UX PA long double alignment change
[not found] <no.id>
` (96 preceding siblings ...)
2002-11-26 19:52 ` clean up some hook routines John David Anglin
@ 2002-12-04 14:22 ` John David Anglin
2002-12-04 14:31 ` Steve Ellcey
2002-12-04 18:14 ` John David Anglin
` (65 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2002-12-04 14:22 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, rth
> >From my reading of the documentation, I think you need both.
> I wonder if GET_MODE_ALIGNMENT could be redefined?
I have tested the following on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
There are no regressions and it reduces the alignment of long doubles in a
simple manner. However, it does require modifying machmode.h to allow
defining GET_MODE_ALIGNMENT in the target headers.
Is this ok for main?
Sorry Steve, I didn't mean to usurp your work.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-12-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* machmode.h (GET_MODE_ALIGNMENT): Don't define if already defined.
* pa.h (GET_MODE_ALIGNMENT): Define to obtain 64-bit alignment for
TFmode on non 64-bit ports.
Index: machmode.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/machmode.h,v
retrieving revision 1.31
diff -u -3 -p -r1.31 machmode.h
--- machmode.h 1 Nov 2002 09:35:24 -0000 1.31
+++ machmode.h 4 Dec 2002 19:13:33 -0000
@@ -159,7 +159,9 @@ extern enum machine_mode get_best_mode P
extern unsigned get_mode_alignment PARAMS ((enum machine_mode));
+#ifndef GET_MODE_ALIGNMENT
#define GET_MODE_ALIGNMENT(MODE) get_mode_alignment (MODE)
+#endif
/* For each class, get the narrowest mode in that class. */
Index: config/pa/pa.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.h,v
retrieving revision 1.176
diff -u -3 -p -r1.176 pa.h
--- config/pa/pa.h 27 Nov 2002 02:34:15 -0000 1.176
+++ config/pa/pa.h 4 Dec 2002 19:13:36 -0000
@@ -478,6 +478,11 @@ do { \
to 128 bits to allow for lock semaphores in the stack frame.*/
#define BIGGEST_ALIGNMENT 128
+/* TFmode data only needs 64-bit alignment on non 64-bit ports. */
+#undef GET_MODE_ALIGNMENT
+#define GET_MODE_ALIGNMENT(MODE) \
+ (!TARGET_64BIT && (MODE) == TFmode ? 64 : get_mode_alignment (MODE))
+
/* Get around hp-ux assembler bug, and make strcpy of constants fast. */
#define CONSTANT_ALIGNMENT(CODE, TYPEALIGN) \
((TYPEALIGN) < 32 ? 32 : (TYPEALIGN))
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HP-UX PA long double alignment change
2002-12-04 14:22 ` HP-UX PA long double alignment change John David Anglin
@ 2002-12-04 14:31 ` Steve Ellcey
0 siblings, 0 replies; 521+ messages in thread
From: Steve Ellcey @ 2002-12-04 14:31 UTC (permalink / raw)
To: dave; +Cc: gcc-patches
> > >From my reading of the documentation, I think you need both.
> > I wonder if GET_MODE_ALIGNMENT could be redefined?
>
> I have tested the following on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
> There are no regressions and it reduces the alignment of long doubles in a
> simple manner. However, it does require modifying machmode.h to allow
> defining GET_MODE_ALIGNMENT in the target headers.
>
> Is this ok for main?
>
> Sorry Steve, I didn't mean to usurp your work.
>
> Dave
That's quite alright with me. This looks simpler then changing both
ADJUST_FIELD_ALIGN and DATA_ALIGNMENT (and possibly LOCAL_ALIGNMENT) to
get them all to match up.
Steve
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: HP-UX PA long double alignment change
[not found] <no.id>
` (97 preceding siblings ...)
2002-12-04 14:22 ` HP-UX PA long double alignment change John David Anglin
@ 2002-12-04 18:14 ` John David Anglin
2003-01-17 17:15 ` [PATCH] Fix RTL sharing problem in CSE John David Anglin
` (64 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2002-12-04 18:14 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, sje, gcc-patches
> So if I understand correctly, you are suggesting that we drop
> BIGGEST_ALIGNMENT back to 64 and increase STACK_BOUNDARY to 128.
> I think then the STARTING_FRAME_OFFSET would have to increase
> to 16. Otherwise, we never have a zero frame size. This will
> add two more unused slots in the stack frame which I don't much
> like.
In the discussion that led to the original change, Richard wrote:
> On Fri, Jan 18, 2002 at 06:35:40PM -0800, Aldy Hernandez wrote:
> > this patch introduces a new macro STARTING_FRAME_PHASE (documented).
>
> There is no need for a new macro. The frame pointer _must_ be
> aligned, as we assert here:
>
> emit-rtl.c:4719: REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
>
> therefore it must always be the case that
>
> sb = STACK_BOUNDARY / BITS_PER_UNIT;
> off = STARTING_FRAME_OFFSET % sb;
>
> STARTING_FRAME_PHASE == (off ? sb - off : 0)
In diagnosing why we never had a zero frame size on hppa64, I found
that when STARTING_FRAME_PHASE % sb is non zero you can never get a
frame size of zero. This seems like a bug as it wastes stack space
if you increase STARTING_FRAME_OFFSET so that off==0.
dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
[not found] <no.id>
` (98 preceding siblings ...)
2002-12-04 18:14 ` John David Anglin
@ 2003-01-17 17:15 ` John David Anglin
2003-01-17 17:24 ` law
2003-01-19 16:59 ` [PATCH]: Fix ICE in convert_move on PA John David Anglin
` (63 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-01-17 17:15 UTC (permalink / raw)
To: John David Anglin; +Cc: roger, gcc-patches
> > 2003-01-16 Roger Sayle <roger@eyesopen.com>
> >
> > * cse.c (cse_insn): Avoid RTL sharing when updating the RETVAL
> > insn's notes following a substitution inside a libcall.
>
> This doesn't fix the hppa64 problem. I will try to investigate further.
This is the insn that causes the ICE:
regclass.i.12.loop:
(insn 599 598 600 0000000000000000 (set (reg:DI 263)
(mult:DI (zero_extend:DI (subreg:SI (reg:DI 262) 4))
(zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
(nil))
regclass.i.13.bypass:
(insn 599 598 600 21 0000000000000000 (set (reg:DI 263)
(mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd4]) 4))
(zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
(nil))
regclass.i.19.life:
(insn 599 598 600 18 0000000000000000 (set (reg:DI 263)
(mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd4]) 4))
(zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
(expr_list:REG_DEAD (reg/v:DI 157)
(nil)))
The ICE occurs because combine tries to simplify it and it can't because
of the constant substitution in the regclass.i.13.bypass pass. It would
seem to me that the subreg should be simplified when the substitution for
DI 262 is made. After that, the mode information is lost.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 17:15 ` [PATCH] Fix RTL sharing problem in CSE John David Anglin
@ 2003-01-17 17:24 ` law
2003-01-17 18:25 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: law @ 2003-01-17 17:24 UTC (permalink / raw)
To: John David Anglin; +Cc: roger, gcc-patches
In message <200301171715.h0HHFOL0006221@hiauly1.hia.nrc.ca>, "John David Anglin
" writes:
>> > 2003-01-16 Roger Sayle <roger@eyesopen.com>
>> >
>> > * cse.c (cse_insn): Avoid RTL sharing when updating the RETVAL
>> > insn's notes following a substitution inside a libcall.
>>
>> This doesn't fix the hppa64 problem. I will try to investigate further.
>
>This is the insn that causes the ICE:
>
>regclass.i.12.loop:
>(insn 599 598 600 0000000000000000 (set (reg:DI 263)
> (mult:DI (zero_extend:DI (subreg:SI (reg:DI 262) 4))
> (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> (nil))
>
>regclass.i.13.bypass:
>(insn 599 598 600 21 0000000000000000 (set (reg:DI 263)
> (mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd
>4]) 4))
> (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> (nil))
>
>regclass.i.19.life:
>(insn 599 598 600 18 0000000000000000 (set (reg:DI 263)
> (mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd
>4]) 4))
> (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> (expr_list:REG_DEAD (reg/v:DI 157)
> (nil)))
>
>The ICE occurs because combine tries to simplify it and it can't because
>of the constant substitution in the regclass.i.13.bypass pass. It would
>seem to me that the subreg should be simplified when the substitution for
>DI 262 is made. After that, the mode information is lost.
Agreed.
jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 17:24 ` law
@ 2003-01-17 18:25 ` Jan Hubicka
2003-01-17 18:59 ` Roger Sayle
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2003-01-17 18:25 UTC (permalink / raw)
To: law; +Cc: John David Anglin, roger, gcc-patches
> In message <200301171715.h0HHFOL0006221@hiauly1.hia.nrc.ca>, "John David Anglin
> " writes:
> >> > 2003-01-16 Roger Sayle <roger@eyesopen.com>
> >> >
> >> > * cse.c (cse_insn): Avoid RTL sharing when updating the RETVAL
> >> > insn's notes following a substitution inside a libcall.
> >>
> >> This doesn't fix the hppa64 problem. I will try to investigate further.
> >
> >This is the insn that causes the ICE:
> >
> >regclass.i.12.loop:
> >(insn 599 598 600 0000000000000000 (set (reg:DI 263)
> > (mult:DI (zero_extend:DI (subreg:SI (reg:DI 262) 4))
> > (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> > (nil))
> >
> >regclass.i.13.bypass:
> >(insn 599 598 600 21 0000000000000000 (set (reg:DI 263)
> > (mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd
> >4]) 4))
> > (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> > (nil))
> >
> >regclass.i.19.life:
> >(insn 599 598 600 18 0000000000000000 (set (reg:DI 263)
> > (mult:DI (zero_extend:DI (subreg:SI (const_int -44 [0xffffffffffffffd
> >4]) 4))
> > (zero_extend:DI (subreg:SI (reg/v:DI 157) 4)))) -1 (nil)
> > (expr_list:REG_DEAD (reg/v:DI 157)
> > (nil)))
> >
> >The ICE occurs because combine tries to simplify it and it can't because
> >of the constant substitution in the regclass.i.13.bypass pass. It would
> >seem to me that the subreg should be simplified when the substitution for
> >DI 262 is made. After that, the mode information is lost.
> Agreed.
When replacement is made by validate_replace_reg, this is done
automatically. I think bypass pass should use it consistently...
Honza
>
> jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 18:25 ` Jan Hubicka
@ 2003-01-17 18:59 ` Roger Sayle
2003-01-17 22:33 ` David Edelsohn
2003-01-17 22:46 ` law
0 siblings, 2 replies; 521+ messages in thread
From: Roger Sayle @ 2003-01-17 18:59 UTC (permalink / raw)
To: Jan Hubicka; +Cc: law, gcc-patches
Hi Jan and Jeff,
> > >The ICE occurs because combine tries to simplify it and it can't because
> > >of the constant substitution in the regclass.i.13.bypass pass. It would
> > >seem to me that the subreg should be simplified when the substitution for
> > >DI 262 is made. After that, the mode information is lost.
> > Agreed.
> When replacement is made by validate_replace_reg, this is done
> automatically. I think bypass pass should use it consistently...
No new RTL modification code was introduced splitting GCSE and
moving the jump bypassing pass after the loop optimizations.
Even prior to that, jump bypassing itself only affects branch
instructions and doesn't modify RTL expressions at all.
I believe that the problems on hppa64 and powerpc will turn out to
be more latent bugs in the existing GCSE or CSE constant propagation
code, just like the one in cse_insn that it has already uncovered
on H8300.
I know the rules, and am more than happy to take responsibility
for latent bugs that are exposed by my changes. If I'm right,
these fixes should also be applied to the 3.3 branch, as they'll
predate my recent changes.
Roger
--
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 18:59 ` Roger Sayle
@ 2003-01-17 22:33 ` David Edelsohn
2003-01-17 23:56 ` Dale Johannesen
2003-01-17 22:46 ` law
1 sibling, 1 reply; 521+ messages in thread
From: David Edelsohn @ 2003-01-17 22:33 UTC (permalink / raw)
To: Roger Sayle; +Cc: gcc-patches
>>>>> Roger Sayle writes:
> I believe that the problems on hppa64 and powerpc will turn out to
> be more latent bugs in the existing GCSE or CSE constant propagation
> code, just like the one in cse_insn that it has already uncovered
> on H8300.
This does appear to be the case for the PowerPC segfault. After
further investigation, I can construct a simplified testcase which fails
with or without the jump bypass patch. The jump bypass patch simply
causes the latent bug to occur in the complete version of the function
that appears in the benchmark.
David
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 22:33 ` David Edelsohn
@ 2003-01-17 23:56 ` Dale Johannesen
0 siblings, 0 replies; 521+ messages in thread
From: Dale Johannesen @ 2003-01-17 23:56 UTC (permalink / raw)
To: David Edelsohn; +Cc: Dale Johannesen, Roger Sayle, gcc-patches
On Friday, January 17, 2003, at 02:33 PM, David Edelsohn wrote:
>>>>>> Roger Sayle writes:
>
>> I believe that the problems on hppa64 and powerpc will turn out to
>> be more latent bugs in the existing GCSE or CSE constant propagation
>> code, just like the one in cse_insn that it has already uncovered
>> on H8300.
>
> This does appear to be the case for the PowerPC segfault. After
> further investigation, I can construct a simplified testcase which
> fails
> with or without the jump bypass patch. The jump bypass patch simply
> causes the latent bug to occur in the complete version of the function
> that appears in the benchmark.
Right. I've tracked this down to a lurker in the ppc-specific code.
Patch coming.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix RTL sharing problem in CSE
2003-01-17 18:59 ` Roger Sayle
2003-01-17 22:33 ` David Edelsohn
@ 2003-01-17 22:46 ` law
1 sibling, 0 replies; 521+ messages in thread
From: law @ 2003-01-17 22:46 UTC (permalink / raw)
To: Roger Sayle; +Cc: Jan Hubicka, gcc-patches
In message <Pine.LNX.4.44.0301171112100.6779-100000@www.eyesopen.com>, Roger Sa
yle writes:
>I believe that the problems on hppa64 and powerpc will turn out to
>be more latent bugs in the existing GCSE or CSE constant propagation
>code, just like the one in cse_insn that it has already uncovered
>on H8300.
I agree completely.
It's worth noting that the code we're tripping in the PA backend is
notoriously flakey -- even more so for PA64. If it wasn't such a
huge win to use xmpyu I'd suggest we drop the damn thing.
Jeff
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH]: Fix ICE in convert_move on PA
[not found] <no.id>
` (99 preceding siblings ...)
2003-01-17 17:15 ` [PATCH] Fix RTL sharing problem in CSE John David Anglin
@ 2003-01-19 16:59 ` John David Anglin
2003-01-20 17:31 ` Richard Henderson
2003-01-24 3:44 ` [PATCH] Fix find_reloads_address bug, take 2 Ulrich Weigand
` (62 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-01-19 16:59 UTC (permalink / raw)
To: John David Anglin; +Cc: jh, gcc-patches, rth
> > > I have determined by elimination that the ifcvt pass reordering
> > >
> > > Sat Oct 26 01:44:46 CEST 2002 Jan Hubicka <jh@suse.cz>
> > >
> > > * toplev.c (dump_file_index): Add DFI_ce3.
> > > (dump_file_info): Likewise.
> > > (rest_of_compilation): Run first ifcvt pass before tracer.
> > >
> > > results in the failure of g77.f-torture/execute/970625-2.f on the PA
> > > (hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11* and hppa64-hp-hpux11*).
> > >
> > > The following error occurs:
> > >
> > > /home/dave/gcc-3.3/gcc/gcc/testsuite/g77.f-torture/execute/970625-2.f:74: internal compiler error: in convert_move, at expr.c:1303
> > >
> > > We have
> > > Breakpoint 1, convert_move (to=0x401ba240, from=0x401ba270, unsignedp=0)
> > > at ../../gcc/gcc/expr.c:1303
> > > 1303 abort ();
> > > (gdb) p debug_rtx (to)
> > > (reg:CCFP 142)
> > > $1 = void
> > > (gdb) p debug_rtx (from)
> > > (reg:SI 143)
> > Interesting.
> > This looks like latent PA bug uncovered, but I will try to check it next
> > week.
Here is a patch to fix the above. It occurs as a result of the installation
of placeholders to set the CCFP register. These were installed last
September to improve optimization of if statements on the PA. Under some
circumstances, the CCFP register can become the destination for
the store flag from a general operand. The enclosed patch restricts
setting the store flag to destinations with a mode class in MODE_INT.
Possibly, this is over restrictive but it seemed reasonable choice.
Tested on hppa64-hp-hpux11.11 with no regressions.
Ok for main and branch?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2003-01-18 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* ifcvt.c (noce_emit_store_flag): Don't emit store flag if mode class
of destination is not MODE_INT.
Index: ifcvt.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.105
diff -u -3 -p -r1.105 ifcvt.c
--- ifcvt.c 19 Sep 2002 01:07:10 -0000 1.105
+++ ifcvt.c 18 Jan 2003 21:09:28 -0000
@@ -645,8 +645,8 @@ noce_emit_store_flag (if_info, x, revers
end_sequence ();
}
- /* Don't even try if the comparison operands are weird. */
- if (cond_complex)
+ /* Don't even try if the comparison operands or the mode of X are weird. */
+ if (cond_complex || GET_MODE_CLASS (GET_MODE (x)) != MODE_INT)
return NULL_RTX;
return emit_store_flag (x, code, XEXP (cond, 0),
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH] Fix find_reloads_address bug, take 2
[not found] <no.id>
` (100 preceding siblings ...)
2003-01-19 16:59 ` [PATCH]: Fix ICE in convert_move on PA John David Anglin
@ 2003-01-24 3:44 ` Ulrich Weigand
2003-02-01 21:40 ` ping: Unreviewed patch to fix patch to fix bootstrap failure on PA John David Anglin
` (61 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: Ulrich Weigand @ 2003-01-24 3:44 UTC (permalink / raw)
To: gcc-patches
I wrote originally:
>Secondly, if the condition hits, the code in question re-forms
>the address from
> (plus (plus frame-pointer index) constant)
>to
> (plus (plus frame-pointer constant) index)
>which is non-canonical RTL. That would not be a problem if
>-as intended- the (plus frame-pointer constant) term got
>reloaded into a register. However, find_reloads is called
>multiple times, and only after the last call will actual
>reloads be made. Unfortunatly, this code segment will
>*modify* the passed-in address RTX in-place on *every*
>call of find_reloads. This means after the return from
>the first find_reloads call out of calculate_needs_all_insns,
>the main insn stream will contain this piece of invalid RTL.
While this is correct, it actually does not really matter.
*If* the condition when to enter this block were correct,
the constant term would be invalid for an address. This
can only happen if that constant was in fact introduced
by eliminate_regs_in_insn just before the call to find_reloads.
In that case, it does not matter that the address is
modified in place, as calculate_needs_all_insns will
throw away the insn body anway to get rid to the changes
done by eliminate_regs.
The reason why I am seeing the ICE on s390 is that this
block is entered -due to the incorrect condition- even
for addresses where the constant term is valid; such
addresses might have been in the insn stream even before
register elimination, and thus calculate_needs_all_insns
will not undo the modification ...
Thus, the only bug that needs to be fixed is in fact
the incorrect condition; the rest should be fine as is.
The following patch implements this, and also fixes a
stupid bug in the original patch: the lines
! && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
and
! && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
need to be swapped, of course.
Also, I've included a test case that shows the ICE on s390.
Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux,
on gcc 3.3 branch and mainline.
OK to apply? Should this be considered for 3.2 as well?
ChangeLog:
gcc/
* reload.c (maybe_memory_address_p): New function.
(find_reloads_address): Use it instead of memory_address_p.
gcc/testsuite/
* gcc.dg/20030123-1.c: New test.
Index: gcc/reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.178.2.4.2.4
diff -c -p -r1.178.2.4.2.4 reload.c
*** gcc/reload.c 24 Oct 2002 08:59:49 -0000 1.178.2.4.2.4
--- gcc/reload.c 23 Jan 2003 20:21:16 -0000
*************** static int alternative_allows_memconst P
*** 257,262 ****
--- 257,263 ----
static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
int, rtx, int *));
static rtx make_memloc PARAMS ((rtx, int));
+ static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *));
static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PARAMS ((rtx, rtx));
*************** make_memloc (ad, regno)
*** 4545,4550 ****
--- 4546,4572 ----
return tem;
}
+ /* Returns true if AD could be turned into a valid memory reference
+ to mode MODE by reloading the part pointed to by PART into a
+ register. */
+
+ static int
+ maybe_memory_address_p (mode, ad, part)
+ enum machine_mode mode;
+ rtx ad;
+ rtx *part;
+ {
+ int retv;
+ rtx tem = *part;
+ rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
+
+ *part = reg;
+ retv = memory_address_p (mode, ad);
+ *part = tem;
+
+ return retv;
+ }
+
/* Record all reloads needed for handling memory address AD
which appears in *LOC in a memory reference to mode MODE
which itself is found in location *MEMREFLOC.
*************** find_reloads_address (mode, memrefloc, a
*** 4844,4850 ****
|| XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
! && ! memory_address_p (mode, ad))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
plus_constant (XEXP (XEXP (ad, 0), 0),
--- 4866,4872 ----
|| XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
! && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
plus_constant (XEXP (XEXP (ad, 0), 0),
*************** find_reloads_address (mode, memrefloc, a
*** 4869,4875 ****
|| XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
! && ! memory_address_p (mode, ad))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
XEXP (XEXP (ad, 0), 0),
--- 4891,4897 ----
|| XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
! && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
XEXP (XEXP (ad, 0), 0),
*** /dev/null Thu Sep 19 11:33:10 2002
--- gcc/testsuite/gcc.dg/20030123-1.c Thu Jan 23 21:27:33 2003
***************
*** 0 ****
--- 1,17 ----
+ /* This used to ICE due to a reload bug on s390*. */
+
+ /* { dg-do compile { target s390*-*-* } } */
+ /* { dg-options "-O2" } */
+
+ void func (char *p);
+
+ void test (void)
+ {
+ char *p = alloca (4096);
+ long idx;
+
+ asm ("" : "=r" (idx) : : "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12");
+
+ func (p + idx + 1);
+ }
+
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de
^ permalink raw reply [flat|nested] 521+ messages in thread
* ping: Unreviewed patch to fix patch to fix bootstrap failure on PA
[not found] <no.id>
` (101 preceding siblings ...)
2003-01-24 3:44 ` [PATCH] Fix find_reloads_address bug, take 2 Ulrich Weigand
@ 2003-02-01 21:40 ` John David Anglin
2003-02-01 21:43 ` Zack Weinberg
2003-02-02 0:23 ` Geoff Keating
2003-02-03 5:02 ` hppa-linux regressions and 3.2.2 release John David Anglin
` (60 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-01 21:40 UTC (permalink / raw)
To: John David Anglin; +Cc: zack, gcc-patches, dj
This patch is needed to fix a problem arising from the rewrite of
libiberty/pexecute.c. The rewrite changed pwait so that it now uses
waitpid instead of wait. Would someone please review:
<http://gcc.gnu.org/ml/gcc-patches/2003-01/msg02069.html>.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: hppa-linux regressions and 3.2.2 release
[not found] <no.id>
` (102 preceding siblings ...)
2003-02-01 21:40 ` ping: Unreviewed patch to fix patch to fix bootstrap failure on PA John David Anglin
@ 2003-02-03 5:02 ` John David Anglin
2003-02-03 11:03 ` Gabriel Dos Reis
2003-02-03 16:26 ` John David Anglin
2003-02-04 21:20 ` Mainline bootstrap failure on hppa2.0w-hp-hpux11.00 John David Anglin
` (59 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-03 5:02 UTC (permalink / raw)
To: John David Anglin; +Cc: gdr, ebotcazou, randolph, gcc, gcc-patches
> I now have tests running on hppa2.0w-hp-hpux11.11, hppa64-hp-hpux11.00
> and hppa-unknown-linux-gnu including the patch set for the other PR from
> Franz Sirl. I will post the results as soon as available.
The hppa2.0w-hp-hpux11.11 are complete and identical to the previous
run without Franz's patch:
<http://gcc.gnu.org/ml/gcc-testresults/2003-02/msg00130.html>.
I had to restart the hppa64-hp-hpux11.00 run. I used the HP linker
and it generates a warning on each link. This totally messes
up the testsuite results. I would like to apply the following patch
from Steve Ellcey to correct the problem. It has been on the main and
3.3 since early last October. The comment describes what it does. It
only affects hppa64-hp-hpux11* and doesn't affect code generation.
As you are doing preleases, I will wait for your OK.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2003-02-02 Steve Ellcey <sje@cup.hp.com>
* config/pa/pa64-hpux.h (INIT_ENVIRONMENT): New.
Index: config/pa/pa64-hpux.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa64-hpux.h,v
retrieving revision 1.9
diff -u -3 -p -r1.9 pa64-hpux.h
--- config/pa/pa64-hpux.h 21 Jan 2002 21:22:19 -0000 1.9
+++ config/pa/pa64-hpux.h 3 Feb 2003 04:38:07 -0000
@@ -232,3 +232,8 @@ do { \
#ifndef ASM_DECLARE_RESULT
#define ASM_DECLARE_RESULT(FILE, RESULT)
#endif
+
+/* If using HP ld do not call pxdb. Use size as a program that does nothing
+ and returns 0. /bin/true cannot be used because it is a script without
+ an interpreter. */
+#define INIT_ENVIRONMENT "LD_PXDB=/usr/ccs/bin/size"
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: hppa-linux regressions and 3.2.2 release
2003-02-03 5:02 ` hppa-linux regressions and 3.2.2 release John David Anglin
@ 2003-02-03 11:03 ` Gabriel Dos Reis
2003-02-03 16:26 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: Gabriel Dos Reis @ 2003-02-03 11:03 UTC (permalink / raw)
To: John David Anglin; +Cc: ebotcazou, randolph, gcc, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
[...]
| As you are doing preleases, I will wait for your OK.
It is OK.
Thanks,
-- Gaby
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: hppa-linux regressions and 3.2.2 release
2003-02-03 5:02 ` hppa-linux regressions and 3.2.2 release John David Anglin
2003-02-03 11:03 ` Gabriel Dos Reis
@ 2003-02-03 16:26 ` John David Anglin
2003-02-03 16:54 ` Gabriel Dos Reis
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-02-03 16:26 UTC (permalink / raw)
To: John David Anglin; +Cc: gdr, ebotcazou, randolph, gcc, gcc-patches
> > I now have tests running on hppa2.0w-hp-hpux11.11, hppa64-hp-hpux11.00
> > and hppa-unknown-linux-gnu including the patch set for the other PR from
> > Franz Sirl. I will post the results as soon as available.
>
> The hppa2.0w-hp-hpux11.11 are complete and identical to the previous
> run without Franz's patch:
All test runs are complete and posted. There are no regressions.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: hppa-linux regressions and 3.2.2 release
2003-02-03 16:26 ` John David Anglin
@ 2003-02-03 16:54 ` Gabriel Dos Reis
2003-02-03 18:02 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Gabriel Dos Reis @ 2003-02-03 16:54 UTC (permalink / raw)
To: John David Anglin; +Cc: ebotcazou, randolph, gcc, gcc-patches
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
| > > I now have tests running on hppa2.0w-hp-hpux11.11, hppa64-hp-hpux11.00
| > > and hppa-unknown-linux-gnu including the patch set for the other PR from
| > > Franz Sirl. I will post the results as soon as available.
| >
| > The hppa2.0w-hp-hpux11.11 are complete and identical to the previous
| > run without Franz's patch:
|
| All test runs are complete and posted. There are no regressions.
Thanks for the report. Please commit the set of patches you tested.
This hopefully will be the last patch to commit.
-- Gaby
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Mainline bootstrap failure on hppa2.0w-hp-hpux11.00
[not found] <no.id>
` (103 preceding siblings ...)
2003-02-03 5:02 ` hppa-linux regressions and 3.2.2 release John David Anglin
@ 2003-02-04 21:20 ` John David Anglin
2003-02-05 18:21 ` John David Anglin
` (58 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-04 21:20 UTC (permalink / raw)
To: John David Anglin; +Cc: roger, gcc-patches
> > I'm getting a bootstrap failure on HPUX with current CVS mainline,
> > probably caused by the recent "-Werror" change.
This may have been obvious but you can avoid the error until the problem
is fixed by configuring with "--disable-werror".
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Mainline bootstrap failure on hppa2.0w-hp-hpux11.00
[not found] <no.id>
` (104 preceding siblings ...)
2003-02-04 21:20 ` Mainline bootstrap failure on hppa2.0w-hp-hpux11.00 John David Anglin
@ 2003-02-05 18:21 ` John David Anglin
2003-02-05 18:46 ` John David Anglin
` (57 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-05 18:21 UTC (permalink / raw)
To: John David Anglin; +Cc: ghazi, gcc-patches, roger
> I don't have exact information but I assume that it is the same as
> isspace. It returns a non zero integer, not necessarily 1.
That's for true.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Mainline bootstrap failure on hppa2.0w-hp-hpux11.00
[not found] <no.id>
` (105 preceding siblings ...)
2003-02-05 18:21 ` John David Anglin
@ 2003-02-05 18:46 ` John David Anglin
2003-02-05 19:12 ` Kaveh R. Ghazi
2003-02-11 19:37 ` Bootstrap failure on hppa-unknown-linux-gnu, trunk John David Anglin
` (56 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-02-05 18:46 UTC (permalink / raw)
To: John David Anglin; +Cc: ghazi, gcc-patches, roger
> I read in 6.3.1.8 which discusses the usual arithmetic conversions,
>
> Otherwise, if the type of the operand with the signed integer
> can represent all of the values of the type of the operand
> with unsigned integer type, then the operand with unsigned
> integer type is converted to the type of the operand with
> signed integer type.
>
> It seems as if this would apply to the case in question. Do we
Thinking more, I am confused and it doesn't apply. While the integer
type can represent all possible values of the unsigned expression, it
can't represent all the values of the unsigned type. So, the latter
conversion would apply and I guess a warning should be generated,
although gcc should know the conversion is safe.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Mainline bootstrap failure on hppa2.0w-hp-hpux11.00
2003-02-05 18:46 ` John David Anglin
@ 2003-02-05 19:12 ` Kaveh R. Ghazi
0 siblings, 0 replies; 521+ messages in thread
From: Kaveh R. Ghazi @ 2003-02-05 19:12 UTC (permalink / raw)
To: dave; +Cc: gcc-patches, roger
> From: "John David Anglin" <dave@hiauly1.hia.nrc.ca>
>
> > I read in 6.3.1.8 which discusses the usual arithmetic conversions,
> >
> > Otherwise, if the type of the operand with the signed integer
> > can represent all of the values of the type of the operand
> > with unsigned integer type, then the operand with unsigned
> > integer type is converted to the type of the operand with
> > signed integer type.
> >
> > It seems as if this would apply to the case in question. Do we
>
> Thinking more, I am confused and it doesn't apply. While the integer
> type can represent all possible values of the unsigned expression, it
> can't represent all the values of the unsigned type. So, the latter
> conversion would apply and I guess a warning should be generated,
Correct, i.e.
This will warn: expr ? unsigned int : int;
This won't: expr ? unsigned char : int;
The case under discussion is of the first form, even though the range
of values is constrained with &.
> although gcc should know the conversion is safe.
> Dave
How? GCC can't "know" the conversion is safe. The unsigned qty has a
small range, but it's still an unsigned int type, so C mandates that
the int qty (_isspace) gets promoted. GCC doesn't know the range of
the int, that's the problem. If GCC knew _isspace was never negative,
we wouldn't warn, same as with int constants like "1". Knowing that
the unsigned portion is a small number doesn't help.
--Kaveh
--
Kaveh R. Ghazi ghazi@caip.rutgers.edu
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure on hppa-unknown-linux-gnu, trunk
[not found] <no.id>
` (106 preceding siblings ...)
2003-02-05 18:46 ` John David Anglin
@ 2003-02-11 19:37 ` John David Anglin
2003-02-11 22:37 ` Josef Zlomek
2003-03-05 22:00 ` Josef Zlomek
2003-03-11 2:04 ` jcf-io.c:339: warning: `origsep' might be used uninitialized John David Anglin
` (55 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-11 19:37 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches, zlomekj
> stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/hppa-linux/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -Werror -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include
> ../../gcc/gcc/bb-reorder.c -o bb-reorder.o
> ../../gcc/gcc/bb-reorder.c: In function `find_traces':
> ../../gcc/gcc/bb-reorder.c:219: error: unrecognizable insn:
> (insn 776 775 777 0x40568f60 (set (reg:DI 70 %fr23 [252])
> (mult:DI (zero_extend:DI (reg:SI 69 %fr22R [246]))
> (reg:DI 74 %fr25))) -1 (nil)
> (expr_list:REG_UNUSED (reg:SI 71 %fr23R)
> (expr_list:REG_DEAD (reg:DI 74 %fr25)
> (nil))))
> ../../gcc/gcc/bb-reorder.c:219: internal compiler error: in num_delay_slots, at insn-attrtab.c:4085
I have determined that it is the addition of this patch that results in
the above ICE:
2003-02-10 Josef Zlomek <zlomekj@suse.cz>
* Makefile.in (bb-reorder.o): Add dependency on $(FIBHEAP_H).
* bb-reorder.c (make_reorder_chain): Deleted.
(make_reorder_chain_1): Deleted.
(find_traces): New function.
(rotate_loop): New function.
(mark_bb_visited): New function.
(find_traces_1_round): New function.
(copy_bb): New function.
(bb_to_key): New function.
(better_edge_p): New function.
(connect_traces): New function.
(copy_bb_p): New function.
(get_uncond_jump_length): New function.
(reorder_basic_blocks): Use new functions (Software Trace Cache).
* cfgcleanup.c (outgoing_edges_match): Enable crossjumping across loop
boundaries.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure on hppa-unknown-linux-gnu, trunk
2003-02-11 19:37 ` Bootstrap failure on hppa-unknown-linux-gnu, trunk John David Anglin
@ 2003-02-11 22:37 ` Josef Zlomek
2003-02-11 22:51 ` John David Anglin
2003-03-05 22:00 ` Josef Zlomek
1 sibling, 1 reply; 521+ messages in thread
From: Josef Zlomek @ 2003-02-11 22:37 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches
> > stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/hppa-linux/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -Werror -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include
> > ../../gcc/gcc/bb-reorder.c -o bb-reorder.o
> > ../../gcc/gcc/bb-reorder.c: In function `find_traces':
> > ../../gcc/gcc/bb-reorder.c:219: error: unrecognizable insn:
> > (insn 776 775 777 0x40568f60 (set (reg:DI 70 %fr23 [252])
> > (mult:DI (zero_extend:DI (reg:SI 69 %fr22R [246]))
> > (reg:DI 74 %fr25))) -1 (nil)
> > (expr_list:REG_UNUSED (reg:SI 71 %fr23R)
> > (expr_list:REG_DEAD (reg:DI 74 %fr25)
> > (nil))))
> > ../../gcc/gcc/bb-reorder.c:219: internal compiler error: in num_delay_slots, at insn-attrtab.c:4085
>
> I have determined that it is the addition of this patch that results in
> the above ICE:
>
> 2003-02-10 Josef Zlomek <zlomekj@suse.cz>
>
> * Makefile.in (bb-reorder.o): Add dependency on $(FIBHEAP_H).
> * bb-reorder.c (make_reorder_chain): Deleted.
> (make_reorder_chain_1): Deleted.
> (find_traces): New function.
> (rotate_loop): New function.
> (mark_bb_visited): New function.
> (find_traces_1_round): New function.
> (copy_bb): New function.
> (bb_to_key): New function.
> (better_edge_p): New function.
> (connect_traces): New function.
> (copy_bb_p): New function.
> (get_uncond_jump_length): New function.
> (reorder_basic_blocks): Use new functions (Software Trace Cache).
> * cfgcleanup.c (outgoing_edges_match): Enable crossjumping across loop
> boundaries.
I apologize for the breakage. It seems that new bb-reorder has uncovered
bugs in machine descriptions.
Honza Hubicka has checked in a patch
(http://gcc.gnu.org/ml/gcc-patches/2003-02/msg00847.html)
which hopefully should enable gcc to bootstrap again.
Josef
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure on hppa-unknown-linux-gnu, trunk
2003-02-11 22:37 ` Josef Zlomek
@ 2003-02-11 22:51 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-02-11 22:51 UTC (permalink / raw)
To: Josef Zlomek; +Cc: gcc, gcc-patches
> > > stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/hppa-linux/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -Werror -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include
> > > ../../gcc/gcc/bb-reorder.c -o bb-reorder.o
> > > ../../gcc/gcc/bb-reorder.c: In function `find_traces':
> > > ../../gcc/gcc/bb-reorder.c:219: error: unrecognizable insn:
> > > (insn 776 775 777 0x40568f60 (set (reg:DI 70 %fr23 [252])
> > > (mult:DI (zero_extend:DI (reg:SI 69 %fr22R [246]))
> > > (reg:DI 74 %fr25))) -1 (nil)
> > > (expr_list:REG_UNUSED (reg:SI 71 %fr23R)
> > > (expr_list:REG_DEAD (reg:DI 74 %fr25)
> > > (nil))))
> > > ../../gcc/gcc/bb-reorder.c:219: internal compiler error: in num_delay_slots, at insn-attrtab.c:4085
> >
> > I have determined that it is the addition of this patch that results in
> > the above ICE:
> >
> > 2003-02-10 Josef Zlomek <zlomekj@suse.cz>
> >
> > * Makefile.in (bb-reorder.o): Add dependency on $(FIBHEAP_H).
> > * bb-reorder.c (make_reorder_chain): Deleted.
> > (make_reorder_chain_1): Deleted.
> > (find_traces): New function.
> > (rotate_loop): New function.
> > (mark_bb_visited): New function.
> > (find_traces_1_round): New function.
> > (copy_bb): New function.
> > (bb_to_key): New function.
> > (better_edge_p): New function.
> > (connect_traces): New function.
> > (copy_bb_p): New function.
> > (get_uncond_jump_length): New function.
> > (reorder_basic_blocks): Use new functions (Software Trace Cache).
> > * cfgcleanup.c (outgoing_edges_match): Enable crossjumping across loop
> > boundaries.
>
> I apologize for the breakage. It seems that new bb-reorder has uncovered
> bugs in machine descriptions.
> Honza Hubicka has checked in a patch
> (http://gcc.gnu.org/ml/gcc-patches/2003-02/msg00847.html)
> which hopefully should enable gcc to bootstrap again.
I have been looking at the patterns which use the xmpyu insn on the PA.
There are two patterns (32 and 64 bit) which have an uint32_operand
predicate and "f" constraint. The "f" constraint is inconsistent with
the predicate. The uint32_operand predicate is inconsistent with the
actual capability of the machine instruction. I had queried Jeff Law
about this in the past. This was his response:
> I thought changing the operands of the pattern to register_operand is a more
> accurate description of the machine insn although reloads still can
> potentially occur.
It's certainly more accurate, but due to secondary effects of register
allocation
and reloading it's actually more profitable to be more general in the
operand predicates than what the instruction actually allows. That is
generally a bad thing to do, but from time to time it is helpful.
Basically, some games are being played with the predicate and constraint
to improve the generated code.
The 32-bit seems to be building again. However, the have been some
"strange" warning messages on hppa64-hp-hpux11.11:
g-yacc.29398.c: In function `yystrlen':
g-yacc.29398.c:708: warning: traditional C rejects ISO C style function definiti
ons
g-yacc.29398.c: In function `yystpcpy':
g-yacc.29398.c:733: warning: traditional C rejects ISO C style function definiti
ons
g-yacc.29398.c: In function `yydestruct':
g-yacc.29398.c:800: warning: traditional C rejects ISO C style function definiti
ons
g-yacc.29398.c: In function `yyparse':
g-yacc.29398.c:863: warning: traditional C rejects ISO C style function definiti
ons
and
c-p29635.c: In function `yy_stack_print':
c-p29635.c:2150: warning: traditional C rejects ISO C style function definitions
c-p29635.c: In function `yy_reduce_print':
c-p29635.c:2176: warning: traditional C rejects ISO C style function definitions
c-p29635.c: In function `yysymprint':
c-p29635.c:2297: warning: traditional C rejects ISO C style function definitions
c-p29635.c: In function `yydestruct':
c-p29635.c:2333: warning: traditional C rejects ISO C style function definitions
c-p29635.c: In function `yyparse':
c-p29635.c:2396: warning: traditional C rejects ISO C style function definitions
Possibly, this is a bison 1.875 problem. Yes, it seems to be.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure on hppa-unknown-linux-gnu, trunk
2003-02-11 19:37 ` Bootstrap failure on hppa-unknown-linux-gnu, trunk John David Anglin
2003-02-11 22:37 ` Josef Zlomek
@ 2003-03-05 22:00 ` Josef Zlomek
2003-03-05 22:03 ` Josef Zlomek
1 sibling, 1 reply; 521+ messages in thread
From: Josef Zlomek @ 2003-03-05 22:00 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches
> > stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/hppa-linux/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -Werror -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include
> > ../../gcc/gcc/bb-reorder.c -o bb-reorder.o
> > ../../gcc/gcc/bb-reorder.c: In function `find_traces':
> > ../../gcc/gcc/bb-reorder.c:219: error: unrecognizable insn:
> > (insn 776 775 777 0x40568f60 (set (reg:DI 70 %fr23 [252])
> > (mult:DI (zero_extend:DI (reg:SI 69 %fr22R [246]))
> > (reg:DI 74 %fr25))) -1 (nil)
> > (expr_list:REG_UNUSED (reg:SI 71 %fr23R)
> > (expr_list:REG_DEAD (reg:DI 74 %fr25)
> > (nil))))
> > ../../gcc/gcc/bb-reorder.c:219: internal compiler error: in num_delay_slots, at insn-attrtab.c:4085
>
> I have determined that it is the addition of this patch that results in
> the above ICE:
Maybe it is a similar problem in machine descriptions as alpha and sh did
have (http://gcc.gnu.org/ml/gcc-patches/2003-02/msg01295.html). But maybe I'm wrong.
The bb-reorder itself is pretty high level, it is a probably first use
of code duplication functions which went to mainline.
Anyway, I apologize for the breakage.
Josef
> 2003-02-10 Josef Zlomek <zlomekj@suse.cz>
>
> * Makefile.in (bb-reorder.o): Add dependency on $(FIBHEAP_H).
> * bb-reorder.c (make_reorder_chain): Deleted.
> (make_reorder_chain_1): Deleted.
> (find_traces): New function.
> (rotate_loop): New function.
> (mark_bb_visited): New function.
> (find_traces_1_round): New function.
> (copy_bb): New function.
> (bb_to_key): New function.
> (better_edge_p): New function.
> (connect_traces): New function.
> (copy_bb_p): New function.
> (get_uncond_jump_length): New function.
> (reorder_basic_blocks): Use new functions (Software Trace Cache).
> * cfgcleanup.c (outgoing_edges_match): Enable crossjumping across loop
> boundaries.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure on hppa-unknown-linux-gnu, trunk
2003-03-05 22:00 ` Josef Zlomek
@ 2003-03-05 22:03 ` Josef Zlomek
0 siblings, 0 replies; 521+ messages in thread
From: Josef Zlomek @ 2003-03-05 22:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc, gcc-patches
> > > stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/hppa-linux/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -fno-common -Werror -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include
> > > ../../gcc/gcc/bb-reorder.c -o bb-reorder.o
> > > ../../gcc/gcc/bb-reorder.c: In function `find_traces':
> > > ../../gcc/gcc/bb-reorder.c:219: error: unrecognizable insn:
> > > (insn 776 775 777 0x40568f60 (set (reg:DI 70 %fr23 [252])
> > > (mult:DI (zero_extend:DI (reg:SI 69 %fr22R [246]))
> > > (reg:DI 74 %fr25))) -1 (nil)
> > > (expr_list:REG_UNUSED (reg:SI 71 %fr23R)
> > > (expr_list:REG_DEAD (reg:DI 74 %fr25)
> > > (nil))))
> > > ../../gcc/gcc/bb-reorder.c:219: internal compiler error: in num_delay_slots, at insn-attrtab.c:4085
> >
> > I have determined that it is the addition of this patch that results in
> > the above ICE:
>
> Maybe it is a similar problem in machine descriptions as alpha and sh did
> have (http://gcc.gnu.org/ml/gcc-patches/2003-02/msg01295.html). But maybe I'm wrong.
> The bb-reorder itself is pretty high level, it is a probably first use
> of code duplication functions which went to mainline.
> Anyway, I apologize for the breakage.
Or there simply is some code in bb-reorder.c which uncovers another bug.
Josef
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: jcf-io.c:339: warning: `origsep' might be used uninitialized
[not found] <no.id>
` (107 preceding siblings ...)
2003-02-11 19:37 ` Bootstrap failure on hppa-unknown-linux-gnu, trunk John David Anglin
@ 2003-03-11 2:04 ` John David Anglin
2003-03-21 0:02 ` [PATCH]: PA long unconditional branch generation (PR10062) John David Anglin
` (54 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-03-11 2:04 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rmathew
> Yet another bootstrap error on hppa64-hp-hpux11.11:
>
> stage1/xgcc -Bstage1/ -B/opt/gnu64/hppa64-hp-hpux11.11/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -fno-common -Werror -DHAVE_CONFIG_H -I. -Ijava -I../../gcc/gcc -I../../gcc/gcc/java -I../../gcc/gcc/config -I../../gcc/gcc/../include -I../../gcc/gcc/../zlib \
> ../../gcc/gcc/java/jcf-io.c -o java/jcf-io.o
> ../../gcc/gcc/java/jcf-io.c: In function `caching_stat':
> ../../gcc/gcc/java/jcf-io.c:339: warning: `origsep' might be used uninitialized in this function
Was the patch that caused this failure tested and approved?
<http://gcc.gnu.org/ml/gcc-cvs/2003-03/msg00510.html>
I don't see any mention of it on gcc-patches.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH]: PA long unconditional branch generation (PR10062)
[not found] <no.id>
` (108 preceding siblings ...)
2003-03-11 2:04 ` jcf-io.c:339: warning: `origsep' might be used uninitialized John David Anglin
@ 2003-03-21 0:02 ` John David Anglin
2003-04-10 19:52 ` Failure of test07 in 27_io/filebuf_members.cc under HP-UX (PR 9964) John David Anglin
` (53 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-03-21 0:02 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, china
> Without inlining, the length of the compare chain is 29. The default
> inlining requires in excess of 768MB of virtual memory to compile
> the testcase in the PR. Clearly, the default inlining parameters
> need to be tweaked to keep the compilation with reasonable bounds
> but I'm not sure how to do this. Possibly, the throttling algorithm
> is broken. It would also be nice to use a jump table.
I should note that once the size of a function exceeds ~240KB we need
to use long calls and branches. These sequences are substantially
longer and less efficient. So, we probably lose more than we gain
at that point.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Failure of test07 in 27_io/filebuf_members.cc under HP-UX (PR 9964)
[not found] <no.id>
` (109 preceding siblings ...)
2003-03-21 0:02 ` [PATCH]: PA long unconditional branch generation (PR10062) John David Anglin
@ 2003-04-10 19:52 ` John David Anglin
2003-04-11 1:22 ` Benjamin Kosnik
2003-04-18 16:32 ` PATCH: Fix PR 8866 John David Anglin
` (52 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-04-10 19:52 UTC (permalink / raw)
To: John David Anglin; +Cc: libstdc++, gcc-patches
> I have examined the failure of 27_io/filebuf_members.cc on
> hppa2.0w-hp-hpux11.11. The test fails because the following code
> from config/io/basic_file_stdio.cc doesn't close the file after a
> character is written to a broken pipe:
The enclosed patch against the 3.3 branch fixes the failure of
27_io/filebuf_members.cc on hppa2.0w-hp-hpux11.11.
Ok for 3.3 and main?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2003-04-10 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* basic_file_stdio.cc (__basic_file<char>::close): Don't flush stream
twice. Always set _M_cfile to 0 when stream was open.
Index: config/io/basic_file_stdio.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/config/io/basic_file_stdio.cc,v
retrieving revision 1.6.2.2
diff -u -3 -p -r1.6.2.2 basic_file_stdio.cc
--- config/io/basic_file_stdio.cc 5 Feb 2003 19:20:07 -0000 1.6.2.2
+++ config/io/basic_file_stdio.cc 10 Apr 2003 19:39:25 -0000
@@ -181,12 +181,12 @@ namespace std
__basic_file* __retval = static_cast<__basic_file*>(NULL);
if (this->is_open())
{
- fflush(_M_cfile);
- if ((_M_cfile_created && fclose(_M_cfile) == 0) || !_M_cfile_created)
- {
- _M_cfile = 0;
- __retval = this;
- }
+ if (_M_cfile_created)
+ fclose(_M_cfile);
+ else
+ fflush(_M_cfile);
+ _M_cfile = 0;
+ __retval = this;
}
return __retval;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: PATCH: Fix PR 8866
[not found] <no.id>
` (110 preceding siblings ...)
2003-04-10 19:52 ` Failure of test07 in 27_io/filebuf_members.cc under HP-UX (PR 9964) John David Anglin
@ 2003-04-18 16:32 ` John David Anglin
2003-05-10 2:15 ` [PATCH] allow zero_extract combines - checked in John David Anglin
` (51 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-04-18 16:32 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
> Hi Mark,
>
> The following patch introduces a testsuite regression on the 3.3 branch
> for hppa64-hp-hpux11.11:
>
> 2003-04-16 Mark Mitchell <mark at codesourcery dot com>
>
> PR middle-end/8866
> * cfgtrl.c (try_redirect_by_replacing_jump): Do not delete
> jumptables.
>
> There are three new fails of gcc.c-torture/execute/20011219-1.c.
> See <http://gcc.gnu.org/ml/gcc-testresults/2003-04/msg01086.html>.
> The compiler appears to go into an infinite loop compiling this
> file at -O2 and above.
As well, the following bootstrap failure on the 3.3 branch occurred on
hppa-unknown-linux-gnu:
stage1/xgcc -Bstage1/ -B/home/dave/opt/gnu/gcc/gcc-3.3-sjlj/hppa-linux/bin/ -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic -Wno-long-long -DHAVE_CONFIG_H -DGENERATOR_FILE -o genrecog \
genrecog.o rtl.o read-rtl.o bitmap.o ggc-none.o gensupport.o insn-conditions.o print-rtl1.o \
errors.o ../libiberty/libiberty.a
./genrecog ../../gcc/gcc/config/pa/pa.md > tmp-recog.c
make[2]: *** [s-recog] Error 137
I had to kill genrecog as it was hung in a loop. I haven't specifically
identified your patch as causing the genrecog problem but it was installed
in the period between the last successful bootstrap and the above failure.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
[not found] <no.id>
` (111 preceding siblings ...)
2003-04-18 16:32 ` PATCH: Fix PR 8866 John David Anglin
@ 2003-05-10 2:15 ` John David Anglin
2003-05-12 2:26 ` Eric Christopher
2003-05-12 16:50 ` Eric Christopher
2003-05-23 1:17 ` speedup collect2 (by not using it) John David Anglin
` (50 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2003-05-10 2:15 UTC (permalink / raw)
To: John David Anglin; +Cc: echristo, gcc-patches
> After combine, we have
>
> (insn 6 5 7 0 0000000000000000 (set (reg:SI 69)
> (mem/s:SI (plus:DI (reg/f:DI 29 %r29)
> (const_int -64 [0xffffffffffffffc0])) [0+0 S4 A32])) 70 {*pa.md:2251} (nil)
> (nil))
>
> (note 7 6 8 0 NOTE_INSN_DELETED)
>
> (insn 8 7 9 0 0000000000000000 (set (mem/s:SI (plus:DI (reg/f:DI 29 %r29)
> (const_int -64 [0xffffffffffffffc0])) [0+0 S4 A32])
> (subreg:SI (reg:DI 68 [ u ]) 4)) 70 {*pa.md:2251} (insn_list 5 (nil))
> (expr_list:REG_DEAD (reg:DI 68 [ u ])
> (expr_list:REG_DEAD (reg/f:DI 29 %r29)
> (nil))))
>
> There isn't a REG_DEAD note for reg:SI 69 any longer. This causes
> find_free_reg to fail because dead_index for this QTYNO is -1:
Actually, it seems insn 6 should have been deleted as there is no
other use of reg:SI 69.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-10 2:15 ` [PATCH] allow zero_extract combines - checked in John David Anglin
@ 2003-05-12 2:26 ` Eric Christopher
2003-05-12 2:43 ` John David Anglin
2003-05-12 16:50 ` Eric Christopher
1 sibling, 1 reply; 521+ messages in thread
From: Eric Christopher @ 2003-05-12 2:26 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> >
> > There isn't a REG_DEAD note for reg:SI 69 any longer. This causes
> > find_free_reg to fail because dead_index for this QTYNO is -1:
>
> Actually, it seems insn 6 should have been deleted as there is no
> other use of reg:SI 69.
Odd. I love exposing bugs in other places. It means I only have to look
at the entire rest of the compiler ;)
Thanks for the help.
Hey, btw, do you have an updated config.guess for hppa64-hp-hpux11.00? I
have to explicitly set it.
-eric
--
Eric Christopher <echristo@redhat.com>
checking host system type... /es/scratch/echristo/gcc/config.guess: unable to guess system type
This script, last modified 2003-01-30, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
ftp://ftp.gnu.org/pub/gnu/config/
If the version you run (/es/scratch/echristo/gcc/config.guess) is already up to
date, please
send the following data and any information you think might be
pertinent to <config-patches@gnu.org> in order to provide the needed
information to handle your system.
config.guess timestamp = 2003-01-30
uname -m = 9000/800
uname -r = B.11.00
uname -s = -t
uname -v = U
/usr/bin/uname -p =
/bin/uname -X =
hostinfo =
/bin/universe =
/usr/bin/arch -k =
/bin/arch =
/usr/bin/oslevel =
/usr/convex/getsysinfo =
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 2:26 ` Eric Christopher
@ 2003-05-12 2:43 ` John David Anglin
2003-05-12 9:11 ` Eric Christopher
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-05-12 2:43 UTC (permalink / raw)
To: Eric Christopher; +Cc: gcc-patches
> Odd. I love exposing bugs in other places. It means I only have to look
> at the entire rest of the compiler ;)
Well it's probably not as bad as that :)
> Hey, btw, do you have an updated config.guess for hppa64-hp-hpux11.00? I
> have to explicitly set it.
No, the current version supports hppa64-hp-hpux11.00. The situation
is somewhat different from other ports in that the 32 and 64-bit ports
are completely separate ports. This is pretty much the situation with
HP's tools as well, although HP provides wrappers around them.
The way to get this to work is to define PATH so that configure finds
a 64-bit version of gcc, or you can define CC so that it selects
a 64-bit compiler (e.g., CC="cc -Ae +DA2.0W"). Then, config.guess will
automatically select hppa64-hp-hpux11.00 rather than hppa2.0w-hp-hpux11.00.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 2:43 ` John David Anglin
@ 2003-05-12 9:11 ` Eric Christopher
0 siblings, 0 replies; 521+ messages in thread
From: Eric Christopher @ 2003-05-12 9:11 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Sun, 2003-05-11 at 19:43, John David Anglin wrote:
> > Odd. I love exposing bugs in other places. It means I only have to look
> > at the entire rest of the compiler ;)
>
> Well it's probably not as bad as that :)
Well.. yeah. :)
> No, the current version supports hppa64-hp-hpux11.00. The situation
> is somewhat different from other ports in that the 32 and 64-bit ports
> are completely separate ports. This is pretty much the situation with
> HP's tools as well, although HP provides wrappers around them.
>
> The way to get this to work is to define PATH so that configure finds
> a 64-bit version of gcc, or you can define CC so that it selects
> a 64-bit compiler (e.g., CC="cc -Ae +DA2.0W"). Then, config.guess will
> automatically select hppa64-hp-hpux11.00 rather than hppa2.0w-hp-hpux11.00.
Ah ha. This will help a lot. Might help with my current build problem on
hpux (native cpp bitching about c-opts.c). *sigh*
-eric
--
Eric Christopher <echristo@redhat.com>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-10 2:15 ` [PATCH] allow zero_extract combines - checked in John David Anglin
2003-05-12 2:26 ` Eric Christopher
@ 2003-05-12 16:50 ` Eric Christopher
2003-05-12 17:05 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Eric Christopher @ 2003-05-12 16:50 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> Actually, it seems insn 6 should have been deleted as there is no
> other use of reg:SI 69.
Apparently this isn't reproducing now, but a full bootstrap is not
reproducible due to fallout from Jan's patch.
-eric
--
Eric Christopher <echristo@redhat.com>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 16:50 ` Eric Christopher
@ 2003-05-12 17:05 ` John David Anglin
2003-05-12 17:13 ` Eric Christopher
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-05-12 17:05 UTC (permalink / raw)
To: Eric Christopher; +Cc: gcc-patches
> > Actually, it seems insn 6 should have been deleted as there is no
> > other use of reg:SI 69.
>
> Apparently this isn't reproducing now, but a full bootstrap is not
> reproducible due to fallout from Jan's patch.
Did you compile with "-O1"? That's the only optimization level where
the problem occurs.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 17:05 ` John David Anglin
@ 2003-05-12 17:13 ` Eric Christopher
2003-05-12 17:59 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Eric Christopher @ 2003-05-12 17:13 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Mon, 2003-05-12 at 10:05, John David Anglin wrote:
> > > Actually, it seems insn 6 should have been deleted as there is no
> > > other use of reg:SI 69.
> >
> > Apparently this isn't reproducing now, but a full bootstrap is not
> > reproducible due to fallout from Jan's patch.
>
> Did you compile with "-O1"? That's the only optimization level where
> the problem occurs.
Actually, it was your comment that I was basing this on - perhaps I
misunderstood you. :)
I'll just wait for your patch and then try again.
-eric
--
Eric Christopher <echristo@redhat.com>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 17:13 ` Eric Christopher
@ 2003-05-12 17:59 ` John David Anglin
2003-05-12 18:03 ` Eric Christopher
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-05-12 17:59 UTC (permalink / raw)
To: Eric Christopher; +Cc: gcc-patches
> On Mon, 2003-05-12 at 10:05, John David Anglin wrote:
> > > > Actually, it seems insn 6 should have been deleted as there is no
> > > > other use of reg:SI 69.
> > >
> > > Apparently this isn't reproducing now, but a full bootstrap is not
> > > reproducible due to fallout from Jan's patch.
> >
> > Did you compile with "-O1"? That's the only optimization level where
> > the problem occurs.
>
> Actually, it was your comment that I was basing this on - perhaps I
> misunderstood you. :)
>
> I'll just wait for your patch and then try again.
I have installed a patch to fix the bootstrap failure resulting from
Jan's patch. I now see the following assembler warning:
stage1/xgcc -Bstage1/ -B/opt/gnu64/hppa64-hp-hpux11.00/bin/ -c -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -pedantic -Wno-long-long -Werror -fno-common -DHAVE_CONFIG_H -I. -I. -I../../gcc/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include \
../../gcc/gcc/c-opts.c -o c-opts.o
/var/tmp//ccAEh2VX.s: Assembler messages:
/var/tmp//ccAEh2VX.s:592: Warning: .space repeat count is zero, ignored
/var/tmp//ccAEh2VX.s:598: Warning: .space repeat count is zero, ignored
...
I believe that this has been reported on other ports as well.
I misunderstood your comment. The "-O1" optimization comment was with
respect to the testsuite failure and not the current bootstrap problems.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] allow zero_extract combines - checked in
2003-05-12 17:59 ` John David Anglin
@ 2003-05-12 18:03 ` Eric Christopher
0 siblings, 0 replies; 521+ messages in thread
From: Eric Christopher @ 2003-05-12 18:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> I believe that this has been reported on other ports as well.
>
Yup :)
> I misunderstood your comment. The "-O1" optimization comment was with
> respect to the testsuite failure and not the current bootstrap problems.
Aaah. I was reading your mail wrong. *sigh* Thanks.
-eric
--
Eric Christopher <echristo@redhat.com>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: speedup collect2 (by not using it)
[not found] <no.id>
` (112 preceding siblings ...)
2003-05-10 2:15 ` [PATCH] allow zero_extract combines - checked in John David Anglin
@ 2003-05-23 1:17 ` John David Anglin
2003-06-19 22:29 ` [PATCH] Fix PCH failures on SPARC John David Anglin
` (49 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-05-23 1:17 UTC (permalink / raw)
To: John David Anglin; +Cc: mrs, austern, gcc-patches, law
> I think you need to add:
>
> ! else
> ! s = find_a_file (&exec_prefixes, "ld", X_OK, 0);
No, gcc is running the correct linker:
# stage1/xgcc -Bstage1/ -B/opt/gnu64/hppa64-hp-hpux11.11/bin/ -g -O2 -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -pedantic -Wno-long-long -Werror -fno-common -DHAVE_CONFIG_H -DGENERATOR_FILE -o gengtype.x gengtype.o gengtype-lex.o gengtype-yacc.o ../libiberty/libiberty.a -v
Reading specs from stage1/specs
Configured with: ../gcc/configure --with-gnu-as --with-as=/opt/gnu64/bin/as --with-ld=/usr/ccs/bin/ld --enable-shared --disable-nls --with-local-prefix=/opt/gnu64 --prefix=/opt/gnu64 --host=hppa64-hp-hpux11.11 : (reconfigured) ../gcc/configure --with-gnu-as --with-as=/opt/gnu64/bin/as --with-ld=/usr/ccs/bin/ld --enable-shared --disable-nls --with-local-prefix=/opt/gnu64 --prefix=/opt/gnu64 --host=hppa64-hp-hpux11.11
Thread model: single
gcc version 3.4 20030523 (experimental)
/usr/ccs/bin/ld +Accept TypeMismatch -E -u main -o gengtype.x /usr/ccs/lib/pa20_64/crt0.o stage1/crtbegin.o -Lstage1 -L/opt/gnu64/hppa64-hp-hpux11.11/bin -L/opt/gnu64/lib/gcc-lib/hppa64-hp-hpux11.11/../../../hppa64-hp-hpux11.11/lib -L/usr/ccs/bin -L/usr/ccs/lib/pa20_64 -L/opt/langtools/lib/pa20_64 -L/opt/gnu64/lib/gcc-lib/hppa64-hp-hpux11.11/../.. gengtype.o gengtype-lex.o gengtype-yacc.o ../libiberty/libiberty.a -lgcc -lc /usr/lib/pa20_64/milli.a -lgcc stage1/crtend.o
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix PCH failures on SPARC
[not found] <no.id>
` (113 preceding siblings ...)
2003-05-23 1:17 ` speedup collect2 (by not using it) John David Anglin
@ 2003-06-19 22:29 ` John David Anglin
2003-06-20 19:12 ` Hookize CFG debugging code John David Anglin
` (48 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-06-19 22:29 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, ebotcazou
> I believe that the patch needs to strip the encoding from the function
> string. That's where the `*' comes from.
The following patch fixes the problem. I will install after a full
bootstrap and check completes.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2003-06-19 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* som.h (ASM_OUTPUT_SOURCE_LINE): Use targetm.strip_name_encoding to
strip name encoding.
Index: config/pa/som.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/pa/som.h,v
retrieving revision 1.42
diff -u -3 -p -r1.42 som.h
--- config/pa/som.h 17 Jun 2003 08:06:57 -0000 1.42
+++ config/pa/som.h 19 Jun 2003 21:40:16 -0000
@@ -30,16 +30,20 @@ Boston, MA 02111-1307, USA. */
/* We make the first line stab special to avoid adding several
gross hacks to GAS. */
#undef ASM_OUTPUT_SOURCE_LINE
-#define ASM_OUTPUT_SOURCE_LINE(file, line, counter) \
- { static tree last_function_decl = NULL; \
- if (current_function_decl == last_function_decl) \
- fprintf (file, "\t.stabn 68,0,%d,L$M%d-%s\nL$M%d:\n", \
- line, counter, \
- XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0) + 1, \
- counter); \
- else \
- fprintf (file, "\t.stabn 68,0,%d,0\n", line); \
- last_function_decl = current_function_decl; \
+#define ASM_OUTPUT_SOURCE_LINE(file, line, counter) \
+ { static tree last_function_decl = NULL; \
+ if (current_function_decl == last_function_decl) \
+ { \
+ rtx func = DECL_RTL (current_function_decl); \
+ const char *name = XSTR (XEXP (func, 0), 0); \
+ fprintf (file, "\t.stabn 68,0,%d,L$M%d-%s\nL$M%d:\n", \
+ line, counter, \
+ (* targetm.strip_name_encoding) (name), \
+ counter); \
+ } \
+ else \
+ fprintf (file, "\t.stabn 68,0,%d,0\n", line); \
+ last_function_decl = current_function_decl; \
}
/* gdb needs a null N_SO at the end of each file for scattered loading. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Hookize CFG debugging code
[not found] <no.id>
` (114 preceding siblings ...)
2003-06-19 22:29 ` [PATCH] Fix PCH failures on SPARC John David Anglin
@ 2003-06-20 19:12 ` John David Anglin
2003-06-20 19:35 ` Jan Hubicka
2003-06-20 20:47 ` [PATCH]: Fix label replacement in REG_NOTES John David Anglin
` (47 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-06-20 19:12 UTC (permalink / raw)
To: John David Anglin; +Cc: jh, gcc-patches, rth
> Yes, the warnings are no longer generated by the test. I'll let you know
> the result of the bootstrap and check when it completes.
stage1/xgcc -Bstage1/ -B/opt/gnu/hppa2.0w-hp-hpux11.00/bin/ -c -O2 -g -fPIC -D
IN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -peda
ntic -Wno-long-long -Werror -fno-common -DHAVE_CONFIG_H -I. -I. -I../../gcc
/gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include ../../g
cc/gcc/cfgrtl.c -o cfgrtl.o
../../gcc/gcc/cfgrtl.c: In function `rtl_verify_flow_info_1':
../../gcc/gcc/cfgrtl.c:1768: warning: `fallthru' might be used uninitialized in
this function
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Hookize CFG debugging code
2003-06-20 19:12 ` Hookize CFG debugging code John David Anglin
@ 2003-06-20 19:35 ` Jan Hubicka
0 siblings, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2003-06-20 19:35 UTC (permalink / raw)
To: John David Anglin; +Cc: jh, gcc-patches, rth
> > Yes, the warnings are no longer generated by the test. I'll let you know
> > the result of the bootstrap and check when it completes.
>
> stage1/xgcc -Bstage1/ -B/opt/gnu/hppa2.0w-hp-hpux11.00/bin/ -c -O2 -g -fPIC -D
> IN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -peda
> ntic -Wno-long-long -Werror -fno-common -DHAVE_CONFIG_H -I. -I. -I../../gcc
> /gcc -I../../gcc/gcc/. -I../../gcc/gcc/config -I../../gcc/gcc/../include ../../g
> cc/gcc/cfgrtl.c -o cfgrtl.o
> ../../gcc/gcc/cfgrtl.c: In function `rtl_verify_flow_info_1':
> ../../gcc/gcc/cfgrtl.c:1768: warning: `fallthru' might be used uninitialized in
> this function
Urgh. Please just add the zero initializer (when it is used it is
initialized so the warning is harmless). Sorry for that.
Honza
>
> Dave
> --
> J. David Anglin dave.anglin@nrc-cnrc.gc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH]: Fix label replacement in REG_NOTES
[not found] <no.id>
` (115 preceding siblings ...)
2003-06-20 19:12 ` Hookize CFG debugging code John David Anglin
@ 2003-06-20 20:47 ` John David Anglin
2003-07-03 20:17 ` Bootstrap failure compiling ada/misc.c John David Anglin
` (46 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-06-20 20:47 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, roger
This patches fixes the bootstrap failure reported in this message:
<http://gcc.gnu.org/ml/gcc-patches/2003-05/msg01841.html>.
The bootstrap failure occurs because of the presence of the following
instruction in a loop:
(jump_insn 66 65 70 4 0x40978750 (set (pc)
(if_then_else (ne (reg:SI 105)
(reg:SI 131))
(label_ref 80)
(pc))) 25 {*pa.md:1674} (nil)
(expr_list:REG_EQUAL (if_then_else (ne (reg:SI 105)
(const_int 112 [0x70]))
(label_ref 80)
(pc))
(nil)))
The target of this conditional branch gets redirected to a new code_label.
However, the presence of a REG_EQUAL note causes the LABEL_NUSES count to
be incremented once too may times for the new label and decremented once
too many times for the old label. This occurs in load_mems.
The enclosed patch fixes this by not updating LABEL_NUSES for label
references in REG_NOTES. The semantics of label references is that
they don't contribute to the usage count. This allows register notes
to be removed without having to worry about updating the the usage
counts.
Tested on hppa-unknown-linux-gnu and hppa2.0w-hp-hpux11.11 with no
regressions.
Ok for main?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2003-06-20 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* cfgcleanup.c (outgoing_edges_match, try_crossjump_to_edge): Use
replace_labels.
* loop.c (load_mems): Likewise.
* rtl.h (replace_label): Delete declaration.
(replace_labels): Add declaration.
* rtlanal.c (replace_label): Make static.
(replace_labels): New function.
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.84
diff -u -3 -p -r1.84 cfgcleanup.c
--- cfgcleanup.c 6 Jun 2003 09:24:23 -0000 1.84
+++ cfgcleanup.c 20 Jun 2003 13:48:55 -0000
@@ -1310,7 +1310,7 @@ outgoing_edges_match (mode, bb1, bb2)
rr.r1 = label1;
rr.r2 = label2;
rr.update_label_nuses = false;
- for_each_rtx (&bb1->end, replace_label, &rr);
+ replace_labels (bb1->end, &rr);
match = insns_match_p (mode, bb1->end, bb2->end);
if (rtl_dump_file && match)
@@ -1323,7 +1323,7 @@ outgoing_edges_match (mode, bb1, bb2)
from the instruction is deleted too. */
rr.r1 = label2;
rr.r2 = label1;
- for_each_rtx (&bb1->end, replace_label, &rr);
+ replace_labels (bb1->end, &rr);
return match;
}
@@ -1474,7 +1474,7 @@ try_crossjump_to_edge (mode, e1, e2)
a block whose end is a tablejump, the tablejump referenced
from the instruction is deleted too. */
if (insn != src1->end)
- for_each_rtx (&insn, replace_label, &rr);
+ replace_labels (insn, &rr);
}
}
}
Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.459
diff -u -3 -p -r1.459 loop.c
--- loop.c 16 Jun 2003 21:41:05 -0000 1.459
+++ loop.c 20 Jun 2003 13:49:57 -0000
@@ -10194,7 +10194,7 @@ load_mems (loop)
for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
{
- for_each_rtx (&p, replace_label, &rr);
+ replace_labels (p, &rr);
}
}
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.418
diff -u -3 -p -r1.418 rtl.h
--- rtl.h 19 Jun 2003 12:25:35 -0000 1.418
+++ rtl.h 20 Jun 2003 13:50:07 -0000
@@ -1721,7 +1721,7 @@ extern int inequality_comparisons_p PARA
extern rtx replace_rtx PARAMS ((rtx, rtx, rtx));
extern rtx replace_regs PARAMS ((rtx, rtx *, unsigned int,
int));
-extern int replace_label PARAMS ((rtx *, void *));
+extern void replace_labels PARAMS ((rtx, replace_label_data *));
extern int rtx_referenced_p PARAMS ((rtx, rtx));
extern bool tablejump_p PARAMS ((rtx, rtx *, rtx *));
extern int computed_jump_p PARAMS ((rtx));
Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtlanal.c,v
retrieving revision 1.158
diff -u -3 -p -r1.158 rtlanal.c
--- rtlanal.c 13 Jun 2003 05:30:33 -0000 1.158
+++ rtlanal.c 20 Jun 2003 13:50:12 -0000
@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - S
static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
static void set_of_1 PARAMS ((rtx, rtx, void *));
static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int replace_label PARAMS ((rtx *, void *));
static int rtx_referenced_p_1 PARAMS ((rtx *, void *));
static int computed_jump_p_1 PARAMS ((rtx));
static void parms_set PARAMS ((rtx, rtx, void *));
@@ -2792,10 +2793,38 @@ replace_regs (x, reg_map, nregs, replace
return x;
}
+/* Replace all occurrences of the old label in INSN with the new one.
+ DATA points to the replacement label data for the old and new labels. */
+
+void
+replace_labels (insn, data)
+ rtx insn;
+ replace_label_data *data;
+{
+ /* Labels in REG_NOTES are not recorded in LABEL_NUSES. */
+ if (data->update_label_nuses && INSN_P (insn))
+ {
+ rtx note = REG_NOTES (insn);
+
+ if (note)
+ {
+ REG_NOTES (insn) = NULL_RTX;
+ data->update_label_nuses = false;
+ for_each_rtx (¬e, replace_label, data);
+ data->update_label_nuses = true;
+ for_each_rtx (&insn, replace_label, data);
+ REG_NOTES (insn) = note;
+ return;
+ }
+ }
+
+ for_each_rtx (&insn, replace_label, data);
+}
+
/* Replace occurrences of the old label in *X with the new one.
DATA is a REPLACE_LABEL_DATA containing the old and new labels. */
-int
+static int
replace_label (x, data)
rtx *x;
void *data;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Bootstrap failure compiling ada/misc.c
[not found] <no.id>
` (116 preceding siblings ...)
2003-06-20 20:47 ` [PATCH]: Fix label replacement in REG_NOTES John David Anglin
@ 2003-07-03 20:17 ` John David Anglin
2003-07-04 17:54 ` [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA John David Anglin
` (45 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-07-03 20:17 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, neil, kraai
> Neil has committed a patch that makes gnat_argv const. I don't
> think this will work, because it produced warnings during the
> first stage of the bootstrap
>
> gcc -c -g -DIN_GCC -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -fno-common -DHAVE_CONFIG_H -I. -Iada -I../../gcc/gcc -I../../gcc/gcc/ada -I../../gcc/gcc/config -I../../gcc/gcc/../include ../../gcc/gcc/ada/misc.c -o ada/misc.o
> ../../gcc/gcc/ada/misc.c: In function `gnat_handle_option':
> ../../gcc/gcc/ada/misc.c:262: warning: assignment of read-only location
> ../../gcc/gcc/ada/misc.c:263: warning: passing arg 1 of `strcpy' discards qualifiers from pointer target type
> ../../gcc/gcc/ada/misc.c: In function `gnat_init_options':
> ../../gcc/gcc/ada/misc.c:288: warning: assignment from incompatible pointer type
>
> but I didn't let the bootstrap proceed far enough to be sure.
It causes a failure.
> Matt Kraai kraai@alumni.cmu.edu Debian GNU/Linux
>
> * misc.c (gnat_handle_option, gnat_init_options): Copy
> arguments.
Can't approve but this worked for me.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA
[not found] <no.id>
` (117 preceding siblings ...)
2003-07-03 20:17 ` Bootstrap failure compiling ada/misc.c John David Anglin
@ 2003-07-04 17:54 ` John David Anglin
2003-07-04 18:16 ` Tom Tromey
2003-07-04 20:24 ` Unreviewed fix for bootstrap failure John David Anglin
` (44 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2003-07-04 17:54 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, roger, hans_boehm, tromey
> What goes wrong building libgcj on hpux? Nobody has ever tried it, as
> far as I know, but it might not be too hard to make it work,
> especially if the GC is working.
I haven't tried hpux but Randolph Chung has a preliminary implementation
of libffi for hppa-linux. Once this is working, it shouldn't be hard
to extend this to hpux. With the libffi implementation, libgcj built
without any problems. There were quite a few failures in the java
testsuite. These might be related to the libffi implementation.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA
2003-07-04 17:54 ` [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA John David Anglin
@ 2003-07-04 18:16 ` Tom Tromey
2003-07-04 18:37 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Tom Tromey @ 2003-07-04 18:16 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, roger, hans_boehm
>>>>> "John" == John David Anglin <dave@hiauly1.hia.nrc.ca> writes:
>> What goes wrong building libgcj on hpux? Nobody has ever tried it, as
>> far as I know, but it might not be too hard to make it work,
>> especially if the GC is working.
John> I haven't tried hpux but Randolph Chung has a preliminary
John> implementation of libffi for hppa-linux. Once this is working,
John> it shouldn't be hard to extend this to hpux. With the libffi
John> implementation, libgcj built without any problems. There were
John> quite a few failures in the java testsuite. These might be
John> related to the libffi implementation.
Quite possible. Did he implement the closure API? That is needed for
the interpreter to work. The other ("normal") API is needed for
reflection.
We should probably set up the test suite to xfail tests when we know
the interpreter won't work.
Tom
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA
2003-07-04 18:16 ` Tom Tromey
@ 2003-07-04 18:37 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-07-04 18:37 UTC (permalink / raw)
To: tromey; +Cc: gcc-patches, roger, hans_boehm
> Quite possible. Did he implement the closure API? That is needed for
Yes, it looks like he implemented the closure API. At my last test,
the were some issues with small structs.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Unreviewed fix for bootstrap failure
[not found] <no.id>
` (118 preceding siblings ...)
2003-07-04 17:54 ` [Boehm-GC] Limit +ESdbgasm to HPUX cc on PA John David Anglin
@ 2003-07-04 20:24 ` John David Anglin
2003-10-06 16:53 ` [PATCH] Bootstrap failure due to reload bug Ulrich Weigand
` (43 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-07-04 20:24 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, rth, gcc-patches
> If you have an indirect jump, you must ensure that all the labels that
> might be used as targets don't get accidentally deleted. LABEL_REFs in
If you want to see how this currently works, look at the rtl generated
for the small program included in this message:
http://gcc.gnu.org/ml/gcc/2003-07/msg00241.html
The label usage counts for label1 and label2 don't include references
that occur in REG_NOTES.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Bootstrap failure due to reload bug
[not found] <no.id>
` (119 preceding siblings ...)
2003-07-04 20:24 ` Unreviewed fix for bootstrap failure John David Anglin
@ 2003-10-06 16:53 ` Ulrich Weigand
2003-11-01 23:48 ` [PATCH] Fix AMD64 handling of functions with huge stack frames (take 2) John David Anglin
` (42 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: Ulrich Weigand @ 2003-10-06 16:53 UTC (permalink / raw)
To: gcc-patches; +Cc: mark, dje
I wrote:
> * reload.c (find_reloads_subreg_address): Use correct offset for
> paradoxical MEM subregs on big-endian targets.
I've now committed the following variant of the patch,
approved in private mail by Mark Mitchell:
Index: gcc/reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.220
diff -c -p -r1.220 reload.c
*** gcc/reload.c 19 Jul 2003 14:47:13 -0000 1.220
--- gcc/reload.c 6 Oct 2003 13:56:47 -0000
*************** find_reloads_subreg_address (rtx x, int
*** 5806,5814 ****
if (force_replace
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
- int offset = SUBREG_BYTE (x);
unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
--- 5806,5821 ----
if (force_replace
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+ int offset;
+
+ /* For big-endian paradoxical subregs, SUBREG_BYTE does not
+ hold the correct (negative) byte offset. */
+ if (BYTES_BIG_ENDIAN && outer_size > inner_size)
+ offset = inner_size - outer_size;
+ else
+ offset = SUBREG_BYTE (x);
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix AMD64 handling of functions with huge stack frames (take 2)
[not found] <no.id>
` (120 preceding siblings ...)
2003-10-06 16:53 ` [PATCH] Bootstrap failure due to reload bug Ulrich Weigand
@ 2003-11-01 23:48 ` John David Anglin
2004-01-22 21:43 ` [PATCH] Optimize subregs of zero and sign extensions " John David Anglin
` (41 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2003-11-01 23:48 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jakub
> The patch is failing on hppa64-hp-hpux11.11 due to some wierd reload errors.
> The symbol_ref that causes the ultimate ICE first appears in the reloads
> for insn 23.
>
> /xxx/gnu/gcc-3.3/gcc/gcc/testsuite/gcc.c-torture/compile/20031023-1.c:54: error:
> unrecognizable insn:
> (insn 88 86 89 1 (set (reg:DI %r21)
> (mem/u/f:DI (symbol_ref/u:DI ("*L$C0002") [flags 0x2]) [0 S8 A64])) -1 (nil)
> (nil))
Thinking more, it would appear that LEGITIMIZE_ADDRESS (i.e.,
legitimize_pic_address) isn't getting called for some reason.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Optimize subregs of zero and sign extensions (take 2)
[not found] <no.id>
` (121 preceding siblings ...)
2003-11-01 23:48 ` [PATCH] Fix AMD64 handling of functions with huge stack frames (take 2) John David Anglin
@ 2004-01-22 21:43 ` John David Anglin
2004-02-28 5:22 ` [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests John David Anglin
` (40 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-01-22 21:43 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, roger
> cmpb,= %r19,%r5,L$0003 ; so we end up comparing zero extended
> ; value of mem with sign extended
> ; (promoted) value
The compare is a SImode compare, so it does the right thing. However,
I still suspect that it's this zero extend/sign extend issue that causing
the test to fail.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests
[not found] <no.id>
` (122 preceding siblings ...)
2004-01-22 21:43 ` [PATCH] Optimize subregs of zero and sign extensions " John David Anglin
@ 2004-02-28 5:22 ` John David Anglin
2004-02-28 18:12 ` Geoff Keating
2004-04-16 22:12 ` [committed 3.5] Tweak xfail for gcc.dg/const-elim-1.c John David Anglin
` (39 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-02-28 5:22 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, aldyh
> > 2004-02-27 Aldy Hernandez <aldyh@redhat.com>
> >
> > * lib/g++.exp (g++_link_flags): Append LD_LIBRARY_PATH to
> > ld_library_path.
I updated my patch since Aldy's patch has been installed. Tested
on hppa-unknown-linux-gnu. Based on lib/libstdc++.exp.
Ok for main?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-02-27 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* lib/g++.exp, lib/g77.exp, lib/objc.exp (LD_LIBRARY_PATH, SHLIB_PATH,
DYLD_LIBRARY_PATH, LD_LIBRARYN32_PATH, LD_LIBRARY64_PATH,
LD_LIBRARY_PATH_32, LD_LIBRARY_PATH_64): Append original library path
to new environment library path.
Index: lib/g++.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/g++.exp,v
retrieving revision 1.37
diff -u -3 -p -r1.37 g++.exp
--- lib/g++.exp 27 Feb 2004 22:05:51 -0000 1.37
+++ lib/g++.exp 28 Feb 2004 02:58:25 -0000
@@ -166,6 +166,25 @@ proc g++_link_flags { paths } {
}
}
+ # Find the existing LD_LIBRARY_PATH.
+ if [info exists env(LD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH)
+ # For HP-UX
+ } elseif [info exists env(SHLIB_PATH)] {
+ set original_ld_library_path $env(SHLIB_PATH)
+ # For Darwin:
+ } elseif [info exists env(DYLD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(DYLD_LIBRARY_PATH)
+ # For Solaris 32 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_32)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_32)
+ # For Solaris 64 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_64)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_64)
+ } else {
+ set original_ld_library_path ""
+ }
+
# On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but
# called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH
# (for the 64-bit ABI). The right way to do this would be to modify
@@ -176,17 +195,13 @@ proc g++_link_flags { paths } {
# (SHLIB_PATH).
# Doing this does cause trouble when testing cross-compilers.
if {![is_remote target]} {
- global env;
- if { $env(LD_LIBRARY_PATH) != "" } {
- append ld_library_path ":$env(LD_LIBRARY_PATH)";
- }
- setenv LD_LIBRARY_PATH $ld_library_path
- setenv SHLIB_PATH $ld_library_path
- setenv LD_LIBRARYN32_PATH $ld_library_path
- setenv LD_LIBRARY64_PATH $ld_library_path
- setenv LD_LIBRARY_PATH_32 $ld_library_path
- setenv LD_LIBRARY_PATH_64 $ld_library_path
- setenv DYLD_LIBRARY_PATH $ld_library_path
+ setenv LD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
+ setenv SHLIB_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARYN32_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY64_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_32 "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_64 "$ld_library_path:$original_ld_library_path"
+ setenv DYLD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
}
return "$flags"
Index: lib/g77.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/g77.exp,v
retrieving revision 1.18
diff -u -3 -p -r1.18 g77.exp
--- lib/g77.exp 23 Jan 2004 04:42:39 -0000 1.18
+++ lib/g77.exp 28 Feb 2004 02:58:25 -0000
@@ -110,6 +110,25 @@ proc g77_link_flags { paths } {
}
}
+ # Find the existing LD_LIBRARY_PATH.
+ if [info exists env(LD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH)
+ # For HP-UX
+ } elseif [info exists env(SHLIB_PATH)] {
+ set original_ld_library_path $env(SHLIB_PATH)
+ # For Darwin:
+ } elseif [info exists env(DYLD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(DYLD_LIBRARY_PATH)
+ # For Solaris 32 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_32)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_32)
+ # For Solaris 64 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_64)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_64)
+ } else {
+ set original_ld_library_path ""
+ }
+
# On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but
# called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH
# (for the 64-bit ABI). The right way to do this would be to modify
@@ -118,13 +137,13 @@ proc g77_link_flags { paths } {
# The same applies to Darwin (DYLD_LIBRARY_PATH), Solaris 32 bit
# (LD_LIBRARY_PATH_32), Solaris 64 bit (LD_LIBRARY_PATH_64), and HP-UX
# (SHLIB_PATH).
- setenv LD_LIBRARY_PATH $ld_library_path
- setenv SHLIB_PATH $ld_library_path
- setenv LD_LIBRARYN32_PATH $ld_library_path
- setenv LD_LIBRARY64_PATH $ld_library_path
- setenv LD_LIBRARY_PATH_32 $ld_library_path
- setenv LD_LIBRARY_PATH_64 $ld_library_path
- setenv DYLD_LIBRARY_PATH $ld_library_path
+ setenv LD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
+ setenv SHLIB_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARYN32_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY64_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_32 "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_64 "$ld_library_path:$original_ld_library_path"
+ setenv DYLD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
return "$flags"
}
Index: lib/objc.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/objc.exp,v
retrieving revision 1.21
diff -u -3 -p -r1.21 objc.exp
--- lib/objc.exp 23 Jan 2004 04:42:39 -0000 1.21
+++ lib/objc.exp 28 Feb 2004 02:58:25 -0000
@@ -184,6 +184,25 @@ proc objc_target_compile { source dest t
}
lappend options "compiler=$OBJC_UNDER_TEST"
+ # Find the existing LD_LIBRARY_PATH.
+ if [info exists env(LD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH)
+ # For HP-UX
+ } elseif [info exists env(SHLIB_PATH)] {
+ set original_ld_library_path $env(SHLIB_PATH)
+ # For Darwin:
+ } elseif [info exists env(DYLD_LIBRARY_PATH)] {
+ set original_ld_library_path $env(DYLD_LIBRARY_PATH)
+ # For Solaris 32 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_32)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_32)
+ # For Solaris 64 bit:
+ } elseif [info exists env(LD_LIBRARY_PATH_64)] {
+ set original_ld_library_path $env(LD_LIBRARY_PATH_64)
+ } else {
+ set original_ld_library_path ""
+ }
+
# On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but
# called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH
# (for the 64-bit ABI). The right way to do this would be to modify
@@ -192,13 +211,13 @@ proc objc_target_compile { source dest t
# The same applies to Darwin (DYLD_LIBRARY_PATH), Solaris 32 bit
# (LD_LIBRARY_PATH_32), Solaris 64 bit (LD_LIBRARY_PATH_64), and HP-UX
# (SHLIB_PATH).
- setenv LD_LIBRARY_PATH $ld_library_path
- setenv SHLIB_PATH $ld_library_path
- setenv LD_LIBRARYN32_PATH $ld_library_path
- setenv LD_LIBRARY64_PATH $ld_library_path
- setenv LD_LIBRARY_PATH_32 $ld_library_path
- setenv LD_LIBRARY_PATH_64 $ld_library_path
- setenv DYLD_LIBRARY_PATH $ld_library_path
+ setenv LD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
+ setenv SHLIB_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARYN32_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY64_PATH "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_32 "$ld_library_path:$original_ld_library_path"
+ setenv LD_LIBRARY_PATH_64 "$ld_library_path:$original_ld_library_path"
+ setenv DYLD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
return [target_compile $source $dest $type $options]
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests
2004-02-28 5:22 ` [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests John David Anglin
@ 2004-02-28 18:12 ` Geoff Keating
2004-02-28 18:30 ` Eric Botcazou
0 siblings, 1 reply; 521+ messages in thread
From: Geoff Keating @ 2004-02-28 18:12 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, aldyh
"John David Anglin" <dave@hiauly1.hia.nrc.ca> writes:
> + # For Solaris 32 bit:
> + } elseif [info exists env(LD_LIBRARY_PATH_32)] {
> + set original_ld_library_path $env(LD_LIBRARY_PATH_32)
> + # For Solaris 64 bit:
> + } elseif [info exists env(LD_LIBRARY_PATH_64)] {
> + set original_ld_library_path $env(LD_LIBRARY_PATH_64)
> + } else {
> + set original_ld_library_path ""
> + }
I'm fairly sure this logic here is not right. Solaris 32 bit and 64
bit coexist on the same system, don't they?
--
- Geoffrey Keating <geoffk@geoffk.org>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests
2004-02-28 18:12 ` Geoff Keating
@ 2004-02-28 18:30 ` Eric Botcazou
0 siblings, 0 replies; 521+ messages in thread
From: Eric Botcazou @ 2004-02-28 18:30 UTC (permalink / raw)
To: Geoff Keating; +Cc: John David Anglin, gcc-patches, aldyh
> I'm fairly sure this logic here is not right. Solaris 32 bit and 64
> bit coexist on the same system, don't they?
Yes, they do. LD_LIBRARY_PATH_32 will preempt any setting of
LD_LIBRARY_PATH for 32-bit executables and LD_LIBRARY_PATH_64 will preempt
any setting of LD_LIBRARY_PATH for 64-bit executables. So both may be
set.
--
Eric Botcazou
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed 3.5] Tweak xfail for gcc.dg/const-elim-1.c
[not found] <no.id>
` (123 preceding siblings ...)
2004-02-28 5:22 ` [patch] do not disregard LD_LIBRARY_PATH for c++, g77 and objc tests John David Anglin
@ 2004-04-16 22:12 ` John David Anglin
2004-04-17 19:09 ` Mark Mitchell
2004-04-18 22:01 ` [patch 3.3/3.4/3.5] Fix PR bootstrap/14671 John David Anglin
` (38 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-16 22:12 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, zack, mark
Mark,
> 2004-04-16 John David Anglin <dava.anglin@nrc-cnrc.gc.ca>
>
> * const-elim-1.c: xfail hppa-*-*.
This is a small tweak to what Zack installed today. `hppa' is valid
as a 32-bit cpu config option.
Is this ok for 3.4?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed 3.5] Tweak xfail for gcc.dg/const-elim-1.c
2004-04-16 22:12 ` [committed 3.5] Tweak xfail for gcc.dg/const-elim-1.c John David Anglin
@ 2004-04-17 19:09 ` Mark Mitchell
0 siblings, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2004-04-17 19:09 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, zack
John David Anglin wrote:
>Mark,
>
>
>
>>2004-04-16 John David Anglin <dava.anglin@nrc-cnrc.gc.ca>
>>
>> * const-elim-1.c: xfail hppa-*-*.
>>
>>
>
>This is a small tweak to what Zack installed today. `hppa' is valid
>as a 32-bit cpu config option.
>
>Is this ok for 3.4?
>
Yes, but the ChangeLog entry is incorrect. It should be
gcc.dg/const-elim-1.c; you're missing the "gcc.dg/".
Thanks,
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
[not found] <no.id>
` (124 preceding siblings ...)
2004-04-16 22:12 ` [committed 3.5] Tweak xfail for gcc.dg/const-elim-1.c John David Anglin
@ 2004-04-18 22:01 ` John David Anglin
2004-04-18 22:51 ` Mark Mitchell
2004-04-19 3:24 ` John David Anglin
` (37 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-18 22:01 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, gdr
> (gdb) p debug_rtx (reg_known_value[294])
> (plus:DI (reg/f:DI 3 %r3)
> (const_int 272 [0x110]))
> (gdb) p reg_known_value[294]
> $3 = 0x800003fffe830600
I probably should add the above rtx is created as follows:
(gdb) bt
#0 0x4000000000299c10 in rtx_alloc_stat (.)
at ../../gcc/gcc/rtl.c:195
#1 0x4000000000299cb0 in copy_rtx ()
at ../../gcc/gcc/rtl.c:250
#2 0x40000000001a67ac in fixup_var_refs_1 ()
at ../../gcc/gcc/function.c:1862
#3 0x40000000001a664c in fixup_var_refs_1 ()
at ../../gcc/gcc/function.c:2459
#4 0x40000000001a7614 in fixup_var_refs_insn ()
at ../../gcc/gcc/function.c:1766
#5 0x40000000001a7c2c in fixup_var_refs ()
at ../../gcc/gcc/function.c:1649
#6 0x40000000001a7f24 in schedule_fixup_var_refs ()
at ../../gcc/gcc/function.c:1500
#7 0x40000000001a8118 in put_reg_into_stack ()
at ../../gcc/gcc/function.c:1474
#8 0x40000000001a8f90 in put_addressof_into_stack ()
at ../../gcc/gcc/function.c:2939
#9 0x40000000001a97d4 in purge_addressof_1 ()
at ../../gcc/gcc/function.c:3001
#10 0x40000000001a99d0 in purge_addressof_1 ()
at ../../gcc/gcc/function.c:3270
#11 0x40000000001a9a44 in purge_addressof_1 ()
at ../../gcc/gcc/function.c:2990
#12 0x40000000001aa108 in purge_addressof ()
at ../../gcc/gcc/function.c:3410
#13 0x4000000000303e5c in rest_of_compilation ()
at ../../gcc/gcc/passes.c:971
...
Just thinking that possibly the rtx isn't being correcly associated with
a hash table so that ggc_mark_roots will mark it.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-18 22:01 ` [patch 3.3/3.4/3.5] Fix PR bootstrap/14671 John David Anglin
@ 2004-04-18 22:51 ` Mark Mitchell
2004-04-18 23:04 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2004-04-18 22:51 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gdr
John David Anglin wrote:
>>(gdb) p debug_rtx (reg_known_value[294])
>>(plus:DI (reg/f:DI 3 %r3)
>> (const_int 272 [0x110]))
>>(gdb) p reg_known_value[294]
>>$3 = 0x800003fffe830600
>>
>>
>
>I probably should add the above rtx is created as follows:
>
>(gdb) bt
>#0 0x4000000000299c10 in rtx_alloc_stat (.)
> at ../../gcc/gcc/rtl.c:195
>#1 0x4000000000299cb0 in copy_rtx ()
> at ../../gcc/gcc/rtl.c:250
>#2 0x40000000001a67ac in fixup_var_refs_1 ()
> at ../../gcc/gcc/function.c:1862
>
RTL generated there should be added into the instruction chain, and
therefore reachable in other ways. So, I still think there's not enough
information here to know for sure that your patch is correct, and not
merely masking some other symptom.
Thanks,
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-18 22:51 ` Mark Mitchell
@ 2004-04-18 23:04 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-18 23:04 UTC (permalink / raw)
To: Mark Mitchell; +Cc: gcc-patches, gdr
> RTL generated there should be added into the instruction chain, and
> therefore reachable in other ways. So, I still think there's not enough
> information here to know for sure that your patch is correct, and not
> merely masking some other symptom.
This suggests that Zdenek's patch on March 18 results in the instructions
which use this RTX being removed from the instruction chain but for
some reason we are still using reg_known_value[294]. I'll try to look
into this.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
[not found] <no.id>
` (125 preceding siblings ...)
2004-04-18 22:01 ` [patch 3.3/3.4/3.5] Fix PR bootstrap/14671 John David Anglin
@ 2004-04-19 3:24 ` John David Anglin
2004-04-19 3:27 ` Mark Mitchell
2004-04-19 5:30 ` Zdenek Dvorak
2004-04-21 19:23 ` [committed 3.5] Fix DBX register numbering for hppa64 John David Anglin
` (36 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-19 3:24 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, gdr, rakdver
> This suggests that Zdenek's patch on March 18 results in the instructions
> which use this RTX being removed from the instruction chain but for
> some reason we are still using reg_known_value[294]. I'll try to look
> into this.
This appears to be what's happening. After gcse, we have:
(insn 529 527 530 43 ../../gcc/gcc/caller-save.c:713 (set (reg/v/f:DI 294 [ to_save ])
(plus:DI (reg/f:DI 3 %r3)
(const_int 272 [0x110]))) 158 {*pa.md:4807} (nil)
(nil))
Loop changes this to:
(insn 1435 1434 1437 (set (reg/f:DI 576)
(plus:DI (reg/f:DI 3 %r3)
(const_int 272 [0x110]))) -1 (nil)
(nil))
...
(insn 1436 511 1438 (set (reg/f:DI 491)
(reg/f:DI 576)) -1 (nil)
(nil))
...
(insn 1298 1024 533 (set (reg/v/f:DI 294 [ to_save ])
(reg/f:DI 491)) -1 (nil)
(nil))
So, we still have reg/v/f:DI 294 but the rtx is reg_known_value[294]
has been orphaned. ggc_collect poisons the rtx. Then, the next time
scan_loop is called we have a problem with the value for reg 294.
Maybe my patch is the best solution. However, I think Zdenek should
look at this. The problem may have been introduced with this change:
2004-03-18 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* doloop.c: Removed.
* loop-doloop.c: New file.
* Makefile.in (doloop.o): Remove.
(loop-doloop.o): New.
* cfgloop.h (get_loop_level, doloop_optimize_loops): Declare.
* cfgloopanal.c (get_loop_level): New function.
* loop-iv.c (iv_number_of_iterations): Handle case when loop
is leaved immediatelly.
* loop.c (strength_reduce): Do not call doloop optimization.
* loop.h (LOOP_BCT): Removed.
* passes.c (rest_of_handle_loop_optimize): Do not use LOOP_BCT.
(rest_of_handle_loop2): Call doloop_optimize_loops.
(rest_of_compilation): Test for optimizations moved to
rest_of_handle_loop2.
However, if that's not the case, then the problem applies to 3.3
and 3.4 as well.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 3:24 ` John David Anglin
@ 2004-04-19 3:27 ` Mark Mitchell
2004-04-19 5:30 ` Zdenek Dvorak
1 sibling, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2004-04-19 3:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, gdr, rakdver
John David Anglin wrote:
>>This suggests that Zdenek's patch on March 18 results in the instructions
>>which use this RTX being removed from the instruction chain but for
>>some reason we are still using reg_known_value[294]. I'll try to look
>>into this.
>
>
> This appears to be what's happening. After gcse, we have:
Thanks for continuing to track this down.
> Maybe my patch is the best solution. However, I think Zdenek should
> look at this.
Yes, please. Zdenek?
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 3:24 ` John David Anglin
2004-04-19 3:27 ` Mark Mitchell
@ 2004-04-19 5:30 ` Zdenek Dvorak
2004-04-19 13:58 ` John David Anglin
2004-04-19 14:49 ` Mark Mitchell
1 sibling, 2 replies; 521+ messages in thread
From: Zdenek Dvorak @ 2004-04-19 5:30 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, gdr
Hello,
> > This suggests that Zdenek's patch on March 18 results in the instructions
> > which use this RTX being removed from the instruction chain but for
> > some reason we are still using reg_known_value[294]. I'll try to look
> > into this.
>
> This appears to be what's happening. After gcse, we have:
>
> (insn 529 527 530 43 ../../gcc/gcc/caller-save.c:713 (set (reg/v/f:DI 294 [ to_save ])
> (plus:DI (reg/f:DI 3 %r3)
> (const_int 272 [0x110]))) 158 {*pa.md:4807} (nil)
> (nil))
>
> Loop changes this to:
>
> (insn 1435 1434 1437 (set (reg/f:DI 576)
> (plus:DI (reg/f:DI 3 %r3)
> (const_int 272 [0x110]))) -1 (nil)
> (nil))
>
> ...
>
> (insn 1436 511 1438 (set (reg/f:DI 491)
> (reg/f:DI 576)) -1 (nil)
> (nil))
>
> ...
>
> (insn 1298 1024 533 (set (reg/v/f:DI 294 [ to_save ])
> (reg/f:DI 491)) -1 (nil)
> (nil))
>
> So, we still have reg/v/f:DI 294 but the rtx is reg_known_value[294]
> has been orphaned. ggc_collect poisons the rtx. Then, the next time
> scan_loop is called we have a problem with the value for reg 294.
this does not make sense. reg_known_value is declared (at least in
mainline) as
static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
so it should keep its members alive by itself (provided that
reg_known_value_size is large enough, which it should be given
the way it is used).
> Maybe my patch is the best solution. However, I think Zdenek should
> look at this. The problem may have been introduced with this change:
>
> 2004-03-18 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
>
> * doloop.c: Removed.
> * loop-doloop.c: New file.
> * Makefile.in (doloop.o): Remove.
> (loop-doloop.o): New.
> * cfgloop.h (get_loop_level, doloop_optimize_loops): Declare.
> * cfgloopanal.c (get_loop_level): New function.
> * loop-iv.c (iv_number_of_iterations): Handle case when loop
> is leaved immediatelly.
> * loop.c (strength_reduce): Do not call doloop optimization.
> * loop.h (LOOP_BCT): Removed.
> * passes.c (rest_of_handle_loop_optimize): Do not use LOOP_BCT.
> (rest_of_handle_loop2): Call doloop_optimize_loops.
> (rest_of_compilation): Test for optimizations moved to
> rest_of_handle_loop2.
Almost definitely not; it probably just exposes the problem by changing
the memory consumption and consequently the time when garbage
collections are triggered.
Zdenek
> However, if that's not the case, then the problem applies to 3.3
> and 3.4 as well.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc-cnrc.gc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 5:30 ` Zdenek Dvorak
@ 2004-04-19 13:58 ` John David Anglin
2004-04-19 14:49 ` Mark Mitchell
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-19 13:58 UTC (permalink / raw)
To: Zdenek Dvorak; +Cc: mark, gcc-patches, gdr
> > So, we still have reg/v/f:DI 294 but the rtx is reg_known_value[294]
> > has been orphaned. ggc_collect poisons the rtx. Then, the next time
> > scan_loop is called we have a problem with the value for reg 294.
>
> this does not make sense. reg_known_value is declared (at least in
> mainline) as
>
> static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
Yes, it does. At the time this problem first occurred, the prototype
was
rtx *reg_known_value;
Richard Henderson changed the prototype on March 24. There have been
several problems appear on the hppa64 port and I was trying to deal
with them sequently. PR 14829 ocurred just after, then the cgraph
merge by Jan Hubicka on April 2 introduced another problem.
I will check if Richard's change plus my fix for PR 14829
<http://gcc.gnu.org/ml/gcc-patches/2004-04/msg01021.html>
resolves the problem. If it does, I think Richard's change needs
to be backported to 3.3 and 3.4.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 5:30 ` Zdenek Dvorak
2004-04-19 13:58 ` John David Anglin
@ 2004-04-19 14:49 ` Mark Mitchell
2004-04-19 15:01 ` Zdenek Dvorak
1 sibling, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2004-04-19 14:49 UTC (permalink / raw)
To: Zdenek Dvorak; +Cc: John David Anglin, gcc-patches, gdr
Zdenek Dvorak wrote:
> Almost definitely not; it probably just exposes the problem by changing
> the memory consumption and consequently the time when garbage
> collections are triggered.
Even if that is so, it is still your responsibility to look into it.
Would you please help J. David to track down what's going on?
Thanks,
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 14:49 ` Mark Mitchell
@ 2004-04-19 15:01 ` Zdenek Dvorak
2004-04-19 16:22 ` John David Anglin
2004-04-19 19:57 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Zdenek Dvorak @ 2004-04-19 15:01 UTC (permalink / raw)
To: Mark Mitchell; +Cc: John David Anglin, gcc-patches, gdr
Hello,
> Zdenek Dvorak wrote:
>
> >Almost definitely not; it probably just exposes the problem by changing
> >the memory consumption and consequently the time when garbage
> >collections are triggered.
>
> Even if that is so, it is still your responsibility to look into it.
>
> Would you please help J. David to track down what's going on?
I believe that the problem should be fixed by the inclusion of GTY
markers on the reg_known_value (which probably should be added to
whatever other branches contain the fix for PR12440).
Zdenek
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 15:01 ` Zdenek Dvorak
@ 2004-04-19 16:22 ` John David Anglin
2004-04-19 17:45 ` Zdenek Dvorak
2004-04-19 19:57 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-19 16:22 UTC (permalink / raw)
To: Zdenek Dvorak; +Cc: mark, gcc-patches, gdr
> > Zdenek Dvorak wrote:
> >
> > >Almost definitely not; it probably just exposes the problem by changing
> > >the memory consumption and consequently the time when garbage
> > >collections are triggered.
> >
> > Even if that is so, it is still your responsibility to look into it.
> >
> > Would you please help J. David to track down what's going on?
>
> I believe that the problem should be fixed by the inclusion of GTY
> markers on the reg_known_value (which probably should be added to
> whatever other branches contain the fix for PR12440).
With the CVS as of D2004.03.26.12.00.00 (i.e., GTY markers on the
reg_known_value array), GCC bootstraps with --enable-languages=c.
I'm now doing a full bootstrap.
I looked at the compilation that was failing with gdb. However, due
to changes in memory consumption, garbage collection no longer occurs
while in loop_optimize. I guess that Richard's patch would have
to be back ported to D2004.03.18.16.43.00 to be absolutely certain
whether it fixes the problem.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 16:22 ` John David Anglin
@ 2004-04-19 17:45 ` Zdenek Dvorak
0 siblings, 0 replies; 521+ messages in thread
From: Zdenek Dvorak @ 2004-04-19 17:45 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, gdr
Hello,
> > > >Almost definitely not; it probably just exposes the problem by changing
> > > >the memory consumption and consequently the time when garbage
> > > >collections are triggered.
> > >
> > > Even if that is so, it is still your responsibility to look into it.
> > >
> > > Would you please help J. David to track down what's going on?
> >
> > I believe that the problem should be fixed by the inclusion of GTY
> > markers on the reg_known_value (which probably should be added to
> > whatever other branches contain the fix for PR12440).
>
> With the CVS as of D2004.03.26.12.00.00 (i.e., GTY markers on the
> reg_known_value array), GCC bootstraps with --enable-languages=c.
> I'm now doing a full bootstrap.
>
> I looked at the compilation that was failing with gdb. However, due
> to changes in memory consumption, garbage collection no longer occurs
> while in loop_optimize.
try setting --param ggc-min-expand=0 --param ggc-min-heapsize=0 (this
should force the garbage collection to occur always).
Zdenek
> I guess that Richard's patch would have
> to be back ported to D2004.03.18.16.43.00 to be absolutely certain
> whether it fixes the problem.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc-cnrc.gc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 15:01 ` Zdenek Dvorak
2004-04-19 16:22 ` John David Anglin
@ 2004-04-19 19:57 ` John David Anglin
2004-04-19 20:03 ` Andrew Pinski
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-19 19:57 UTC (permalink / raw)
To: Zdenek Dvorak; +Cc: mark, gcc-patches, gdr
> > Zdenek Dvorak wrote:
> >
> > >Almost definitely not; it probably just exposes the problem by changing
> > >the memory consumption and consequently the time when garbage
> > >collections are triggered.
> >
> > Even if that is so, it is still your responsibility to look into it.
> >
> > Would you please help J. David to track down what's going on?
>
> I believe that the problem should be fixed by the inclusion of GTY
> markers on the reg_known_value (which probably should be added to
> whatever other branches contain the fix for PR12440).
The good news is that Richard's patch fixes the problem. The bad
news is that the patch uses ggc_free which isn't in 3.3 and 3.4.
Implementing ggc_free looks like it would require back porting
3 or 4 more patches.
Richard wrote in
<http://gcc.gnu.org/ml/gcc-patches/2004-03/msg02057.html>:
No idea why this is happening now, and apparently only to me, but
the fact is that data gets put into reg_known_value and a call to
ggc_collect happens before end_alias_analysis. The call to collect
happens during CSE, and is protected by a ggc_push_context, but it
still doesn't seem terribly safe.
Thus, it would seem that the push and pop fix isn't safe.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 19:57 ` John David Anglin
@ 2004-04-19 20:03 ` Andrew Pinski
2004-04-20 16:05 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Andrew Pinski @ 2004-04-19 20:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, Zdenek Dvorak, gdr, mark, Andrew Pinski
On Apr 19, 2004, at 15:57, John David Anglin wrote:
>
> The good news is that Richard's patch fixes the problem. The bad
> news is that the patch uses ggc_free which isn't in 3.3 and 3.4.
> Implementing ggc_free looks like it would require back porting
> 3 or 4 more patches.
Even better news is that ggc_free is really not need at all, it
is an optimization. You should be able to replace the call to
ggc_free with set that variable to NULL and have it work.
-Andrew Pinski
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-19 20:03 ` Andrew Pinski
@ 2004-04-20 16:05 ` John David Anglin
2004-04-21 19:07 ` Mark Mitchell
2004-04-21 21:44 ` Richard Henderson
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-20 16:05 UTC (permalink / raw)
To: Andrew Pinski; +Cc: gcc-patches, rakdver, gdr, mark, pinskia, rth
> On Apr 19, 2004, at 15:57, John David Anglin wrote:
> >
> > The good news is that Richard's patch fixes the problem. The bad
> > news is that the patch uses ggc_free which isn't in 3.3 and 3.4.
> > Implementing ggc_free looks like it would require back porting
> > 3 or 4 more patches.
>
> Even better news is that ggc_free is really not need at all, it
> is an optimization. You should be able to replace the call to
> ggc_free with set that variable to NULL and have it work.
Enclosed is a backport of Richard's patch to 3.4. The only functional
difference is the removal of the ggc_free call from end_alias_analysis.
I believe that this just defers garbage collection of reg_known_value.
I've tested the patch on hppa64-hp-hpux11.00 and hppa-unknown-linux-gnu
with no regressions.
Ok for 3.4?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-04-20 Richard Henderson <rth@redhat.com>
PR bootstrap/14671
* alias.c (alias_invariant, alias_invariant_size): Mark GTY.
(reg_known_value, reg_known_value_size): Likewise; make static.
(reg_known_equiv_p): Make static.
(clear_reg_alias_info): Update for new indexing.
(get_reg_known_value, set_reg_known_value): New.
(get_reg_known_equiv_p, set_reg_known_equiv_p): New.
(canon_rtx): Use them.
(init_alias_analysis): Likewise. Allocate reg_known_value with gc.
Don't play queer offsetting games with reg_known_value and
reg_known_equiv_p.
(end_alias_analysis): Don't free reg_known_value.
* rtl.h (get_reg_known_value, get_reg_known_equiv_p): Declare.
* sched-deps.c (reg_known_equiv_p, reg_known_value): Remove.
(deps_may_trap_p, sched_analyze_1, sched_analyze_2): Use the new
functions instead.
Index: alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/alias.c,v
retrieving revision 1.209.2.4
diff -u -3 -p -r1.209.2.4 alias.c
--- alias.c 12 Feb 2004 23:28:27 -0000 1.209.2.4
+++ alias.c 19 Apr 2004 20:13:15 -0000
@@ -181,17 +181,16 @@ static GTY (()) rtx static_reg_base_valu
Because this array contains only pseudo registers it has no effect
after reload. */
-static rtx *alias_invariant;
-unsigned int alias_invariant_size;
+static GTY((length("alias_invariant_size"))) rtx *alias_invariant;
+unsigned GTY(()) int alias_invariant_size;
/* Vector indexed by N giving the initial (unchanging) value known for
- pseudo-register N. This array is initialized in
- init_alias_analysis, and does not change until end_alias_analysis
- is called. */
-rtx *reg_known_value;
+ pseudo-register N. This array is initialized in init_alias_analysis,
+ and does not change until end_alias_analysis is called. */
+static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
/* Indicates number of valid entries in reg_known_value. */
-static unsigned int reg_known_value_size;
+static GTY(()) unsigned int reg_known_value_size;
/* Vector recording for each reg_known_value whether it is due to a
REG_EQUIV note. Future passes (viz., reload) may replace the
@@ -205,7 +204,7 @@ static unsigned int reg_known_value_size
REG_EQUIV notes. One could argue that the REG_EQUIV notes are
wrong, but solving the problem in the scheduler will likely give
better code, so we do it here. */
-char *reg_known_equiv_p;
+static bool *reg_known_equiv_p;
/* True when scanning insns from the start of the rtl to the
NOTE_INSN_FUNCTION_BEG note. */
@@ -1061,10 +1060,70 @@ clear_reg_alias_info (rtx reg)
{
unsigned int regno = REGNO (reg);
- if (regno < reg_known_value_size && regno >= FIRST_PSEUDO_REGISTER)
- reg_known_value[regno] = reg;
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno -= FIRST_PSEUDO_REGISTER;
+ if (regno < reg_known_value_size)
+ {
+ reg_known_value[regno] = reg;
+ reg_known_equiv_p[regno] = false;
+ }
+ }
+}
+
+/* If a value is known for REGNO, return it. */
+
+rtx
+get_reg_known_value (unsigned int regno)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno -= FIRST_PSEUDO_REGISTER;
+ if (regno < reg_known_value_size)
+ return reg_known_value[regno];
+ }
+ return NULL;
}
+/* Set it. */
+
+static void
+set_reg_known_value (unsigned int regno, rtx val)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno -= FIRST_PSEUDO_REGISTER;
+ if (regno < reg_known_value_size)
+ reg_known_value[regno] = val;
+ }
+}
+
+/* Similarly for reg_known_equiv_p. */
+
+bool
+get_reg_known_equiv_p (unsigned int regno)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno -= FIRST_PSEUDO_REGISTER;
+ if (regno < reg_known_value_size)
+ return reg_known_equiv_p[regno];
+ }
+ return false;
+}
+
+static void
+set_reg_known_equiv_p (unsigned int regno, bool val)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno -= FIRST_PSEUDO_REGISTER;
+ if (regno < reg_known_value_size)
+ reg_known_equiv_p[regno] = val;
+ }
+}
+
+
/* Returns a canonical version of X, from the point of view alias
analysis. (For example, if X is a MEM whose address is a register,
and the register has a known value (say a SYMBOL_REF), then a MEM
@@ -1074,11 +1133,16 @@ rtx
canon_rtx (rtx x)
{
/* Recursively look for equivalences. */
- if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER
- && REGNO (x) < reg_known_value_size)
- return reg_known_value[REGNO (x)] == x
- ? x : canon_rtx (reg_known_value[REGNO (x)]);
- else if (GET_CODE (x) == PLUS)
+ if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+ {
+ rtx t = get_reg_known_value (REGNO (x));
+ if (t == x)
+ return x;
+ if (t)
+ return canon_rtx (t);
+ }
+
+ if (GET_CODE (x) == PLUS)
{
rtx x0 = canon_rtx (XEXP (x, 0));
rtx x1 = canon_rtx (XEXP (x, 1));
@@ -2725,14 +2789,9 @@ init_alias_analysis (void)
timevar_push (TV_ALIAS_ANALYSIS);
- reg_known_value_size = maxreg;
-
- reg_known_value
- = (rtx *) xcalloc ((maxreg - FIRST_PSEUDO_REGISTER), sizeof (rtx))
- - FIRST_PSEUDO_REGISTER;
- reg_known_equiv_p
- = (char*) xcalloc ((maxreg - FIRST_PSEUDO_REGISTER), sizeof (char))
- - FIRST_PSEUDO_REGISTER;
+ reg_known_value_size = maxreg - FIRST_PSEUDO_REGISTER;
+ reg_known_value = ggc_calloc (reg_known_value_size, sizeof (rtx));
+ reg_known_equiv_p = xcalloc (reg_known_value_size, sizeof (bool));
/* Overallocate reg_base_value to allow some growth during loop
optimization. Loop unrolling can create a large number of
@@ -2850,6 +2909,7 @@ init_alias_analysis (void)
{
unsigned int regno = REGNO (SET_DEST (set));
rtx src = SET_SRC (set);
+ rtx t;
if (REG_NOTES (insn) != 0
&& (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
@@ -2857,29 +2917,28 @@ init_alias_analysis (void)
|| (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
&& GET_CODE (XEXP (note, 0)) != EXPR_LIST
&& ! rtx_varies_p (XEXP (note, 0), 1)
- && ! reg_overlap_mentioned_p (SET_DEST (set), XEXP (note, 0)))
+ && ! reg_overlap_mentioned_p (SET_DEST (set),
+ XEXP (note, 0)))
{
- reg_known_value[regno] = XEXP (note, 0);
- reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
+ set_reg_known_value (regno, XEXP (note, 0));
+ set_reg_known_equiv_p (regno,
+ REG_NOTE_KIND (note) == REG_EQUIV);
}
else if (REG_N_SETS (regno) == 1
&& GET_CODE (src) == PLUS
&& GET_CODE (XEXP (src, 0)) == REG
- && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER
- && (reg_known_value[REGNO (XEXP (src, 0))])
+ && (t = get_reg_known_value (REGNO (XEXP (src, 0))))
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
- rtx op0 = XEXP (src, 0);
- op0 = reg_known_value[REGNO (op0)];
- reg_known_value[regno]
- = plus_constant (op0, INTVAL (XEXP (src, 1)));
- reg_known_equiv_p[regno] = 0;
+ t = plus_constant (t, INTVAL (XEXP (src, 1)));
+ set_reg_known_value (regno, t);
+ set_reg_known_equiv_p (regno, 0);
}
else if (REG_N_SETS (regno) == 1
&& ! rtx_varies_p (src, 1))
{
- reg_known_value[regno] = src;
- reg_known_equiv_p[regno] = 0;
+ set_reg_known_value (regno, src);
+ set_reg_known_equiv_p (regno, 0);
}
}
}
@@ -2906,9 +2965,9 @@ init_alias_analysis (void)
while (changed && ++pass < MAX_ALIAS_LOOP_PASSES);
/* Fill in the remaining entries. */
- for (i = FIRST_PSEUDO_REGISTER; i < (int)maxreg; i++)
+ for (i = 0; i < (int)reg_known_value_size; i++)
if (reg_known_value[i] == 0)
- reg_known_value[i] = regno_reg_rtx[i];
+ reg_known_value[i] = regno_reg_rtx[i + FIRST_PSEUDO_REGISTER];
/* Simplify the reg_base_value array so that no register refers to
another register, except to special registers indirectly through
@@ -2954,10 +3013,9 @@ void
end_alias_analysis (void)
{
old_reg_base_value = reg_base_value;
- free (reg_known_value + FIRST_PSEUDO_REGISTER);
reg_known_value = 0;
reg_known_value_size = 0;
- free (reg_known_equiv_p + FIRST_PSEUDO_REGISTER);
+ free (reg_known_equiv_p);
reg_known_equiv_p = 0;
if (alias_invariant)
{
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.448.4.4
diff -u -3 -p -r1.448.4.4 rtl.h
--- rtl.h 25 Mar 2004 16:44:43 -0000 1.448.4.4
+++ rtl.h 19 Apr 2004 20:13:15 -0000
@@ -2303,6 +2303,8 @@ extern void end_alias_analysis (void);
extern rtx addr_side_effect_eval (rtx, int, int);
extern bool memory_modified_in_insn_p (rtx, rtx);
extern rtx find_base_term (rtx);
+extern rtx get_reg_known_value (unsigned int);
+extern bool get_reg_known_equiv_p (unsigned int);
/* In sibcall.c */
typedef enum {
Index: sched-deps.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-deps.c,v
retrieving revision 1.65.2.1
diff -u -3 -p -r1.65.2.1 sched-deps.c
--- sched-deps.c 23 Jan 2004 23:36:02 -0000 1.65.2.1
+++ sched-deps.c 19 Apr 2004 20:13:15 -0000
@@ -44,8 +44,6 @@ Software Foundation, 59 Temple Place - S
#include "cselib.h"
#include "df.h"
-extern char *reg_known_equiv_p;
-extern rtx *reg_known_value;
static regset_head reg_pending_sets_head;
static regset_head reg_pending_clobbers_head;
@@ -113,10 +111,12 @@ deps_may_trap_p (rtx mem)
{
rtx addr = XEXP (mem, 0);
- if (REG_P (addr)
- && REGNO (addr) >= FIRST_PSEUDO_REGISTER
- && reg_known_value[REGNO (addr)])
- addr = reg_known_value[REGNO (addr)];
+ if (REG_P (addr) && REGNO (addr) >= FIRST_PSEUDO_REGISTER)
+ {
+ rtx t = get_reg_known_value (REGNO (addr));
+ if (t)
+ addr = t;
+ }
return rtx_addr_can_trap_p (addr);
}
\f
@@ -523,10 +523,12 @@ sched_analyze_1 (struct deps *deps, rtx
/* Pseudos that are REG_EQUIV to something may be replaced
by that during reloading. We need only add dependencies for
the address in the REG_EQUIV note. */
- if (!reload_completed
- && reg_known_equiv_p[regno]
- && GET_CODE (reg_known_value[regno]) == MEM)
- sched_analyze_2 (deps, XEXP (reg_known_value[regno], 0), insn);
+ if (!reload_completed && get_reg_known_equiv_p (regno))
+ {
+ rtx t = get_reg_known_value (regno);
+ if (GET_CODE (t) == MEM)
+ sched_analyze_2 (deps, XEXP (t, 0), insn);
+ }
/* Don't let it cross a call after scheduling if it doesn't
already cross one. */
@@ -659,10 +661,12 @@ sched_analyze_2 (struct deps *deps, rtx
/* Pseudos that are REG_EQUIV to something may be replaced
by that during reloading. We need only add dependencies for
the address in the REG_EQUIV note. */
- if (!reload_completed
- && reg_known_equiv_p[regno]
- && GET_CODE (reg_known_value[regno]) == MEM)
- sched_analyze_2 (deps, XEXP (reg_known_value[regno], 0), insn);
+ if (!reload_completed && get_reg_known_equiv_p (regno))
+ {
+ rtx t = get_reg_known_value (regno);
+ if (GET_CODE (t) == MEM)
+ sched_analyze_2 (deps, XEXP (t, 0), insn);
+ }
/* If the register does not already cross any calls, then add this
insn to the sched_before_next_call list so that it will still
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-20 16:05 ` John David Anglin
@ 2004-04-21 19:07 ` Mark Mitchell
2004-04-21 21:44 ` Richard Henderson
1 sibling, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2004-04-21 19:07 UTC (permalink / raw)
To: John David Anglin; +Cc: Andrew Pinski, gcc-patches, rakdver, gdr, rth
John David Anglin wrote:
>>On Apr 19, 2004, at 15:57, John David Anglin wrote:
>>
>>
>>>The good news is that Richard's patch fixes the problem. The bad
>>>news is that the patch uses ggc_free which isn't in 3.3 and 3.4.
>>>Implementing ggc_free looks like it would require back porting
>>>3 or 4 more patches.
>>>
>>>
>>Even better news is that ggc_free is really not need at all, it
>>is an optimization. You should be able to replace the call to
>>ggc_free with set that variable to NULL and have it work.
>>
>>
>
>Enclosed is a backport of Richard's patch to 3.4. The only functional
>difference is the removal of the ggc_free call from end_alias_analysis.
>I believe that this just defers garbage collection of reg_known_value.
>
>I've tested the patch on hppa64-hp-hpux11.00 and hppa-unknown-linux-gnu
>with no regressions.
>
>Ok for 3.4?
>
>
Yes, this is OK.
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch 3.3/3.4/3.5] Fix PR bootstrap/14671
2004-04-20 16:05 ` John David Anglin
2004-04-21 19:07 ` Mark Mitchell
@ 2004-04-21 21:44 ` Richard Henderson
2004-04-22 20:38 ` Gabriel Dos Reis
1 sibling, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2004-04-21 21:44 UTC (permalink / raw)
To: John David Anglin; +Cc: Andrew Pinski, gcc-patches, rakdver, gdr, mark
On Tue, Apr 20, 2004 at 12:04:52PM -0400, John David Anglin wrote:
> Ok for 3.4?
Looks ok to me; Mark's still got gate control.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed 3.5] Fix DBX register numbering for hppa64
[not found] <no.id>
` (126 preceding siblings ...)
2004-04-19 3:24 ` John David Anglin
@ 2004-04-21 19:23 ` John David Anglin
2004-04-22 17:25 ` Mark Mitchell
2004-04-25 16:00 ` [PATCH] Re: Fix problem with constant modulus John David Anglin
` (35 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-21 19:23 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
Mark,
Is this ok for the 3.4 branch? It fixes a couple of register numbering
issues on hppa64 with respect to the shift amount register (cr11).
This appears to be a cut and paste error and it probably has been around
from the beginning of the hppa64 port. Thus, it's just a bug.
I believe that this change is safe. It only affects hppa64. The
change has been tested with 3.4 and 3.5 on hppa64-hp-hpux11.00.
> 2004-04-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
>
> * pa64-regs.h (DBX_REGISTER_NUMBER): Simplify and correct mapping of
> SAR register. Fix comment.
> (ADDITIONAL_REGISTER_NAMES): Correct register number of SAR register
> (%cr11).
>
> Index: config/pa/pa64-regs.h
> ===================================================================
> RCS file: /cvs/gcc/gcc/gcc/config/pa/pa64-regs.h,v
> retrieving revision 1.15
> diff -u -3 -p -r1.15 pa64-regs.h
> --- config/pa/pa64-regs.h 15 Mar 2004 18:20:49 -0000 1.15
> +++ config/pa/pa64-regs.h 16 Apr 2004 14:53:42 -0000
> @@ -169,13 +169,11 @@ Boston, MA 02111-1307, USA. */
>
> Registers 0 - 31 remain unchanged.
>
> - Registers 32 - 60 are mapped to 72, 74, 76 ...
> -
> - Register 88 is mapped to 32. */
> + Registers 32 - 59 are mapped to 72, 74, 76 ...
>
> + Register 60 is mapped to 32. */
> #define DBX_REGISTER_NUMBER(REGNO) \
> - ((REGNO) <= 31 ? (REGNO) : \
> - ((REGNO) > 31 && (REGNO) <= 60 ? (REGNO - 32) * 2 + 72 : 32))
> + ((REGNO) <= 31 ? (REGNO) : ((REGNO) < 60 ? (REGNO - 32) * 2 + 72 : 32))
>
> /* We must not use the DBX register numbers for the DWARF 2 CFA column
> numbers because that maps to numbers beyond FIRST_PSEUDO_REGISTER.
> @@ -292,7 +290,7 @@ enum reg_class { NO_REGS, R1_REGS, GENER
> "%fr28", "%fr29", "%fr30", "%fr31", "SAR"}
>
> #define ADDITIONAL_REGISTER_NAMES \
> - {{"%cr11",88}}
> + {{"%cr11",60}}
>
> #define FP_SAVED_REG_LAST 49
> #define FP_SAVED_REG_FIRST 40
>
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed 3.5] Fix DBX register numbering for hppa64
2004-04-21 19:23 ` [committed 3.5] Fix DBX register numbering for hppa64 John David Anglin
@ 2004-04-22 17:25 ` Mark Mitchell
2004-04-22 17:40 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2004-04-22 17:25 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
John David Anglin wrote:
>Mark,
>
>Is this ok for the 3.4 branch? It fixes a couple of register numbering
>issues on hppa64 with respect to the shift amount register (cr11).
>This appears to be a cut and paste error and it probably has been around
>from the beginning of the hppa64 port. Thus, it's just a bug.
>
>
OK.
Out of curiousity, what debugger are you using on hppa64-hp-hpux11.00
and what options to you provide to GCC to get debugging information that
works with that debugger? We've tried a bunch of different combinations
with varying levels of success, but I'd be interested in your experience.
Thanks,
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed 3.5] Fix DBX register numbering for hppa64
2004-04-22 17:25 ` Mark Mitchell
@ 2004-04-22 17:40 ` John David Anglin
0 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-22 17:40 UTC (permalink / raw)
To: Mark Mitchell; +Cc: gcc-patches
> Out of curiousity, what debugger are you using on hppa64-hp-hpux11.00
> and what options to you provide to GCC to get debugging information that
> works with that debugger? We've tried a bunch of different combinations
> with varying levels of success, but I'd be interested in your experience.
The situation is fairly miserable. I have a collection of four or five
different builds and sometimes one will work better than another. I
have a collection of hacks which improve things slightly. Randolph
Chung is spending a bit of time working on gdb and hopefully things will
get better.
Mostly, I use the standard dwarf2 information on hppa64.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Re: Fix problem with constant modulus
[not found] <no.id>
` (127 preceding siblings ...)
2004-04-21 19:23 ` [committed 3.5] Fix DBX register numbering for hppa64 John David Anglin
@ 2004-04-25 16:00 ` John David Anglin
2004-04-25 22:17 ` [ping] Unreviewed patch John David Anglin
` (34 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-04-25 16:00 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, weigand, kenner
> This patch is definite progress (the ada bootstrap on hppa-linux
> no longer fails with an assertion failure) but there are several
> testsuite regressions which are probably caused by the constant
> modulus changes. For example, gcc.c-torture/execute/multdi-1.c
> now fails on hppa-unknown-linux-gnu.
Sorry, this message was erroneous. I need to recheck.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* [ping] Unreviewed patch
[not found] <no.id>
` (128 preceding siblings ...)
2004-04-25 16:00 ` [PATCH] Re: Fix problem with constant modulus John David Anglin
@ 2004-04-25 22:17 ` John David Anglin
2004-04-27 23:34 ` Mark Mitchell
2004-05-04 0:50 ` [PATCH] Ulrich Weigand
` (33 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-04-25 22:17 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
Could a global or dwarf2 maintainer review the following patch:
<http://gcc.gnu.org/ml/gcc-patches/2004-04/msg01021.html>?
Thanks,
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH]
[not found] <no.id>
` (129 preceding siblings ...)
2004-04-25 22:17 ` [ping] Unreviewed patch John David Anglin
@ 2004-05-04 0:50 ` Ulrich Weigand
2004-05-04 0:52 ` [PATCH] Eric Christopher
2004-06-04 15:56 ` building sh-elf / sh-linux (Was: Re: [PATCH/RFA] PR target/13250) Joern Rennecke
` (32 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: Ulrich Weigand @ 2004-05-04 0:50 UTC (permalink / raw)
To: weigand; +Cc: echristo, gcc-patches, uweigand
I wrote:
> >+(define_insn "prologue_tpf"
> >+ [(unspec_volatile [(const_int 0)] UNSPECV_TPF_PROLOGUE)]
> >+ "TARGET_TPF"
> >+ "bas\t%%r1,4064"
> >+ [(set_attr "type" "jsr")])
>
> We should have a (clobber (reg 1)) here at least ...
Oh, and we should have (set_attr "op_type" "RX") for
insn length computation and scheduling ...
Bye,
Ulrich
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH]
2004-05-04 0:50 ` [PATCH] Ulrich Weigand
@ 2004-05-04 0:52 ` Eric Christopher
0 siblings, 0 replies; 521+ messages in thread
From: Eric Christopher @ 2004-05-04 0:52 UTC (permalink / raw)
To: Ulrich Weigand; +Cc: gcc-patches, uweigand
On Mon, 2004-05-03 at 17:47, Ulrich Weigand wrote:
> I wrote:
>
> > >+(define_insn "prologue_tpf"
> > >+ [(unspec_volatile [(const_int 0)] UNSPECV_TPF_PROLOGUE)]
> > >+ "TARGET_TPF"
> > >+ "bas\t%%r1,4064"
> > >+ [(set_attr "type" "jsr")])
> >
> > We should have a (clobber (reg 1)) here at least ...
>
> Oh, and we should have (set_attr "op_type" "RX") for
> insn length computation and scheduling ...
That I can do. Thanks for the scheduling info :)
-eric
--
Eric Christopher <echristo@redhat.com>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: building sh-elf / sh-linux (Was: Re: [PATCH/RFA] PR target/13250)
[not found] <no.id>
` (130 preceding siblings ...)
2004-05-04 0:50 ` [PATCH] Ulrich Weigand
@ 2004-06-04 15:56 ` Joern Rennecke
2004-06-04 18:25 ` Joern Rennecke
2004-07-07 21:10 ` [PATCH] Fix PR target/16344 John David Anglin
` (31 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: Joern Rennecke @ 2004-06-04 15:56 UTC (permalink / raw)
To: renneckej; +Cc: Kaz Kojima, joern.rennecke, gcc-patches, aoliva
>
> I'm not really happy with having the scheduler follow through jumps to
> find call / call-value-copy pairs. I have now implemented
> the approach of deleting fixup_fallthru_exit_predecessor and making
> mid-function epilogues valid.
> There was also a real.c bug that got in the way. I'm appending the patch
> set that I am currently testing; I'll submit the two new patches
> individually when they are tested.
>
> 2004-06-04 J"orn Rennecke <joern.rennecke@superh.com>
>
> * basic-block.h (could_fall_through): Declare.
> * cfganal.c (can_fallthru): Suceed if the target is EXIT_BLOCK_PTR.
> Fail if the source already has a fallthrough edge to the exit
> block pointer.
> (could_fall_through): New function.
> (make_edges): Check if we already have a fallthrough edge to the
> exit block pointer.
> cfglayout.c (fixup_fallthru_exit_predecessor): Delete.
> (cfg_layout_finalize): Don't call it.
> (fixup_reorder_chain): A fall through to the exit block does not
> require the block to come last. Add sanity checks.
> * cfgrtl.c (rtl_split_edge): Add special handling of fall through
> edges to the exit block.
>
> 2004-06-03 J"orn Rennecke <joern.rennecke@superh.com>
>
> * real.c (do_add): Initialize r->signalling and r->canonical.
>
> 2004-05-14 J"orn Rennecke <joern.rennecke@superh.com>
>
> * sched-int.h (in_post_call_group_p): Change type to enum.
> * sched-deps.c (sched_analyze_insn):
> (sched_analyze): When in_post_call_group_p is post_call_initial,
> don't add a dependency, but still set SCHED_GROUP_P and CANT_MOVE,
> and also reset in_post_call_group_p to post_call.
> (sched_analyze): When the previous basic block ended in a CALL_INSN,
I've chosen a i686-pc-linux-gnu host for a bootstrap test.
For the unmodified control, I got a failure during stage1 building
crtbegin.o - cc1 throws a floating point exception. The patched
compiler has moved on to stage2 in the meantime.
Likewise, sh-elf (using sources from the 26th May as baseline) has suceeded
building and the sh1 big endian results are:
=== gcc Summary for sh-hms-sim ===
# of expected passes 25703
# of unexpected failures 29
# of unexpected successes 1
# of expected failures 68
# of unresolved testcases 5
# of untested testcases 28
# of unsupported tests 368
Considering that the controls don't build at all, I suppose I can say the
regression test passed.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: building sh-elf / sh-linux (Was: Re: [PATCH/RFA] PR target/13250)
2004-06-04 15:56 ` building sh-elf / sh-linux (Was: Re: [PATCH/RFA] PR target/13250) Joern Rennecke
@ 2004-06-04 18:25 ` Joern Rennecke
0 siblings, 0 replies; 521+ messages in thread
From: Joern Rennecke @ 2004-06-04 18:25 UTC (permalink / raw)
To: Joern Rennecke; +Cc: Kaz Kojima, joern.rennecke, gcc-patches, aoliva, gcc
> I've chosen a i686-pc-linux-gnu host for a bootstrap test.
> For the unmodified control, I got a failure during stage1 building
> crtbegin.o - cc1 throws a floating point exception. The patched
> compiler has moved on to stage2 in the meantime.
Hmm, it's actually a stage2 failure, and it is the same with
and without patches.
Program received signal SIGFPE, Arithmetic exception.
0x08421ace in narrow_str_to_charconst (pfile=0x8590518, str=
{len = 2, text = 0x85bcc78 "\n"}, pchars_seen=0xbfffe650,
unsignedp=0xbfffe654) at ../../srcw/libcpp/charset.c:1214
1214 size_t max_chars = CPP_OPTION (pfile, int_precision) / width;
(gdb) p width
$1 = 0
(gdb) l
1209 static cppchar_t
1210 narrow_str_to_charconst (cpp_reader *pfile, cpp_string str,
1211 unsigned int *pchars_seen, int *unsignedp)
1212 {
1213 size_t width = CPP_OPTION (pfile, char_precision);
1214 size_t max_chars = CPP_OPTION (pfile, int_precision) / width;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix PR target/16344
[not found] <no.id>
` (131 preceding siblings ...)
2004-06-04 15:56 ` building sh-elf / sh-linux (Was: Re: [PATCH/RFA] PR target/13250) Joern Rennecke
@ 2004-07-07 21:10 ` John David Anglin
2004-07-08 5:56 ` Mark Mitchell
2004-07-09 21:01 ` [RFT/RFA] gimplify pa va_arg John David Anglin
` (30 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2004-07-07 21:10 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, geoffk, gcc-patches
> The problem is the PLT is moving from one invocation of cc1plus to
> another. I'm not sure why. Currently, function descriptors live in
> the PLT. So, if it moves, the PCH is dead even if the text is in the
> same location as it was when the PCH file was written. If this can't
> be fixed, then the only solution is to avoid writing out any function
> pointers.
It turns out that the PLT isn't moving. The problem is a Makefile
issue. The runtime libraries are being built with the training compiler
in a profiled build. Then, we use the profiled feedback compiler
when the testsuite is run. As a result, PCH is disabled.
I am testing the enclosed fix.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-07-07 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/16344
* Makefile.tpl: Build runtime libraries with feedback based compiler.
Index: Makefile.tpl
===================================================================
RCS file: /cvs/gcc/gcc/Makefile.tpl,v
retrieving revision 1.79
diff -u -3 -p -r1.79 Makefile.tpl
--- Makefile.tpl 14 Jan 2004 20:09:37 -0000 1.79
+++ Makefile.tpl 7 Jul 2004 20:11:09 -0000
@@ -1177,18 +1177,18 @@ profiledbootstrap: all-bootstrap configu
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(SET_LIB_PATH) \
- echo "Bootstrapping the compiler"; \
+ echo "Bootstrapping the training compiler"; \
cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) stageprofile_build
@r=`${PWD_COMMAND}`; export r; \
- s=`cd $(srcdir); ${PWD_COMMAND}` ; export s; \
- $(SET_LIB_PATH) \
- echo "Building runtime libraries and training compiler"; \
- $(MAKE) $(BASE_FLAGS_TO_PASS) $(RECURSE_FLAGS) all
- @r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(SET_LIB_PATH) \
- echo "Building feedback based compiler"; \
+ echo "Building the feedback based compiler"; \
cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) stagefeedback_build
+ @r=`${PWD_COMMAND}`; export r; \
+ s=`cd $(srcdir); ${PWD_COMMAND}` ; export s; \
+ $(SET_LIB_PATH) \
+ echo "Building the runtime libraries"; \
+ $(MAKE) $(BASE_FLAGS_TO_PASS) $(RECURSE_FLAGS) all
.PHONY: cross
cross: all-texinfo all-bison all-byacc all-binutils all-gas all-ld
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix PR target/16344
2004-07-07 21:10 ` [PATCH] Fix PR target/16344 John David Anglin
@ 2004-07-08 5:56 ` Mark Mitchell
0 siblings, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2004-07-08 5:56 UTC (permalink / raw)
To: John David Anglin; +Cc: geoffk, gcc-patches
John David Anglin wrote:
>>The problem is the PLT is moving from one invocation of cc1plus to
>>another. I'm not sure why. Currently, function descriptors live in
>>the PLT. So, if it moves, the PCH is dead even if the text is in the
>>same location as it was when the PCH file was written. If this can't
>>be fixed, then the only solution is to avoid writing out any function
>>pointers.
>>
>>
>
>It turns out that the PLT isn't moving. The problem is a Makefile
>issue. The runtime libraries are being built with the training compiler
>in a profiled build. Then, we use the profiled feedback compiler
>when the testsuite is run. As a result, PCH is disabled.
>
>I am testing the enclosed fix.
>
That makes sense to me. OK, if it works, and Geoff/others do not object.
--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [RFT/RFA] gimplify pa va_arg
[not found] <no.id>
` (132 preceding siblings ...)
2004-07-07 21:10 ` [PATCH] Fix PR target/16344 John David Anglin
@ 2004-07-09 21:01 ` John David Anglin
2004-07-10 18:38 ` gimple va_arg for hppa John David Anglin
` (29 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-07-09 21:01 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, paolo.bonzini, rth
> The code generated for f4 is wrong. Garbage is used for the first
Doh. Just forget the last message.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: gimple va_arg for hppa
[not found] <no.id>
` (133 preceding siblings ...)
2004-07-09 21:01 ` [RFT/RFA] gimplify pa va_arg John David Anglin
@ 2004-07-10 18:38 ` John David Anglin
2004-07-11 13:07 ` [PATCH] DWARF-2 unwinder off-by-one problem with signal frames Ulrich Weigand
` (28 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-07-10 18:38 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rth
> It looks as if std_expand_builtin_va_arg should handle this. It looks
Oh crum, wrong routine. However, we are still not aligning arguments
larger than a word on hppa64.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] DWARF-2 unwinder off-by-one problem with signal frames
[not found] <no.id>
` (134 preceding siblings ...)
2004-07-10 18:38 ` gimple va_arg for hppa John David Anglin
@ 2004-07-11 13:07 ` Ulrich Weigand
2004-10-31 20:11 ` [PATCH] Fix PR target/16304: AIX 4.x forward reference proble John David Anglin
` (27 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: Ulrich Weigand @ 2004-07-11 13:07 UTC (permalink / raw)
To: gcc-patches, java-patches; +Cc: rth
> ChangeLog:
>
> * config/s390/linux.h (MD_FALLBACK_FRAME_STATE_FOR): For SIGSEGV and
> SIGBUS signal frames, the PSW address points *to* the faulting
> instruction, not after it.
>
> libjava/ChangeLog:
>
> * include/s390-signal.c (SIGNAL_HANDLER): Use SIGINFO-style prototype.
> (struct old_s390_kernel_sigaction): Likewise for k_sa_handler.
> (MAKE_THROW_FRAME): Do not modify PSW address.
> (INIT_SEGV): Install SIGINFO-style signal handler.
> (INIT_FPE): Likewise.
I've committed this now.
Bye,
Ulrich
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix PR target/16304: AIX 4.x forward reference proble
[not found] <no.id>
` (135 preceding siblings ...)
2004-07-11 13:07 ` [PATCH] DWARF-2 unwinder off-by-one problem with signal frames Ulrich Weigand
@ 2004-10-31 20:11 ` John David Anglin
2004-11-27 17:39 ` [committed] Fix pch/14940 on hppa-unknown-linux-gnu John David Anglin
` (26 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-10-31 20:11 UTC (permalink / raw)
To: John David Anglin; +Cc: mark, gcc-patches, china, dje
> > Do we actually need the thunk alias stuff for AIX? AFAIK, things worked
> > fine without that for a long time; I believe it was added for GNU/Linux
> > magic. Can we just diable thunk aliases for AIX?
>
> I believe that can be done.
This is probably best done using the TARGET_USE_LOCAL_THUNK_ALIAS_P
macro that Danny Smith added to the main branch on 2004-04-08. This
change could be back ported to 3.4.
Using a thunk alias avoids in some situations the linker adding a
stub between the thunk and thunk function. Having a direct jump
from thunk to thunk function is necessary under HP-UX. Thus, this
magic is important for systems other than GNU/Linux.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix pch/14940 on hppa-unknown-linux-gnu
[not found] <no.id>
` (136 preceding siblings ...)
2004-10-31 20:11 ` [PATCH] Fix PR target/16304: AIX 4.x forward reference proble John David Anglin
@ 2004-11-27 17:39 ` John David Anglin
2004-11-28 20:24 ` [ping] Fix PR target/16304: AIX 4.x forward reference problem John David Anglin
` (25 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-11-27 17:39 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2004-11-22 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
>
> PR pch/14940
> * config/host-linux.c (TRY_EMPTY_VM_SPACE): Define for __hppa__.
This scheme doesn't work on hppa-linux. The issue is not finding empty space.
The problem is the kernel doesn't always return the same mmap address for
the pch file given the same start and length.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-11-27 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR pch/14940
* config/host-linux.c (TRY_EMPTY_VM_SPACE): Revert 2004-11-22 change.
Index: config/host-linux.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/host-linux.c,v
retrieving revision 1.5
diff -u -3 -p -r1.5 host-linux.c
--- config/host-linux.c 23 Nov 2004 02:29:38 -0000 1.5
+++ config/host-linux.c 27 Nov 2004 16:51:09 -0000
@@ -77,8 +77,6 @@
# define TRY_EMPTY_VM_SPACE 0x8000000000
#elif defined(__s390__)
# define TRY_EMPTY_VM_SPACE 0x60000000
-#elif defined(__hppa__)
-# define TRY_EMPTY_VM_SPACE 0xa0000000
#elif defined(__sparc__) && defined(__LP64__)
# define TRY_EMPTY_VM_SPACE 0x8000000000
#elif defined(__sparc__)
^ permalink raw reply [flat|nested] 521+ messages in thread
* [ping] Fix PR target/16304: AIX 4.x forward reference problem
[not found] <no.id>
` (137 preceding siblings ...)
2004-11-27 17:39 ` [committed] Fix pch/14940 on hppa-unknown-linux-gnu John David Anglin
@ 2004-11-28 20:24 ` John David Anglin
2004-12-05 0:01 ` [patch] Fix for PR 14838 John David Anglin
` (24 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-11-28 20:24 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, china, mark, dje
Would someone please review the following patch:
<http://gcc.gnu.org/ml/gcc-patches/2004-10/msg02685.html>.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Fix for PR 14838
[not found] <no.id>
` (138 preceding siblings ...)
2004-11-28 20:24 ` [ping] Fix PR target/16304: AIX 4.x forward reference problem John David Anglin
@ 2004-12-05 0:01 ` John David Anglin
2004-12-05 1:17 ` Richard Henderson
2004-12-05 5:18 ` Gabriel Dos Reis
2004-12-27 2:57 ` [committed] Fix PR target/17643 on main and 3.4, and 3.3 John David Anglin
` (23 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2004-12-05 0:01 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark, gdr
> The enclosed change fixes PR 14838. It makes get_first_nonnote_insn
> and get_last_nonnote_insn more conservative in that they no longer
> assume that the first/last insn is always a note insn.
>
> The only users of these two functions are pa.c and avr.c.
I'm afraid the fix for PR 14838 fixed one problem and introduced another
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18730>. I failed to consider
the case where the first/last insn is a sequence.
This change fixes the bootstrap failure of the hppa1.1-hp-hpux10.20.
Tested on hppa1.1-hp-hpux10.20, hppa2.0w-hp-hpux11.11 and
hppa64-hp-hpux11.11 for the last week with no regressions.
Ok for 3.3, 3.4 and main?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-12-04 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle-end/18730
* emit-rtl.c (get_first_nonnote_insn, get_last_nonnote_insn): When
the first/last insn is a sequence, return the first/last insn of the
sequence.
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.365.4.6
diff -u -3 -p -r1.365.4.6 emit-rtl.c
--- emit-rtl.c 23 Nov 2004 03:01:10 -0000 1.365.4.6
+++ emit-rtl.c 30 Nov 2004 03:43:47 -0000
@@ -2908,9 +2908,22 @@ get_last_insn_anywhere (void)
rtx
get_first_nonnote_insn (void)
{
- rtx insn;
+ rtx insn = first_insn;
+
+ if (insn)
+ {
+ if (NOTE_P (insn))
+ for (insn = next_insn (insn);
+ insn && NOTE_P (insn);
+ insn = next_insn (insn));
+ else
+ {
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ insn = XVECEXP (PATTERN (insn), 0, 0);
+ }
+ }
- for (insn = first_insn; insn && NOTE_P (insn); insn = next_insn (insn));
return insn;
}
@@ -2920,9 +2933,23 @@ get_first_nonnote_insn (void)
rtx
get_last_nonnote_insn (void)
{
- rtx insn;
+ rtx insn = last_insn;
+
+ if (insn)
+ {
+ if (NOTE_P (insn))
+ for (insn = previous_insn (insn);
+ insn && NOTE_P (insn);
+ insn = previous_insn (insn));
+ else
+ {
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ insn = XVECEXP (PATTERN (insn), 0,
+ XVECLEN (PATTERN (insn), 0) - 1);
+ }
+ }
- for (insn = last_insn; insn && NOTE_P (insn); insn = previous_insn (insn));
return insn;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Fix for PR 14838
2004-12-05 0:01 ` [patch] Fix for PR 14838 John David Anglin
@ 2004-12-05 1:17 ` Richard Henderson
2004-12-05 5:18 ` Gabriel Dos Reis
1 sibling, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2004-12-05 1:17 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark, gdr
On Sat, Dec 04, 2004 at 07:01:16PM -0500, John David Anglin wrote:
> + for (insn = next_insn (insn);
> + insn && NOTE_P (insn);
> + insn = next_insn (insn));
Please put a "continue;" on the next line.
Otherwise it looks ok.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Fix for PR 14838
2004-12-05 0:01 ` [patch] Fix for PR 14838 John David Anglin
2004-12-05 1:17 ` Richard Henderson
@ 2004-12-05 5:18 ` Gabriel Dos Reis
1 sibling, 0 replies; 521+ messages in thread
From: Gabriel Dos Reis @ 2004-12-05 5:18 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, mark
On Sat, 4 Dec 2004, John David Anglin wrote:
| > The enclosed change fixes PR 14838. It makes get_first_nonnote_insn
| > and get_last_nonnote_insn more conservative in that they no longer
| > assume that the first/last insn is always a note insn.
| >
| > The only users of these two functions are pa.c and avr.c.
|
| I'm afraid the fix for PR 14838 fixed one problem and introduced another
| <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18730>. I failed to consider
| the case where the first/last insn is a sequence.
|
| This change fixes the bootstrap failure of the hppa1.1-hp-hpux10.20.
| Tested on hppa1.1-hp-hpux10.20, hppa2.0w-hp-hpux11.11 and
| hppa64-hp-hpux11.11 for the last week with no regressions.
|
| Ok for 3.3, 3.4 and main?
OK for 3.3.x when it goes in 3.4.x (with modification as suggested by RTH).
-- Gaby
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix PR target/17643 on main and 3.4, and 3.3
[not found] <no.id>
` (139 preceding siblings ...)
2004-12-05 0:01 ` [patch] Fix for PR 14838 John David Anglin
@ 2004-12-27 2:57 ` John David Anglin
2005-01-21 0:25 ` Change to gcc.dg/tree-ssa/loop-1.c John David Anglin
` (22 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2004-12-27 2:57 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> main and 3.4 branch. 3.3 needs a different fix.
Here is the 3.3 fix.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2004-12-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/17643
* config/pa/pa32-linux.h (FUNCTION_OK_FOR_SIBCALL): Return false when
TARGET_PORTABLE_RUNTIME is true.
Index: config/pa/pa32-linux.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/pa/pa32-linux.h,v
retrieving revision 1.10
diff -u -3 -p -r1.10 pa32-linux.h
--- config/pa/pa32-linux.h 6 Dec 2002 02:54:38 -0000 1.10
+++ config/pa/pa32-linux.h 27 Dec 2004 02:41:23 -0000
@@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */
pointer into the frame. This target does not need multiple
subspace stubs, so we allow sibcalls to all functions. */
#undef FUNCTION_OK_FOR_SIBCALL
-#define FUNCTION_OK_FOR_SIBCALL(DECL) 1
+#define FUNCTION_OK_FOR_SIBCALL(DECL) (!TARGET_PORTABLE_RUNTIME)
/* The libcall __canonicalize_funcptr_for_compare is referenced in
crtend.o and the reference isn't resolved in objects that don't
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
[not found] <no.id>
` (140 preceding siblings ...)
2004-12-27 2:57 ` [committed] Fix PR target/17643 on main and 3.4, and 3.3 John David Anglin
@ 2005-01-21 0:25 ` John David Anglin
2005-01-21 0:31 ` John David Anglin
2005-04-06 16:49 ` [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2) John David Anglin
` (21 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-01-21 0:25 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, sje
> FAIL: gcc.dg/tree-ssa/loop-1.c scan-assembler-times foo 5
Maybe this is fixed, I'll recheck.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 0:25 ` Change to gcc.dg/tree-ssa/loop-1.c John David Anglin
@ 2005-01-21 0:31 ` John David Anglin
2005-01-21 0:43 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-01-21 0:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, sje
> > FAIL: gcc.dg/tree-ssa/loop-1.c scan-assembler-times foo 5
>
> Maybe this is fixed, I'll recheck.
The reason the test was the way it was is the "foo" form passes on
hppa elf targets that don't include an external definition for foo.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 0:31 ` John David Anglin
@ 2005-01-21 0:43 ` John David Anglin
2005-01-21 0:49 ` Steve Ellcey
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-01-21 0:43 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, sje
> > > FAIL: gcc.dg/tree-ssa/loop-1.c scan-assembler-times foo 5
> >
> > Maybe this is fixed, I'll recheck.
>
> The reason the test was the way it was is the "foo" form passes on
> hppa elf targets that don't include an external definition for foo.
For example on hppa-unknown-linux-gnu, I got the following results:
Executing on host: /home/dave/gnu/gcc-4.0/objdir/gcc/xgcc -B/home/dave/gnu/gcc-4.0/objdir/gcc/ /home/dave/gnu/gcc-4.0/gcc/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c -O1 -ftree-loop-ivcanon -funroll-loops -fdump-tree-ivcanon-details -fdump-tree-cunroll-details -fdump-tree-vars -S -o loop-1.s (timeout = 300)
PASS: gcc.dg/tree-ssa/loop-1.c (test for excess errors)
PASS: gcc.dg/tree-ssa/loop-1.c scan-tree-dump-times Added canonical iv to loop 1, 4 iterations 1
PASS: gcc.dg/tree-ssa/loop-1.c scan-tree-dump-times Unrolled loop 1 completely 1
PASS: gcc.dg/tree-ssa/loop-1.c scan-tree-dump-times foo 5
ERROR: gcc.dg/tree-ssa/loop-1.c: error executing dg-final: scan-assembler: too many arguments
UNRESOLVED: gcc.dg/tree-ssa/loop-1.c: error executing dg-final: scan-assembler: too many arguments
I also saw the ERROR on hppa64-hp-hpux11.11.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 0:43 ` John David Anglin
@ 2005-01-21 0:49 ` Steve Ellcey
2005-01-21 14:57 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Steve Ellcey @ 2005-01-21 0:49 UTC (permalink / raw)
To: dave; +Cc: gcc-patches
> PASS: gcc.dg/tree-ssa/loop-1.c scan-tree-dump-times foo 5
> ERROR: gcc.dg/tree-ssa/loop-1.c: error executing dg-final: scan-assembler: too many arguments
> UNRESOLVED: gcc.dg/tree-ssa/loop-1.c: error executing dg-final: scan-assembler: too many arguments
>
> I also saw the ERROR on hppa64-hp-hpux11.11.
Yes, this was a bug in my original patch. Can you make sure you have
the latest (checked in this morning) version of loop-1.c and re-run.
You should get an XFAIL (maybe an XPASS on hppa elf targets if they have
no external declarations) but no FAIL and no ERROR using the latest
version of this test case.
Steve Ellcey
sje@cup.hp.com
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 0:49 ` Steve Ellcey
@ 2005-01-21 14:57 ` John David Anglin
2005-01-21 16:44 ` Steve Ellcey
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-01-21 14:57 UTC (permalink / raw)
To: Steve Ellcey; +Cc: gcc-patches
> You should get an XFAIL (maybe an XPASS on hppa elf targets if they have
> no external declarations) but no FAIL and no ERROR using the latest
> version of this test case.
We now have an XFAIL on SOM and an XPASS on ELF. I don't see this as
progress as the XPASS isn't unexpected.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 14:57 ` John David Anglin
@ 2005-01-21 16:44 ` Steve Ellcey
2005-01-21 17:42 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Steve Ellcey @ 2005-01-21 16:44 UTC (permalink / raw)
To: dave; +Cc: gcc-patches
> > You should get an XFAIL (maybe an XPASS on hppa elf targets if they have
> > no external declarations) but no FAIL and no ERROR using the latest
> > version of this test case.
>
> We now have an XFAIL on SOM and an XPASS on ELF. I don't see this as
> progress as the XPASS isn't unexpected.
>
> Dave
I didn't realize we would get any XPASS's but I only tested the HP-UX
targets. I don't see any way to get rid of both the XPASS's and XFAIL's
without using if statements which Janis Johnson didn't want me doing.
See the discussion starting at:
http://gcc.gnu.org/ml/gcc-patches/2005-01/msg00545.html
How about the following patch (untested), it should get rid of the
XPASS's and leave only some XFAIL's by checking for hppa*-*-hpux*
instead of hppa*-*-*:
2005-01-21 Steve Ellcey <sje@cup.hp.com>
* gcc.dg/tree-ssa/loop-1.c: Fix target names for hppa.
*** gcc.orig/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c Fri Jan 21 08:42:04 2005
--- gcc/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c Fri Jan 21 08:42:38 2005
*************** void xxx(void)
*** 29,36 ****
well as the calls we need to look for something more specific then just
foo in order to count only the calls and not the declaration. */
! /* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* } } } */
! /* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-* } } } */
/* { dg-final { scan-assembler-times "= foo" 5 { target ia64*-*-* } } } */
--- 29,36 ----
well as the calls we need to look for something more specific then just
foo in order to count only the calls and not the declaration. */
! /* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-hpux* ia64*-*-* } } } */
! /* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-hpux* } } } */
/* { dg-final { scan-assembler-times "= foo" 5 { target ia64*-*-* } } } */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 16:44 ` Steve Ellcey
@ 2005-01-21 17:42 ` John David Anglin
2005-01-21 20:33 ` Janis Johnson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-01-21 17:42 UTC (permalink / raw)
To: Steve Ellcey; +Cc: gcc-patches
> How about the following patch (untested), it should get rid of the
> XPASS's and leave only some XFAIL's by checking for hppa*-*-hpux*
> instead of hppa*-*-*:
I think that this approach will work but I believe that you also need
to check for hppa*-*-rtems*. It includes pa/elf.h which defines
ASM_OUTPUT_EXTERNAL.
This would all be simpler with a target skip mechanism.
I'm running a check of your change on hppa64-hp-hpux11.11.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Change to gcc.dg/tree-ssa/loop-1.c
2005-01-21 17:42 ` John David Anglin
@ 2005-01-21 20:33 ` Janis Johnson
0 siblings, 0 replies; 521+ messages in thread
From: Janis Johnson @ 2005-01-21 20:33 UTC (permalink / raw)
To: John David Anglin; +Cc: Steve Ellcey, gcc-patches
On Fri, Jan 21, 2005 at 12:41:24PM -0500, John David Anglin wrote:
> > How about the following patch (untested), it should get rid of the
> > XPASS's and leave only some XFAIL's by checking for hppa*-*-hpux*
> > instead of hppa*-*-*:
>
> I think that this approach will work but I believe that you also need
> to check for hppa*-*-rtems*. It includes pa/elf.h which defines
> ASM_OUTPUT_EXTERNAL.
>
> This would all be simpler with a target skip mechanism.
Or logical expressions in target and xfail lists. See my new proposal
in http://gcc.gnu.org/ml/gcc/2005-01/msg01264.html.
Janis
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
[not found] <no.id>
` (141 preceding siblings ...)
2005-01-21 0:25 ` Change to gcc.dg/tree-ssa/loop-1.c John David Anglin
@ 2005-04-06 16:49 ` John David Anglin
2005-04-29 10:27 ` Arnaud Charlet
2005-08-20 16:15 ` [patch]: Fix PR testsuite/23239 John David Anglin
` (20 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-04-06 16:49 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, charlet, laurent
Here is take 2. The changes from the previous version are all to the
file s-osinte-linux-hppa.ads:
1) Definition of struct_sigaction corrected,
2) Definition of SA_SIGINFO corrected,
3) sigset_t changed to array of unsigned_long.
There is one x86'ism, the record Machine_State. This is unused
and there apparently needs to be a cleanup in other files. Laurent
said that he would address this issue in a followup patch.
Tested on hppa-unknown-linux-gnu:
<http://gcc.gnu.org/ml/gcc-testresults/2005-04/msg00400.html>. There
was a further reduction in the number of testsuite fails to 11.
Ok?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2005-04-06 Laurent GUERBY <laurent@guerby.net>
John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* Makefile.in: Add make ifeq define for hppa linux tasking support.
* system-hpux.ads: Define Signed_Zeros to be True.
* system-linux-hppa.ads, s-osinte-linux-hppa.ads: New files.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/Makefile.in,v
retrieving revision 1.115
diff -u -3 -p -r1.115 Makefile.in
--- Makefile.in 29 Mar 2005 16:16:59 -0000 1.115
+++ Makefile.in 5 Apr 2005 23:08:06 -0000
@@ -1365,6 +1365,31 @@ ifeq ($(strip $(filter-out sparc% linux%
LIBRARY_VERSION := $(LIB_VERSION)
endif
+ifeq ($(strip $(filter-out hppa% linux%,$(arch) $(osys))),)
+ LIBGNAT_TARGET_PAIRS = \
+ a-intnam.ads<a-intnam-linux.ads \
+ s-inmaop.adb<s-inmaop-posix.adb \
+ s-intman.adb<s-intman-posix.adb \
+ s-osinte.adb<s-osinte-posix.adb \
+ s-osinte.ads<s-osinte-linux-hppa.ads \
+ s-osprim.adb<s-osprim-posix.adb \
+ s-taprop.adb<s-taprop-linux.adb \
+ s-taspri.ads<s-taspri-linux.ads \
+ s-tpopsp.adb<s-tpopsp-posix-foreign.adb \
+ s-parame.adb<s-parame-linux.adb \
+ system.ads<system-linux-hppa.ads
+
+ TOOLS_TARGET_PAIRS = \
+ mlib-tgt.adb<mlib-tgt-linux.adb \
+ indepsw.adb<indepsw-linux.adb
+
+ THREADSLIB = -lpthread
+ GNATLIB_SHARED = gnatlib-shared-dual
+ GMEM_LIB = gmemlib
+ PREFIX_OBJS = $(PREFIX_REAL_OBJS)
+ LIBRARY_VERSION := $(LIB_VERSION)
+endif
+
ifeq ($(strip $(filter-out %ia64 linux%,$(arch) $(osys))),)
LIBGNAT_TARGET_PAIRS = \
a-intnam.ads<a-intnam-linux.ads \
Index: system-hpux.ads
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/system-hpux.ads,v
retrieving revision 1.3
diff -u -3 -p -r1.3 system-hpux.ads
--- system-hpux.ads 15 Mar 2005 15:45:58 -0000 1.3
+++ system-hpux.ads 5 Apr 2005 23:08:06 -0000
@@ -130,7 +130,7 @@ private
Machine_Rounds : constant Boolean := True;
OpenVMS : constant Boolean := False;
Preallocated_Stacks : constant Boolean := False;
- Signed_Zeros : constant Boolean := False;
+ Signed_Zeros : constant Boolean := True;
Stack_Check_Default : constant Boolean := False;
Stack_Check_Probes : constant Boolean := False;
Support_64_Bit_Divides : constant Boolean := True;
--- /dev/null 2005-03-26 22:51:43.000000000 -0500
+++ system-linux-hppa.ads 2005-04-04 15:58:14.000000000 -0400
@@ -0,0 +1,151 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT RUN-TIME COMPONENTS --
+-- --
+-- S Y S T E M --
+-- --
+-- S p e c --
+-- (GNU/Linux-HPPA Version) --
+-- --
+-- Copyright (C) 1992-2005 Free Software Foundation, Inc. --
+-- --
+-- This specification is derived from the Ada Reference Manual for use with --
+-- GNAT. The copyright notice above, and the license provisions that follow --
+-- apply solely to the contents of the part following the private keyword. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 2, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNAT; see file COPYING. If not, write --
+-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
+-- MA 02111-1307, USA. --
+-- --
+-- As a special exception, if other files instantiate generics from this --
+-- unit, or you link this unit with other files to produce an executable, --
+-- this unit does not by itself cause the resulting executable to be --
+-- covered by the GNU General Public License. This exception does not --
+-- however invalidate any other reasons why the executable file might be --
+-- covered by the GNU Public License. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+package System is
+pragma Pure (System);
+-- Note that we take advantage of the implementation permission to
+-- make this unit Pure instead of Preelaborable, see RM 13.7(36)
+
+ type Name is (SYSTEM_NAME_GNAT);
+ System_Name : constant Name := SYSTEM_NAME_GNAT;
+
+ -- System-Dependent Named Numbers
+
+ Min_Int : constant := Long_Long_Integer'First;
+ Max_Int : constant := Long_Long_Integer'Last;
+
+ Max_Binary_Modulus : constant := 2 ** Long_Long_Integer'Size;
+ Max_Nonbinary_Modulus : constant := Integer'Last;
+
+ Max_Base_Digits : constant := Long_Long_Float'Digits;
+ Max_Digits : constant := Long_Long_Float'Digits;
+
+ Max_Mantissa : constant := 63;
+ Fine_Delta : constant := 2.0 ** (-Max_Mantissa);
+
+ Tick : constant := 0.000_001;
+
+ -- Storage-related Declarations
+
+ type Address is private;
+ Null_Address : constant Address;
+
+ Storage_Unit : constant := 8;
+ Word_Size : constant := 32;
+ Memory_Size : constant := 2 ** 32;
+
+ -- Address comparison
+
+ function "<" (Left, Right : Address) return Boolean;
+ function "<=" (Left, Right : Address) return Boolean;
+ function ">" (Left, Right : Address) return Boolean;
+ function ">=" (Left, Right : Address) return Boolean;
+ function "=" (Left, Right : Address) return Boolean;
+
+ pragma Import (Intrinsic, "<");
+ pragma Import (Intrinsic, "<=");
+ pragma Import (Intrinsic, ">");
+ pragma Import (Intrinsic, ">=");
+ pragma Import (Intrinsic, "=");
+
+ -- Other System-Dependent Declarations
+
+ type Bit_Order is (High_Order_First, Low_Order_First);
+ Default_Bit_Order : constant Bit_Order := High_Order_First;
+
+ -- Priority-related Declarations (RM D.1)
+
+ Max_Priority : constant Positive := 30;
+ Max_Interrupt_Priority : constant Positive := 31;
+
+ subtype Any_Priority is Integer range 0 .. 31;
+ subtype Priority is Any_Priority range 0 .. 30;
+ subtype Interrupt_Priority is Any_Priority range 31 .. 31;
+
+ Default_Priority : constant Priority := 15;
+
+private
+
+ type Address is mod Memory_Size;
+ Null_Address : constant Address := 0;
+
+ --------------------------------------
+ -- System Implementation Parameters --
+ --------------------------------------
+
+ -- These parameters provide information about the target that is used
+ -- by the compiler. They are in the private part of System, where they
+ -- can be accessed using the special circuitry in the Targparm unit
+ -- whose source should be consulted for more detailed descriptions
+ -- of the individual switch values.
+
+ AAMP : constant Boolean := False;
+ Backend_Divide_Checks : constant Boolean := False;
+ Backend_Overflow_Checks : constant Boolean := False;
+ Command_Line_Args : constant Boolean := True;
+ Configurable_Run_Time : constant Boolean := False;
+ Denorm : constant Boolean := True;
+ Duration_32_Bits : constant Boolean := False;
+ Exit_Status_Supported : constant Boolean := True;
+ Fractional_Fixed_Ops : constant Boolean := False;
+ Frontend_Layout : constant Boolean := False;
+ Functions_Return_By_DSP : constant Boolean := False;
+ Machine_Overflows : constant Boolean := False;
+ Machine_Rounds : constant Boolean := True;
+ OpenVMS : constant Boolean := False;
+ Preallocated_Stacks : constant Boolean := False;
+ Signed_Zeros : constant Boolean := True;
+ Stack_Check_Default : constant Boolean := False;
+ Stack_Check_Probes : constant Boolean := False;
+ Support_64_Bit_Divides : constant Boolean := True;
+ Support_Aggregates : constant Boolean := True;
+ Support_Composite_Assign : constant Boolean := True;
+ Support_Composite_Compare : constant Boolean := True;
+ Support_Long_Shifts : constant Boolean := True;
+ Suppress_Standard_Library : constant Boolean := False;
+ Use_Ada_Main_Program_Name : constant Boolean := False;
+ ZCX_By_Default : constant Boolean := True;
+ GCC_ZCX_Support : constant Boolean := True;
+ Front_End_ZCX_Support : constant Boolean := False;
+
+ -- Obsolete entries, to be removed eventually (bootstrap issues!)
+
+ High_Integrity_Mode : constant Boolean := False;
+ Long_Shifts_Inlined : constant Boolean := False;
+
+end System;
--- /dev/null 2005-03-26 22:51:43.000000000 -0500
+++ s-osinte-linux-hppa.ads 2005-04-05 21:47:35.000000000 -0400
@@ -0,0 +1,533 @@
+------------------------------------------------------------------------------
+-- --
+-- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS --
+-- --
+-- S Y S T E M . O S _ I N T E R F A C E --
+-- --
+-- S p e c --
+-- (GNU/Linux-HPPA Version) --
+-- --
+-- Copyright (C) 1991-1994, Florida State University --
+-- Copyright (C) 1995-2005, Free Software Foundation, Inc. --
+-- --
+-- GNARL is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 2, or (at your option) any later ver- --
+-- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNARL; see file COPYING. If not, write --
+-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
+-- MA 02111-1307, USA. --
+-- --
+-- As a special exception, if other files instantiate generics from this --
+-- unit, or you link this unit with other files to produce an executable, --
+-- this unit does not by itself cause the resulting executable to be --
+-- covered by the GNU General Public License. This exception does not --
+-- however invalidate any other reasons why the executable file might be --
+-- covered by the GNU Public License. --
+-- --
+-- GNARL was developed by the GNARL team at Florida State University. --
+-- Extensive contributions were provided by Ada Core Technologies, Inc. --
+-- --
+------------------------------------------------------------------------------
+
+-- This is a GNU/Linux (GNU/LinuxThreads) version of this package
+
+-- This package encapsulates all direct interfaces to OS services
+-- that are needed by children of System.
+
+-- PLEASE DO NOT add any with-clauses to this package or remove the pragma
+-- Preelaborate. This package is designed to be a bottom-level (leaf) package.
+
+with Interfaces.C;
+with Unchecked_Conversion;
+
+package System.OS_Interface is
+ pragma Preelaborate;
+
+ pragma Linker_Options ("-lpthread");
+
+ subtype int is Interfaces.C.int;
+ subtype char is Interfaces.C.char;
+ subtype short is Interfaces.C.short;
+ subtype long is Interfaces.C.long;
+ subtype unsigned is Interfaces.C.unsigned;
+ subtype unsigned_short is Interfaces.C.unsigned_short;
+ subtype unsigned_long is Interfaces.C.unsigned_long;
+ subtype unsigned_char is Interfaces.C.unsigned_char;
+ subtype plain_char is Interfaces.C.plain_char;
+ subtype size_t is Interfaces.C.size_t;
+
+ -----------
+ -- Errno --
+ -----------
+
+ function errno return int;
+ pragma Import (C, errno, "__get_errno");
+
+ EAGAIN : constant := 11;
+ EINTR : constant := 4;
+ EINVAL : constant := 22;
+ ENOMEM : constant := 12;
+ EPERM : constant := 1;
+ ETIMEDOUT : constant := 238;
+
+ -------------
+ -- Signals --
+ -------------
+
+ Max_Interrupt : constant := 63;
+ type Signal is new int range 0 .. Max_Interrupt;
+ for Signal'Size use int'Size;
+
+ SIGHUP : constant := 1; -- hangup
+ SIGINT : constant := 2; -- interrupt (rubout)
+ SIGQUIT : constant := 3; -- quit (ASCD FS)
+ SIGILL : constant := 4; -- illegal instruction (not reset)
+ SIGTRAP : constant := 5; -- trace trap (not reset)
+ SIGIOT : constant := 6; -- IOT instruction
+ SIGABRT : constant := 6; -- used by abort, replace SIGIOT in the future
+ SIGEMT : constant := 7; -- EMT
+ SIGFPE : constant := 8; -- floating point exception
+ SIGKILL : constant := 9; -- kill (cannot be caught or ignored)
+ SIGBUS : constant := 10; -- bus error
+ SIGSEGV : constant := 11; -- segmentation violation
+ SIGSYS : constant := 12; -- bad system call
+ SIGPIPE : constant := 13; -- write on a pipe with no one to read it
+ SIGALRM : constant := 14; -- alarm clock
+ SIGTERM : constant := 15; -- software termination signal from kill
+ SIGUSR1 : constant := 16; -- user defined signal 1
+ SIGUSR2 : constant := 17; -- user defined signal 2
+ SIGCLD : constant := 18; -- alias for SIGCHLD
+ SIGCHLD : constant := 18; -- child status change
+ SIGPWR : constant := 19; -- power-fail restart
+ SIGVTALRM : constant := 20; -- virtual timer expired
+ SIGPROF : constant := 21; -- profiling timer expired
+ SIGPOLL : constant := 22; -- pollable event occurred
+ SIGIO : constant := 22; -- I/O now possible (4.2 BSD)
+ SIGWINCH : constant := 23; -- window size change
+ SIGSTOP : constant := 24; -- stop (cannot be caught or ignored)
+ SIGTSTP : constant := 25; -- user stop requested from tty
+ SIGCONT : constant := 26; -- stopped process has been continued
+ SIGTTIN : constant := 27; -- background tty read attempted
+ SIGTTOU : constant := 28; -- background tty write attempted
+ SIGURG : constant := 29; -- urgent condition on IO channel
+ SIGLOST : constant := 30; -- File lock lost
+ SIGUNUSED : constant := 31; -- unused signal (GNU/Linux)
+ SIGXCPU : constant := 33; -- CPU time limit exceeded
+ SIGXFSZ : constant := 34; -- filesize limit exceeded
+ SIGSTKFLT : constant := 36; -- coprocessor stack fault (Linux)
+ SIGLTHRRES : constant := 37; -- GNU/LinuxThreads restart signal
+ SIGLTHRCAN : constant := 38; -- GNU/LinuxThreads cancel signal
+ SIGLTHRDBG : constant := 39; -- GNU/LinuxThreads debugger signal
+
+ SIGADAABORT : constant := SIGABRT;
+ -- Change this if you want to use another signal for task abort.
+ -- SIGTERM might be a good one.
+
+ type Signal_Set is array (Natural range <>) of Signal;
+
+ Unmasked : constant Signal_Set := (
+ SIGTRAP,
+ -- To enable debugging on multithreaded applications, mark SIGTRAP to
+ -- be kept unmasked.
+
+ SIGBUS,
+
+ SIGTTIN, SIGTTOU, SIGTSTP,
+ -- Keep these three signals unmasked so that background processes
+ -- and IO behaves as normal "C" applications
+
+ SIGPROF,
+ -- To avoid confusing the profiler
+
+ SIGKILL, SIGSTOP,
+ -- These two signals actually cannot be masked;
+ -- POSIX simply won't allow it.
+
+ SIGLTHRRES, SIGLTHRCAN, SIGLTHRDBG);
+ -- These three signals are used by GNU/LinuxThreads starting from
+ -- glibc 2.1 (future 2.2).
+
+ Reserved : constant Signal_Set :=
+ -- I am not sure why the following two signals are reserved.
+ -- I guess they are not supported by this version of GNU/Linux.
+ (SIGVTALRM, SIGUNUSED);
+
+ type sigset_t is private;
+
+ function sigaddset (set : access sigset_t; sig : Signal) return int;
+ pragma Import (C, sigaddset, "sigaddset");
+
+ function sigdelset (set : access sigset_t; sig : Signal) return int;
+ pragma Import (C, sigdelset, "sigdelset");
+
+ function sigfillset (set : access sigset_t) return int;
+ pragma Import (C, sigfillset, "sigfillset");
+
+ function sigismember (set : access sigset_t; sig : Signal) return int;
+ pragma Import (C, sigismember, "sigismember");
+
+ function sigemptyset (set : access sigset_t) return int;
+ pragma Import (C, sigemptyset, "sigemptyset");
+
+ type union_type_3 is new String (1 .. 116);
+ type siginfo_t is record
+ si_signo : int;
+ si_code : int;
+ si_errno : int;
+ X_data : union_type_3;
+ end record;
+ pragma Convention (C, siginfo_t);
+
+ type struct_sigaction is record
+ sa_handler : System.Address;
+ sa_flags : unsigned_long;
+ sa_mask : sigset_t;
+ end record;
+ pragma Convention (C, struct_sigaction);
+ type struct_sigaction_ptr is access all struct_sigaction;
+
+ type Machine_State is record
+ eip : unsigned_long;
+ ebx : unsigned_long;
+ esp : unsigned_long;
+ ebp : unsigned_long;
+ esi : unsigned_long;
+ edi : unsigned_long;
+ end record;
+ type Machine_State_Ptr is access all Machine_State;
+
+ SA_SIGINFO : constant := 16;
+
+ SIG_BLOCK : constant := 0;
+ SIG_UNBLOCK : constant := 1;
+ SIG_SETMASK : constant := 2;
+
+ SIG_DFL : constant := 0;
+ SIG_IGN : constant := 1;
+
+ function sigaction
+ (sig : Signal;
+ act : struct_sigaction_ptr;
+ oact : struct_sigaction_ptr) return int;
+ pragma Import (C, sigaction, "sigaction");
+
+ ----------
+ -- Time --
+ ----------
+
+ type timespec is private;
+
+ function To_Duration (TS : timespec) return Duration;
+ pragma Inline (To_Duration);
+
+ function To_Timespec (D : Duration) return timespec;
+ pragma Inline (To_Timespec);
+
+ type struct_timeval is private;
+
+ function To_Duration (TV : struct_timeval) return Duration;
+ pragma Inline (To_Duration);
+
+ function To_Timeval (D : Duration) return struct_timeval;
+ pragma Inline (To_Timeval);
+
+ function gettimeofday
+ (tv : access struct_timeval;
+ tz : System.Address := System.Null_Address) return int;
+ pragma Import (C, gettimeofday, "gettimeofday");
+
+ function sysconf (name : int) return long;
+ pragma Import (C, sysconf);
+
+ SC_CLK_TCK : constant := 2;
+
+ -------------------------
+ -- Priority Scheduling --
+ -------------------------
+
+ SCHED_OTHER : constant := 0;
+ SCHED_FIFO : constant := 1;
+ SCHED_RR : constant := 2;
+
+ -------------
+ -- Process --
+ -------------
+
+ type pid_t is private;
+
+ function kill (pid : pid_t; sig : Signal) return int;
+ pragma Import (C, kill, "kill");
+
+ function getpid return pid_t;
+ pragma Import (C, getpid, "getpid");
+
+ -------------
+ -- Threads --
+ -------------
+
+ type Thread_Body is access
+ function (arg : System.Address) return System.Address;
+
+ function Thread_Body_Access is new
+ Unchecked_Conversion (System.Address, Thread_Body);
+
+ type pthread_t is new unsigned_long;
+ subtype Thread_Id is pthread_t;
+
+ function To_pthread_t is new Unchecked_Conversion
+ (unsigned_long, pthread_t);
+
+ type pthread_mutex_t is limited private;
+ type pthread_cond_t is limited private;
+ type pthread_attr_t is limited private;
+ type pthread_mutexattr_t is limited private;
+ type pthread_condattr_t is limited private;
+ type pthread_key_t is private;
+
+ PTHREAD_CREATE_DETACHED : constant := 1;
+
+ -----------
+ -- Stack --
+ -----------
+
+ function Get_Stack_Base (thread : pthread_t) return Address;
+ pragma Inline (Get_Stack_Base);
+ -- This is a dummy procedure to share some GNULLI files
+
+ ---------------------------------------
+ -- Nonstandard Thread Initialization --
+ ---------------------------------------
+
+ procedure pthread_init;
+ pragma Inline (pthread_init);
+ -- This is a dummy procedure to share some GNULLI files
+
+ -------------------------
+ -- POSIX.1c Section 3 --
+ -------------------------
+
+ function sigwait (set : access sigset_t; sig : access Signal) return int;
+ pragma Import (C, sigwait, "sigwait");
+
+ function pthread_kill (thread : pthread_t; sig : Signal) return int;
+ pragma Import (C, pthread_kill, "pthread_kill");
+
+ type sigset_t_ptr is access all sigset_t;
+
+ function pthread_sigmask
+ (how : int;
+ set : sigset_t_ptr;
+ oset : sigset_t_ptr) return int;
+ pragma Import (C, pthread_sigmask, "pthread_sigmask");
+
+ --------------------------
+ -- POSIX.1c Section 11 --
+ --------------------------
+
+ function pthread_mutexattr_init
+ (attr : access pthread_mutexattr_t) return int;
+ pragma Import (C, pthread_mutexattr_init, "pthread_mutexattr_init");
+
+ function pthread_mutexattr_destroy
+ (attr : access pthread_mutexattr_t) return int;
+ pragma Import (C, pthread_mutexattr_destroy, "pthread_mutexattr_destroy");
+
+ function pthread_mutex_init
+ (mutex : access pthread_mutex_t;
+ attr : access pthread_mutexattr_t) return int;
+ pragma Import (C, pthread_mutex_init, "pthread_mutex_init");
+
+ function pthread_mutex_destroy (mutex : access pthread_mutex_t) return int;
+ pragma Import (C, pthread_mutex_destroy, "pthread_mutex_destroy");
+
+ function pthread_mutex_lock (mutex : access pthread_mutex_t) return int;
+ pragma Import (C, pthread_mutex_lock, "pthread_mutex_lock");
+
+ function pthread_mutex_unlock (mutex : access pthread_mutex_t) return int;
+ pragma Import (C, pthread_mutex_unlock, "pthread_mutex_unlock");
+
+ function pthread_condattr_init
+ (attr : access pthread_condattr_t) return int;
+ pragma Import (C, pthread_condattr_init, "pthread_condattr_init");
+
+ function pthread_condattr_destroy
+ (attr : access pthread_condattr_t) return int;
+ pragma Import (C, pthread_condattr_destroy, "pthread_condattr_destroy");
+
+ function pthread_cond_init
+ (cond : access pthread_cond_t;
+ attr : access pthread_condattr_t) return int;
+ pragma Import (C, pthread_cond_init, "pthread_cond_init");
+
+ function pthread_cond_destroy (cond : access pthread_cond_t) return int;
+ pragma Import (C, pthread_cond_destroy, "pthread_cond_destroy");
+
+ function pthread_cond_signal (cond : access pthread_cond_t) return int;
+ pragma Import (C, pthread_cond_signal, "pthread_cond_signal");
+
+ function pthread_cond_wait
+ (cond : access pthread_cond_t;
+ mutex : access pthread_mutex_t) return int;
+ pragma Import (C, pthread_cond_wait, "pthread_cond_wait");
+
+ function pthread_cond_timedwait
+ (cond : access pthread_cond_t;
+ mutex : access pthread_mutex_t;
+ abstime : access timespec) return int;
+ pragma Import (C, pthread_cond_timedwait, "pthread_cond_timedwait");
+
+ --------------------------
+ -- POSIX.1c Section 13 --
+ --------------------------
+
+ type struct_sched_param is record
+ sched_priority : int; -- scheduling priority
+ end record;
+ pragma Convention (C, struct_sched_param);
+
+ function pthread_setschedparam
+ (thread : pthread_t;
+ policy : int;
+ param : access struct_sched_param) return int;
+ pragma Import (C, pthread_setschedparam, "pthread_setschedparam");
+
+ function pthread_attr_setschedpolicy
+ (attr : access pthread_attr_t;
+ policy : int) return int;
+ pragma Import
+ (C, pthread_attr_setschedpolicy, "pthread_attr_setschedpolicy");
+
+ function sched_yield return int;
+ pragma Import (C, sched_yield, "sched_yield");
+
+ ---------------------------
+ -- P1003.1c - Section 16 --
+ ---------------------------
+
+ function pthread_attr_init
+ (attributes : access pthread_attr_t) return int;
+ pragma Import (C, pthread_attr_init, "pthread_attr_init");
+
+ function pthread_attr_destroy
+ (attributes : access pthread_attr_t) return int;
+ pragma Import (C, pthread_attr_destroy, "pthread_attr_destroy");
+
+ function pthread_attr_setdetachstate
+ (attr : access pthread_attr_t;
+ detachstate : int) return int;
+ pragma Import
+ (C, pthread_attr_setdetachstate, "pthread_attr_setdetachstate");
+
+ function pthread_attr_setstacksize
+ (attr : access pthread_attr_t;
+ stacksize : size_t) return int;
+ pragma Import (C, pthread_attr_setstacksize, "pthread_attr_setstacksize");
+
+ function pthread_create
+ (thread : access pthread_t;
+ attributes : access pthread_attr_t;
+ start_routine : Thread_Body;
+ arg : System.Address) return int;
+ pragma Import (C, pthread_create, "pthread_create");
+
+ procedure pthread_exit (status : System.Address);
+ pragma Import (C, pthread_exit, "pthread_exit");
+
+ function pthread_self return pthread_t;
+ pragma Import (C, pthread_self, "pthread_self");
+
+ --------------------------
+ -- POSIX.1c Section 17 --
+ --------------------------
+
+ function pthread_setspecific
+ (key : pthread_key_t;
+ value : System.Address) return int;
+ pragma Import (C, pthread_setspecific, "pthread_setspecific");
+
+ function pthread_getspecific (key : pthread_key_t) return System.Address;
+ pragma Import (C, pthread_getspecific, "pthread_getspecific");
+
+ type destructor_pointer is access procedure (arg : System.Address);
+
+ function pthread_key_create
+ (key : access pthread_key_t;
+ destructor : destructor_pointer) return int;
+ pragma Import (C, pthread_key_create, "pthread_key_create");
+
+private
+
+ type sigset_t is array (0 .. 31) of unsigned_long;
+ pragma Convention (C, sigset_t);
+
+ type pid_t is new int;
+
+ type time_t is new long;
+
+ type timespec is record
+ tv_sec : time_t;
+ tv_nsec : long;
+ end record;
+ pragma Convention (C, timespec);
+
+ type struct_timeval is record
+ tv_sec : time_t;
+ tv_usec : time_t;
+ end record;
+ pragma Convention (C, struct_timeval);
+
+ type pthread_attr_t is record
+ detachstate : int;
+ schedpolicy : int;
+ schedparam : struct_sched_param;
+ inheritsched : int;
+ scope : int;
+ guardsize : size_t;
+ stackaddr_set : int;
+ stackaddr : System.Address;
+ stacksize : size_t;
+ end record;
+ pragma Convention (C, pthread_attr_t);
+
+ type pthread_condattr_t is record
+ dummy : int;
+ end record;
+ pragma Convention (C, pthread_condattr_t);
+
+ type pthread_mutexattr_t is record
+ mutexkind : int;
+ end record;
+ pragma Convention (C, pthread_mutexattr_t);
+
+ type lock_array is array (1 .. 4) of int;
+ type atomic_lock_t is record
+ lock : lock_array;
+ end record;
+ pragma Convention (C, atomic_lock_t);
+ for atomic_lock_t'Alignment use 8 * 16;
+
+ type struct_pthread_fast_lock is record
+ spinlock : atomic_lock_t;
+ status : long;
+ end record;
+ pragma Convention (C, struct_pthread_fast_lock);
+
+ type pthread_mutex_t is record
+ m_reserved : int;
+ m_count : int;
+ m_owner : System.Address;
+ m_kind : int;
+ m_lock : struct_pthread_fast_lock;
+ end record;
+ pragma Convention (C, pthread_mutex_t);
+
+ type pthread_cond_t is array (0 .. 47) of unsigned_char;
+ pragma Convention (C, pthread_cond_t);
+
+ type pthread_key_t is new unsigned;
+
+end System.OS_Interface;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-06 16:49 ` [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2) John David Anglin
@ 2005-04-29 10:27 ` Arnaud Charlet
2005-04-29 13:43 ` John David Anglin
2005-04-30 0:14 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Arnaud Charlet @ 2005-04-29 10:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> Here is take 2. The changes from the previous version are all to the
> file s-osinte-linux-hppa.ads:
BTW, I missed the approval of this patch, could you point me to the
email approving this change ?
> 1) Definition of struct_sigaction corrected,
> 2) Definition of SA_SIGINFO corrected,
> 3) sigset_t changed to array of unsigned_long.
Could you explain why you changed sigset_t definition ?
Also, the alignment for atomic_lock_t seems wrong to me: you are using
8 * 16, but the alignment is specified in *bytes*, not bits (a usual
confusion), so this value seems very high to me. Didn't you mean 16
instead ?
Thanks for checking.
Also, there are really too many undesirable duplications between
s-osinte-linux*.ads files, which is a maintenance issue, so I'd rather
see a clean up in this area (such as moving target specific bits such as
signal numbers in a separate file).
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 10:27 ` Arnaud Charlet
@ 2005-04-29 13:43 ` John David Anglin
2005-04-29 15:07 ` Arnaud Charlet
2005-04-30 0:14 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-04-29 13:43 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> BTW, I missed the approval of this patch, could you point me to the
> email approving this change ?
<http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00789.html>.
I'll try to reply to your other questions next week.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 13:43 ` John David Anglin
@ 2005-04-29 15:07 ` Arnaud Charlet
2005-04-29 15:19 ` John David Anglin
2005-04-29 23:41 ` Richard Henderson
0 siblings, 2 replies; 521+ messages in thread
From: Arnaud Charlet @ 2005-04-29 15:07 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> > BTW, I missed the approval of this patch, could you point me to the
> > email approving this change ?
>
> <http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00789.html>.
Well, that's not a very clear OK, since Geert was referring to the
system-hpux.ads patch only as far as I know, and not the tasking
specific part ;-)
Anyway, let's now sort what is checked in: fix the obvious errors,
and later address the unfortunate code duplication that has happened
now twice recently (for alpha-linux and hppa-linux).
Also, I haven't fully reviewed the other bits of your patch,
so there might be some other issues, to be double checked.
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 15:07 ` Arnaud Charlet
@ 2005-04-29 15:19 ` John David Anglin
2005-04-29 23:41 ` Richard Henderson
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2005-04-29 15:19 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> Anyway, let's now sort what is checked in: fix the obvious errors,
> and later address the unfortunate code duplication that has happened
> now twice recently (for alpha-linux and hppa-linux).
>
> Also, I haven't fully reviewed the other bits of your patch,
> so there might be some other issues, to be double checked.
Ok. I'll try to get to this as soon as possible. My DSL modem
failed this week and I'm waiting for a replacement.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 15:07 ` Arnaud Charlet
2005-04-29 15:19 ` John David Anglin
@ 2005-04-29 23:41 ` Richard Henderson
2005-05-01 22:52 ` Mark Mitchell
1 sibling, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2005-04-29 23:41 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: John David Anglin, gcc-patches, laurent
On Fri, Apr 29, 2005 at 04:44:05PM +0200, Arnaud Charlet wrote:
> Anyway, let's now sort what is checked in: fix the obvious errors,
> and later address the unfortunate code duplication that has happened
> now twice recently (for alpha-linux and hppa-linux).
One way to fix all of this would be to move libada out to the top level,
and use configure and/or generator programs that actually probe the
contents of /usr/include for the data.
Personally I don't think any other solution is in fact a solution.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 23:41 ` Richard Henderson
@ 2005-05-01 22:52 ` Mark Mitchell
2005-05-02 17:49 ` Florian Weimer
0 siblings, 1 reply; 521+ messages in thread
From: Mark Mitchell @ 2005-05-01 22:52 UTC (permalink / raw)
To: Richard Henderson; +Cc: Arnaud Charlet, John David Anglin, gcc-patches, laurent
Richard Henderson wrote:
> On Fri, Apr 29, 2005 at 04:44:05PM +0200, Arnaud Charlet wrote:
>
>>Anyway, let's now sort what is checked in: fix the obvious errors,
>>and later address the unfortunate code duplication that has happened
>>now twice recently (for alpha-linux and hppa-linux).
>
>
> One way to fix all of this would be to move libada out to the top level,
> and use configure and/or generator programs that actually probe the
> contents of /usr/include for the data.
>
> Personally I don't think any other solution is in fact a solution.
I agree. Ada should handle its runtime library just like the other
languages handle theirs.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
(916) 791-8304
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-01 22:52 ` Mark Mitchell
@ 2005-05-02 17:49 ` Florian Weimer
2005-05-02 18:54 ` Mark Mitchell
0 siblings, 1 reply; 521+ messages in thread
From: Florian Weimer @ 2005-05-02 17:49 UTC (permalink / raw)
To: Mark Mitchell
Cc: Richard Henderson, Arnaud Charlet, John David Anglin,
gcc-patches, laurent
* Mark Mitchell:
>> One way to fix all of this would be to move libada out to the top
>> level, and use configure and/or generator programs that actually
>> probe the contents of /usr/include for the data. Personally I
>> don't think any other solution is in fact a solution.
>
> I agree. Ada should handle its runtime library just like the other
> languages handle theirs.
Would it be acceptable to add a switch to the C front end to cause it
to dump the layout of struct definitions? This would simplify things
enormously. We could implement it without this feature, especially
for well-defined structs whose fields are known (but not their order
and sizes), but it's not very efficient when cross-compiling.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 17:49 ` Florian Weimer
@ 2005-05-02 18:54 ` Mark Mitchell
0 siblings, 0 replies; 521+ messages in thread
From: Mark Mitchell @ 2005-05-02 18:54 UTC (permalink / raw)
To: Florian Weimer
Cc: Richard Henderson, Arnaud Charlet, John David Anglin,
gcc-patches, laurent
Florian Weimer wrote:
> * Mark Mitchell:
>
>
>>>One way to fix all of this would be to move libada out to the top
>>>level, and use configure and/or generator programs that actually
>>>probe the contents of /usr/include for the data. Personally I
>>>don't think any other solution is in fact a solution.
>>
>>I agree. Ada should handle its runtime library just like the other
>>languages handle theirs.
>
>
> Would it be acceptable to add a switch to the C front end to cause it
> to dump the layout of struct definitions? This would simplify things
> enormously. We could implement it without this feature, especially
> for well-defined structs whose fields are known (but not their order
> and sizes), but it's not very efficient when cross-compiling.
Yes, but even better would be to add a switch that works in a
language-independent manner.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
(916) 791-8304
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-29 10:27 ` Arnaud Charlet
2005-04-29 13:43 ` John David Anglin
@ 2005-04-30 0:14 ` John David Anglin
2005-05-02 9:54 ` Arnaud Charlet
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-04-30 0:14 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> > 3) sigset_t changed to array of unsigned_long.
>
> Could you explain why you changed sigset_t definition ?
From bits/sigset.h:
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
> Also, the alignment for atomic_lock_t seems wrong to me: you are using
> 8 * 16, but the alignment is specified in *bytes*, not bits (a usual
> confusion), so this value seems very high to me. Didn't you mean 16
> instead ?
The required alignment is 16 bytes.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-04-30 0:14 ` John David Anglin
@ 2005-05-02 9:54 ` Arnaud Charlet
2005-05-02 13:40 ` John David Anglin
2005-06-13 1:33 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Arnaud Charlet @ 2005-05-02 9:54 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> > > 3) sigset_t changed to array of unsigned_long.
> >
> > Could you explain why you changed sigset_t definition ?
>
> >From bits/sigset.h:
>
> # define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
> typedef struct
> {
> unsigned long int __val[_SIGSET_NWORDS];
> } __sigset_t;
I understand that, but the previous code used an array of bytes explicitely
to share code between 32 and 64 bit platforms where typically Long_Integer'Size
is different. So unless the underlying structure/alignment is different,
I would stick to the previous definition.
You can check the size and alignment used by compiling the file with -gnatR3
> > Also, the alignment for atomic_lock_t seems wrong to me: you are using
> > 8 * 16, but the alignment is specified in *bytes*, not bits (a usual
> > confusion), so this value seems very high to me. Didn't you mean 16
> > instead ?
>
> The required alignment is 16 bytes.
So the alignment in the file is indeed wrong and should be 16 rather than
8 * 16
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 9:54 ` Arnaud Charlet
@ 2005-05-02 13:40 ` John David Anglin
2005-05-02 13:44 ` Arnaud Charlet
2005-06-13 1:33 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-05-02 13:40 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> > > Could you explain why you changed sigset_t definition ?
> >
> > >From bits/sigset.h:
> >
> > # define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
> > typedef struct
> > {
> > unsigned long int __val[_SIGSET_NWORDS];
> > } __sigset_t;
>
> I understand that, but the previous code used an array of bytes explicitely
> to share code between 32 and 64 bit platforms where typically Long_Integer'Size
> is different. So unless the underlying structure/alignment is different,
> I would stick to the previous definition.
One of the reasons that I changed the definition is the PA is big
endian. So, the bit masks won't work using bytes unless this is
taken into account.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 13:40 ` John David Anglin
@ 2005-05-02 13:44 ` Arnaud Charlet
2005-05-02 15:45 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Arnaud Charlet @ 2005-05-02 13:44 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> One of the reasons that I changed the definition is the PA is big
> endian. So, the bit masks won't work using bytes unless this is
> taken into account.
The sigset_t type is private on the Ada side, so there cannot be
bit masks done, this type is only used through function calls to C.
In other words, it's an opaque type as far as Ada is concerned.
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 13:44 ` Arnaud Charlet
@ 2005-05-02 15:45 ` John David Anglin
2005-05-02 15:48 ` Arnaud Charlet
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-05-02 15:45 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> > One of the reasons that I changed the definition is the PA is big
> > endian. So, the bit masks won't work using bytes unless this is
> > taken into account.
>
> The sigset_t type is private on the Ada side, so there cannot be
> bit masks done, this type is only used through function calls to C.
Then the details of the Ada definition don't matter as long as the
size and alignment are correct. Although a 64-bit hppa-linux runtime
doesn't exist yet, we are still stuck with the unsigned long int
type for the __val field. The alignment requirement for longs has
to be different in the 32 and 64-bit runtimes because of the strict
alignment requirements of the parisc architecture.
Thus, I would prefer to leave the Ada define as is.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 15:45 ` John David Anglin
@ 2005-05-02 15:48 ` Arnaud Charlet
2005-05-02 16:05 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Arnaud Charlet @ 2005-05-02 15:48 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> Then the details of the Ada definition don't matter as long as the
> size and alignment are correct.
Exactly. What matters is writing this definition so that it can,
as much as possible, be used on all linux platforms, hence my comments.
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 15:48 ` Arnaud Charlet
@ 2005-05-02 16:05 ` John David Anglin
2005-05-03 8:22 ` Arnaud Charlet
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-05-02 16:05 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> > Then the details of the Ada definition don't matter as long as the
> > size and alignment are correct.
>
> Exactly. What matters is writing this definition so that it can,
> as much as possible, be used on all linux platforms, hence my comments.
The definition in s-osinte-linux.ads would need to be modified to provide
4 and 8 byte alignment for the 32 and 64-bit hppa runtimes.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-05-02 9:54 ` Arnaud Charlet
2005-05-02 13:40 ` John David Anglin
@ 2005-06-13 1:33 ` John David Anglin
2005-06-13 6:31 ` Arnaud Charlet
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-06-13 1:33 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> You can check the size and alignment used by compiling the file with -gnatR3
It shows the wrong alignment.
> > > Also, the alignment for atomic_lock_t seems wrong to me: you are using
> > > 8 * 16, but the alignment is specified in *bytes*, not bits (a usual
> > > confusion), so this value seems very high to me. Didn't you mean 16
> > > instead ?
> >
> > The required alignment is 16 bytes.
>
> So the alignment in the file is indeed wrong and should be 16 rather than
> 8 * 16
Reducing the alignment to 16 causes an number of testsuite regressions.
Free is being called with a bad pointer. Here is an example:
Program received signal SIGSEGV, Segmentation fault.
0x409b979c in __libc_free (mem=0x67d60) at malloc.c:3348
3348 ar_ptr = arena_for_chunk(p);
(gdb) bt
#0 0x409b979c in __libc_free (mem=0x67d60) at malloc.c:3348
#1 0x0001da90 in <__gnat_free> (ptr=425312) at s-memory.adb:113
#2 0x0001f6f0 in system.task_primitives.operations.finalize_tcb (t=0x67d60)
at s-taprop.adb:907
#3 0x0003284c in system.tasking.stages.vulnerable_complete_master (self_id=Variable "self_id" is not available.
)
at s-tassta.adb:1563
#4 0x00035d2c in c41306b () at c41306b.adb:39
#5 0x000155d4 in main (argc=1, argv=3220178412, envp=3220178420)
at b~c41306b.adb:190
As far as I can tell, this region of memory was never allocated by
malloc but it's somehow a TCB being freed by
Breakpoint 11, system.tasking.stages.vulnerable_complete_master (self_id=Variable "self_id" is not available.
)
at s-tassta.adb:1563
1563 Vulnerable_Free_Task (T);
(gdb) p/x T
$93 = 0x67d60
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-06-13 1:33 ` John David Anglin
@ 2005-06-13 6:31 ` Arnaud Charlet
2005-06-13 14:16 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Arnaud Charlet @ 2005-06-13 6:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> > You can check the size and alignment used by compiling the file with -gnatR3
>
> It shows the wrong alignment.
Meaning ?
> Reducing the alignment to 16 causes an number of testsuite regressions.
> Free is being called with a bad pointer. Here is an example:
Well, that seems to be an unrelated bug that is being hidden by setting
a huge alignment, don't you think ?
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-06-13 6:31 ` Arnaud Charlet
@ 2005-06-13 14:16 ` John David Anglin
2005-06-13 15:22 ` Arnaud Charlet
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2005-06-13 14:16 UTC (permalink / raw)
To: Arnaud Charlet; +Cc: gcc-patches, laurent
> > Reducing the alignment to 16 causes an number of testsuite regressions.
> > Free is being called with a bad pointer. Here is an example:
>
> Well, that seems to be an unrelated bug that is being hidden by setting
> a huge alignment, don't you think ?
At this point, I'm not sure it's unrelated. The bug may be a locking
issue somehow affected by the alignment. When debugging, there was a
point where a certain set of breaks would allow successful execution
of the test.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2)
2005-06-13 14:16 ` John David Anglin
@ 2005-06-13 15:22 ` Arnaud Charlet
0 siblings, 0 replies; 521+ messages in thread
From: Arnaud Charlet @ 2005-06-13 15:22 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, laurent
> > Well, that seems to be an unrelated bug that is being hidden by setting
> > a huge alignment, don't you think ?
>
> At this point, I'm not sure it's unrelated. The bug may be a locking
> issue somehow affected by the alignment. When debugging, there was a
> point where a certain set of breaks would allow successful execution
> of the test.
In this case, it would mean that e.g. the alignment is greater than 16 bytes,
although this seems surprising that a C library would require a bigger
alignment.
Arno
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch]: Fix PR testsuite/23239
[not found] <no.id>
` (142 preceding siblings ...)
2005-04-06 16:49 ` [patch] Add Ada tasking support for hppa-unknown-linux-gnu (take 2) John David Anglin
@ 2005-08-20 16:15 ` John David Anglin
2005-12-07 0:52 ` fix post-weakref gthr-*.h on HP-UX (and others?) John David Anglin
` (19 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2005-08-20 16:15 UTC (permalink / raw)
To: John David Anglin; +Cc: wilson, gcc-patches
> Your investigation got me curious as to why ASM_PN_FORMAT is defined
> in pa.h. At the moment, it's not at all clear why the default in
> defaults.h isn't usable. Dots and dollars are allowed in labels.
Answering my own question, I find that gdb confuses private names
using the dot format with struct fields. Possibly, this is stabs
specific.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: fix post-weakref gthr-*.h on HP-UX (and others?)
[not found] <no.id>
` (143 preceding siblings ...)
2005-08-20 16:15 ` [patch]: Fix PR testsuite/23239 John David Anglin
@ 2005-12-07 0:52 ` John David Anglin
2006-01-17 4:54 ` [PING * 2] One line patch John David Anglin
` (18 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2005-12-07 0:52 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, aoliva
> > Index: gcc/ChangeLog
> > from Alexandre Oliva <aoliva@redhat.com>
> >
> > PR other/24829
Actually, I've found that the patch doesn't completely fix PR 24829
on hppa64-hp-hpux11.11. We still have the issue that we now need to
link against libpthread to resolve the pthread references introduced
by the original change adding weakref support to these files.
Executing on host: /test/gnu/gcc-3.3/objdir/gcc/xgcc -B/test/gnu/gcc-3.3/objdir/
gcc/ /test/gnu/gcc-3.3/gcc-4.1/gcc/testsuite/objc.dg/bitfield-1.m -I/test/gnu
/gcc-3.3/gcc-4.1/gcc/testsuite/../../libobjc -L/test/gnu/gcc-3.3/objdir/hppa64-h
p-hpux11.11/./libobjc/.libs -lobjc -lm -o ./bitfield-1.exe (timeout = 300)
ld: (Warning) Unsatisfied symbol "pthread_create" in file /test/gnu/gcc-3.3/objd
ir/hppa64-hp-hpux11.11/./libobjc/.libs/libobjc.sl
ld: (Warning) Unsatisfied symbol "pthread_attr_init" in file /test/gnu/gcc-3.3/o
bjdir/hppa64-hp-hpux11.11/./libobjc/.libs/libobjc.sl
2 warnings.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PING * 2] One line patch
[not found] <no.id>
` (144 preceding siblings ...)
2005-12-07 0:52 ` fix post-weakref gthr-*.h on HP-UX (and others?) John David Anglin
@ 2006-01-17 4:54 ` John David Anglin
2006-01-17 4:58 ` [committed] Fix PR target/20754: ACATS cxg1005 fails at runtime on hppa-linux John David Anglin
` (17 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2006-01-17 4:54 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> http://gcc.gnu.org/ml/gcc-patches/2005-12/msg00820.html
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix PR target/20754: ACATS cxg1005 fails at runtime on hppa-linux
[not found] <no.id>
` (145 preceding siblings ...)
2006-01-17 4:54 ` [PING * 2] One line patch John David Anglin
@ 2006-01-17 4:58 ` John David Anglin
2006-02-05 16:29 ` [committed] Fix PR target/25926: A87B59A SIGABRT John David Anglin
` (16 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2006-01-17 4:58 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2006-01-10 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
>
> PR target/20754
I've applied the following patch to fix a regression in code generation
caused by the fix for PR 20754. The register allocator was too often
choosing a floating-point register instead of a general register when
a general register.
Tested on hppa2.0w-hp-hpux11.11. Committed to 4.0 through to trunk.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2006-01-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.md: Disparage copies between general and floating-point registers
in 32-bit move patterns.
Index: config/pa/pa.md
===================================================================
--- config/pa/pa.md (revision 109740)
+++ config/pa/pa.md (working copy)
@@ -2307,9 +2307,9 @@
(define_insn ""
[(set (match_operand:SI 0 "move_dest_operand"
- "=r,r,r,r,r,r,Q,!*q,!r,!*f,*f,T,r,f")
+ "=r,r,r,r,r,r,Q,!*q,!r,!*f,*f,T,!r,!f")
(match_operand:SI 1 "move_src_operand"
- "A,r,J,N,K,RQ,rM,!rM,!*q,!*fM,RT,*f,f,r"))]
+ "A,r,J,N,K,RQ,rM,!rM,!*q,!*fM,RT,*f,!f,!r"))]
"(register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))
&& !TARGET_SOFT_FLOAT
@@ -3869,9 +3869,9 @@
(define_insn ""
[(set (match_operand:DF 0 "move_dest_operand"
- "=f,*r,Q,?o,?Q,f,*r,*r,r,f")
+ "=f,*r,Q,?o,?Q,f,*r,*r,!r,!f")
(match_operand:DF 1 "reg_or_0_or_nonsymb_mem_operand"
- "fG,*rG,f,*r,*r,RQ,o,RQ,f,r"))]
+ "fG,*rG,f,*r,*r,RQ,o,RQ,!f,!r"))]
"(register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))
&& !(GET_CODE (operands[1]) == CONST_DOUBLE
@@ -4043,9 +4043,9 @@
(define_insn ""
[(set (match_operand:DF 0 "move_dest_operand"
- "=r,?o,?Q,r,r,r,f")
+ "=r,?o,?Q,r,r,!r,!f")
(match_operand:DF 1 "reg_or_0_or_nonsymb_mem_operand"
- "rG,r,r,o,RQ,f,r"))]
+ "rG,r,r,o,RQ,!f,!r"))]
"(register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))
&& !TARGET_64BIT
@@ -4185,9 +4185,9 @@
(define_insn ""
[(set (match_operand:DI 0 "move_dest_operand"
- "=r,o,Q,r,r,r,*f,*f,T,r,f")
+ "=r,o,Q,r,r,r,*f,*f,T,!r,!f")
(match_operand:DI 1 "general_operand"
- "rM,r,r,o*R,Q,i,*fM,RT,*f,f,r"))]
+ "rM,r,r,o*R,Q,i,*fM,RT,*f,!f,!r"))]
"(register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))
&& !TARGET_64BIT
@@ -4414,9 +4414,9 @@
(define_insn ""
[(set (match_operand:SF 0 "move_dest_operand"
- "=f,!*r,f,*r,Q,Q,r,f")
+ "=f,!*r,f,*r,Q,Q,!r,!f")
(match_operand:SF 1 "reg_or_0_or_nonsymb_mem_operand"
- "fG,!*rG,RQ,RQ,f,*rG,f,r"))]
+ "fG,!*rG,RQ,RQ,f,*rG,!f,!r"))]
"(register_operand (operands[0], SFmode)
|| reg_or_0_operand (operands[1], SFmode))
&& !TARGET_SOFT_FLOAT
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix PR target/25926: A87B59A SIGABRT
[not found] <no.id>
` (146 preceding siblings ...)
2006-01-17 4:58 ` [committed] Fix PR target/20754: ACATS cxg1005 fails at runtime on hppa-linux John David Anglin
@ 2006-02-05 16:29 ` John David Anglin
2006-11-18 18:11 ` Ping: [PATCH] Limit precision of *bitsizetypes types John David Anglin
` (15 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2006-02-05 16:29 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The attached change fixes PR target/25926. As noted in the PR, __main ()
> now needs to be called when using Ada on HP-UX 10 to initialize the EH tables,
> as is done for C and C++.
>
> Tested on hppa1.1-hp-hpux10.20:
> http://gcc.gnu.org/ml/gcc-testresults/2006-02/msg00150.html.
The previous change failed on hpux11. The "ifeq" didn't work.
I've reworked the change using separate t- and x- files for hpux10
and hpux11. I did some rearrangement of rules and defines, placing
common hpux defines and rules in t-pa-hpux. t-pa is nolonger used
on hpux, so I removed the quadlib.c rule that is only needed for
hpux.
Tested on hppa64-hp-hpux11.11, hppa2.0w-hp-hpux11.11 and
hppa-unknown-linux-gnu. Test in progress on hppa1.1-hp-hpux10.20.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2006-02-05 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa/x-ada-hpux10, pa/t-pa-hpux10, pa/t-pa-hpux11: New files.
* config.gcc (hppa[12]*-*-hpux10*): Use pa/t-pa-hpux10 instead of
pa/t-pa.
* config.gcc (hppa[12]*-*-hpux11*): Use pa/t-pa-hpux11 instead of
pa/t-pa.
* config.host (hppa*-*-hpux10*): Use pa/x-ada-hpux10 instead of
pa/x-ada.
* pa/t-pa-hpux: Add lib2funcs.asm and quadlib.c rules.
* pa/t-pa64: Delete quadlib.c rule.
* pa/x-ada: Revert last change.
* pa/t-pa: Revert last change. Delete quadlib.c rule.
--- /dev/null Sat Feb 4 17:27:15 2006
+++ config/pa/x-ada-hpux10 Sat Feb 4 17:08:11 2006
@@ -0,0 +1,4 @@
+# The ada virtual array implementation requires that indexing be disabled on
+# hosts such as hpux that use a segmented memory architecture. Both the c
+# and ada files need to be compiled with this option for correct operation.
+X_ADA_CFLAGS = -mdisable-indexing -D_X_HPUX10
--- /dev/null Sat Feb 4 17:27:15 2006
+++ config/pa/t-pa-hpux10 Sat Feb 4 17:29:22 2006
@@ -0,0 +1,2 @@
+TARGET_LIBGCC2_CFLAGS = -fPIC -D_T_HPUX10
+LIB2FUNCS_EXTRA=lib2funcs.asm quadlib.c
--- /dev/null Sat Feb 4 17:27:15 2006
+++ config/pa/t-pa-hpux11 Sat Feb 4 17:29:35 2006
@@ -0,0 +1,2 @@
+TARGET_LIBGCC2_CFLAGS = -fPIC
+LIB2FUNCS_EXTRA=lib2funcs.asm quadlib.c
Index: config.gcc
===================================================================
--- config.gcc (revision 110593)
+++ config.gcc (working copy)
@@ -890,7 +890,7 @@
extra_options="${extra_options} pa/pa-hpux1010.opt"
;;
esac
- tmake_file="pa/t-pa pa/t-pa-hpux pa/t-hpux-shlib"
+ tmake_file="pa/t-pa-hpux10 pa/t-pa-hpux pa/t-hpux-shlib"
case ${enable_threads} in
"")
if test x$have_pthread_h = xyes ; then
@@ -967,7 +967,7 @@
extra_options="${extra_options} pa/pa-hpux1111.opt"
;;
esac
- tmake_file="pa/t-pa pa/t-pa-hpux pa/t-hpux-shlib"
+ tmake_file="pa/t-pa-hpux11 pa/t-pa-hpux pa/t-hpux-shlib"
# Set the libgcc version number
if test x$sjlj = x1; then
tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver"
Index: config.host
===================================================================
--- config.host (revision 110593)
+++ config.host (working copy)
@@ -119,7 +119,10 @@
hppa1.1-*-bsd*)
host_xmake_file="pa/x-ada"
;;
- hppa1.0-*-hpux10* | hppa1.1-*-hpux10* | hppa2*-*-hpux10* | \
+ hppa1.0-*-hpux10* | hppa1.1-*-hpux10* | hppa2*-*-hpux10*)
+ out_host_hook_obj=host-hpux.o
+ host_xmake_file="pa/x-ada-hpux10 x-hpux"
+ ;;
hppa1.0-*-hpux11* | hppa1.1-*-hpux11* | hppa2*-*-hpux11* | \
hppa*64*-*-hpux11*)
out_host_hook_obj=host-hpux.o
Index: config/pa/t-pa-hpux
===================================================================
--- config/pa/t-pa-hpux (revision 110593)
+++ config/pa/t-pa-hpux (working copy)
@@ -1,2 +1,10 @@
# So putenv and other functions get seen by fixproto.
FIXPROTO_DEFINES = -D_HPUX_SOURCE -D_HIUX_SOURCE
+
+lib2funcs.asm: $(srcdir)/config/pa/lib2funcs.asm
+ rm -f lib2funcs.asm
+ cp $(srcdir)/config/pa/lib2funcs.asm .
+
+quadlib.c: $(srcdir)/config/pa/quadlib.c
+ rm -f quadlib.c
+ cp $(srcdir)/config/pa/quadlib.c .
Index: config/pa/t-pa64
===================================================================
--- config/pa/t-pa64 (revision 110593)
+++ config/pa/t-pa64 (working copy)
@@ -1,10 +1,2 @@
TARGET_LIBGCC2_CFLAGS = -fPIC -Dpa64=1 -DELF=1 -mlong-calls
-
LIB2FUNCS_EXTRA=quadlib.c
-
-# We'll need this once .init sections are enabled on PA64.
-#EXTRA_PARTS = crtbegin.o crtend.o
-
-quadlib.c: $(srcdir)/config/pa/quadlib.c
- rm -f quadlib.c
- cp $(srcdir)/config/pa/quadlib.c .
Index: config/pa/x-ada
===================================================================
--- config/pa/x-ada (revision 110593)
+++ config/pa/x-ada (working copy)
@@ -1,10 +1,4 @@
# The ada virtual array implementation requires that indexing be disabled on
# hosts such as hpux that use a segmented memory architecture. Both the c
# and ada files need to be compiled with this option for correct operation.
-# On HP-UX 10 hosts, we define _X_HPUX10 to cause __main () to be called at
-# startup.
-ifeq ($(strip $(filter-out hppa% hp hpux10%,$(targ))),)
- X_ADA_CFLAGS = -mdisable-indexing -D_X_HPUX10
-else
- X_ADA_CFLAGS = -mdisable-indexing
-endif
+X_ADA_CFLAGS=-mdisable-indexing
Index: config/pa/t-pa
===================================================================
--- config/pa/t-pa (revision 110593)
+++ config/pa/t-pa (working copy)
@@ -1,15 +1,7 @@
-LIB2FUNCS_EXTRA=lib2funcs.asm quadlib.c
+TARGET_LIBGCC2_CFLAGS = -fPIC
+LIB2FUNCS_EXTRA=lib2funcs.asm
+
lib2funcs.asm: $(srcdir)/config/pa/lib2funcs.asm
rm -f lib2funcs.asm
cp $(srcdir)/config/pa/lib2funcs.asm .
-
-quadlib.c: $(srcdir)/config/pa/quadlib.c
- rm -f quadlib.c
- cp $(srcdir)/config/pa/quadlib.c .
-
-ifeq ($(strip $(filter-out hppa% hp hpux10%,$(targ))),)
- TARGET_LIBGCC2_CFLAGS = -fPIC -D_T_HPUX10
-else
- TARGET_LIBGCC2_CFLAGS = -fPIC
-endif
^ permalink raw reply [flat|nested] 521+ messages in thread
* Ping: [PATCH] Limit precision of *bitsizetypes types
[not found] <no.id>
` (147 preceding siblings ...)
2006-02-05 16:29 ` [committed] Fix PR target/25926: A87B59A SIGABRT John David Anglin
@ 2006-11-18 18:11 ` John David Anglin
2006-11-18 21:47 ` Roger Sayle
2007-01-25 23:55 ` [PATCH, commited] PR other/30182, Fix __builtin_finite on HP-UX John David Anglin
` (14 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2006-11-18 18:11 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
Small patch to stor-layout.c:
<http://gcc.gnu.org/ml/gcc-patches/2006-10/msg01522.html>.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Ping: [PATCH] Limit precision of *bitsizetypes types
2006-11-18 18:11 ` Ping: [PATCH] Limit precision of *bitsizetypes types John David Anglin
@ 2006-11-18 21:47 ` Roger Sayle
2006-11-18 21:51 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Roger Sayle @ 2006-11-18 21:47 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Sat, 18 Nov 2006, John David Anglin wrote:
> Small patch to stor-layout.c:
> <http://gcc.gnu.org/ml/gcc-patches/2006-10/msg01522.html>.
Sorry for the delay. This is OK for mainline.
Thanks for fixing this.
Do you have any opinions on the use of nested MIN/MAX macros? Whilst
as long as the arguments are side-effect free, we'll produce valid code,
it may result in significant (temporary) code duplication caused by
macro expansion.
Perhaps:
precision = MIN (precision, MAX_FIXED_MODE_SIZE);
or
if (precision > MAX_FIXED_MODE_SIZE)
precision = MAX_FIXED_MODE_SIZE;
which I think might be easier to read for some people, and may be easier
for the compiler to recognize as a pair on MIN_EXPRs. Or perhaps
reassociate to use "MIN (MAX_FIXED_MODE_SIZE, 2 * HOST_BITS_PER_WIDE_INT)"
which should be a compile-time constant?
Oh, I don't know. The code is perfectly fine as it is. I suspect I'm
beginning to view things far too much from fold's perspective, and such
micro-optimizations are meaningless to the GCC big picture.
Ok for mainline.
Roger
--
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH, commited] PR other/30182, Fix __builtin_finite on HP-UX
[not found] <no.id>
` (148 preceding siblings ...)
2006-11-18 18:11 ` Ping: [PATCH] Limit precision of *bitsizetypes types John David Anglin
@ 2007-01-25 23:55 ` John David Anglin
2007-01-26 0:58 ` Steve Ellcey
2007-02-28 10:53 ` [committed] Fix bug target/30634 John David Anglin
` (13 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2007-01-25 23:55 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches
> > Should we create a TARGET_HPUX_11 or TARGET_HPUX_11_00 macro to use
> > for this? We could put it in config/pa/pa-hpux11.h. Do you have a
> > name preference?
>
> I like TARGET_HPUX_11 in pa-hpux11.h.
Oh, to mirror the way the other TARGET_HPUX macros are handled, the
macro should also be defined to 0 in pa.h.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH, commited] PR other/30182, Fix __builtin_finite on HP-UX
2007-01-25 23:55 ` [PATCH, commited] PR other/30182, Fix __builtin_finite on HP-UX John David Anglin
@ 2007-01-26 0:58 ` Steve Ellcey
0 siblings, 0 replies; 521+ messages in thread
From: Steve Ellcey @ 2007-01-26 0:58 UTC (permalink / raw)
To: dave; +Cc: gcc-patches
> > I like TARGET_HPUX_11 in pa-hpux11.h.
>
> Oh, to mirror the way the other TARGET_HPUX macros are handled, the
> macro should also be defined to 0 in pa.h.
Here is the patch I am testing (on 11.11), does it look OK to you?
Steve Ellcey
sje@cup.hp.com
2007-01-25 Steve Ellcey <sje@cup.hp.com>
PR other/30182
* config/pa/pa.h (TARGET_HPUX_11): New.
* config/pa/pa-hpux11.h (TARGET_HPUX_11): New.
* config/pa/pa.c (pa_init_builtins): Use TARGET_HPUX_11.
Index: pa.h
===================================================================
--- pa.h (revision 121157)
+++ pa.h (working copy)
@@ -84,6 +84,11 @@ extern int flag_pa_unix;
#define TARGET_HPUX_10_10 0
#endif
+/* HP-UX 11.* features (11.00, 11.11, 11.23, etc.) */
+#ifndef TARGET_HPUX_11
+#define TARGET_HPUX_11 0
+#endif
+
/* HP-UX 11i multibyte and UNIX 98 extensions. */
#ifndef TARGET_HPUX_11_11
#define TARGET_HPUX_11_11 0
Index: pa-hpux11.h
===================================================================
--- pa-hpux11.h (revision 121157)
+++ pa-hpux11.h (working copy)
@@ -191,3 +191,6 @@ Boston, MA 02110-1301, USA. */
with secondary definition (weak) symbols. */
#undef TARGET_SOM_SDEF
#define TARGET_SOM_SDEF 1
+
+#undef TARGET_HPUX_11
+#define TARGET_HPUX_11 1
Index: pa.c
===================================================================
--- pa.c (revision 121178)
+++ pa.c (working copy)
@@ -512,7 +512,7 @@ pa_init_builtins (void)
implicit_built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED]
= implicit_built_in_decls[(int) BUILT_IN_PUTC_UNLOCKED];
#endif
-#if TARGET_HPUX
+#if TARGET_HPUX_11
if (built_in_decls [BUILT_IN_FINITE])
set_user_assembler_name (built_in_decls [BUILT_IN_FINITE], "_Isfinite");
if (built_in_decls [BUILT_IN_FINITEF])
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix bug target/30634
[not found] <no.id>
` (149 preceding siblings ...)
2007-01-25 23:55 ` [PATCH, commited] PR other/30182, Fix __builtin_finite on HP-UX John David Anglin
@ 2007-02-28 10:53 ` John David Anglin
2007-03-17 0:31 ` [committed] Fix long local calls on PA HP-UX SOM target John David Anglin
` (12 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-02-28 10:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> Tested on hppa64-hp-hpux11.11 with no regressions.
Unfortunately, I somehow missed in testing that the 64-bit DFmode
move pattern contained bugs and didn't actually support a zero
CONST_DOUBLE as a source operand as intended. The enclosed change
corrects this deficiency.
Tested on hppa64-hp-hpux11.11 and hppa-unknown-linux-gnu with no
observed regressions. Committed to 4.1, 4.2 and trunk.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-02-27 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa/predicates.md (move_src_operand): Allow zero for mode.
* pa/pa.md: Fix constraints for zero CONST_DOUBLE in 64-bit DFmode
move pattern.
Index: config/pa/predicates.md
===================================================================
--- config/pa/predicates.md (revision 122374)
+++ config/pa/predicates.md (working copy)
@@ -207,11 +207,14 @@
;; instruction.
(define_predicate "move_src_operand"
- (match_code "subreg,reg,const_int,mem")
+ (match_code "subreg,reg,const_int,const_double,mem")
{
if (register_operand (op, mode))
return 1;
+ if (op == CONST0_RTX (mode))
+ return 1;
+
if (GET_CODE (op) == CONST_INT)
return cint_ok_for_move (INTVAL (op));
Index: config/pa/pa.md
===================================================================
--- config/pa/pa.md (revision 122374)
+++ config/pa/pa.md (working copy)
@@ -4343,7 +4343,7 @@
[(set (match_operand:DF 0 "move_dest_operand"
"=!*r,*r,*r,*r,*r,Q,f,f,T")
(match_operand:DF 1 "move_src_operand"
- "!*r,J,N,K,RQ,*rM,fM,RT,f"))]
+ "!*r,J,N,K,RQ,*rG,fG,RT,f"))]
"(register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))
&& !TARGET_SOFT_FLOAT && TARGET_64BIT"
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix long local calls on PA HP-UX SOM target
[not found] <no.id>
` (150 preceding siblings ...)
2007-02-28 10:53 ` [committed] Fix bug target/30634 John David Anglin
@ 2007-03-17 0:31 ` John David Anglin
2007-08-27 2:07 ` [patch,testsuite] Fix PR testsuite/33153 John David Anglin
` (11 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-03-17 0:31 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> To fix this, we need to use the "LONG_PIC_SDIFF" sequence which uses
> a difference of labels. GAS does handle this correctly.
Sigh, I messed up on this one. GAS does *not* handle local calls using
this sequence.
Tested on hppa2.0w-hp-hpux11.11 and hppa-unknown-linux-gnu.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-03-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.c (attr_length_call): Partially revert change of 2007-03-09.
(output_call): Likewise.
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c (revision 122960)
+++ config/pa/pa.c (working copy)
@@ -7271,7 +7271,7 @@
length += 12;
/* long pc-relative branch sequence. */
- else if ((TARGET_SOM && (TARGET_LONG_PIC_SDIFF_CALL || local_call))
+ else if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
|| (TARGET_64BIT && !TARGET_GAS)
|| (TARGET_GAS && !TARGET_SOM
&& (TARGET_LONG_PIC_PCREL_CALL || local_call)))
@@ -7384,7 +7384,7 @@
of increasing length and complexity. In most cases,
they don't allow an instruction in the delay slot. */
if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
- && !(TARGET_SOM && (TARGET_LONG_PIC_SDIFF_CALL || local_call))
+ && !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
&& !(TARGET_GAS && !TARGET_SOM
&& (TARGET_LONG_PIC_PCREL_CALL || local_call))
&& !TARGET_64BIT)
@@ -7432,7 +7432,7 @@
}
else
{
- if ((TARGET_SOM && (TARGET_LONG_PIC_SDIFF_CALL || local_call))
+ if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
|| (TARGET_64BIT && !TARGET_GAS))
{
/* The HP assembler and linker can handle relocations
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch,testsuite] Fix PR testsuite/33153
[not found] <no.id>
` (151 preceding siblings ...)
2007-03-17 0:31 ` [committed] Fix long local calls on PA HP-UX SOM target John David Anglin
@ 2007-08-27 2:07 ` John David Anglin
2007-08-27 8:56 ` Jakub Jelinek
2007-09-16 9:20 ` ping: [PATCH] Fix PR middle-end/33273 John David Anglin
` (10 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2007-08-27 2:07 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jakub
> Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
Hmmm, it appears that I didn't look at the results for hppa64-hp-hpux11.11
carefully enough as pr32912-2.c still fails. However, it's not for the
reason addressed by the proposed change. The function foo is miscompiled.
In looking at pr32912-2.c, I noticed that a, b, c, d, e and f are
not used, so I would like to revise my last patch.
Ok?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-08-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR testsuite/33153
* gcc.dg/pr32912-1.c: Make declaration of a, b, c, d, e and f static.
* gcc.dg/pr32912-2.c: Delete declaration of a, b, c, d, e and f.
Index: gcc.dg/pr32912-1.c
===================================================================
--- gcc.dg/pr32912-1.c (revision 127802)
+++ gcc.dg/pr32912-1.c (working copy)
@@ -6,7 +6,7 @@
typedef int __m128i __attribute__ ((__vector_size__ (16)));
-__m128i a, b, c, d, e, f;
+static __m128i a, b, c, d, e, f;
void
foo (__m128i x)
Index: gcc.dg/pr32912-2.c
===================================================================
--- gcc.dg/pr32912-2.c (revision 127802)
+++ gcc.dg/pr32912-2.c (working copy)
@@ -5,8 +5,6 @@
typedef int __m128i __attribute__ ((__vector_size__ (16)));
-__m128i a, b, c, d, e, f;
-
__m128i
foo (void)
{
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch,testsuite] Fix PR testsuite/33153
2007-08-27 2:07 ` [patch,testsuite] Fix PR testsuite/33153 John David Anglin
@ 2007-08-27 8:56 ` Jakub Jelinek
2007-08-28 5:31 ` John David Anglin
2007-09-13 2:28 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Jakub Jelinek @ 2007-08-27 8:56 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
On Sun, Aug 26, 2007 at 07:00:51PM -0400, John David Anglin wrote:
> > Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
>
> Hmmm, it appears that I didn't look at the results for hppa64-hp-hpux11.11
> carefully enough as pr32912-2.c still fails. However, it's not for the
> reason addressed by the proposed change. The function foo is miscompiled.
>
> In looking at pr32912-2.c, I noticed that a, b, c, d, e and f are
> not used, so I would like to revise my last patch.
Both changes look ok to me, the latter is certainly obvious.
For the first you could alternatively try __attribute__((nocommon)),
though I wonder if pa/hpux shouldn't do that automatically for objects
which it can't create as common, perhaps with some warning.
> 2007-08-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
>
> PR testsuite/33153
> * gcc.dg/pr32912-1.c: Make declaration of a, b, c, d, e and f static.
> * gcc.dg/pr32912-2.c: Delete declaration of a, b, c, d, e and f.
>
> Index: gcc.dg/pr32912-1.c
> ===================================================================
> --- gcc.dg/pr32912-1.c (revision 127802)
> +++ gcc.dg/pr32912-1.c (working copy)
> @@ -6,7 +6,7 @@
>
> typedef int __m128i __attribute__ ((__vector_size__ (16)));
>
> -__m128i a, b, c, d, e, f;
> +static __m128i a, b, c, d, e, f;
>
> void
> foo (__m128i x)
> Index: gcc.dg/pr32912-2.c
> ===================================================================
> --- gcc.dg/pr32912-2.c (revision 127802)
> +++ gcc.dg/pr32912-2.c (working copy)
> @@ -5,8 +5,6 @@
>
> typedef int __m128i __attribute__ ((__vector_size__ (16)));
>
> -__m128i a, b, c, d, e, f;
> -
> __m128i
> foo (void)
> {
Jakub
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch,testsuite] Fix PR testsuite/33153
2007-08-27 8:56 ` Jakub Jelinek
@ 2007-08-28 5:31 ` John David Anglin
2007-09-13 2:28 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-08-28 5:31 UTC (permalink / raw)
To: jakub; +Cc: gcc-patches
> For the first you could alternatively try __attribute__((nocommon)),
> though I wonder if pa/hpux shouldn't do that automatically for objects
> which it can't create as common, perhaps with some warning.
It looks like bss_initializer_p() would need to be modified to support
this, or is there some other way?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [patch,testsuite] Fix PR testsuite/33153
2007-08-27 8:56 ` Jakub Jelinek
2007-08-28 5:31 ` John David Anglin
@ 2007-09-13 2:28 ` John David Anglin
2007-09-13 5:45 ` Mark Mitchell
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2007-09-13 2:28 UTC (permalink / raw)
To: jakub; +Cc: gcc-patches, mark
> > In looking at pr32912-2.c, I noticed that a, b, c, d, e and f are
> > not used, so I would like to revise my last patch.
>
> Both changes look ok to me, the latter is certainly obvious.
> For the first you could alternatively try __attribute__((nocommon)),
> though I wonder if pa/hpux shouldn't do that automatically for objects
> which it can't create as common, perhaps with some warning.
I've committed the following to trunk.
Mark, this fixes a testsuite regression introduced after the 4.2.1
release. Is this ok for 4.2.2?
Regards,
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-09-12 John David Anglin <dave.anglin@nrc-crnc.gc.ca>
PR testsuite/33153
* gcc.dg/pr32912-1.c: Add -fno-common to options on hppa*-*-hpux*.
* gcc.dg/pr32912-2.c: Delete declaration of a, b, c, d, e and f.
Index: gcc.dg/pr32912-1.c
===================================================================
--- gcc.dg/pr32912-1.c (revision 128448)
+++ gcc.dg/pr32912-1.c (working copy)
@@ -1,6 +1,7 @@
/* PR middle-end/32912 */
/* { dg-do run } */
/* { dg-options "-O2 -w" } */
+/* { dg-options "-O2 -w -fno-common" { target hppa*-*-hpux* } } */
extern void abort (void);
Index: gcc.dg/pr32912-2.c
===================================================================
--- gcc.dg/pr32912-2.c (revision 128448)
+++ gcc.dg/pr32912-2.c (working copy)
@@ -5,8 +5,6 @@
typedef int __m128i __attribute__ ((__vector_size__ (16)));
-__m128i a, b, c, d, e, f;
-
__m128i
foo (void)
{
^ permalink raw reply [flat|nested] 521+ messages in thread
* ping: [PATCH] Fix PR middle-end/33273
[not found] <no.id>
` (152 preceding siblings ...)
2007-08-27 2:07 ` [patch,testsuite] Fix PR testsuite/33153 John David Anglin
@ 2007-09-16 9:20 ` John David Anglin
2007-09-16 9:21 ` Jakub Jelinek
2007-09-16 19:49 ` Richard Guenther
2007-12-10 3:24 ` [committed] [PR target/34091] Secondary reloads for floating-point register classes John David Anglin
` (9 subsequent siblings)
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2007-09-16 9:20 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jakub
http://gcc.gnu.org/ml/gcc-patches/2007-09/msg00084.html
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] [PR target/34091] Secondary reloads for floating-point register classes
[not found] <no.id>
` (153 preceding siblings ...)
2007-09-16 9:20 ` ping: [PATCH] Fix PR middle-end/33273 John David Anglin
@ 2007-12-10 3:24 ` John David Anglin
2007-12-14 1:57 ` John David Anglin
` (8 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-12-10 3:24 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> 2) We don't have reload_inhi and reload_outhi patterns, so the secondary
> reload technique described above is broken for HImode and QImode values
> in the floating-point registers.
The thought that HImode and QImode values could be loaded to or stored
from from the floating-point registers is wrong. This can only be done
by loading/storing first to the general registers. Thus, I've decided
to apply the change to the 4.2 branch as well.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] [PR target/34091] Secondary reloads for floating-point register classes
[not found] <no.id>
` (154 preceding siblings ...)
2007-12-10 3:24 ` [committed] [PR target/34091] Secondary reloads for floating-point register classes John David Anglin
@ 2007-12-14 1:57 ` John David Anglin
2007-12-22 11:05 ` [committed] Fix PR target/34525 - unrecognized insn (take 2) John David Anglin
` (7 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-12-14 1:57 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
I added the following test from PR target/34091. Tested on
hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-12-13 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/34091
* gcc.c-torture/compile/pr34091.c: New test.
--- /dev/null Sun Dec 9 15:49:09 2007
+++ gcc.c-torture/compile/pr34091.c Sun Dec 9 15:46:56 2007
@@ -0,0 +1,175 @@
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef int GLint;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef float GLfloat;
+typedef GLushort GLchan;
+struct gl_texture_image;
+typedef struct __GLcontextRec GLcontext;
+typedef void (*FetchTexelFuncC) (const struct gl_texture_image * texImage,
+ GLint col, GLint row, GLint img,
+ GLchan * texelOut);
+struct gl_texture_format
+{
+};
+struct gl_texture_image
+{
+ GLenum _BaseFormat;
+ GLboolean _IsPowerOfTwo;
+ FetchTexelFuncC FetchTexelc;
+};
+struct gl_texture_object
+{
+ GLenum Target;
+ GLenum WrapS;
+ GLenum MinFilter;
+ GLenum MagFilter;
+ GLint BaseLevel;
+ GLint _MaxLevel;
+ struct gl_texture_image *Image[6][12];
+};
+enum _format
+{
+ MESA_FORMAT_RGBA_DXT3, MESA_FORMAT_RGBA_DXT5, MESA_FORMAT_RGBA,
+ MESA_FORMAT_RGB, MESA_FORMAT_ALPHA, MESA_FORMAT_LUMINANCE,
+};
+typedef void (*texture_sample_func) (GLcontext * ctx,
+ const struct gl_texture_object * tObj,
+ GLuint n, const GLfloat texcoords[][4],
+ const GLfloat lambda[],
+ GLchan rgba[][4]);
+lerp_2d (GLfloat a, GLfloat b, GLfloat v00, GLfloat v10, GLfloat v01,
+ GLfloat v11)
+{
+ const GLfloat temp0 = ((v00) + (a) * ((v10) - (v00)));
+ const GLfloat temp1 = ((v01) + (a) * ((v11) - (v01)));
+ return ((temp0) + (b) * ((temp1) - (temp0)));
+}
+static __inline__ void
+lerp_rgba (GLchan result[4], GLfloat t, const GLchan a[4], const GLchan b[4])
+{
+ result[0] = (GLchan) (((a[0]) + (t) * ((b[0]) - (a[0]))) + 0.5);
+ result[1] = (GLchan) (((a[1]) + (t) * ((b[1]) - (a[1]))) + 0.5);
+ result[2] = (GLchan) (((a[2]) + (t) * ((b[2]) - (a[2]))) + 0.5);
+}
+static __inline__ void
+lerp_rgba_2d (GLchan result[4], GLfloat a, GLfloat b, const GLchan t00[4],
+ const GLchan t10[4], const GLchan t01[4], const GLchan t11[4])
+{
+ result[0] = (GLchan) (lerp_2d (a, b, t00[0], t10[0], t01[0], t11[0]) + 0.5);
+ result[1] = (GLchan) (lerp_2d (a, b, t00[1], t10[1], t01[1], t11[1]) + 0.5);
+ result[2] = (GLchan) (lerp_2d (a, b, t00[2], t10[2], t01[2], t11[2]) + 0.5);
+}
+static __inline__ void
+sample_2d_linear_repeat (GLcontext * ctx,
+ const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ const GLfloat texcoord[4], GLchan rgba[])
+{
+ GLint i0, j0, i1, j1;
+ GLfloat a, b;
+ GLchan t00[4], t10[4], t01[4], t11[4];
+ {
+ };
+ img->FetchTexelc (img, i1, j1, 0, t11);
+ lerp_rgba_2d (rgba, a, b, t00, t10, t01, t11);
+}
+sample_2d_nearest_mipmap_linear (GLcontext * ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ GLint level = linear_mipmap_level (tObj, lambda[i]);
+ sample_2d_nearest (ctx, tObj, tObj->Image[0][tObj->_MaxLevel], texcoord[i], rgba[i]);
+ GLchan t0[4], t1[4];
+ sample_2d_nearest (ctx, tObj, tObj->Image[0][level], texcoord[i], t0);
+ sample_2d_nearest (ctx, tObj, tObj->Image[0][level + 1], texcoord[i], t1);
+}
+static void
+sample_2d_linear_mipmap_linear_repeat (GLcontext * ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+ for (i = 0; i < n; i++)
+ {
+ GLint level = linear_mipmap_level (tObj, lambda[i]);
+ if (level >= tObj->_MaxLevel)
+ {
+ GLchan t0[4], t1[4];
+ const GLfloat f = ((lambda[i]) - ifloor (lambda[i]));
+ sample_2d_linear_repeat (ctx, tObj, tObj->Image[0][level],
+ texcoord[i], t0);
+ sample_2d_linear_repeat (ctx, tObj, tObj->Image[0][level + 1],
+ texcoord[i], t1);
+ lerp_rgba (rgba[i], f, t0, t1);
+ }
+ }
+}
+static void
+sample_lambda_2d (GLcontext * ctx, const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoords[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
+ GLuint minStart, minEnd;
+ GLuint magStart, magEnd;
+ const GLboolean repeatNoBorderPOT = (tObj->WrapS == 0x2901)
+ && (tImg->_BaseFormat != 0x1900) && tImg->_IsPowerOfTwo;
+ compute_min_mag_ranges (tObj, n, lambda, &minStart, &minEnd, &magStart,
+ &magEnd);
+ if (minStart < minEnd)
+ {
+ const GLuint m = minEnd - minStart;
+ switch (tObj->MinFilter)
+ {
+ case 0x2600:
+ if (repeatNoBorderPOT)
+ {
+ case MESA_FORMAT_RGB:
+ opt_sample_rgb_2d (ctx, tObj, m, texcoords + minStart,
+ ((void *) 0), rgba + minStart);
+ case MESA_FORMAT_RGBA:
+ opt_sample_rgba_2d (ctx, tObj, m, texcoords + minStart,
+ ((void *) 0), rgba + minStart);
+ }
+ {
+ sample_nearest_2d (ctx, tObj, m, texcoords + minStart,
+ ((void *) 0), rgba + minStart);
+ }
+ break;
+ sample_2d_nearest_mipmap_linear (ctx, tObj, m, texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ case 0x2703:
+ if (repeatNoBorderPOT)
+ sample_2d_linear_mipmap_linear_repeat (ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ }
+ switch (tObj->MagFilter)
+ {
+ case MESA_FORMAT_RGB:
+ opt_sample_rgb_2d (ctx, tObj, m, texcoords + magStart,
+ ((void *) 0), rgba + magStart);
+ opt_sample_rgba_2d (ctx, tObj, m, texcoords + magStart,
+ ((void *) 0), rgba + magStart);
+ sample_nearest_2d (ctx, tObj, m, texcoords + magStart,
+ ((void *) 0), rgba + magStart);
+ }
+ }
+}
+texture_sample_func
+_swrast_choose_texture_sample_func (const struct gl_texture_object *t)
+{
+ switch (t->Target)
+ {
+ case 0x0DE0:
+ return &sample_lambda_2d;
+ }
+}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix PR target/34525 - unrecognized insn (take 2)
[not found] <no.id>
` (155 preceding siblings ...)
2007-12-14 1:57 ` John David Anglin
@ 2007-12-22 11:05 ` John David Anglin
2008-01-18 10:22 ` [ping] Ignore thread local symbols when generating dbx debug info John David Anglin
` (6 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2007-12-22 11:05 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The enclosed change fixes PR target/34525. An unrecognized instruction
> was generated because a function label was not forced to memory.
Sigh, I forgot to load the label after forcing it to memory. The
enclosed updated fixes this.
Tested on hppa-unknown-linux-gnu and hppa64-hp-hpux11.11 with no
regressions. Committed to trunk.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2007-12-21 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/34525
* pa.c (legitimize_pic_address): Emit insn to load function label
forced to memory.
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c (revision 131125)
+++ config/pa/pa.c (working copy)
@@ -694,19 +694,37 @@
tmp_reg = ((reload_in_progress || reload_completed)
? reg : gen_reg_rtx (Pmode));
- /* Force function labels into memory. */
if (function_label_operand (orig, mode))
- orig = force_const_mem (mode, orig);
-
- emit_move_insn (tmp_reg,
- gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
- gen_rtx_HIGH (word_mode, orig)));
- pic_ref
- = gen_const_mem (Pmode,
- gen_rtx_LO_SUM (Pmode, tmp_reg,
- gen_rtx_UNSPEC (Pmode,
+ {
+ /* Force function label into memory. */
+ orig = XEXP (force_const_mem (mode, orig), 0);
+ /* Load plabel address from DLT. */
+ emit_move_insn (tmp_reg,
+ gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
+ gen_rtx_HIGH (word_mode, orig)));
+ pic_ref
+ = gen_const_mem (Pmode,
+ gen_rtx_LO_SUM (Pmode, tmp_reg,
+ gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, orig),
+ UNSPEC_DLTIND14R)));
+ emit_move_insn (reg, pic_ref);
+ /* Now load address of function descriptor. */
+ pic_ref = gen_rtx_MEM (Pmode, reg);
+ }
+ else
+ {
+ /* Load symbol reference from DLT. */
+ emit_move_insn (tmp_reg,
+ gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
+ gen_rtx_HIGH (word_mode, orig)));
+ pic_ref
+ = gen_const_mem (Pmode,
+ gen_rtx_LO_SUM (Pmode, tmp_reg,
+ gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, orig),
UNSPEC_DLTIND14R)));
+ }
current_function_uses_pic_offset_table = 1;
mark_reg_pointer (reg, BITS_PER_UNIT);
^ permalink raw reply [flat|nested] 521+ messages in thread
* [ping] Ignore thread local symbols when generating dbx debug info
[not found] <no.id>
` (156 preceding siblings ...)
2007-12-22 11:05 ` [committed] Fix PR target/34525 - unrecognized insn (take 2) John David Anglin
@ 2008-01-18 10:22 ` John David Anglin
2008-02-08 2:49 ` John David Anglin
2008-02-07 2:32 ` [committed] Remove xfail for hppa*-*-* from g++.dg/tree-ssa/ivopts-1.C John David Anglin
` (5 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-01-18 10:22 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, wilson
http://gcc.gnu.org/ml/gcc-patches/2007-12/msg01166.html
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [ping] Ignore thread local symbols when generating dbx debug info
2008-01-18 10:22 ` [ping] Ignore thread local symbols when generating dbx debug info John David Anglin
@ 2008-02-08 2:49 ` John David Anglin
2008-03-05 3:28 ` Jim Wilson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-02-08 2:49 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, wilson, jakub
Second ping.
> http://gcc.gnu.org/ml/gcc-patches/2007-12/msg01166.html
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [ping] Ignore thread local symbols when generating dbx debug info
2008-02-08 2:49 ` John David Anglin
@ 2008-03-05 3:28 ` Jim Wilson
2008-03-08 20:48 ` [ping] Ignore thread local symbols when generating dbx debug John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jim Wilson @ 2008-03-05 3:28 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jakub
[-- Attachment #1: Type: text/plain, Size: 3191 bytes --]
On Thu, 2008-02-07 at 19:43 -0500, John David Anglin wrote:
> Second ping.
> > http://gcc.gnu.org/ml/gcc-patches/2007-12/msg01166.html
Belatedly replying to this, now that I'm doing FSF gcc work again... I
had to spend a bit of time looking at the code. This assumes some
knowledge of emutls, fortran, and hpux, all of which I am lacking. I do
see the problem though. A emutls variable access requires a call to
__emutls_get_address, and then we find the variable at a fixed offset
from the return value. There is no way to express this in the stabs
debug info.
It is a bit annoying that the emutls.c file has no comments explaining
what it does. It doesn't even have comments for each function as
required by the coding conventions. It would be easier to understand if
this stuff was documented some place.
I thought it curious that this was failing for Fortran, but not
apparently for C. Otherwise presumably you would have given a C
testcase. I also wasn't able to reproduce this with a trivial C
example. I tried debugging this a little bit. I see that the normal
variable handling in expand_expr_real_1, case VAR_DECL, has an out for
emutls variables. We create the necessary code to access it, and then
return, before we use DECL_RTL, which calls make_decl_rtl which sets the
DECL_RTL field. Since the emutls variable has no DECL_RTL, we don't try
to emit debug info for it. However, with the Fortran testcase, the
DECL_RTL got created in nonoverlapping_memrefs_p during the cse pass.
This seems questionable to me. With emutls, a variable may or may not
have a DECL_RTL set, depending on how it was optimized. This could lead
to confusion later. It may also be causing subtle bugs. For instance,
mudflap has hooks in make_decl_rtl, which may or may not be called with
emutls, depending on how it was optimized, which means mudflap may or
may not be tracking the variable. Perhaps we should be creating the
DECL_RTL always in expand_expr_real_1. Perhaps make_decl_rtl should
have support for emutls variables.
Anyways, the dbxout.c change looks basically OK to me. It would be nice
if there was a comment explaining what the patch is doing. You are
right that canonical form for RTL will always put the SYMBOL_REF before
the CONST_INT in a PLUS. It looks like we only have to handle the
output of dbxout_expand_expr, so we don't have to handle any more
complicated expressions. However, this points to another possible
solution, which looks a little simpler to me. We can put this test in
dbxout_expand_expr. I attached a patch that does this.
Trying my patch on the testcase, I see the result is a little bit
different than yours. With my patch, debug info is disabled for foo,
thrc, bar1, and bar2. With your patch, debug info is disable for foo,
thrc, and bar2. Which means you still have debug info for bar1. The
debug info seems confused for bar1 though. Internally, gcc thinks it is
addressed relative to thrc_, and then doesn't emit the address because
it is a global, so it slips through your checks.
Can you test my patch and see if it works? If not, then your patch is
fine, preferably with a comment added like the one in my patch.
Jim
[-- Attachment #2: patch.dbx.emutls --]
[-- Type: text/plain, Size: 924 bytes --]
2008-03-04 James E. Wilson <wilson@tuliptree.org>
* dbxout.c (dbxout_expand_expr, case VAR_DECL): Return NULL for
emulated thread local variables.
Index: dbxout.c
===================================================================
--- dbxout.c (revision 132829)
+++ dbxout.c (working copy)
@@ -2332,6 +2332,15 @@
switch (TREE_CODE (expr))
{
case VAR_DECL:
+ /* We can't handle emulated tls variables, because the address is an
+ offset to the return value of __emutls_get_address, and there is no
+ way to express that in stabs. Also, there are name mangling issues
+ here. We end up with references to undefined symbols if we don't
+ disable debug info for these variables. */
+ if (!targetm.have_tls && DECL_THREAD_LOCAL_P (expr))
+ return NULL;
+ /* FALLTHRU */
+
case PARM_DECL:
if (DECL_HAS_VALUE_EXPR_P (expr))
return dbxout_expand_expr (DECL_VALUE_EXPR (expr));
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [ping] Ignore thread local symbols when generating dbx debug
2008-03-05 3:28 ` Jim Wilson
@ 2008-03-08 20:48 ` John David Anglin
2008-03-10 16:27 ` [Bulk] " Jim Wilson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-03-08 20:48 UTC (permalink / raw)
To: Jim Wilson; +Cc: gcc-patches, jakub
> 2008-03-04 James E. Wilson <wilson@tuliptree.org>
>
> * dbxout.c (dbxout_expand_expr, case VAR_DECL): Return NULL for
> emulated thread local variables.
This change also works. It eliminates all the emulated TLS failures
in the libgomp testsuite on hppa2.0w-hp-hpux11* and I didn't see any
new regressions related to the change.
Thanks,
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [Bulk] Re: [ping] Ignore thread local symbols when generating dbx debug
2008-03-08 20:48 ` [ping] Ignore thread local symbols when generating dbx debug John David Anglin
@ 2008-03-10 16:27 ` Jim Wilson
2008-03-10 16:45 ` [Bulk] Re: [ping] Ignore thread local symbols when generating John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Jim Wilson @ 2008-03-10 16:27 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, jakub
On Sat, 2008-03-08 at 15:48 -0500, John David Anglin wrote:
> This change also works. It eliminates all the emulated TLS failures
> in the libgomp testsuite on hppa2.0w-hp-hpux11* and I didn't see any
> new regressions related to the change.
Great, so this is OK to install. I know that mainline is open, but I'm
a little out of touch on the branches. Is this a regression that we
need fixed on one of the branches?
Jim
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [Bulk] Re: [ping] Ignore thread local symbols when generating
2008-03-10 16:27 ` [Bulk] " Jim Wilson
@ 2008-03-10 16:45 ` John David Anglin
2008-03-12 6:32 ` Jim Wilson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-03-10 16:45 UTC (permalink / raw)
To: Jim Wilson; +Cc: gcc-patches, jakub
> Great, so this is OK to install. I know that mainline is open, but I'm
> a little out of touch on the branches. Is this a regression that we
> need fixed on one of the branches?
It's a regression on 4.3.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Remove xfail for hppa*-*-* from g++.dg/tree-ssa/ivopts-1.C
[not found] <no.id>
` (157 preceding siblings ...)
2008-01-18 10:22 ` [ping] Ignore thread local symbols when generating dbx debug info John David Anglin
@ 2008-02-07 2:32 ` John David Anglin
2008-02-09 22:03 ` RFC: Fix PR middle-end/34150 -- Lost LABEL_NUSES counts John David Anglin
` (4 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2008-02-07 2:32 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> Committed to trunk. Tested on hppa2.0w-hp-hpux11.11.
Likewise on 4.2, the test is no longer failing on hppa*-*-*.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2008-02-06 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* g++.dg/tree-ssa/ivopts-1.C: Remove xfails for hppa*-*-*.
Index: g++.dg/tree-ssa/ivopts-1.C
===================================================================
--- g++.dg/tree-ssa/ivopts-1.C (revision 132079)
+++ g++.dg/tree-ssa/ivopts-1.C (working copy)
@@ -13,6 +13,6 @@
}
/* { dg-final { scan-tree-dump-not "-&x" "ivopts" } } */
-/* { dg-final { scan-tree-dump-not "offset: -4B" "ivopts" { xfail i?86-*-* x86_64-*-* hppa*-*-* } } } */
-/* { dg-final { scan-tree-dump-not "&x\\\[5\\\]" "ivopts" { xfail i?86-*-* x86_64-*-* hppa*-*-* } } } */
+/* { dg-final { scan-tree-dump-not "offset: -4B" "ivopts" { xfail i?86-*-* x86_64-*-* } } } */
+/* { dg-final { scan-tree-dump-not "&x\\\[5\\\]" "ivopts" { xfail i?86-*-* x86_64-*-* } } } */
/* { dg-final { cleanup-tree-dump "ivopts" } } */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: RFC: Fix PR middle-end/34150 -- Lost LABEL_NUSES counts
[not found] <no.id>
` (158 preceding siblings ...)
2008-02-07 2:32 ` [committed] Remove xfail for hppa*-*-* from g++.dg/tree-ssa/ivopts-1.C John David Anglin
@ 2008-02-09 22:03 ` John David Anglin
2008-08-18 14:23 ` update dwarf2 asm unwind info [hppa64-*-* failures] John David Anglin
` (3 subsequent siblings)
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2008-02-09 22:03 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The attached patch is a target specific fix for PR middle-end/34150.
> Is this the right approach, or should reload handle this?
I have convinced myself that this is the right approach. alpha.md
has a postreload split that handles LABEL_REFs in a similar manner.
I checked the lreg and greg rtl dumps for the testcase in the PR.
We now have identical REG_NOTES when setting a register with a LABEL_REF
after lreg and greg. Similarly, the LABEL_NUSES counts for nonlocal
goto labels agree.
The patch has been tested on hppa-unknown-linux-gnu and hppa64-hp-hpux11.11.
Committed to all active branches.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2008-02-09 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle_end/34150
* pa.c (legitimize_pic_address): Add REG_EQUAL note on sets with a
pic_label_operand source. Similarly, add a REG_LABEL_OPERAND note
and update LABEL_NUSES during and after reload.
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c (revision 132195)
+++ config/pa/pa.c (working copy)
@@ -668,6 +668,8 @@
/* Labels need special handling. */
if (pic_label_operand (orig, mode))
{
+ rtx insn;
+
/* We do not want to go through the movXX expanders here since that
would create recursion.
@@ -678,7 +680,24 @@
So instead we just emit the raw set, which avoids the movXX
expanders completely. */
mark_reg_pointer (reg, BITS_PER_UNIT);
- emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
+ insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
+
+ /* Put a REG_EQUAL note on this insn, so that it can be optimized. */
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn));
+
+ /* During and after reload, we need to generate a REG_LABEL_OPERAND note
+ and update LABEL_NUSES because this is not done automatically. */
+ if (reload_in_progress || reload_completed)
+ {
+ /* Extract LABEL_REF. */
+ if (GET_CODE (orig) == CONST)
+ orig = XEXP (XEXP (orig, 0), 0);
+ /* Extract CODE_LABEL. */
+ orig = XEXP (orig, 0);
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, orig,
+ REG_NOTES (insn));
+ LABEL_NUSES (orig)++;
+ }
current_function_uses_pic_offset_table = 1;
return reg;
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
[not found] <no.id>
` (159 preceding siblings ...)
2008-02-09 22:03 ` RFC: Fix PR middle-end/34150 -- Lost LABEL_NUSES counts John David Anglin
@ 2008-08-18 14:23 ` John David Anglin
2008-08-21 20:10 ` Richard Henderson
2009-08-02 19:35 ` [committed] Fix previous change to pa.c John David Anglin
` (2 subsequent siblings)
163 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-18 14:23 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, sje, gcc-patches, dave.anglin, binutils-patches
> The first form works. I'll see if the addend can be adjusted.
I've appended an updated binutils change. This adjusts the addend
in tc-hppa.c and readelf.c to account for the fact that PA-RISC
PCREL relocations are for symbol - PC - 8 + addend.
GAS now appears to generate correct locations for symbol differences,
and the cfi tests are now successful on both hppa-unknown-linux-gnu
and hppa64-hp-hpux11.11. However, we still have some EH failures
on linux. On hppa64, we aren't failing the C cleanup tests but
there are still a lot of g++ and libstdc++ EH failures.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.423
diff -u -3 -p -r1.423 readelf.c
--- binutils/readelf.c 8 Aug 2008 19:24:48 -0000 1.423
+++ binutils/readelf.c 17 Aug 2008 19:23:05 -0000
@@ -8156,7 +8156,7 @@ is_32bit_pcrel_reloc (unsigned int reloc
case EM_ARM:
return reloc_type == 3; /* R_ARM_REL32 */
case EM_PARISC:
- return reloc_type == 0; /* R_PARISC_NONE. *//* FIXME: This reloc is generated, but it may be a bug. */
+ return reloc_type == 9; /* R_PARISC_PCREL32. */
case EM_PPC:
return reloc_type == 26; /* R_PPC_REL32. */
case EM_PPC64:
@@ -8219,6 +8219,36 @@ is_64bit_abs_reloc (unsigned int reloc_t
}
}
+/* Like is_32bit_pcrel_reloc except that it returns TRUE iff RELOC_TYPE is
+ a 64-bit pc-relative RELA relocation used in DWARF debug sections. */
+
+static bfd_boolean
+is_64bit_pcrel_reloc (unsigned int reloc_type)
+{
+ switch (elf_header.e_machine)
+ {
+ case EM_ALPHA:
+ return reloc_type == 11; /* R_ALPHA_SREL64 */
+ case EM_IA_64:
+ return reloc_type == 0x4f; /* R_IA64_PCREL64LSB */
+ case EM_PARISC:
+ return reloc_type == 72; /* R_PARISC_PCREL64 */
+ case EM_PPC64:
+ return reloc_type == 44; /* R_PPC64_REL64 */
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPARC:
+ return reloc_type == 46; /* R_SPARC_DISP64 */
+ case EM_X86_64:
+ return reloc_type == 24; /* R_X86_64_PC64 */
+ case EM_S390_OLD:
+ case EM_S390:
+ return reloc_type == 23; /* R_S390_PC64 */
+ default:
+ return FALSE;
+ }
+}
+
/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
a 16-bit absolute RELA relocation used in DWARF debug sections. */
@@ -8392,7 +8422,8 @@ debug_apply_relocations (void *file,
if (is_32bit_abs_reloc (reloc_type)
|| is_32bit_pcrel_reloc (reloc_type))
reloc_size = 4;
- else if (is_64bit_abs_reloc (reloc_type))
+ else if (is_64bit_abs_reloc (reloc_type)
+ || is_64bit_pcrel_reloc (reloc_type))
reloc_size = 8;
else if (is_16bit_abs_reloc (reloc_type))
reloc_size = 2;
@@ -8435,10 +8466,16 @@ debug_apply_relocations (void *file,
}
addend = is_rela ? rp->r_addend : byte_get (loc, reloc_size);
-
- if (is_32bit_pcrel_reloc (reloc_type))
- byte_put (loc, (addend + sym->st_value) - rp->r_offset,
- reloc_size);
+
+ if (is_32bit_pcrel_reloc (reloc_type)
+ || is_64bit_pcrel_reloc (reloc_type))
+ {
+ /* Adjust addend on PA-RISC. */
+ if (elf_header.e_machine == EM_PARISC)
+ addend -= 8;
+ byte_put (loc, (addend + sym->st_value) - rp->r_offset,
+ reloc_size);
+ }
else
byte_put (loc, addend + sym->st_value, reloc_size);
}
Index: gas/dw2gencfi.c
===================================================================
RCS file: /cvs/src/src/gas/dw2gencfi.c,v
retrieving revision 1.34
diff -u -3 -p -r1.34 dw2gencfi.c
--- gas/dw2gencfi.c 13 Feb 2008 10:14:37 -0000 1.34
+++ gas/dw2gencfi.c 17 Aug 2008 19:23:05 -0000
@@ -31,6 +31,16 @@
# define DWARF2_LINE_MIN_INSN_LENGTH 1
#endif
+/* By default, use 32-bit relocations from .eh_frame into .text. */
+#ifndef DWARF2_FDE_RELOC_SIZE
+# define DWARF2_FDE_RELOC_SIZE 4
+#endif
+
+/* By default, use a read-only .eh_frame section. */
+#ifndef DWARF2_EH_FRAME_READ_ONLY
+# define DWARF2_EH_FRAME_READ_ONLY SEC_READONLY
+#endif
+
#ifndef EH_FRAME_ALIGNMENT
# define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
#endif
@@ -1041,6 +1051,7 @@ output_cie (struct cie_entry *cie)
expressionS exp;
struct cfi_insn_data *i;
offsetT augmentation_size;
+ int enc;
cie->start_address = symbol_temp_new_now ();
after_size_address = symbol_temp_make ();
@@ -1096,11 +1107,22 @@ output_cie (struct cie_entry *cie)
}
if (cie->lsda_encoding != DW_EH_PE_omit)
out_one (cie->lsda_encoding);
+
+ switch (DWARF2_FDE_RELOC_SIZE)
+ {
+ case 4:
+ enc = DW_EH_PE_sdata4;
+ break;
+ case 8:
+ enc = DW_EH_PE_sdata8;
+ break;
+ default:
+ abort ();
+ }
#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
- out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
-#else
- out_one (DW_EH_PE_sdata4);
+ enc |= DW_EH_PE_pcrel;
#endif
+ out_one (enc);
if (cie->first)
for (i = cie->first; i != cie->last; i = i->next)
@@ -1135,22 +1157,22 @@ output_fde (struct fde_entry *fde, struc
#ifdef DIFF_EXPR_OK
exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = symbol_temp_new_now ();
- emit_expr (&exp, 4); /* Code offset. */
+ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else
exp.X_op = O_symbol;
exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr
- tc_cfi_emit_pcrel_expr (&exp, 4); /* Code offset. */
+ tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else
- emit_expr (&exp, 4); /* Code offset. */
+ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#endif
exp.X_op = O_subtract;
#endif
exp.X_add_symbol = fde->end_address;
exp.X_op_symbol = fde->start_address; /* Code length. */
- emit_expr (&exp, 4);
+ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);
augmentation_size = encoding_size (fde->lsda_encoding);
out_uleb128 (augmentation_size); /* Augmentation size. */
@@ -1319,7 +1341,8 @@ cfi_finish (void)
/* Open .eh_frame section. */
cfi_seg = subseg_new (".eh_frame", 0);
bfd_set_section_flags (stdoutput, cfi_seg,
- SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY);
+ SEC_ALLOC | SEC_LOAD | SEC_DATA
+ | DWARF2_EH_FRAME_READ_ONLY);
subseg_set (cfi_seg, 0);
record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
Index: gas/config/tc-hppa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-hppa.c,v
retrieving revision 1.138
diff -u -3 -p -r1.138 tc-hppa.c
--- gas/config/tc-hppa.c 16 Mar 2008 23:16:03 -0000 1.138
+++ gas/config/tc-hppa.c 17 Aug 2008 19:23:05 -0000
@@ -1375,6 +1375,16 @@ tc_gen_reloc (asection *section, fixS *f
reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+
+ /* Allow fixup_segment to recognize hand-written pc-relative
+ relocations. When we went through cons_fix_new_hppa, we
+ classified them as complex. Simplify that now. */
+ if (fixp->fx_r_type == R_HPPA_COMPLEX && fixp->fx_pcrel)
+ {
+ fixp->fx_r_type = R_HPPA_PCREL_CALL;
+ fixp->fx_offset += 8;
+ }
+
codes = hppa_gen_reloc_type (stdoutput,
fixp->fx_r_type,
hppa_fixp->fx_r_format,
Index: gas/config/tc-hppa.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-hppa.h,v
retrieving revision 1.35
diff -u -3 -p -r1.35 tc-hppa.h
--- gas/config/tc-hppa.h 12 Aug 2008 23:39:30 -0000 1.35
+++ gas/config/tc-hppa.h 17 Aug 2008 19:23:05 -0000
@@ -186,8 +186,6 @@ int hppa_fix_adjustable (struct fix *);
#define elf_tc_final_processing elf_hppa_final_processing
void elf_hppa_final_processing (void);
-
-#define DWARF2_LINE_MIN_INSN_LENGTH 4
#endif /* OBJ_ELF */
#define md_operand(x)
@@ -213,10 +211,18 @@ extern int hppa_regname_to_dw2regnum (ch
#define DWARF2_LINE_MIN_INSN_LENGTH 4
#define DWARF2_DEFAULT_RETURN_COLUMN 2
#if TARGET_ARCH_SIZE == 64
-#define DWARF2_CIE_DATA_ALIGNMENT (-8)
+#define DWARF2_CIE_DATA_ALIGNMENT 8
+#define DWARF2_FDE_RELOC_SIZE 8
#else
-#define DWARF2_CIE_DATA_ALIGNMENT (-4)
+#define DWARF2_CIE_DATA_ALIGNMENT 4
#endif
+
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
+/* Due to the way dynamic linking to personality functions is handled
+ on HP-UX, we need to have a read-write .eh_frame section. */
+#define DWARF2_EH_FRAME_READ_ONLY 0
+#endif
+
#endif
#endif /* _TC_HPPA_H */
Index: gas/testsuite/gas/cfi/cfi-common-1.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/cfi/cfi-common-1.d,v
retrieving revision 1.5
diff -u -3 -p -r1.5 cfi-common-1.d
--- gas/testsuite/gas/cfi/cfi-common-1.d 28 Jan 2008 15:15:31 -0000 1.5
+++ gas/testsuite/gas/cfi/cfi-common-1.d 17 Aug 2008 19:23:05 -0000
@@ -14,10 +14,11 @@ The section .eh_frame contains:
DW_CFA_nop
DW_CFA_nop
-00000014 00000018 00000018 FDE cie=00000000 pc=.*
+00000014 000000(18|1c|20) 00000018 FDE cie=00000000 pc=.*
DW_CFA_advance_loc: 4 to .*
DW_CFA_def_cfa: r0( \([er]ax\)|) ofs 16
- DW_CFA_offset: r1( \((rdx|ecx)\)|) at cfa-8
+ DW_CFA_offset(_extended_sf|): r1( \((rdx|ecx)\)|) at cfa-8
DW_CFA_advance_loc: 4 to .*
DW_CFA_def_cfa_offset: 32
- DW_CFA_offset: r2( \((rcx|edx)\)|) at cfa-24
+ DW_CFA_offset(_extended_sf|): r2( \((rcx|edx)\)|) at cfa-24
+#...
Index: gas/testsuite/gas/cfi/cfi-hppa-1.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/cfi/cfi-hppa-1.d,v
retrieving revision 1.2
diff -u -3 -p -r1.2 cfi-hppa-1.d
--- gas/testsuite/gas/cfi/cfi-hppa-1.d 28 Jan 2008 15:15:31 -0000 1.2
+++ gas/testsuite/gas/cfi/cfi-hppa-1.d 17 Aug 2008 19:23:05 -0000
@@ -6,13 +6,13 @@ The section .eh_frame contains:
Version: 1
Augmentation: "zR"
Code alignment factor: 4
- Data alignment factor: -[48]
+ Data alignment factor: [48]
Return address column: 2
- Augmentation data: 1b
+ Augmentation data: 1[bc]
DW_CFA_def_cfa: r30 ofs 0
-00000014 00000018 00000018 FDE cie=00000000 pc=00000000..00000018
+00000014 000000(18|20) 00000018 FDE cie=00000000 pc=00000000..00000018
DW_CFA_advance_loc: 8 to 00000008
DW_CFA_def_cfa_register: r3
DW_CFA_advance_loc: 4 to 0000000c
@@ -21,17 +21,16 @@ The section .eh_frame contains:
DW_CFA_def_cfa_register: r30
DW_CFA_nop
-00000030 00000018 00000034 FDE cie=00000000 pc=00000018..00000040
+0000003[08] 000000(18|20) 0000003[4c] FDE cie=00000000 pc=00000018..00000040
DW_CFA_advance_loc: 12 to 00000024
DW_CFA_def_cfa_register: r3
- DW_CFA_offset: r2 at cfa-24
+ DW_CFA_offset_extended_sf: r2 at cfa-24
DW_CFA_advance_loc: 24 to 0000003c
DW_CFA_def_cfa_register: r30
DW_CFA_nop
DW_CFA_nop
- DW_CFA_nop
-0000004c 00000010 00000050 FDE cie=00000000 pc=00000040..00000048
+000000[45]c 0000001[08] 000000[56]0 FDE cie=00000000 pc=00000040..00000048
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
Index: gas/testsuite/gas/cfi/cfi.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/cfi/cfi.exp,v
retrieving revision 1.21
diff -u -3 -p -r1.21 cfi.exp
--- gas/testsuite/gas/cfi/cfi.exp 18 Feb 2008 21:05:07 -0000 1.21
+++ gas/testsuite/gas/cfi/cfi.exp 17 Aug 2008 19:23:05 -0000
@@ -80,13 +80,18 @@ if { [istarget "i*86-*-*"] || [istarget
}
run_list_test "cfi-diag-1" ""
-run_dump_test "cfi-common-1"
-run_dump_test "cfi-common-2"
-run_dump_test "cfi-common-3"
-run_dump_test "cfi-common-4"
-run_dump_test "cfi-common-5"
-# MIPS doesn't support PC relative cfi directives
+# HPPA64 uses 64-bit relocations, which results in all of the dump
+# offset numbers not matching up.
+if { ![istarget "hppa64*-*"] } then {
+ run_dump_test "cfi-common-1"
+ run_dump_test "cfi-common-2"
+ run_dump_test "cfi-common-3"
+ run_dump_test "cfi-common-4"
+ run_dump_test "cfi-common-5"
+}
+
+# MIPS doesn't support PC relative cfi directives.
if { ![istarget "mips*-*"] } then {
run_dump_test "cfi-common-6"
}
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-18 14:23 ` update dwarf2 asm unwind info [hppa64-*-* failures] John David Anglin
@ 2008-08-21 20:10 ` Richard Henderson
2008-08-21 21:28 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2008-08-21 20:10 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
John David Anglin wrote:
> I've appended an updated binutils change. This adjusts the addend
> in tc-hppa.c and readelf.c to account for the fact that PA-RISC
> PCREL relocations are for symbol - PC - 8 + addend.
Gah. What an annoying feature that is. I've checked in the patch
with that change installed.
> However, we still have some EH failures
> on linux. On hppa64, we aren't failing the C cleanup tests but
> there are still a lot of g++ and libstdc++ EH failures.
Interesting that it works on hpux and not linux... I thought we
were generating the same output on those two systems?
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-21 20:10 ` Richard Henderson
@ 2008-08-21 21:28 ` John David Anglin
2008-08-22 0:09 ` Richard Henderson
2008-08-23 19:46 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2008-08-21 21:28 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
> > However, we still have some EH failures
> > on linux. On hppa64, we aren't failing the C cleanup tests but
> > there are still a lot of g++ and libstdc++ EH failures.
>
> Interesting that it works on hpux and not linux... I thought we
> were generating the same output on those two systems?
I believe the C cleanup tests are also passing on linux using
the CFI directions.
As far as the EH output goes, we have been using pc-relative
relocations on linux for some time. We use an indirect pc-relative
encoding to handle the plabel needed for the call to the personality
function.
We haven't been able to use pc-relative relocations with HP-UX
because of the segmented memory space. So, we used aligned and
absptr encoding there.
I will do some more comparisons of the difference between the CFI
directives and the old encoding this weekend. I know simply
interchanging libgcc_s.so fixed some failures before. As I understand
it, the CFI directives are not being used yet with g++.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-21 21:28 ` John David Anglin
@ 2008-08-22 0:09 ` Richard Henderson
2008-08-22 3:27 ` John David Anglin
2008-08-23 19:46 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2008-08-22 0:09 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin
John David Anglin wrote:
> We haven't been able to use pc-relative relocations with HP-UX
> because of the segmented memory space. So, we used aligned and
> absptr encoding there.
I don't suppose the HP linker supports R_PARISC_SEGREL32 at
an unaligned address? If so, you could fairly easily arrange
to use DW_EH_PE_textrel as the encoding for the function addrs.
> I will do some more comparisons of the difference between the CFI
> directives and the old encoding this weekend. I know simply
> interchanging libgcc_s.so fixed some failures before. As I understand
> it, the CFI directives are not being used yet with g++.
Correct. Which means that if you see C++ failures, then libgcc
itself was miscompiled.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-22 0:09 ` Richard Henderson
@ 2008-08-22 3:27 ` John David Anglin
2008-08-22 17:53 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-22 3:27 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin
> I don't suppose the HP linker supports R_PARISC_SEGREL32 at
> an unaligned address? If so, you could fairly easily arrange
> to use DW_EH_PE_textrel as the encoding for the function addrs.
Don't know but I doubt it. I would expect the situation is the
same as for ia64.
It is possible that pc-relative relocations might work if .eh_frame
was read-only for hppa64. I have checked and found that plabels can
be in a read-only in both executables and shared libraries. However,
I'm still not sure that the EH processing will work for shared
libraries. Also, putting the EH data in a read-only section would
probably break existing code.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-22 3:27 ` John David Anglin
@ 2008-08-22 17:53 ` Richard Henderson
2008-08-22 18:30 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2008-08-22 17:53 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin
John David Anglin wrote:
>> I don't suppose the HP linker supports R_PARISC_SEGREL32 at
>> an unaligned address? If so, you could fairly easily arrange
>> to use DW_EH_PE_textrel as the encoding for the function addrs.
>
> Don't know but I doubt it. I would expect the situation is the
> same as for ia64.
>
> It is possible that pc-relative relocations might work if .eh_frame
> was read-only for hppa64. I have checked and found that plabels can
> be in a read-only in both executables and shared libraries. However,
> I'm still not sure that the EH processing will work for shared
> libraries. Also, putting the EH data in a read-only section would
> probably break existing code.
I wasn't considering making the EH data read-only, I was only
considering reducing the number of dynamic relocations needed.
At present, the absolute addresses mean that you need dynamic
fixups for shared libraries, and for executables when the segments
used aren't what the static linker selected. If segment-relative
relocations were used, you'd only have one dynamic relocation --
the one that records the base of the segment in
__register_frame_info_bases.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-22 17:53 ` Richard Henderson
@ 2008-08-22 18:30 ` John David Anglin
2008-08-22 20:57 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-22 18:30 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin
> I wasn't considering making the EH data read-only, I was only
> considering reducing the number of dynamic relocations needed.
Ok.
> At present, the absolute addresses mean that you need dynamic
> fixups for shared libraries, and for executables when the segments
> used aren't what the static linker selected. If segment-relative
> relocations were used, you'd only have one dynamic relocation --
> the one that records the base of the segment in
> __register_frame_info_bases.
I'll look at this. There isn't a direct to generate SEGREL relocations
although it looks easy to tweak gas to do it (DIR64 relocations could
be converted to SEGREL64 in .eh_frame). It's not clear to me how the
segment base would be recorded.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-22 18:30 ` John David Anglin
@ 2008-08-22 20:57 ` Richard Henderson
0 siblings, 0 replies; 521+ messages in thread
From: Richard Henderson @ 2008-08-22 20:57 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin
John David Anglin wrote:
> I'll look at this. There isn't a direct to generate SEGREL relocations
> although it looks easy to tweak gas to do it (DIR64 relocations could
> be converted to SEGREL64 in .eh_frame).
I strongly discourage converting relocations based on the section.
The fact that this already happens for DIR32 I think is a mistake.
You should instead use a special directive (like alpha's .gprel)
or annotations next to the symbol (like ia64's @segrel(foo)).
> It's not clear to me how the segment base would be recorded.
From my scant reading of include/elf/hppa.h, it appears that the
"segments" are not really related to what we think of as the runtime
segments at all, but are specified to the linker with the
R_PARISC_SEGBASE relocation. So you can pick some well-known
system symbol such as _text and use that. Hopefully there's some
symbol that exists for both programs and shared libraries.
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-21 21:28 ` John David Anglin
2008-08-22 0:09 ` Richard Henderson
@ 2008-08-23 19:46 ` John David Anglin
2008-08-23 21:14 ` John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-23 19:46 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, sje, gcc-patches, dave.anglin, binutils-patches
> I will do some more comparisons of the difference between the CFI
> directives and the old encoding this weekend.
I compared the .eh_frame's generated on hppa-linux by adding
"-fno-dwarf2-cfi-asm -fnon-call-exceptions" to the default compilation
options for unwind-dw2.c to the default options.
--- unwind-dw2_s_nc.wf 2008-08-23 13:22:37.000000000 -0400
+++ unwind-dw2_s.wf 2008-08-23 13:19:50.000000000 -0400
@@ -3,7 +3,7 @@
00000000 00000010 00000000 CIE
Version: 1
Augmentation: "zR"
- Code alignment factor: 1
+ Code alignment factor: 4
Data alignment factor: 4
Return address column: 2
Augmentation data: 1b
@@ -57,39 +57,39 @@
000000c8 00000018 000000cc FDE cie=00000000 pc=000000a8..000000d8
DW_CFA_advance_loc: 8 to 000000b0
- DW_CFA_def_cfa_offset_sf: -64
+ DW_CFA_def_cfa_offset_sf: -16
+ DW_CFA_advance_loc: 20 to 000000c4
DW_CFA_offset: r4 at cfa+0
DW_CFA_offset_extended_sf: r2 at cfa-20
DW_CFA_nop
DW_CFA_nop
- DW_CFA_nop
000000e4 00000018 000000e8 FDE cie=00000000 pc=000000d8..00000144
DW_CFA_advance_loc: 12 to 000000e4
- DW_CFA_def_cfa_offset_sf: -64
+ DW_CFA_def_cfa_offset_sf: -16
The first difference is the code alignment factor. It seems this
is hard-coded to 1 in dwarf2out.c.
It looks like the offset of -16 is wrong:
.cfi_startproc
_Unwind_DeleteException:
.PROC
.CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=3
.ENTRY
stw %r2,-20(%r30)
stwm %r4,64(%r30)
.cfi_def_cfa_offset -16
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-23 19:46 ` John David Anglin
@ 2008-08-23 21:14 ` John David Anglin
2008-08-24 20:09 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-23 21:14 UTC (permalink / raw)
To: John David Anglin; +Cc: rth, sje, gcc-patches, dave.anglin, binutils-patches
> @@ -57,39 +57,39 @@
>
> 000000c8 00000018 000000cc FDE cie=00000000 pc=000000a8..000000d8
> DW_CFA_advance_loc: 8 to 000000b0
> - DW_CFA_def_cfa_offset_sf: -64
> + DW_CFA_def_cfa_offset_sf: -16
> + DW_CFA_advance_loc: 20 to 000000c4
> DW_CFA_offset: r4 at cfa+0
> DW_CFA_offset_extended_sf: r2 at cfa-20
> DW_CFA_nop
> DW_CFA_nop
> - DW_CFA_nop
>
> 000000e4 00000018 000000e8 FDE cie=00000000 pc=000000d8..00000144
> DW_CFA_advance_loc: 12 to 000000e4
> - DW_CFA_def_cfa_offset_sf: -64
> + DW_CFA_def_cfa_offset_sf: -16
>
> The first difference is the code alignment factor. It seems this
> is hard-coded to 1 in dwarf2out.c.
>
> It looks like the offset of -16 is wrong:
>
> .cfi_startproc
> _Unwind_DeleteException:
> .PROC
> .CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=3
> .ENTRY
> stw %r2,-20(%r30)
> stwm %r4,64(%r30)
> .cfi_def_cfa_offset -16
Comparatively, with -fno-dwarf2-asm, the .eh_frame output is
.byte 0x13
.sleb128 -16
So, both bits of code output an "offset" of -16. It seems gas doesn't
have a .cfi_def_cfa_offset_sf directive, yet the ".cfi_def_cfa_offset -16"
encodes the value with DW_CFA_def_cfa_offset_sf when the value is negative.
I see the following code in dw2gencfi.c:
case DW_CFA_def_cfa_offset:
offset = insn->u.i;
if (offset < 0)
{
out_one (DW_CFA_def_cfa_offset_sf);
out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
}
else
{
out_one (DW_CFA_def_cfa_offset);
out_uleb128 (offset);
}
As can be seen, gas is dividing DWARF2_CIE_DATA_ALIGNMENT when the
offset is negative. GCC is also dividing by the data alignment.
So, which is wrong?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-23 21:14 ` John David Anglin
@ 2008-08-24 20:09 ` Richard Henderson
2008-08-24 21:06 ` John David Anglin
0 siblings, 1 reply; 521+ messages in thread
From: Richard Henderson @ 2008-08-24 20:09 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
[-- Attachment #1: Type: text/plain, Size: 254 bytes --]
John David Anglin wrote:
> As can be seen, gas is dividing DWARF2_CIE_DATA_ALIGNMENT when the
> offset is negative. GCC is also dividing by the data alignment.
> So, which is wrong?
Gcc is wrong. Here's a patch to avoid doing the division twice.
r~
[-- Attachment #2: z.txt --]
[-- Type: text/plain, Size: 4595 bytes --]
--- dwarf2out.c (revision 139547)
+++ dwarf2out.c (local)
@@ -776,23 +776,16 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_loc
switch (cfi->dw_cfi_opc)
{
case DW_CFA_def_cfa_offset:
- loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
- break;
case DW_CFA_def_cfa_offset_sf:
- loc->offset
- = cfi->dw_cfi_oprnd1.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
break;
case DW_CFA_def_cfa_register:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
break;
case DW_CFA_def_cfa:
- loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
- loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
- break;
case DW_CFA_def_cfa_sf:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
- loc->offset
- = cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
break;
case DW_CFA_def_cfa_expression:
get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
@@ -891,20 +884,14 @@ def_cfa_1 (const char *label, dw_cfa_loc
if (loc.reg == old_cfa.reg && !loc.indirect)
{
/* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
- the CFA register did not change but the offset did. */
+ the CFA register did not change but the offset did. The data
+ factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
+ in the assembler via the .cfi_def_cfa_offset directive. */
if (loc.offset < 0)
- {
- HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
- gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
-
- cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
- cfi->dw_cfi_oprnd1.dw_cfi_offset = f_offset;
- }
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
else
- {
- cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
- cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
- }
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
}
#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
@@ -924,22 +911,15 @@ def_cfa_1 (const char *label, dw_cfa_loc
{
/* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
indicating the CFA register has changed to <register> with
- the specified offset. */
+ the specified offset. The data factoring for DW_CFA_def_cfa_sf
+ happens in output_cfi, or in the assembler via the .cfi_def_cfa
+ directive. */
if (loc.offset < 0)
- {
- HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
- gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
-
- cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
- cfi->dw_cfi_oprnd2.dw_cfi_offset = f_offset;
- }
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
else
- {
- cfi->dw_cfi_opc = DW_CFA_def_cfa;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
- cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
- }
+ cfi->dw_cfi_opc = DW_CFA_def_cfa;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
}
else
{
@@ -2552,6 +2532,8 @@ static void
output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
{
unsigned long r;
+ HOST_WIDE_INT off;
+
if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
dw2_asm_output_data (1, (cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
@@ -2622,12 +2604,20 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref f
break;
case DW_CFA_offset_extended_sf:
- case DW_CFA_def_cfa_sf:
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
break;
+ case DW_CFA_def_cfa_sf:
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+
+ off = cfi->dw_cfi_oprnd2.dw_cfi_offset;
+ gcc_assert (off % DWARF_CIE_DATA_ALIGNMENT == 0);
+ dw2_asm_output_data_sleb128 (off / DWARF_CIE_DATA_ALIGNMENT, NULL);
+ break;
+
case DW_CFA_restore_extended:
case DW_CFA_undefined:
case DW_CFA_same_value:
@@ -2649,7 +2639,9 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref f
break;
case DW_CFA_def_cfa_offset_sf:
- dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
+ off = cfi->dw_cfi_oprnd1.dw_cfi_offset;
+ gcc_assert (off % DWARF_CIE_DATA_ALIGNMENT == 0);
+ dw2_asm_output_data_sleb128 (off / DWARF_CIE_DATA_ALIGNMENT, NULL);
break;
case DW_CFA_GNU_window_save:
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-24 20:09 ` Richard Henderson
@ 2008-08-24 21:06 ` John David Anglin
2008-08-25 1:42 ` Richard Henderson
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2008-08-24 21:06 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
> Gcc is wrong. Here's a patch to avoid doing the division twice.
I'll give it a try. I had tried the simple fix to multiply by
DWARF_CIE_DATA_ALIGNMENT in the output for DW_CFA_def_cfa_offset_sf.
This fixed the the linux EH fails using CFI directives.
I'm now pondering what to do about hppa64-hpux. I have the sense
that pc-relative relocations might work if .eh_frame is read-only.
I think the relocated value will then point to the correct place
for code in shared libraries. Making .eh_frame read-only would
have to be forced. I believe that we would need the same pc-relative
indirect trick as we currently use on linux to get the plabel out of
.eh_frame (see patch below). This looks like the easiest approach
if it works.
The other alternative is to use SEGREL relocations. It looks like
the assembler CFI directives can't support this. We would also
need to define a way to indicate to the assembler that we want a
SEGREL relocation. It looks like the symbol __text_seg provides
the text base, but it is a dynamic symbol. crtstuff.c probably
would need some modification to pass the correct text and data bases.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 139524)
+++ dwarf2out.c (working copy)
@@ -145,12 +145,12 @@
return false;
/* Make sure the personality encoding is one the assembler can support.
- In particular, aligned addresses can't be handled. */
+ In particular, indirect and aligned addresses can't be handled. */
enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,/*global=*/1);
- if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
+ if ((enc & 0xF0) != 0 && (enc & 0xF0) != DW_EH_PE_pcrel)
return false;
enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,/*global=*/0);
- if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
+ if ((enc & 0xF0) != 0 && (enc & 0xF0) != DW_EH_PE_pcrel)
return false;
return true;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-24 21:06 ` John David Anglin
@ 2008-08-25 1:42 ` Richard Henderson
2008-08-25 3:31 ` John David Anglin
2008-08-25 4:57 ` John David Anglin
0 siblings, 2 replies; 521+ messages in thread
From: Richard Henderson @ 2008-08-25 1:42 UTC (permalink / raw)
To: John David Anglin; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
John David Anglin wrote:
> Making .eh_frame read-only would
> have to be forced. I believe that we would need the same pc-relative
> indirect trick as we currently use on linux to get the plabel out of
> .eh_frame (see patch below).
The patch is wrong. We handle the indirect part inside the compiler
before we pass it on to the assembler.
But if you can get pc-relative relocs to those plabels, it would be
the easiest thing to do. Far better than playing with segment bases.
> It looks like the symbol __text_seg provides
> the text base, but it is a dynamic symbol. crtstuff.c probably
> would need some modification to pass the correct text and data bases.
Perhaps you could force __text_seg to be .hidden. I don't know if
the hpux linker supports that sort of thing though...
r~
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-25 1:42 ` Richard Henderson
@ 2008-08-25 3:31 ` John David Anglin
2008-08-25 4:57 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2008-08-25 3:31 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
> But if you can get pc-relative relocs to those plabels, it would be
> the easiest thing to do. Far better than playing with segment bases.
>
> > It looks like the symbol __text_seg provides
> > the text base, but it is a dynamic symbol. crtstuff.c probably
> > would need some modification to pass the correct text and data bases.
>
> Perhaps you could force __text_seg to be .hidden. I don't know if
> the hpux linker supports that sort of thing though...
The segment bases are a bit of a problem. It appears that they must
be obtained from the dynamic loader using dlget() or dlmodinfo() calls.
The later provides a load module descriptor for an instruction pointer.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: update dwarf2 asm unwind info [hppa64-*-* failures]
2008-08-25 1:42 ` Richard Henderson
2008-08-25 3:31 ` John David Anglin
@ 2008-08-25 4:57 ` John David Anglin
1 sibling, 0 replies; 521+ messages in thread
From: John David Anglin @ 2008-08-25 4:57 UTC (permalink / raw)
To: Richard Henderson; +Cc: sje, gcc-patches, dave.anglin, binutils-patches
>
> John David Anglin wrote:
> > Making .eh_frame read-only would
> > have to be forced. I believe that we would need the same pc-relative
> > indirect trick as we currently use on linux to get the plabel out of
> > .eh_frame (see patch below).
>
> The patch is wrong. We handle the indirect part inside the compiler
> before we pass it on to the assembler.
Ok, I see. It handles the case in a manner similar to that in
dwarf2asm.c. I will recheck but I believe there was a problem in
using dw2_force_const_mem() for the indirection to a plabel. We
handle the output ourself using ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
when not using CFI directives.
Trying to make .eh_frame read-only didn't work on hppa64-hpux.
So, we have to deal with the assembler using pc-relative relocations
for the FDE's until I see if segment relative relocations can
be made to work. Possibly, DIFF_EXPR_OK shouldn't be defined although
I'm hesitant to give up completely on it as it works within a
segment. However, it still should be possible to generate pc-relative
data using the obscure $PIC_pcrel$0 semantics.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Fix previous change to pa.c
[not found] <no.id>
` (160 preceding siblings ...)
2008-08-18 14:23 ` update dwarf2 asm unwind info [hppa64-*-* failures] John David Anglin
@ 2009-08-02 19:35 ` John David Anglin
2009-11-25 3:28 ` [committed] Shorten non PIC PA 1.1 calls on hppa-hpux John David Anglin
2010-03-27 15:44 ` [PATCH] Fix visibility of constructors/destructors with -fwhole-program John David Anglin
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2009-08-02 19:35 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The enclosed fixes compile errors instroduced in the previous change
> to the file. Tested on hppa-unknown-linux-gnu. Committed to trunk.
I was a bit too quick. This cleans up the declaration. Tested on
hppa-unknown-linux-gnu with compile check. Committed to trunk.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2009-08-02 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.c (pa_promote_function_mode): Remove ATTRIBUTE_UNUSED from
declaration arguments.
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c (revision 150354)
+++ config/pa/pa.c (working copy)
@@ -159,11 +159,9 @@
enum machine_mode,
secondary_reload_info *);
static void pa_extra_live_on_entry (bitmap);
-static enum machine_mode pa_promote_function_mode (const_tree ATTRIBUTE_UNUSED,
- enum machine_mode,
- int * ATTRIBUTE_UNUSED,
- const_tree ATTRIBUTE_UNUSED,
- int for_return);
+static enum machine_mode pa_promote_function_mode (const_tree,
+ enum machine_mode, int *,
+ const_tree, int);
/* The following extra sections are only used for SOM. */
static GTY(()) section *som_readonly_data_section;
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [committed] Shorten non PIC PA 1.1 calls on hppa-hpux
[not found] <no.id>
` (161 preceding siblings ...)
2009-08-02 19:35 ` [committed] Fix previous change to pa.c John David Anglin
@ 2009-11-25 3:28 ` John David Anglin
2010-03-27 15:44 ` [PATCH] Fix visibility of constructors/destructors with -fwhole-program John David Anglin
163 siblings, 0 replies; 521+ messages in thread
From: John David Anglin @ 2009-11-25 3:28 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches
> The enclosed change shortens long PA 1.x calls when not generating PIC
> code. In this case, we can just use space register sr4 for the be and
> bel branch instructions, avoiding two instructions to load the space
> register of the call destination. This is always a stub in the current
> space.
Sigh, I was wrong about there always being a stub in the current space.
With the above change, we get an ICE building the current trunk. The
attached patch revises the change to only use the sr4 short form when
the call target binds local. The problem affects 32-bit hppa*-*-hpux*.
Current change was tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11,
trunk and 4.4 branches with no regressions. Committed to trunk and 4.4.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2009-11-24 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.c (output_call): Only use sr4 for long interspace calls if
call binds local and generating non PIC code.
(attr_length_call): Adjust length calculation for above.
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c (revision 152888)
+++ config/pa/pa.c (working copy)
@@ -7437,7 +7437,7 @@
{
length += 20;
- if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS && flag_pic)
+ if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
length += 8;
}
@@ -7457,7 +7457,7 @@
if (!sibcall)
length += 8;
- if (!TARGET_NO_SPACE_REGS && flag_pic)
+ if (!TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
length += 8;
}
}
@@ -7654,7 +7654,7 @@
if (!sibcall && !TARGET_PA_20)
{
output_asm_insn ("{bl|b,l} .+8,%%r2", xoperands);
- if (TARGET_NO_SPACE_REGS)
+ if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
output_asm_insn ("addi 8,%%r2,%%r2", xoperands);
else
output_asm_insn ("addi 16,%%r2,%%r2", xoperands);
@@ -7679,20 +7679,20 @@
}
else
{
- if (!TARGET_NO_SPACE_REGS && flag_pic)
+ if (!TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
output_asm_insn ("ldsid (%%r1),%%r31\n\tmtsp %%r31,%%sr0",
xoperands);
if (sibcall)
{
- if (TARGET_NO_SPACE_REGS || !flag_pic)
+ if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
output_asm_insn ("be 0(%%sr4,%%r1)", xoperands);
else
output_asm_insn ("be 0(%%sr0,%%r1)", xoperands);
}
else
{
- if (TARGET_NO_SPACE_REGS || !flag_pic)
+ if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
output_asm_insn ("ble 0(%%sr4,%%r1)", xoperands);
else
output_asm_insn ("ble 0(%%sr0,%%r1)", xoperands);
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with -fwhole-program
[not found] <no.id>
` (162 preceding siblings ...)
2009-11-25 3:28 ` [committed] Shorten non PIC PA 1.1 calls on hppa-hpux John David Anglin
@ 2010-03-27 15:44 ` John David Anglin
2010-03-27 15:52 ` Richard Guenther
2010-03-27 17:53 ` Jan Hubicka
163 siblings, 2 replies; 521+ messages in thread
From: John David Anglin @ 2010-03-27 15:44 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rguenth
> This patch fixes PR middle-end/41674. With -fwhole-program, the
> constructor _GLOBAL__I_65535_0_main has its public flag turned off
> by function_and_variable_visibility and thereby made local. However,
> these symbols need to be global for collect2 to arrange to call them.
>
> Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
Here is take 2. The first version was deemed overkill and Richard suggested
using DECL_PRESERVE_P.
Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11 with no regressions.
Ok for trunk?
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2010-01-02 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle-end/41674
* cgraphunit.c (cgraph_build_static_cdtor): If target doesn't have
cdtors, set DECL_PRESERVE_P.
* ipa.c (cgraph_externally_visible_p): Return true if declaration
should be preseved.
Index: cgraphunit.c
===================================================================
--- cgraphunit.c (revision 157617)
+++ cgraphunit.c (working copy)
@@ -1946,7 +1946,11 @@
DECL_ARTIFICIAL (decl) = 1;
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
DECL_SAVED_TREE (decl) = body;
- TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors;
+ if (!targetm.have_ctors_dtors)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_PRESERVE_P (decl) = 1;
+ }
DECL_UNINLINABLE (decl) = 1;
DECL_INITIAL (decl) = make_node (BLOCK);
Index: ipa.c
===================================================================
--- ipa.c (revision 157617)
+++ ipa.c (working copy)
@@ -317,6 +317,8 @@
return false;
if (!whole_program)
return true;
+ if (DECL_PRESERVE_P (node->decl))
+ return true;
/* COMDAT functions must be shared only if they have address taken,
otherwise we can produce our own private implementation with
-fwhole-program. */
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with -fwhole-program
2010-03-27 15:44 ` [PATCH] Fix visibility of constructors/destructors with -fwhole-program John David Anglin
@ 2010-03-27 15:52 ` Richard Guenther
2010-03-27 17:53 ` Jan Hubicka
1 sibling, 0 replies; 521+ messages in thread
From: Richard Guenther @ 2010-03-27 15:52 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rguenth
On Sat, 27 Mar 2010, John David Anglin wrote:
> > This patch fixes PR middle-end/41674. With -fwhole-program, the
> > constructor _GLOBAL__I_65535_0_main has its public flag turned off
> > by function_and_variable_visibility and thereby made local. However,
> > these symbols need to be global for collect2 to arrange to call them.
> >
> > Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
>
> Here is take 2. The first version was deemed overkill and Richard suggested
> using DECL_PRESERVE_P.
>
> Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11 with no regressions.
>
> Ok for trunk?
Ok.
Thanks,
Richard.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with -fwhole-program
2010-03-27 15:44 ` [PATCH] Fix visibility of constructors/destructors with -fwhole-program John David Anglin
2010-03-27 15:52 ` Richard Guenther
@ 2010-03-27 17:53 ` Jan Hubicka
2010-03-27 21:11 ` [PATCH] Fix visibility of constructors/destructors with John David Anglin
1 sibling, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2010-03-27 17:53 UTC (permalink / raw)
To: John David Anglin; +Cc: gcc-patches, rguenth
> > This patch fixes PR middle-end/41674. With -fwhole-program, the
> > constructor _GLOBAL__I_65535_0_main has its public flag turned off
> > by function_and_variable_visibility and thereby made local. However,
> > these symbols need to be global for collect2 to arrange to call them.
> >
> > Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11.
>
> Here is take 2. The first version was deemed overkill and Richard suggested
> using DECL_PRESERVE_P.
>
> Tested on hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11 with no regressions.
>
> Ok for trunk?
Hmm, I see it was applied already, but this imply that attribute used on functions
now imply externally_visible, while on variables it does not.
I am not sure what would be best behaviour of used WRT whole-program. I guess
the symbol should be still brought static, but the mangling (i.e. .1234) should
not be applied so asm statements from other source files (within same LTO unit)
can refer to it.
I guess it is resonable to want something like the following work:
t1.c:
__attribute__ ((used)) int q;
__attribute__ ((used))
void
t()
{
}
t2.c:
main()
{
int q;
asm("call t; movl $q,%0":"=r"(q));
return q;
}
and expect this to link properly -fwhole-program or not and I guess also to
make -fwhole-program privatize both q and t unless externally_visible is given.
At present (before this patch) we seem to get 't' right (i.e. it is static and
with original name), but we do not output q. If this seems like intended
behaviour, I guess I can fix this as well as make this hppa fix to attach
externally visible attribute (or simply force externally visible flag on the
cgraph node that should have same effect)
Honza
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with
2010-03-27 17:53 ` Jan Hubicka
@ 2010-03-27 21:11 ` John David Anglin
2010-03-27 21:48 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: John David Anglin @ 2010-03-27 21:11 UTC (permalink / raw)
To: Jan Hubicka; +Cc: gcc-patches, rguenth
> Hmm, I see it was applied already, but this imply that attribute used on functions
> now imply externally_visible, while on variables it does not.
It only implies externally_visible with -fwhole-program if the declaration
was originally externally visible.
The documentation for attribute used says:
@item used
@cindex @code{used} attribute.
This attribute, attached to a function, means that code must be emitted
for the function even if it appears that the function is not referenced.
This is useful, for example, when the function is referenced only in
inline assembly.
As can be seen, there is no mention on its effect on variables and
as far as I can tell the change didn't alter the visibility of variables
given that cgraph_externally_visible_p is not currently called for
variables.
> I am not sure what would be best behaviour of used WRT whole-program. I guess
> the symbol should be still brought static, but the mangling (i.e. .1234) should
> not be applied so asm statements from other source files (within same LTO unit)
> can refer to it.
>
> I guess it is resonable to want something like the following work:
>
> t1.c:
> __attribute__ ((used)) int q;
> __attribute__ ((used))
> void
> t()
> {
> }
>
> t2.c:
> main()
> {
> int q;
> asm("call t; movl $q,%0":"=r"(q));
> return q;
> }
>
> and expect this to link properly -fwhole-program or not and I guess also to
> make -fwhole-program privatize both q and t unless externally_visible is given.
>
> At present (before this patch) we seem to get 't' right (i.e. it is static and
> with original name), but we do not output q. If this seems like intended
> behaviour, I guess I can fix this as well as make this hppa fix to attach
> externally visible attribute (or simply force externally visible flag on the
> cgraph node that should have same effect)
The only reason I didn't try using the externally visible attribute was
attaching the attribute seemed tricky.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with
2010-03-27 21:11 ` [PATCH] Fix visibility of constructors/destructors with John David Anglin
@ 2010-03-27 21:48 ` Jan Hubicka
2010-03-27 21:54 ` Richard Guenther
0 siblings, 1 reply; 521+ messages in thread
From: Jan Hubicka @ 2010-03-27 21:48 UTC (permalink / raw)
To: John David Anglin; +Cc: Jan Hubicka, gcc-patches, rguenth
> > Hmm, I see it was applied already, but this imply that attribute used on functions
> > now imply externally_visible, while on variables it does not.
>
> It only implies externally_visible with -fwhole-program if the declaration
> was originally externally visible.
>
> The documentation for attribute used says:
>
> @item used
> @cindex @code{used} attribute.
> This attribute, attached to a function, means that code must be emitted
> for the function even if it appears that the function is not referenced.
> This is useful, for example, when the function is referenced only in
> inline assembly.
Well, the manual says nothing about external visibility. It only says that you
can reffer it from assembly (as given in the example bellow). I would say that
for -fwhole-program we can still bring it local as long as all the assembly
refering it is part of the unit and otherwise user is required to add the
externally visible attribute same way as he has to add to anything else refered
outside the unit compiled with -fwhole-program.
"used" attribute is IMO intended primarily for static variables/functions
refered from inline assembly. For functions referred from assembly in .s unit
no decoration is needed.
>
> As can be seen, there is no mention on its effect on variables and
> as far as I can tell the change didn't alter the visibility of variables
> given that cgraph_externally_visible_p is not currently called for
> variables.
The documentation does not speak about variables, but since unit-at-a-time was
introduced we support both (i.e. the unused/used attributes on both variables
and functions) and they should behave symmetricaly. This change breaks the
symmetry.
Honza
>
> > I am not sure what would be best behaviour of used WRT whole-program. I guess
> > the symbol should be still brought static, but the mangling (i.e. .1234) should
> > not be applied so asm statements from other source files (within same LTO unit)
> > can refer to it.
> >
> > I guess it is resonable to want something like the following work:
> >
> > t1.c:
> > __attribute__ ((used)) int q;
> > __attribute__ ((used))
> > void
> > t()
> > {
> > }
> >
> > t2.c:
> > main()
> > {
> > int q;
> > asm("call t; movl $q,%0":"=r"(q));
> > return q;
> > }
> >
> > and expect this to link properly -fwhole-program or not and I guess also to
> > make -fwhole-program privatize both q and t unless externally_visible is given.
> >
> > At present (before this patch) we seem to get 't' right (i.e. it is static and
> > with original name), but we do not output q. If this seems like intended
> > behaviour, I guess I can fix this as well as make this hppa fix to attach
> > externally visible attribute (or simply force externally visible flag on the
> > cgraph node that should have same effect)
>
> The only reason I didn't try using the externally visible attribute was
> attaching the attribute seemed tricky.
>
> Dave
> --
> J. David Anglin dave.anglin@nrc-cnrc.gc.ca
> National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with
2010-03-27 21:48 ` Jan Hubicka
@ 2010-03-27 21:54 ` Richard Guenther
2010-03-28 1:39 ` Jan Hubicka
0 siblings, 1 reply; 521+ messages in thread
From: Richard Guenther @ 2010-03-27 21:54 UTC (permalink / raw)
To: Jan Hubicka; +Cc: John David Anglin, gcc-patches, rguenth
On Sat, 27 Mar 2010, Jan Hubicka wrote:
> > > Hmm, I see it was applied already, but this imply that attribute used on functions
> > > now imply externally_visible, while on variables it does not.
> >
> > It only implies externally_visible with -fwhole-program if the declaration
> > was originally externally visible.
> >
> > The documentation for attribute used says:
> >
> > @item used
> > @cindex @code{used} attribute.
> > This attribute, attached to a function, means that code must be emitted
> > for the function even if it appears that the function is not referenced.
> > This is useful, for example, when the function is referenced only in
> > inline assembly.
>
> Well, the manual says nothing about external visibility. It only says that you
> can reffer it from assembly (as given in the example bellow). I would say that
> for -fwhole-program we can still bring it local as long as all the assembly
> refering it is part of the unit and otherwise user is required to add the
> externally visible attribute same way as he has to add to anything else refered
> outside the unit compiled with -fwhole-program.
>
> "used" attribute is IMO intended primarily for static variables/functions
> refered from inline assembly. For functions referred from assembly in .s unit
> no decoration is needed.
Well, I think "used" means used in ways not visible to the compiler.
So I think making that imply "externally_visible" is reasonable
(and as we can't do anything useful with "used" things not bringing
it local with -fwhole-program shouldn't be something to worry about).
But yes, the change should probably be applied to variables as well.
Richard.
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] Fix visibility of constructors/destructors with
2010-03-27 21:54 ` Richard Guenther
@ 2010-03-28 1:39 ` Jan Hubicka
0 siblings, 0 replies; 521+ messages in thread
From: Jan Hubicka @ 2010-03-28 1:39 UTC (permalink / raw)
To: Richard Guenther; +Cc: Jan Hubicka, John David Anglin, gcc-patches, rguenth
> On Sat, 27 Mar 2010, Jan Hubicka wrote:
>
> > > > Hmm, I see it was applied already, but this imply that attribute used on functions
> > > > now imply externally_visible, while on variables it does not.
> > >
> > > It only implies externally_visible with -fwhole-program if the declaration
> > > was originally externally visible.
> > >
> > > The documentation for attribute used says:
> > >
> > > @item used
> > > @cindex @code{used} attribute.
> > > This attribute, attached to a function, means that code must be emitted
> > > for the function even if it appears that the function is not referenced.
> > > This is useful, for example, when the function is referenced only in
> > > inline assembly.
> >
> > Well, the manual says nothing about external visibility. It only says that you
> > can reffer it from assembly (as given in the example bellow). I would say that
> > for -fwhole-program we can still bring it local as long as all the assembly
> > refering it is part of the unit and otherwise user is required to add the
> > externally visible attribute same way as he has to add to anything else refered
> > outside the unit compiled with -fwhole-program.
> >
> > "used" attribute is IMO intended primarily for static variables/functions
> > refered from inline assembly. For functions referred from assembly in .s unit
> > no decoration is needed.
>
> Well, I think "used" means used in ways not visible to the compiler.
> So I think making that imply "externally_visible" is reasonable
> (and as we can't do anything useful with "used" things not bringing
> it local with -fwhole-program shouldn't be something to worry about).
We can still e.g. emit IP relative relocations for it in PIC libraries etc.
But since not bringing used symbols local is conservative thing to do, I am fine with that.
If we won't explicitly document this behaviour we can still later make thing more aggressive if we
find use for this. I am not sure how many real uses ((used)) attribute has in code that cares
about performance.
Honza
>
> But yes, the change should probably be applied to variables as well.
>
> Richard.
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH] strub: machine-independent stack scrubbing
[not found] <ormtqpsbuc.fsf@lxoliva.fsfla.org>
@ 2021-09-09 7:11 ` Alexandre Oliva
2022-07-29 6:16 ` [PATCH v2 00/10] Introduce " Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2021-09-09 7:11 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson
(moving from gcc@ to gcc-patches@)
On Jul 14, 2021, Alexandre Oliva <oliva@adacore.com> wrote:
> I've been working on an implementation of stack scrubbing
https://gcc.gnu.org/pipermail/gcc/2021-July/236780.html
Here's the patch that implements it.
introduce stack scrub (strub) feature
This patch adds the strub attribute for function and variable types,
command-line options, passes and adjustments to implement it,
documentation, and tests.
Regstrapped on x86_64-linux-gnu. Also successfully bootstrapped with
-fstrub=all, along with other patches in branch users/aoliva/heads/strub:
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575040.html
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575043.html
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575044.html
Is this ok to install?
for gcc/ChangeLog
* Makefile.in (OBJS): Add ipa-strub.o.
* builtins.def (BUILT_IN_STACK_ADDRESS): New.
(BUILT_IN___STRUB_ENTER): New.
(BUILT_IN___STRUB_UPDATE): New.
(BUILT_IN___STRUB_LEAVE): New.
* builtins.c: Include ipa-strub.h.
(STACK_STOPS, STACK_UNSIGNED): Define.
(expand_builtin_stack_address): New.
(expand_builtin_strub_enter): New.
(expand_builtin_strub_update): New.
(expand_builtin_strub_leave): New.
(expand_bulitin): Call them.
* common.opt (fstrub=*): New options.
* doc/extend.texi (strub): New type attribute.
(__builtin_stack_address): New function.
(Stack Scrubbing): New section.
* doc/invoke.texi (-fstrub=*): New options.
(-fdump-ipa-*): New passes.
* ipa-inline.c: Include ipa-strub.h.
(can_inline_edge_p): Test strub_inlinable_to_p.
* ipa-split.c: Include ipa-strub.h.
(execute_split_functions): Test strub_splittable_p.
* ipa-strub.c, ipa-strub.h: New.
* passes.def: Add strub_mode and strub passes.
* tree-cfg.c (gimple_verify_flow_info): Note on debug stmts.
* tree-pass.h (make_pass_ipa_strub_mode): Declare.
(make_pass_ipa_strub): Declare.
(make_pass_ipa_function_and_variable_visibility): Fix
formatting.
* tree-ssa-ccp.c (optimize_stack_restore): Keep restores
before strub leave.
* multiple_target.c (pass_target_clone::gate): Test seen_error.
* attribs.c: Include ipa-strub.h.
(decl_attributes): Support applying attributes to function
type, rather than pointer type, at handler's request.
(comp_type_attributes): Combine strub_comptypes and target
comp_type results.
for gcc/c-family/ChangeLog
* c-attribs.c: Include ipa-strub.h.
(handle_strub_attribute): New.
(c_common_attribute_table): Add strub.
for gcc/ada/ChangeLog
* doc/gnat_rm.rst: Add...
* doc/gnat_rm/security_hardening_features.rst: New.
* doc/gnat_rm/about_this_guide.rst: Link to new chapter.
* libgnat/a-except.adb: Make Rcheck_CE_* strub-callable.
* libgnat/a-except.ads (Raise_Exception): Likewise.
(Raise_Exception_Always): Likewise.
* libgnat/s-arit128.ads (Multiply_With_Ovflo_Check128):
Likewise.
* libgnat/s-arit64.ads (Multiply_With_Ovflo_Check64):
Likewise.
* libgnat/s-secsta.ads (SS_Allocate, SS_Mark, SS_Release):
Likewise.
* gcc-interface/trans.c: Include ipa-strub.h.
(gigi): Make internal decls for targets of compiler-generated
calls strub-callable too.
* gcc-interface/utils.c: Include ipa-strub.h.
(handle_strub_attribute): New.
(gnat_internal_attribute_table): Add strub.
for gcc/testsuite/ChangeLog
* c-c++-common/strub-O0.c: New.
* c-c++-common/strub-O1.c: New.
* c-c++-common/strub-O2.c: New.
* c-c++-common/strub-O2fni.c: New.
* c-c++-common/strub-O3.c: New.
* c-c++-common/strub-O3fni.c: New.
* c-c++-common/strub-Og.c: New.
* c-c++-common/strub-Os.c: New.
* c-c++-common/strub-all1.c: New.
* c-c++-common/strub-all2.c: New.
* c-c++-common/strub-apply1.c: New.
* c-c++-common/strub-apply2.c: New.
* c-c++-common/strub-apply3.c: New.
* c-c++-common/strub-apply4.c: New.
* c-c++-common/strub-at-calls1.c: New.
* c-c++-common/strub-at-calls2.c: New.
* c-c++-common/strub-defer-O1.c: New.
* c-c++-common/strub-defer-O2.c: New.
* c-c++-common/strub-defer-O3.c: New.
* c-c++-common/strub-defer-Os.c: New.
* c-c++-common/strub-internal1.c: New.
* c-c++-common/strub-internal2.c: New.
* c-c++-common/strub-parms1.c: New.
* c-c++-common/strub-parms2.c: New.
* c-c++-common/strub-parms3.c: New.
* c-c++-common/strub-relaxed1.c: New.
* c-c++-common/strub-relaxed2.c: New.
* c-c++-common/strub-short-O0-exc.c: New.
* c-c++-common/strub-short-O0.c: New.
* c-c++-common/strub-short-O1.c: New.
* c-c++-common/strub-short-O2.c: New.
* c-c++-common/strub-short-O3.c: New.
* c-c++-common/strub-short-Os.c: New.
* c-c++-common/strub-strict1.c: New.
* c-c++-common/strub-strict2.c: New.
* c-c++-common/strub-tail-O1.c: New.
* c-c++-common/strub-tail-O2.c: New.
* c-c++-common/torture/strub-callable1.c: New.
* c-c++-common/torture/strub-callable2.c: New.
* c-c++-common/torture/strub-const1.c: New.
* c-c++-common/torture/strub-const2.c: New.
* c-c++-common/torture/strub-const3.c: New.
* c-c++-common/torture/strub-const4.c: New.
* c-c++-common/torture/strub-data1.c: New.
* c-c++-common/torture/strub-data2.c: New.
* c-c++-common/torture/strub-data3.c: New.
* c-c++-common/torture/strub-data4.c: New.
* c-c++-common/torture/strub-data5.c: New.
* c-c++-common/torture/strub-indcall1.c: New.
* c-c++-common/torture/strub-indcall2.c: New.
* c-c++-common/torture/strub-indcall3.c: New.
* c-c++-common/torture/strub-inlinable1.c: New.
* c-c++-common/torture/strub-inlinable2.c: New.
* c-c++-common/torture/strub-ptrfn1.c: New.
* c-c++-common/torture/strub-ptrfn2.c: New.
* c-c++-common/torture/strub-ptrfn3.c: New.
* c-c++-common/torture/strub-ptrfn4.c: New.
* c-c++-common/torture/strub-pure1.c: New.
* c-c++-common/torture/strub-pure2.c: New.
* c-c++-common/torture/strub-pure3.c: New.
* c-c++-common/torture/strub-pure4.c: New.
* c-c++-common/torture/strub-run1.c: New.
* c-c++-common/torture/strub-run2.c: New.
* c-c++-common/torture/strub-run3.c: New.
* c-c++-common/torture/strub-run4.c: New.
* c-c++-common/torture/strub-run4c.c: New.
* c-c++-common/torture/strub-run4d.c: New.
* c-c++-common/torture/strub-run4i.c: New.
* g++.dg/strub-run1.C: New.
* g++.dg/torture/strub-init1.C: New.
* g++.dg/torture/strub-init2.C: New.
* g++.dg/torture/strub-init3.C: New.
* gnat.dg/strub_attr.adb, gnat.dg/strub_attr.ads: New.
* gnat.dg/strub_ind.adb, gnat.dg/strub_ind.ads: New.
for libgcc/ChangeLog
* Makefile.in (LIB2ADD): Add strub.c.
* libgcc2.h (__strub_enter, __strub_update, __strub_leave):
Declare.
* strub.c: New.
---
gcc/Makefile.in | 1
gcc/ada/doc/gnat_rm.rst | 1
gcc/ada/doc/gnat_rm/about_this_guide.rst | 3
.../doc/gnat_rm/security_hardening_features.rst | 88 +
gcc/ada/gcc-interface/trans.c | 5
gcc/ada/gcc-interface/utils.c | 67
gcc/ada/libgnat/a-except.adb | 90 +
gcc/ada/libgnat/a-except.ads | 8
gcc/ada/libgnat/s-arit128.ads | 6
gcc/ada/libgnat/s-arit64.ads | 6
gcc/ada/libgnat/s-secsta.ads | 10
gcc/attribs.c | 39
gcc/builtins.c | 273 ++
gcc/builtins.def | 4
gcc/c-family/c-attribs.c | 68
gcc/common.opt | 29
gcc/doc/extend.texi | 307 ++
gcc/doc/invoke.texi | 60
gcc/ipa-inline.c | 6
gcc/ipa-split.c | 7
gcc/ipa-strub.c | 3336 ++++++++++++++++++++
gcc/ipa-strub.h | 45
gcc/multiple_target.c | 2
gcc/passes.def | 2
gcc/testsuite/c-c++-common/strub-O0.c | 14
gcc/testsuite/c-c++-common/strub-O1.c | 15
gcc/testsuite/c-c++-common/strub-O2.c | 16
gcc/testsuite/c-c++-common/strub-O2fni.c | 15
gcc/testsuite/c-c++-common/strub-O3.c | 12
gcc/testsuite/c-c++-common/strub-O3fni.c | 15
gcc/testsuite/c-c++-common/strub-Og.c | 16
gcc/testsuite/c-c++-common/strub-Os.c | 18
gcc/testsuite/c-c++-common/strub-all1.c | 32
gcc/testsuite/c-c++-common/strub-all2.c | 24
gcc/testsuite/c-c++-common/strub-apply1.c | 15
gcc/testsuite/c-c++-common/strub-apply2.c | 12
gcc/testsuite/c-c++-common/strub-apply3.c | 8
gcc/testsuite/c-c++-common/strub-apply4.c | 21
gcc/testsuite/c-c++-common/strub-at-calls1.c | 30
gcc/testsuite/c-c++-common/strub-at-calls2.c | 23
gcc/testsuite/c-c++-common/strub-defer-O1.c | 7
gcc/testsuite/c-c++-common/strub-defer-O2.c | 8
gcc/testsuite/c-c++-common/strub-defer-O3.c | 93 +
gcc/testsuite/c-c++-common/strub-defer-Os.c | 7
gcc/testsuite/c-c++-common/strub-internal1.c | 31
gcc/testsuite/c-c++-common/strub-internal2.c | 21
gcc/testsuite/c-c++-common/strub-parms1.c | 48
gcc/testsuite/c-c++-common/strub-parms2.c | 36
gcc/testsuite/c-c++-common/strub-parms3.c | 58
gcc/testsuite/c-c++-common/strub-relaxed1.c | 18
gcc/testsuite/c-c++-common/strub-relaxed2.c | 14
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 10
gcc/testsuite/c-c++-common/strub-short-O0.c | 10
gcc/testsuite/c-c++-common/strub-short-O1.c | 10
gcc/testsuite/c-c++-common/strub-short-O2.c | 10
gcc/testsuite/c-c++-common/strub-short-O3.c | 12
gcc/testsuite/c-c++-common/strub-short-Os.c | 12
gcc/testsuite/c-c++-common/strub-strict1.c | 36
gcc/testsuite/c-c++-common/strub-strict2.c | 25
gcc/testsuite/c-c++-common/strub-tail-O1.c | 8
gcc/testsuite/c-c++-common/strub-tail-O2.c | 14
.../c-c++-common/torture/strub-callable1.c | 9
.../c-c++-common/torture/strub-callable2.c | 264 ++
gcc/testsuite/c-c++-common/torture/strub-const1.c | 18
gcc/testsuite/c-c++-common/torture/strub-const2.c | 22
gcc/testsuite/c-c++-common/torture/strub-const3.c | 13
gcc/testsuite/c-c++-common/torture/strub-const4.c | 17
gcc/testsuite/c-c++-common/torture/strub-data1.c | 13
gcc/testsuite/c-c++-common/torture/strub-data2.c | 14
gcc/testsuite/c-c++-common/torture/strub-data3.c | 14
gcc/testsuite/c-c++-common/torture/strub-data4.c | 14
gcc/testsuite/c-c++-common/torture/strub-data5.c | 15
.../c-c++-common/torture/strub-indcall1.c | 14
.../c-c++-common/torture/strub-indcall2.c | 14
.../c-c++-common/torture/strub-indcall3.c | 14
.../c-c++-common/torture/strub-inlinable1.c | 16
.../c-c++-common/torture/strub-inlinable2.c | 7
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 10
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 55
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 50
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 43
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17
gcc/testsuite/c-c++-common/torture/strub-run1.c | 85 +
gcc/testsuite/c-c++-common/torture/strub-run2.c | 75
gcc/testsuite/c-c++-common/torture/strub-run3.c | 75
gcc/testsuite/c-c++-common/torture/strub-run4.c | 101 +
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 5
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 7
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 5
gcc/testsuite/g++.dg/strub-run1.C | 19
gcc/testsuite/g++.dg/torture/strub-init1.C | 13
gcc/testsuite/g++.dg/torture/strub-init2.C | 14
gcc/testsuite/g++.dg/torture/strub-init3.C | 13
gcc/testsuite/gnat.dg/strub_attr.adb | 37
gcc/testsuite/gnat.dg/strub_attr.ads | 12
gcc/testsuite/gnat.dg/strub_ind.adb | 44
gcc/testsuite/gnat.dg/strub_ind.ads | 23
gcc/tree-cfg.c | 1
gcc/tree-pass.h | 5
gcc/tree-ssa-ccp.c | 4
libgcc/Makefile.in | 2
libgcc/libgcc2.h | 4
libgcc/strub.c | 112 +
106 files changed, 6588 insertions(+), 11 deletions(-)
create mode 100644 gcc/ada/doc/gnat_rm/security_hardening_features.rst
create mode 100644 gcc/ipa-strub.c
create mode 100644 gcc/ipa-strub.h
create mode 100644 gcc/testsuite/c-c++-common/strub-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Og.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply4.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0-exc.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data5.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4c.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4d.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4i.c
create mode 100644 gcc/testsuite/g++.dg/strub-run1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init2.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init3.C
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.ads
create mode 100644 libgcc/strub.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f0c560fe45b77..b60bf8f3d3e64 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1472,6 +1472,7 @@ OBJS = \
ipa-reference.o \
ipa-ref.o \
ipa-utils.o \
+ ipa-strub.o \
ipa.o \
ira.o \
ira-build.o \
diff --git a/gcc/ada/doc/gnat_rm.rst b/gcc/ada/doc/gnat_rm.rst
index 97f7e4d457036..7743ef8b5f437 100644
--- a/gcc/ada/doc/gnat_rm.rst
+++ b/gcc/ada/doc/gnat_rm.rst
@@ -55,6 +55,7 @@ GNAT Reference Manual
gnat_rm/specialized_needs_annexes
gnat_rm/implementation_of_specific_ada_features
gnat_rm/implementation_of_ada_2012_features
+ gnat_rm/security_hardening_features
gnat_rm/obsolescent_features
gnat_rm/compatibility_and_porting_guide
diff --git a/gcc/ada/doc/gnat_rm/about_this_guide.rst b/gcc/ada/doc/gnat_rm/about_this_guide.rst
index b48785eeed0e9..9defee818aca3 100644
--- a/gcc/ada/doc/gnat_rm/about_this_guide.rst
+++ b/gcc/ada/doc/gnat_rm/about_this_guide.rst
@@ -96,6 +96,9 @@ This reference manual contains the following chapters:
* :ref:`Implementation_of_Ada_2012_Features`, describes the status of the
GNAT implementation of the Ada 2012 language standard.
+* :ref:`Security_Hardening_Features` documents GNAT extensions aimed
+ at security hardening.
+
* :ref:`Obsolescent_Features` documents implementation dependent features,
including pragmas and attributes, which are considered obsolescent, since
there are other preferred ways of achieving the same results. These
diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst
new file mode 100644
index 0000000000000..753452904128e
--- /dev/null
+++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst
@@ -0,0 +1,88 @@
+.. _Security_Hardening_Features:
+
+***************************
+Security Hardening Features
+***************************
+
+This chapter describes Ada extensions aimed at security hardening that
+are provided by GNAT.
+
+.. Register Scrubbing:
+
+Register Scrubbing
+==================
+
+GNAT can generate code to zero-out hardware registers before returning
+from a subprogram.
+
+It can be enabled with the *-fzero-call-used-regs* command line
+option, to affect all subprograms in a compilation, and with a
+:samp:`Machine_Attribute` pragma, to affect only specific subprograms.
+
+.. code-block:: ada
+
+ procedure Foo;
+ pragma Machine_Attribute (Foo, "zero_call_used_regs", "used");
+ -- Before returning, Foo scrubs only call-clobbered registers
+ -- that it uses itself.
+
+ function Bar return Integer;
+ pragma Machine_Attribute (Bar, "zero_call_used_regs", "all");
+ -- Before returning, Bar scrubs all call-clobbered registers.
+
+
+For usage and more details on the command line option, and on the
+``zero_call_used_regs`` attribute, see :title:`Using the GNU Compiler
+Collection (GCC)`.
+
+
+.. Stack Scrubbing:
+
+Stack Scrubbing
+===============
+
+GNAT can generate code to zero-out stack frames used by subprograms.
+
+It can be activated with the :samp:`Machine_Attribute` pragma, on
+specific subprograms, variables, and types.
+
+.. code-block:: ada
+
+ function Foo returns Integer;
+ pragma Machine_Attribute (Foo, "strub");
+ -- Foo and its callers are modified so as to scrub the stack
+ -- space used by Foo after it returns.
+
+ procedure Bar;
+ pragma Machine_Attribute (Bar, "strub", "internal");
+ -- Bar is turned into a wrapper for its original body,
+ -- and they scrub the stack used by the original body.
+
+ Var : Integer;
+ pragma Machine_Attribute (Var, "strub");
+ -- Reading from Var in a subprogram enables stack scrubbing
+ -- of the stack space used by the subprogram.
+
+
+There are also *-fstrub* command line options to control default
+settings. For usage and more details on the command line option, and
+on the ``strub`` attribute, see :title:`Using the GNU Compiler
+Collection (GCC)`.
+
+Note that Ada secondary stacks are not scrubbed. The restriction
+``No_Secondary_Stack`` avoids their use, and thus their accidental
+preservation of data that should be scrubbed.
+
+Also note that the machine attribute is not integrated in the Ada type
+system. Though it may modify subprogram and variable interfaces, it
+is not fully reflected in Ada types, ``Access`` attributes, renaming
+and overriding. Every access type, renaming, and overriding and
+overridden dispatching operations that may refer to an entity with an
+attribute-modified interface must be annotated with the same
+interface-modifying attribute, or with an interface-compatible one.
+
+Even then, applying the pragma to anything other than subprograms and
+scalar variables is not currently supported, and may be silently
+ignored. Specifically, it is not recommended to rely on any effects
+of this pragma on access types and objects to data variables and to
+subprograms.
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 3df56aa0560e1..f1524a3fb906c 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -43,6 +43,7 @@
#include "output.h"
#include "debug.h"
#include "libfuncs.h" /* For set_stack_check_libfunc. */
+#include "ipa-strub.h" /* For strub_make_callable. */
#include "tree-iterator.h"
#include "gimplify.h"
#include "opts.h"
@@ -444,6 +445,7 @@ gigi (Node_Id gnat_root,
int64_type, NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv64_decl);
if (Enable_128bit_Types)
{
@@ -456,6 +458,7 @@ gigi (Node_Id gnat_root,
NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv128_decl);
}
/* Name of the _Parent field in tagged record types. */
@@ -531,6 +534,7 @@ gigi (Node_Id gnat_root,
= create_subprog_decl
(get_identifier ("__gnat_raise_nodefer_with_msg"), NULL_TREE, ftype,
NULL_TREE, is_default, true, true, true, false, false, NULL, Empty);
+ strub_make_callable (raise_nodefer_decl);
set_exception_parameter_decl
= create_subprog_decl
@@ -779,6 +783,7 @@ build_raise_check (int check, enum exception_info_kind kind)
= create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype,
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (result);
return result;
}
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index f85373e2f76ef..193772cc82970 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -39,6 +39,7 @@
#include "varasm.h"
#include "toplev.h"
#include "opts.h"
+#include "ipa-strub.h"
#include "output.h"
#include "debug.h"
#include "convert.h"
@@ -94,6 +95,7 @@ static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_stack_protector_attribute (tree *, tree, tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
@@ -157,6 +159,8 @@ const struct attribute_spec gnat_internal_attribute_table[] =
{ "no_stack_protector",0, 0, true, false, false, false,
handle_no_stack_protector_attribute,
attr_stack_protect_exclusions },
+ { "strub", 0, 1, false, true, false, true,
+ handle_strub_attribute, NULL },
{ "noinline", 0, 0, true, false, false, false,
handle_noinline_attribute, NULL },
{ "noclone", 0, 0, true, false, false, false,
@@ -6599,6 +6603,69 @@ handle_no_stack_protector_attribute (tree *node, tree name, tree, int,
return NULL_TREE;
}
+/* Handle a "strub" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ bool enable = true;
+
+ if (args
+ && POINTER_TYPE_P (*node)
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*node)))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
+ return NULL_TREE;
+}
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/ada/libgnat/a-except.adb b/gcc/ada/libgnat/a-except.adb
index c332afad0f8a1..593392809d92d 100644
--- a/gcc/ada/libgnat/a-except.adb
+++ b/gcc/ada/libgnat/a-except.adb
@@ -629,6 +629,96 @@ package body Ada.Exceptions is
pragma No_Return (Rcheck_CE_Invalid_Data_Ext);
pragma No_Return (Rcheck_CE_Range_Check_Ext);
+ -- Make all of these procedures callable from strub contexts.
+ -- These attributes are not visible to callers; they are made
+ -- visible in trans.c:build_raise_check.
+
+ pragma Machine_Attribute (Rcheck_CE_Access_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Null_Access_Parameter,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Discriminant_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Divide_By_Zero,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Explicit_Raise,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Index_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Invalid_Data,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Length_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Null_Exception_Id,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Null_Not_Allowed,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Overflow_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Partition_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Range_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Tag_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Access_Before_Elaboration,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Accessibility_Check,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Address_Of_Intrinsic,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Aliased_Parameters,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_All_Guards_Closed,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Bad_Predicated_Generic_Type,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Build_In_Place_Mismatch,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Current_Task_In_Entry_Body,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Duplicated_Entry_Address,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Explicit_Raise,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Implicit_Return,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Misaligned_Address_Value,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Missing_Return,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Non_Transportable_Actual,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Overlaid_Controlled_Object,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Potentially_Blocking_Operation,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Stream_Operation_Not_Allowed,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Stubbed_Subprogram_Called,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Unchecked_Union_Restriction,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_PE_Finalize_Raised_Exception,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_SE_Empty_Storage_Pool,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_SE_Explicit_Raise,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_SE_Infinite_Recursion,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_SE_Object_Too_Large,
+ "strub", "callable");
+
+ pragma Machine_Attribute (Rcheck_CE_Access_Check_Ext,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Index_Check_Ext,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Invalid_Data_Ext,
+ "strub", "callable");
+ pragma Machine_Attribute (Rcheck_CE_Range_Check_Ext,
+ "strub", "callable");
+
---------------------------------------------
-- Reason Strings for Run-Time Check Calls --
---------------------------------------------
diff --git a/gcc/ada/libgnat/a-except.ads b/gcc/ada/libgnat/a-except.ads
index 2b27adb6ca1b8..b5a2e48f96aae 100644
--- a/gcc/ada/libgnat/a-except.ads
+++ b/gcc/ada/libgnat/a-except.ads
@@ -81,6 +81,10 @@ package Ada.Exceptions is
pragma No_Return (Raise_Exception);
-- Note: In accordance with AI-466, CE is raised if E = Null_Id
+ -- Make it callable from strub contexts.
+ pragma Machine_Attribute (Raise_Exception,
+ "strub", "callable");
+
function Exception_Message (X : Exception_Occurrence) return String;
procedure Reraise_Occurrence (X : Exception_Occurrence);
@@ -184,6 +188,10 @@ private
-- Raise_Exception_Always if it can determine this is the case. The Export
-- allows this routine to be accessed from Pure units.
+ -- Make it callable from strub contexts.
+ pragma Machine_Attribute (Raise_Exception_Always,
+ "strub", "callable");
+
procedure Raise_From_Controlled_Operation (X : Exception_Occurrence);
pragma No_Return (Raise_From_Controlled_Operation);
pragma Export
diff --git a/gcc/ada/libgnat/s-arit128.ads b/gcc/ada/libgnat/s-arit128.ads
index 6213cfb569a24..5d3fff6d8e14f 100644
--- a/gcc/ada/libgnat/s-arit128.ads
+++ b/gcc/ada/libgnat/s-arit128.ads
@@ -57,6 +57,12 @@ package System.Arith_128 is
-- bits, otherwise returns the 128-bit signed integer product.
-- Gigi may also call this routine directly.
+ -- Make it callable from strub contexts.
+ -- There is a matching setting in trans.c,
+ -- for calls issued by Gigi.
+ pragma Machine_Attribute (Multiply_With_Ovflo_Check128,
+ "strub", "callable");
+
procedure Scaled_Divide128
(X, Y, Z : Int128;
Q, R : out Int128;
diff --git a/gcc/ada/libgnat/s-arit64.ads b/gcc/ada/libgnat/s-arit64.ads
index c9141f5fe3e89..170c2bdf1de93 100644
--- a/gcc/ada/libgnat/s-arit64.ads
+++ b/gcc/ada/libgnat/s-arit64.ads
@@ -57,6 +57,12 @@ package System.Arith_64 is
-- bits, otherwise returns the 64-bit signed integer product.
-- Gigi may also call this routine directly.
+ -- Make it callable from strub contexts.
+ -- There is a matching setting in trans.c,
+ -- for calls issued by Gigi.
+ pragma Machine_Attribute (Multiply_With_Ovflo_Check64,
+ "strub", "callable");
+
procedure Scaled_Divide64
(X, Y, Z : Int64;
Q, R : out Int64;
diff --git a/gcc/ada/libgnat/s-secsta.ads b/gcc/ada/libgnat/s-secsta.ads
index 7d6b1b9a90eb0..63df82c8392e4 100644
--- a/gcc/ada/libgnat/s-secsta.ads
+++ b/gcc/ada/libgnat/s-secsta.ads
@@ -85,6 +85,9 @@ package System.Secondary_Stack is
--
-- * Create a new chunk that fits the requested Storage_Size.
+ pragma Machine_Attribute (SS_Allocate, "strub", "callable");
+ -- Enable it to be called from within strub contexts.
+
procedure SS_Free (Stack : in out SS_Stack_Ptr);
-- Free all dynamic chunks of secondary stack Stack. If possible, free the
-- stack itself.
@@ -92,9 +95,16 @@ package System.Secondary_Stack is
function SS_Mark return Mark_Id;
-- Capture and return the state of the invoking task's secondary stack
+ pragma Machine_Attribute (SS_Mark, "strub", "callable");
+ -- Enable it to be called from within strub contexts.
+
procedure SS_Release (M : Mark_Id);
-- Restore the state of the invoking task's secondary stack to mark M
+ pragma Machine_Attribute (SS_Release, "strub", "callable");
+ -- Enable it to be called from within strub contexts.
+ -- FIXME: should there be a scrubbing SS_Release?
+
function SS_Get_Max return Long_Long_Integer;
-- Return the high water mark of the invoking task's secondary stack, in
-- bytes.
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 0d22c20a35e16..07f81285d7a2d 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "attribs.h"
#include "fold-const.h"
+#include "ipa-strub.h"
#include "stor-layout.h"
#include "langhooks.h"
#include "plugin.h"
@@ -617,12 +618,11 @@ decl_attributes (tree *node, tree attributes, int flags,
flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
- if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
+ if (spec->function_type_required
+ && !FUNC_OR_METHOD_TYPE_P (*anode))
{
if (TREE_CODE (*anode) == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
{
/* OK, this is a bit convoluted. We can't just make a copy
of the pointer type and modify its TREE_TYPE, because if
@@ -715,7 +715,23 @@ decl_attributes (tree *node, tree attributes, int flags,
tree ret = (spec->handler) (cur_and_last_decl, name, args,
flags|cxx11_flag, &no_add_attrs);
- *anode = cur_and_last_decl[0];
+ if (*anode != cur_and_last_decl[0])
+ {
+ /* Even if !spec->function_type_required, allow the attribute
+ handler to request the attribute to be applied to the function
+ type, rather than to the function pointer type, by setting
+ cur_and_last_decl[0] to the function type. */
+ if (!fn_ptr_tmp
+ && POINTER_TYPE_P (*anode)
+ && TREE_TYPE (*anode) == cur_and_last_decl[0]
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+ {
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ }
+ *anode = cur_and_last_decl[0];
+ }
if (ret == error_mark_node)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1353,9 +1369,20 @@ comp_type_attributes (const_tree type1, const_tree type2)
if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
return 0;
+ int strub_ret = strub_comptypes (CONST_CAST_TREE (type1),
+ CONST_CAST_TREE (type2));
+ if (strub_ret == 0)
+ return strub_ret;
/* As some type combinations - like default calling-convention - might
be compatible, we have to call the target hook to get the final result. */
- return targetm.comp_type_attributes (type1, type2);
+ int target_ret = targetm.comp_type_attributes (type1, type2);
+ if (target_ret == 0)
+ return target_ret;
+ if (strub_ret == 2 || target_ret == 2)
+ return 2;
+ if (strub_ret == 1 && target_ret == 1)
+ return 1;
+ gcc_unreachable ();
}
/* PREDICATE acts as a function of type:
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9954862776125..7ad91ea6f7a3e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "intl.h"
#include "file-prefix-map.h" /* remap_macro_filename() */
+#include "ipa-strub.h" /* strub_watermark_parm() */
#include "gomp-constants.h"
#include "omp-general.h"
#include "tree-dfa.h"
@@ -150,6 +151,7 @@ static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
static rtx expand_builtin_alloca (tree);
static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
+static rtx expand_builtin_stack_address ();
static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx);
static rtx expand_builtin_expect_with_probability (tree, rtx);
@@ -4871,6 +4873,256 @@ expand_builtin_frame_address (tree fndecl, tree exp)
}
}
+#ifndef STACK_GROWS_DOWNWARD
+# define STACK_TOPS GT
+#else
+# define STACK_TOPS LT
+#endif
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+# define STACK_UNSIGNED POINTERS_EXTEND_UNSIGNED
+#else
+# define STACK_UNSIGNED true
+#endif
+
+/* Expand a call to builtin function __builtin_stack_address. */
+
+static rtx
+expand_builtin_stack_address ()
+{
+ return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
+ STACK_UNSIGNED);
+}
+
+/* Expand a call to builtin function __builtin_strub_enter. */
+
+static rtx
+expand_builtin_strub_enter (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 1 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = NULL_RTX;
+
+#if 1 || defined RED_ZONE_SIZE
+ if (tree wmptr = (optimize
+ ? strub_watermark_parm (current_function_decl)
+ : NULL_TREE))
+ {
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ stktop = force_reg (ptr_mode, wmark);
+ }
+#endif
+
+ if (!stktop)
+ stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ emit_move_insn (wmark, stktop);
+
+ return const0_rtx;
+}
+
+/* Expand a call to builtin function __builtin_strub_update. */
+
+static rtx
+expand_builtin_strub_update (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+#ifdef RED_ZONE_SIZE
+ /* Here's how the strub enter, update and leave functions deal with red zones.
+
+ If it weren't for red zones, update, called from within a strub context,
+ would bump the watermark to the top of the stack. Enter and leave, running
+ in the caller, would use the caller's top of stack address both to
+ initialize the watermark passed to the callee, and to start strubbing the
+ stack afterwards.
+
+ Ideally, we'd update the watermark so as to cover the used amount of red
+ zone, and strub starting at the caller's other end of the (presumably
+ unused) red zone. Normally, only leaf functions use the red zone, but at
+ this point we can't tell whether a function is a leaf, nor can we tell how
+ much of the red zone it uses. Furthermore, some strub contexts may have
+ been inlined so that update and leave are called from the same stack frame,
+ and the strub builtins may all have been inlined, turning a strub function
+ into a leaf.
+
+ So cleaning the range from the caller's stack pointer (one end of the red
+ zone) to the (potentially inlined) callee's (other end of the) red zone
+ could scribble over the caller's own red zone.
+
+ We avoid this possibility by arranging for callers that are strub contexts
+ to use their own watermark as the strub starting point. So, if A calls B,
+ and B calls C, B will tell A to strub up to the end of B's red zone, and
+ will strub itself only the part of C's stack frame and red zone that
+ doesn't overlap with B's. With that, we don't need to know who's leaf and
+ who isn't: inlined calls will shrink their strub window to zero, each
+ remaining call will strub some portion of the stack, and eventually the
+ strub context will return to a caller that isn't a strub context itself,
+ that will therefore use its own stack pointer as the strub starting point.
+ It's not a leaf, because strub contexts can't be inlined into non-strub
+ contexts, so it doesn't use the red zone, and it will therefore correctly
+ strub up the callee's stack frame up to the end of the callee's red zone.
+ Neat! */
+ if (true /* (flags_from_decl_or_type (current_function_decl) & ECF_LEAF) */)
+ {
+ poly_int64 red_zone_size = RED_ZONE_SIZE;
+#if STACK_GROWS_DOWNWARD
+ red_zone_size = -red_zone_size;
+#endif
+ stktop = plus_constant (ptr_mode, stktop, red_zone_size);
+ stktop = force_reg (ptr_mode, stktop);
+ }
+#endif
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+ rtx_code_label *lab = gen_label_rtx ();
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+
+#if 1 || defined RED_ZONE_SIZE
+ /* If this is an inlined strub function, also bump the watermark for the
+ enclosing function. This avoids a problem with the following scenario: A
+ calls B and B calls C, and both B and C get inlined into A. B allocates
+ temporary stack space before calling C. If we don't update A's watermark,
+ we may use an outdated baseline for the post-C strub_leave, erasing B's
+ temporary stack allocation. We only need this if we're fully expanding
+ strub_leave inline. */
+ tree xwmptr = (optimize > 2
+ ? strub_watermark_parm (current_function_decl)
+ : wmptr);
+ if (wmptr != xwmptr)
+ {
+ wmptr = xwmptr;
+ wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ wmarkr = force_reg (ptr_mode, wmark);
+
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+ }
+#endif
+
+ emit_label (lab);
+
+ return const0_rtx;
+}
+
+
+/* Expand a call to builtin function __builtin_strub_leave. */
+
+static rtx
+expand_builtin_strub_leave (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || optimize_size || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = NULL_RTX;
+
+#if 1 || defined RED_ZONE_SIZE
+ if (tree wmptr = (optimize
+ ? strub_watermark_parm (current_function_decl)
+ : NULL_TREE))
+ {
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ stktop = force_reg (ptr_mode, wmark);
+ }
+#endif
+
+ if (!stktop)
+ stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+#ifndef STACK_GROWS_DOWNWARD
+ rtx base = stktop;
+ rtx end = wmarkr;
+#else
+ rtx base = wmarkr;
+ rtx end = stktop;
+#endif
+
+ /* We're going to modify it, so make sure it's not e.g. the stack pointer. */
+ base = copy_to_reg (base);
+
+ rtx_code_label *done = gen_label_rtx ();
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, done, NULL,
+ profile_probability::very_likely ());
+
+ if (optimize < 3)
+ expand_call (exp, NULL_RTX, true);
+ else
+ {
+ /* Ok, now we've determined we want to copy the block, so convert the
+ addresses to Pmode, as needed to dereference them to access ptr_mode
+ memory locations, so that we don't have to convert anything within the
+ loop. */
+ base = memory_address (ptr_mode, base);
+ end = memory_address (ptr_mode, end);
+
+ rtx zero = force_operand (const0_rtx, NULL_RTX);
+ int ulen = GET_MODE_SIZE (ptr_mode);
+ rtx incr = plus_constant (Pmode, base, ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, base);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (dstm, zero);
+ emit_move_insn (base, force_operand (incr, NULL_RTX));
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ Pmode, NULL_RTX, NULL, loop,
+ profile_probability::very_likely ());
+ }
+
+ emit_label (done);
+
+ return const0_rtx;
+}
+
/* Expand EXP, a call to the alloca builtin. Return NULL_RTX if we
failed and the caller should emit a normal call. */
@@ -7110,6 +7362,27 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
case BUILT_IN_RETURN_ADDRESS:
return expand_builtin_frame_address (fndecl, exp);
+ case BUILT_IN_STACK_ADDRESS:
+ return expand_builtin_stack_address ();
+
+ case BUILT_IN___STRUB_ENTER:
+ target = expand_builtin_strub_enter (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_UPDATE:
+ target = expand_builtin_strub_update (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_LEAVE:
+ target = expand_builtin_strub_leave (exp);
+ if (target)
+ return target;
+ break;
+
/* Returns the address of the area where the structure is returned.
0 otherwise. */
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 45a09b4d42def..f83c1f5fcd7ed 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -874,6 +874,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHRO
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
+DEF_GCC_BUILTIN (BUILT_IN_STACK_ADDRESS, "stack_address", BT_FN_PTR, ATTR_NULL)
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_ENTER, "__builtin___strub_enter")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_UPDATE, "__builtin___strub_update")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_LEAVE, "__builtin___strub_leave")
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
DEF_LIB_BUILTIN (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index d14e9c441b39b..0453ac563cc40 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "common/common-target.h"
#include "langhooks.h"
#include "tree-inline.h"
+#include "ipa-strub.h"
#include "toplev.h"
#include "tree-iterator.h"
#include "opts.h"
@@ -69,6 +70,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_stack_protector_function_attribute (tree *, tree,
tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -308,6 +310,8 @@ const struct attribute_spec c_common_attribute_table[] =
{ "no_stack_protector", 0, 0, true, false, false, false,
handle_no_stack_protector_function_attribute,
attr_stack_protect_exclusions },
+ { "strub", 0, 1, false, true, false, true,
+ handle_strub_attribute, NULL },
{ "noinline", 0, 0, true, false, false, false,
handle_noinline_attribute,
attr_noinline_exclusions },
@@ -1294,6 +1298,70 @@ handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
return NULL_TREE;
}
+/* Handle a "strub" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ bool enable = true;
+
+ if (args
+ && POINTER_TYPE_P (*node)
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*node)))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
+ return NULL_TREE;
+}
+
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/common.opt b/gcc/common.opt
index 7d69ab5ef7c3d..ef018ebf73512 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2687,6 +2687,35 @@ fstrict-overflow
Common
Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer.
+fstrub=disable
+Common RejectNegative Var(flag_strub, 0)
+Disable stack scrub entirely, disregarding strub attributes.
+
+fstrub=strict
+Common RejectNegative Var(flag_strub, -4)
+Enable stack scrub as per attributes, with strict call checking.
+
+; If any strub-enabling attribute is seen when the default or strict
+; initializer values are in effect, flag_strub is bumped up by 2. The
+; scrub mode gate function will then bump these initializer values to
+; 0 if no strub-enabling attribute is seen. This minimizes the strub
+; overhead.
+fstrub=relaxed
+Common RejectNegative Var(flag_strub, -3) Init(-3)
+Restore default strub mode: as per attributes, with relaxed checking.
+
+fstrub=all
+Common RejectNegative Var(flag_strub, 3)
+Enable stack scrubbing for all viable functions.
+
+fstrub=at-calls
+Common RejectNegative Var(flag_strub, 1)
+Enable at-calls stack scrubbing for all viable functions.
+
+fstrub=internal
+Common RejectNegative Var(flag_strub, 2)
+Enable internal stack scrubbing for all viable functions.
+
fsync-libcalls
Common Var(flag_sync_libcalls) Init(1)
Implement __atomic operations via libcalls to legacy __sync functions.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7fb22ed806323..d85e695d85cc0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -77,6 +77,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Function Names:: Printable strings which are the name of the current
function.
* Return Address:: Getting the return or frame address of a function.
+* Stack Scrubbing:: Stack scrubbing internal interfaces.
* Vector Extensions:: Using vector instructions through built-in functions.
* Offsetof:: Special syntax for implementing @code{offsetof}.
* __sync Builtins:: Legacy built-in functions for atomic memory access.
@@ -8725,6 +8726,263 @@ pid_t wait (wait_status_ptr_t p)
@}
@end smallexample
+@item strub
+@cindex @code{strub} type attribute
+This attribute defines stack-scrubbing properties of functions and
+variables. Being a type attribute, it attaches to types, even when
+specified in function and variable declarations. When applied to
+function types, it takes an optional string argument. When applied to a
+pointer-to-function type, if the optional argument is given, it gets
+propagated to the function type.
+
+@smallexample
+/* A strub variable. */
+int __attribute__ ((strub)) var;
+/* A strub variable that happens to be a pointer. */
+__attribute__ ((strub)) int *strub_ptr_to_int;
+/* A pointer type that may point to a strub variable. */
+typedef int __attribute__ ((strub)) *ptr_to_strub_int_type;
+
+/* A declaration of a strub function. */
+extern int __attribute__ ((strub)) foo (void);
+/* A pointer to that strub function. */
+int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo;
+@end smallexample
+
+A function associated with @code{at-calls} @code{strub} mode
+(@code{strub("at-calls")}, or just @code{strub}) undergoes interface
+changes. Its callers are adjusted to match the changes, and to scrub
+(overwrite with zeros) the stack space used by the called function after
+it returns. The interface change makes the function type incompatible
+with an unadorned but otherwise equivalent type, so @emph{every}
+declaration and every type that may be used to call the function must be
+associated with this strub mode.
+
+A function associated with @code{internal} @code{strub} mode
+(@code{strub("internal")}) retains an unmodified, type-compatible
+interface, but it may be turned into a wrapper that calls the wrapped
+body using a custom interface. The wrapper then scrubs the stack space
+used by the wrapped body. Though the wrapped body has its stack space
+scrubbed, the wrapper does not, so arguments and return values may
+remain unscrubbed even when such a function is called by another
+function that enables @code{strub}. This is why, when compiling with
+@option{-fstrub=strict}, a @code{strub} context is not allowed to call
+@code{internal} @code{strub} functions.
+
+@smallexample
+/* A declaration of an internal-strub function. */
+extern int __attribute__ ((strub ("internal"))) bar (void);
+
+int __attribute__ ((strub))
+baz (void)
+@{
+ /* Ok, foo was declared above as an at-calls strub function. */
+ foo ();
+ /* Not allowed in strict mode, otherwise allowed. */
+ bar ();
+@}
+@end smallexample
+
+An automatically-allocated variable associated with the @code{strub}
+attribute causes the (immediately) enclosing function to have
+@code{strub} enabled.
+
+A statically-allocated variable associated with the @code{strub}
+attribute causes functions that @emph{read} it, through its @code{strub}
+data type, to have @code{strub} enabled. Reading data by dereferencing
+a pointer to a @code{strub} data type has the same effect. Note: The
+attribute does not carry over from a composite type to the types of its
+components, so the intended effect may not be obtained with non-scalar
+types.
+
+When selecting a @code{strub}-enabled mode for a function that is not
+explicitly associated with one, because of @code{strub} variables or
+data pointers, the function must satisfy @code{internal} mode viability
+requirements (see below), even when @code{at-calls} mode is also viable
+and, being more efficient, ends up selected as an optimization.
+
+@smallexample
+/* zapme is implicitly strub-enabled because of strub variables.
+ Optimization may change its strub mode, but not the requirements. */
+static int
+zapme (int i)
+@{
+ /* A local strub variable enables strub. */
+ int __attribute__ ((strub)) lvar;
+ /* Reading strub data through a pointer-to-strub enables strub. */
+ lvar = * (ptr_to_strub_int_type) &i;
+ /* Writing to a global strub variable does not enable strub. */
+ var = lvar;
+ /* Reading from a global strub variable enables strub. */
+ return var;
+@}
+@end smallexample
+
+A @code{strub} context is the body (as opposed to the interface) of a
+function that has @code{strub} enabled, be it explicitly, by
+@code{at-calls} or @code{internal} mode, or implicitly, due to
+@code{strub} variables or command-line options.
+
+A function of a type associated with the @code{disabled} @code{strub}
+mode (@code{strub("disabled")} will not have its own stack space
+scrubbed. Such functions @emph{cannot} be called from within
+@code{strub} contexts.
+
+In order to enable a function to be called from within @code{strub}
+contexts without having its stack space scrubbed, associate it with the
+@code{callable} @code{strub} mode (@code{strub("callable")}).
+
+When a function is not assigned a @code{strub} mode, explicitly or
+implicitly, the mode defaults to @code{callable}, except when compiling
+with @option{-fstrub=strict}, that causes @code{strub} mode to default
+to @code{disabled}.
+
+@example
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+ /* Implicitly disabled with -fstrub=strict, otherwise callable. */
+extern int bah (void);
+
+int __attribute__ ((strub))
+bal (void)
+@{
+ /* Not allowed, bad is not strub-callable. */
+ bad ();
+ /* Ok, bac is strub-callable. */
+ bac ();
+ /* Not allowed with -fstrub=strict, otherwise allowed. */
+ bah ();
+@}
+@end example
+
+Function types marked @code{callable} and @code{disabled} are not
+mutually compatible types, but the underlying interfaces are compatible,
+so it is safe to convert pointers between them, and to use such pointers
+or alternate declarations to call them. Interfaces are also
+interchangeable between them and @code{internal} (but not
+@code{at-calls}!), but adding @code{internal} to a pointer type will not
+cause the pointed-to function to perform stack scrubbing.
+
+@example
+void __attribute__ ((strub))
+bap (void)
+@{
+ /* Assign a callable function to pointer-to-disabled.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac;
+ /* Not allowed: calls disabled type in a strub context. */
+ d_p ();
+
+ /* Assign a disabled function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an internal function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ c_p = bar;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an at-calls function to pointer-to-callable.
+ Flaggged as incompatible. */
+ c_p = bal;
+ /* The call through an interface-incompatible type will not use the
+ modified interface expected by the at-calls function, so it is
+ likely to misbehave at runtime. */
+ c_p ();
+@}
+@end example
+
+@code{Strub} contexts are never inlined into non-@code{strub} contexts.
+When an @code{internal}-strub function is split up, the wrapper can
+often be inlined, but the wrapped body @emph{never} is. A function
+marked as @code{always_inline}, even if explicitly assigned
+@code{internal} strub mode, will not undergo wrapping, so its body gets
+inlined as required.
+
+@example
+inline int __attribute__ ((strub ("at-calls")))
+inl_atc (void)
+@{
+ /* This body may get inlined into strub contexts. */
+@}
+
+inline int __attribute__ ((strub ("internal")))
+inl_int (void)
+@{
+ /* This body NEVER gets inlined, though its wrapper may. */
+@}
+
+inline int __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+@{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+@}
+
+void __attribute__ ((strub ("disabled")))
+bat (void)
+@{
+ /* Not allowed, cannot inline into a non-strub context. */
+ inl_int_ali ();
+@}
+@end example
+
+@cindex strub eligibility and viability
+Some @option{-fstrub=*} command line options enable @code{strub} modes
+implicitly where viable. A @code{strub} mode is only viable for a
+function if the function is eligible for that mode, and if other
+conditions, detailed below, are satisfied. If it's not eligible for a
+mode, attempts to explicitly associate it with that mode are rejected
+with an error message. If it is eligible, that mode may be assigned
+explicitly through this attribute, but implicit assignment through
+command-line options may involve additional viability requirements.
+
+A function is ineligible for @code{at-calls} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, if attribute
+@code{noipa} is present, or if it calls @code{__builtin_apply_args}.
+@code{At-calls} @code{strub} mode, if not requested through the function
+type, is only viable for an eligible function if the function is not
+visible to other translation units, and if it doesn't have its address
+taken.
+
+@smallexample
+/* bar is eligible for at-calls strub mode,
+ but not viable for that mode because it is visible to other units.
+ It is eligible and viable for internal strub mode. */
+void bav () @{@}
+
+/* setp is eligible for at-calls strub mode,
+ but not viable for that mode because its address is taken.
+ It is eligible and viable for internal strub mode. */
+void setp (void) @{ static void (*p)(void); = setp; @}
+@end smallexample
+
+A function is ineligible for @code{internal} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, or if attribute
+@code{noipa} is present. For an @code{always_inline} function, meeting
+these requirements is enough to make it eligible. Any function that has
+attribute @code{noclone}, that uses such extensions as non-local labels,
+computed gotos, alternate variable argument passing interfaces,
+@code{__builtin_next_arg}, or @code{__builtin_return_address}, or that
+takes too many (about 64Ki) arguments is ineligible, unless it is
+@code{always_inline}. For @code{internal} @code{strub} mode, all
+eligible functions are viable.
+
+@smallexample
+/* flop is not eligible, thus not viable, for at-calls strub mode.
+ Likewise for internal strub mode. */
+__attribute__ ((noipa)) void flop (void) @{@}
+
+/* flip is eligible and viable for at-calls strub mode.
+ It would be ineligible for internal strub mode, because of noclone,
+ if it weren't for always_inline. With always_inline, noclone is not
+ an obstacle, so it is also eligible and viable for internal strub mode. */
+inline __attribute__ ((noclone, always_inline)) void flip (void) @{@}
+@end smallexample
+
@item unused
@cindex @code{unused} type attribute
When attached to a type (including a @code{union} or a @code{struct}),
@@ -11749,6 +12007,55 @@ option is in effect. Such calls should only be made in debugging
situations.
@end deftypefn
+@deftypefn {Built-in Function} {void *} __builtin_stack_address ()
+This function returns the value of the stack pointer register.
+@end deftypefn
+
+@node Stack Scrubbing
+@section Stack scrubbing internal interfaces
+
+Stack scrubbing involves cooperation between a @code{strub} context,
+i.e., a function whose stack frame is to be zeroed-out, and its callers.
+The caller initializes a stack watermark, the @code{strub} context
+updates the watermark according to its stack use, and the caller zeroes
+it out once it regains control, whether by the callee's returning or by
+an exception.
+
+Each of these steps is performed by a different builtin function call.
+Calls to these builtins are introduced automatically, in response to
+@code{strub} attributes and command-line options; they are not expected
+to be explicitly called by source code.
+
+The functions that implement the builtins are available in libgcc but,
+depending on optimization levels, they are expanded internally, adjusted
+to account for inlining, and sometimes combined/deferred (e.g. passing
+the caller-supplied watermark on to callees, refraining from erasing
+stack areas that the caller will) to enable tail calls and to optimize
+for code size.
+
+@deftypefn {Built-in Function} {void} __builtin___strub_enter (void **@var{wmptr})
+This function initializes a stack @var{watermark} variable with the
+current top of the stack. A call to this builtin function is introduced
+before entering a @code{strub} context. It remains as a function call
+if optimization is not enabled.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_update (void **@var{wmptr})
+This function updates a stack @var{watermark} variable with the current
+top of the stack, if it tops the previous watermark. A call to this
+builtin function is inserted within @code{strub} contexts, whenever
+additional stack space may have been used. It remains as a function
+call at optimization levels lower than 2.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_leave (void **@var{wmptr})
+This function overwrites the memory area between the current top of the
+stack, and the @var{watermark}ed address. A call to this builtin
+function is inserted after leaving a @code{strub} context. It remains
+as a function call at optimization levels lower than 3, and it is guarded by
+a condition at level 2.
+@end deftypefn
+
@node Vector Extensions
@section Using Vector Instructions through Built-in Functions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8969bac664d31..afcb37914acb1 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -599,6 +599,8 @@ Objective-C and Objective-C++ Dialects}.
-fstack-protector-explicit -fstack-check @gol
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol
-fno-stack-limit -fsplit-stack @gol
+-fstrub=disable -fstrub=strict -fstrub=relaxed @gol
+-fstrub=all -fstrub=at-calls -fstrub=internal @gol
-fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} @gol
-fvtv-counts -fvtv-debug @gol
-finstrument-functions @gol
@@ -15512,6 +15514,56 @@ without @option{-fsplit-stack} always has a large stack. Support for
this is implemented in the gold linker in GNU binutils release 2.21
and later.
+@item -fstrub=disable
+@opindex -fstrub=disable
+Disable stack scrubbing entirely, ignoring any @code{strub} attributes.
+See @xref{Common Type Attributes}.
+
+@item -fstrub=strict
+@opindex fstrub=strict
+Functions default to @code{strub} mode @code{disabled}, and apply
+@option{strict}ly the restriction that only functions associated with
+@code{strub}-@code{callable} modes (@code{at-calls}, @code{callable} and
+@code{always_inline} @code{internal}) are @code{callable} by functions
+with @code{strub}-enabled modes (@code{at-calls} and @code{internal}).
+
+@item -fstrub=relaxed
+@opindex fstrub=relaxed
+Restore the default stack scrub (@code{strub}) setting, namely,
+@code{strub} is only enabled as required by @code{strub} attributes
+associated with function and data types. @code{Relaxed} means that
+strub contexts are only prevented from calling functions explicitly
+associated with @code{strub} mode @code{disabled}. This option is only
+useful to override other @option{-fstrub=*} options that precede it in
+the command line.
+
+@item -fstrub=at-calls
+@opindex fstrub=at-calls
+Enable @code{at-calls} @code{strub} mode where viable. The primary use
+of this option is for testing. It exercises the @code{strub} machinery
+in scenarios strictly local to a translation unit. This @code{strub}
+mode modifies function interfaces, so any function that is visible to
+other translation units, or that has its address taken, will @emph{not}
+be affected by this option. Optimization options may also affect
+viability. See the @code{strub} attribute documentation for details on
+viability and eligibility requirements.
+
+@item -fstrub=internal
+@opindex fstrub=internal
+Enable @code{internal} @code{strub} mode where viable. The primary use
+of this option is for testing. This option is intended to exercise
+thoroughly parts of the @code{strub} machinery that implement the less
+efficient, but interface-preserving @code{strub} mode. Functions that
+would not be affected by this option are quite uncommon.
+
+@item -fstrub=all
+@opindex fstrub=all
+Enable some @code{strub} mode where viable. When both strub modes are
+viable, @code{at-calls} is preferred. @option{-fdump-ipa-strubm} adds
+function attributes that tell which mode was selected for each function.
+The primary use of this option is for testing, to exercise thoroughly
+the @code{strub} machinery.
+
@item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
@opindex fvtable-verify
This option is only available when compiling C++ code.
@@ -17385,6 +17437,14 @@ and inlining decisions.
@item inline
Dump after function inlining.
+@item strubm
+Dump after selecting @code{strub} modes, and recording the selections as
+function attributes.
+
+@item strub
+Dump @code{strub} transformations: interface changes, function wrapping,
+and insertion of builtin calls for stack scrubbing and watermarking.
+
@end table
Additionally, the options @option{-optimized}, @option{-missed},
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 413446bcc46cd..932e49dba8ef6 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "ipa-strub.h"
typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
typedef fibonacci_node <sreal, cgraph_edge> edge_heap_node_t;
@@ -396,6 +397,11 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
e->inline_failed = CIF_SANITIZE_ATTRIBUTE_MISMATCH;
inlinable = false;
}
+ if (!strub_inlinable_to_p (callee, caller))
+ {
+ e->inline_failed = CIF_UNSPECIFIED;
+ inlinable = false;
+ }
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index c68577d04a994..8c880747eb7a3 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-fnsummary.h"
#include "cfgloop.h"
#include "attribs.h"
+#include "ipa-strub.h"
/* Per basic block info. */
@@ -1792,6 +1793,12 @@ execute_split_functions (void)
"section.\n");
return 0;
}
+ if (!strub_splittable_p (node))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not splitting: function is a strub context.\n");
+ return 0;
+ }
/* We enforce splitting after loop headers when profile info is not
available. */
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
new file mode 100644
index 0000000000000..663fe7b2920d2
--- /dev/null
+++ b/gcc/ipa-strub.c
@@ -0,0 +1,3336 @@
+/* strub (stack scrubbing) support.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "tree-cfg.h"
+#include "cfghooks.h"
+#include "cfgloop.h"
+#include "cfgcleanup.h"
+#include "tree-eh.h"
+#include "except.h"
+#include "builtins.h"
+#include "attribs.h"
+#include "tree-inline.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "ipa-fnsummary.h"
+#include "gimple-fold.h"
+#include "fold-const.h"
+#include "gimple-walk.h"
+#include "tree-dfa.h"
+#include "langhooks.h"
+#include "calls.h"
+#include "vec.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "alias.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "ipa-strub.h"
+
+#if BUILDING_GCC_MAJOR >= 11
+# include "symtab-thunks.h"
+# include "attr-fnspec.h"
+# define HAVE_ATTR_FNSPEC 1
+# define FOR_GCC_11P 1
+#else
+# define HAVE_ATTR_FNSPEC 0
+# define FOR_GCC_11P 0
+#endif
+
+/* Const and pure functions that gain a watermark parameter for strub purposes
+ are still regarded as such, which may cause the inline expansions of the
+ __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
+ us to inform the backend about requirements and side effects of the call, but
+ call_fusage building in calls.c:expand_call does not even look at
+ attr_fnspec, so we resort to asm loads and updates to attain an equivalent
+ effect. Once expand_call gains the ability to issue extra memory uses and
+ clobbers based on pure/const function's fnspec, we can define this to 1. */
+#define ATTR_FNSPEC_DECONST_WATERMARK 0
+
+enum strub_mode {
+ /* This mode denotes a regular function, that does not require stack
+ scrubbing (strubbing). It may call any other functions, but if
+ it calls AT_CALLS (or WRAPPED) ones, strubbing logic is
+ automatically introduced around those calls (the latter, by
+ inlining INTERNAL wrappers). */
+ STRUB_DISABLED = 0,
+
+ /* This denotes a function whose signature is (to be) modified to
+ take an extra parameter, for stack use annotation, and its
+ callers must initialize and pass that argument, and perform the
+ strubbing. Functions that are explicitly marked with attribute
+ strub must have the mark visible wherever the function is,
+ including aliases, and overriders and overriding methods.
+ Functions that are implicitly marked for strubbing, for accessing
+ variables explicitly marked as such, will only select this
+ strubbing method if they are internal to a translation unit. It
+ can only be inlined into other strubbing functions, i.e.,
+ STRUB_AT_CALLS or STRUB_WRAPPED. */
+ STRUB_AT_CALLS = 1,
+
+ /* This denotes a function that is to perform strubbing internally,
+ without any changes to its interface (the function is turned into
+ a strubbing wrapper, and its original body is moved to a separate
+ STRUB_WRAPPED function, with a modified interface). Functions
+ may be explicitly marked with attribute strub(2), and the
+ attribute must be visible at the point of definition. Functions
+ that are explicitly marked for strubbing, for accessing variables
+ explicitly marked as such, may select this strubbing mode if
+ their interface cannot change, e.g. because its interface is
+ visible to other translation units, directly, by indirection
+ (having its address taken), inheritance, etc. Functions that use
+ this method must not have the noclone attribute, nor the noipa
+ one. Functions marked as always_inline may select this mode, but
+ they are NOT wrapped, they remain unchanged, and are only inlined
+ into strubbed contexts. Once non-always_inline functions are
+ wrapped, the wrapper becomes STRUB_WRAPPER, and the wrapped becomes
+ STRUB_WRAPPED. */
+ STRUB_INTERNAL = 2,
+
+ /* This denotes a function whose stack is not strubbed, but that is
+ nevertheless explicitly or implicitly marked as callable from strubbing
+ functions. Normally, only STRUB_AT_CALLS (and STRUB_INTERNAL ->
+ STRUB_WRAPPED) functions can be called from strubbing contexts (bodies of
+ STRUB_AT_CALLS, STRUB_INTERNAL and STRUB_WRAPPED functions), but attribute
+ strub(3) enables other functions to be (indirectly) called from these
+ contexts. Some builtins and internal functions may be implicitly marked as
+ STRUB_CALLABLE. */
+ STRUB_CALLABLE = 3,
+
+ /* This denotes the function that took over the body of a
+ STRUB_INTERNAL function. At first, it's only called by its
+ wrapper, but the wrapper may be inlined. The wrapped function,
+ in turn, can only be inlined into other functions whose stack
+ frames are strubbed, i.e., that are STRUB_WRAPPED or
+ STRUB_AT_CALLS. */
+ STRUB_WRAPPED = -1,
+
+ /* This denotes the wrapper function that replaced the STRUB_INTERNAL
+ function. This mode overrides the STRUB_INTERNAL mode at the time the
+ internal to-be-wrapped function becomes a wrapper, so that inlining logic
+ can tell one from the other. */
+ STRUB_WRAPPER = -2,
+
+ /* This denotes an always_inline function that requires strubbing. It can
+ only be called from, and inlined into, other strubbing contexts. */
+ STRUB_INLINABLE = -3,
+
+ /* This denotes a function that accesses strub variables, so it would call for
+ internal strubbing (whether or not it's eligible for that), but since
+ at-calls strubbing is viable, that's selected as an optimization. This
+ mode addresses the inconvenience that such functions may have different
+ modes selected depending on optimization flags, and get a different
+ callable status depending on that choice: if we assigned them
+ STRUB_AT_CALLS mode, they would be callable when optimizing, whereas
+ STRUB_INTERNAL would not be callable. */
+ STRUB_AT_CALLS_OPT = -4,
+
+};
+
+/* Look up a strub attribute in TYPE, and return it. */
+
+static tree
+get_strub_attr_from_type (tree type)
+{
+ return lookup_attribute ("strub", TYPE_ATTRIBUTES (type));
+}
+
+/* Look up a strub attribute in DECL or in its type, and return it. */
+
+static tree
+get_strub_attr_from_decl (tree decl)
+{
+ tree ret = lookup_attribute ("strub", DECL_ATTRIBUTES (decl));
+ if (ret)
+ return ret;
+ return get_strub_attr_from_type (TREE_TYPE (decl));
+}
+
+/* Define a function to cache identifier ID, to be used as a strub attribute
+ parameter for a strub mode named after NAME. */
+#define DEF_STRUB_IDS(NAME, ID) \
+static inline tree get_strub_mode_id_ ## NAME () { \
+ static tree identifier = NULL_TREE; \
+ if (!identifier) \
+ identifier = get_identifier (ID); \
+ return identifier; \
+}
+/* Same as DEF_STRUB_IDS, but use the string expansion of NAME as ID. */
+#define DEF_STRUB_ID(NAME) \
+DEF_STRUB_IDS (NAME, #NAME)
+
+/* Define functions for each of the strub mode identifiers.
+ Expose dashes rather than underscores. */
+DEF_STRUB_ID (disabled)
+DEF_STRUB_IDS (at_calls, "at-calls")
+DEF_STRUB_ID (internal)
+DEF_STRUB_ID (callable)
+DEF_STRUB_ID (wrapped)
+DEF_STRUB_ID (wrapper)
+DEF_STRUB_ID (inlinable)
+DEF_STRUB_IDS (at_calls_opt, "at-calls-opt")
+
+/* Release the temporary macro names. */
+#undef DEF_STRUB_IDS
+#undef DEF_STRUB_ID
+
+/* Return the identifier corresponding to strub MODE. */
+
+static tree
+get_strub_mode_attr_parm (enum strub_mode mode)
+{
+ switch (mode)
+ {
+ case STRUB_DISABLED:
+ return get_strub_mode_id_disabled ();
+
+ case STRUB_AT_CALLS:
+ return get_strub_mode_id_at_calls ();
+
+ case STRUB_INTERNAL:
+ return get_strub_mode_id_internal ();
+
+ case STRUB_CALLABLE:
+ return get_strub_mode_id_callable ();
+
+ case STRUB_WRAPPED:
+ return get_strub_mode_id_wrapped ();
+
+ case STRUB_WRAPPER:
+ return get_strub_mode_id_wrapper ();
+
+ case STRUB_INLINABLE:
+ return get_strub_mode_id_inlinable ();
+
+ case STRUB_AT_CALLS_OPT:
+ return get_strub_mode_id_at_calls_opt ();
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the parmeters (TREE_VALUE) for a strub attribute of MODE.
+ We know we use a single parameter, so we bypass the creation of a
+ tree list. */
+
+static tree
+get_strub_mode_attr_value (enum strub_mode mode)
+{
+ return get_strub_mode_attr_parm (mode);
+}
+
+/* Determine whether ID is a well-formed strub mode-specifying attribute
+ parameter for a function (type). Only user-visible modes are accepted, and
+ ID must be non-NULL.
+
+ For unacceptable parms, return 0, otherwise a nonzero value as below.
+
+ If the parm enables strub, return positive, otherwise negative.
+
+ If the affected type must be a distinct, incompatible type,return an integer
+ of absolute value 2, otherwise 1. */
+
+int
+strub_validate_fn_attr_parm (tree id)
+{
+ int ret;
+ const char *s = NULL;
+ size_t len = 0;
+
+ /* do NOT test for NULL. This is only to be called with non-NULL arguments.
+ We assume that the strub parameter applies to a function, because only
+ functions accept an explicit argument. If we accepted NULL, and we
+ happened to be called to verify the argument for a variable, our return
+ values would be wrong. */
+ if (TREE_CODE (id) == STRING_CST)
+ {
+ s = TREE_STRING_POINTER (id);
+ len = TREE_STRING_LENGTH (id) - 1;
+ }
+ else if (TREE_CODE (id) == IDENTIFIER_NODE)
+ {
+ s = IDENTIFIER_POINTER (id);
+ len = IDENTIFIER_LENGTH (id);
+ }
+ else
+ return 0;
+
+ enum strub_mode mode;
+
+ if (len != 8)
+ return 0;
+
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ ret = -1;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ ret = 2;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ ret = 1;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ ret = -2;
+ break;
+
+ default:
+ /* Other parms are for internal use only. */
+ return 0;
+ }
+
+ tree mode_id = get_strub_mode_attr_parm (mode);
+
+ if (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id != mode_id
+ : strncmp (s, IDENTIFIER_POINTER (mode_id), len) != 0)
+ return 0;
+
+ return ret;
+}
+
+/* Return the strub mode from STRUB_ATTR. VAR_P should be true if the attribute
+ is taken from a variable, rather than from a function, or a type thereof. */
+
+static enum strub_mode
+get_strub_mode_from_attr (tree strub_attr, bool var_p = false)
+{
+ enum strub_mode mode = STRUB_DISABLED;
+
+ if (strub_attr)
+ {
+ if (!TREE_VALUE (strub_attr))
+ mode = !var_p ? STRUB_AT_CALLS : STRUB_INTERNAL;
+ else
+ {
+ gcc_checking_assert (!var_p);
+ tree id = TREE_VALUE (strub_attr);
+ if (TREE_CODE (id) == TREE_LIST)
+ id = TREE_VALUE (id);
+ const char *s = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_POINTER (id)
+ : IDENTIFIER_POINTER (id));
+ size_t len = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_LENGTH (id) - 1
+ : IDENTIFIER_LENGTH (id));
+
+ switch (len)
+ {
+ case 7:
+ switch (s[6])
+ {
+ case 'r':
+ mode = STRUB_WRAPPER;
+ break;
+
+ case 'd':
+ mode = STRUB_WRAPPED;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 8:
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 9:
+ mode = STRUB_INLINABLE;
+ break;
+
+ case 12:
+ mode = STRUB_AT_CALLS_OPT;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id == get_strub_mode_attr_parm (mode)
+ : strncmp (IDENTIFIER_POINTER
+ (get_strub_mode_attr_parm (mode)),
+ s, len) == 0);
+ }
+ }
+
+ return mode;
+}
+
+/* Look up, decode and return the strub mode associated with FNDECL. */
+
+static enum strub_mode
+get_strub_mode_from_fndecl (tree fndecl)
+{
+ return get_strub_mode_from_attr (get_strub_attr_from_decl (fndecl));
+}
+
+/* Look up, decode and return the strub mode associated with NODE. */
+
+static enum strub_mode
+get_strub_mode (cgraph_node *node)
+{
+ return get_strub_mode_from_fndecl (node->decl);
+}
+
+/* Look up, decode and return the strub mode associated with TYPE. */
+
+static enum strub_mode
+get_strub_mode_from_type (tree type)
+{
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (type);
+ tree attr = get_strub_attr_from_type (type);
+
+ if (attr)
+ return get_strub_mode_from_attr (attr, var_p);
+
+ if (flag_strub >= -1 && !var_p)
+ return STRUB_CALLABLE;
+
+ return STRUB_DISABLED;
+}
+
+\f
+/* Return true iff NODE calls builtin va_start. */
+
+static bool
+calls_builtin_va_start_p (cgraph_node *node)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (fndecl_built_in_p (cdecl, BUILT_IN_VA_START))
+ return true;
+ }
+
+ return result;
+}
+
+/* Return true iff NODE calls builtin apply_args, and optionally REPORT it. */
+
+static bool
+calls_builtin_apply_args_p (cgraph_node *node, bool report = false)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!fndecl_built_in_p (cdecl, BUILT_IN_APPLY_ARGS))
+ continue;
+
+ result = true;
+
+ if (!report)
+ break;
+
+ sorry_at (gimple_location (e->call_stmt),
+ "at-calls %<strub%> does not support call to %qD",
+ cdecl);
+ }
+
+ return result;
+}
+
+/* Return true iff NODE carries the always_inline attribute. */
+
+static inline bool
+strub_always_inline_p (cgraph_node *node)
+{
+ return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
+}
+
+/* Return true iff NODE is potentially eligible for any strub-enabled mode, and
+ optionally REPORT the reasons for ineligibility. */
+
+static inline bool
+can_strub_p (cgraph_node *node, bool report = false)
+{
+ bool result = true;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<noipa%>",
+ node->decl);
+ }
+
+ /* We can't, and don't want to vectorize the watermark and other
+ strub-introduced parms. */
+ if (lookup_attribute ("simd", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<simd%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return true iff NODE is eligible for at-calls strub, and optionally REPORT
+ the reasons for ineligibility. Besides general non-eligibility for
+ strub-enabled modes, at-calls rules out calling builtin apply_args. */
+
+static bool
+can_strub_at_calls_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ return !calls_builtin_apply_args_p (node, report);
+}
+
+/* Symbolic macro for the max number of arguments that internal strub may add to
+ a function. */
+
+#define STRUB_INTERNAL_MAX_EXTRA_ARGS 3
+
+/* We can't perform internal strubbing if the function body involves certain
+ features:
+
+ - a non-default __builtin_va_start (e.g. x86's __builtin_ms_va_start) is
+ currently unsupported because we can't discover the corresponding va_copy and
+ va_end decls in the wrapper, and we don't convey the alternate variable
+ arguments ABI to the modified wrapped function. The default
+ __builtin_va_start is supported by calling va_start/va_end at the wrapper,
+ that takes variable arguments, passing a pointer to the va_list object to the
+ wrapped function, that runs va_copy from it where the original function ran
+ va_start.
+
+ __builtin_next_arg is currently unsupported because the wrapped function
+ won't be a variable argument function. We could process it in the wrapper,
+ that remains a variable argument function, and replace calls in the wrapped
+ body, but we currently don't.
+
+ __builtin_return_address is rejected because it's generally used when the
+ actual caller matters, and introducing a wrapper breaks such uses as those in
+ the unwinder. */
+
+static bool
+can_strub_internally_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ /* Since we're not changing the function identity proper, just
+ moving its full implementation, we *could* disable
+ fun->cannot_be_copied_reason and/or temporarily drop a noclone
+ attribute, but we'd have to prevent remapping of the labels. */
+ if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%>"
+ " because of attribute %<noclone%>",
+ node->decl);
+ }
+
+ if (node->has_gimple_body_p ())
+ {
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!((fndecl_built_in_p (cdecl, BUILT_IN_VA_START)
+ && cdecl != builtin_decl_explicit (BUILT_IN_VA_START))
+ || fndecl_built_in_p (cdecl, BUILT_IN_NEXT_ARG)
+ || fndecl_built_in_p (cdecl, BUILT_IN_RETURN_ADDRESS)))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (gimple_location (e->call_stmt),
+ "%qD is not eligible for internal %<strub%> "
+ "because it calls %qD",
+ node->decl, cdecl);
+ }
+
+ struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
+ if (fun->has_nonlocal_label)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it contains a non-local goto target",
+ node->decl);
+ }
+
+ if (fun->has_forced_label_in_static)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because the address of a local label escapes",
+ node->decl);
+ }
+
+ /* Catch any other case that would prevent versioning/cloning
+ so as to also have it covered above. */
+ gcc_checking_assert (!result /* || !node->has_gimple_body_p () */
+ || tree_versionable_function_p (node->decl));
+
+
+ /* Label values references are not preserved when copying. If referenced
+ in nested functions, as in 920415-1.c and 920721-4.c their decls get
+ remapped independently. The exclusion below might be too broad, in
+ that we might be able to support correctly cases in which the labels
+ are only used internally in a function, but disconnecting forced labels
+ from their original declarations is undesirable in general. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
+ tree target;
+
+ if (!label_stmt)
+ break;
+
+ target = gimple_label_label (label_stmt);
+
+ if (!FORCED_LABEL (target))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (gimple_location (label_stmt),
+ "internal %<strub%> does not support forced labels");
+ }
+ }
+
+ if (list_length (TYPE_ARG_TYPES (TREE_TYPE (node->decl)))
+ >= (((HOST_WIDE_INT) 1 << IPA_PARAM_MAX_INDEX_BITS)
+ - STRUB_INTERNAL_MAX_EXTRA_ARGS))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD has too many arguments for internal %<strub%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE has any strub-requiring local variable, or accesses (as
+ in reading) any variable through a strub-requiring type. */
+
+static bool
+strub_from_body_p (cgraph_node *node)
+{
+ if (!node->has_gimple_body_p ())
+ return false;
+
+ /* If any local variable is marked for strub... */
+ unsigned i;
+ tree var;
+ FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (node->decl),
+ i, var)
+ if (get_strub_mode_from_type (TREE_TYPE (var))
+ != STRUB_DISABLED)
+ return true;
+
+ /* Now scan the body for loads with strub-requiring types.
+ ??? Compound types don't propagate the strub requirement to
+ component types. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (!gimple_assign_load_p (stmt))
+ continue;
+
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if (get_strub_mode_from_type (TREE_TYPE (rhs))
+ != STRUB_DISABLED)
+ return true;
+ }
+
+ return false;
+}
+
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* This temporarily allocates stack for the call, and we can't reasonably
+ update the watermark for that. Besides, we don't check the actual call
+ target, nor its signature, and it seems to be overkill to as much as
+ try to do so. */
+ case BUILT_IN_APPLY:
+ return false;
+
+ /* Conversely, this shouldn't be called from within strub contexts, since
+ the caller may have had its signature modified. STRUB_INTERNAL is ok,
+ the call will remain in the STRUB_WRAPPER, and removed from the
+ STRUB_WRAPPED clone. */
+ case BUILT_IN_APPLY_ARGS:
+ return false;
+
+ /* ??? Make all other builtins callable. We wish to make any builtin call
+ the compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
+/* Compute the strub mode to be used for NODE. STRUB_ATTR should be the strub
+ attribute,found for NODE, if any. */
+
+static enum strub_mode
+compute_strub_mode (cgraph_node *node, tree strub_attr)
+{
+ enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr);
+
+ gcc_checking_assert (flag_strub >= -2 && flag_strub <= 3);
+
+ /* Symbolic encodings of the -fstrub-* flags. */
+ /* Enable strub when explicitly requested through attributes to functions or
+ variables, reporting errors if the requests cannot be satisfied. */
+ const bool strub_flag_auto = flag_strub < 0;
+ /* strub_flag_auto with strub call verification; without this, functions are
+ implicitly callable. */
+ const bool strub_flag_strict = flag_strub < -1;
+ /* Disable strub altogether, ignore attributes entirely. */
+ const bool strub_flag_disabled = flag_strub == 0;
+ /* On top of _auto, also enable strub implicitly for functions that can
+ safely undergo at-calls strubbing. Internal mode will still be used in
+ functions that request it explicitly with attribute strub(2), or when the
+ function body requires strubbing and at-calls strubbing is not viable. */
+ const bool strub_flag_at_calls = flag_strub == 1;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo internal strubbing. At-calls mode will still be used in
+ functions that requiest it explicitly with attribute strub() or strub(1),
+ or when the function body requires strubbing and internal strubbing is not
+ viable. */
+ const bool strub_flag_internal = flag_strub == 2;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo strubbing in either mode. When both modes are viable,
+ at-calls is preferred. */
+ const bool strub_flag_either = flag_strub == 3;
+ /* Besides the default behavior, enable strub implicitly for all viable
+ functions. */
+ const bool strub_flag_viable = flag_strub > 0;
+
+ /* The consider_* variables should be true if selecting the corresponding
+ strub modes would be consistent with requests from attributes and command
+ line flags. Attributes associated with functions pretty much mandate a
+ selection, and should report an error if not satisfied; strub_flag_auto
+ implicitly enables some viable strub mode if that's required by references
+ to variables marked for strub; strub_flag_viable enables strub if viable
+ (even when favoring one mode, body-requested strub can still be satisfied
+ by either mode), and falls back to callable, silently unless variables
+ require strubbing. */
+
+ const bool consider_at_calls
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_AT_CALLS
+ : true));
+ const bool consider_internal
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_INTERNAL
+ : true));
+
+ const bool consider_callable
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_CALLABLE
+ : (!strub_flag_strict
+ || strub_callable_builtin_p (node))));
+
+ /* This is a shorthand for either strub-enabled mode. */
+ const bool consider_strub
+ = (consider_at_calls || consider_internal);
+
+ /* We can cope with always_inline functions even with noipa and noclone,
+ because we just leave them alone. */
+ const bool is_always_inline
+ = strub_always_inline_p (node);
+
+ /* Strubbing in general, and each specific strub mode, may have its own set of
+ requirements. We require noipa for strubbing, either because of cloning
+ required for internal strub, or because of caller enumeration required for
+ at-calls strub. We don't consider the at-calls mode eligible if it's not
+ even considered, it has no further requirements. Internal mode requires
+ cloning and the absence of certain features in the body and, like at-calls,
+ it's not eligible if it's not even under consideration.
+
+ ??? Do we need target hooks for further constraints? E.g., x86's
+ "interrupt" attribute breaks internal strubbing because the wrapped clone
+ carries the attribute and thus isn't callable; in this case, we could use a
+ target hook to adjust the clone instead. */
+ const bool strub_eligible
+ = (consider_strub
+ && (is_always_inline || can_strub_p (node)));
+ const bool at_calls_eligible
+ = (consider_at_calls && strub_eligible
+ && can_strub_at_calls_p (node));
+ const bool internal_eligible
+ = (consider_internal && strub_eligible
+ && (is_always_inline
+ || can_strub_internally_p (node)));
+
+ /* In addition to the strict eligibility requirements, some additional
+ constraints are placed on implicit selection of certain modes. These do
+ not prevent the selection of a mode if explicitly specified as part of a
+ function interface (the strub attribute), but they may prevent modes from
+ being selected by the command line or by function bodies. The only actual
+ constraint is on at-calls mode: since we change the function's exposed
+ signature, we won't do it implicitly if the function can possibly be used
+ in ways that do not expect the signature change, e.g., if the function is
+ available to or interposable by other units, if its address is taken,
+ etc. */
+ const bool at_calls_viable
+ = (at_calls_eligible
+ && (strub_attr
+ || (node->has_gimple_body_p ()
+ && (!node->externally_visible
+ || (node->binds_to_current_def_p ()
+ && node->can_be_local_p ()))
+ && node->only_called_directly_p ())));
+ const bool internal_viable
+ = (internal_eligible);
+
+ /* Shorthand. */
+ const bool strub_viable
+ = (at_calls_viable || internal_viable);
+
+ /* We wish to analyze the body, to look for implicit requests for strub, both
+ to implicitly enable it when the body calls for it, and to report errors if
+ the body calls for it but neither mode is viable (even if that follows from
+ non-eligibility because of the explicit specification of some non-strubbing
+ mode). We can refrain from scanning the body only in rare circumstances:
+ when strub is enabled by a function attribute (scanning might be redundant
+ in telling us to also enable it), and when we are enabling strub implicitly
+ but there are non-viable modes: we want to know whether strubbing is
+ required, to fallback to another mode, even if we're only enabling a
+ certain mode, or, when either mode would do, to report an error if neither
+ happens to be viable. */
+ const bool analyze_body
+ = (strub_attr
+ ? !consider_strub
+ : (strub_flag_auto
+ || (strub_flag_viable && (!at_calls_viable && !internal_viable))
+ || (strub_flag_either && !strub_viable)));
+
+ /* Cases in which strubbing is enabled or disabled by strub_flag_auto.
+ Unsatisfiable requests ought to be reported. */
+ const bool strub_required
+ = ((strub_attr && consider_strub)
+ || (analyze_body && strub_from_body_p (node)));
+
+ /* Besides the required cases, we want to abide by the requests to enabling on
+ an if-viable basis. */
+ const bool strub_enable
+ = (strub_required
+ || (strub_flag_at_calls && at_calls_viable)
+ || (strub_flag_internal && internal_viable)
+ || (strub_flag_either && strub_viable));
+
+ /* And now we're finally ready to select a mode that abides by the viability
+ and eligibility constraints, and that satisfies the strubbing requirements
+ and requests, subject to the constraints. If both modes are viable and
+ strub is to be enabled, pick STRUB_AT_CALLS unless STRUB_INTERNAL was named
+ as preferred. */
+ const enum strub_mode mode
+ = ((strub_enable && is_always_inline)
+ ? (strub_required ? STRUB_INLINABLE : STRUB_CALLABLE)
+ : (strub_enable && internal_viable
+ && (strub_flag_internal || !at_calls_viable))
+ ? STRUB_INTERNAL
+ : (strub_enable && at_calls_viable)
+ ? (strub_required && !strub_attr
+ ? STRUB_AT_CALLS_OPT
+ : STRUB_AT_CALLS)
+ : consider_callable
+ ? STRUB_CALLABLE
+ : STRUB_DISABLED);
+
+ switch (mode)
+ {
+ case STRUB_CALLABLE:
+ if (is_always_inline)
+ break;
+ /* Fall through. */
+
+ case STRUB_DISABLED:
+ if (strub_enable && !strub_attr)
+ {
+ gcc_checking_assert (analyze_body);
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD requires %<strub%>,"
+ " but no viable %<strub%> mode was found",
+ node->decl);
+ break;
+ }
+ /* Fall through. */
+
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ /* Differences from an mode requested through a function attribute are
+ reported in set_strub_mode_to. */
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ /* Functions that select this mode do so because of references to strub
+ variables. Even if we choose at-calls as an optimization, the
+ requirements for internal strub must still be satisfied. Optimization
+ options may render implicit at-calls strub not viable (-O0 sets
+ force_output for static non-inline functions), and it would not be good
+ if changing optimization options turned a well-formed into an
+ ill-formed one. */
+ if (!internal_viable)
+ can_strub_internally_p (node, true);
+ break;
+
+ case STRUB_WRAPPED:
+ case STRUB_WRAPPER:
+ default:
+ gcc_unreachable ();
+ }
+
+ return mode;
+}
+
+/* Set FNDT's strub mode to MODE; FNDT may be a function decl or
+ function type. If OVERRIDE, do not check whether a mode is already
+ set. */
+
+static void
+strub_set_fndt_mode_to (tree fndt, enum strub_mode mode, bool override)
+{
+ gcc_checking_assert (override
+ || !(DECL_P (fndt)
+ ? get_strub_attr_from_decl (fndt)
+ : get_strub_attr_from_type (fndt)));
+
+ tree attr = tree_cons (get_identifier ("strub"),
+ get_strub_mode_attr_value (mode),
+ NULL_TREE);
+ tree *attrp = NULL;
+ if (DECL_P (fndt))
+ {
+ gcc_checking_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndt)));
+ attrp = &DECL_ATTRIBUTES (fndt);
+ }
+ else if (FUNC_OR_METHOD_TYPE_P (fndt))
+ attrp = &TYPE_ATTRIBUTES (fndt);
+ else
+ gcc_unreachable ();
+
+ TREE_CHAIN (attr) = *attrp;
+ *attrp = attr;
+}
+
+/* Set FNDT's strub mode to callable.
+ FNDT may be a function decl or a function type. */
+
+void
+strub_make_callable (tree fndt)
+{
+ strub_set_fndt_mode_to (fndt, STRUB_CALLABLE, false);
+}
+
+/* Set NODE to strub MODE. Report incompatibilities between MODE and the mode
+ requested through explicit attributes, and cases of non-eligibility. */
+
+static void
+set_strub_mode_to (cgraph_node *node, enum strub_mode mode)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+ enum strub_mode req_mode = get_strub_mode_from_attr (attr);
+
+ if (attr)
+ {
+ /* Check for and report incompatible mode changes. */
+ if (mode != req_mode
+ && !(req_mode == STRUB_INTERNAL
+ && (mode == STRUB_WRAPPED
+ || mode == STRUB_WRAPPER))
+ && !((req_mode == STRUB_INTERNAL
+ || req_mode == STRUB_AT_CALLS
+ || req_mode == STRUB_CALLABLE)
+ && mode == STRUB_INLINABLE))
+ {
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<strub%> mode %qE selected for %qD, when %qE was requested",
+ get_strub_mode_attr_parm (mode),
+ node->decl,
+ get_strub_mode_attr_parm (req_mode));
+ if (node->alias)
+ {
+ cgraph_node *target = node->ultimate_alias_target ();
+ if (target != node)
+ error_at (DECL_SOURCE_LOCATION (target->decl),
+ "the incompatible selection was determined"
+ " by ultimate alias target %qD",
+ target->decl);
+ }
+
+ /* Report any incompatibilities with explicitly-requested strub. */
+ switch (req_mode)
+ {
+ case STRUB_AT_CALLS:
+ can_strub_at_calls_p (node, true);
+ break;
+
+ case STRUB_INTERNAL:
+ can_strub_internally_p (node, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Drop any incompatible strub attributes leading the decl attribute
+ chain. Return if we find one with the mode we need. */
+ for (;;)
+ {
+ if (mode == req_mode)
+ return;
+
+ if (DECL_ATTRIBUTES (node->decl) != attr)
+ break;
+
+ DECL_ATTRIBUTES (node->decl) = TREE_CHAIN (attr);
+ attr = get_strub_attr_from_decl (node->decl);
+ if (!attr)
+ break;
+
+ req_mode = get_strub_mode_from_attr (attr);
+ }
+ }
+ else if (mode == req_mode)
+ return;
+
+ strub_set_fndt_mode_to (node->decl, mode, attr);
+}
+
+/* Compute and set NODE's strub mode. */
+
+static void
+set_strub_mode (cgraph_node *node)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+
+ if (attr)
+ switch (get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ cgraph_node *xnode = node;
+ if (node->alias)
+ xnode = node->ultimate_alias_target ();
+ /* Weakrefs may remain unresolved (the above will return node) if
+ their targets are not defined, so make sure we compute a strub
+ mode for them, instead of defaulting to STRUB_DISABLED and
+ rendering them uncallable. */
+ enum strub_mode mode = (xnode != node && !xnode->alias
+ ? get_strub_mode (xnode)
+ : compute_strub_mode (node, attr));
+
+ set_strub_mode_to (node, mode);
+}
+
+\f
+/* Non-strub functions shouldn't be called from within strub contexts,
+ except through callable ones. Always inline strub functions can
+ only be called from strub functions. */
+
+static bool
+strub_callable_from_p (cgraph_node *callee, cgraph_node *caller)
+{
+ strub_mode caller_mode = get_strub_mode (caller);
+ strub_mode callee_mode = get_strub_mode (callee);
+
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ return callee_mode != STRUB_INLINABLE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return (flag_strub >= -1);
+
+ case STRUB_DISABLED:
+ return false;
+
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return true if CALLEE can be inlined into CALLER. We wish to avoid inlining
+ WRAPPED functions back into their WRAPPERs. More generally, we wish to avoid
+ inlining strubbed functions into non-strubbed ones. CALLER doesn't have to
+ be an immediate caller of CALLEE: the immediate caller may have already been
+ cloned for inlining, and then CALLER may be further up the original call
+ chain. ??? It would be nice if our own caller would retry inlining callee
+ if caller gets inlined. */
+
+bool
+strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller)
+{
+ strub_mode callee_mode = get_strub_mode (callee);
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ /* When we consider inlining, we've already verified callability, so we
+ can even inline callable and then disabled into a strub context. That
+ will get strubbed along with the context, so it's hopefully not a
+ problem. */
+ return true;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ strub_mode caller_mode = get_strub_mode (caller);
+
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return true;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+/* Check that types T1 and T2 are strub-compatible. Return 1 if the strub modes
+ are the same, 2 if they are interchangeable, and 0 otherwise. */
+
+int
+strub_comptypes (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
+
+ enum strub_mode m1 = get_strub_mode_from_type (t1);
+ enum strub_mode m2 = get_strub_mode_from_type (t2);
+
+ if (m1 == m2)
+ return 1;
+
+ /* We're dealing with types, so only strub modes that can be selected by
+ attributes in the front end matter. If either mode is at-calls (for
+ functions) or internal (for variables), the conversion is not
+ compatible. */
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (t1);
+ enum strub_mode mr = var_p ? STRUB_INTERNAL : STRUB_AT_CALLS;
+ if (m1 == mr || m2 == mr)
+ return 0;
+
+ return 2;
+}
+
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ /* It's expected that check strub-wise pointer type compatibility of variables
+ and of functions is already taken care of by front-ends, on account of the
+ attribute's being marked as affecting type identity and of the creation of
+ distinct types. */
+
+ /* Check that call targets in strub contexts have strub-callable types. */
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_AT_CALLS_OPT
+ || caller_mode == STRUB_INTERNAL
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-%<strub%> call in %<strub%> context %qD",
+ node->decl);
+ }
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+ if (!strub_callable_from_p (e->callee, node))
+ {
+ if (get_strub_mode (e->callee) == STRUB_INLINABLE)
+ error_at (gimple_location (e->call_stmt),
+ "calling %<always_inline%> %<strub%> %qD"
+ " in non-%<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else if (fndecl_built_in_p (e->callee->decl, BUILT_IN_APPLY_ARGS)
+ && get_strub_mode (node) == STRUB_INTERNAL)
+ /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
+ from the STRUB_WRAPPED's strub context. */
+ continue;
+ else
+ error_at (gimple_location (e->call_stmt),
+ "calling non-%<strub%> %qD in %<strub%> context %qD",
+ e->callee->decl, node->decl);
+ }
+ }
+ }
+}
+
+namespace {
+
+/* Define a pass to compute strub modes. */
+const pass_data pass_data_ipa_strub_mode = {
+ SIMPLE_IPA_PASS,
+ "strubm",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ 0, // properties_finish
+};
+
+class pass_ipa_strub_mode : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub_mode (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub_mode, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub_mode (m_ctxt); }
+ virtual bool gate (function *) {
+ /* In relaxed (-3) and strict (-4) settings, that only enable strub at a
+ function or variable attribute's request, the attribute handler changes
+ flag_strub to -1 or -2, respectively, if any strub-enabling occurence of
+ the attribute is found. Therefore, if it remains at -3 or -4, nothing
+ that would enable strub was found, so we can disable it and avoid the
+ overhead. */
+ if (flag_strub < -2)
+ flag_strub = 0;
+ return flag_strub;
+ }
+ virtual unsigned int execute (function *);
+};
+
+/* Define a pass to introduce strub transformations. */
+const pass_data pass_data_ipa_strub = {
+ SIMPLE_IPA_PASS,
+ "strub",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg | PROP_ssa, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ TODO_update_ssa
+ | TODO_cleanup_cfg
+ | TODO_rebuild_cgraph_edges
+ | TODO_verify_il, // properties_finish
+};
+
+class pass_ipa_strub : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub (m_ctxt); }
+ virtual bool gate (function *) { return flag_strub && !seen_error (); }
+ virtual unsigned int execute (function *);
+
+ /* Define on demand and cache some types we use often. */
+#define DEF_TYPE(NAME, INIT) \
+ static inline tree get_ ## NAME () { \
+ static tree type = NULL_TREE; \
+ if (!type) \
+ type = (INIT); \
+ return type; \
+ }
+
+ /* Use a distinct ptr_type_node to denote the watermark, so that we can
+ recognize it in arg lists and avoid modifying types twice. */
+ DEF_TYPE (wmt, build_variant_type_copy (ptr_type_node))
+
+ DEF_TYPE (pwmt, build_reference_type (get_wmt ()))
+
+ DEF_TYPE (qpwmt,
+ build_qualified_type (get_pwmt (),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+ DEF_TYPE (qptr,
+ build_qualified_type (ptr_type_node,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST))
+
+ DEF_TYPE (qpvalst,
+ build_qualified_type (build_reference_type
+ (va_list_type_node),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+#undef DEF_TYPE
+
+ /* Define non-strub builtins on demand. */
+#define DEF_NM_BUILTIN(NAME, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ decl = add_builtin_function \
+ ("__builtin_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ NULL, NULL); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_NM_BUILTIN (stack_address,
+ BUILT_IN_STACK_ADDRESS,
+ (ptr_type_node, NULL))
+
+#undef DEF_NM_BUILTIN
+
+ /* Define strub builtins on demand. */
+#define DEF_SS_BUILTIN(NAME, FNSPEC, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ tree attrs = NULL; \
+ if (FNSPEC && HAVE_ATTR_FNSPEC) \
+ attrs = tree_cons (get_identifier ("fn spec"), \
+ build_tree_list \
+ (NULL_TREE, \
+ build_string (strlen (FNSPEC), \
+ (FNSPEC))), \
+ attrs); \
+ decl = add_builtin_function_ext_scope \
+ ("__builtin___strub_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ "__strub_" #NAME, attrs); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_SS_BUILTIN (enter, ". Ot",
+ BUILT_IN___STRUB_ENTER,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (update, ". Wt",
+ BUILT_IN___STRUB_UPDATE,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (leave, ". w ",
+ BUILT_IN___STRUB_LEAVE,
+ (void_type_node, get_qpwmt (), NULL))
+
+#undef DEF_SS_BUILTIN
+
+ /* Define strub identifiers on demand. */
+#define DEF_IDENT(NAME) \
+ static inline tree get_ ## NAME () { \
+ static tree identifier = NULL_TREE; \
+ if (!identifier) \
+ identifier = get_identifier (".strub." #NAME); \
+ return identifier; \
+ }
+
+ DEF_IDENT (watermark_ptr)
+ DEF_IDENT (va_list_ptr)
+ DEF_IDENT (apply_args)
+
+#undef DEF_IDENT
+
+ static inline int adjust_at_calls_type (tree);
+ static inline void adjust_at_calls_call (cgraph_edge *, int);
+ static inline void adjust_at_calls_calls (cgraph_node *);
+
+ /* Add to SEQ a call to the strub watermark update builtin, taking NODE's
+ location if given. Optionally add the corresponding edge from NODE, with
+ execution frequency COUNT. Return the modified SEQ. */
+
+ static inline gimple_seq
+ call_update_watermark (tree wmptr, cgraph_node *node, profile_count count,
+ gimple_seq seq = NULL)
+ {
+ tree uwm = get_update ();
+ gcall *update = gimple_build_call (uwm, 1, wmptr);
+ if (node)
+ gimple_set_location (update, DECL_SOURCE_LOCATION (node->decl));
+ gimple_seq_add_stmt (&seq, update);
+ if (node)
+#if !IMPLICIT_CGRAPH_EDGES
+ node->create_edge (cgraph_node::get_create (uwm), update, count, false);
+#else
+ (void)count;
+#endif
+ return seq;
+ }
+
+};
+
+} // anon namespace
+
+/* Gather with this type a collection of parameters that we're turning into
+ explicit references. */
+
+typedef hash_set<tree> indirect_parms_t;
+
+/* Dereference OP's incoming turned-into-reference parm if it's an
+ INDIRECT_PARMS or an ADDR_EXPR thereof. Set *REC and return according to
+ gimple-walking expectations. */
+
+static tree
+maybe_make_indirect (indirect_parms_t &indirect_parms, tree op, int *rec)
+{
+ if (DECL_P (op))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (op))
+ {
+ tree ret = gimple_fold_indirect_ref (op);
+ if (!ret)
+ ret = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (op)),
+ op,
+ build_int_cst (TREE_TYPE (op), 0));
+ return ret;
+ }
+ }
+ else if (TREE_CODE (op) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (op, 0)))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (TREE_OPERAND (op, 0)))
+ {
+ op = TREE_OPERAND (op, 0);
+ return op;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that adds dereferencing to indirect parms. */
+
+static tree
+walk_make_indirect (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ indirect_parms_t &indirect_parms = *(indirect_parms_t *)wi->info;
+
+ if (!*op || TYPE_P (*op))
+ {
+ *rec = 0;
+ return NULL_TREE;
+ }
+
+ if (tree repl = maybe_make_indirect (indirect_parms, *op, rec))
+ {
+ *op = repl;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that turns any non-gimple-val ADDR_EXPRs into a
+ separate SSA. Though addresses of e.g. parameters, and of members thereof,
+ are gimple vals, turning parameters into references, with an extra layer of
+ indirection and thus explicit dereferencing, need to be regimplified. */
+
+static tree
+walk_regimplify_addr_expr (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ gimple_stmt_iterator &gsi = *(gimple_stmt_iterator *)wi->info;
+
+ *rec = 0;
+
+ if (!*op || TREE_CODE (*op) != ADDR_EXPR)
+ return NULL_TREE;
+
+ if (!is_gimple_val (*op))
+ {
+ tree ret = force_gimple_operand_gsi (&gsi, *op, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ gcc_assert (ret != *op);
+ *op = ret;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Turn STMT's PHI arg defs into separate SSA defs if they've become
+ non-gimple_val. Return TRUE if any edge insertions need to be committed. */
+
+static bool
+walk_regimplify_phi (gphi *stmt)
+{
+ bool needs_commit = false;
+
+ for (unsigned i = 0, n = gimple_phi_num_args (stmt); i < n; i++)
+ {
+ tree op = gimple_phi_arg_def (stmt, i);
+ if ((TREE_CODE (op) == ADDR_EXPR
+ && !is_gimple_val (op))
+ /* ??? A PARM_DECL that was addressable in the original function and
+ had its address in PHI nodes, but that became a reference in the
+ wrapped clone would NOT be updated by update_ssa in PHI nodes.
+ Alas, if we were to create a default def for it now, update_ssa
+ would complain that the symbol that needed rewriting already has
+ SSA names associated with it. OTOH, leaving the PARM_DECL alone,
+ it eventually causes errors because it remains unchanged in PHI
+ nodes, but it gets rewritten as expected if it appears in other
+ stmts. So we cheat a little here, and force the PARM_DECL out of
+ the PHI node and into an assignment. It's a little expensive,
+ because we insert it at the edge, which introduces a basic block
+ that's entirely unnecessary, but it works, and the block will be
+ removed as the default def gets propagated back into the PHI node,
+ so the final optimized code looks just as expected. */
+ || (TREE_CODE (op) == PARM_DECL
+ && !TREE_ADDRESSABLE (op)))
+ {
+ tree temp = make_ssa_name (TREE_TYPE (op), stmt);
+ if (TREE_CODE (op) == PARM_DECL)
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (temp, DECL_NAME (op));
+ SET_PHI_ARG_DEF (stmt, i, temp);
+
+ gimple *assign = gimple_build_assign (temp, op);
+ if (gimple_phi_arg_has_location (stmt, i))
+ gimple_set_location (assign, gimple_phi_arg_location (stmt, i));
+ gsi_insert_on_edge (gimple_phi_arg_edge (stmt, i), assign);
+ needs_commit = true;
+ }
+ }
+
+ return needs_commit;
+}
+
+/* Create a reference type to use for PARM when turning it into a reference.
+ NONALIASED causes the reference type to gain its own separate alias set, so
+ that accessing the indirectly-passed parm won'will not add aliasing
+ noise. */
+
+static tree
+build_ref_type_for (tree parm, bool nonaliased = true)
+{
+ gcc_checking_assert (TREE_CODE (parm) == PARM_DECL);
+
+ tree ref_type = build_reference_type (TREE_TYPE (parm));
+
+ if (!nonaliased)
+ return ref_type;
+
+ /* Each PARM turned indirect still points to the distinct memory area at the
+ wrapper, and the reference in unchanging, so we might qualify it, but...
+ const is not really important, since we're only using default defs for the
+ reference parm anyway, and not introducing any defs, and restrict seems to
+ cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that,
+ if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias
+ set seems to not run afoul of this problem, and it hopefully enables the
+ compiler to tell the pointers do point to objects that are not otherwise
+ aliased. */
+#if 1
+ tree qref_type = build_variant_type_copy (ref_type);
+
+ TYPE_ALIAS_SET (qref_type) = new_alias_set ();
+ record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type));
+
+ return qref_type;
+#else
+ tree qref_type = build_qualified_type (ref_type,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST);
+
+ return qref_type;
+#endif
+}
+
+/* Add cgraph edges from current_function_decl to callees in SEQ with frequency
+ COUNT, assuming all calls in SEQ are direct. */
+
+static void
+add_call_edges_for_seq (gimple_seq seq, profile_count count)
+{
+#if IMPLICIT_CGRAPH_EDGES
+ return;
+#endif
+
+ cgraph_node *node = cgraph_node::get_create (current_function_decl);
+
+ for (gimple_stmt_iterator gsi = gsi_start (seq);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ if (!call)
+ continue;
+
+ tree callee = gimple_call_fndecl (call);
+ gcc_checking_assert (callee);
+ node->create_edge (cgraph_node::get_create (callee), call, count, false);
+ }
+}
+
+/* Insert SEQ after the call at GSI, as if the call was in a try block with SEQ
+ as finally, i.e., SEQ will run after the call whether it returns or
+ propagates an exception. This handles block splitting, EH edge and block
+ creation, noreturn and nothrow optimizations, and even throwing calls without
+ preexisting local handlers. */
+
+static void
+gsi_insert_finally_seq_after_call (gimple_stmt_iterator gsi, gimple_seq seq)
+{
+ if (!seq)
+ return;
+
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gimple_has_location (stmt))
+ annotate_all_with_location (seq, gimple_location (stmt));
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ bool noreturn_p = call && gimple_call_noreturn_p (call);
+ int eh_lp = lookup_stmt_eh_lp (stmt);
+ bool must_not_throw_p = eh_lp < 0;
+ bool nothrow_p = (must_not_throw_p
+ || (call && gimple_call_nothrow_p (call))
+ || (eh_lp <= 0
+ && (TREE_NOTHROW (cfun->decl)
+ || !flag_exceptions)));
+
+ if (noreturn_p && nothrow_p)
+ return;
+
+ /* Don't expect an EH edge if we're not to throw, or if we're not in an EH
+ region yet. */
+ bool no_eh_edge_p = (nothrow_p || !eh_lp);
+ bool must_end_bb = stmt_ends_bb_p (stmt);
+
+ edge eft = NULL, eeh = NULL;
+ if (must_end_bb && !(noreturn_p && no_eh_edge_p))
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->succs)
+ {
+ if ((e->flags & EDGE_EH))
+ {
+ gcc_checking_assert (!eeh);
+ eeh = e;
+#if !CHECKING_P
+ if (eft || noreturn_p)
+ break;
+#endif
+ }
+ if ((e->flags & EDGE_FALLTHRU))
+ {
+ gcc_checking_assert (!eft);
+ eft = e;
+#if !CHECKING_P
+ if (eeh || no_eh_edge_p)
+ break;
+#endif
+ }
+ }
+
+ gcc_checking_assert (!(eft && (eft->flags & EDGE_FALLTHRU))
+ == noreturn_p);
+ gcc_checking_assert (!(eeh && (eeh->flags & EDGE_EH))
+ == no_eh_edge_p);
+ gcc_checking_assert (eft != eeh);
+ }
+
+ if (!noreturn_p)
+ {
+ gimple_seq nseq = nothrow_p ? seq : gimple_seq_copy (seq);
+
+ if (must_end_bb)
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+ add_call_edges_for_seq (nseq, eft->count ());
+ gsi_insert_seq_on_edge_immediate (eft, nseq);
+ }
+ else
+ {
+ add_call_edges_for_seq (nseq, gsi_bb (gsi)->count);
+ gsi_insert_seq_after (&gsi, nseq, GSI_SAME_STMT);
+ }
+ }
+
+ if (nothrow_p)
+ return;
+
+ if (eh_lp)
+ {
+ add_call_edges_for_seq (seq, eeh->count ());
+ gsi_insert_seq_on_edge_immediate (eeh, seq);
+ return;
+ }
+
+ /* A throwing call may appear within a basic block in a function that doesn't
+ have any EH regions. We're going to add a cleanup if so, therefore the
+ block will have to be split. */
+ basic_block bb = gsi_bb (gsi);
+ if (!gsi_one_before_end_p (gsi))
+ split_block (bb, stmt);
+
+ /* Create a new block for the EH cleanup. */
+ basic_block bb_eh_cleanup = create_empty_bb (bb);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, bb_eh_cleanup, bb);
+ if (current_loops)
+ add_bb_to_loop (bb_eh_cleanup, current_loops->tree_root);
+
+ /* Make the new block an EH cleanup for the call. */
+ eh_region new_r = gen_eh_region_cleanup (NULL);
+ eh_landing_pad lp = gen_eh_landing_pad (new_r);
+ tree label = gimple_block_label (bb_eh_cleanup);
+ lp->post_landing_pad = label;
+ EH_LANDING_PAD_NR (label) = lp->index;
+ add_stmt_to_eh_lp (stmt, lp->index);
+
+ /* Add the cleanup code to the EH cleanup block. */
+ gsi = gsi_after_labels (bb_eh_cleanup);
+ gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+
+ /* And then propagate the exception further. */
+ gresx *resx = gimple_build_resx (new_r->index);
+ if (gimple_has_location (stmt))
+ gimple_set_location (resx, gimple_location (stmt));
+ gsi_insert_before (&gsi, resx, GSI_SAME_STMT);
+
+ /* Finally, wire the EH cleanup block into the CFG. */
+ make_eh_edges (stmt);
+ add_call_edges_for_seq (seq, single_pred_edge (bb_eh_cleanup)->count ());
+}
+
+/* Copy the attribute list at *ATTRS, minus any NAME attributes, leaving
+ shareable trailing nodes alone. */
+
+static inline void
+remove_named_attribute_unsharing (const char *name, tree *attrs)
+{
+ while (tree found = lookup_attribute (name, *attrs))
+ {
+ /* Copy nodes up to the next NAME attribute. */
+ while (*attrs != found)
+ {
+ *attrs = tree_cons (TREE_PURPOSE (*attrs),
+ TREE_VALUE (*attrs),
+ TREE_CHAIN (*attrs));
+ attrs = &TREE_CHAIN (*attrs);
+ }
+ /* Then drop it. */
+ gcc_checking_assert (*attrs == found);
+ *attrs = TREE_CHAIN (*attrs);
+ }
+}
+
+/* Record the order of the last cgraph entry whose mode we've already set, so
+ that we can perform mode setting incrementally without duplication. */
+static int last_cgraph_order;
+
+/* Set strub modes for functions introduced since the last call. */
+
+static void
+ipa_strub_set_mode_for_new_functions ()
+{
+ if (symtab->order == last_cgraph_order)
+ return;
+
+ cgraph_node *node;
+
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
+ for (int aliases = 0; aliases <= 1; aliases++)
+ FOR_EACH_FUNCTION (node)
+ {
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ set_strub_mode (node);
+ }
+
+ last_cgraph_order = symtab->order;
+}
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+
+bool
+strub_splittable_p (cgraph_node *node)
+{
+ switch (get_strub_mode (node))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INLINABLE:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return false;
+
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */
+
+tree
+strub_watermark_parm (tree fndecl)
+{
+ switch (get_strub_mode_from_fndecl (fndecl))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ case STRUB_INLINABLE:
+ return NULL_TREE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+ /* The type (variant) compare finds the parameter even in a just-created
+ clone, before we set its name, but the type-based compare doesn't work
+ during builtin expansion within the lto compiler, because we'll have
+ created a separate variant in that run. */
+ if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()
+ || DECL_NAME (parm) == pass_ipa_strub::get_watermark_ptr ())
+ return parm;
+
+ gcc_unreachable ();
+}
+
+/* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it
+ hasn't been added yet. Return the named argument count. */
+
+int
+pass_ipa_strub::adjust_at_calls_type (tree type)
+{
+ int named_args = 0;
+
+ if (!TYPE_ARG_TYPES (type))
+ return named_args;
+
+ tree *tlist = &TYPE_ARG_TYPES (type);
+ tree qpwmptrt = get_qpwmt ();
+ while (*tlist && TREE_VALUE (*tlist) != void_type_node)
+ {
+ /* The type has already been adjusted. */
+ if (TREE_VALUE (*tlist) == qpwmptrt)
+ return named_args;
+ named_args++;
+ *tlist = tree_cons (TREE_PURPOSE (*tlist),
+ TREE_VALUE (*tlist),
+ TREE_CHAIN (*tlist));
+ tlist = &TREE_CHAIN (*tlist);
+ }
+
+ /* Add the new argument after all named arguments, so as to not mess with
+ attributes that reference parameters. */
+ *tlist = tree_cons (NULL_TREE, get_qpwmt (), *tlist);
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ if (!type_already_adjusted)
+ {
+ int flags = flags_from_decl_or_type (type);
+ tree fnspec = lookup_attribute ("fn spec", type);
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1;
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied, if needed, before adding
+ parameters. */
+ TYPE_ATTRIBUTES (type)
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (type));
+ }
+ }
+#endif
+
+ return named_args;
+}
+
+/* Adjust a call to an at-calls call target. Create a watermark local variable
+ if needed, initialize it before, pass it to the callee according to the
+ modified at-calls interface, and release the callee's stack space after the
+ call, if not deferred. If the call is const or pure, arrange for the
+ watermark to not be assumed unused or unchanged. */
+
+void
+pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args)
+{
+ gcall *ocall = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (ocall);
+
+ /* Make sure we haven't modified this call yet. */
+ gcc_checking_assert (!(int (gimple_call_num_args (ocall)) > named_args
+ && (TREE_TYPE (gimple_call_arg (ocall, named_args))
+ == get_pwmt ())));
+
+ /* If we're already within a strub context, pass on the incoming watermark
+ pointer, and omit the enter and leave calls around the modified call, as an
+ optimization, or as a means to satisfy a tail-call requirement. */
+ tree swmp = ((optimize_size || optimize > 2
+ || gimple_call_must_tail_p (ocall)
+ || (optimize == 2 && gimple_call_tail_p (ocall)))
+ ? strub_watermark_parm (e->caller->decl)
+ : NULL_TREE);
+ bool omit_own_watermark = swmp;
+ tree swm = NULL_TREE;
+ if (!omit_own_watermark)
+ {
+ swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ /* Initialize the watermark before the call. */
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1,
+ unshare_expr (swmp));
+ if (gimple_has_location (ocall))
+ gimple_set_location (stptr, gimple_location (ocall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+#if !IMPLICIT_CGRAPH_EDGES
+ e->caller->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+#endif
+ }
+
+
+ /* Replace the call with one that passes the swmp argument first. */
+ gcall *wrcall;
+ { gcall *stmt = ocall;
+ // Mostly copied from gimple_call_copy_skip_args.
+ int i = 0;
+ int nargs = gimple_call_num_args (stmt);
+ auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
+ gcall *new_stmt;
+
+ /* pr71109.c calls a prototypeless function, then defines it with
+ additional arguments. It's ill-formed, but after it's inlined,
+ it somehow works out. */
+ for (; i < named_args && i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+ for (; i < named_args; i++)
+ vargs.quick_push (null_pointer_node);
+
+ vargs.quick_push (unshare_expr (swmp));
+
+ for (; i < nargs; i++)
+#if 0
+ if (!bitmap_bit_p (args_to_skip, i))
+#endif
+ vargs.quick_push (gimple_call_arg (stmt, i));
+
+ if (gimple_call_internal_p (stmt))
+#if 0
+ new_stmt = gimple_build_call_internal_vec (gimple_call_internal_fn (stmt),
+ vargs);
+#endif
+ gcc_unreachable ();
+ else
+ new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
+
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+#if 0
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+#else
+ gimple_move_vops (new_stmt, stmt);
+#endif
+
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gimple_call_copy_flags (new_stmt, stmt);
+ gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+
+ gimple_set_modified (new_stmt, true);
+
+ wrcall = new_stmt;
+ }
+
+ update_stmt (wrcall);
+ gsi_replace (&gsi, wrcall, true);
+ cgraph_edge::set_call_stmt (e, wrcall, false);
+
+ /* Insert the strub code after the call. */
+ gimple_seq seq = NULL;
+
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ if (!swm)
+ swm = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (swmp)),
+ swmp,
+ build_int_cst (TREE_TYPE (swmp), 0));
+
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ unshare_expr (swm)));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ if (gimple_has_location (wrcall))
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ if (!omit_own_watermark)
+ {
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+}
+
+/* Adjust all at-calls calls in NODE. */
+
+void
+pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
+{
+ /* Adjust unknown-callee indirect calls with STRUB_AT_CALLS types within
+ onode. */
+ if (node->indirect_calls)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args);
+ }
+ pop_cfun ();
+ }
+
+ if (node->callees)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ enum strub_mode callee_mode = get_strub_mode (e->callee);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (TREE_TYPE (e->callee->decl));
+
+ adjust_at_calls_call (e, named_args);
+ }
+ pop_cfun ();
+ }
+}
+
+/* The strubm (strub mode) pass computes a strub mode for each function in the
+ call graph, and checks, before any inlining, that strub callability
+ requirements in effect are satisfied. */
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ last_cgraph_order = 0;
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
+
+ return 0;
+}
+
+/* Create a strub mode pass. */
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub_mode (gcc::context *ctxt)
+{
+ return new pass_ipa_strub_mode (ctxt);
+}
+
+/* The strub pass proper adjusts types, signatures, and at-calls calls, and
+ splits internal-strub functions. */
+
+unsigned int
+pass_ipa_strub::execute (function *)
+{
+ cgraph_node *onode;
+
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* First, adjust the signature of at-calls functions. We adjust types of
+ at-calls functions first, so that we don't modify types in place unless
+ strub is explicitly requested. */
+ FOR_EACH_FUNCTION (onode)
+ {
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode == STRUB_AT_CALLS
+ || mode == STRUB_AT_CALLS_OPT)
+ {
+ /* Create a type variant if strubbing was not explicitly requested in
+ the function type. */
+ if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
+ TREE_TYPE (onode->decl) = build_distinct_type_copy (TREE_TYPE
+ (onode->decl));
+
+ int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));
+
+ /* An external function explicitly declared with strub won't have a
+ body. Even with implicit at-calls strub, a function may have had its
+ body removed after we selected the mode, and then we have nothing
+ further to do. */
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ tree *pargs = &DECL_ARGUMENTS (onode->decl);
+
+ /* A noninterposable_alias reuses the same parm decl chain, don't add
+ the parm twice. */
+ bool aliased_parms = (onode->alias && *pargs
+ && DECL_CONTEXT (*pargs) != onode->decl);
+
+ if (aliased_parms)
+ continue;
+
+ for (int i = 0; i < named_args; i++)
+ pargs = &DECL_CHAIN (*pargs);
+
+ tree wmptr = build_decl (DECL_SOURCE_LOCATION (onode->decl),
+ PARM_DECL,
+ get_watermark_ptr (),
+ get_qpwmt ());
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_ARG_TYPE (wmptr) = get_qpwmt ();
+ DECL_CONTEXT (wmptr) = onode->decl;
+ TREE_USED (wmptr) = 1;
+ DECL_CHAIN (wmptr) = *pargs;
+ *pargs = wmptr;
+
+ if (onode->alias)
+ continue;
+
+ cgraph_node *nnode = onode;
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca)
+ {
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, cfun)
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+
+ if (!call)
+ continue;
+
+ if (gimple_alloca_call_p (call))
+ {
+ /* Capture stack growth. */
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)
+ ->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ }
+ }
+
+ pop_cfun ();
+ }
+ }
+
+ FOR_EACH_FUNCTION (onode)
+ {
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode != STRUB_INTERNAL)
+ {
+ adjust_at_calls_calls (onode);
+ continue;
+ }
+
+ bool is_stdarg = calls_builtin_va_start_p (onode);;
+ bool apply_args = calls_builtin_apply_args_p (onode);
+
+ vec<ipa_adjusted_param, va_gc> *nparms = NULL;
+ unsigned j = 0;
+ {
+ // The following loop copied from ipa-split.c:split_function.
+ for (tree parm = DECL_ARGUMENTS (onode->decl);
+ parm; parm = DECL_CHAIN (parm), j++)
+ {
+ ipa_adjusted_param adj = {};
+ adj.op = IPA_PARAM_OP_COPY;
+ adj.base_index = j;
+ adj.prev_clone_index = j;
+ vec_safe_push (nparms, adj);
+ }
+
+ if (apply_args)
+ {
+ ipa_adjusted_param aaadj = {};
+ aaadj.op = IPA_PARAM_OP_NEW;
+ aaadj.type = get_qptr ();
+ vec_safe_push (nparms, aaadj);
+ }
+
+ if (is_stdarg)
+ {
+ ipa_adjusted_param vladj = {};
+ vladj.op = IPA_PARAM_OP_NEW;
+ vladj.type = get_qpvalst ();
+ vec_safe_push (nparms, vladj);
+ }
+
+ ipa_adjusted_param wmadj = {};
+ wmadj.op = IPA_PARAM_OP_NEW;
+ wmadj.type = get_qpwmt ();
+ vec_safe_push (nparms, wmadj);
+ }
+ ipa_param_adjustments adj (nparms, -1, false);
+
+ cgraph_node *nnode = onode->create_version_clone_with_body
+ (auto_vec<cgraph_edge *> (0),
+ NULL, &adj, NULL, NULL, "strub", NULL);
+
+ if (!nnode)
+ {
+ error_at (DECL_SOURCE_LOCATION (onode->decl),
+ "failed to split %qD for %<strub%>",
+ onode->decl);
+ continue;
+ }
+
+ onode->split_part = true;
+ if (onode->calls_comdat_local)
+ nnode->add_to_same_comdat_group (onode);
+
+ gcc_checking_assert (!DECL_STRUCT_FUNCTION (nnode->decl)->stdarg);
+
+ set_strub_mode_to (onode, STRUB_WRAPPER);
+ set_strub_mode_to (nnode, STRUB_WRAPPED);
+
+ adjust_at_calls_calls (nnode);
+
+ /* Decide which of the wrapped function's parms we want to turn into
+ references to the argument passed to the wrapper. In general, we want to
+ copy small arguments, and avoid copying large ones. Variable-sized array
+ lengths given by other arguments, as in 20020210-1.c, would lead to
+ problems if passed by value, after resetting the original function and
+ dropping the length computation; passing them by reference works.
+ DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
+ anyway, but performed at the caller. */
+ indirect_parms_t indirect_nparms (3, false);
+ unsigned adjust_ftype = 0;
+ unsigned named_args = 0;
+ for (tree parm = DECL_ARGUMENTS (onode->decl),
+ nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
+ parm;
+ named_args++,
+ parm = DECL_CHAIN (parm),
+ nparm = DECL_CHAIN (nparm),
+ nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
+ if (!(0 /* DECL_BY_REFERENCE (narg) */
+ || is_gimple_reg_type (TREE_TYPE (nparm))
+ || VECTOR_TYPE_P (TREE_TYPE (nparm))
+ || TREE_CODE (TREE_TYPE (nparm)) == COMPLEX_TYPE
+ || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ && (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ <= 4 * UNITS_PER_WORD))))
+ {
+ indirect_nparms.add (nparm);
+
+ /* ??? Is there any case in which it is not safe to suggest the parms
+ turned indirect don't alias anything else? They are distinct,
+ unaliased memory in the wrapper, and the wrapped can't possibly
+ take pointers into them because none of the pointers passed to the
+ wrapper can alias other incoming parameters passed by value, even
+ if with transparent reference, and the wrapper doesn't take any
+ extra parms that could point into wrapper's parms. So we can
+ probably drop the TREE_ADDRESSABLE and keep the true. */
+ tree ref_type = build_ref_type_for (nparm,
+ true
+ || !TREE_ADDRESSABLE (parm));
+
+ DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type;
+ relayout_decl (nparm);
+ TREE_ADDRESSABLE (nparm) = 0;
+ DECL_BY_REFERENCE (nparm) = 0;
+#if FOR_GCC_11P
+ DECL_NOT_GIMPLE_REG_P (nparm) = 0;
+#else
+ DECL_GIMPLE_REG_P (nparm) = 1;
+#endif
+ /* ??? This avoids mismatches in debug info bind stmts in
+ e.g. a-chahan . */
+ DECL_ABSTRACT_ORIGIN (nparm) = NULL;
+
+ if (nparmt)
+ adjust_ftype++;
+ }
+
+ /* Also adjust the wrapped function type, if needed. */
+ if (adjust_ftype)
+ {
+ tree nftype = TREE_TYPE (nnode->decl);
+
+ /* We always add at least one argument at the end of the signature, when
+ cloning the function, so we don't expect to need to duplicate the
+ type here. */
+ gcc_checking_assert (TYPE_ARG_TYPES (nftype)
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+
+#if HAVE_ATTR_FNSPEC
+ /* Check that fnspec still works for the modified function signature,
+ and drop it otherwise. */
+ bool drop_fnspec = false;
+ tree fnspec = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (nftype));
+ attr_fnspec spec = fnspec ? attr_fnspec (fnspec) : attr_fnspec ("");
+
+ unsigned retcopy;
+ if (!(fnspec && spec.returns_arg (&retcopy)))
+ retcopy = (unsigned) -1;
+
+ unsigned i = 0;
+#endif
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (nftype);
+ adjust_ftype > 0;
+#if HAVE_ATTR_FNSPEC
+ i++,
+#endif
+ nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
+ if (indirect_nparms.contains (nparm))
+ {
+ TREE_VALUE (nparmt) = TREE_TYPE (nparm);
+ adjust_ftype--;
+
+#if HAVE_ATTR_FNSPEC
+ if (fnspec && !drop_fnspec)
+ {
+ if (i == retcopy)
+ drop_fnspec = true;
+ else if (spec.arg_specified_p (i))
+ {
+ /* Properties that apply to pointers only must not be
+ present, because we don't make pointers further
+ indirect. */
+ gcc_checking_assert
+ (!spec.arg_max_access_size_given_by_arg_p (i, NULL));
+ gcc_checking_assert (!spec.arg_copied_to_arg_p (i, NULL));
+
+ /* Any claim of direct access only is invalidated by
+ adding an indirection level. */
+ if (spec.arg_direct_p (i))
+ drop_fnspec = true;
+
+ /* If there's a claim the argument is not read from, the
+ added indirection invalidates it: if the argument is
+ used at all, then the pointer will necessarily be
+ read. */
+ if (!spec.arg_maybe_read_p (i)
+ && spec.arg_used_p (i))
+ drop_fnspec = true;
+ }
+ }
+#endif
+ }
+
+#if HAVE_ATTR_FNSPEC
+ /* ??? Maybe we could adjust it instead. */
+ if (drop_fnspec)
+ remove_named_attribute_unsharing ("fn spec",
+ &TYPE_ATTRIBUTES (nftype));
+#endif
+
+ TREE_TYPE (nnode->decl) = nftype;
+ }
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (nnode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1 + int (is_stdarg) + int (apply_args);
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ bool no_writes_p = true;
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
+ && curlen >= 2
+ && nspec[1] != 'c' && nspec[1] != 'C'
+ && nspec[1] != 'p' && nspec[1] != 'P')
+ no_writes_p = false;
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+
+ /* These extra args are unlikely to be present in const or pure
+ functions. It's conceivable that a function that takes variable
+ arguments, or that passes its arguments on to another function,
+ could be const or pure, but it would not modify the arguments, and,
+ being pure or const, it couldn't possibly modify or even access
+ memory referenced by them. But it can read from these internal
+ data structures created by the wrapper, and from any
+ argument-passing memory referenced by them, so we denote the
+ possibility of reading from multiple levels of indirection, but
+ only of reading because const/pure. */
+ if (apply_args)
+ {
+ nspec[curlen++] = 'r';
+ nspec[curlen++] = ' ';
+ }
+ if (is_stdarg)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
+ }
+ }
+#endif
+
+ {
+ tree decl = onode->decl;
+ cgraph_node *target = nnode;
+
+ { // copied from create_wrapper
+
+ /* Preserve DECL_RESULT so we get right by reference flag. */
+ tree decl_result = DECL_RESULT (decl);
+
+ /* Remove the function's body but keep arguments to be reused
+ for thunk. */
+ onode->release_body (true);
+ onode->reset ();
+
+ DECL_UNINLINABLE (decl) = false;
+ DECL_RESULT (decl) = decl_result;
+ DECL_INITIAL (decl) = NULL;
+ allocate_struct_function (decl, false);
+ set_cfun (NULL);
+
+ /* Turn alias into thunk and expand it into GIMPLE representation. */
+ onode->definition = true;
+
+#if FOR_GCC_11P
+ thunk_info::get_create (onode);
+ onode->thunk = true;
+#else
+ memset (&onode->thunk, 0, sizeof (cgraph_thunk_info));
+ onode->thunk.thunk_p = true;
+ onode->thunk.alias = target->decl;
+#endif
+#if !IMPLICIT_CGRAPH_EDGES
+ onode->create_edge (target, NULL, onode->count);
+#endif
+ onode->callees->can_throw_external = !TREE_NOTHROW (target->decl);
+
+ tree arguments = DECL_ARGUMENTS (decl);
+
+ while (arguments)
+ {
+ TREE_ADDRESSABLE (arguments) = false;
+ arguments = TREE_CHAIN (arguments);
+ }
+
+ {
+ tree alias = onode->callees->callee->decl;
+ tree thunk_fndecl = decl;
+ tree a;
+
+ int nxargs = 1 + is_stdarg + apply_args;
+
+ { // Simplified from expand_thunk.
+ tree restype;
+ basic_block bb, then_bb, else_bb, return_bb;
+ gimple_stmt_iterator bsi;
+ int nargs = 0;
+ tree arg;
+ int i;
+ tree resdecl;
+ tree restmp = NULL;
+
+ gcall *call;
+ greturn *ret;
+ bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
+
+ a = DECL_ARGUMENTS (thunk_fndecl);
+
+ current_function_decl = thunk_fndecl;
+
+#if FOR_GCC_11P
+ /* Ensure thunks are emitted in their correct sections. */
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
+#endif
+
+ bitmap_obstack_initialize (NULL);
+
+ /* Build the return declaration for the function. */
+ restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
+ if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
+ {
+ resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = thunk_fndecl;
+ DECL_RESULT (thunk_fndecl) = resdecl;
+ }
+ else
+ resdecl = DECL_RESULT (thunk_fndecl);
+
+ profile_count cfg_count = onode->count;
+ if (!cfg_count.initialized_p ())
+ cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
+
+ bb = then_bb = else_bb = return_bb
+ = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
+
+ bsi = gsi_start_bb (bb);
+
+ /* Build call to the function being thunked. */
+ if (!VOID_TYPE_P (restype)
+ && (!alias_is_noreturn
+ || TREE_ADDRESSABLE (restype)
+ || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
+ {
+ if (DECL_BY_REFERENCE (resdecl))
+ {
+ restmp = gimple_fold_indirect_ref (resdecl);
+ if (!restmp)
+ restmp = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (resdecl)),
+ resdecl,
+ build_int_cst (TREE_TYPE (resdecl), 0));
+ }
+ else if (!is_gimple_reg_type (restype))
+ {
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+ {
+ restmp = resdecl;
+
+ if (VAR_P (restmp))
+ {
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl))
+ = restmp;
+ }
+ }
+ else
+ restmp = create_tmp_var (restype, "retval");
+ }
+ else
+ restmp = create_tmp_reg (restype, "retval");
+ }
+
+ for (arg = a; arg; arg = DECL_CHAIN (arg))
+ nargs++;
+ auto_vec<tree> vargs (nargs + nxargs);
+ i = 0;
+ arg = a;
+
+ if (nargs)
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl);
+ i < nargs;
+ i++, arg = DECL_CHAIN (arg), nparm = DECL_CHAIN (nparm))
+ {
+ tree save_arg = arg;
+ tree tmp = arg;
+
+ /* Arrange to pass indirectly the parms, if we decided to do
+ so, and revert its type in the wrapper. */
+ if (indirect_nparms.contains (nparm))
+ {
+ tree ref_type = TREE_TYPE (nparm);
+ TREE_ADDRESSABLE (arg) = true;
+ tree addr = build1 (ADDR_EXPR, ref_type, arg);
+ tmp = arg = addr;
+ }
+#if ! FOR_GCC_11P
+ else if (VECTOR_TYPE_P (TREE_TYPE (arg))
+ || TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ DECL_GIMPLE_REG_P (arg) = 1;
+#else
+ else
+ DECL_NOT_GIMPLE_REG_P (arg) = 0;
+#endif
+
+ /* Convert the argument back to the type used by the calling
+ conventions, e.g. a non-prototyped float type is passed as
+ double, as in 930603-1.c, and needs to be converted back to
+ double to be passed on unchanged to the wrapped
+ function. */
+ if (TREE_TYPE (nparm) != DECL_ARG_TYPE (nparm))
+ arg = fold_convert (DECL_ARG_TYPE (nparm), arg);
+
+ if (!is_gimple_val (arg))
+ {
+ tmp = create_tmp_reg (TYPE_MAIN_VARIANT
+ (TREE_TYPE (arg)), "arg");
+ gimple *stmt = gimple_build_assign (tmp, arg);
+ gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
+ }
+ vargs.quick_push (tmp);
+ arg = save_arg;
+ }
+ /* These strub arguments are adjusted later. */
+ if (apply_args)
+ vargs.quick_push (null_pointer_node);
+ if (is_stdarg)
+ vargs.quick_push (null_pointer_node);
+ vargs.quick_push (null_pointer_node);
+ call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias),
+ vargs);
+ onode->callees->call_stmt = call;
+ // gimple_call_set_from_thunk (call, true);
+ if (DECL_STATIC_CHAIN (alias))
+ {
+ tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
+ tree type = TREE_TYPE (p);
+ tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ PARM_DECL, create_tmp_var_name ("CHAIN"),
+ type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_CONTEXT (decl) = thunk_fndecl;
+ DECL_ARG_TYPE (decl) = type;
+ TREE_READONLY (decl) = 1;
+
+ struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
+ sf->static_chain_decl = decl;
+
+ gimple_call_set_chain (call, decl);
+ }
+
+ /* Return slot optimization is always possible and in fact required to
+ return values with DECL_BY_REFERENCE. */
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+ && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+ || DECL_BY_REFERENCE (resdecl)))
+ gimple_call_set_return_slot_opt (call, true);
+
+ if (restmp)
+ {
+ gimple_call_set_lhs (call, restmp);
+ gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
+ TREE_TYPE (TREE_TYPE (alias))));
+ }
+ gsi_insert_after (&bsi, call, GSI_NEW_STMT);
+ if (!alias_is_noreturn)
+ {
+ /* Build return value. */
+ if (!DECL_BY_REFERENCE (resdecl))
+ ret = gimple_build_return (restmp);
+ else
+ ret = gimple_build_return (resdecl);
+
+ gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
+ }
+ else
+ {
+ remove_edge (single_succ_edge (bb));
+ }
+
+ cfun->gimple_df->in_ssa_p = true;
+ update_max_bb_count ();
+ profile_status_for_fn (cfun)
+ = cfg_count.initialized_p () && cfg_count.ipa_p ()
+ ? PROFILE_READ : PROFILE_GUESSED;
+#if FOR_GCC_11P
+ /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
+ // TREE_ASM_WRITTEN (thunk_fndecl) = false;
+#endif
+ delete_unreachable_blocks ();
+ update_ssa (TODO_update_ssa);
+ checking_verify_flow_info ();
+ free_dominance_info (CDI_DOMINATORS);
+
+ /* Since we want to emit the thunk, we explicitly mark its name as
+ referenced. */
+#if FOR_GCC_11P
+ onode->thunk = false;
+#else
+ onode->thunk.thunk_p = false;
+#endif
+ onode->lowered = true;
+ bitmap_obstack_release (NULL);
+ }
+ current_function_decl = NULL;
+ set_cfun (NULL);
+ }
+
+#if FOR_GCC_11P
+ thunk_info::remove (onode);
+#endif
+
+ // some more of create_wrapper at the end of the next block.
+ }
+ }
+
+ {
+ tree aaval = NULL_TREE;
+ tree vaptr = NULL_TREE;
+ tree wmptr = NULL_TREE;
+ for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg))
+ {
+ aaval = vaptr;
+ vaptr = wmptr;
+ wmptr = arg;
+ }
+
+ if (!apply_args)
+ aaval = NULL_TREE;
+ /* The trailing args are [apply_args], [va_list_ptr], and
+ watermark. If we don't have a va_list_ptr, the penultimate
+ argument is apply_args.
+ */
+ else if (!is_stdarg)
+ aaval = vaptr;
+
+ if (!is_stdarg)
+ vaptr = NULL_TREE;
+
+ DECL_NAME (wmptr) = get_watermark_ptr ();
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_IGNORED_P (wmptr) = 1;
+ TREE_USED (wmptr) = 1;
+
+ if (is_stdarg)
+ {
+ DECL_NAME (vaptr) = get_va_list_ptr ();
+ DECL_ARTIFICIAL (vaptr) = 1;
+ DECL_IGNORED_P (vaptr) = 1;
+ TREE_USED (vaptr) = 1;
+ }
+
+ if (apply_args)
+ {
+ DECL_NAME (aaval) = get_apply_args ();
+ DECL_ARTIFICIAL (aaval) = 1;
+ DECL_IGNORED_P (aaval) = 1;
+ TREE_USED (aaval) = 1;
+ }
+
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ bool any_indirect = !indirect_nparms.is_empty ();
+
+ if (any_indirect)
+ {
+ basic_block bb;
+ bool needs_commit = false;
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
+ !gsi_end_p (gsi);
+ gsi_next_nonvirtual_phi (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed && !is_gimple_debug (gsi_stmt (gsi)))
+ if (walk_regimplify_phi (stmt))
+ needs_commit = true;
+ }
+
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed)
+ {
+ if (!is_gimple_debug (stmt))
+ {
+ wi.info = &gsi;
+ walk_gimple_op (stmt, walk_regimplify_addr_expr,
+ &wi);
+ }
+ update_stmt (stmt);
+ }
+ }
+ }
+ if (needs_commit)
+ gsi_commit_edge_inserts ();
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca
+ || is_stdarg || apply_args)
+ for (cgraph_edge *e = nnode->callees, *enext; e; e = enext)
+ {
+ gcall *call = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (call);
+ tree fndecl = e->callee->decl;
+
+ enext = e->next_callee;
+
+ if (gimple_alloca_call_p (call))
+ {
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ else if (fndecl && is_stdarg
+ && fndecl_built_in_p (fndecl, BUILT_IN_VA_START))
+ {
+ /* Using a non-default stdarg ABI makes the function ineligible
+ for internal strub. */
+ gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START)
+ == fndecl);
+ tree bvacopy = builtin_decl_explicit (BUILT_IN_VA_COPY);
+ gimple_call_set_fndecl (call, bvacopy);
+ tree arg = vaptr;
+ /* The va_copy source must be dereferenced, unless it's an array
+ type, that would have decayed to a pointer. */
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (vaptr))) != ARRAY_TYPE)
+ {
+ arg = gimple_fold_indirect_ref (vaptr);
+ if (!arg)
+ arg = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (vaptr)),
+ vaptr,
+ build_int_cst (TREE_TYPE (vaptr), 0));
+ }
+ gimple_call_set_arg (call, 1, arg);
+ update_stmt (call);
+ e->redirect_callee (cgraph_node::get_create (bvacopy));
+ }
+ else if (fndecl && apply_args
+ && fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
+ {
+ tree lhs = gimple_call_lhs (call);
+ gimple *assign = (lhs
+ ? gimple_build_assign (lhs, aaval)
+ : gimple_build_nop ());
+ gsi_replace (&gsi, assign, true);
+ cgraph_edge::remove (e);
+ }
+ }
+
+ { // a little more copied from create_wrapper
+
+ /* Inline summary set-up. */
+ nnode->analyze ();
+ // inline_analyze_function (nnode);
+ }
+
+ pop_cfun ();
+ }
+
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (onode->decl));
+ gimple_stmt_iterator gsi
+ = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+
+ gcall *wrcall;
+ while (!(wrcall = dyn_cast <gcall *> (gsi_stmt (gsi))))
+ gsi_next (&gsi);
+
+ tree swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1, unshare_expr (swmp));
+ gimple_set_location (stptr, gimple_location (wrcall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+#if !IMPLICIT_CGRAPH_EDGES
+ onode->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+#endif
+
+ int nargs = gimple_call_num_args (wrcall);
+
+ gimple_seq seq = NULL;
+
+ if (apply_args)
+ {
+ tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args");
+ tree bappargs = builtin_decl_explicit (BUILT_IN_APPLY_ARGS);
+ gcall *appargs = gimple_build_call (bappargs, 0);
+ gimple_call_set_lhs (appargs, aalst);
+ gimple_set_location (appargs, gimple_location (wrcall));
+ gsi_insert_before (&gsi, appargs, GSI_SAME_STMT);
+ gimple_call_set_arg (wrcall, nargs - 2 - is_stdarg, aalst);
+#if !IMPLICIT_CGRAPH_EDGES
+ onode->create_edge (cgraph_node::get_create (bappargs),
+ appargs, gsi_bb (gsi)->count, false);
+#endif
+ }
+
+ if (is_stdarg)
+ {
+ tree valst = create_tmp_var (va_list_type_node, ".strub.va_list");
+ TREE_ADDRESSABLE (valst) = true;
+ tree vaptr = build1 (ADDR_EXPR,
+ build_pointer_type (va_list_type_node),
+ valst);
+ gimple_call_set_arg (wrcall, nargs - 2, unshare_expr (vaptr));
+
+ tree bvastart = builtin_decl_explicit (BUILT_IN_VA_START);
+ gcall *vastart = gimple_build_call (bvastart, 2,
+ unshare_expr (vaptr),
+ integer_zero_node);
+ gimple_set_location (vastart, gimple_location (wrcall));
+ gsi_insert_before (&gsi, vastart, GSI_SAME_STMT);
+#if !IMPLICIT_CGRAPH_EDGES
+ onode->create_edge (cgraph_node::get_create (bvastart),
+ vastart, gsi_bb (gsi)->count, false);
+#endif
+
+ tree bvaend = builtin_decl_explicit (BUILT_IN_VA_END);
+ gcall *vaend = gimple_build_call (bvaend, 1, unshare_expr (vaptr));
+ gimple_set_location (vaend, gimple_location (wrcall));
+ gimple_seq_add_stmt (&seq, vaend);
+ }
+
+ gimple_call_set_arg (wrcall, nargs - 1, unshare_expr (swmp));
+ // gimple_call_set_tail (wrcall, false);
+ update_stmt (wrcall);
+
+ {
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+
+ /* For nnode, we don't rebuild edges because we wish to retain
+ any redirections copied to it from earlier passes, so we add
+ call graph edges explicitly there, but for onode, we create a
+ fresh function, so we may as well just issue the calls and
+ then rebuild all cgraph edges. */
+ // cgraph_edge::rebuild_edges ();
+ onode->analyze ();
+ // inline_analyze_function (onode);
+
+ pop_cfun ();
+ }
+ }
+
+ return 0;
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub (gcc::context *ctxt)
+{
+ return new pass_ipa_strub (ctxt);
+}
diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h
new file mode 100644
index 0000000000000..5c0b266c3f81b
--- /dev/null
+++ b/gcc/ipa-strub.h
@@ -0,0 +1,45 @@
+/* strub (stack scrubbing) infrastructure.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Return TRUE if CALLEE can be inlined into CALLER, as far as stack scrubbing
+ constraints are concerned. CALLEE doesn't have to be called directly by
+ CALLER, but the returned value says nothing about intervening functions. */
+extern bool strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller);
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+extern bool strub_splittable_p (cgraph_node *node);
+
+/* Locate and return the watermark_ptr parameter for FNDECL. If FNDECL is not a
+ strub context, return NULL. */
+extern tree strub_watermark_parm (tree fndecl);
+
+/* Make a function type or declaration callable. */
+extern void strub_make_callable (tree fndecl);
+
+/* Return zero iff ID is NOT an acceptable parameter for a user-supplied strub
+ attribute for a function. Otherwise, return >0 if it enables strub, <0 if it
+ does not. Return +/-1 if the attribute-modified type is compatible with the
+ type without the attribute, or +/-2 if it is not compatible. */
+extern int strub_validate_fn_attr_parm (tree id);
+
+/* Like comptypes, return 0 if t1 and t2 are not compatible, 1 if they are
+ compatible, and 2 if they are nearly compatible. Same strub mode is
+ compatible, interface-compatible strub modes are nearly compatible. */
+extern int strub_comptypes (tree t1, tree t2);
diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c
index 28d5f95dca52b..07cdb66e337bd 100644
--- a/gcc/multiple_target.c
+++ b/gcc/multiple_target.c
@@ -557,7 +557,7 @@ public:
bool
pass_target_clone::gate (function *)
{
- return true;
+ return !seen_error ();
}
} // anon namespace
diff --git a/gcc/passes.def b/gcc/passes.def
index d7a1f8c97a676..8e4638d20edac 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
INSERT_PASSES_AFTER (all_small_ipa_passes)
NEXT_PASS (pass_ipa_free_lang_data);
NEXT_PASS (pass_ipa_function_and_variable_visibility);
+ NEXT_PASS (pass_ipa_strub_mode);
NEXT_PASS (pass_build_ssa_passes);
PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
NEXT_PASS (pass_fixup_cfg);
@@ -111,6 +112,7 @@ along with GCC; see the file COPYING3. If not see
POP_INSERT_PASSES ()
NEXT_PASS (pass_ipa_remove_symbols);
+ NEXT_PASS (pass_ipa_strub);
NEXT_PASS (pass_ipa_oacc);
PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc)
NEXT_PASS (pass_ipa_pta);
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
new file mode 100644
index 0000000000000..c7a79a6ea0d8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O0, none of the strub builtins are expanded inline. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
new file mode 100644
index 0000000000000..96285c975d98e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O1, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
new file mode 100644
index 0000000000000..8edc0d8aa1321
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O2, without -fno-inline, we fully expand enter and update, and add a test
+ around the leave call. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
new file mode 100644
index 0000000000000..c6d900cf3c45b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
new file mode 100644
index 0000000000000..33ee465e51cb6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
new file mode 100644
index 0000000000000..2936f82079e18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
new file mode 100644
index 0000000000000..479746e57d87e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Og, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
new file mode 100644
index 0000000000000..2241d4ea07f27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Os, without -fno-inline, we fully expand enter, and also update. The
+ expanded update might be larger than a call proper, but argument saving and
+ restoring required by the call will most often make it larger. The leave
+ call is left untouched. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
new file mode 100644
index 0000000000000..a322bcc5da606
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
new file mode 100644
index 0000000000000..db60026d0e080
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
+ is set for static non-inline functions when not optimizing, and that keeps
+ only_called_directly_p from returning true, which makes STRUB_AT_CALLS
+ non-viable. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
new file mode 100644
index 0000000000000..2f462adc1efe0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__ ("callable")))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0);
+}
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ void *args = __builtin_apply_args ();
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
new file mode 100644
index 0000000000000..a5d7551f5da5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+extern void __attribute__ ((__strub__))
+apply_function (void *args);
+
+void __attribute__ ((__strub__))
+apply_args (int i, int j, double d) /* { dg-error "selected" } */
+{
+ void *args = __builtin_apply_args (); /* { dg-message "does not support" } */
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
new file mode 100644
index 0000000000000..64422a0d1e880
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0); /* { dg-error "in .strub. context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
new file mode 100644
index 0000000000000..15ffaa031b899
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+
+/* Check that implicit enabling of strub mode selects internal strub when the
+ function uses __builtin_apply_args, that prevents the optimization to
+ at-calls mode. */
+
+int __attribute__ ((__strub__)) var;
+
+static inline void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+void f() {
+ apply_args (1, 2, 3);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
new file mode 100644
index 0000000000000..b70843b4215a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
new file mode 100644
index 0000000000000..97a3988a6b922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
+ force_output is set for static non-inline functions when not optimizing, and
+ that keeps only_called_directly_p from returning true, which makes
+ STRUB_AT_CALLS non-viable. It becomes STRUB_CALLABLE instead. */
+static void
+g() {
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
new file mode 100644
index 0000000000000..3d73431b3dcd3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O1" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O1. */
+
+#include "strub-defer-O2.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
new file mode 100644
index 0000000000000..fddf3c745e7e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O2" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O2. */
+
+#define EXPECT_DEFERRAL !
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
new file mode 100644
index 0000000000000..2bc384ee8d1e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -0,0 +1,93 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O3" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -O3. */
+
+#ifndef EXPECT_DEFERRAL
+# define EXPECT_DEFERRAL
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[sizeof (test_string)];
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char*)__builtin_stack_address ();
+
+ f (s);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+int
+look_for_string (char *e)
+{
+ char *p = (char*)__builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__strub__ ("at-calls"), __noinline__, __noclone__))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+deferred_at_calls ()
+{
+ char *ret = at_calls ();
+ if (EXPECT_DEFERRAL !look_for_string (ret))
+ __builtin_abort ();
+ return ret;
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+deferred_internal ()
+{
+ char *ret = at_calls ();
+ if (EXPECT_DEFERRAL !look_for_string (ret))
+ __builtin_abort ();
+ return ret;
+}
+
+int main ()
+{
+ if (look_for_string (deferred_at_calls ()))
+ __builtin_abort ();
+ if (look_for_string (deferred_internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
new file mode 100644
index 0000000000000..fbaf85fe0fafe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -Os" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -Os. */
+
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
new file mode 100644
index 0000000000000..e9d7b7b9ee0a8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
new file mode 100644
index 0000000000000..8b8e15a51c71c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
new file mode 100644
index 0000000000000..0a4a7539d3489
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("internal")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("internal")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
new file mode 100644
index 0000000000000..147171d96d5a1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("at-calls")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("at-calls")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]* \[(\]struct large_arg la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("at-calls")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]* \[(\]int i, void \\* &\[^&,\]*.strub.watermark_ptr\[, .]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-not "va_copy \\(" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
new file mode 100644
index 0000000000000..4e92682895a43
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that uses of a strub variable implicitly enables internal strub for
+ publicly-visible functions, and causes the same transformations to their
+ signatures as those in strub-parms1.c. */
+
+#include <stdarg.h>
+
+int __attribute__ ((__strub__)) var;
+
+void
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void
+large_byref_arg (struct large_arg la)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ var++;
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
new file mode 100644
index 0000000000000..e2f9d8aebca58
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. Without the error,
+ inlining takes place. */
+
+#include "strub-strict1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
new file mode 100644
index 0000000000000..98474435d2e59
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. */
+
+#include "strub-strict2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
new file mode 100644
index 0000000000000..1de15342595e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 89 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
new file mode 100644
index 0000000000000..f9209c819004b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
new file mode 100644
index 0000000000000..bed1dcfb54a45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
new file mode 100644
index 0000000000000..6bf0071f52b93
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
new file mode 100644
index 0000000000000..4732f515bf70c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
new file mode 100644
index 0000000000000..8d6424c479a3a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
new file mode 100644
index 0000000000000..368522442066e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* h becomes STRUB_INLINABLE, because of the use of the strub variable,
+ and the always_inline flag. It would get inlined before pass_ipa_strub, if
+ it weren't for the error. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+ var++;
+}
+
+/* g becomes STRUB_AT_CALLS_OPT, because of the use of the strub variable, and
+ the viability of at-calls strubbing. Though internally a strub context, its
+ interface is not strub-enabled, so it's not callable from within strub
+ contexts. */
+static inline void
+g() {
+ var--;
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
new file mode 100644
index 0000000000000..b4f2888321821
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* g becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. It's not STRUB_AT_CALLS_OPT
+ because force_output is set for static non-inline functions when not
+ optimizing, and that keeps only_called_directly_p from returning true, which
+ makes STRUB_AT_CALLS[_OPT] non-viable. */
+static void
+g() {
+ var--;
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
new file mode 100644
index 0000000000000..e48e0610e079b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+#include "strub-tail-O2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
new file mode 100644
index 0000000000000..87cda7ab21b16
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued.
+ Tail calls are short-circuited at -O2+. */
+
+int __attribute__ ((__strub__))
+g (int i, int j) {
+ return g (i, j);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 0 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 0 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
new file mode 100644
index 0000000000000..b5e45ab0525ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that strub and non-strub functions can be called from non-strub
+ contexts, and that strub and callable functions can be called from strub
+ contexts. */
+
+#define OMIT_IMPERMISSIBLE_CALLS 1
+#include "strub-callable2.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
new file mode 100644
index 0000000000000..96aa7fe4b07f7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -0,0 +1,264 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that impermissible (cross-strub-context) calls are reported. */
+
+extern int __attribute__ ((__strub__ ("callable"))) xcallable (void);
+extern int __attribute__ ((__strub__ ("internal"))) xinternal (void);
+extern int __attribute__ ((__strub__ ("at-calls"))) xat_calls (void);
+extern int __attribute__ ((__strub__ ("disabled"))) xdisabled (void);
+
+int __attribute__ ((__strub__ ("callable"))) callable (void);
+int __attribute__ ((__strub__ ("internal"))) internal (void);
+int __attribute__ ((__strub__ ("at-calls"))) at_calls (void);
+int __attribute__ ((__strub__ ("disabled"))) disabled (void);
+
+int __attribute__ ((__strub__)) var;
+int var_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+icallable (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+iinternal (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+idisabled (void);
+static inline int __attribute__ ((__always_inline__))
+ivar_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+i_callable (void) { return 0; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+i_internal (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+i_at_calls (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+i_disabled (void) { return 0; }
+static inline int __attribute__ ((__always_inline__))
+i_var_user (void) { return var; }
+
+#define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## at_calls (); \
+ ret += i ## ISEP ## internal (); \
+ ret += i ## ISEP ## var_user (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \
+ do { \
+ ret += internal (); \
+ ret += disabled (); \
+ ret += var_user (); \
+ \
+ ret += i ## ISEP ## disabled (); \
+ \
+ ret += xinternal (); \
+ ret += xdisabled (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## callable (); \
+ \
+ ret += callable (); \
+ ret += at_calls (); \
+ \
+ ret += xat_calls (); \
+ ret += xcallable (); \
+ } while (0)
+
+/* Not a strub context, so it can call anything.
+ Explicitly declared as callable even from within strub contexts. */
+int __attribute__ ((__strub__ ("callable")))
+callable (void) {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+/* Internal strubbing means the body is a strub context, so it can only call
+ strub functions, and it's not itself callable from strub functions. */
+int __attribute__ ((__strub__ ("internal")))
+internal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("at-calls")))
+at_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+disabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+int
+var_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+icallable (void)
+{
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+iinternal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+idisabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+ivar_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
new file mode 100644
index 0000000000000..2857195706ed6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const function call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __const__))
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
new file mode 100644
index 0000000000000..98a92bc9eac2b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const function call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
new file mode 100644
index 0000000000000..5511a6e1e71d3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __const__))
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
new file mode 100644
index 0000000000000..47ee927964dff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const wrapping call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
new file mode 100644
index 0000000000000..7c27a2a1a6dca
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointed-to data enables strubbing if accessed. */
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
new file mode 100644
index 0000000000000..e66d903780afd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, enabling internal strubbing when
+ its value is used. */
+int __attribute__ ((__strub__)) *ptr;
+
+int *f() {
+ return ptr;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
new file mode 100644
index 0000000000000..5e08e0e58c658
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) var;
+
+void f() {
+ var = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
new file mode 100644
index 0000000000000..a818e7a38bb5f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) *ptr;
+
+void f() {
+ ptr = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
new file mode 100644
index 0000000000000..ddb0b5c0543b0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* It would be desirable to issue at least warnings for these. */
+
+typedef int __attribute__ ((__strub__)) strub_int;
+strub_int *ptr;
+
+int *f () {
+ return ptr; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+strub_int *g () {
+ return f (); /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
new file mode 100644
index 0000000000000..c165f312f16de
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype ();
+fntype (*ptr);
+
+void f() {
+ ptr ();
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(&\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
new file mode 100644
index 0000000000000..69fcff8d3763d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
new file mode 100644
index 0000000000000..ff006224909bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0, 1, 1);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+, 1, 1)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
new file mode 100644
index 0000000000000..614b02228ba29
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+inline void __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+}
+
+void
+bat (void)
+{
+ /* Not allowed, not a strub context. */
+ inl_int_ali (); /* { dg-error "context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
new file mode 100644
index 0000000000000..f9a6b4a16faf8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all" } */
+
+#include "strub-inlinable1.c"
+
+/* With -fstrub=all, the caller becomes a strub context, so the strub-inlinable
+ callee is not rejected. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
new file mode 100644
index 0000000000000..b4a7f3992bbaa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+typedef void ft (void);
+typedef void ft2 (int, int);
+extern ft __attribute__ ((__strub__)) fnac;
+
+ft * f (void) {
+ return fnac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
new file mode 100644
index 0000000000000..d9d2c0caec42d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+
+/* C++ does not warn about the partial incompatibilities.
+
+ The d_p () calls are actually rejected, even in C++, but they are XFAILed
+ here because we don't get far enough in the compilation as to observe them,
+ because the incompatibilities are errors without -fpermissive.
+ strub-ptrfn3.c uses -fpermissive to check those.
+ */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
new file mode 100644
index 0000000000000..e1f179e160e5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
+/* { dg-prune-output "command-line option .-fpermissive." } */
+
+/* See strub-ptrfn2.c. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
new file mode 100644
index 0000000000000..70b558afad040
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+/* This is strub-ptrfn2.c without -Wpedantic.
+
+ Even C doesn't report the (not-quite-)compatible conversions without it. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
new file mode 100644
index 0000000000000..a262a086837b2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure function call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
new file mode 100644
index 0000000000000..4c4bd50c209a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure function call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
new file mode 100644
index 0000000000000..ce195c6b1f1b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
new file mode 100644
index 0000000000000..75cd54ccb5b5d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
new file mode 100644
index 0000000000000..c596066a045eb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -0,0 +1,85 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[sizeof (test_string)];
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char *) __builtin_stack_address ();
+
+ f (s);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ if (!look_for_string (callable ()))
+ __builtin_abort ();
+ if (look_for_string (at_calls ()))
+ __builtin_abort ();
+ if (look_for_string (internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
new file mode 100644
index 0000000000000..1fdba214a07f9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -0,0 +1,75 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ asm ("" : "+rm" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ if (!look_for_string (callable ()))
+ __builtin_abort ();
+ if (look_for_string (at_calls ()))
+ __builtin_abort ();
+ if (look_for_string (internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
new file mode 100644
index 0000000000000..afbc2cc9ab484
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -0,0 +1,75 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ char *s = (char *) __builtin_alloca (len);
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ if (!look_for_string (callable ()))
+ __builtin_abort ();
+ if (look_for_string (at_calls ()))
+ __builtin_abort ();
+ if (look_for_string (internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
new file mode 100644
index 0000000000000..5300f1d330b87
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -0,0 +1,101 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that multi-level, multi-inlined functions still get cleaned up as
+ expected, without overwriting temporary stack allocations while they should
+ still be available. */
+
+#ifndef ATTR_STRUB_AT_CALLS
+# define ATTR_STRUB_AT_CALLS /* Defined in strub-run4d.c. */
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__))
+char *
+leak_string (void)
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+innermost ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = leak_string ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+intermediate ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = innermost ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return intermediate ();
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+main ()
+{
+ if (look_for_string (internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
new file mode 100644
index 0000000000000..57f9baf758ded
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=at-calls" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
new file mode 100644
index 0000000000000..08de3f1c3b17c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+#define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
new file mode 100644
index 0000000000000..459f6886c5499
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=internal" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
new file mode 100644
index 0000000000000..0d367fb83d09d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -0,0 +1,19 @@
+// { dg-do run }
+// { dg-options "-fstrub=internal" }
+
+// Check that we don't get extra copies.
+
+struct T {
+ T &self;
+ void check () const { if (&self != this) __builtin_abort (); }
+ T() : self (*this) { check (); }
+ T(const T& ck) : self (*this) { ck.check (); check (); }
+ ~T() { check (); }
+};
+
+T foo (T q) { q.check (); return T(); }
+T bar (T p) { p.check (); return foo (p); }
+
+int main () {
+ bar (T()).check ();
+}
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
new file mode 100644
index 0000000000000..c226ab10ff651
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ static int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
new file mode 100644
index 0000000000000..a7911f1fa7212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+static int x = initializer ();
+
+int f() {
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
new file mode 100644
index 0000000000000..6ebebcd01e8ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
new file mode 100644
index 0000000000000..10445d7cf8451
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -0,0 +1,37 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+
+package body Strub_Attr is
+ E : exception;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (F (X));
+ -- function G return Integer is (FP (X));
+ -- Calling G would likely raise an exception, because although FP
+ -- carries the strub at-calls attribute needed to call F, the
+ -- attribute is dropped from the type used for the call proper.
+end Strub_Attr;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 2 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 0 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark_ptr" 6 "strub" } }
+-- We have 1 at-calls subprogram (F) and 2 wrapped (P and G).
+-- For each of them, there's one match for the wrapped signature,
+-- and one for the update call.
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark" 27 "strub" } }
+-- The 6 matches above, plus:
+-- 5*2: wm var decl, enter, call, leave and clobber for each wrapper;
+-- 2*1: an extra leave and clobber for the exception paths in the wrappers.
+-- 7*1: for the F call in G, including EH path.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.ads b/gcc/testsuite/gnat.dg/strub_attr.ads
new file mode 100644
index 0000000000000..a94c23bf41833
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.ads
@@ -0,0 +1,12 @@
+package Strub_Attr is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function G return Integer;
+end Strub_Attr;
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
new file mode 100644
index 0000000000000..d08341a23b351
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -0,0 +1,44 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but applying attributes to access types as well.
+-- That doesn't quite work yet, so we get an error we shouldn't get.
+
+package body Strub_Ind is
+ E : exception;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (FP (X)); -- { dg-bogus "non-.strub." "" { xfail *-*-* } }
+ -- Calling G would likely raise an exception, because although FP
+ -- carries the strub at-calls attribute needed to call F, the
+ -- attribute is dropped from the type used for the call proper.
+
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "at-calls");
+ -- The pragma above seems to have no effect.
+
+ GP : GT := G'Access; -- { dg-warning "incompatible" "" { xfail *-*-* } }
+ pragma Machine_Attribute (GP, "strub", "at-calls");
+ -- The pragma above does modify GP's type,
+ -- but dereferencing it uses an unmodified copy of the type.
+ -- The initializer should be diagnosed:
+ -- GT should only reference functions with at-calls strub.
+
+end Strub_Ind;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 2 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 0 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
+
+-- No "strub" dump checking because of the bogus error above.
diff --git a/gcc/testsuite/gnat.dg/strub_ind.ads b/gcc/testsuite/gnat.dg/strub_ind.ads
new file mode 100644
index 0000000000000..53dede60eacdd
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.ads
@@ -0,0 +1,23 @@
+package Strub_Ind is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function G return Integer;
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+ -- The pragma above seems to get discarded in GNAT; Gigi doesn't see it.
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+ -- The pragma above does modify FP's type,
+ -- but a call with it gets it converted to its Ada type,
+ -- that is cached by the translator as the unmodified type.
+
+end Strub_Ind;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 61b53913e0b30..9b01f2bb01ba7 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -5620,6 +5620,7 @@ gimple_verify_flow_info (void)
{
gimple *stmt = gsi_stmt (gsi);
+ /* Do NOT disregard debug stmts after found_ctrl_stmt. */
if (found_ctrl_stmt)
{
error ("control flow in the middle of basic block %d",
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 83941bc0ceef0..df4abdf144928 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -497,8 +497,9 @@ extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
-extern simple_ipa_opt_pass
- *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tree_profile (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_auto_profile (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 70ce6a4d5b8d1..dca5233cc7bb6 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -3050,7 +3050,9 @@ optimize_stack_restore (gimple_stmt_iterator i)
if (!callee
|| !fndecl_built_in_p (callee, BUILT_IN_NORMAL)
/* All regular builtins are ok, just obviously not alloca. */
- || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)))
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
+ /* Do not remove stack updates before strub leave. */
+ || fndecl_built_in_p (callee, BUILT_IN___STRUB_LEAVE))
return NULL_TREE;
if (fndecl_built_in_p (callee, BUILT_IN_STACK_RESTORE))
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 7ec9758455445..c4ee6701cb33b 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -428,7 +428,7 @@ ifneq ($(enable_shared),yes)
iterator = $(patsubst %,$(srcdir)/static-object.mk,$(iter-items))
endif
-LIB2ADD += enable-execute-stack.c
+LIB2ADD += enable-execute-stack.c $(srcdir)/strub.c
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
# instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h
index 1819ff3ac3d03..857091e65c82b 100644
--- a/libgcc/libgcc2.h
+++ b/libgcc/libgcc2.h
@@ -532,6 +532,10 @@ extern int __parityDI2 (UDWtype);
extern void __enable_execute_stack (void *);
+extern void __strub_enter (void **);
+extern void __strub_update (void**);
+extern void __strub_leave (void **);
+
#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
#endif
diff --git a/libgcc/strub.c b/libgcc/strub.c
new file mode 100644
index 0000000000000..7c58deee1e602
--- /dev/null
+++ b/libgcc/strub.c
@@ -0,0 +1,112 @@
+/* Stack scrubbing infrastructure
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+#include "libgcc2.h"
+
+#ifndef STACK_GROWS_DOWNWARD
+# define TOPS >
+#else
+# define TOPS <
+#endif
+
+#define ATTRIBUTE_STRUB_CALLABLE __attribute__ ((__strub__ ("callable")))
+
+/* Enter a stack scrubbing context, initializing the watermark to the caller's
+ stack address. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_enter (void **watermark)
+{
+ *watermark = __builtin_frame_address (0);
+}
+
+/* Update the watermark within a stack scrubbing context with the current stack
+ pointer. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_update (void **watermark)
+{
+ void *sp = __builtin_frame_address (0);
+
+ if (sp TOPS *watermark)
+ *watermark = sp;
+}
+
+#ifndef TARGET_STRUB_USE_DYNAMIC_ARRAY
+# define TARGET_STRUB_DONT_USE_DYNAMIC_ARRAY 1
+#endif
+
+#ifndef TARGET_STRUB_DONT_USE_DYNAMIC_ARRAY
+# ifdef TARGET_STRUB_MAY_USE_MEMSET
+# define TARGET_STRUB_DONT_USE_DYNAMIC_ARRAY 1
+# else
+# define TARGET_STRUB_MAY_USE_MEMSET 1
+# endif
+#endif
+
+/* Leave a stack scrubbing context, restoring and updating SAVED, and
+ clearing the stack between top and watermark. */
+void ATTRIBUTE_STRUB_CALLABLE
+#if ! TARGET_STRUB_MAY_USE_MEMSET
+__attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
+#endif
+__strub_leave (void **mark)
+{
+ void *sp = __builtin_stack_address ();
+
+ void **base, **end;
+#ifndef STACK_GROWS_DOWNWARD
+ base = sp;
+ end = *mark;
+#else
+ base = *mark;
+ end = sp;
+#endif
+
+ ptrdiff_t len = end - base;
+ if (len <= 0)
+ return;
+
+#if ! TARGET_STRUB_DONT_USE_DYNAMIC_ARRAY
+ /* Allocate a dynamically-sized array covering the desired range, so that we
+ can safely call memset on it. */
+ void *ptr[len];
+ base = &ptr[0];
+ end = &ptr[len];
+#else
+ void **ptr = end;
+#endif /* TARGET_STRUB_DONT_USE_DYNAMIC_ARRAY */
+
+ /* ldist turns this into a memset. Without the dynamic array above, that call
+ is likely unsafe: possibly tail-called, and likely scribbling over its own
+ stack frame. */
+ while (base < end)
+ *base++ = 0;
+
+ asm ("" : : "m" (ptr));
+}
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
Disinformation flourishes because many people care deeply about injustice
but very few check the facts. Ask me about <https://stallmansupport.org>
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH v2 00/10] Introduce strub: machine-independent stack scrubbing
2021-09-09 7:11 ` [PATCH] strub: machine-independent stack scrubbing Alexandre Oliva
@ 2022-07-29 6:16 ` Alexandre Oliva
2023-06-16 6:09 ` [PATCH v3] " Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2022-07-29 6:16 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson
This patch adds the strub attribute for function and variable types,
command-line options, passes and adjustments to implement it,
documentation, and tests.
Stack scrubbing is implemented in a machine-independent way: functions
with strub enabled are modified so that they take an extra stack
watermark argument, that they update with their stack use, and the
caller can then zero it out once it regains control, whether by return
or exception. There are two ways to go about it: at-calls, that
modifies the visible interface (signature) of the function, and
internal, in which the body is moved to a clone, the clone undergoes
the interface change, and the function becomes a wrapper, preserving
its original interface, that calls the clone and then clears the stack
used by it.
Variables can also be annotated with the strub attribute, so that
functions that read from them get stack scrubbing enabled implicitly,
whether at-calls, for functions only usable within a translation unit,
or internal, for functions whose interfaces must not be modified.
There is a strict mode, in which functions that have their stack
scrubbed can only call other functions with stack-scrubbing
interfaces, or those explicitly marked as callable from strub
contexts, so that an entire call chain gets scrubbing, at once or
piecemeal depending on optimization levels. In the default mode,
relaxed, this requirement is not enforced by the compiler.
The implementation adds two IPA passes, one that assigns strub modes
early on, another that modifies interfaces and adds calls to the
builtins that jointly implement stack scrubbing. Another builtin,
that obtains the stack pointer, is added for use in the implementation
of the builtins, whether expanded inline or called in libgcc.
There are new command-line options to change operation modes and to
force the feature disabled; it is enabled by default, but it has no
effect and is implicitly disabled if the strub attribute is never
used. There are also options meant to use for testing the feature,
enabling different strubbing modes for all (viable) functions.
I'm going to split up the very large patch into separate posts:
1:documentation, tests (2:C/C++ torture, 3:C/C++ non-torture, 4:C++
and Ada), 5:builtins and runtime, 6:attributes, 7:interfaces and
adjustments, and ipa-strub.cc fragments (8:strub modes, 9:strub mode
assignment pass, and 10:strub pass proper).
This is an refreshed and updated version of the patch posted in Sept
last year. It was regstrapped on x86_64-linux-gnu, bootstrapped with a
patchlet that enables -fstrub=all by default (with a fix for a warning
exposed by it). Earlier, essentially the same change has undergone
significant testing, with and without -fstrub=all on multiple embedded
platforms. Ok to install?
for gcc/ChangeLog
* Makefile.in (OBJS): Add ipa-strub.o.
* builtins.def (BUILT_IN_STACK_ADDRESS): New.
(BUILT_IN___STRUB_ENTER): New.
(BUILT_IN___STRUB_UPDATE): New.
(BUILT_IN___STRUB_LEAVE): New.
* builtins.cc: Include ipa-strub.h.
(STACK_STOPS, STACK_UNSIGNED): Define.
(expand_builtin_stack_address): New.
(expand_builtin_strub_enter): New.
(expand_builtin_strub_update): New.
(expand_builtin_strub_leave): New.
(expand_bulitin): Call them.
* common.opt (fstrub=*): New options.
* doc/extend.texi (strub): New type attribute.
(__builtin_stack_address): New function.
(Stack Scrubbing): New section.
* doc/invoke.texi (-fstrub=*): New options.
(-fdump-ipa-*): New passes.
* ipa-inline.cc: Include ipa-strub.h.
(can_inline_edge_p): Test strub_inlinable_to_p.
* ipa-split.cc: Include ipa-strub.h.
(execute_split_functions): Test strub_splittable_p.
* ipa-strub.cc, ipa-strub.h: New.
* passes.def: Add strub_mode and strub passes.
* tree-cfg.cc (gimple_verify_flow_info): Note on debug stmts.
* tree-pass.h (make_pass_ipa_strub_mode): Declare.
(make_pass_ipa_strub): Declare.
(make_pass_ipa_function_and_variable_visibility): Fix
formatting.
* tree-ssa-ccp.cc (optimize_stack_restore): Keep restores
before strub leave.
* multiple_target.cc (pass_target_clone::gate): Test seen_error.
* attribs.cc: Include ipa-strub.h.
(decl_attributes): Support applying attributes to function
type, rather than pointer type, at handler's request.
(comp_type_attributes): Combine strub_comptypes and target
comp_type results.
for gcc/c-family/ChangeLog
* c-attribs.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(c_common_attribute_table): Add strub.
for gcc/ada/ChangeLog
* gcc-interface/trans.cc: Include ipa-strub.h.
(gigi): Make internal decls for targets of compiler-generated
calls strub-callable too.
(build_raise_check): Likewise.
* gcc-interface/utils.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(gnat_internal_attribute_table): Add strub.
for gcc/testsuite/ChangeLog
* c-c++-common/strub-O0.c: New.
* c-c++-common/strub-O1.c: New.
* c-c++-common/strub-O2.c: New.
* c-c++-common/strub-O2fni.c: New.
* c-c++-common/strub-O3.c: New.
* c-c++-common/strub-O3fni.c: New.
* c-c++-common/strub-Og.c: New.
* c-c++-common/strub-Os.c: New.
* c-c++-common/strub-all1.c: New.
* c-c++-common/strub-all2.c: New.
* c-c++-common/strub-apply1.c: New.
* c-c++-common/strub-apply2.c: New.
* c-c++-common/strub-apply3.c: New.
* c-c++-common/strub-apply4.c: New.
* c-c++-common/strub-at-calls1.c: New.
* c-c++-common/strub-at-calls2.c: New.
* c-c++-common/strub-defer-O1.c: New.
* c-c++-common/strub-defer-O2.c: New.
* c-c++-common/strub-defer-O3.c: New.
* c-c++-common/strub-defer-Os.c: New.
* c-c++-common/strub-internal1.c: New.
* c-c++-common/strub-internal2.c: New.
* c-c++-common/strub-parms1.c: New.
* c-c++-common/strub-parms2.c: New.
* c-c++-common/strub-parms3.c: New.
* c-c++-common/strub-relaxed1.c: New.
* c-c++-common/strub-relaxed2.c: New.
* c-c++-common/strub-short-O0-exc.c: New.
* c-c++-common/strub-short-O0.c: New.
* c-c++-common/strub-short-O1.c: New.
* c-c++-common/strub-short-O2.c: New.
* c-c++-common/strub-short-O3.c: New.
* c-c++-common/strub-short-Os.c: New.
* c-c++-common/strub-strict1.c: New.
* c-c++-common/strub-strict2.c: New.
* c-c++-common/strub-tail-O1.c: New.
* c-c++-common/strub-tail-O2.c: New.
* c-c++-common/torture/strub-callable1.c: New.
* c-c++-common/torture/strub-callable2.c: New.
* c-c++-common/torture/strub-const1.c: New.
* c-c++-common/torture/strub-const2.c: New.
* c-c++-common/torture/strub-const3.c: New.
* c-c++-common/torture/strub-const4.c: New.
* c-c++-common/torture/strub-data1.c: New.
* c-c++-common/torture/strub-data2.c: New.
* c-c++-common/torture/strub-data3.c: New.
* c-c++-common/torture/strub-data4.c: New.
* c-c++-common/torture/strub-data5.c: New.
* c-c++-common/torture/strub-indcall1.c: New.
* c-c++-common/torture/strub-indcall2.c: New.
* c-c++-common/torture/strub-indcall3.c: New.
* c-c++-common/torture/strub-inlinable1.c: New.
* c-c++-common/torture/strub-inlinable2.c: New.
* c-c++-common/torture/strub-ptrfn1.c: New.
* c-c++-common/torture/strub-ptrfn2.c: New.
* c-c++-common/torture/strub-ptrfn3.c: New.
* c-c++-common/torture/strub-ptrfn4.c: New.
* c-c++-common/torture/strub-pure1.c: New.
* c-c++-common/torture/strub-pure2.c: New.
* c-c++-common/torture/strub-pure3.c: New.
* c-c++-common/torture/strub-pure4.c: New.
* c-c++-common/torture/strub-run1.c: New.
* c-c++-common/torture/strub-run2.c: New.
* c-c++-common/torture/strub-run3.c: New.
* c-c++-common/torture/strub-run4.c: New.
* c-c++-common/torture/strub-run4c.c: New.
* c-c++-common/torture/strub-run4d.c: New.
* c-c++-common/torture/strub-run4i.c: New.
* g++.dg/strub-run1.C: New.
* g++.dg/torture/strub-init1.C: New.
* g++.dg/torture/strub-init2.C: New.
* g++.dg/torture/strub-init3.C: New.
* gnat.dg/strub_attr.adb, gnat.dg/strub_attr.ads: New.
* gnat.dg/strub_ind.adb, gnat.dg/strub_ind.ads: New.
for libgcc/ChangeLog
* Makefile.in (LIB2ADD): Add strub.c.
* libgcc2.h (__strub_enter, __strub_update, __strub_leave):
Declare.
* strub.c: New.
---
gcc/Makefile.in | 1
gcc/ada/gcc-interface/trans.cc | 18
gcc/ada/gcc-interface/utils.cc | 73
gcc/attribs.cc | 40
gcc/builtins.cc | 273 ++
gcc/builtins.def | 4
gcc/c-family/c-attribs.cc | 82
gcc/common.opt | 29
gcc/doc/extend.texi | 307 ++
gcc/doc/invoke.texi | 60
gcc/ipa-inline.cc | 6
gcc/ipa-split.cc | 7
gcc/ipa-strub.cc | 3489 ++++++++++++++++++++
gcc/ipa-strub.h | 45
gcc/multiple_target.cc | 2
gcc/passes.def | 2
gcc/testsuite/c-c++-common/strub-O0.c | 14
gcc/testsuite/c-c++-common/strub-O1.c | 15
gcc/testsuite/c-c++-common/strub-O2.c | 16
gcc/testsuite/c-c++-common/strub-O2fni.c | 15
gcc/testsuite/c-c++-common/strub-O3.c | 12
gcc/testsuite/c-c++-common/strub-O3fni.c | 15
gcc/testsuite/c-c++-common/strub-Og.c | 16
gcc/testsuite/c-c++-common/strub-Os.c | 18
gcc/testsuite/c-c++-common/strub-all1.c | 32
gcc/testsuite/c-c++-common/strub-all2.c | 24
gcc/testsuite/c-c++-common/strub-apply1.c | 15
gcc/testsuite/c-c++-common/strub-apply2.c | 12
gcc/testsuite/c-c++-common/strub-apply3.c | 8
gcc/testsuite/c-c++-common/strub-apply4.c | 21
gcc/testsuite/c-c++-common/strub-at-calls1.c | 30
gcc/testsuite/c-c++-common/strub-at-calls2.c | 23
gcc/testsuite/c-c++-common/strub-defer-O1.c | 7
gcc/testsuite/c-c++-common/strub-defer-O2.c | 8
gcc/testsuite/c-c++-common/strub-defer-O3.c | 97 +
gcc/testsuite/c-c++-common/strub-defer-Os.c | 7
gcc/testsuite/c-c++-common/strub-internal1.c | 31
gcc/testsuite/c-c++-common/strub-internal2.c | 21
gcc/testsuite/c-c++-common/strub-parms1.c | 48
gcc/testsuite/c-c++-common/strub-parms2.c | 36
gcc/testsuite/c-c++-common/strub-parms3.c | 58
gcc/testsuite/c-c++-common/strub-relaxed1.c | 18
gcc/testsuite/c-c++-common/strub-relaxed2.c | 14
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 10
gcc/testsuite/c-c++-common/strub-short-O0.c | 10
gcc/testsuite/c-c++-common/strub-short-O1.c | 10
gcc/testsuite/c-c++-common/strub-short-O2.c | 10
gcc/testsuite/c-c++-common/strub-short-O3.c | 12
gcc/testsuite/c-c++-common/strub-short-Os.c | 12
gcc/testsuite/c-c++-common/strub-strict1.c | 36
gcc/testsuite/c-c++-common/strub-strict2.c | 25
gcc/testsuite/c-c++-common/strub-tail-O1.c | 8
gcc/testsuite/c-c++-common/strub-tail-O2.c | 14
gcc/testsuite/c-c++-common/strub-var1.c | 24
.../c-c++-common/torture/strub-callable1.c | 9
.../c-c++-common/torture/strub-callable2.c | 264 ++
gcc/testsuite/c-c++-common/torture/strub-const1.c | 18
gcc/testsuite/c-c++-common/torture/strub-const2.c | 22
gcc/testsuite/c-c++-common/torture/strub-const3.c | 13
gcc/testsuite/c-c++-common/torture/strub-const4.c | 17
gcc/testsuite/c-c++-common/torture/strub-data1.c | 13
gcc/testsuite/c-c++-common/torture/strub-data2.c | 14
gcc/testsuite/c-c++-common/torture/strub-data3.c | 14
gcc/testsuite/c-c++-common/torture/strub-data4.c | 14
gcc/testsuite/c-c++-common/torture/strub-data5.c | 15
.../c-c++-common/torture/strub-indcall1.c | 14
.../c-c++-common/torture/strub-indcall2.c | 14
.../c-c++-common/torture/strub-indcall3.c | 14
.../c-c++-common/torture/strub-inlinable1.c | 16
.../c-c++-common/torture/strub-inlinable2.c | 7
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 10
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 55
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 50
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 43
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17
gcc/testsuite/c-c++-common/torture/strub-run1.c | 90 +
gcc/testsuite/c-c++-common/torture/strub-run2.c | 79
gcc/testsuite/c-c++-common/torture/strub-run3.c | 75
gcc/testsuite/c-c++-common/torture/strub-run4.c | 101 +
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 5
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 7
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 5
gcc/testsuite/g++.dg/strub-run1.C | 19
gcc/testsuite/g++.dg/torture/strub-init1.C | 13
gcc/testsuite/g++.dg/torture/strub-init2.C | 14
gcc/testsuite/g++.dg/torture/strub-init3.C | 13
gcc/testsuite/gnat.dg/strub_access.adb | 21
gcc/testsuite/gnat.dg/strub_access1.adb | 16
gcc/testsuite/gnat.dg/strub_attr.adb | 37
gcc/testsuite/gnat.dg/strub_attr.ads | 12
gcc/testsuite/gnat.dg/strub_disp.adb | 64
gcc/testsuite/gnat.dg/strub_disp1.adb | 79
gcc/testsuite/gnat.dg/strub_ind.adb | 33
gcc/testsuite/gnat.dg/strub_ind.ads | 17
gcc/testsuite/gnat.dg/strub_ind1.adb | 41
gcc/testsuite/gnat.dg/strub_ind1.ads | 17
gcc/testsuite/gnat.dg/strub_ind2.adb | 34
gcc/testsuite/gnat.dg/strub_ind2.ads | 17
gcc/testsuite/gnat.dg/strub_intf.adb | 93 +
gcc/testsuite/gnat.dg/strub_intf1.adb | 86
gcc/testsuite/gnat.dg/strub_intf2.adb | 55
gcc/testsuite/gnat.dg/strub_renm.adb | 21
gcc/testsuite/gnat.dg/strub_renm1.adb | 32
gcc/testsuite/gnat.dg/strub_renm2.adb | 32
gcc/testsuite/gnat.dg/strub_var.adb | 16
gcc/testsuite/gnat.dg/strub_var1.adb | 20
gcc/tree-cfg.cc | 1
gcc/tree-pass.h | 5
gcc/tree-ssa-ccp.cc | 4
libgcc/Makefile.in | 3
libgcc/libgcc2.h | 4
libgcc/strub.c | 112 +
115 files changed, 7227 insertions(+), 12 deletions(-)
create mode 100644 gcc/ipa-strub.cc
create mode 100644 gcc/ipa-strub.h
create mode 100644 gcc/testsuite/c-c++-common/strub-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Og.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply4.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0-exc.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-var1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data5.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4c.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4d.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4i.c
create mode 100644 gcc/testsuite/g++.dg/strub-run1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init2.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init3.C
create mode 100644 gcc/testsuite/gnat.dg/strub_access.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_access1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_disp.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_disp1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_intf.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var1.adb
create mode 100644 libgcc/strub.c
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
Disinformation flourishes because many people care deeply about injustice
but very few check the facts. Ask me about <https://stallmansupport.org>
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v3] Introduce strub: machine-independent stack scrubbing
2022-07-29 6:16 ` [PATCH v2 00/10] Introduce " Alexandre Oliva
@ 2023-06-16 6:09 ` Alexandre Oliva
2023-10-20 6:03 ` [PATCH v4] " Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-06-16 6:09 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson
This patch adds the strub attribute for function and variable types,
command-line options, passes and adjustments to implement it,
documentation, and tests.
Stack scrubbing is implemented in a machine-independent way: functions
with strub enabled are modified so that they take an extra stack
watermark argument, that they update with their stack use, and the
caller can then zero it out once it regains control, whether by return
or exception. There are two ways to go about it: at-calls, that
modifies the visible interface (signature) of the function, and
internal, in which the body is moved to a clone, the clone undergoes
the interface change, and the function becomes a wrapper, preserving
its original interface, that calls the clone and then clears the stack
used by it.
Variables can also be annotated with the strub attribute, so that
functions that read from them get stack scrubbing enabled implicitly,
whether at-calls, for functions only usable within a translation unit,
or internal, for functions whose interfaces must not be modified.
There is a strict mode, in which functions that have their stack
scrubbed can only call other functions with stack-scrubbing
interfaces, or those explicitly marked as callable from strub
contexts, so that an entire call chain gets scrubbing, at once or
piecemeal depending on optimization levels. In the default mode,
relaxed, this requirement is not enforced by the compiler.
The implementation adds two IPA passes, one that assigns strub modes
early on, another that modifies interfaces and adds calls to the
builtins that jointly implement stack scrubbing. Another builtin,
that obtains the stack pointer, is added for use in the implementation
of the builtins, whether expanded inline or called in libgcc.
There are new command-line options to change operation modes and to
force the feature disabled; it is enabled by default, but it has no
effect and is implicitly disabled if the strub attribute is never
used. There are also options meant to use for testing the feature,
enabling different strubbing modes for all (viable) functions.
Regstrapped on x86_64-linux-gnu. Also tested with gcc-13, and with
various other targets. Ok to install?
There have been only minor changes since v2:
- scrub the stack in the same direction it grows, inline and out-of-line
- remove need for stack space in __strub_leave
- add (ultimately not needed) means to avoid using the red zone in
__strub_leave
- introduce and document TARGET_ macros to tune __strub_leave
- drop a misoptimization in inlined __strub_enter
- fix handling of cgraph edges without call stmts
- adjust some testcases (async stack uses; Ada compiler bug fix)
- drop bits for compatibility with gcc 10
- preserve the comdat group when resetting a function into a strub
wrapper, coping with a symtab_node::reset change in gcc-13
for gcc/ChangeLog
* Makefile.in (OBJS): Add ipa-strub.o.
* builtins.def (BUILT_IN_STACK_ADDRESS): New.
(BUILT_IN___STRUB_ENTER): New.
(BUILT_IN___STRUB_UPDATE): New.
(BUILT_IN___STRUB_LEAVE): New.
* builtins.cc: Include ipa-strub.h.
(STACK_STOPS, STACK_UNSIGNED): Define.
(expand_builtin_stack_address): New.
(expand_builtin_strub_enter): New.
(expand_builtin_strub_update): New.
(expand_builtin_strub_leave): New.
(expand_builtin): Call them.
* common.opt (fstrub=*): New options.
* doc/extend.texi (strub): New type attribute.
(__builtin_stack_address): New function.
(Stack Scrubbing): New section.
* doc/invoke.texi (-fstrub=*): New options.
(-fdump-ipa-*): New passes.
* ipa-inline.cc: Include ipa-strub.h.
(can_inline_edge_p): Test strub_inlinable_to_p.
* ipa-split.cc: Include ipa-strub.h.
(execute_split_functions): Test strub_splittable_p.
* ipa-strub.cc, ipa-strub.h: New.
* passes.def: Add strub_mode and strub passes.
* tree-cfg.cc (gimple_verify_flow_info): Note on debug stmts.
* tree-pass.h (make_pass_ipa_strub_mode): Declare.
(make_pass_ipa_strub): Declare.
(make_pass_ipa_function_and_variable_visibility): Fix
formatting.
* tree-ssa-ccp.cc (optimize_stack_restore): Keep restores
before strub leave.
* multiple_target.cc (pass_target_clone::gate): Test seen_error.
* attribs.cc: Include ipa-strub.h.
(decl_attributes): Support applying attributes to function
type, rather than pointer type, at handler's request.
(comp_type_attributes): Combine strub_comptypes and target
comp_type results.
* doc/tm.texi.in (TARGET_STRUB_USE_DYNAMIC_ARRAY): New.
(TARGET_STRUB_MAY_USE_MEMSET): New.
* doc/tm.texi: Rebuilt.
* cgraph.h (symtab_node::reset): Add preserve_comdat_group
param, with a default.
* cgraphunit.cc (symtab_node::reset): Use it.
for gcc/c-family/ChangeLog
* c-attribs.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(c_common_attribute_table): Add strub.
for gcc/ada/ChangeLog
* gcc-interface/trans.cc: Include ipa-strub.h.
(gigi): Make internal decls for targets of compiler-generated
calls strub-callable too.
(build_raise_check): Likewise.
* gcc-interface/utils.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(gnat_internal_attribute_table): Add strub.
for gcc/testsuite/ChangeLog
* c-c++-common/strub-O0.c: New.
* c-c++-common/strub-O1.c: New.
* c-c++-common/strub-O2.c: New.
* c-c++-common/strub-O2fni.c: New.
* c-c++-common/strub-O3.c: New.
* c-c++-common/strub-O3fni.c: New.
* c-c++-common/strub-Og.c: New.
* c-c++-common/strub-Os.c: New.
* c-c++-common/strub-all1.c: New.
* c-c++-common/strub-all2.c: New.
* c-c++-common/strub-apply1.c: New.
* c-c++-common/strub-apply2.c: New.
* c-c++-common/strub-apply3.c: New.
* c-c++-common/strub-apply4.c: New.
* c-c++-common/strub-at-calls1.c: New.
* c-c++-common/strub-at-calls2.c: New.
* c-c++-common/strub-defer-O1.c: New.
* c-c++-common/strub-defer-O2.c: New.
* c-c++-common/strub-defer-O3.c: New.
* c-c++-common/strub-defer-Os.c: New.
* c-c++-common/strub-internal1.c: New.
* c-c++-common/strub-internal2.c: New.
* c-c++-common/strub-parms1.c: New.
* c-c++-common/strub-parms2.c: New.
* c-c++-common/strub-parms3.c: New.
* c-c++-common/strub-relaxed1.c: New.
* c-c++-common/strub-relaxed2.c: New.
* c-c++-common/strub-short-O0-exc.c: New.
* c-c++-common/strub-short-O0.c: New.
* c-c++-common/strub-short-O1.c: New.
* c-c++-common/strub-short-O2.c: New.
* c-c++-common/strub-short-O3.c: New.
* c-c++-common/strub-short-Os.c: New.
* c-c++-common/strub-strict1.c: New.
* c-c++-common/strub-strict2.c: New.
* c-c++-common/strub-tail-O1.c: New.
* c-c++-common/strub-tail-O2.c: New.
* c-c++-common/torture/strub-callable1.c: New.
* c-c++-common/torture/strub-callable2.c: New.
* c-c++-common/torture/strub-const1.c: New.
* c-c++-common/torture/strub-const2.c: New.
* c-c++-common/torture/strub-const3.c: New.
* c-c++-common/torture/strub-const4.c: New.
* c-c++-common/torture/strub-data1.c: New.
* c-c++-common/torture/strub-data2.c: New.
* c-c++-common/torture/strub-data3.c: New.
* c-c++-common/torture/strub-data4.c: New.
* c-c++-common/torture/strub-data5.c: New.
* c-c++-common/torture/strub-indcall1.c: New.
* c-c++-common/torture/strub-indcall2.c: New.
* c-c++-common/torture/strub-indcall3.c: New.
* c-c++-common/torture/strub-inlinable1.c: New.
* c-c++-common/torture/strub-inlinable2.c: New.
* c-c++-common/torture/strub-ptrfn1.c: New.
* c-c++-common/torture/strub-ptrfn2.c: New.
* c-c++-common/torture/strub-ptrfn3.c: New.
* c-c++-common/torture/strub-ptrfn4.c: New.
* c-c++-common/torture/strub-pure1.c: New.
* c-c++-common/torture/strub-pure2.c: New.
* c-c++-common/torture/strub-pure3.c: New.
* c-c++-common/torture/strub-pure4.c: New.
* c-c++-common/torture/strub-run1.c: New.
* c-c++-common/torture/strub-run2.c: New.
* c-c++-common/torture/strub-run3.c: New.
* c-c++-common/torture/strub-run4.c: New.
* c-c++-common/torture/strub-run4c.c: New.
* c-c++-common/torture/strub-run4d.c: New.
* c-c++-common/torture/strub-run4i.c: New.
* g++.dg/strub-run1.C: New.
* g++.dg/torture/strub-init1.C: New.
* g++.dg/torture/strub-init2.C: New.
* g++.dg/torture/strub-init3.C: New.
* gnat.dg/strub_attr.adb, gnat.dg/strub_attr.ads: New.
* gnat.dg/strub_ind.adb, gnat.dg/strub_ind.ads: New.
for libgcc/ChangeLog
* Makefile.in (LIB2ADD): Add strub.c.
* libgcc2.h (__strub_enter, __strub_update, __strub_leave):
Declare.
* strub.c: New.
---
gcc/Makefile.in | 1
gcc/ada/gcc-interface/trans.cc | 18
gcc/ada/gcc-interface/utils.cc | 73
gcc/attribs.cc | 37
gcc/builtins.cc | 269 ++
gcc/builtins.def | 4
gcc/c-family/c-attribs.cc | 82
gcc/cgraph.h | 2
gcc/cgraphunit.cc | 5
gcc/common.opt | 29
gcc/doc/extend.texi | 307 ++
gcc/doc/invoke.texi | 60
gcc/doc/tm.texi | 19
gcc/doc/tm.texi.in | 19
gcc/ipa-inline.cc | 6
gcc/ipa-split.cc | 7
gcc/ipa-strub.cc | 3450 ++++++++++++++++++++
gcc/ipa-strub.h | 45
gcc/passes.def | 2
gcc/testsuite/c-c++-common/strub-O0.c | 14
gcc/testsuite/c-c++-common/strub-O1.c | 15
gcc/testsuite/c-c++-common/strub-O2.c | 16
gcc/testsuite/c-c++-common/strub-O2fni.c | 15
gcc/testsuite/c-c++-common/strub-O3.c | 12
gcc/testsuite/c-c++-common/strub-O3fni.c | 15
gcc/testsuite/c-c++-common/strub-Og.c | 16
gcc/testsuite/c-c++-common/strub-Os.c | 18
gcc/testsuite/c-c++-common/strub-all1.c | 32
gcc/testsuite/c-c++-common/strub-all2.c | 24
gcc/testsuite/c-c++-common/strub-apply1.c | 15
gcc/testsuite/c-c++-common/strub-apply2.c | 12
gcc/testsuite/c-c++-common/strub-apply3.c | 8
gcc/testsuite/c-c++-common/strub-apply4.c | 21
gcc/testsuite/c-c++-common/strub-at-calls1.c | 30
gcc/testsuite/c-c++-common/strub-at-calls2.c | 23
gcc/testsuite/c-c++-common/strub-defer-O1.c | 7
gcc/testsuite/c-c++-common/strub-defer-O2.c | 8
gcc/testsuite/c-c++-common/strub-defer-O3.c | 97 +
gcc/testsuite/c-c++-common/strub-defer-Os.c | 7
gcc/testsuite/c-c++-common/strub-internal1.c | 31
gcc/testsuite/c-c++-common/strub-internal2.c | 21
gcc/testsuite/c-c++-common/strub-parms1.c | 48
gcc/testsuite/c-c++-common/strub-parms2.c | 36
gcc/testsuite/c-c++-common/strub-parms3.c | 58
gcc/testsuite/c-c++-common/strub-relaxed1.c | 18
gcc/testsuite/c-c++-common/strub-relaxed2.c | 14
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 10
gcc/testsuite/c-c++-common/strub-short-O0.c | 10
gcc/testsuite/c-c++-common/strub-short-O1.c | 10
gcc/testsuite/c-c++-common/strub-short-O2.c | 10
gcc/testsuite/c-c++-common/strub-short-O3.c | 12
gcc/testsuite/c-c++-common/strub-short-Os.c | 12
gcc/testsuite/c-c++-common/strub-strict1.c | 36
gcc/testsuite/c-c++-common/strub-strict2.c | 25
gcc/testsuite/c-c++-common/strub-tail-O1.c | 8
gcc/testsuite/c-c++-common/strub-tail-O2.c | 14
gcc/testsuite/c-c++-common/strub-var1.c | 24
.../c-c++-common/torture/strub-callable1.c | 9
.../c-c++-common/torture/strub-callable2.c | 264 ++
gcc/testsuite/c-c++-common/torture/strub-const1.c | 18
gcc/testsuite/c-c++-common/torture/strub-const2.c | 22
gcc/testsuite/c-c++-common/torture/strub-const3.c | 13
gcc/testsuite/c-c++-common/torture/strub-const4.c | 17
gcc/testsuite/c-c++-common/torture/strub-data1.c | 13
gcc/testsuite/c-c++-common/torture/strub-data2.c | 14
gcc/testsuite/c-c++-common/torture/strub-data3.c | 14
gcc/testsuite/c-c++-common/torture/strub-data4.c | 14
gcc/testsuite/c-c++-common/torture/strub-data5.c | 15
.../c-c++-common/torture/strub-indcall1.c | 14
.../c-c++-common/torture/strub-indcall2.c | 14
.../c-c++-common/torture/strub-indcall3.c | 14
.../c-c++-common/torture/strub-inlinable1.c | 16
.../c-c++-common/torture/strub-inlinable2.c | 7
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 10
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 55
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 50
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 43
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17
gcc/testsuite/c-c++-common/torture/strub-run1.c | 95 +
gcc/testsuite/c-c++-common/torture/strub-run2.c | 84
gcc/testsuite/c-c++-common/torture/strub-run3.c | 80
gcc/testsuite/c-c++-common/torture/strub-run4.c | 106 +
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 5
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 7
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 5
gcc/testsuite/g++.dg/strub-run1.C | 19
gcc/testsuite/g++.dg/torture/strub-init1.C | 13
gcc/testsuite/g++.dg/torture/strub-init2.C | 14
gcc/testsuite/g++.dg/torture/strub-init3.C | 13
gcc/testsuite/gnat.dg/strub_access.adb | 21
gcc/testsuite/gnat.dg/strub_access1.adb | 16
gcc/testsuite/gnat.dg/strub_attr.adb | 37
gcc/testsuite/gnat.dg/strub_attr.ads | 12
gcc/testsuite/gnat.dg/strub_disp.adb | 64
gcc/testsuite/gnat.dg/strub_disp1.adb | 79
gcc/testsuite/gnat.dg/strub_ind.adb | 33
gcc/testsuite/gnat.dg/strub_ind.ads | 17
gcc/testsuite/gnat.dg/strub_ind1.adb | 41
gcc/testsuite/gnat.dg/strub_ind1.ads | 17
gcc/testsuite/gnat.dg/strub_ind2.adb | 34
gcc/testsuite/gnat.dg/strub_ind2.ads | 17
gcc/testsuite/gnat.dg/strub_intf.adb | 93 +
gcc/testsuite/gnat.dg/strub_intf1.adb | 86
gcc/testsuite/gnat.dg/strub_intf2.adb | 55
gcc/testsuite/gnat.dg/strub_renm.adb | 21
gcc/testsuite/gnat.dg/strub_renm1.adb | 32
gcc/testsuite/gnat.dg/strub_renm2.adb | 32
gcc/testsuite/gnat.dg/strub_var.adb | 16
gcc/testsuite/gnat.dg/strub_var1.adb | 20
gcc/tree-cfg.cc | 1
gcc/tree-pass.h | 5
gcc/tree-ssa-ccp.cc | 4
libgcc/Makefile.in | 3
libgcc/libgcc2.h | 4
libgcc/strub.c | 149 +
118 files changed, 7281 insertions(+), 12 deletions(-)
create mode 100644 gcc/ipa-strub.cc
create mode 100644 gcc/ipa-strub.h
create mode 100644 gcc/testsuite/c-c++-common/strub-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Og.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply4.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0-exc.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-var1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data5.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4c.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4d.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4i.c
create mode 100644 gcc/testsuite/g++.dg/strub-run1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init2.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init3.C
create mode 100644 gcc/testsuite/gnat.dg/strub_access.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_access1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_disp.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_disp1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_intf.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var1.adb
create mode 100644 libgcc/strub.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3c5804bdb21fe..96d920d1f6a8d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1520,6 +1520,7 @@ OBJS = \
ipa-reference.o \
ipa-ref.o \
ipa-utils.o \
+ ipa-strub.o \
ipa.o \
ira.o \
ira-build.o \
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index 965565ad2da01..6a1aa7d3ca6ea 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -69,6 +69,21 @@
#include "ada-tree.h"
#include "gigi.h"
+/* The following #include is for strub_make_callable.
+
+ This function marks a function as safe to call from strub contexts. We mark
+ Ada subprograms that may be called implicitly by the compiler, and that won't
+ leave on the stack caller data passed to them. This stops implicit calls
+ introduced in subprograms that have their stack scrubbed from being flagged
+ as unsafe, even in -fstrub=strict mode.
+
+ These subprograms are also marked with the strub(callable) attribute in Ada
+ sources, but their declarations aren't necessarily imported by GNAT, or made
+ visible to gigi, in units that end up relying on them. So when gigi
+ introduces their declarations on its own, it must also add the attribute, by
+ calling strub_make_callable. */
+#include "ipa-strub.h"
+
/* We should avoid allocating more than ALLOCA_THRESHOLD bytes via alloca,
for fear of running out of stack space. If we need more, we use xmalloc
instead. */
@@ -454,6 +469,7 @@ gigi (Node_Id gnat_root,
int64_type, NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv64_decl);
if (Enable_128bit_Types)
{
@@ -466,6 +482,7 @@ gigi (Node_Id gnat_root,
NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv128_decl);
}
/* Name of the _Parent field in tagged record types. */
@@ -723,6 +740,7 @@ build_raise_check (int check, enum exception_info_kind kind)
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
set_call_expr_flags (result, ECF_NORETURN | ECF_THROW);
+ strub_make_callable (result);
return result;
}
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index d0a13d2af3331..f36af1d52b85a 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -39,6 +39,7 @@
#include "varasm.h"
#include "toplev.h"
#include "opts.h"
+#include "ipa-strub.h"
#include "output.h"
#include "debug.h"
#include "convert.h"
@@ -6632,9 +6633,77 @@ handle_no_stack_protector_attribute (tree *node, tree name, tree, int,
struct attribute_spec.handler. */
static tree
-handle_strub_attribute (tree *, tree, tree, int, bool *no_add_attrs)
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
- *no_add_attrs = true;
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
return NULL_TREE;
}
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index b8cb55b97df38..ee075b0fe1bbd 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "attribs.h"
#include "fold-const.h"
+#include "ipa-strub.h"
#include "stor-layout.h"
#include "langhooks.h"
#include "plugin.h"
@@ -779,8 +780,8 @@ decl_attributes (tree *node, tree attributes, int flags,
flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
- if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
+ if (spec->function_type_required
+ && !FUNC_OR_METHOD_TYPE_P (*anode))
{
if (TREE_CODE (*anode) == POINTER_TYPE
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
@@ -892,7 +893,24 @@ decl_attributes (tree *node, tree attributes, int flags,
TYPE_NAME (tt) = *node;
}
- *anode = cur_and_last_decl[0];
+ if (*anode != cur_and_last_decl[0])
+ {
+ /* Even if !spec->function_type_required, allow the attribute
+ handler to request the attribute to be applied to the function
+ type, rather than to the function pointer type, by setting
+ cur_and_last_decl[0] to the function type. */
+ if (!fn_ptr_tmp
+ && POINTER_TYPE_P (*anode)
+ && TREE_TYPE (*anode) == cur_and_last_decl[0]
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+ {
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ }
+ *anode = cur_and_last_decl[0];
+ }
+
if (ret == error_mark_node)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1495,9 +1513,20 @@ comp_type_attributes (const_tree type1, const_tree type2)
if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
return 0;
+ int strub_ret = strub_comptypes (CONST_CAST_TREE (type1),
+ CONST_CAST_TREE (type2));
+ if (strub_ret == 0)
+ return strub_ret;
/* As some type combinations - like default calling-convention - might
be compatible, we have to call the target hook to get the final result. */
- return targetm.comp_type_attributes (type1, type2);
+ int target_ret = targetm.comp_type_attributes (type1, type2);
+ if (target_ret == 0)
+ return target_ret;
+ if (strub_ret == 2 || target_ret == 2)
+ return 2;
+ if (strub_ret == 1 && target_ret == 1)
+ return 1;
+ gcc_unreachable ();
}
/* PREDICATE acts as a function of type:
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 8400adaf5b4db..a6dc923de5712 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "intl.h"
#include "file-prefix-map.h" /* remap_macro_filename() */
+#include "ipa-strub.h" /* strub_watermark_parm() */
#include "gomp-constants.h"
#include "omp-general.h"
#include "tree-dfa.h"
@@ -152,6 +153,7 @@ static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
static rtx expand_builtin_alloca (tree);
static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
+static rtx expand_builtin_stack_address ();
static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx);
static rtx expand_builtin_expect_with_probability (tree, rtx);
@@ -5281,6 +5283,252 @@ expand_builtin_frame_address (tree fndecl, tree exp)
}
}
+#ifndef STACK_GROWS_DOWNWARD
+# define STACK_TOPS GT
+#else
+# define STACK_TOPS LT
+#endif
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+# define STACK_UNSIGNED POINTERS_EXTEND_UNSIGNED
+#else
+# define STACK_UNSIGNED true
+#endif
+
+/* Expand a call to builtin function __builtin_stack_address. */
+
+static rtx
+expand_builtin_stack_address ()
+{
+ return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
+ STACK_UNSIGNED);
+}
+
+/* Expand a call to builtin function __builtin_strub_enter. */
+
+static rtx
+expand_builtin_strub_enter (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 1 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ emit_move_insn (wmark, stktop);
+
+ return const0_rtx;
+}
+
+/* Expand a call to builtin function __builtin_strub_update. */
+
+static rtx
+expand_builtin_strub_update (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+#ifdef RED_ZONE_SIZE
+ /* Here's how the strub enter, update and leave functions deal with red zones.
+
+ If it weren't for red zones, update, called from within a strub context,
+ would bump the watermark to the top of the stack. Enter and leave, running
+ in the caller, would use the caller's top of stack address both to
+ initialize the watermark passed to the callee, and to start strubbing the
+ stack afterwards.
+
+ Ideally, we'd update the watermark so as to cover the used amount of red
+ zone, and strub starting at the caller's other end of the (presumably
+ unused) red zone. Normally, only leaf functions use the red zone, but at
+ this point we can't tell whether a function is a leaf, nor can we tell how
+ much of the red zone it uses. Furthermore, some strub contexts may have
+ been inlined so that update and leave are called from the same stack frame,
+ and the strub builtins may all have been inlined, turning a strub function
+ into a leaf.
+
+ So cleaning the range from the caller's stack pointer (one end of the red
+ zone) to the (potentially inlined) callee's (other end of the) red zone
+ could scribble over the caller's own red zone.
+
+ We avoid this possibility by arranging for callers that are strub contexts
+ to use their own watermark as the strub starting point. So, if A calls B,
+ and B calls C, B will tell A to strub up to the end of B's red zone, and
+ will strub itself only the part of C's stack frame and red zone that
+ doesn't overlap with B's. With that, we don't need to know who's leaf and
+ who isn't: inlined calls will shrink their strub window to zero, each
+ remaining call will strub some portion of the stack, and eventually the
+ strub context will return to a caller that isn't a strub context itself,
+ that will therefore use its own stack pointer as the strub starting point.
+ It's not a leaf, because strub contexts can't be inlined into non-strub
+ contexts, so it doesn't use the red zone, and it will therefore correctly
+ strub up the callee's stack frame up to the end of the callee's red zone.
+ Neat! */
+ if (true /* (flags_from_decl_or_type (current_function_decl) & ECF_LEAF) */)
+ {
+ poly_int64 red_zone_size = RED_ZONE_SIZE;
+#if STACK_GROWS_DOWNWARD
+ red_zone_size = -red_zone_size;
+#endif
+ stktop = plus_constant (ptr_mode, stktop, red_zone_size);
+ stktop = force_reg (ptr_mode, stktop);
+ }
+#endif
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+ rtx_code_label *lab = gen_label_rtx ();
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+
+ /* If this is an inlined strub function, also bump the watermark for the
+ enclosing function. This avoids a problem with the following scenario: A
+ calls B and B calls C, and both B and C get inlined into A. B allocates
+ temporary stack space before calling C. If we don't update A's watermark,
+ we may use an outdated baseline for the post-C strub_leave, erasing B's
+ temporary stack allocation. We only need this if we're fully expanding
+ strub_leave inline. */
+ tree xwmptr = (optimize > 2
+ ? strub_watermark_parm (current_function_decl)
+ : wmptr);
+ if (wmptr != xwmptr)
+ {
+ wmptr = xwmptr;
+ wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ wmarkr = force_reg (ptr_mode, wmark);
+
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+ }
+
+ emit_label (lab);
+
+ return const0_rtx;
+}
+
+
+/* Expand a call to builtin function __builtin_strub_leave. */
+
+static rtx
+expand_builtin_strub_leave (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || optimize_size || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = NULL_RTX;
+
+ if (tree wmptr = (optimize
+ ? strub_watermark_parm (current_function_decl)
+ : NULL_TREE))
+ {
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ stktop = force_reg (ptr_mode, wmark);
+ }
+
+ if (!stktop)
+ stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+#ifndef STACK_GROWS_DOWNWARD
+ rtx base = stktop;
+ rtx end = wmarkr;
+#else
+ rtx base = wmarkr;
+ rtx end = stktop;
+#endif
+
+ /* We're going to modify it, so make sure it's not e.g. the stack pointer. */
+ base = copy_to_reg (base);
+
+ rtx_code_label *done = gen_label_rtx ();
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, done, NULL,
+ profile_probability::very_likely ());
+
+ if (optimize < 3)
+ expand_call (exp, NULL_RTX, true);
+ else
+ {
+ /* Ok, now we've determined we want to copy the block, so convert the
+ addresses to Pmode, as needed to dereference them to access ptr_mode
+ memory locations, so that we don't have to convert anything within the
+ loop. */
+ base = memory_address (ptr_mode, base);
+ end = memory_address (ptr_mode, end);
+
+ rtx zero = force_operand (const0_rtx, NULL_RTX);
+ int ulen = GET_MODE_SIZE (ptr_mode);
+
+ /* ??? It would be nice to use setmem or similar patterns here,
+ but they do not necessarily obey the stack growth direction,
+ which has security implications. We also have to avoid calls
+ (memset, bzero or any machine-specific ones), which are
+ likely unsafe here (see TARGET_STRUB_MAY_USE_MEMSET). */
+#ifndef STACK_GROWS_DOWNWARD
+ rtx incr = plus_constant (Pmode, base, ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, base);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (dstm, zero);
+ emit_move_insn (base, force_operand (incr, NULL_RTX));
+#else
+ rtx decr = plus_constant (Pmode, end, -ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, end);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (end, force_operand (decr, NULL_RTX));
+ emit_move_insn (dstm, zero);
+#endif
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ Pmode, NULL_RTX, NULL, loop,
+ profile_probability::very_likely ());
+ }
+
+ emit_label (done);
+
+ return const0_rtx;
+}
+
/* Expand EXP, a call to the alloca builtin. Return NULL_RTX if we
failed and the caller should emit a normal call. */
@@ -7608,6 +7856,27 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
case BUILT_IN_RETURN_ADDRESS:
return expand_builtin_frame_address (fndecl, exp);
+ case BUILT_IN_STACK_ADDRESS:
+ return expand_builtin_stack_address ();
+
+ case BUILT_IN___STRUB_ENTER:
+ target = expand_builtin_strub_enter (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_UPDATE:
+ target = expand_builtin_strub_update (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_LEAVE:
+ target = expand_builtin_strub_leave (exp);
+ if (target)
+ return target;
+ break;
+
/* Returns the address of the area where the structure is returned.
0 otherwise. */
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 1958b3abf598b..7dbaa803ab778 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -989,6 +989,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHRO
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
+DEF_GCC_BUILTIN (BUILT_IN_STACK_ADDRESS, "stack_address", BT_FN_PTR, ATTR_NULL)
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_ENTER, "__builtin___strub_enter")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_UPDATE, "__builtin___strub_update")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_LEAVE, "__builtin___strub_leave")
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
DEF_LIB_BUILTIN (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 365319e642b1a..31ca21803002f 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "common/common-target.h"
#include "langhooks.h"
#include "tree-inline.h"
+#include "ipa-strub.h"
#include "toplev.h"
#include "tree-iterator.h"
#include "opts.h"
@@ -69,6 +70,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_stack_protector_function_attribute (tree *, tree,
tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -321,6 +323,8 @@ const struct attribute_spec c_common_attribute_table[] =
{ "no_stack_protector", 0, 0, true, false, false, false,
handle_no_stack_protector_function_attribute,
attr_stack_protect_exclusions },
+ { "strub", 0, 1, false, true, false, true,
+ handle_strub_attribute, NULL },
{ "noinline", 0, 0, true, false, false, false,
handle_noinline_attribute,
attr_noinline_exclusions },
@@ -1430,6 +1434,84 @@ handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
return NULL_TREE;
}
+/* Handle a "strub" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
+ return NULL_TREE;
+}
+
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cedaaac3a45b7..177bd9dc5b7ac 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -153,7 +153,7 @@ public:
void remove (void);
/* Undo any definition or use of the symbol. */
- void reset (void);
+ void reset (bool preserve_comdat_group = false);
/* Dump symtab node to F. */
void dump (FILE *f);
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index bccd2f2abb5a3..9a550a5cce645 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -384,7 +384,7 @@ symbol_table::process_new_functions (void)
functions or variables. */
void
-symtab_node::reset (void)
+symtab_node::reset (bool preserve_comdat_group)
{
/* Reset our data structures so we can analyze the function again. */
analyzed = false;
@@ -395,7 +395,8 @@ symtab_node::reset (void)
cpp_implicit_alias = false;
remove_all_references ();
- remove_from_same_comdat_group ();
+ if (!preserve_comdat_group)
+ remove_from_same_comdat_group ();
if (cgraph_node *cn = dyn_cast <cgraph_node *> (this))
{
diff --git a/gcc/common.opt b/gcc/common.opt
index feea4920c9d75..d2e1d606b442d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2845,6 +2845,35 @@ fstrict-overflow
Common
Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer.
+fstrub=disable
+Common RejectNegative Var(flag_strub, 0)
+Disable stack scrub entirely, disregarding strub attributes.
+
+fstrub=strict
+Common RejectNegative Var(flag_strub, -4)
+Enable stack scrub as per attributes, with strict call checking.
+
+; If any strub-enabling attribute is seen when the default or strict
+; initializer values are in effect, flag_strub is bumped up by 2. The
+; scrub mode gate function will then bump these initializer values to
+; 0 if no strub-enabling attribute is seen. This minimizes the strub
+; overhead.
+fstrub=relaxed
+Common RejectNegative Var(flag_strub, -3) Init(-3)
+Restore default strub mode: as per attributes, with relaxed checking.
+
+fstrub=all
+Common RejectNegative Var(flag_strub, 3)
+Enable stack scrubbing for all viable functions.
+
+fstrub=at-calls
+Common RejectNegative Var(flag_strub, 1)
+Enable at-calls stack scrubbing for all viable functions.
+
+fstrub=internal
+Common RejectNegative Var(flag_strub, 2)
+Enable internal stack scrubbing for all viable functions.
+
fsync-libcalls
Common Var(flag_sync_libcalls) Init(1)
Implement __atomic operations via libcalls to legacy __sync functions.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f8b0bb53ef5d4..0e9edd35ca348 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -77,6 +77,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Function Names:: Printable strings which are the name of the current
function.
* Return Address:: Getting the return or frame address of a function.
+* Stack Scrubbing:: Stack scrubbing internal interfaces.
* Vector Extensions:: Using vector instructions through built-in functions.
* Offsetof:: Special syntax for implementing @code{offsetof}.
* __sync Builtins:: Legacy built-in functions for atomic memory access.
@@ -8950,6 +8951,263 @@ pid_t wait (wait_status_ptr_t p)
@}
@end smallexample
+@cindex @code{strub} type attribute
+@item strub
+This attribute defines stack-scrubbing properties of functions and
+variables. Being a type attribute, it attaches to types, even when
+specified in function and variable declarations. When applied to
+function types, it takes an optional string argument. When applied to a
+pointer-to-function type, if the optional argument is given, it gets
+propagated to the function type.
+
+@smallexample
+/* A strub variable. */
+int __attribute__ ((strub)) var;
+/* A strub variable that happens to be a pointer. */
+__attribute__ ((strub)) int *strub_ptr_to_int;
+/* A pointer type that may point to a strub variable. */
+typedef int __attribute__ ((strub)) *ptr_to_strub_int_type;
+
+/* A declaration of a strub function. */
+extern int __attribute__ ((strub)) foo (void);
+/* A pointer to that strub function. */
+int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo;
+@end smallexample
+
+A function associated with @code{at-calls} @code{strub} mode
+(@code{strub("at-calls")}, or just @code{strub}) undergoes interface
+changes. Its callers are adjusted to match the changes, and to scrub
+(overwrite with zeros) the stack space used by the called function after
+it returns. The interface change makes the function type incompatible
+with an unadorned but otherwise equivalent type, so @emph{every}
+declaration and every type that may be used to call the function must be
+associated with this strub mode.
+
+A function associated with @code{internal} @code{strub} mode
+(@code{strub("internal")}) retains an unmodified, type-compatible
+interface, but it may be turned into a wrapper that calls the wrapped
+body using a custom interface. The wrapper then scrubs the stack space
+used by the wrapped body. Though the wrapped body has its stack space
+scrubbed, the wrapper does not, so arguments and return values may
+remain unscrubbed even when such a function is called by another
+function that enables @code{strub}. This is why, when compiling with
+@option{-fstrub=strict}, a @code{strub} context is not allowed to call
+@code{internal} @code{strub} functions.
+
+@smallexample
+/* A declaration of an internal-strub function. */
+extern int __attribute__ ((strub ("internal"))) bar (void);
+
+int __attribute__ ((strub))
+baz (void)
+@{
+ /* Ok, foo was declared above as an at-calls strub function. */
+ foo ();
+ /* Not allowed in strict mode, otherwise allowed. */
+ bar ();
+@}
+@end smallexample
+
+An automatically-allocated variable associated with the @code{strub}
+attribute causes the (immediately) enclosing function to have
+@code{strub} enabled.
+
+A statically-allocated variable associated with the @code{strub}
+attribute causes functions that @emph{read} it, through its @code{strub}
+data type, to have @code{strub} enabled. Reading data by dereferencing
+a pointer to a @code{strub} data type has the same effect. Note: The
+attribute does not carry over from a composite type to the types of its
+components, so the intended effect may not be obtained with non-scalar
+types.
+
+When selecting a @code{strub}-enabled mode for a function that is not
+explicitly associated with one, because of @code{strub} variables or
+data pointers, the function must satisfy @code{internal} mode viability
+requirements (see below), even when @code{at-calls} mode is also viable
+and, being more efficient, ends up selected as an optimization.
+
+@smallexample
+/* zapme is implicitly strub-enabled because of strub variables.
+ Optimization may change its strub mode, but not the requirements. */
+static int
+zapme (int i)
+@{
+ /* A local strub variable enables strub. */
+ int __attribute__ ((strub)) lvar;
+ /* Reading strub data through a pointer-to-strub enables strub. */
+ lvar = * (ptr_to_strub_int_type) &i;
+ /* Writing to a global strub variable does not enable strub. */
+ var = lvar;
+ /* Reading from a global strub variable enables strub. */
+ return var;
+@}
+@end smallexample
+
+A @code{strub} context is the body (as opposed to the interface) of a
+function that has @code{strub} enabled, be it explicitly, by
+@code{at-calls} or @code{internal} mode, or implicitly, due to
+@code{strub} variables or command-line options.
+
+A function of a type associated with the @code{disabled} @code{strub}
+mode (@code{strub("disabled")} will not have its own stack space
+scrubbed. Such functions @emph{cannot} be called from within
+@code{strub} contexts.
+
+In order to enable a function to be called from within @code{strub}
+contexts without having its stack space scrubbed, associate it with the
+@code{callable} @code{strub} mode (@code{strub("callable")}).
+
+When a function is not assigned a @code{strub} mode, explicitly or
+implicitly, the mode defaults to @code{callable}, except when compiling
+with @option{-fstrub=strict}, that causes @code{strub} mode to default
+to @code{disabled}.
+
+@example
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+ /* Implicitly disabled with -fstrub=strict, otherwise callable. */
+extern int bah (void);
+
+int __attribute__ ((strub))
+bal (void)
+@{
+ /* Not allowed, bad is not strub-callable. */
+ bad ();
+ /* Ok, bac is strub-callable. */
+ bac ();
+ /* Not allowed with -fstrub=strict, otherwise allowed. */
+ bah ();
+@}
+@end example
+
+Function types marked @code{callable} and @code{disabled} are not
+mutually compatible types, but the underlying interfaces are compatible,
+so it is safe to convert pointers between them, and to use such pointers
+or alternate declarations to call them. Interfaces are also
+interchangeable between them and @code{internal} (but not
+@code{at-calls}!), but adding @code{internal} to a pointer type will not
+cause the pointed-to function to perform stack scrubbing.
+
+@example
+void __attribute__ ((strub))
+bap (void)
+@{
+ /* Assign a callable function to pointer-to-disabled.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac;
+ /* Not allowed: calls disabled type in a strub context. */
+ d_p ();
+
+ /* Assign a disabled function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an internal function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ c_p = bar;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an at-calls function to pointer-to-callable.
+ Flaggged as incompatible. */
+ c_p = bal;
+ /* The call through an interface-incompatible type will not use the
+ modified interface expected by the at-calls function, so it is
+ likely to misbehave at runtime. */
+ c_p ();
+@}
+@end example
+
+@code{Strub} contexts are never inlined into non-@code{strub} contexts.
+When an @code{internal}-strub function is split up, the wrapper can
+often be inlined, but the wrapped body @emph{never} is. A function
+marked as @code{always_inline}, even if explicitly assigned
+@code{internal} strub mode, will not undergo wrapping, so its body gets
+inlined as required.
+
+@example
+inline int __attribute__ ((strub ("at-calls")))
+inl_atc (void)
+@{
+ /* This body may get inlined into strub contexts. */
+@}
+
+inline int __attribute__ ((strub ("internal")))
+inl_int (void)
+@{
+ /* This body NEVER gets inlined, though its wrapper may. */
+@}
+
+inline int __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+@{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+@}
+
+void __attribute__ ((strub ("disabled")))
+bat (void)
+@{
+ /* Not allowed, cannot inline into a non-strub context. */
+ inl_int_ali ();
+@}
+@end example
+
+@cindex strub eligibility and viability
+Some @option{-fstrub=*} command line options enable @code{strub} modes
+implicitly where viable. A @code{strub} mode is only viable for a
+function if the function is eligible for that mode, and if other
+conditions, detailed below, are satisfied. If it's not eligible for a
+mode, attempts to explicitly associate it with that mode are rejected
+with an error message. If it is eligible, that mode may be assigned
+explicitly through this attribute, but implicit assignment through
+command-line options may involve additional viability requirements.
+
+A function is ineligible for @code{at-calls} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, if attribute
+@code{noipa} is present, or if it calls @code{__builtin_apply_args}.
+@code{At-calls} @code{strub} mode, if not requested through the function
+type, is only viable for an eligible function if the function is not
+visible to other translation units, if it doesn't have its address
+taken, and if it is never called with a function type overrider.
+
+@smallexample
+/* bar is eligible for at-calls strub mode,
+ but not viable for that mode because it is visible to other units.
+ It is eligible and viable for internal strub mode. */
+void bav () @{@}
+
+/* setp is eligible for at-calls strub mode,
+ but not viable for that mode because its address is taken.
+ It is eligible and viable for internal strub mode. */
+void setp (void) @{ static void (*p)(void); = setp; @}
+@end smallexample
+
+A function is ineligible for @code{internal} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, or if attribute
+@code{noipa} is present. For an @code{always_inline} function, meeting
+these requirements is enough to make it eligible. Any function that has
+attribute @code{noclone}, that uses such extensions as non-local labels,
+computed gotos, alternate variable argument passing interfaces,
+@code{__builtin_next_arg}, or @code{__builtin_return_address}, or that
+takes too many (about 64Ki) arguments is ineligible, unless it is
+@code{always_inline}. For @code{internal} @code{strub} mode, all
+eligible functions are viable.
+
+@smallexample
+/* flop is not eligible, thus not viable, for at-calls strub mode.
+ Likewise for internal strub mode. */
+__attribute__ ((noipa)) void flop (void) @{@}
+
+/* flip is eligible and viable for at-calls strub mode.
+ It would be ineligible for internal strub mode, because of noclone,
+ if it weren't for always_inline. With always_inline, noclone is not
+ an obstacle, so it is also eligible and viable for internal strub mode. */
+inline __attribute__ ((noclone, always_inline)) void flip (void) @{@}
+@end smallexample
+
@cindex @code{unused} type attribute
@item unused
When attached to a type (including a @code{union} or a @code{struct}),
@@ -12041,6 +12299,55 @@ option is in effect. Such calls should only be made in debugging
situations.
@enddefbuiltin
+@deftypefn {Built-in Function} {void *} __builtin_stack_address ()
+This function returns the value of the stack pointer register.
+@end deftypefn
+
+@node Stack Scrubbing
+@section Stack scrubbing internal interfaces
+
+Stack scrubbing involves cooperation between a @code{strub} context,
+i.e., a function whose stack frame is to be zeroed-out, and its callers.
+The caller initializes a stack watermark, the @code{strub} context
+updates the watermark according to its stack use, and the caller zeroes
+it out once it regains control, whether by the callee's returning or by
+an exception.
+
+Each of these steps is performed by a different builtin function call.
+Calls to these builtins are introduced automatically, in response to
+@code{strub} attributes and command-line options; they are not expected
+to be explicitly called by source code.
+
+The functions that implement the builtins are available in libgcc but,
+depending on optimization levels, they are expanded internally, adjusted
+to account for inlining, and sometimes combined/deferred (e.g. passing
+the caller-supplied watermark on to callees, refraining from erasing
+stack areas that the caller will) to enable tail calls and to optimize
+for code size.
+
+@deftypefn {Built-in Function} {void} __builtin___strub_enter (void **@var{wmptr})
+This function initializes a stack @var{watermark} variable with the
+current top of the stack. A call to this builtin function is introduced
+before entering a @code{strub} context. It remains as a function call
+if optimization is not enabled.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_update (void **@var{wmptr})
+This function updates a stack @var{watermark} variable with the current
+top of the stack, if it tops the previous watermark. A call to this
+builtin function is inserted within @code{strub} contexts, whenever
+additional stack space may have been used. It remains as a function
+call at optimization levels lower than 2.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_leave (void **@var{wmptr})
+This function overwrites the memory area between the current top of the
+stack, and the @var{watermark}ed address. A call to this builtin
+function is inserted after leaving a @code{strub} context. It remains
+as a function call at optimization levels lower than 3, and it is guarded by
+a condition at level 2.
+@end deftypefn
+
@node Vector Extensions
@section Using Vector Instructions through Built-in Functions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 45a9f2372c969..b8c3c2863fa74 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -642,6 +642,8 @@ Objective-C and Objective-C++ Dialects}.
-fstack-protector-explicit -fstack-check
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
-fno-stack-limit -fsplit-stack
+-fstrub=disable -fstrub=strict -fstrub=relaxed
+-fstrub=all -fstrub=at-calls -fstrub=internal
-fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
-fvtv-counts -fvtv-debug
-finstrument-functions -finstrument-functions-once
@@ -17449,6 +17451,56 @@ without @option{-fsplit-stack} always has a large stack. Support for
this is implemented in the gold linker in GNU binutils release 2.21
and later.
+@opindex -fstrub=disable
+@item -fstrub=disable
+Disable stack scrubbing entirely, ignoring any @code{strub} attributes.
+See @xref{Common Type Attributes}.
+
+@opindex fstrub=strict
+@item -fstrub=strict
+Functions default to @code{strub} mode @code{disabled}, and apply
+@option{strict}ly the restriction that only functions associated with
+@code{strub}-@code{callable} modes (@code{at-calls}, @code{callable} and
+@code{always_inline} @code{internal}) are @code{callable} by functions
+with @code{strub}-enabled modes (@code{at-calls} and @code{internal}).
+
+@opindex fstrub=relaxed
+@item -fstrub=relaxed
+Restore the default stack scrub (@code{strub}) setting, namely,
+@code{strub} is only enabled as required by @code{strub} attributes
+associated with function and data types. @code{Relaxed} means that
+strub contexts are only prevented from calling functions explicitly
+associated with @code{strub} mode @code{disabled}. This option is only
+useful to override other @option{-fstrub=*} options that precede it in
+the command line.
+
+@opindex fstrub=at-calls
+@item -fstrub=at-calls
+Enable @code{at-calls} @code{strub} mode where viable. The primary use
+of this option is for testing. It exercises the @code{strub} machinery
+in scenarios strictly local to a translation unit. This @code{strub}
+mode modifies function interfaces, so any function that is visible to
+other translation units, or that has its address taken, will @emph{not}
+be affected by this option. Optimization options may also affect
+viability. See the @code{strub} attribute documentation for details on
+viability and eligibility requirements.
+
+@opindex fstrub=internal
+@item -fstrub=internal
+Enable @code{internal} @code{strub} mode where viable. The primary use
+of this option is for testing. This option is intended to exercise
+thoroughly parts of the @code{strub} machinery that implement the less
+efficient, but interface-preserving @code{strub} mode. Functions that
+would not be affected by this option are quite uncommon.
+
+@opindex fstrub=all
+@item -fstrub=all
+Enable some @code{strub} mode where viable. When both strub modes are
+viable, @code{at-calls} is preferred. @option{-fdump-ipa-strubm} adds
+function attributes that tell which mode was selected for each function.
+The primary use of this option is for testing, to exercise thoroughly
+the @code{strub} machinery.
+
@opindex fvtable-verify
@item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
This option is only available when compiling C++ code.
@@ -19354,6 +19406,14 @@ and inlining decisions.
@item inline
Dump after function inlining.
+@item strubm
+Dump after selecting @code{strub} modes, and recording the selections as
+function attributes.
+
+@item strub
+Dump @code{strub} transformations: interface changes, function wrapping,
+and insertion of builtin calls for stack scrubbing and watermarking.
+
@end table
Additionally, the options @option{-optimized}, @option{-missed},
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 95ba56e05ae4a..903ebecc8e4d3 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3399,6 +3399,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 4ac96dc357d35..25dbb37fb9445 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2648,6 +2648,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc
index efc8df7d4e0f6..3f8299b8ef47e 100644
--- a/gcc/ipa-inline.cc
+++ b/gcc/ipa-inline.cc
@@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "ipa-strub.h"
/* Inliner uses greedy algorithm to inline calls in a priority order.
Badness is used as the key in a Fibonacci heap which roughly corresponds
@@ -443,6 +444,11 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
inlinable = false;
}
+ if (inlinable && !strub_inlinable_to_p (callee, caller))
+ {
+ e->inline_failed = CIF_UNSPECIFIED;
+ inlinable = false;
+ }
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc
index 6730f4f9d0e31..1a7285ff5dcf8 100644
--- a/gcc/ipa-split.cc
+++ b/gcc/ipa-split.cc
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-fnsummary.h"
#include "cfgloop.h"
#include "attribs.h"
+#include "ipa-strub.h"
/* Per basic block info. */
@@ -1811,6 +1812,12 @@ execute_split_functions (void)
"section.\n");
return 0;
}
+ if (!strub_splittable_p (node))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not splitting: function is a strub context.\n");
+ return 0;
+ }
/* We enforce splitting after loop headers when profile info is not
available. */
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
new file mode 100644
index 0000000000000..73a8771315c35
--- /dev/null
+++ b/gcc/ipa-strub.cc
@@ -0,0 +1,3450 @@
+/* strub (stack scrubbing) support.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "tree-cfg.h"
+#include "cfghooks.h"
+#include "cfgloop.h"
+#include "cfgcleanup.h"
+#include "tree-eh.h"
+#include "except.h"
+#include "builtins.h"
+#include "attribs.h"
+#include "tree-inline.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "ipa-fnsummary.h"
+#include "gimple-fold.h"
+#include "fold-const.h"
+#include "gimple-walk.h"
+#include "tree-dfa.h"
+#include "langhooks.h"
+#include "calls.h"
+#include "vec.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "alias.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "ipa-strub.h"
+#include "symtab-thunks.h"
+#include "attr-fnspec.h"
+
+/* Const and pure functions that gain a watermark parameter for strub purposes
+ are still regarded as such, which may cause the inline expansions of the
+ __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
+ us to inform the backend about requirements and side effects of the call, but
+ call_fusage building in calls.c:expand_call does not even look at
+ attr_fnspec, so we resort to asm loads and updates to attain an equivalent
+ effect. Once expand_call gains the ability to issue extra memory uses and
+ clobbers based on pure/const function's fnspec, we can define this to 1. */
+#define ATTR_FNSPEC_DECONST_WATERMARK 0
+
+enum strub_mode {
+ /* This mode denotes a regular function, that does not require stack
+ scrubbing (strubbing). It may call any other functions, but if
+ it calls AT_CALLS (or WRAPPED) ones, strubbing logic is
+ automatically introduced around those calls (the latter, by
+ inlining INTERNAL wrappers). */
+ STRUB_DISABLED = 0,
+
+ /* This denotes a function whose signature is (to be) modified to
+ take an extra parameter, for stack use annotation, and its
+ callers must initialize and pass that argument, and perform the
+ strubbing. Functions that are explicitly marked with attribute
+ strub must have the mark visible wherever the function is,
+ including aliases, and overriders and overriding methods.
+ Functions that are implicitly marked for strubbing, for accessing
+ variables explicitly marked as such, will only select this
+ strubbing method if they are internal to a translation unit. It
+ can only be inlined into other strubbing functions, i.e.,
+ STRUB_AT_CALLS or STRUB_WRAPPED. */
+ STRUB_AT_CALLS = 1,
+
+ /* This denotes a function that is to perform strubbing internally,
+ without any changes to its interface (the function is turned into
+ a strubbing wrapper, and its original body is moved to a separate
+ STRUB_WRAPPED function, with a modified interface). Functions
+ may be explicitly marked with attribute strub(2), and the
+ attribute must be visible at the point of definition. Functions
+ that are explicitly marked for strubbing, for accessing variables
+ explicitly marked as such, may select this strubbing mode if
+ their interface cannot change, e.g. because its interface is
+ visible to other translation units, directly, by indirection
+ (having its address taken), inheritance, etc. Functions that use
+ this method must not have the noclone attribute, nor the noipa
+ one. Functions marked as always_inline may select this mode, but
+ they are NOT wrapped, they remain unchanged, and are only inlined
+ into strubbed contexts. Once non-always_inline functions are
+ wrapped, the wrapper becomes STRUB_WRAPPER, and the wrapped becomes
+ STRUB_WRAPPED. */
+ STRUB_INTERNAL = 2,
+
+ /* This denotes a function whose stack is not strubbed, but that is
+ nevertheless explicitly or implicitly marked as callable from strubbing
+ functions. Normally, only STRUB_AT_CALLS (and STRUB_INTERNAL ->
+ STRUB_WRAPPED) functions can be called from strubbing contexts (bodies of
+ STRUB_AT_CALLS, STRUB_INTERNAL and STRUB_WRAPPED functions), but attribute
+ strub(3) enables other functions to be (indirectly) called from these
+ contexts. Some builtins and internal functions may be implicitly marked as
+ STRUB_CALLABLE. */
+ STRUB_CALLABLE = 3,
+
+ /* This denotes the function that took over the body of a
+ STRUB_INTERNAL function. At first, it's only called by its
+ wrapper, but the wrapper may be inlined. The wrapped function,
+ in turn, can only be inlined into other functions whose stack
+ frames are strubbed, i.e., that are STRUB_WRAPPED or
+ STRUB_AT_CALLS. */
+ STRUB_WRAPPED = -1,
+
+ /* This denotes the wrapper function that replaced the STRUB_INTERNAL
+ function. This mode overrides the STRUB_INTERNAL mode at the time the
+ internal to-be-wrapped function becomes a wrapper, so that inlining logic
+ can tell one from the other. */
+ STRUB_WRAPPER = -2,
+
+ /* This denotes an always_inline function that requires strubbing. It can
+ only be called from, and inlined into, other strubbing contexts. */
+ STRUB_INLINABLE = -3,
+
+ /* This denotes a function that accesses strub variables, so it would call for
+ internal strubbing (whether or not it's eligible for that), but since
+ at-calls strubbing is viable, that's selected as an optimization. This
+ mode addresses the inconvenience that such functions may have different
+ modes selected depending on optimization flags, and get a different
+ callable status depending on that choice: if we assigned them
+ STRUB_AT_CALLS mode, they would be callable when optimizing, whereas
+ STRUB_INTERNAL would not be callable. */
+ STRUB_AT_CALLS_OPT = -4,
+
+};
+
+/* Look up a strub attribute in TYPE, and return it. */
+
+static tree
+get_strub_attr_from_type (tree type)
+{
+ return lookup_attribute ("strub", TYPE_ATTRIBUTES (type));
+}
+
+/* Look up a strub attribute in DECL or in its type, and return it. */
+
+static tree
+get_strub_attr_from_decl (tree decl)
+{
+ tree ret = lookup_attribute ("strub", DECL_ATTRIBUTES (decl));
+ if (ret)
+ return ret;
+ return get_strub_attr_from_type (TREE_TYPE (decl));
+}
+
+/* Define a function to cache identifier ID, to be used as a strub attribute
+ parameter for a strub mode named after NAME. */
+#define DEF_STRUB_IDS(NAME, ID) \
+static inline tree get_strub_mode_id_ ## NAME () { \
+ static tree identifier = NULL_TREE; \
+ if (!identifier) \
+ identifier = get_identifier (ID); \
+ return identifier; \
+}
+/* Same as DEF_STRUB_IDS, but use the string expansion of NAME as ID. */
+#define DEF_STRUB_ID(NAME) \
+DEF_STRUB_IDS (NAME, #NAME)
+
+/* Define functions for each of the strub mode identifiers.
+ Expose dashes rather than underscores. */
+DEF_STRUB_ID (disabled)
+DEF_STRUB_IDS (at_calls, "at-calls")
+DEF_STRUB_ID (internal)
+DEF_STRUB_ID (callable)
+DEF_STRUB_ID (wrapped)
+DEF_STRUB_ID (wrapper)
+DEF_STRUB_ID (inlinable)
+DEF_STRUB_IDS (at_calls_opt, "at-calls-opt")
+
+/* Release the temporary macro names. */
+#undef DEF_STRUB_IDS
+#undef DEF_STRUB_ID
+
+/* Return the identifier corresponding to strub MODE. */
+
+static tree
+get_strub_mode_attr_parm (enum strub_mode mode)
+{
+ switch (mode)
+ {
+ case STRUB_DISABLED:
+ return get_strub_mode_id_disabled ();
+
+ case STRUB_AT_CALLS:
+ return get_strub_mode_id_at_calls ();
+
+ case STRUB_INTERNAL:
+ return get_strub_mode_id_internal ();
+
+ case STRUB_CALLABLE:
+ return get_strub_mode_id_callable ();
+
+ case STRUB_WRAPPED:
+ return get_strub_mode_id_wrapped ();
+
+ case STRUB_WRAPPER:
+ return get_strub_mode_id_wrapper ();
+
+ case STRUB_INLINABLE:
+ return get_strub_mode_id_inlinable ();
+
+ case STRUB_AT_CALLS_OPT:
+ return get_strub_mode_id_at_calls_opt ();
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the parmeters (TREE_VALUE) for a strub attribute of MODE.
+ We know we use a single parameter, so we bypass the creation of a
+ tree list. */
+
+static tree
+get_strub_mode_attr_value (enum strub_mode mode)
+{
+ return get_strub_mode_attr_parm (mode);
+}
+
+/* Determine whether ID is a well-formed strub mode-specifying attribute
+ parameter for a function (type). Only user-visible modes are accepted, and
+ ID must be non-NULL.
+
+ For unacceptable parms, return 0, otherwise a nonzero value as below.
+
+ If the parm enables strub, return positive, otherwise negative.
+
+ If the affected type must be a distinct, incompatible type,return an integer
+ of absolute value 2, otherwise 1. */
+
+int
+strub_validate_fn_attr_parm (tree id)
+{
+ int ret;
+ const char *s = NULL;
+ size_t len = 0;
+
+ /* do NOT test for NULL. This is only to be called with non-NULL arguments.
+ We assume that the strub parameter applies to a function, because only
+ functions accept an explicit argument. If we accepted NULL, and we
+ happened to be called to verify the argument for a variable, our return
+ values would be wrong. */
+ if (TREE_CODE (id) == STRING_CST)
+ {
+ s = TREE_STRING_POINTER (id);
+ len = TREE_STRING_LENGTH (id) - 1;
+ }
+ else if (TREE_CODE (id) == IDENTIFIER_NODE)
+ {
+ s = IDENTIFIER_POINTER (id);
+ len = IDENTIFIER_LENGTH (id);
+ }
+ else
+ return 0;
+
+ enum strub_mode mode;
+
+ if (len != 8)
+ return 0;
+
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ ret = -1;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ ret = 2;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ ret = 1;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ ret = -2;
+ break;
+
+ default:
+ /* Other parms are for internal use only. */
+ return 0;
+ }
+
+ tree mode_id = get_strub_mode_attr_parm (mode);
+
+ if (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id != mode_id
+ : strncmp (s, IDENTIFIER_POINTER (mode_id), len) != 0)
+ return 0;
+
+ return ret;
+}
+
+/* Return the strub mode from STRUB_ATTR. VAR_P should be TRUE if the attribute
+ is taken from a variable, rather than from a function, or a type thereof. */
+
+static enum strub_mode
+get_strub_mode_from_attr (tree strub_attr, bool var_p = false)
+{
+ enum strub_mode mode = STRUB_DISABLED;
+
+ if (strub_attr)
+ {
+ if (!TREE_VALUE (strub_attr))
+ mode = !var_p ? STRUB_AT_CALLS : STRUB_INTERNAL;
+ else
+ {
+ gcc_checking_assert (!var_p);
+ tree id = TREE_VALUE (strub_attr);
+ if (TREE_CODE (id) == TREE_LIST)
+ id = TREE_VALUE (id);
+ const char *s = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_POINTER (id)
+ : IDENTIFIER_POINTER (id));
+ size_t len = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_LENGTH (id) - 1
+ : IDENTIFIER_LENGTH (id));
+
+ switch (len)
+ {
+ case 7:
+ switch (s[6])
+ {
+ case 'r':
+ mode = STRUB_WRAPPER;
+ break;
+
+ case 'd':
+ mode = STRUB_WRAPPED;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 8:
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 9:
+ mode = STRUB_INLINABLE;
+ break;
+
+ case 12:
+ mode = STRUB_AT_CALLS_OPT;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id == get_strub_mode_attr_parm (mode)
+ : strncmp (IDENTIFIER_POINTER
+ (get_strub_mode_attr_parm (mode)),
+ s, len) == 0);
+ }
+ }
+
+ return mode;
+}
+
+/* Look up, decode and return the strub mode associated with FNDECL. */
+
+static enum strub_mode
+get_strub_mode_from_fndecl (tree fndecl)
+{
+ return get_strub_mode_from_attr (get_strub_attr_from_decl (fndecl));
+}
+
+/* Look up, decode and return the strub mode associated with NODE. */
+
+static enum strub_mode
+get_strub_mode (cgraph_node *node)
+{
+ return get_strub_mode_from_fndecl (node->decl);
+}
+
+/* Look up, decode and return the strub mode associated with TYPE. */
+
+static enum strub_mode
+get_strub_mode_from_type (tree type)
+{
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (type);
+ tree attr = get_strub_attr_from_type (type);
+
+ if (attr)
+ return get_strub_mode_from_attr (attr, var_p);
+
+ if (flag_strub >= -1 && !var_p)
+ return STRUB_CALLABLE;
+
+ return STRUB_DISABLED;
+}
+
+\f
+/* Return TRUE iff NODE calls builtin va_start. */
+
+static bool
+calls_builtin_va_start_p (cgraph_node *node)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (fndecl_built_in_p (cdecl, BUILT_IN_VA_START))
+ return true;
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE calls builtin apply_args, and optionally REPORT it. */
+
+static bool
+calls_builtin_apply_args_p (cgraph_node *node, bool report = false)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!fndecl_built_in_p (cdecl, BUILT_IN_APPLY_ARGS))
+ continue;
+
+ result = true;
+
+ if (!report)
+ break;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "at-calls %<strub%> does not support call to %qD",
+ cdecl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE carries the always_inline attribute. */
+
+static inline bool
+strub_always_inline_p (cgraph_node *node)
+{
+ return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
+}
+
+/* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
+ optionally REPORT the reasons for ineligibility. */
+
+static inline bool
+can_strub_p (cgraph_node *node, bool report = false)
+{
+ bool result = true;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<noipa%>",
+ node->decl);
+ }
+
+ /* We can't, and don't want to vectorize the watermark and other
+ strub-introduced parms. */
+ if (lookup_attribute ("simd", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<simd%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE is eligible for at-calls strub, and optionally REPORT
+ the reasons for ineligibility. Besides general non-eligibility for
+ strub-enabled modes, at-calls rules out calling builtin apply_args. */
+
+static bool
+can_strub_at_calls_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ return !calls_builtin_apply_args_p (node, report);
+}
+
+/* Return TRUE iff the called function (pointer or, if available,
+ decl) undergoes a significant type conversion for the call. Strub
+ mode changes between function types, and other non-useless type
+ conversions, are regarded as significant. When the function type
+ is overridden, the effective strub mode for the call is that of the
+ call fntype, rather than that of the pointer or of the decl.
+ Functions called with type overrides cannot undergo type changes;
+ it's as if their address was taken, so they're considered
+ non-viable for implicit at-calls strub mode. */
+
+static inline bool
+strub_call_fntype_override_p (const gcall *gs)
+{
+ if (gimple_call_internal_p (gs))
+ return false;
+ tree fn_type = TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+ if (tree decl = gimple_call_fndecl (gs))
+ fn_type = TREE_TYPE (decl);
+
+ /* We do NOT want to take the mode from the decl here. This
+ function is used to tell whether we can change the strub mode of
+ a function, and whether the effective mode for the call is to be
+ taken from the decl or from an overrider type. When the strub
+ mode is explicitly declared, or overridden with a type cast, the
+ difference will be noticed in function types. However, if the
+ strub mode is implicit due to e.g. strub variables or -fstrub=*
+ command-line flags, we will adjust call types along with function
+ types. In either case, the presence of type or strub mode
+ overriders in calls will prevent a function from having its strub
+ modes changed in ways that would imply type changes, but taking
+ strub modes from decls would defeat this, since we set strub
+ modes and then call this function to tell whether the original
+ type was overridden to decide whether to adjust the call. We
+ need the answer to be about the type, not the decl. */
+ enum strub_mode mode = get_strub_mode_from_type (fn_type);
+ return (get_strub_mode_from_type (gs->u.fntype) != mode
+ || !useless_type_conversion_p (gs->u.fntype, fn_type));
+}
+
+/* Return TRUE iff NODE is called directly with a type override. */
+
+static bool
+called_directly_with_type_override_p (cgraph_node *node, void *)
+{
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ if (e->call_stmt && strub_call_fntype_override_p (e->call_stmt))
+ return true;
+
+ return false;
+}
+
+/* Return TRUE iff NODE or any other nodes aliased to it are called
+ with type overrides. We can't safely change the type of such
+ functions. */
+
+static bool
+called_with_type_override_p (cgraph_node *node)
+{
+ return (node->call_for_symbol_thunks_and_aliases
+ (called_directly_with_type_override_p, NULL, true, true));
+}
+
+/* Symbolic macro for the max number of arguments that internal strub may add to
+ a function. */
+
+#define STRUB_INTERNAL_MAX_EXTRA_ARGS 3
+
+/* We can't perform internal strubbing if the function body involves certain
+ features:
+
+ - a non-default __builtin_va_start (e.g. x86's __builtin_ms_va_start) is
+ currently unsupported because we can't discover the corresponding va_copy and
+ va_end decls in the wrapper, and we don't convey the alternate variable
+ arguments ABI to the modified wrapped function. The default
+ __builtin_va_start is supported by calling va_start/va_end at the wrapper,
+ that takes variable arguments, passing a pointer to the va_list object to the
+ wrapped function, that runs va_copy from it where the original function ran
+ va_start.
+
+ __builtin_next_arg is currently unsupported because the wrapped function
+ won't be a variable argument function. We could process it in the wrapper,
+ that remains a variable argument function, and replace calls in the wrapped
+ body, but we currently don't.
+
+ __builtin_return_address is rejected because it's generally used when the
+ actual caller matters, and introducing a wrapper breaks such uses as those in
+ the unwinder. */
+
+static bool
+can_strub_internally_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ /* Since we're not changing the function identity proper, just
+ moving its full implementation, we *could* disable
+ fun->cannot_be_copied_reason and/or temporarily drop a noclone
+ attribute, but we'd have to prevent remapping of the labels. */
+ if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%>"
+ " because of attribute %<noclone%>",
+ node->decl);
+ }
+
+ if (node->has_gimple_body_p ())
+ {
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!((fndecl_built_in_p (cdecl, BUILT_IN_VA_START)
+ && cdecl != builtin_decl_explicit (BUILT_IN_VA_START))
+ || fndecl_built_in_p (cdecl, BUILT_IN_NEXT_ARG)
+ || fndecl_built_in_p (cdecl, BUILT_IN_RETURN_ADDRESS)))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it calls %qD",
+ node->decl, cdecl);
+ }
+
+ struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
+ if (fun->has_nonlocal_label)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it contains a non-local goto target",
+ node->decl);
+ }
+
+ if (fun->has_forced_label_in_static)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because the address of a local label escapes",
+ node->decl);
+ }
+
+ /* Catch any other case that would prevent versioning/cloning
+ so as to also have it covered above. */
+ gcc_checking_assert (!result /* || !node->has_gimple_body_p () */
+ || tree_versionable_function_p (node->decl));
+
+
+ /* Label values references are not preserved when copying. If referenced
+ in nested functions, as in 920415-1.c and 920721-4.c their decls get
+ remapped independently. The exclusion below might be too broad, in
+ that we might be able to support correctly cases in which the labels
+ are only used internally in a function, but disconnecting forced labels
+ from their original declarations is undesirable in general. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
+ tree target;
+
+ if (!label_stmt)
+ break;
+
+ target = gimple_label_label (label_stmt);
+
+ if (!FORCED_LABEL (target))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (gimple_location (label_stmt),
+ "internal %<strub%> does not support forced labels");
+ }
+ }
+
+ if (list_length (TYPE_ARG_TYPES (TREE_TYPE (node->decl)))
+ >= (((HOST_WIDE_INT) 1 << IPA_PARAM_MAX_INDEX_BITS)
+ - STRUB_INTERNAL_MAX_EXTRA_ARGS))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD has too many arguments for internal %<strub%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE has any strub-requiring local variable, or accesses (as
+ in reading) any variable through a strub-requiring type. */
+
+static bool
+strub_from_body_p (cgraph_node *node)
+{
+ if (!node->has_gimple_body_p ())
+ return false;
+
+ /* If any local variable is marked for strub... */
+ unsigned i;
+ tree var;
+ FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (node->decl),
+ i, var)
+ if (get_strub_mode_from_type (TREE_TYPE (var))
+ != STRUB_DISABLED)
+ return true;
+
+ /* Now scan the body for loads with strub-requiring types.
+ ??? Compound types don't propagate the strub requirement to
+ component types. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (!gimple_assign_load_p (stmt))
+ continue;
+
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if (get_strub_mode_from_type (TREE_TYPE (rhs))
+ != STRUB_DISABLED)
+ return true;
+ }
+
+ return false;
+}
+
+/* Return TRUE iff node is associated with a builtin that should be callable
+ from strub contexts. */
+
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* This temporarily allocates stack for the call, and we can't reasonably
+ update the watermark for that. Besides, we don't check the actual call
+ target, nor its signature, and it seems to be overkill to as much as
+ try to do so. */
+ case BUILT_IN_APPLY:
+ return false;
+
+ /* Conversely, this shouldn't be called from within strub contexts, since
+ the caller may have had its signature modified. STRUB_INTERNAL is ok,
+ the call will remain in the STRUB_WRAPPER, and removed from the
+ STRUB_WRAPPED clone. */
+ case BUILT_IN_APPLY_ARGS:
+ return false;
+
+ /* ??? Make all other builtins callable. We wish to make any builtin call
+ the compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
+/* Compute the strub mode to be used for NODE. STRUB_ATTR should be the strub
+ attribute,found for NODE, if any. */
+
+static enum strub_mode
+compute_strub_mode (cgraph_node *node, tree strub_attr)
+{
+ enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr);
+
+ gcc_checking_assert (flag_strub >= -2 && flag_strub <= 3);
+
+ /* Symbolic encodings of the -fstrub-* flags. */
+ /* Enable strub when explicitly requested through attributes to functions or
+ variables, reporting errors if the requests cannot be satisfied. */
+ const bool strub_flag_auto = flag_strub < 0;
+ /* strub_flag_auto with strub call verification; without this, functions are
+ implicitly callable. */
+ const bool strub_flag_strict = flag_strub < -1;
+ /* Disable strub altogether, ignore attributes entirely. */
+ const bool strub_flag_disabled = flag_strub == 0;
+ /* On top of _auto, also enable strub implicitly for functions that can
+ safely undergo at-calls strubbing. Internal mode will still be used in
+ functions that request it explicitly with attribute strub(2), or when the
+ function body requires strubbing and at-calls strubbing is not viable. */
+ const bool strub_flag_at_calls = flag_strub == 1;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo internal strubbing. At-calls mode will still be used in
+ functions that requiest it explicitly with attribute strub() or strub(1),
+ or when the function body requires strubbing and internal strubbing is not
+ viable. */
+ const bool strub_flag_internal = flag_strub == 2;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo strubbing in either mode. When both modes are viable,
+ at-calls is preferred. */
+ const bool strub_flag_either = flag_strub == 3;
+ /* Besides the default behavior, enable strub implicitly for all viable
+ functions. */
+ const bool strub_flag_viable = flag_strub > 0;
+
+ /* The consider_* variables should be TRUE if selecting the corresponding
+ strub modes would be consistent with requests from attributes and command
+ line flags. Attributes associated with functions pretty much mandate a
+ selection, and should report an error if not satisfied; strub_flag_auto
+ implicitly enables some viable strub mode if that's required by references
+ to variables marked for strub; strub_flag_viable enables strub if viable
+ (even when favoring one mode, body-requested strub can still be satisfied
+ by either mode), and falls back to callable, silently unless variables
+ require strubbing. */
+
+ const bool consider_at_calls
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_AT_CALLS
+ : true));
+ const bool consider_internal
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_INTERNAL
+ : true));
+
+ const bool consider_callable
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_CALLABLE
+ : (!strub_flag_strict
+ || strub_callable_builtin_p (node))));
+
+ /* This is a shorthand for either strub-enabled mode. */
+ const bool consider_strub
+ = (consider_at_calls || consider_internal);
+
+ /* We can cope with always_inline functions even with noipa and noclone,
+ because we just leave them alone. */
+ const bool is_always_inline
+ = strub_always_inline_p (node);
+
+ /* Strubbing in general, and each specific strub mode, may have its own set of
+ requirements. We require noipa for strubbing, either because of cloning
+ required for internal strub, or because of caller enumeration required for
+ at-calls strub. We don't consider the at-calls mode eligible if it's not
+ even considered, it has no further requirements. Internal mode requires
+ cloning and the absence of certain features in the body and, like at-calls,
+ it's not eligible if it's not even under consideration.
+
+ ??? Do we need target hooks for further constraints? E.g., x86's
+ "interrupt" attribute breaks internal strubbing because the wrapped clone
+ carries the attribute and thus isn't callable; in this case, we could use a
+ target hook to adjust the clone instead. */
+ const bool strub_eligible
+ = (consider_strub
+ && (is_always_inline || can_strub_p (node)));
+ const bool at_calls_eligible
+ = (consider_at_calls && strub_eligible
+ && can_strub_at_calls_p (node));
+ const bool internal_eligible
+ = (consider_internal && strub_eligible
+ && (is_always_inline
+ || can_strub_internally_p (node)));
+
+ /* In addition to the strict eligibility requirements, some additional
+ constraints are placed on implicit selection of certain modes. These do
+ not prevent the selection of a mode if explicitly specified as part of a
+ function interface (the strub attribute), but they may prevent modes from
+ being selected by the command line or by function bodies. The only actual
+ constraint is on at-calls mode: since we change the function's exposed
+ signature, we won't do it implicitly if the function can possibly be used
+ in ways that do not expect the signature change, e.g., if the function is
+ available to or interposable by other units, if its address is taken,
+ etc. */
+ const bool at_calls_viable
+ = (at_calls_eligible
+ && (strub_attr
+ || (node->has_gimple_body_p ()
+ && (!node->externally_visible
+ || (node->binds_to_current_def_p ()
+ && node->can_be_local_p ()))
+ && node->only_called_directly_p ()
+ && !called_with_type_override_p (node))));
+ const bool internal_viable
+ = (internal_eligible);
+
+ /* Shorthand. */
+ const bool strub_viable
+ = (at_calls_viable || internal_viable);
+
+ /* We wish to analyze the body, to look for implicit requests for strub, both
+ to implicitly enable it when the body calls for it, and to report errors if
+ the body calls for it but neither mode is viable (even if that follows from
+ non-eligibility because of the explicit specification of some non-strubbing
+ mode). We can refrain from scanning the body only in rare circumstances:
+ when strub is enabled by a function attribute (scanning might be redundant
+ in telling us to also enable it), and when we are enabling strub implicitly
+ but there are non-viable modes: we want to know whether strubbing is
+ required, to fallback to another mode, even if we're only enabling a
+ certain mode, or, when either mode would do, to report an error if neither
+ happens to be viable. */
+ const bool analyze_body
+ = (strub_attr
+ ? !consider_strub
+ : (strub_flag_auto
+ || (strub_flag_viable && (!at_calls_viable && !internal_viable))
+ || (strub_flag_either && !strub_viable)));
+
+ /* Cases in which strubbing is enabled or disabled by strub_flag_auto.
+ Unsatisfiable requests ought to be reported. */
+ const bool strub_required
+ = ((strub_attr && consider_strub)
+ || (analyze_body && strub_from_body_p (node)));
+
+ /* Besides the required cases, we want to abide by the requests to enabling on
+ an if-viable basis. */
+ const bool strub_enable
+ = (strub_required
+ || (strub_flag_at_calls && at_calls_viable)
+ || (strub_flag_internal && internal_viable)
+ || (strub_flag_either && strub_viable));
+
+ /* And now we're finally ready to select a mode that abides by the viability
+ and eligibility constraints, and that satisfies the strubbing requirements
+ and requests, subject to the constraints. If both modes are viable and
+ strub is to be enabled, pick STRUB_AT_CALLS unless STRUB_INTERNAL was named
+ as preferred. */
+ const enum strub_mode mode
+ = ((strub_enable && is_always_inline)
+ ? (strub_required ? STRUB_INLINABLE : STRUB_CALLABLE)
+ : (strub_enable && internal_viable
+ && (strub_flag_internal || !at_calls_viable))
+ ? STRUB_INTERNAL
+ : (strub_enable && at_calls_viable)
+ ? (strub_required && !strub_attr
+ ? STRUB_AT_CALLS_OPT
+ : STRUB_AT_CALLS)
+ : consider_callable
+ ? STRUB_CALLABLE
+ : STRUB_DISABLED);
+
+ switch (mode)
+ {
+ case STRUB_CALLABLE:
+ if (is_always_inline)
+ break;
+ /* Fall through. */
+
+ case STRUB_DISABLED:
+ if (strub_enable && !strub_attr)
+ {
+ gcc_checking_assert (analyze_body);
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD requires %<strub%>,"
+ " but no viable %<strub%> mode was found",
+ node->decl);
+ break;
+ }
+ /* Fall through. */
+
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ /* Differences from an mode requested through a function attribute are
+ reported in set_strub_mode_to. */
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ /* Functions that select this mode do so because of references to strub
+ variables. Even if we choose at-calls as an optimization, the
+ requirements for internal strub must still be satisfied. Optimization
+ options may render implicit at-calls strub not viable (-O0 sets
+ force_output for static non-inline functions), and it would not be good
+ if changing optimization options turned a well-formed into an
+ ill-formed one. */
+ if (!internal_viable)
+ can_strub_internally_p (node, true);
+ break;
+
+ case STRUB_WRAPPED:
+ case STRUB_WRAPPER:
+ default:
+ gcc_unreachable ();
+ }
+
+ return mode;
+}
+
+/* Set FNDT's strub mode to MODE; FNDT may be a function decl or
+ function type. If OVERRIDE, do not check whether a mode is already
+ set. */
+
+static void
+strub_set_fndt_mode_to (tree fndt, enum strub_mode mode, bool override)
+{
+ gcc_checking_assert (override
+ || !(DECL_P (fndt)
+ ? get_strub_attr_from_decl (fndt)
+ : get_strub_attr_from_type (fndt)));
+
+ tree attr = tree_cons (get_identifier ("strub"),
+ get_strub_mode_attr_value (mode),
+ NULL_TREE);
+ tree *attrp = NULL;
+ if (DECL_P (fndt))
+ {
+ gcc_checking_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndt)));
+ attrp = &DECL_ATTRIBUTES (fndt);
+ }
+ else if (FUNC_OR_METHOD_TYPE_P (fndt))
+ attrp = &TYPE_ATTRIBUTES (fndt);
+ else
+ gcc_unreachable ();
+
+ TREE_CHAIN (attr) = *attrp;
+ *attrp = attr;
+}
+
+/* Set FNDT's strub mode to callable.
+ FNDT may be a function decl or a function type. */
+
+void
+strub_make_callable (tree fndt)
+{
+ strub_set_fndt_mode_to (fndt, STRUB_CALLABLE, false);
+}
+
+/* Set NODE to strub MODE. Report incompatibilities between MODE and the mode
+ requested through explicit attributes, and cases of non-eligibility. */
+
+static void
+set_strub_mode_to (cgraph_node *node, enum strub_mode mode)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+ enum strub_mode req_mode = get_strub_mode_from_attr (attr);
+
+ if (attr)
+ {
+ /* Check for and report incompatible mode changes. */
+ if (mode != req_mode
+ && !(req_mode == STRUB_INTERNAL
+ && (mode == STRUB_WRAPPED
+ || mode == STRUB_WRAPPER))
+ && !((req_mode == STRUB_INTERNAL
+ || req_mode == STRUB_AT_CALLS
+ || req_mode == STRUB_CALLABLE)
+ && mode == STRUB_INLINABLE))
+ {
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<strub%> mode %qE selected for %qD, when %qE was requested",
+ get_strub_mode_attr_parm (mode),
+ node->decl,
+ get_strub_mode_attr_parm (req_mode));
+ if (node->alias)
+ {
+ cgraph_node *target = node->ultimate_alias_target ();
+ if (target != node)
+ error_at (DECL_SOURCE_LOCATION (target->decl),
+ "the incompatible selection was determined"
+ " by ultimate alias target %qD",
+ target->decl);
+ }
+
+ /* Report any incompatibilities with explicitly-requested strub. */
+ switch (req_mode)
+ {
+ case STRUB_AT_CALLS:
+ can_strub_at_calls_p (node, true);
+ break;
+
+ case STRUB_INTERNAL:
+ can_strub_internally_p (node, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Drop any incompatible strub attributes leading the decl attribute
+ chain. Return if we find one with the mode we need. */
+ for (;;)
+ {
+ if (mode == req_mode)
+ return;
+
+ if (DECL_ATTRIBUTES (node->decl) != attr)
+ break;
+
+ DECL_ATTRIBUTES (node->decl) = TREE_CHAIN (attr);
+ attr = get_strub_attr_from_decl (node->decl);
+ if (!attr)
+ break;
+
+ req_mode = get_strub_mode_from_attr (attr);
+ }
+ }
+ else if (mode == req_mode)
+ return;
+
+ strub_set_fndt_mode_to (node->decl, mode, attr);
+}
+
+/* Compute and set NODE's strub mode. */
+
+static void
+set_strub_mode (cgraph_node *node)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+
+ if (attr)
+ switch (get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ cgraph_node *xnode = node;
+ if (node->alias)
+ xnode = node->ultimate_alias_target ();
+ /* Weakrefs may remain unresolved (the above will return node) if
+ their targets are not defined, so make sure we compute a strub
+ mode for them, instead of defaulting to STRUB_DISABLED and
+ rendering them uncallable. */
+ enum strub_mode mode = (xnode != node && !xnode->alias
+ ? get_strub_mode (xnode)
+ : compute_strub_mode (node, attr));
+
+ set_strub_mode_to (node, mode);
+}
+
+\f
+/* Non-strub functions shouldn't be called from within strub contexts,
+ except through callable ones. Always inline strub functions can
+ only be called from strub functions. */
+
+static bool
+strub_callable_from_p (strub_mode caller_mode, strub_mode callee_mode)
+{
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ return callee_mode != STRUB_INLINABLE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return (flag_strub >= -1);
+
+ case STRUB_DISABLED:
+ return false;
+
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return TRUE iff CALLEE can be inlined into CALLER. We wish to avoid inlining
+ WRAPPED functions back into their WRAPPERs. More generally, we wish to avoid
+ inlining strubbed functions into non-strubbed ones. CALLER doesn't have to
+ be an immediate caller of CALLEE: the immediate caller may have already been
+ cloned for inlining, and then CALLER may be further up the original call
+ chain. ??? It would be nice if our own caller would retry inlining callee
+ if caller gets inlined. */
+
+bool
+strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller)
+{
+ strub_mode callee_mode = get_strub_mode (callee);
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ /* When we consider inlining, we've already verified callability, so we
+ can even inline callable and then disabled into a strub context. That
+ will get strubbed along with the context, so it's hopefully not a
+ problem. */
+ return true;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ strub_mode caller_mode = get_strub_mode (caller);
+
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return true;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+/* Check that types T1 and T2 are strub-compatible. Return 1 if the strub modes
+ are the same, 2 if they are interchangeable, and 0 otherwise. */
+
+int
+strub_comptypes (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
+
+ enum strub_mode m1 = get_strub_mode_from_type (t1);
+ enum strub_mode m2 = get_strub_mode_from_type (t2);
+
+ if (m1 == m2)
+ return 1;
+
+ /* We're dealing with types, so only strub modes that can be selected by
+ attributes in the front end matter. If either mode is at-calls (for
+ functions) or internal (for variables), the conversion is not
+ compatible. */
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (t1);
+ enum strub_mode mr = var_p ? STRUB_INTERNAL : STRUB_AT_CALLS;
+ if (m1 == mr || m2 == mr)
+ return 0;
+
+ return 2;
+}
+
+/* Return the effective strub mode used for CALL, and set *TYPEP to
+ the effective type used for the call. The effective type and mode
+ are those of the callee, unless the call involves a typecast. */
+
+static enum strub_mode
+effective_strub_mode_for_call (gcall *call, tree *typep)
+{
+ tree type;
+ enum strub_mode mode;
+
+ if (strub_call_fntype_override_p (call))
+ {
+ type = gimple_call_fntype (call);
+ mode = get_strub_mode_from_type (type);
+ }
+ else
+ {
+ type = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
+ tree decl = gimple_call_fndecl (call);
+ if (decl)
+ mode = get_strub_mode_from_fndecl (decl);
+ else
+ mode = get_strub_mode_from_type (type);
+ }
+
+ if (typep)
+ *typep = type;
+
+ return mode;
+}
+
+/* Create a distinct copy of the type of NODE's function, and change
+ the fntype of all calls to it with the same main type to the new
+ type. */
+
+static void
+distinctify_node_type (cgraph_node *node)
+{
+ tree old_type = TREE_TYPE (node->decl);
+ tree new_type = build_distinct_type_copy (old_type);
+ tree new_ptr_type = NULL_TREE;
+
+ /* Remap any calls to node->decl that use old_type, or a variant
+ thereof, to new_type as well. We don't look for aliases, their
+ declarations will have their types changed independently, and
+ we'll adjust their fntypes then. */
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->call_stmt)
+ continue;
+ tree fnaddr = gimple_call_fn (e->call_stmt);
+ gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
+ && TREE_OPERAND (fnaddr, 0) == node->decl);
+ if (strub_call_fntype_override_p (e->call_stmt))
+ continue;
+ if (!new_ptr_type)
+ new_ptr_type = build_pointer_type (new_type);
+ TREE_TYPE (fnaddr) = new_ptr_type;
+ gimple_call_set_fntype (e->call_stmt, new_type);
+ }
+
+ TREE_TYPE (node->decl) = new_type;
+}
+
+/* Return TRUE iff TYPE and any variants have the same strub mode. */
+
+static bool
+same_strub_mode_in_variants_p (tree type)
+{
+ enum strub_mode mode = get_strub_mode_from_type (type);
+
+ for (tree other = TYPE_MAIN_VARIANT (type);
+ other != NULL_TREE; other = TYPE_NEXT_VARIANT (other))
+ if (type != other && mode != get_strub_mode_from_type (other))
+ return false;
+
+ /* Check that the canonical type, if set, either is in the same
+ variant chain, or has the same strub mode as type. Also check
+ the variants of the canonical type. */
+ if (TYPE_CANONICAL (type)
+ && (TYPE_MAIN_VARIANT (TYPE_CANONICAL (type))
+ != TYPE_MAIN_VARIANT (type)))
+ {
+ if (mode != get_strub_mode_from_type (TYPE_CANONICAL (type)))
+ return false;
+ else
+ return same_strub_mode_in_variants_p (TYPE_CANONICAL (type));
+ }
+
+ return true;
+}
+
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ /* It's expected that check strub-wise pointer type compatibility of variables
+ and of functions is already taken care of by front-ends, on account of the
+ attribute's being marked as affecting type identity and of the creation of
+ distinct types. */
+
+ /* Check that call targets in strub contexts have strub-callable types. */
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, NULL);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-%<strub%> call in %<strub%> context %qD",
+ node->decl);
+ }
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ {
+ if (callee_mode == STRUB_INLINABLE)
+ error_at (gimple_location (e->call_stmt),
+ "calling %<always_inline%> %<strub%> %qD"
+ " in non-%<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else if (fndecl_built_in_p (e->callee->decl, BUILT_IN_APPLY_ARGS)
+ && caller_mode == STRUB_INTERNAL)
+ /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
+ from the STRUB_WRAPPED's strub context. */
+ continue;
+ else if (!strub_call_fntype_override_p (e->call_stmt))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-%<strub%> %qD in %<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else
+ error_at (gimple_location (e->call_stmt),
+ "calling %qD using non-%<strub%> type %qT"
+ " in %<strub%> context %qD",
+ e->callee->decl, callee_fntype, node->decl);
+ }
+ }
+ }
+}
+
+namespace {
+
+/* Define a pass to compute strub modes. */
+const pass_data pass_data_ipa_strub_mode = {
+ SIMPLE_IPA_PASS,
+ "strubm",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ 0, // properties_finish
+};
+
+class pass_ipa_strub_mode : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub_mode (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub_mode, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub_mode (m_ctxt); }
+ virtual bool gate (function *) {
+ /* In relaxed (-3) and strict (-4) settings, that only enable strub at a
+ function or variable attribute's request, the attribute handler changes
+ flag_strub to -1 or -2, respectively, if any strub-enabling occurence of
+ the attribute is found. Therefore, if it remains at -3 or -4, nothing
+ that would enable strub was found, so we can disable it and avoid the
+ overhead. */
+ if (flag_strub < -2)
+ flag_strub = 0;
+ return flag_strub;
+ }
+ virtual unsigned int execute (function *);
+};
+
+/* Define a pass to introduce strub transformations. */
+const pass_data pass_data_ipa_strub = {
+ SIMPLE_IPA_PASS,
+ "strub",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg | PROP_ssa, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ TODO_update_ssa
+ | TODO_cleanup_cfg
+ | TODO_rebuild_cgraph_edges
+ | TODO_verify_il, // properties_finish
+};
+
+class pass_ipa_strub : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub (m_ctxt); }
+ virtual bool gate (function *) { return flag_strub && !seen_error (); }
+ virtual unsigned int execute (function *);
+
+ /* Define on demand and cache some types we use often. */
+#define DEF_TYPE(NAME, INIT) \
+ static inline tree get_ ## NAME () { \
+ static tree type = NULL_TREE; \
+ if (!type) \
+ type = (INIT); \
+ return type; \
+ }
+
+ /* Use a distinct ptr_type_node to denote the watermark, so that we can
+ recognize it in arg lists and avoid modifying types twice. */
+ DEF_TYPE (wmt, build_variant_type_copy (ptr_type_node))
+
+ DEF_TYPE (pwmt, build_reference_type (get_wmt ()))
+
+ DEF_TYPE (qpwmt,
+ build_qualified_type (get_pwmt (),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+ DEF_TYPE (qptr,
+ build_qualified_type (ptr_type_node,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST))
+
+ DEF_TYPE (qpvalst,
+ build_qualified_type (build_reference_type
+ (va_list_type_node),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+#undef DEF_TYPE
+
+ /* Define non-strub builtins on demand. */
+#define DEF_NM_BUILTIN(NAME, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ decl = add_builtin_function \
+ ("__builtin_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ NULL, NULL); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_NM_BUILTIN (stack_address,
+ BUILT_IN_STACK_ADDRESS,
+ (ptr_type_node, NULL))
+
+#undef DEF_NM_BUILTIN
+
+ /* Define strub builtins on demand. */
+#define DEF_SS_BUILTIN(NAME, FNSPEC, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ tree attrs = NULL; \
+ if (FNSPEC) \
+ attrs = tree_cons (get_identifier ("fn spec"), \
+ build_tree_list \
+ (NULL_TREE, \
+ build_string (strlen (FNSPEC), \
+ (FNSPEC))), \
+ attrs); \
+ decl = add_builtin_function_ext_scope \
+ ("__builtin___strub_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ "__strub_" #NAME, attrs); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_SS_BUILTIN (enter, ". Ot",
+ BUILT_IN___STRUB_ENTER,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (update, ". Wt",
+ BUILT_IN___STRUB_UPDATE,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (leave, ". w ",
+ BUILT_IN___STRUB_LEAVE,
+ (void_type_node, get_qpwmt (), NULL))
+
+#undef DEF_SS_BUILTIN
+
+ /* Define strub identifiers on demand. */
+#define DEF_IDENT(NAME) \
+ static inline tree get_ ## NAME () { \
+ static tree identifier = NULL_TREE; \
+ if (!identifier) \
+ identifier = get_identifier (".strub." #NAME); \
+ return identifier; \
+ }
+
+ DEF_IDENT (watermark_ptr)
+ DEF_IDENT (va_list_ptr)
+ DEF_IDENT (apply_args)
+
+#undef DEF_IDENT
+
+ static inline int adjust_at_calls_type (tree);
+ static inline void adjust_at_calls_call (cgraph_edge *, int, tree);
+ static inline void adjust_at_calls_calls (cgraph_node *);
+
+ /* Add to SEQ a call to the strub watermark update builtin, taking NODE's
+ location if given. Optionally add the corresponding edge from NODE, with
+ execution frequency COUNT. Return the modified SEQ. */
+
+ static inline gimple_seq
+ call_update_watermark (tree wmptr, cgraph_node *node, profile_count count,
+ gimple_seq seq = NULL)
+ {
+ tree uwm = get_update ();
+ gcall *update = gimple_build_call (uwm, 1, wmptr);
+ if (node)
+ gimple_set_location (update, DECL_SOURCE_LOCATION (node->decl));
+ gimple_seq_add_stmt (&seq, update);
+ if (node)
+ node->create_edge (cgraph_node::get_create (uwm), update, count, false);
+ return seq;
+ }
+
+};
+
+} // anon namespace
+
+/* Gather with this type a collection of parameters that we're turning into
+ explicit references. */
+
+typedef hash_set<tree> indirect_parms_t;
+
+/* Dereference OP's incoming turned-into-reference parm if it's an
+ INDIRECT_PARMS or an ADDR_EXPR thereof. Set *REC and return according to
+ gimple-walking expectations. */
+
+static tree
+maybe_make_indirect (indirect_parms_t &indirect_parms, tree op, int *rec)
+{
+ if (DECL_P (op))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (op))
+ {
+ tree ret = gimple_fold_indirect_ref (op);
+ if (!ret)
+ ret = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (op)),
+ op,
+ build_int_cst (TREE_TYPE (op), 0));
+ return ret;
+ }
+ }
+ else if (TREE_CODE (op) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (op, 0)))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (TREE_OPERAND (op, 0)))
+ {
+ op = TREE_OPERAND (op, 0);
+ return op;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that adds dereferencing to indirect parms. */
+
+static tree
+walk_make_indirect (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ indirect_parms_t &indirect_parms = *(indirect_parms_t *)wi->info;
+
+ if (!*op || TYPE_P (*op))
+ {
+ *rec = 0;
+ return NULL_TREE;
+ }
+
+ if (tree repl = maybe_make_indirect (indirect_parms, *op, rec))
+ {
+ *op = repl;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that turns any non-gimple-val ADDR_EXPRs into a
+ separate SSA. Though addresses of e.g. parameters, and of members thereof,
+ are gimple vals, turning parameters into references, with an extra layer of
+ indirection and thus explicit dereferencing, need to be regimplified. */
+
+static tree
+walk_regimplify_addr_expr (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ gimple_stmt_iterator &gsi = *(gimple_stmt_iterator *)wi->info;
+
+ *rec = 0;
+
+ if (!*op || TREE_CODE (*op) != ADDR_EXPR)
+ return NULL_TREE;
+
+ if (!is_gimple_val (*op))
+ {
+ tree ret = force_gimple_operand_gsi (&gsi, *op, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ gcc_assert (ret != *op);
+ *op = ret;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Turn STMT's PHI arg defs into separate SSA defs if they've become
+ non-gimple_val. Return TRUE if any edge insertions need to be committed. */
+
+static bool
+walk_regimplify_phi (gphi *stmt)
+{
+ bool needs_commit = false;
+
+ for (unsigned i = 0, n = gimple_phi_num_args (stmt); i < n; i++)
+ {
+ tree op = gimple_phi_arg_def (stmt, i);
+ if ((TREE_CODE (op) == ADDR_EXPR
+ && !is_gimple_val (op))
+ /* ??? A PARM_DECL that was addressable in the original function and
+ had its address in PHI nodes, but that became a reference in the
+ wrapped clone would NOT be updated by update_ssa in PHI nodes.
+ Alas, if we were to create a default def for it now, update_ssa
+ would complain that the symbol that needed rewriting already has
+ SSA names associated with it. OTOH, leaving the PARM_DECL alone,
+ it eventually causes errors because it remains unchanged in PHI
+ nodes, but it gets rewritten as expected if it appears in other
+ stmts. So we cheat a little here, and force the PARM_DECL out of
+ the PHI node and into an assignment. It's a little expensive,
+ because we insert it at the edge, which introduces a basic block
+ that's entirely unnecessary, but it works, and the block will be
+ removed as the default def gets propagated back into the PHI node,
+ so the final optimized code looks just as expected. */
+ || (TREE_CODE (op) == PARM_DECL
+ && !TREE_ADDRESSABLE (op)))
+ {
+ tree temp = make_ssa_name (TREE_TYPE (op), stmt);
+ if (TREE_CODE (op) == PARM_DECL)
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (temp, DECL_NAME (op));
+ SET_PHI_ARG_DEF (stmt, i, temp);
+
+ gimple *assign = gimple_build_assign (temp, op);
+ if (gimple_phi_arg_has_location (stmt, i))
+ gimple_set_location (assign, gimple_phi_arg_location (stmt, i));
+ gsi_insert_on_edge (gimple_phi_arg_edge (stmt, i), assign);
+ needs_commit = true;
+ }
+ }
+
+ return needs_commit;
+}
+
+/* Create a reference type to use for PARM when turning it into a reference.
+ NONALIASED causes the reference type to gain its own separate alias set, so
+ that accessing the indirectly-passed parm won'will not add aliasing
+ noise. */
+
+static tree
+build_ref_type_for (tree parm, bool nonaliased = true)
+{
+ gcc_checking_assert (TREE_CODE (parm) == PARM_DECL);
+
+ tree ref_type = build_reference_type (TREE_TYPE (parm));
+
+ if (!nonaliased)
+ return ref_type;
+
+ /* Each PARM turned indirect still points to the distinct memory area at the
+ wrapper, and the reference in unchanging, so we might qualify it, but...
+ const is not really important, since we're only using default defs for the
+ reference parm anyway, and not introducing any defs, and restrict seems to
+ cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that,
+ if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias
+ set seems to not run afoul of this problem, and it hopefully enables the
+ compiler to tell the pointers do point to objects that are not otherwise
+ aliased. */
+#if 1
+ tree qref_type = build_variant_type_copy (ref_type);
+
+ TYPE_ALIAS_SET (qref_type) = new_alias_set ();
+ record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type));
+
+ return qref_type;
+#else
+ tree qref_type = build_qualified_type (ref_type,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST);
+
+ return qref_type;
+#endif
+}
+
+/* Add cgraph edges from current_function_decl to callees in SEQ with frequency
+ COUNT, assuming all calls in SEQ are direct. */
+
+static void
+add_call_edges_for_seq (gimple_seq seq, profile_count count)
+{
+ cgraph_node *node = cgraph_node::get_create (current_function_decl);
+
+ for (gimple_stmt_iterator gsi = gsi_start (seq);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ if (!call)
+ continue;
+
+ tree callee = gimple_call_fndecl (call);
+ gcc_checking_assert (callee);
+ node->create_edge (cgraph_node::get_create (callee), call, count, false);
+ }
+}
+
+/* Insert SEQ after the call at GSI, as if the call was in a try block with SEQ
+ as finally, i.e., SEQ will run after the call whether it returns or
+ propagates an exception. This handles block splitting, EH edge and block
+ creation, noreturn and nothrow optimizations, and even throwing calls without
+ preexisting local handlers. */
+
+static void
+gsi_insert_finally_seq_after_call (gimple_stmt_iterator gsi, gimple_seq seq)
+{
+ if (!seq)
+ return;
+
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gimple_has_location (stmt))
+ annotate_all_with_location (seq, gimple_location (stmt));
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ bool noreturn_p = call && gimple_call_noreturn_p (call);
+ int eh_lp = lookup_stmt_eh_lp (stmt);
+ bool must_not_throw_p = eh_lp < 0;
+ bool nothrow_p = (must_not_throw_p
+ || (call && gimple_call_nothrow_p (call))
+ || (eh_lp <= 0
+ && (TREE_NOTHROW (cfun->decl)
+ || !flag_exceptions)));
+
+ if (noreturn_p && nothrow_p)
+ return;
+
+ /* Don't expect an EH edge if we're not to throw, or if we're not in an EH
+ region yet. */
+ bool no_eh_edge_p = (nothrow_p || !eh_lp);
+ bool must_end_bb = stmt_ends_bb_p (stmt);
+
+ edge eft = NULL, eeh = NULL;
+ if (must_end_bb && !(noreturn_p && no_eh_edge_p))
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->succs)
+ {
+ if ((e->flags & EDGE_EH))
+ {
+ gcc_checking_assert (!eeh);
+ eeh = e;
+#if !CHECKING_P
+ if (eft || noreturn_p)
+ break;
+#endif
+ }
+ if ((e->flags & EDGE_FALLTHRU))
+ {
+ gcc_checking_assert (!eft);
+ eft = e;
+#if !CHECKING_P
+ if (eeh || no_eh_edge_p)
+ break;
+#endif
+ }
+ }
+
+ gcc_checking_assert (!(eft && (eft->flags & EDGE_FALLTHRU))
+ == noreturn_p);
+ gcc_checking_assert (!(eeh && (eeh->flags & EDGE_EH))
+ == no_eh_edge_p);
+ gcc_checking_assert (eft != eeh);
+ }
+
+ if (!noreturn_p)
+ {
+ gimple_seq nseq = nothrow_p ? seq : gimple_seq_copy (seq);
+
+ if (must_end_bb)
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+ add_call_edges_for_seq (nseq, eft->count ());
+ gsi_insert_seq_on_edge_immediate (eft, nseq);
+ }
+ else
+ {
+ add_call_edges_for_seq (nseq, gsi_bb (gsi)->count);
+ gsi_insert_seq_after (&gsi, nseq, GSI_SAME_STMT);
+ }
+ }
+
+ if (nothrow_p)
+ return;
+
+ if (eh_lp)
+ {
+ add_call_edges_for_seq (seq, eeh->count ());
+ gsi_insert_seq_on_edge_immediate (eeh, seq);
+ return;
+ }
+
+ /* A throwing call may appear within a basic block in a function that doesn't
+ have any EH regions. We're going to add a cleanup if so, therefore the
+ block will have to be split. */
+ basic_block bb = gsi_bb (gsi);
+ if (!gsi_one_before_end_p (gsi))
+ split_block (bb, stmt);
+
+ /* Create a new block for the EH cleanup. */
+ basic_block bb_eh_cleanup = create_empty_bb (bb);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, bb_eh_cleanup, bb);
+ if (current_loops)
+ add_bb_to_loop (bb_eh_cleanup, current_loops->tree_root);
+
+ /* Make the new block an EH cleanup for the call. */
+ eh_region new_r = gen_eh_region_cleanup (NULL);
+ eh_landing_pad lp = gen_eh_landing_pad (new_r);
+ tree label = gimple_block_label (bb_eh_cleanup);
+ lp->post_landing_pad = label;
+ EH_LANDING_PAD_NR (label) = lp->index;
+ add_stmt_to_eh_lp (stmt, lp->index);
+
+ /* Add the cleanup code to the EH cleanup block. */
+ gsi = gsi_after_labels (bb_eh_cleanup);
+ gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+
+ /* And then propagate the exception further. */
+ gresx *resx = gimple_build_resx (new_r->index);
+ if (gimple_has_location (stmt))
+ gimple_set_location (resx, gimple_location (stmt));
+ gsi_insert_before (&gsi, resx, GSI_SAME_STMT);
+
+ /* Finally, wire the EH cleanup block into the CFG. */
+ make_eh_edges (stmt);
+ add_call_edges_for_seq (seq, single_pred_edge (bb_eh_cleanup)->count ());
+}
+
+/* Copy the attribute list at *ATTRS, minus any NAME attributes, leaving
+ shareable trailing nodes alone. */
+
+static inline void
+remove_named_attribute_unsharing (const char *name, tree *attrs)
+{
+ while (tree found = lookup_attribute (name, *attrs))
+ {
+ /* Copy nodes up to the next NAME attribute. */
+ while (*attrs != found)
+ {
+ *attrs = tree_cons (TREE_PURPOSE (*attrs),
+ TREE_VALUE (*attrs),
+ TREE_CHAIN (*attrs));
+ attrs = &TREE_CHAIN (*attrs);
+ }
+ /* Then drop it. */
+ gcc_checking_assert (*attrs == found);
+ *attrs = TREE_CHAIN (*attrs);
+ }
+}
+
+/* Record the order of the last cgraph entry whose mode we've already set, so
+ that we can perform mode setting incrementally without duplication. */
+static int last_cgraph_order;
+
+/* Set strub modes for functions introduced since the last call. */
+
+static void
+ipa_strub_set_mode_for_new_functions ()
+{
+ if (symtab->order == last_cgraph_order)
+ return;
+
+ cgraph_node *node;
+
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
+ for (int aliases = 0; aliases <= 1; aliases++)
+ FOR_EACH_FUNCTION (node)
+ {
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ set_strub_mode (node);
+ }
+
+ last_cgraph_order = symtab->order;
+}
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+
+bool
+strub_splittable_p (cgraph_node *node)
+{
+ switch (get_strub_mode (node))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INLINABLE:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return false;
+
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */
+
+tree
+strub_watermark_parm (tree fndecl)
+{
+ switch (get_strub_mode_from_fndecl (fndecl))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ case STRUB_INLINABLE:
+ return NULL_TREE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+ /* The type (variant) compare finds the parameter even in a just-created
+ clone, before we set its name, but the type-based compare doesn't work
+ during builtin expansion within the lto compiler, because we'll have
+ created a separate variant in that run. */
+ if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()
+ || DECL_NAME (parm) == pass_ipa_strub::get_watermark_ptr ())
+ return parm;
+
+ gcc_unreachable ();
+}
+
+/* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it
+ hasn't been added yet. Return the named argument count. */
+
+int
+pass_ipa_strub::adjust_at_calls_type (tree type)
+{
+ int named_args = 0;
+
+ gcc_checking_assert (same_strub_mode_in_variants_p (type));
+
+ if (!TYPE_ARG_TYPES (type))
+ return named_args;
+
+ tree *tlist = &TYPE_ARG_TYPES (type);
+ tree qpwmptrt = get_qpwmt ();
+ while (*tlist && TREE_VALUE (*tlist) != void_type_node)
+ {
+ /* The type has already been adjusted. */
+ if (TREE_VALUE (*tlist) == qpwmptrt)
+ return named_args;
+ named_args++;
+ *tlist = tree_cons (TREE_PURPOSE (*tlist),
+ TREE_VALUE (*tlist),
+ TREE_CHAIN (*tlist));
+ tlist = &TREE_CHAIN (*tlist);
+ }
+
+ /* Add the new argument after all named arguments, so as to not mess with
+ attributes that reference parameters. */
+ *tlist = tree_cons (NULL_TREE, get_qpwmt (), *tlist);
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ if (!type_already_adjusted)
+ {
+ int flags = flags_from_decl_or_type (type);
+ tree fnspec = lookup_attribute ("fn spec", type);
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1;
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied, if needed, before adding
+ parameters. */
+ TYPE_ATTRIBUTES (type)
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (type));
+ }
+ }
+#endif
+
+ return named_args;
+}
+
+/* Adjust a call to an at-calls call target. Create a watermark local variable
+ if needed, initialize it before, pass it to the callee according to the
+ modified at-calls interface, and release the callee's stack space after the
+ call, if not deferred. If the call is const or pure, arrange for the
+ watermark to not be assumed unused or unchanged. */
+
+void
+pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
+ tree callee_fntype)
+{
+ gcc_checking_assert (e->call_stmt);
+ gcall *ocall = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (ocall);
+
+ /* Make sure we haven't modified this call yet. */
+ gcc_checking_assert (!(int (gimple_call_num_args (ocall)) > named_args
+ && (TREE_TYPE (gimple_call_arg (ocall, named_args))
+ == get_pwmt ())));
+
+ /* If we're already within a strub context, pass on the incoming watermark
+ pointer, and omit the enter and leave calls around the modified call, as an
+ optimization, or as a means to satisfy a tail-call requirement. */
+ tree swmp = ((optimize_size || optimize > 2
+ || gimple_call_must_tail_p (ocall)
+ || (optimize == 2 && gimple_call_tail_p (ocall)))
+ ? strub_watermark_parm (e->caller->decl)
+ : NULL_TREE);
+ bool omit_own_watermark = swmp;
+ tree swm = NULL_TREE;
+ if (!omit_own_watermark)
+ {
+ swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ /* Initialize the watermark before the call. */
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1,
+ unshare_expr (swmp));
+ if (gimple_has_location (ocall))
+ gimple_set_location (stptr, gimple_location (ocall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ e->caller->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+ }
+
+
+ /* Replace the call with one that passes the swmp argument first. */
+ gcall *wrcall;
+ { gcall *stmt = ocall;
+ // Mostly copied from gimple_call_copy_skip_args.
+ int i = 0;
+ int nargs = gimple_call_num_args (stmt);
+ auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
+ gcall *new_stmt;
+
+ /* pr71109.c calls a prototypeless function, then defines it with
+ additional arguments. It's ill-formed, but after it's inlined,
+ it somehow works out. */
+ for (; i < named_args && i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+ for (; i < named_args; i++)
+ vargs.quick_push (null_pointer_node);
+
+ vargs.quick_push (unshare_expr (swmp));
+
+ for (; i < nargs; i++)
+#if 0
+ if (!bitmap_bit_p (args_to_skip, i))
+#endif
+ vargs.quick_push (gimple_call_arg (stmt, i));
+
+ if (gimple_call_internal_p (stmt))
+#if 0
+ new_stmt = gimple_build_call_internal_vec (gimple_call_internal_fn (stmt),
+ vargs);
+#endif
+ gcc_unreachable ();
+ else
+ new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
+ gimple_call_set_fntype (new_stmt, callee_fntype);
+
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+#if 0
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+#else
+ gimple_move_vops (new_stmt, stmt);
+#endif
+
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gimple_call_copy_flags (new_stmt, stmt);
+ gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+
+ gimple_set_modified (new_stmt, true);
+
+ wrcall = new_stmt;
+ }
+
+ update_stmt (wrcall);
+ gsi_replace (&gsi, wrcall, true);
+ cgraph_edge::set_call_stmt (e, wrcall, false);
+
+ /* Insert the strub code after the call. */
+ gimple_seq seq = NULL;
+
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ if (!swm)
+ swm = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (swmp)),
+ swmp,
+ build_int_cst (TREE_TYPE (swmp), 0));
+
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ unshare_expr (swm)));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ if (gimple_has_location (wrcall))
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ if (!omit_own_watermark)
+ {
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+}
+
+/* Adjust all at-calls calls in NODE. */
+
+void
+pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
+{
+ /* Adjust unknown-callee indirect calls with STRUB_AT_CALLS types within
+ onode. */
+ if (node->indirect_calls)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+
+ if (node->callees)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+}
+
+/* The strubm (strub mode) pass computes a strub mode for each function in the
+ call graph, and checks, before any inlining, that strub callability
+ requirements in effect are satisfied. */
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ last_cgraph_order = 0;
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
+
+ return 0;
+}
+
+/* Create a strub mode pass. */
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub_mode (gcc::context *ctxt)
+{
+ return new pass_ipa_strub_mode (ctxt);
+}
+
+/* The strub pass proper adjusts types, signatures, and at-calls calls, and
+ splits internal-strub functions. */
+
+unsigned int
+pass_ipa_strub::execute (function *)
+{
+ cgraph_node *onode;
+
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* First, adjust the signature of at-calls functions. We adjust types of
+ at-calls functions first, so that we don't modify types in place unless
+ strub is explicitly requested. */
+ FOR_EACH_FUNCTION (onode)
+ {
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode == STRUB_AT_CALLS
+ || mode == STRUB_AT_CALLS_OPT)
+ {
+ /* Create a type variant if strubbing was not explicitly requested in
+ the function type. */
+ if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
+ distinctify_node_type (onode);
+
+ int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));
+
+ /* An external function explicitly declared with strub won't have a
+ body. Even with implicit at-calls strub, a function may have had its
+ body removed after we selected the mode, and then we have nothing
+ further to do. */
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ tree *pargs = &DECL_ARGUMENTS (onode->decl);
+
+ /* A noninterposable_alias reuses the same parm decl chain, don't add
+ the parm twice. */
+ bool aliased_parms = (onode->alias && *pargs
+ && DECL_CONTEXT (*pargs) != onode->decl);
+
+ if (aliased_parms)
+ continue;
+
+ for (int i = 0; i < named_args; i++)
+ pargs = &DECL_CHAIN (*pargs);
+
+ tree wmptr = build_decl (DECL_SOURCE_LOCATION (onode->decl),
+ PARM_DECL,
+ get_watermark_ptr (),
+ get_qpwmt ());
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_ARG_TYPE (wmptr) = get_qpwmt ();
+ DECL_CONTEXT (wmptr) = onode->decl;
+ TREE_USED (wmptr) = 1;
+ DECL_CHAIN (wmptr) = *pargs;
+ *pargs = wmptr;
+
+ if (onode->alias)
+ continue;
+
+ cgraph_node *nnode = onode;
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca)
+ {
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, cfun)
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+
+ if (!call)
+ continue;
+
+ if (gimple_alloca_call_p (call))
+ {
+ /* Capture stack growth. */
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)
+ ->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ }
+ }
+
+ pop_cfun ();
+ }
+ }
+
+ FOR_EACH_FUNCTION (onode)
+ {
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode != STRUB_INTERNAL)
+ {
+ adjust_at_calls_calls (onode);
+ continue;
+ }
+
+ bool is_stdarg = calls_builtin_va_start_p (onode);;
+ bool apply_args = calls_builtin_apply_args_p (onode);
+
+ vec<ipa_adjusted_param, va_gc> *nparms = NULL;
+ unsigned j = 0;
+ {
+ // The following loop copied from ipa-split.c:split_function.
+ for (tree parm = DECL_ARGUMENTS (onode->decl);
+ parm; parm = DECL_CHAIN (parm), j++)
+ {
+ ipa_adjusted_param adj = {};
+ adj.op = IPA_PARAM_OP_COPY;
+ adj.base_index = j;
+ adj.prev_clone_index = j;
+ vec_safe_push (nparms, adj);
+ }
+
+ if (apply_args)
+ {
+ ipa_adjusted_param aaadj = {};
+ aaadj.op = IPA_PARAM_OP_NEW;
+ aaadj.type = get_qptr ();
+ vec_safe_push (nparms, aaadj);
+ }
+
+ if (is_stdarg)
+ {
+ ipa_adjusted_param vladj = {};
+ vladj.op = IPA_PARAM_OP_NEW;
+ vladj.type = get_qpvalst ();
+ vec_safe_push (nparms, vladj);
+ }
+
+ ipa_adjusted_param wmadj = {};
+ wmadj.op = IPA_PARAM_OP_NEW;
+ wmadj.type = get_qpwmt ();
+ vec_safe_push (nparms, wmadj);
+ }
+ ipa_param_adjustments adj (nparms, -1, false);
+
+ cgraph_node *nnode = onode->create_version_clone_with_body
+ (auto_vec<cgraph_edge *> (0),
+ NULL, &adj, NULL, NULL, "strub", NULL);
+
+ if (!nnode)
+ {
+ error_at (DECL_SOURCE_LOCATION (onode->decl),
+ "failed to split %qD for %<strub%>",
+ onode->decl);
+ continue;
+ }
+
+ onode->split_part = true;
+ if (onode->calls_comdat_local)
+ nnode->add_to_same_comdat_group (onode);
+
+ set_strub_mode_to (onode, STRUB_WRAPPER);
+ set_strub_mode_to (nnode, STRUB_WRAPPED);
+
+ adjust_at_calls_calls (nnode);
+
+ /* Decide which of the wrapped function's parms we want to turn into
+ references to the argument passed to the wrapper. In general, we want to
+ copy small arguments, and avoid copying large ones. Variable-sized array
+ lengths given by other arguments, as in 20020210-1.c, would lead to
+ problems if passed by value, after resetting the original function and
+ dropping the length computation; passing them by reference works.
+ DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
+ anyway, but performed at the caller. */
+ indirect_parms_t indirect_nparms (3, false);
+ unsigned adjust_ftype = 0;
+ unsigned named_args = 0;
+ for (tree parm = DECL_ARGUMENTS (onode->decl),
+ nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
+ parm;
+ named_args++,
+ parm = DECL_CHAIN (parm),
+ nparm = DECL_CHAIN (nparm),
+ nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
+ if (!(0 /* DECL_BY_REFERENCE (narg) */
+ || is_gimple_reg_type (TREE_TYPE (nparm))
+ || VECTOR_TYPE_P (TREE_TYPE (nparm))
+ || TREE_CODE (TREE_TYPE (nparm)) == COMPLEX_TYPE
+ || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ && (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ <= 4 * UNITS_PER_WORD))))
+ {
+ indirect_nparms.add (nparm);
+
+ /* ??? Is there any case in which it is not safe to suggest the parms
+ turned indirect don't alias anything else? They are distinct,
+ unaliased memory in the wrapper, and the wrapped can't possibly
+ take pointers into them because none of the pointers passed to the
+ wrapper can alias other incoming parameters passed by value, even
+ if with transparent reference, and the wrapper doesn't take any
+ extra parms that could point into wrapper's parms. So we can
+ probably drop the TREE_ADDRESSABLE and keep the TRUE. */
+ tree ref_type = build_ref_type_for (nparm,
+ true
+ || !TREE_ADDRESSABLE (parm));
+
+ DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type;
+ relayout_decl (nparm);
+ TREE_ADDRESSABLE (nparm) = 0;
+ DECL_BY_REFERENCE (nparm) = 0;
+ DECL_NOT_GIMPLE_REG_P (nparm) = 0;
+ /* ??? This avoids mismatches in debug info bind stmts in
+ e.g. a-chahan . */
+ DECL_ABSTRACT_ORIGIN (nparm) = NULL;
+
+ if (nparmt)
+ adjust_ftype++;
+ }
+
+ /* Also adjust the wrapped function type, if needed. */
+ if (adjust_ftype)
+ {
+ tree nftype = TREE_TYPE (nnode->decl);
+
+ /* We always add at least one argument at the end of the signature, when
+ cloning the function, so we don't expect to need to duplicate the
+ type here. */
+ gcc_checking_assert (TYPE_ARG_TYPES (nftype)
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+
+ /* Check that fnspec still works for the modified function signature,
+ and drop it otherwise. */
+ bool drop_fnspec = false;
+ tree fnspec = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (nftype));
+ attr_fnspec spec = fnspec ? attr_fnspec (fnspec) : attr_fnspec ("");
+
+ unsigned retcopy;
+ if (!(fnspec && spec.returns_arg (&retcopy)))
+ retcopy = (unsigned) -1;
+
+ unsigned i = 0;
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (nftype);
+ adjust_ftype > 0;
+ i++, nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
+ if (indirect_nparms.contains (nparm))
+ {
+ TREE_VALUE (nparmt) = TREE_TYPE (nparm);
+ adjust_ftype--;
+
+ if (fnspec && !drop_fnspec)
+ {
+ if (i == retcopy)
+ drop_fnspec = true;
+ else if (spec.arg_specified_p (i))
+ {
+ /* Properties that apply to pointers only must not be
+ present, because we don't make pointers further
+ indirect. */
+ gcc_checking_assert
+ (!spec.arg_max_access_size_given_by_arg_p (i, NULL));
+ gcc_checking_assert (!spec.arg_copied_to_arg_p (i, NULL));
+
+ /* Any claim of direct access only is invalidated by
+ adding an indirection level. */
+ if (spec.arg_direct_p (i))
+ drop_fnspec = true;
+
+ /* If there's a claim the argument is not read from, the
+ added indirection invalidates it: if the argument is
+ used at all, then the pointer will necessarily be
+ read. */
+ if (!spec.arg_maybe_read_p (i)
+ && spec.arg_used_p (i))
+ drop_fnspec = true;
+ }
+ }
+ }
+
+ /* ??? Maybe we could adjust it instead. */
+ if (drop_fnspec)
+ remove_named_attribute_unsharing ("fn spec",
+ &TYPE_ATTRIBUTES (nftype));
+
+ TREE_TYPE (nnode->decl) = nftype;
+ }
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (nnode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1 + int (is_stdarg) + int (apply_args);
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ bool no_writes_p = true;
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
+ && curlen >= 2
+ && nspec[1] != 'c' && nspec[1] != 'C'
+ && nspec[1] != 'p' && nspec[1] != 'P')
+ no_writes_p = false;
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+
+ /* These extra args are unlikely to be present in const or pure
+ functions. It's conceivable that a function that takes variable
+ arguments, or that passes its arguments on to another function,
+ could be const or pure, but it would not modify the arguments, and,
+ being pure or const, it couldn't possibly modify or even access
+ memory referenced by them. But it can read from these internal
+ data structures created by the wrapper, and from any
+ argument-passing memory referenced by them, so we denote the
+ possibility of reading from multiple levels of indirection, but
+ only of reading because const/pure. */
+ if (apply_args)
+ {
+ nspec[curlen++] = 'r';
+ nspec[curlen++] = ' ';
+ }
+ if (is_stdarg)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
+ }
+ }
+#endif
+
+ {
+ tree decl = onode->decl;
+ cgraph_node *target = nnode;
+
+ { // copied from create_wrapper
+
+ /* Preserve DECL_RESULT so we get right by reference flag. */
+ tree decl_result = DECL_RESULT (decl);
+
+ /* Remove the function's body but keep arguments to be reused
+ for thunk. */
+ onode->release_body (true);
+ onode->reset (/* unlike create_wrapper: preserve_comdat_group = */true);
+
+ DECL_UNINLINABLE (decl) = false;
+ DECL_RESULT (decl) = decl_result;
+ DECL_INITIAL (decl) = NULL;
+ allocate_struct_function (decl, false);
+ set_cfun (NULL);
+
+ /* Turn alias into thunk and expand it into GIMPLE representation. */
+ onode->definition = true;
+
+ thunk_info::get_create (onode);
+ onode->thunk = true;
+ onode->create_edge (target, NULL, onode->count);
+ onode->callees->can_throw_external = !TREE_NOTHROW (target->decl);
+
+ tree arguments = DECL_ARGUMENTS (decl);
+
+ while (arguments)
+ {
+ TREE_ADDRESSABLE (arguments) = false;
+ arguments = TREE_CHAIN (arguments);
+ }
+
+ {
+ tree alias = onode->callees->callee->decl;
+ tree thunk_fndecl = decl;
+ tree a;
+
+ int nxargs = 1 + is_stdarg + apply_args;
+
+ { // Simplified from expand_thunk.
+ tree restype;
+ basic_block bb, then_bb, else_bb, return_bb;
+ gimple_stmt_iterator bsi;
+ int nargs = 0;
+ tree arg;
+ int i;
+ tree resdecl;
+ tree restmp = NULL;
+
+ gcall *call;
+ greturn *ret;
+ bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
+
+ a = DECL_ARGUMENTS (thunk_fndecl);
+
+ current_function_decl = thunk_fndecl;
+
+ /* Ensure thunks are emitted in their correct sections. */
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
+
+ bitmap_obstack_initialize (NULL);
+
+ /* Build the return declaration for the function. */
+ restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
+ if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
+ {
+ resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = thunk_fndecl;
+ DECL_RESULT (thunk_fndecl) = resdecl;
+ }
+ else
+ resdecl = DECL_RESULT (thunk_fndecl);
+
+ profile_count cfg_count = onode->count;
+ if (!cfg_count.initialized_p ())
+ cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
+
+ bb = then_bb = else_bb = return_bb
+ = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
+
+ bsi = gsi_start_bb (bb);
+
+ /* Build call to the function being thunked. */
+ if (!VOID_TYPE_P (restype)
+ && (!alias_is_noreturn
+ || TREE_ADDRESSABLE (restype)
+ || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
+ {
+ if (DECL_BY_REFERENCE (resdecl))
+ {
+ restmp = gimple_fold_indirect_ref (resdecl);
+ if (!restmp)
+ restmp = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (resdecl)),
+ resdecl,
+ build_int_cst (TREE_TYPE (resdecl), 0));
+ }
+ else if (!is_gimple_reg_type (restype))
+ {
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+ {
+ restmp = resdecl;
+
+ if (VAR_P (restmp))
+ {
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl))
+ = restmp;
+ }
+ }
+ else
+ restmp = create_tmp_var (restype, "retval");
+ }
+ else
+ restmp = create_tmp_reg (restype, "retval");
+ }
+
+ for (arg = a; arg; arg = DECL_CHAIN (arg))
+ nargs++;
+ auto_vec<tree> vargs (nargs + nxargs);
+ i = 0;
+ arg = a;
+
+ if (nargs)
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl);
+ i < nargs;
+ i++, arg = DECL_CHAIN (arg), nparm = DECL_CHAIN (nparm))
+ {
+ tree save_arg = arg;
+ tree tmp = arg;
+
+ /* Arrange to pass indirectly the parms, if we decided to do
+ so, and revert its type in the wrapper. */
+ if (indirect_nparms.contains (nparm))
+ {
+ tree ref_type = TREE_TYPE (nparm);
+ TREE_ADDRESSABLE (arg) = true;
+ tree addr = build1 (ADDR_EXPR, ref_type, arg);
+ tmp = arg = addr;
+ }
+ else
+ DECL_NOT_GIMPLE_REG_P (arg) = 0;
+
+ /* Convert the argument back to the type used by the calling
+ conventions, e.g. a non-prototyped float type is passed as
+ double, as in 930603-1.c, and needs to be converted back to
+ double to be passed on unchanged to the wrapped
+ function. */
+ if (TREE_TYPE (nparm) != DECL_ARG_TYPE (nparm))
+ arg = fold_convert (DECL_ARG_TYPE (nparm), arg);
+
+ if (!is_gimple_val (arg))
+ {
+ tmp = create_tmp_reg (TYPE_MAIN_VARIANT
+ (TREE_TYPE (arg)), "arg");
+ gimple *stmt = gimple_build_assign (tmp, arg);
+ gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
+ }
+ vargs.quick_push (tmp);
+ arg = save_arg;
+ }
+ /* These strub arguments are adjusted later. */
+ if (apply_args)
+ vargs.quick_push (null_pointer_node);
+ if (is_stdarg)
+ vargs.quick_push (null_pointer_node);
+ vargs.quick_push (null_pointer_node);
+ call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias),
+ vargs);
+ onode->callees->call_stmt = call;
+ // gimple_call_set_from_thunk (call, true);
+ if (DECL_STATIC_CHAIN (alias))
+ {
+ tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
+ tree type = TREE_TYPE (p);
+ tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ PARM_DECL, create_tmp_var_name ("CHAIN"),
+ type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_CONTEXT (decl) = thunk_fndecl;
+ DECL_ARG_TYPE (decl) = type;
+ TREE_READONLY (decl) = 1;
+
+ struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
+ sf->static_chain_decl = decl;
+
+ gimple_call_set_chain (call, decl);
+ }
+
+ /* Return slot optimization is always possible and in fact required to
+ return values with DECL_BY_REFERENCE. */
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+ && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+ || DECL_BY_REFERENCE (resdecl)))
+ gimple_call_set_return_slot_opt (call, true);
+
+ if (restmp)
+ {
+ gimple_call_set_lhs (call, restmp);
+ gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
+ TREE_TYPE (TREE_TYPE (alias))));
+ }
+ gsi_insert_after (&bsi, call, GSI_NEW_STMT);
+ if (!alias_is_noreturn)
+ {
+ /* Build return value. */
+ if (!DECL_BY_REFERENCE (resdecl))
+ ret = gimple_build_return (restmp);
+ else
+ ret = gimple_build_return (resdecl);
+
+ gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
+ }
+ else
+ {
+ remove_edge (single_succ_edge (bb));
+ }
+
+ cfun->gimple_df->in_ssa_p = true;
+ update_max_bb_count ();
+ profile_status_for_fn (cfun)
+ = cfg_count.initialized_p () && cfg_count.ipa_p ()
+ ? PROFILE_READ : PROFILE_GUESSED;
+ /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
+ // TREE_ASM_WRITTEN (thunk_fndecl) = false;
+ delete_unreachable_blocks ();
+ update_ssa (TODO_update_ssa);
+ checking_verify_flow_info ();
+ free_dominance_info (CDI_DOMINATORS);
+
+ /* Since we want to emit the thunk, we explicitly mark its name as
+ referenced. */
+ onode->thunk = false;
+ onode->lowered = true;
+ bitmap_obstack_release (NULL);
+ }
+ current_function_decl = NULL;
+ set_cfun (NULL);
+ }
+
+ thunk_info::remove (onode);
+
+ // some more of create_wrapper at the end of the next block.
+ }
+ }
+
+ {
+ tree aaval = NULL_TREE;
+ tree vaptr = NULL_TREE;
+ tree wmptr = NULL_TREE;
+ for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg))
+ {
+ aaval = vaptr;
+ vaptr = wmptr;
+ wmptr = arg;
+ }
+
+ if (!apply_args)
+ aaval = NULL_TREE;
+ /* The trailing args are [apply_args], [va_list_ptr], and
+ watermark. If we don't have a va_list_ptr, the penultimate
+ argument is apply_args.
+ */
+ else if (!is_stdarg)
+ aaval = vaptr;
+
+ if (!is_stdarg)
+ vaptr = NULL_TREE;
+
+ DECL_NAME (wmptr) = get_watermark_ptr ();
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_IGNORED_P (wmptr) = 1;
+ TREE_USED (wmptr) = 1;
+
+ if (is_stdarg)
+ {
+ DECL_NAME (vaptr) = get_va_list_ptr ();
+ DECL_ARTIFICIAL (vaptr) = 1;
+ DECL_IGNORED_P (vaptr) = 1;
+ TREE_USED (vaptr) = 1;
+ }
+
+ if (apply_args)
+ {
+ DECL_NAME (aaval) = get_apply_args ();
+ DECL_ARTIFICIAL (aaval) = 1;
+ DECL_IGNORED_P (aaval) = 1;
+ TREE_USED (aaval) = 1;
+ }
+
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ bool any_indirect = !indirect_nparms.is_empty ();
+
+ if (any_indirect)
+ {
+ basic_block bb;
+ bool needs_commit = false;
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
+ !gsi_end_p (gsi);
+ gsi_next_nonvirtual_phi (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed && !is_gimple_debug (gsi_stmt (gsi)))
+ if (walk_regimplify_phi (stmt))
+ needs_commit = true;
+ }
+
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed)
+ {
+ if (!is_gimple_debug (stmt))
+ {
+ wi.info = &gsi;
+ walk_gimple_op (stmt, walk_regimplify_addr_expr,
+ &wi);
+ }
+ update_stmt (stmt);
+ }
+ }
+ }
+ if (needs_commit)
+ gsi_commit_edge_inserts ();
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca
+ || is_stdarg || apply_args)
+ for (cgraph_edge *e = nnode->callees, *enext; e; e = enext)
+ {
+ if (!e->call_stmt)
+ continue;
+
+ gcall *call = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (call);
+ tree fndecl = e->callee->decl;
+
+ enext = e->next_callee;
+
+ if (gimple_alloca_call_p (call))
+ {
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ else if (fndecl && is_stdarg
+ && fndecl_built_in_p (fndecl, BUILT_IN_VA_START))
+ {
+ /* Using a non-default stdarg ABI makes the function ineligible
+ for internal strub. */
+ gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START)
+ == fndecl);
+ tree bvacopy = builtin_decl_explicit (BUILT_IN_VA_COPY);
+ gimple_call_set_fndecl (call, bvacopy);
+ tree arg = vaptr;
+ /* The va_copy source must be dereferenced, unless it's an array
+ type, that would have decayed to a pointer. */
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (vaptr))) != ARRAY_TYPE)
+ {
+ arg = gimple_fold_indirect_ref (vaptr);
+ if (!arg)
+ arg = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (vaptr)),
+ vaptr,
+ build_int_cst (TREE_TYPE (vaptr), 0));
+ }
+ gimple_call_set_arg (call, 1, arg);
+ update_stmt (call);
+ e->redirect_callee (cgraph_node::get_create (bvacopy));
+ }
+ else if (fndecl && apply_args
+ && fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
+ {
+ tree lhs = gimple_call_lhs (call);
+ gimple *assign = (lhs
+ ? gimple_build_assign (lhs, aaval)
+ : gimple_build_nop ());
+ gsi_replace (&gsi, assign, true);
+ cgraph_edge::remove (e);
+ }
+ }
+
+ { // a little more copied from create_wrapper
+
+ /* Inline summary set-up. */
+ nnode->analyze ();
+ // inline_analyze_function (nnode);
+ }
+
+ pop_cfun ();
+ }
+
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (onode->decl));
+ gimple_stmt_iterator gsi
+ = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+
+ gcall *wrcall;
+ while (!(wrcall = dyn_cast <gcall *> (gsi_stmt (gsi))))
+ gsi_next (&gsi);
+
+ tree swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1, unshare_expr (swmp));
+ gimple_set_location (stptr, gimple_location (wrcall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+
+ int nargs = gimple_call_num_args (wrcall);
+
+ gimple_seq seq = NULL;
+
+ if (apply_args)
+ {
+ tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args");
+ tree bappargs = builtin_decl_explicit (BUILT_IN_APPLY_ARGS);
+ gcall *appargs = gimple_build_call (bappargs, 0);
+ gimple_call_set_lhs (appargs, aalst);
+ gimple_set_location (appargs, gimple_location (wrcall));
+ gsi_insert_before (&gsi, appargs, GSI_SAME_STMT);
+ gimple_call_set_arg (wrcall, nargs - 2 - is_stdarg, aalst);
+ onode->create_edge (cgraph_node::get_create (bappargs),
+ appargs, gsi_bb (gsi)->count, false);
+ }
+
+ if (is_stdarg)
+ {
+ tree valst = create_tmp_var (va_list_type_node, ".strub.va_list");
+ TREE_ADDRESSABLE (valst) = true;
+ tree vaptr = build1 (ADDR_EXPR,
+ build_pointer_type (va_list_type_node),
+ valst);
+ gimple_call_set_arg (wrcall, nargs - 2, unshare_expr (vaptr));
+
+ tree bvastart = builtin_decl_explicit (BUILT_IN_VA_START);
+ gcall *vastart = gimple_build_call (bvastart, 2,
+ unshare_expr (vaptr),
+ integer_zero_node);
+ gimple_set_location (vastart, gimple_location (wrcall));
+ gsi_insert_before (&gsi, vastart, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (bvastart),
+ vastart, gsi_bb (gsi)->count, false);
+
+ tree bvaend = builtin_decl_explicit (BUILT_IN_VA_END);
+ gcall *vaend = gimple_build_call (bvaend, 1, unshare_expr (vaptr));
+ gimple_set_location (vaend, gimple_location (wrcall));
+ gimple_seq_add_stmt (&seq, vaend);
+ }
+
+ gimple_call_set_arg (wrcall, nargs - 1, unshare_expr (swmp));
+ // gimple_call_set_tail (wrcall, false);
+ update_stmt (wrcall);
+
+ {
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+
+ /* For nnode, we don't rebuild edges because we wish to retain
+ any redirections copied to it from earlier passes, so we add
+ call graph edges explicitly there, but for onode, we create a
+ fresh function, so we may as well just issue the calls and
+ then rebuild all cgraph edges. */
+ // cgraph_edge::rebuild_edges ();
+ onode->analyze ();
+ // inline_analyze_function (onode);
+
+ pop_cfun ();
+ }
+ }
+
+ return 0;
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub (gcc::context *ctxt)
+{
+ return new pass_ipa_strub (ctxt);
+}
diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h
new file mode 100644
index 0000000000000..29869fadfa6c9
--- /dev/null
+++ b/gcc/ipa-strub.h
@@ -0,0 +1,45 @@
+/* strub (stack scrubbing) infrastructure.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Return TRUE if CALLEE can be inlined into CALLER, as far as stack scrubbing
+ constraints are concerned. CALLEE doesn't have to be called directly by
+ CALLER, but the returned value says nothing about intervening functions. */
+extern bool strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller);
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+extern bool strub_splittable_p (cgraph_node *node);
+
+/* Locate and return the watermark_ptr parameter for FNDECL. If FNDECL is not a
+ strub context, return NULL. */
+extern tree strub_watermark_parm (tree fndecl);
+
+/* Make a function type or declaration callable. */
+extern void strub_make_callable (tree fndecl);
+
+/* Return zero iff ID is NOT an acceptable parameter for a user-supplied strub
+ attribute for a function. Otherwise, return >0 if it enables strub, <0 if it
+ does not. Return +/-1 if the attribute-modified type is compatible with the
+ type without the attribute, or +/-2 if it is not compatible. */
+extern int strub_validate_fn_attr_parm (tree id);
+
+/* Like comptypes, return 0 if t1 and t2 are not compatible, 1 if they are
+ compatible, and 2 if they are nearly compatible. Same strub mode is
+ compatible, interface-compatible strub modes are nearly compatible. */
+extern int strub_comptypes (tree t1, tree t2);
diff --git a/gcc/passes.def b/gcc/passes.def
index 6166279ec42c8..6cc7efd5d7653 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
INSERT_PASSES_AFTER (all_small_ipa_passes)
NEXT_PASS (pass_ipa_free_lang_data);
NEXT_PASS (pass_ipa_function_and_variable_visibility);
+ NEXT_PASS (pass_ipa_strub_mode);
NEXT_PASS (pass_build_ssa_passes);
PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
NEXT_PASS (pass_fixup_cfg);
@@ -113,6 +114,7 @@ along with GCC; see the file COPYING3. If not see
POP_INSERT_PASSES ()
NEXT_PASS (pass_ipa_remove_symbols);
+ NEXT_PASS (pass_ipa_strub);
NEXT_PASS (pass_ipa_oacc);
PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc)
NEXT_PASS (pass_ipa_pta);
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
new file mode 100644
index 0000000000000..c7a79a6ea0d8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O0, none of the strub builtins are expanded inline. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
new file mode 100644
index 0000000000000..96285c975d98e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O1, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
new file mode 100644
index 0000000000000..8edc0d8aa1321
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O2, without -fno-inline, we fully expand enter and update, and add a test
+ around the leave call. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
new file mode 100644
index 0000000000000..c6d900cf3c45b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
new file mode 100644
index 0000000000000..33ee465e51cb6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
new file mode 100644
index 0000000000000..2936f82079e18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
new file mode 100644
index 0000000000000..479746e57d87e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Og, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
new file mode 100644
index 0000000000000..2241d4ea07f27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Os, without -fno-inline, we fully expand enter, and also update. The
+ expanded update might be larger than a call proper, but argument saving and
+ restoring required by the call will most often make it larger. The leave
+ call is left untouched. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
new file mode 100644
index 0000000000000..a322bcc5da606
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
new file mode 100644
index 0000000000000..db60026d0e080
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
+ is set for static non-inline functions when not optimizing, and that keeps
+ only_called_directly_p from returning true, which makes STRUB_AT_CALLS
+ non-viable. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
new file mode 100644
index 0000000000000..2f462adc1efe0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__ ("callable")))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0);
+}
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ void *args = __builtin_apply_args ();
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
new file mode 100644
index 0000000000000..a5d7551f5da5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+extern void __attribute__ ((__strub__))
+apply_function (void *args);
+
+void __attribute__ ((__strub__))
+apply_args (int i, int j, double d) /* { dg-error "selected" } */
+{
+ void *args = __builtin_apply_args (); /* { dg-message "does not support" } */
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
new file mode 100644
index 0000000000000..64422a0d1e880
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0); /* { dg-error "in .strub. context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
new file mode 100644
index 0000000000000..15ffaa031b899
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+
+/* Check that implicit enabling of strub mode selects internal strub when the
+ function uses __builtin_apply_args, that prevents the optimization to
+ at-calls mode. */
+
+int __attribute__ ((__strub__)) var;
+
+static inline void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+void f() {
+ apply_args (1, 2, 3);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
new file mode 100644
index 0000000000000..b70843b4215a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
new file mode 100644
index 0000000000000..97a3988a6b922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
+ force_output is set for static non-inline functions when not optimizing, and
+ that keeps only_called_directly_p from returning true, which makes
+ STRUB_AT_CALLS non-viable. It becomes STRUB_CALLABLE instead. */
+static void
+g() {
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
new file mode 100644
index 0000000000000..3d73431b3dcd3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O1" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O1. */
+
+#include "strub-defer-O2.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
new file mode 100644
index 0000000000000..fddf3c745e7e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O2" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O2. */
+
+#define EXPECT_DEFERRAL !
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
new file mode 100644
index 0000000000000..5974e72efed46
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -0,0 +1,97 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O3" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -O3. */
+
+#ifndef EXPECT_DEFERRAL
+# define EXPECT_DEFERRAL
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char*)__builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+int
+look_for_string (char *e)
+{
+ char *p = (char*)__builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__strub__ ("at-calls"), __noinline__, __noclone__))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+deferred_at_calls ()
+{
+ char *ret = at_calls ();
+ if (EXPECT_DEFERRAL !look_for_string (ret))
+ __builtin_abort ();
+ return ret;
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+deferred_internal ()
+{
+ char *ret = at_calls ();
+ if (EXPECT_DEFERRAL !look_for_string (ret))
+ __builtin_abort ();
+ return ret;
+}
+
+int main ()
+{
+ if (look_for_string (deferred_at_calls ()))
+ __builtin_abort ();
+ if (look_for_string (deferred_internal ()))
+ __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
new file mode 100644
index 0000000000000..fbaf85fe0fafe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -Os" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -Os. */
+
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
new file mode 100644
index 0000000000000..e9d7b7b9ee0a8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
new file mode 100644
index 0000000000000..8b8e15a51c71c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
new file mode 100644
index 0000000000000..0a4a7539d3489
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("internal")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("internal")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
new file mode 100644
index 0000000000000..147171d96d5a1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("at-calls")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("at-calls")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]* \[(\]struct large_arg la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("at-calls")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]* \[(\]int i, void \\* &\[^&,\]*.strub.watermark_ptr\[, .]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-not "va_copy \\(" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
new file mode 100644
index 0000000000000..4e92682895a43
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that uses of a strub variable implicitly enables internal strub for
+ publicly-visible functions, and causes the same transformations to their
+ signatures as those in strub-parms1.c. */
+
+#include <stdarg.h>
+
+int __attribute__ ((__strub__)) var;
+
+void
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void
+large_byref_arg (struct large_arg la)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ var++;
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
new file mode 100644
index 0000000000000..e2f9d8aebca58
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. Without the error,
+ inlining takes place. */
+
+#include "strub-strict1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
new file mode 100644
index 0000000000000..98474435d2e59
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. */
+
+#include "strub-strict2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
new file mode 100644
index 0000000000000..1de15342595e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 89 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
new file mode 100644
index 0000000000000..f9209c819004b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
new file mode 100644
index 0000000000000..bed1dcfb54a45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
new file mode 100644
index 0000000000000..6bf0071f52b93
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
new file mode 100644
index 0000000000000..4732f515bf70c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
new file mode 100644
index 0000000000000..8d6424c479a3a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
new file mode 100644
index 0000000000000..368522442066e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* h becomes STRUB_INLINABLE, because of the use of the strub variable,
+ and the always_inline flag. It would get inlined before pass_ipa_strub, if
+ it weren't for the error. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+ var++;
+}
+
+/* g becomes STRUB_AT_CALLS_OPT, because of the use of the strub variable, and
+ the viability of at-calls strubbing. Though internally a strub context, its
+ interface is not strub-enabled, so it's not callable from within strub
+ contexts. */
+static inline void
+g() {
+ var--;
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
new file mode 100644
index 0000000000000..b4f2888321821
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* g becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. It's not STRUB_AT_CALLS_OPT
+ because force_output is set for static non-inline functions when not
+ optimizing, and that keeps only_called_directly_p from returning true, which
+ makes STRUB_AT_CALLS[_OPT] non-viable. */
+static void
+g() {
+ var--;
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
new file mode 100644
index 0000000000000..e48e0610e079b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+#include "strub-tail-O2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
new file mode 100644
index 0000000000000..87cda7ab21b16
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued.
+ Tail calls are short-circuited at -O2+. */
+
+int __attribute__ ((__strub__))
+g (int i, int j) {
+ return g (i, j);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 0 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 0 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
new file mode 100644
index 0000000000000..eb6250fd39c90
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+
+int __attribute__ ((strub)) x;
+float __attribute__ ((strub)) f;
+double __attribute__ ((strub)) d;
+
+/* The attribute applies to the type of the declaration, i.e., to the pointer
+ variable p, not to the pointed-to integer. */
+int __attribute__ ((strub)) *
+p = &x; /* { dg-message "incompatible|invalid conversion" } */
+
+typedef int __attribute__ ((strub)) strub_int;
+strub_int *q = &x; /* Now this is compatible. */
+
+int __attribute__ ((strub))
+a[2]; /* { dg-warning "does not apply to elements" } */
+
+int __attribute__ ((vector_size (4 * sizeof (int))))
+ __attribute__ ((strub))
+v; /* { dg-warning "does not apply to elements" } */
+
+struct s {
+ int i, j;
+} __attribute__ ((strub)) w; /* { dg-warning "does not apply to fields" } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
new file mode 100644
index 0000000000000..b5e45ab0525ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that strub and non-strub functions can be called from non-strub
+ contexts, and that strub and callable functions can be called from strub
+ contexts. */
+
+#define OMIT_IMPERMISSIBLE_CALLS 1
+#include "strub-callable2.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
new file mode 100644
index 0000000000000..96aa7fe4b07f7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -0,0 +1,264 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that impermissible (cross-strub-context) calls are reported. */
+
+extern int __attribute__ ((__strub__ ("callable"))) xcallable (void);
+extern int __attribute__ ((__strub__ ("internal"))) xinternal (void);
+extern int __attribute__ ((__strub__ ("at-calls"))) xat_calls (void);
+extern int __attribute__ ((__strub__ ("disabled"))) xdisabled (void);
+
+int __attribute__ ((__strub__ ("callable"))) callable (void);
+int __attribute__ ((__strub__ ("internal"))) internal (void);
+int __attribute__ ((__strub__ ("at-calls"))) at_calls (void);
+int __attribute__ ((__strub__ ("disabled"))) disabled (void);
+
+int __attribute__ ((__strub__)) var;
+int var_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+icallable (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+iinternal (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+idisabled (void);
+static inline int __attribute__ ((__always_inline__))
+ivar_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+i_callable (void) { return 0; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+i_internal (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+i_at_calls (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+i_disabled (void) { return 0; }
+static inline int __attribute__ ((__always_inline__))
+i_var_user (void) { return var; }
+
+#define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## at_calls (); \
+ ret += i ## ISEP ## internal (); \
+ ret += i ## ISEP ## var_user (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \
+ do { \
+ ret += internal (); \
+ ret += disabled (); \
+ ret += var_user (); \
+ \
+ ret += i ## ISEP ## disabled (); \
+ \
+ ret += xinternal (); \
+ ret += xdisabled (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## callable (); \
+ \
+ ret += callable (); \
+ ret += at_calls (); \
+ \
+ ret += xat_calls (); \
+ ret += xcallable (); \
+ } while (0)
+
+/* Not a strub context, so it can call anything.
+ Explicitly declared as callable even from within strub contexts. */
+int __attribute__ ((__strub__ ("callable")))
+callable (void) {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+/* Internal strubbing means the body is a strub context, so it can only call
+ strub functions, and it's not itself callable from strub functions. */
+int __attribute__ ((__strub__ ("internal")))
+internal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("at-calls")))
+at_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+disabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+int
+var_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+icallable (void)
+{
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+iinternal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+idisabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+ivar_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
new file mode 100644
index 0000000000000..2857195706ed6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const function call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __const__))
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
new file mode 100644
index 0000000000000..98a92bc9eac2b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const function call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
new file mode 100644
index 0000000000000..5511a6e1e71d3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __const__))
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
new file mode 100644
index 0000000000000..47ee927964dff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const wrapping call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
new file mode 100644
index 0000000000000..7c27a2a1a6dca
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointed-to data enables strubbing if accessed. */
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
new file mode 100644
index 0000000000000..e66d903780afd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, enabling internal strubbing when
+ its value is used. */
+int __attribute__ ((__strub__)) *ptr;
+
+int *f() {
+ return ptr;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
new file mode 100644
index 0000000000000..5e08e0e58c658
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) var;
+
+void f() {
+ var = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
new file mode 100644
index 0000000000000..a818e7a38bb5f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) *ptr;
+
+void f() {
+ ptr = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
new file mode 100644
index 0000000000000..ddb0b5c0543b0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* It would be desirable to issue at least warnings for these. */
+
+typedef int __attribute__ ((__strub__)) strub_int;
+strub_int *ptr;
+
+int *f () {
+ return ptr; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+strub_int *g () {
+ return f (); /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
new file mode 100644
index 0000000000000..c165f312f16de
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype ();
+fntype (*ptr);
+
+void f() {
+ ptr ();
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(&\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
new file mode 100644
index 0000000000000..69fcff8d3763d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
new file mode 100644
index 0000000000000..ff006224909bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0, 1, 1);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+, 1, 1)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
new file mode 100644
index 0000000000000..614b02228ba29
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+inline void __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+}
+
+void
+bat (void)
+{
+ /* Not allowed, not a strub context. */
+ inl_int_ali (); /* { dg-error "context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
new file mode 100644
index 0000000000000..f9a6b4a16faf8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all" } */
+
+#include "strub-inlinable1.c"
+
+/* With -fstrub=all, the caller becomes a strub context, so the strub-inlinable
+ callee is not rejected. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
new file mode 100644
index 0000000000000..b4a7f3992bbaa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+typedef void ft (void);
+typedef void ft2 (int, int);
+extern ft __attribute__ ((__strub__)) fnac;
+
+ft * f (void) {
+ return fnac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
new file mode 100644
index 0000000000000..d9d2c0caec42d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+
+/* C++ does not warn about the partial incompatibilities.
+
+ The d_p () calls are actually rejected, even in C++, but they are XFAILed
+ here because we don't get far enough in the compilation as to observe them,
+ because the incompatibilities are errors without -fpermissive.
+ strub-ptrfn3.c uses -fpermissive to check those.
+ */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
new file mode 100644
index 0000000000000..e1f179e160e5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
+/* { dg-prune-output "command-line option .-fpermissive." } */
+
+/* See strub-ptrfn2.c. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
new file mode 100644
index 0000000000000..70b558afad040
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+/* This is strub-ptrfn2.c without -Wpedantic.
+
+ Even C doesn't report the (not-quite-)compatible conversions without it. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
new file mode 100644
index 0000000000000..a262a086837b2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure function call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
new file mode 100644
index 0000000000000..4c4bd50c209a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure function call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
new file mode 100644
index 0000000000000..ce195c6b1f1b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
new file mode 100644
index 0000000000000..75cd54ccb5b5d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
new file mode 100644
index 0000000000000..7458b3fb54da5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Avoid the use of red zones by avoiding
+ leaf functions. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char *) __builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
new file mode 100644
index 0000000000000..5d60a7775f4bb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -0,0 +1,84 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Allow red zones to be used. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ asm ("" : "+rm" (len));
+ char s[2 * PAD + 1][len];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
new file mode 100644
index 0000000000000..c2ad710858e87
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ char *s = (char *) __builtin_alloca (len);
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
new file mode 100644
index 0000000000000..3b36b8e5d68ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -0,0 +1,106 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that multi-level, multi-inlined functions still get cleaned up as
+ expected, without overwriting temporary stack allocations while they should
+ still be available. */
+
+#ifndef ATTR_STRUB_AT_CALLS
+# define ATTR_STRUB_AT_CALLS /* Defined in strub-run4d.c. */
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__))
+char *
+leak_string (void)
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+innermost ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = leak_string ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+intermediate ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = innermost ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return intermediate ();
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
new file mode 100644
index 0000000000000..57f9baf758ded
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=at-calls" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
new file mode 100644
index 0000000000000..08de3f1c3b17c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+#define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
new file mode 100644
index 0000000000000..459f6886c5499
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=internal" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
new file mode 100644
index 0000000000000..0d367fb83d09d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -0,0 +1,19 @@
+// { dg-do run }
+// { dg-options "-fstrub=internal" }
+
+// Check that we don't get extra copies.
+
+struct T {
+ T &self;
+ void check () const { if (&self != this) __builtin_abort (); }
+ T() : self (*this) { check (); }
+ T(const T& ck) : self (*this) { ck.check (); check (); }
+ ~T() { check (); }
+};
+
+T foo (T q) { q.check (); return T(); }
+T bar (T p) { p.check (); return foo (p); }
+
+int main () {
+ bar (T()).check ();
+}
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
new file mode 100644
index 0000000000000..c226ab10ff651
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ static int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
new file mode 100644
index 0000000000000..a7911f1fa7212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+static int x = initializer ();
+
+int f() {
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
new file mode 100644
index 0000000000000..6ebebcd01e8ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
new file mode 100644
index 0000000000000..29e6996ecf61c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+
+-- The main subprogram doesn't read from the automatic variable, but
+-- being an automatic variable, its presence should be enough for the
+-- procedure to get strub enabled.
+
+procedure Strub_Access is
+ type Strub_Int is new Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ X : aliased Strub_Int := 0;
+
+ function F (P : access Strub_Int) return Strub_Int is (P.all);
+
+begin
+ X := F (X'Access);
+end Strub_Access;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls-opt\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
new file mode 100644
index 0000000000000..dae4706016436
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed" }
+
+-- Check that we reject 'Access of a strub variable whose type does
+-- not carry a strub modifier.
+
+procedure Strub_Access1 is
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function F (P : access Integer) return Integer is (P.all);
+
+begin
+ X := F (X'Unchecked_access); -- OK.
+ X := F (X'Access); -- { dg-error "target access type drops .strub. mode" }
+end Strub_Access1;
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
new file mode 100644
index 0000000000000..10445d7cf8451
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -0,0 +1,37 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+
+package body Strub_Attr is
+ E : exception;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (F (X));
+ -- function G return Integer is (FP (X));
+ -- Calling G would likely raise an exception, because although FP
+ -- carries the strub at-calls attribute needed to call F, the
+ -- attribute is dropped from the type used for the call proper.
+end Strub_Attr;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 2 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 0 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark_ptr" 6 "strub" } }
+-- We have 1 at-calls subprogram (F) and 2 wrapped (P and G).
+-- For each of them, there's one match for the wrapped signature,
+-- and one for the update call.
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark" 27 "strub" } }
+-- The 6 matches above, plus:
+-- 5*2: wm var decl, enter, call, leave and clobber for each wrapper;
+-- 2*1: an extra leave and clobber for the exception paths in the wrappers.
+-- 7*1: for the F call in G, including EH path.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.ads b/gcc/testsuite/gnat.dg/strub_attr.ads
new file mode 100644
index 0000000000000..a94c23bf41833
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.ads
@@ -0,0 +1,12 @@
+package Strub_Attr is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function G return Integer;
+end Strub_Attr;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
new file mode 100644
index 0000000000000..3dbcc4a357cba
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -0,0 +1,64 @@
+-- { dg-do compile }
+
+procedure Strub_Disp is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X));
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Disp;
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
new file mode 100644
index 0000000000000..09756a74b7d81
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -0,0 +1,79 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls are transformed.
+
+procedure Strub_Disp1 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X)); -- strub-at-calls non-dispatching call
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X); -- strub-at-calls dispatching call.
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access); -- strub-at-calls non-dispatching call
+ I := I + F (XB'Access); -- strub-at-calls non-dispatching call
+
+ XC := XA'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+
+ XC := XB'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+end Strub_Disp1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 3 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
new file mode 100644
index 0000000000000..da56acaa957d2
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -0,0 +1,33 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but applying attributes to access types as well.
+-- That doesn't quite work yet, so we get an error we shouldn't get.
+
+package body Strub_Ind is
+ E : exception;
+
+ function G return Integer;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+
+ type GT_SAC is access function return Integer;
+ pragma Machine_Attribute (GT_SAC, "strub", "at-calls");
+
+ GP : GT_SAC := GT_SAC (GT'(G'Access)); -- { dg-error "incompatible" }
+ -- pragma Machine_Attribute (GP, "strub", "at-calls");
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind.ads b/gcc/testsuite/gnat.dg/strub_ind.ads
new file mode 100644
index 0000000000000..99a65fc24b1ec
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.ads
@@ -0,0 +1,17 @@
+package Strub_Ind is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ -- pragma Machine_Attribute (FP, "strub", "at-calls"); -- not needed
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
new file mode 100644
index 0000000000000..825e395e6819c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -0,0 +1,41 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind1 is
+ E : exception;
+
+ type Strub_Int is New Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "disabled");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "disabled");
+
+ type GT_SC is access function return Integer;
+ pragma Machine_Attribute (GT_SC, "strub", "callable");
+
+ GP : GT_SC := GT_SC (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "callable"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all;
+ end;
+
+end Strub_Ind1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]disabled\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.ads b/gcc/testsuite/gnat.dg/strub_ind1.ads
new file mode 100644
index 0000000000000..d3f1273b3a6b9
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.ads
@@ -0,0 +1,17 @@
+package Strub_Ind1 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind1;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
new file mode 100644
index 0000000000000..e918b39263117
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -0,0 +1,34 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind2 is
+ E : exception;
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "callable");
+
+ type GT_SD is access function return Integer;
+ pragma Machine_Attribute (GT_SD, "strub", "disabled");
+
+ GP : GT_SD := GT_SD (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "disabled"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all; -- { dg-error "using non-.strub. type" }
+ end;
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.ads b/gcc/testsuite/gnat.dg/strub_ind2.ads
new file mode 100644
index 0000000000000..e13865ec49c38
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.ads
@@ -0,0 +1,17 @@
+package Strub_Ind2 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
new file mode 100644
index 0000000000000..8f0212a75866f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -0,0 +1,93 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported.
+
+procedure Strub_Intf is
+ package Foo is
+ type TP is interface;
+ procedure P (I : Integer; X : TP) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type TF is interface;
+ function F (X : access TF) return Integer is abstract;
+
+ type TX is interface;
+ procedure P (I : Integer; X : TX) is abstract;
+
+ type TI is interface and TP and TF and TX;
+ -- When we freeze TI, we detect the mismatch between the
+ -- inherited P and another parent's P. Because TP appears
+ -- before TX, we inherit P from TP, and report the mismatch at
+ -- the pragma inherited from TP against TX's P. In contrast,
+ -- when we freeze TII below, since TX appears before TP, we
+ -- report the error at the line in which the inherited
+ -- subprogram is synthesized, namely the line below, against
+ -- the line of the pragma.
+
+ type TII is interface and TX and TP and TF; -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access TI) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type A is new TI with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer; -- { dg-error "requires the same .strub. mode" }
+
+ type B is new TI with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TI'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf;
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
new file mode 100644
index 0000000000000..bf77321cef790
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -0,0 +1,86 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls to interfaces are transformed.
+
+procedure Strub_Intf1 is
+ package Foo is
+ type TX is Interface;
+ procedure P (I : Integer; X : TX) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls");
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type A is new TX with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new TX with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 2 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
new file mode 100644
index 0000000000000..e8880dbc43730
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -0,0 +1,55 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported even when the overriders for an
+-- interface's subprograms are inherited from a type that is not a
+-- descendent of the interface.
+
+procedure Strub_Intf2 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer;
+
+ type TX is Interface;
+
+ procedure P (I : Integer; X : TX) is abstract;
+
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A and TX with null record; -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XB);
+
+ I := I + F (XB'Access);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf2;
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
new file mode 100644
index 0000000000000..217367e712d82
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+
+procedure Strub_Renm is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+ pragma Machine_Attribute (F, "strub", "internal");
+
+ procedure Q (X : Integer) renames P; -- { dg-error "requires the same .strub. mode" }
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "callable"); -- { dg-error "requires the same .strub. mode" }
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm;
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
new file mode 100644
index 0000000000000..a11adbfb5a9d6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+
+procedure Strub_Renm1 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "internal");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm1;
+
+-- This is for P; Q is an alias.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 1 "strub" } }
+
+-- This is *not* for G, but for Strub_Renm1.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapped\[)\]\[)\]" 1 "strub" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapper\[)\]\[)\]" 1 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
new file mode 100644
index 0000000000000..c488c20826fdb
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strub" }
+
+procedure Strub_Renm2 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ type T is access function return Integer;
+
+ type TC is access function return Integer;
+ pragma Machine_Attribute (TC, "strub", "callable");
+
+ FCptr : constant TC := TC (T'(F'Access));
+
+ function G return Integer renames FCptr.all;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F); -- { dg-error "calling non-.strub." }
+ Q (G); -- ok, G is callable.
+end Strub_Renm2;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
new file mode 100644
index 0000000000000..3d158de28031f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- We don't read from the automatic variable, but being an automatic
+-- variable, its presence should be enough for the procedure to get
+-- strub enabled.
+
+with Strub_Attr;
+procedure Strub_Var is
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+begin
+ X := Strub_Attr.F (0);
+end Strub_Var;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
new file mode 100644
index 0000000000000..6a504e09198b6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -0,0 +1,20 @@
+-- { dg-do compile }
+
+with Strub_Attr;
+procedure Strub_Var1 is
+ type TA -- { dg-warning "does not apply to elements" }
+ is array (1..2) of Integer;
+ pragma Machine_Attribute (TA, "strub");
+
+ A : TA := (0, 0); -- { dg-warning "does not apply to elements" }
+
+ type TR is record -- { dg-warning "does not apply to fields" }
+ M, N : Integer;
+ end record;
+ pragma Machine_Attribute (TR, "strub");
+
+ R : TR := (0, 0);
+
+begin
+ A(2) := Strub_Attr.F (A(1));
+end Strub_Var1;
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 30f26af69f287..395d32f5faaca 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -5738,6 +5738,7 @@ gimple_verify_flow_info (void)
{
gimple *stmt = gsi_stmt (gsi);
+ /* Do NOT disregard debug stmts after found_ctrl_stmt. */
if (found_ctrl_stmt)
{
error ("control flow in the middle of basic block %d",
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index b39d2c5db958d..e628a87187075 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -506,8 +506,9 @@ extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
-extern simple_ipa_opt_pass
- *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tree_profile (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_auto_profile (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 26d5e445abd55..4428133c188be 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -3069,7 +3069,9 @@ optimize_stack_restore (gimple_stmt_iterator i)
if (!callee
|| !fndecl_built_in_p (callee, BUILT_IN_NORMAL)
/* All regular builtins are ok, just obviously not alloca. */
- || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)))
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
+ /* Do not remove stack updates before strub leave. */
+ || fndecl_built_in_p (callee, BUILT_IN___STRUB_LEAVE))
return NULL_TREE;
if (fndecl_built_in_p (callee, BUILT_IN_STACK_RESTORE))
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 0135d2740661f..d30e791bb956c 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -433,6 +433,9 @@ LIB2ADD += enable-execute-stack.c
# Control Flow Redundancy hardening out-of-line checker.
LIB2ADD += $(srcdir)/hardcfr.c
+# Stack scrubbing infrastructure.
+LIB2ADD += $(srcdir)/strub.c
+
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
# instead of LIB2ADD because that's the way to be sure on some targets
# (e.g. *-*-darwin*) only one copy of it is linked.
diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h
index 3ec9bbd816475..5cdb58648ac33 100644
--- a/libgcc/libgcc2.h
+++ b/libgcc/libgcc2.h
@@ -536,6 +536,10 @@ extern int __parityDI2 (UDWtype);
extern void __enable_execute_stack (void *);
+extern void __strub_enter (void **);
+extern void __strub_update (void**);
+extern void __strub_leave (void **);
+
#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
#endif
diff --git a/libgcc/strub.c b/libgcc/strub.c
new file mode 100644
index 0000000000000..2a2b930b6039d
--- /dev/null
+++ b/libgcc/strub.c
@@ -0,0 +1,149 @@
+/* Stack scrubbing infrastructure
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+#include "libgcc2.h"
+
+#ifndef STACK_GROWS_DOWNWARD
+# define TOPS >
+#else
+# define TOPS <
+#endif
+
+#define ATTRIBUTE_STRUB_CALLABLE __attribute__ ((__strub__ ("callable")))
+
+/* Enter a stack scrubbing context, initializing the watermark to the caller's
+ stack address. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_enter (void **watermark)
+{
+ *watermark = __builtin_frame_address (0);
+}
+
+/* Update the watermark within a stack scrubbing context with the current stack
+ pointer. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_update (void **watermark)
+{
+ void *sp = __builtin_frame_address (0);
+
+ if (sp TOPS *watermark)
+ *watermark = sp;
+}
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY && ! defined TARGET_STRUB_MAY_USE_MEMSET
+# define TARGET_STRUB_MAY_USE_MEMSET 1
+#endif
+
+#if defined __x86_64__ && __OPTIMIZE__
+# define TARGET_STRUB_DISABLE_RED_ZONE \
+ /* __attribute__ ((__target__ ("no-red-zone"))) // not needed when optimizing */
+#elif !defined RED_ZONE_SIZE || defined __i386__
+# define TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+
+#ifndef TARGET_STRUB_DISABLE_RED_ZONE
+/* Dummy function, called to force the caller to not be a leaf function, so
+ that it can't use the red zone. */
+static void ATTRIBUTE_STRUB_CALLABLE
+__attribute__ ((__noinline__, __noipa__))
+__strub_dummy_force_no_leaf (void)
+{
+}
+#endif
+
+/* Leave a stack scrubbing context, clearing the stack between its top and
+ *MARK. */
+void ATTRIBUTE_STRUB_CALLABLE
+#if ! TARGET_STRUB_MAY_USE_MEMSET
+__attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
+#endif
+#ifdef TARGET_STRUB_DISABLE_RED_ZONE
+TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+__strub_leave (void **mark)
+{
+ void *sp = __builtin_stack_address ();
+
+ void **base, **end;
+#ifndef STACK_GROWS_DOWNWARD
+ base = sp; /* ??? Do we need an offset here? */
+ end = *mark;
+#else
+ base = *mark;
+ end = sp; /* ??? Does any platform require an offset here? */
+#endif
+
+ if (! (base < end))
+ return;
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY
+ /* Compute the length without assuming the pointers are both sufficiently
+ aligned. They should be, but pointer differences expected to be exact may
+ yield unexpected results when the assumption doesn't hold. Given the
+ potential security implications, compute the length without that
+ expectation. If the pointers are misaligned, we may leave a partial
+ unscrubbed word behind. */
+ ptrdiff_t len = ((char *)end - (char *)base) / sizeof (void *);
+ /* Allocate a dynamically-sized array covering the desired range, so that we
+ can safely call memset on it. */
+ void *ptr[len];
+ base = &ptr[0];
+ end = &ptr[len];
+#elifndef TARGET_STRUB_DISABLE_RED_ZONE
+ /* Prevent the use of the red zone, by making this function non-leaf through
+ an unreachable call that, because of the asm stmt, the compiler will
+ consider reachable. */
+ asm goto ("" : : : : no_leaf);
+ if (0)
+ {
+ no_leaf:
+ __strub_dummy_force_no_leaf ();
+ return;
+ }
+#endif
+
+ /* ldist may turn these loops into a memset (thus the conditional
+ -fno-tree-loop-distribute-patterns above). Without the dynamic array
+ above, that call would likely be unsafe: possibly tail-called, and likely
+ scribbling over its own stack frame. */
+#ifndef STACK_GROWS_DOWNWARD
+ do
+ *base++ = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (end[0]));
+#else
+ do
+ *--end = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (base[0]));
+#endif
+}
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
Disinformation flourishes because many people care deeply about injustice
but very few check the facts. Ask me about <https://stallmansupport.org>
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-06-16 6:09 ` [PATCH v3] " Alexandre Oliva
@ 2023-10-20 6:03 ` Alexandre Oliva
2023-10-26 6:15 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-10-20 6:03 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson, Jeff Law
This is a refreshed and improved version of the version posted back in
June. https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621936.html
Compared with the previous version, this patch initializes probabilities
of newly-created EH edges and execution counts of EH newly-created
blocks; drops obsolete preprocessor conditionals; improve GCing of
identifiers, decls and types introduced by strub; enable gengtype to
cope with token pasting within multi-line macros; gimplify wrapped
va-list loading (needed on ppc64le); adjusted more testcases to tolerate
async stack overwrites.
Regstrapped on x86_64-linux-gnu and ppc64le-linux-gnu, also boostrapped
with -fstrub=all. Ok to install?
----
This patch adds the strub attribute for function and variable types,
command-line options, passes and adjustments to implement it,
documentation, and tests.
Stack scrubbing is implemented in a machine-independent way: functions
with strub enabled are modified so that they take an extra stack
watermark argument, that they update with their stack use, and the
caller can then zero it out once it regains control, whether by return
or exception. There are two ways to go about it: at-calls, that
modifies the visible interface (signature) of the function, and
internal, in which the body is moved to a clone, the clone undergoes
the interface change, and the function becomes a wrapper, preserving
its original interface, that calls the clone and then clears the stack
used by it.
Variables can also be annotated with the strub attribute, so that
functions that read from them get stack scrubbing enabled implicitly,
whether at-calls, for functions only usable within a translation unit,
or internal, for functions whose interfaces must not be modified.
There is a strict mode, in which functions that have their stack
scrubbed can only call other functions with stack-scrubbing
interfaces, or those explicitly marked as callable from strub
contexts, so that an entire call chain gets scrubbing, at once or
piecemeal depending on optimization levels. In the default mode,
relaxed, this requirement is not enforced by the compiler.
The implementation adds two IPA passes, one that assigns strub modes
early on, another that modifies interfaces and adds calls to the
builtins that jointly implement stack scrubbing. Another builtin,
that obtains the stack pointer, is added for use in the implementation
of the builtins, whether expanded inline or called in libgcc.
There are new command-line options to change operation modes and to
force the feature disabled; it is enabled by default, but it has no
effect and is implicitly disabled if the strub attribute is never
used. There are also options meant to use for testing the feature,
enabling different strubbing modes for all (viable) functions.
for gcc/ChangeLog
* Makefile.in (OBJS): Add ipa-strub.o.
(GTFILES): Add ipa-strub.cc.
* builtins.def (BUILT_IN_STACK_ADDRESS): New.
(BUILT_IN___STRUB_ENTER): New.
(BUILT_IN___STRUB_UPDATE): New.
(BUILT_IN___STRUB_LEAVE): New.
* builtins.cc: Include ipa-strub.h.
(STACK_STOPS, STACK_UNSIGNED): Define.
(expand_builtin_stack_address): New.
(expand_builtin_strub_enter): New.
(expand_builtin_strub_update): New.
(expand_builtin_strub_leave): New.
(expand_builtin): Call them.
* common.opt (fstrub=*): New options.
* doc/extend.texi (strub): New type attribute.
(__builtin_stack_address): New function.
(Stack Scrubbing): New section.
* doc/invoke.texi (-fstrub=*): New options.
(-fdump-ipa-*): New passes.
* gengtype-lex.l: Ignore multi-line pp-directives.
* ipa-inline.cc: Include ipa-strub.h.
(can_inline_edge_p): Test strub_inlinable_to_p.
* ipa-split.cc: Include ipa-strub.h.
(execute_split_functions): Test strub_splittable_p.
* ipa-strub.cc, ipa-strub.h: New.
* passes.def: Add strub_mode and strub passes.
* tree-cfg.cc (gimple_verify_flow_info): Note on debug stmts.
* tree-pass.h (make_pass_ipa_strub_mode): Declare.
(make_pass_ipa_strub): Declare.
(make_pass_ipa_function_and_variable_visibility): Fix
formatting.
* tree-ssa-ccp.cc (optimize_stack_restore): Keep restores
before strub leave.
* multiple_target.cc (pass_target_clone::gate): Test seen_error.
* attribs.cc: Include ipa-strub.h.
(decl_attributes): Support applying attributes to function
type, rather than pointer type, at handler's request.
(comp_type_attributes): Combine strub_comptypes and target
comp_type results.
* doc/tm.texi.in (TARGET_STRUB_USE_DYNAMIC_ARRAY): New.
(TARGET_STRUB_MAY_USE_MEMSET): New.
* doc/tm.texi: Rebuilt.
* cgraph.h (symtab_node::reset): Add preserve_comdat_group
param, with a default.
* cgraphunit.cc (symtab_node::reset): Use it.
for gcc/c-family/ChangeLog
* c-attribs.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(c_common_attribute_table): Add strub.
for gcc/ada/ChangeLog
* gcc-interface/trans.cc: Include ipa-strub.h.
(gigi): Make internal decls for targets of compiler-generated
calls strub-callable too.
(build_raise_check): Likewise.
* gcc-interface/utils.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(gnat_internal_attribute_table): Add strub.
for gcc/testsuite/ChangeLog
* c-c++-common/strub-O0.c: New.
* c-c++-common/strub-O1.c: New.
* c-c++-common/strub-O2.c: New.
* c-c++-common/strub-O2fni.c: New.
* c-c++-common/strub-O3.c: New.
* c-c++-common/strub-O3fni.c: New.
* c-c++-common/strub-Og.c: New.
* c-c++-common/strub-Os.c: New.
* c-c++-common/strub-all1.c: New.
* c-c++-common/strub-all2.c: New.
* c-c++-common/strub-apply1.c: New.
* c-c++-common/strub-apply2.c: New.
* c-c++-common/strub-apply3.c: New.
* c-c++-common/strub-apply4.c: New.
* c-c++-common/strub-at-calls1.c: New.
* c-c++-common/strub-at-calls2.c: New.
* c-c++-common/strub-defer-O1.c: New.
* c-c++-common/strub-defer-O2.c: New.
* c-c++-common/strub-defer-O3.c: New.
* c-c++-common/strub-defer-Os.c: New.
* c-c++-common/strub-internal1.c: New.
* c-c++-common/strub-internal2.c: New.
* c-c++-common/strub-parms1.c: New.
* c-c++-common/strub-parms2.c: New.
* c-c++-common/strub-parms3.c: New.
* c-c++-common/strub-relaxed1.c: New.
* c-c++-common/strub-relaxed2.c: New.
* c-c++-common/strub-short-O0-exc.c: New.
* c-c++-common/strub-short-O0.c: New.
* c-c++-common/strub-short-O1.c: New.
* c-c++-common/strub-short-O2.c: New.
* c-c++-common/strub-short-O3.c: New.
* c-c++-common/strub-short-Os.c: New.
* c-c++-common/strub-strict1.c: New.
* c-c++-common/strub-strict2.c: New.
* c-c++-common/strub-tail-O1.c: New.
* c-c++-common/strub-tail-O2.c: New.
* c-c++-common/torture/strub-callable1.c: New.
* c-c++-common/torture/strub-callable2.c: New.
* c-c++-common/torture/strub-const1.c: New.
* c-c++-common/torture/strub-const2.c: New.
* c-c++-common/torture/strub-const3.c: New.
* c-c++-common/torture/strub-const4.c: New.
* c-c++-common/torture/strub-data1.c: New.
* c-c++-common/torture/strub-data2.c: New.
* c-c++-common/torture/strub-data3.c: New.
* c-c++-common/torture/strub-data4.c: New.
* c-c++-common/torture/strub-data5.c: New.
* c-c++-common/torture/strub-indcall1.c: New.
* c-c++-common/torture/strub-indcall2.c: New.
* c-c++-common/torture/strub-indcall3.c: New.
* c-c++-common/torture/strub-inlinable1.c: New.
* c-c++-common/torture/strub-inlinable2.c: New.
* c-c++-common/torture/strub-ptrfn1.c: New.
* c-c++-common/torture/strub-ptrfn2.c: New.
* c-c++-common/torture/strub-ptrfn3.c: New.
* c-c++-common/torture/strub-ptrfn4.c: New.
* c-c++-common/torture/strub-pure1.c: New.
* c-c++-common/torture/strub-pure2.c: New.
* c-c++-common/torture/strub-pure3.c: New.
* c-c++-common/torture/strub-pure4.c: New.
* c-c++-common/torture/strub-run1.c: New.
* c-c++-common/torture/strub-run2.c: New.
* c-c++-common/torture/strub-run3.c: New.
* c-c++-common/torture/strub-run4.c: New.
* c-c++-common/torture/strub-run4c.c: New.
* c-c++-common/torture/strub-run4d.c: New.
* c-c++-common/torture/strub-run4i.c: New.
* g++.dg/strub-run1.C: New.
* g++.dg/torture/strub-init1.C: New.
* g++.dg/torture/strub-init2.C: New.
* g++.dg/torture/strub-init3.C: New.
* gnat.dg/strub_attr.adb, gnat.dg/strub_attr.ads: New.
* gnat.dg/strub_ind.adb, gnat.dg/strub_ind.ads: New.
for libgcc/ChangeLog
* Makefile.in (LIB2ADD): Add strub.c.
* libgcc2.h (__strub_enter, __strub_update, __strub_leave):
Declare.
* strub.c: New.
---
gcc/Makefile.in | 2
gcc/ada/gcc-interface/trans.cc | 18
gcc/ada/gcc-interface/utils.cc | 73
gcc/attribs.cc | 37
gcc/builtins.cc | 269 ++
gcc/builtins.def | 4
gcc/c-family/c-attribs.cc | 82
gcc/cgraph.h | 2
gcc/cgraphunit.cc | 5
gcc/common.opt | 29
gcc/doc/extend.texi | 307 ++
gcc/doc/invoke.texi | 60
gcc/doc/tm.texi | 19
gcc/doc/tm.texi.in | 19
gcc/gengtype-lex.l | 3
gcc/ipa-inline.cc | 6
gcc/ipa-split.cc | 7
gcc/ipa-strub.cc | 3454 ++++++++++++++++++++
gcc/ipa-strub.h | 45
gcc/passes.def | 2
gcc/testsuite/c-c++-common/strub-O0.c | 14
gcc/testsuite/c-c++-common/strub-O1.c | 15
gcc/testsuite/c-c++-common/strub-O2.c | 16
gcc/testsuite/c-c++-common/strub-O2fni.c | 15
gcc/testsuite/c-c++-common/strub-O3.c | 12
gcc/testsuite/c-c++-common/strub-O3fni.c | 15
gcc/testsuite/c-c++-common/strub-Og.c | 16
gcc/testsuite/c-c++-common/strub-Os.c | 18
gcc/testsuite/c-c++-common/strub-all1.c | 32
gcc/testsuite/c-c++-common/strub-all2.c | 24
gcc/testsuite/c-c++-common/strub-apply1.c | 15
gcc/testsuite/c-c++-common/strub-apply2.c | 12
gcc/testsuite/c-c++-common/strub-apply3.c | 8
gcc/testsuite/c-c++-common/strub-apply4.c | 21
gcc/testsuite/c-c++-common/strub-at-calls1.c | 30
gcc/testsuite/c-c++-common/strub-at-calls2.c | 23
gcc/testsuite/c-c++-common/strub-defer-O1.c | 7
gcc/testsuite/c-c++-common/strub-defer-O2.c | 8
gcc/testsuite/c-c++-common/strub-defer-O3.c | 110 +
gcc/testsuite/c-c++-common/strub-defer-Os.c | 7
gcc/testsuite/c-c++-common/strub-internal1.c | 31
gcc/testsuite/c-c++-common/strub-internal2.c | 21
gcc/testsuite/c-c++-common/strub-parms1.c | 48
gcc/testsuite/c-c++-common/strub-parms2.c | 36
gcc/testsuite/c-c++-common/strub-parms3.c | 58
gcc/testsuite/c-c++-common/strub-relaxed1.c | 18
gcc/testsuite/c-c++-common/strub-relaxed2.c | 14
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 10
gcc/testsuite/c-c++-common/strub-short-O0.c | 10
gcc/testsuite/c-c++-common/strub-short-O1.c | 10
gcc/testsuite/c-c++-common/strub-short-O2.c | 10
gcc/testsuite/c-c++-common/strub-short-O3.c | 12
gcc/testsuite/c-c++-common/strub-short-Os.c | 12
gcc/testsuite/c-c++-common/strub-strict1.c | 36
gcc/testsuite/c-c++-common/strub-strict2.c | 25
gcc/testsuite/c-c++-common/strub-tail-O1.c | 8
gcc/testsuite/c-c++-common/strub-tail-O2.c | 14
gcc/testsuite/c-c++-common/strub-var1.c | 24
.../c-c++-common/torture/strub-callable1.c | 9
.../c-c++-common/torture/strub-callable2.c | 264 ++
gcc/testsuite/c-c++-common/torture/strub-const1.c | 18
gcc/testsuite/c-c++-common/torture/strub-const2.c | 22
gcc/testsuite/c-c++-common/torture/strub-const3.c | 13
gcc/testsuite/c-c++-common/torture/strub-const4.c | 17
gcc/testsuite/c-c++-common/torture/strub-data1.c | 13
gcc/testsuite/c-c++-common/torture/strub-data2.c | 14
gcc/testsuite/c-c++-common/torture/strub-data3.c | 14
gcc/testsuite/c-c++-common/torture/strub-data4.c | 14
gcc/testsuite/c-c++-common/torture/strub-data5.c | 15
.../c-c++-common/torture/strub-indcall1.c | 14
.../c-c++-common/torture/strub-indcall2.c | 14
.../c-c++-common/torture/strub-indcall3.c | 14
.../c-c++-common/torture/strub-inlinable1.c | 16
.../c-c++-common/torture/strub-inlinable2.c | 7
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 10
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 55
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 50
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 43
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17
gcc/testsuite/c-c++-common/torture/strub-run1.c | 95 +
gcc/testsuite/c-c++-common/torture/strub-run2.c | 84
gcc/testsuite/c-c++-common/torture/strub-run3.c | 80
gcc/testsuite/c-c++-common/torture/strub-run4.c | 106 +
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 5
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 7
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 5
gcc/testsuite/g++.dg/strub-run1.C | 19
gcc/testsuite/g++.dg/torture/strub-init1.C | 13
gcc/testsuite/g++.dg/torture/strub-init2.C | 14
gcc/testsuite/g++.dg/torture/strub-init3.C | 13
gcc/testsuite/gnat.dg/strub_access.adb | 21
gcc/testsuite/gnat.dg/strub_access1.adb | 16
gcc/testsuite/gnat.dg/strub_attr.adb | 37
gcc/testsuite/gnat.dg/strub_attr.ads | 12
gcc/testsuite/gnat.dg/strub_disp.adb | 64
gcc/testsuite/gnat.dg/strub_disp1.adb | 79
gcc/testsuite/gnat.dg/strub_ind.adb | 33
gcc/testsuite/gnat.dg/strub_ind.ads | 17
gcc/testsuite/gnat.dg/strub_ind1.adb | 41
gcc/testsuite/gnat.dg/strub_ind1.ads | 17
gcc/testsuite/gnat.dg/strub_ind2.adb | 34
gcc/testsuite/gnat.dg/strub_ind2.ads | 17
gcc/testsuite/gnat.dg/strub_intf.adb | 93 +
gcc/testsuite/gnat.dg/strub_intf1.adb | 86
gcc/testsuite/gnat.dg/strub_intf2.adb | 55
gcc/testsuite/gnat.dg/strub_renm.adb | 21
gcc/testsuite/gnat.dg/strub_renm1.adb | 32
gcc/testsuite/gnat.dg/strub_renm2.adb | 32
gcc/testsuite/gnat.dg/strub_var.adb | 16
gcc/testsuite/gnat.dg/strub_var1.adb | 20
gcc/tree-cfg.cc | 1
gcc/tree-pass.h | 5
gcc/tree-ssa-ccp.cc | 4
libgcc/Makefile.in | 3
libgcc/libgcc2.h | 4
libgcc/strub.c | 149 +
119 files changed, 7302 insertions(+), 12 deletions(-)
create mode 100644 gcc/ipa-strub.cc
create mode 100644 gcc/ipa-strub.h
create mode 100644 gcc/testsuite/c-c++-common/strub-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Og.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply4.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0-exc.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-var1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data5.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4c.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4d.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4i.c
create mode 100644 gcc/testsuite/g++.dg/strub-run1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init2.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init3.C
create mode 100644 gcc/testsuite/gnat.dg/strub_access.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_access1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_disp.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_disp1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_intf.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var1.adb
create mode 100644 libgcc/strub.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a25a1e32fbc5f..53e953e224344 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1542,6 +1542,7 @@ OBJS = \
ipa-reference.o \
ipa-ref.o \
ipa-utils.o \
+ ipa-strub.o \
ipa.o \
ira.o \
ira-build.o \
@@ -2846,6 +2847,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/sanopt.cc \
$(srcdir)/sancov.cc \
$(srcdir)/ipa-devirt.cc \
+ $(srcdir)/ipa-strub.cc \
$(srcdir)/internal-fn.h \
$(srcdir)/calls.cc \
$(srcdir)/omp-general.h \
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index 89f0a07c824e3..49046bf51fb38 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -69,6 +69,21 @@
#include "ada-tree.h"
#include "gigi.h"
+/* The following #include is for strub_make_callable.
+
+ This function marks a function as safe to call from strub contexts. We mark
+ Ada subprograms that may be called implicitly by the compiler, and that won't
+ leave on the stack caller data passed to them. This stops implicit calls
+ introduced in subprograms that have their stack scrubbed from being flagged
+ as unsafe, even in -fstrub=strict mode.
+
+ These subprograms are also marked with the strub(callable) attribute in Ada
+ sources, but their declarations aren't necessarily imported by GNAT, or made
+ visible to gigi, in units that end up relying on them. So when gigi
+ introduces their declarations on its own, it must also add the attribute, by
+ calling strub_make_callable. */
+#include "ipa-strub.h"
+
/* We should avoid allocating more than ALLOCA_THRESHOLD bytes via alloca,
for fear of running out of stack space. If we need more, we use xmalloc
instead. */
@@ -454,6 +469,7 @@ gigi (Node_Id gnat_root,
int64_type, NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv64_decl);
if (Enable_128bit_Types)
{
@@ -466,6 +482,7 @@ gigi (Node_Id gnat_root,
NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv128_decl);
}
/* Name of the _Parent field in tagged record types. */
@@ -722,6 +739,7 @@ build_raise_check (int check, enum exception_info_kind kind)
= create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype,
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (result);
set_call_expr_flags (result, ECF_NORETURN | ECF_XTHROW);
return result;
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index 4e2ed173fbe97..5b4d16d7904ae 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -39,6 +39,7 @@
#include "varasm.h"
#include "toplev.h"
#include "opts.h"
+#include "ipa-strub.h"
#include "output.h"
#include "debug.h"
#include "convert.h"
@@ -6727,9 +6728,77 @@ handle_no_stack_protector_attribute (tree *node, tree name, tree, int,
struct attribute_spec.handler. */
static tree
-handle_strub_attribute (tree *, tree, tree, int, bool *no_add_attrs)
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
- *no_add_attrs = true;
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
return NULL_TREE;
}
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index 229d8b32c1ee0..caa157d0a4e24 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "attribs.h"
#include "fold-const.h"
+#include "ipa-strub.h"
#include "stor-layout.h"
#include "langhooks.h"
#include "plugin.h"
@@ -785,8 +786,8 @@ decl_attributes (tree *node, tree attributes, int flags,
flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
- if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
+ if (spec->function_type_required
+ && !FUNC_OR_METHOD_TYPE_P (*anode))
{
if (TREE_CODE (*anode) == POINTER_TYPE
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
@@ -898,7 +899,24 @@ decl_attributes (tree *node, tree attributes, int flags,
TYPE_NAME (tt) = *node;
}
- *anode = cur_and_last_decl[0];
+ if (*anode != cur_and_last_decl[0])
+ {
+ /* Even if !spec->function_type_required, allow the attribute
+ handler to request the attribute to be applied to the function
+ type, rather than to the function pointer type, by setting
+ cur_and_last_decl[0] to the function type. */
+ if (!fn_ptr_tmp
+ && POINTER_TYPE_P (*anode)
+ && TREE_TYPE (*anode) == cur_and_last_decl[0]
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+ {
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ }
+ *anode = cur_and_last_decl[0];
+ }
+
if (ret == error_mark_node)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1501,9 +1519,20 @@ comp_type_attributes (const_tree type1, const_tree type2)
if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
return 0;
+ int strub_ret = strub_comptypes (CONST_CAST_TREE (type1),
+ CONST_CAST_TREE (type2));
+ if (strub_ret == 0)
+ return strub_ret;
/* As some type combinations - like default calling-convention - might
be compatible, we have to call the target hook to get the final result. */
- return targetm.comp_type_attributes (type1, type2);
+ int target_ret = targetm.comp_type_attributes (type1, type2);
+ if (target_ret == 0)
+ return target_ret;
+ if (strub_ret == 2 || target_ret == 2)
+ return 2;
+ if (strub_ret == 1 && target_ret == 1)
+ return 1;
+ gcc_unreachable ();
}
/* PREDICATE acts as a function of type:
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index cb90bd03b3ea3..b89c7a9376a95 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "intl.h"
#include "file-prefix-map.h" /* remap_macro_filename() */
+#include "ipa-strub.h" /* strub_watermark_parm() */
#include "gomp-constants.h"
#include "omp-general.h"
#include "tree-dfa.h"
@@ -151,6 +152,7 @@ static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
static rtx expand_builtin_alloca (tree);
static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
+static rtx expand_builtin_stack_address ();
static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx);
static rtx expand_builtin_expect_with_probability (tree, rtx);
@@ -5258,6 +5260,252 @@ expand_builtin_frame_address (tree fndecl, tree exp)
}
}
+#ifndef STACK_GROWS_DOWNWARD
+# define STACK_TOPS GT
+#else
+# define STACK_TOPS LT
+#endif
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+# define STACK_UNSIGNED POINTERS_EXTEND_UNSIGNED
+#else
+# define STACK_UNSIGNED true
+#endif
+
+/* Expand a call to builtin function __builtin_stack_address. */
+
+static rtx
+expand_builtin_stack_address ()
+{
+ return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
+ STACK_UNSIGNED);
+}
+
+/* Expand a call to builtin function __builtin_strub_enter. */
+
+static rtx
+expand_builtin_strub_enter (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 1 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ emit_move_insn (wmark, stktop);
+
+ return const0_rtx;
+}
+
+/* Expand a call to builtin function __builtin_strub_update. */
+
+static rtx
+expand_builtin_strub_update (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+#ifdef RED_ZONE_SIZE
+ /* Here's how the strub enter, update and leave functions deal with red zones.
+
+ If it weren't for red zones, update, called from within a strub context,
+ would bump the watermark to the top of the stack. Enter and leave, running
+ in the caller, would use the caller's top of stack address both to
+ initialize the watermark passed to the callee, and to start strubbing the
+ stack afterwards.
+
+ Ideally, we'd update the watermark so as to cover the used amount of red
+ zone, and strub starting at the caller's other end of the (presumably
+ unused) red zone. Normally, only leaf functions use the red zone, but at
+ this point we can't tell whether a function is a leaf, nor can we tell how
+ much of the red zone it uses. Furthermore, some strub contexts may have
+ been inlined so that update and leave are called from the same stack frame,
+ and the strub builtins may all have been inlined, turning a strub function
+ into a leaf.
+
+ So cleaning the range from the caller's stack pointer (one end of the red
+ zone) to the (potentially inlined) callee's (other end of the) red zone
+ could scribble over the caller's own red zone.
+
+ We avoid this possibility by arranging for callers that are strub contexts
+ to use their own watermark as the strub starting point. So, if A calls B,
+ and B calls C, B will tell A to strub up to the end of B's red zone, and
+ will strub itself only the part of C's stack frame and red zone that
+ doesn't overlap with B's. With that, we don't need to know who's leaf and
+ who isn't: inlined calls will shrink their strub window to zero, each
+ remaining call will strub some portion of the stack, and eventually the
+ strub context will return to a caller that isn't a strub context itself,
+ that will therefore use its own stack pointer as the strub starting point.
+ It's not a leaf, because strub contexts can't be inlined into non-strub
+ contexts, so it doesn't use the red zone, and it will therefore correctly
+ strub up the callee's stack frame up to the end of the callee's red zone.
+ Neat! */
+ if (true /* (flags_from_decl_or_type (current_function_decl) & ECF_LEAF) */)
+ {
+ poly_int64 red_zone_size = RED_ZONE_SIZE;
+#if STACK_GROWS_DOWNWARD
+ red_zone_size = -red_zone_size;
+#endif
+ stktop = plus_constant (ptr_mode, stktop, red_zone_size);
+ stktop = force_reg (ptr_mode, stktop);
+ }
+#endif
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+ rtx_code_label *lab = gen_label_rtx ();
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+
+ /* If this is an inlined strub function, also bump the watermark for the
+ enclosing function. This avoids a problem with the following scenario: A
+ calls B and B calls C, and both B and C get inlined into A. B allocates
+ temporary stack space before calling C. If we don't update A's watermark,
+ we may use an outdated baseline for the post-C strub_leave, erasing B's
+ temporary stack allocation. We only need this if we're fully expanding
+ strub_leave inline. */
+ tree xwmptr = (optimize > 2
+ ? strub_watermark_parm (current_function_decl)
+ : wmptr);
+ if (wmptr != xwmptr)
+ {
+ wmptr = xwmptr;
+ wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ wmarkr = force_reg (ptr_mode, wmark);
+
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+ }
+
+ emit_label (lab);
+
+ return const0_rtx;
+}
+
+
+/* Expand a call to builtin function __builtin_strub_leave. */
+
+static rtx
+expand_builtin_strub_leave (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || optimize_size || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = NULL_RTX;
+
+ if (tree wmptr = (optimize
+ ? strub_watermark_parm (current_function_decl)
+ : NULL_TREE))
+ {
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ stktop = force_reg (ptr_mode, wmark);
+ }
+
+ if (!stktop)
+ stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+#ifndef STACK_GROWS_DOWNWARD
+ rtx base = stktop;
+ rtx end = wmarkr;
+#else
+ rtx base = wmarkr;
+ rtx end = stktop;
+#endif
+
+ /* We're going to modify it, so make sure it's not e.g. the stack pointer. */
+ base = copy_to_reg (base);
+
+ rtx_code_label *done = gen_label_rtx ();
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, done, NULL,
+ profile_probability::very_likely ());
+
+ if (optimize < 3)
+ expand_call (exp, NULL_RTX, true);
+ else
+ {
+ /* Ok, now we've determined we want to copy the block, so convert the
+ addresses to Pmode, as needed to dereference them to access ptr_mode
+ memory locations, so that we don't have to convert anything within the
+ loop. */
+ base = memory_address (ptr_mode, base);
+ end = memory_address (ptr_mode, end);
+
+ rtx zero = force_operand (const0_rtx, NULL_RTX);
+ int ulen = GET_MODE_SIZE (ptr_mode);
+
+ /* ??? It would be nice to use setmem or similar patterns here,
+ but they do not necessarily obey the stack growth direction,
+ which has security implications. We also have to avoid calls
+ (memset, bzero or any machine-specific ones), which are
+ likely unsafe here (see TARGET_STRUB_MAY_USE_MEMSET). */
+#ifndef STACK_GROWS_DOWNWARD
+ rtx incr = plus_constant (Pmode, base, ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, base);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (dstm, zero);
+ emit_move_insn (base, force_operand (incr, NULL_RTX));
+#else
+ rtx decr = plus_constant (Pmode, end, -ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, end);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (end, force_operand (decr, NULL_RTX));
+ emit_move_insn (dstm, zero);
+#endif
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ Pmode, NULL_RTX, NULL, loop,
+ profile_probability::very_likely ());
+ }
+
+ emit_label (done);
+
+ return const0_rtx;
+}
+
/* Expand EXP, a call to the alloca builtin. Return NULL_RTX if we
failed and the caller should emit a normal call. */
@@ -7585,6 +7833,27 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
case BUILT_IN_RETURN_ADDRESS:
return expand_builtin_frame_address (fndecl, exp);
+ case BUILT_IN_STACK_ADDRESS:
+ return expand_builtin_stack_address ();
+
+ case BUILT_IN___STRUB_ENTER:
+ target = expand_builtin_strub_enter (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_UPDATE:
+ target = expand_builtin_strub_update (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_LEAVE:
+ target = expand_builtin_strub_leave (exp);
+ if (target)
+ return target;
+ break;
+
/* Returns the address of the area where the structure is returned.
0 otherwise. */
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index eb6f4ec2034cd..068a60e1e6dce 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -995,6 +995,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHRO
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
+DEF_GCC_BUILTIN (BUILT_IN_STACK_ADDRESS, "stack_address", BT_FN_PTR, ATTR_NULL)
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_ENTER, "__builtin___strub_enter")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_UPDATE, "__builtin___strub_update")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_LEAVE, "__builtin___strub_leave")
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
DEF_LIB_BUILTIN (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 232365d46e237..241e50bbd81ce 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "common/common-target.h"
#include "langhooks.h"
#include "tree-inline.h"
+#include "ipa-strub.h"
#include "toplev.h"
#include "tree-iterator.h"
#include "opts.h"
@@ -69,6 +70,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_stack_protector_function_attribute (tree *, tree,
tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -321,6 +323,8 @@ const struct attribute_spec c_common_attribute_table[] =
{ "no_stack_protector", 0, 0, true, false, false, false,
handle_no_stack_protector_function_attribute,
attr_stack_protect_exclusions },
+ { "strub", 0, 1, false, true, false, true,
+ handle_strub_attribute, NULL },
{ "noinline", 0, 0, true, false, false, false,
handle_noinline_attribute,
attr_noinline_exclusions },
@@ -1476,6 +1480,84 @@ handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
return NULL_TREE;
}
+/* Handle a "strub" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
+ return NULL_TREE;
+}
+
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cedaaac3a45b7..177bd9dc5b7ac 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -153,7 +153,7 @@ public:
void remove (void);
/* Undo any definition or use of the symbol. */
- void reset (void);
+ void reset (bool preserve_comdat_group = false);
/* Dump symtab node to F. */
void dump (FILE *f);
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index bccd2f2abb5a3..9a550a5cce645 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -384,7 +384,7 @@ symbol_table::process_new_functions (void)
functions or variables. */
void
-symtab_node::reset (void)
+symtab_node::reset (bool preserve_comdat_group)
{
/* Reset our data structures so we can analyze the function again. */
analyzed = false;
@@ -395,7 +395,8 @@ symtab_node::reset (void)
cpp_implicit_alias = false;
remove_all_references ();
- remove_from_same_comdat_group ();
+ if (!preserve_comdat_group)
+ remove_from_same_comdat_group ();
if (cgraph_node *cn = dyn_cast <cgraph_node *> (this))
{
diff --git a/gcc/common.opt b/gcc/common.opt
index ce34075561f9f..c35b6a3de552a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2875,6 +2875,35 @@ fstrict-overflow
Common
Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer.
+fstrub=disable
+Common RejectNegative Var(flag_strub, 0)
+Disable stack scrub entirely, disregarding strub attributes.
+
+fstrub=strict
+Common RejectNegative Var(flag_strub, -4)
+Enable stack scrub as per attributes, with strict call checking.
+
+; If any strub-enabling attribute is seen when the default or strict
+; initializer values are in effect, flag_strub is bumped up by 2. The
+; scrub mode gate function will then bump these initializer values to
+; 0 if no strub-enabling attribute is seen. This minimizes the strub
+; overhead.
+fstrub=relaxed
+Common RejectNegative Var(flag_strub, -3) Init(-3)
+Restore default strub mode: as per attributes, with relaxed checking.
+
+fstrub=all
+Common RejectNegative Var(flag_strub, 3)
+Enable stack scrubbing for all viable functions.
+
+fstrub=at-calls
+Common RejectNegative Var(flag_strub, 1)
+Enable at-calls stack scrubbing for all viable functions.
+
+fstrub=internal
+Common RejectNegative Var(flag_strub, 2)
+Enable internal stack scrubbing for all viable functions.
+
fsync-libcalls
Common Var(flag_sync_libcalls) Init(1)
Implement __atomic operations via libcalls to legacy __sync functions.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e1295898fc25c..0cdbbc208c059 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -77,6 +77,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Function Names:: Printable strings which are the name of the current
function.
* Return Address:: Getting the return or frame address of a function.
+* Stack Scrubbing:: Stack scrubbing internal interfaces.
* Vector Extensions:: Using vector instructions through built-in functions.
* Offsetof:: Special syntax for implementing @code{offsetof}.
* __sync Builtins:: Legacy built-in functions for atomic memory access.
@@ -9096,6 +9097,263 @@ pid_t wait (wait_status_ptr_t p)
@}
@end smallexample
+@cindex @code{strub} type attribute
+@item strub
+This attribute defines stack-scrubbing properties of functions and
+variables. Being a type attribute, it attaches to types, even when
+specified in function and variable declarations. When applied to
+function types, it takes an optional string argument. When applied to a
+pointer-to-function type, if the optional argument is given, it gets
+propagated to the function type.
+
+@smallexample
+/* A strub variable. */
+int __attribute__ ((strub)) var;
+/* A strub variable that happens to be a pointer. */
+__attribute__ ((strub)) int *strub_ptr_to_int;
+/* A pointer type that may point to a strub variable. */
+typedef int __attribute__ ((strub)) *ptr_to_strub_int_type;
+
+/* A declaration of a strub function. */
+extern int __attribute__ ((strub)) foo (void);
+/* A pointer to that strub function. */
+int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo;
+@end smallexample
+
+A function associated with @code{at-calls} @code{strub} mode
+(@code{strub("at-calls")}, or just @code{strub}) undergoes interface
+changes. Its callers are adjusted to match the changes, and to scrub
+(overwrite with zeros) the stack space used by the called function after
+it returns. The interface change makes the function type incompatible
+with an unadorned but otherwise equivalent type, so @emph{every}
+declaration and every type that may be used to call the function must be
+associated with this strub mode.
+
+A function associated with @code{internal} @code{strub} mode
+(@code{strub("internal")}) retains an unmodified, type-compatible
+interface, but it may be turned into a wrapper that calls the wrapped
+body using a custom interface. The wrapper then scrubs the stack space
+used by the wrapped body. Though the wrapped body has its stack space
+scrubbed, the wrapper does not, so arguments and return values may
+remain unscrubbed even when such a function is called by another
+function that enables @code{strub}. This is why, when compiling with
+@option{-fstrub=strict}, a @code{strub} context is not allowed to call
+@code{internal} @code{strub} functions.
+
+@smallexample
+/* A declaration of an internal-strub function. */
+extern int __attribute__ ((strub ("internal"))) bar (void);
+
+int __attribute__ ((strub))
+baz (void)
+@{
+ /* Ok, foo was declared above as an at-calls strub function. */
+ foo ();
+ /* Not allowed in strict mode, otherwise allowed. */
+ bar ();
+@}
+@end smallexample
+
+An automatically-allocated variable associated with the @code{strub}
+attribute causes the (immediately) enclosing function to have
+@code{strub} enabled.
+
+A statically-allocated variable associated with the @code{strub}
+attribute causes functions that @emph{read} it, through its @code{strub}
+data type, to have @code{strub} enabled. Reading data by dereferencing
+a pointer to a @code{strub} data type has the same effect. Note: The
+attribute does not carry over from a composite type to the types of its
+components, so the intended effect may not be obtained with non-scalar
+types.
+
+When selecting a @code{strub}-enabled mode for a function that is not
+explicitly associated with one, because of @code{strub} variables or
+data pointers, the function must satisfy @code{internal} mode viability
+requirements (see below), even when @code{at-calls} mode is also viable
+and, being more efficient, ends up selected as an optimization.
+
+@smallexample
+/* zapme is implicitly strub-enabled because of strub variables.
+ Optimization may change its strub mode, but not the requirements. */
+static int
+zapme (int i)
+@{
+ /* A local strub variable enables strub. */
+ int __attribute__ ((strub)) lvar;
+ /* Reading strub data through a pointer-to-strub enables strub. */
+ lvar = * (ptr_to_strub_int_type) &i;
+ /* Writing to a global strub variable does not enable strub. */
+ var = lvar;
+ /* Reading from a global strub variable enables strub. */
+ return var;
+@}
+@end smallexample
+
+A @code{strub} context is the body (as opposed to the interface) of a
+function that has @code{strub} enabled, be it explicitly, by
+@code{at-calls} or @code{internal} mode, or implicitly, due to
+@code{strub} variables or command-line options.
+
+A function of a type associated with the @code{disabled} @code{strub}
+mode (@code{strub("disabled")} will not have its own stack space
+scrubbed. Such functions @emph{cannot} be called from within
+@code{strub} contexts.
+
+In order to enable a function to be called from within @code{strub}
+contexts without having its stack space scrubbed, associate it with the
+@code{callable} @code{strub} mode (@code{strub("callable")}).
+
+When a function is not assigned a @code{strub} mode, explicitly or
+implicitly, the mode defaults to @code{callable}, except when compiling
+with @option{-fstrub=strict}, that causes @code{strub} mode to default
+to @code{disabled}.
+
+@example
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+ /* Implicitly disabled with -fstrub=strict, otherwise callable. */
+extern int bah (void);
+
+int __attribute__ ((strub))
+bal (void)
+@{
+ /* Not allowed, bad is not strub-callable. */
+ bad ();
+ /* Ok, bac is strub-callable. */
+ bac ();
+ /* Not allowed with -fstrub=strict, otherwise allowed. */
+ bah ();
+@}
+@end example
+
+Function types marked @code{callable} and @code{disabled} are not
+mutually compatible types, but the underlying interfaces are compatible,
+so it is safe to convert pointers between them, and to use such pointers
+or alternate declarations to call them. Interfaces are also
+interchangeable between them and @code{internal} (but not
+@code{at-calls}!), but adding @code{internal} to a pointer type will not
+cause the pointed-to function to perform stack scrubbing.
+
+@example
+void __attribute__ ((strub))
+bap (void)
+@{
+ /* Assign a callable function to pointer-to-disabled.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac;
+ /* Not allowed: calls disabled type in a strub context. */
+ d_p ();
+
+ /* Assign a disabled function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an internal function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ c_p = bar;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an at-calls function to pointer-to-callable.
+ Flaggged as incompatible. */
+ c_p = bal;
+ /* The call through an interface-incompatible type will not use the
+ modified interface expected by the at-calls function, so it is
+ likely to misbehave at runtime. */
+ c_p ();
+@}
+@end example
+
+@code{Strub} contexts are never inlined into non-@code{strub} contexts.
+When an @code{internal}-strub function is split up, the wrapper can
+often be inlined, but the wrapped body @emph{never} is. A function
+marked as @code{always_inline}, even if explicitly assigned
+@code{internal} strub mode, will not undergo wrapping, so its body gets
+inlined as required.
+
+@example
+inline int __attribute__ ((strub ("at-calls")))
+inl_atc (void)
+@{
+ /* This body may get inlined into strub contexts. */
+@}
+
+inline int __attribute__ ((strub ("internal")))
+inl_int (void)
+@{
+ /* This body NEVER gets inlined, though its wrapper may. */
+@}
+
+inline int __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+@{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+@}
+
+void __attribute__ ((strub ("disabled")))
+bat (void)
+@{
+ /* Not allowed, cannot inline into a non-strub context. */
+ inl_int_ali ();
+@}
+@end example
+
+@cindex strub eligibility and viability
+Some @option{-fstrub=*} command line options enable @code{strub} modes
+implicitly where viable. A @code{strub} mode is only viable for a
+function if the function is eligible for that mode, and if other
+conditions, detailed below, are satisfied. If it's not eligible for a
+mode, attempts to explicitly associate it with that mode are rejected
+with an error message. If it is eligible, that mode may be assigned
+explicitly through this attribute, but implicit assignment through
+command-line options may involve additional viability requirements.
+
+A function is ineligible for @code{at-calls} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, if attribute
+@code{noipa} is present, or if it calls @code{__builtin_apply_args}.
+@code{At-calls} @code{strub} mode, if not requested through the function
+type, is only viable for an eligible function if the function is not
+visible to other translation units, if it doesn't have its address
+taken, and if it is never called with a function type overrider.
+
+@smallexample
+/* bar is eligible for at-calls strub mode,
+ but not viable for that mode because it is visible to other units.
+ It is eligible and viable for internal strub mode. */
+void bav () @{@}
+
+/* setp is eligible for at-calls strub mode,
+ but not viable for that mode because its address is taken.
+ It is eligible and viable for internal strub mode. */
+void setp (void) @{ static void (*p)(void); = setp; @}
+@end smallexample
+
+A function is ineligible for @code{internal} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, or if attribute
+@code{noipa} is present. For an @code{always_inline} function, meeting
+these requirements is enough to make it eligible. Any function that has
+attribute @code{noclone}, that uses such extensions as non-local labels,
+computed gotos, alternate variable argument passing interfaces,
+@code{__builtin_next_arg}, or @code{__builtin_return_address}, or that
+takes too many (about 64Ki) arguments is ineligible, unless it is
+@code{always_inline}. For @code{internal} @code{strub} mode, all
+eligible functions are viable.
+
+@smallexample
+/* flop is not eligible, thus not viable, for at-calls strub mode.
+ Likewise for internal strub mode. */
+__attribute__ ((noipa)) void flop (void) @{@}
+
+/* flip is eligible and viable for at-calls strub mode.
+ It would be ineligible for internal strub mode, because of noclone,
+ if it weren't for always_inline. With always_inline, noclone is not
+ an obstacle, so it is also eligible and viable for internal strub mode. */
+inline __attribute__ ((noclone, always_inline)) void flip (void) @{@}
+@end smallexample
+
@cindex @code{unused} type attribute
@item unused
When attached to a type (including a @code{union} or a @code{struct}),
@@ -12241,6 +12499,55 @@ option is in effect. Such calls should only be made in debugging
situations.
@enddefbuiltin
+@deftypefn {Built-in Function} {void *} __builtin_stack_address ()
+This function returns the value of the stack pointer register.
+@end deftypefn
+
+@node Stack Scrubbing
+@section Stack scrubbing internal interfaces
+
+Stack scrubbing involves cooperation between a @code{strub} context,
+i.e., a function whose stack frame is to be zeroed-out, and its callers.
+The caller initializes a stack watermark, the @code{strub} context
+updates the watermark according to its stack use, and the caller zeroes
+it out once it regains control, whether by the callee's returning or by
+an exception.
+
+Each of these steps is performed by a different builtin function call.
+Calls to these builtins are introduced automatically, in response to
+@code{strub} attributes and command-line options; they are not expected
+to be explicitly called by source code.
+
+The functions that implement the builtins are available in libgcc but,
+depending on optimization levels, they are expanded internally, adjusted
+to account for inlining, and sometimes combined/deferred (e.g. passing
+the caller-supplied watermark on to callees, refraining from erasing
+stack areas that the caller will) to enable tail calls and to optimize
+for code size.
+
+@deftypefn {Built-in Function} {void} __builtin___strub_enter (void **@var{wmptr})
+This function initializes a stack @var{watermark} variable with the
+current top of the stack. A call to this builtin function is introduced
+before entering a @code{strub} context. It remains as a function call
+if optimization is not enabled.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_update (void **@var{wmptr})
+This function updates a stack @var{watermark} variable with the current
+top of the stack, if it tops the previous watermark. A call to this
+builtin function is inserted within @code{strub} contexts, whenever
+additional stack space may have been used. It remains as a function
+call at optimization levels lower than 2.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_leave (void **@var{wmptr})
+This function overwrites the memory area between the current top of the
+stack, and the @var{watermark}ed address. A call to this builtin
+function is inserted after leaving a @code{strub} context. It remains
+as a function call at optimization levels lower than 3, and it is guarded by
+a condition at level 2.
+@end deftypefn
+
@node Vector Extensions
@section Using Vector Instructions through Built-in Functions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1a762bdcc480f..f18c31fca1f2f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -649,6 +649,8 @@ Objective-C and Objective-C++ Dialects}.
-fstack-protector-explicit -fstack-check
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
-fno-stack-limit -fsplit-stack
+-fstrub=disable -fstrub=strict -fstrub=relaxed
+-fstrub=all -fstrub=at-calls -fstrub=internal
-fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
-fvtv-counts -fvtv-debug
-finstrument-functions -finstrument-functions-once
@@ -17689,6 +17691,56 @@ without @option{-fsplit-stack} always has a large stack. Support for
this is implemented in the gold linker in GNU binutils release 2.21
and later.
+@opindex -fstrub=disable
+@item -fstrub=disable
+Disable stack scrubbing entirely, ignoring any @code{strub} attributes.
+See @xref{Common Type Attributes}.
+
+@opindex fstrub=strict
+@item -fstrub=strict
+Functions default to @code{strub} mode @code{disabled}, and apply
+@option{strict}ly the restriction that only functions associated with
+@code{strub}-@code{callable} modes (@code{at-calls}, @code{callable} and
+@code{always_inline} @code{internal}) are @code{callable} by functions
+with @code{strub}-enabled modes (@code{at-calls} and @code{internal}).
+
+@opindex fstrub=relaxed
+@item -fstrub=relaxed
+Restore the default stack scrub (@code{strub}) setting, namely,
+@code{strub} is only enabled as required by @code{strub} attributes
+associated with function and data types. @code{Relaxed} means that
+strub contexts are only prevented from calling functions explicitly
+associated with @code{strub} mode @code{disabled}. This option is only
+useful to override other @option{-fstrub=*} options that precede it in
+the command line.
+
+@opindex fstrub=at-calls
+@item -fstrub=at-calls
+Enable @code{at-calls} @code{strub} mode where viable. The primary use
+of this option is for testing. It exercises the @code{strub} machinery
+in scenarios strictly local to a translation unit. This @code{strub}
+mode modifies function interfaces, so any function that is visible to
+other translation units, or that has its address taken, will @emph{not}
+be affected by this option. Optimization options may also affect
+viability. See the @code{strub} attribute documentation for details on
+viability and eligibility requirements.
+
+@opindex fstrub=internal
+@item -fstrub=internal
+Enable @code{internal} @code{strub} mode where viable. The primary use
+of this option is for testing. This option is intended to exercise
+thoroughly parts of the @code{strub} machinery that implement the less
+efficient, but interface-preserving @code{strub} mode. Functions that
+would not be affected by this option are quite uncommon.
+
+@opindex fstrub=all
+@item -fstrub=all
+Enable some @code{strub} mode where viable. When both strub modes are
+viable, @code{at-calls} is preferred. @option{-fdump-ipa-strubm} adds
+function attributes that tell which mode was selected for each function.
+The primary use of this option is for testing, to exercise thoroughly
+the @code{strub} machinery.
+
@opindex fvtable-verify
@item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
This option is only available when compiling C++ code.
@@ -19594,6 +19646,14 @@ and inlining decisions.
@item inline
Dump after function inlining.
+@item strubm
+Dump after selecting @code{strub} modes, and recording the selections as
+function attributes.
+
+@item strub
+Dump @code{strub} transformations: interface changes, function wrapping,
+and insertion of builtin calls for stack scrubbing and watermarking.
+
@end table
Additionally, the options @option{-optimized}, @option{-missed},
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index f7ac806ff157c..3c6fc506cc1c1 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3449,6 +3449,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 141027e0bb464..d513de365e93e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2685,6 +2685,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index 34837d9dc9a8f..a7bb44cf2b9ad 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -165,6 +165,9 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|m
[(){},*:<>;=%/|+\!\?\.-] { return yytext[0]; }
/* ignore pp-directives */
+^{HWS}"#"{HWS}[a-z_]+([^\n]*"\\"\n)+[^\n]*\n {
+ update_lineno (yytext, yyleng);
+}
^{HWS}"#"{HWS}[a-z_]+[^\n]*\n {lexer_line.line++;}
. {
diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc
index dc120e6da5af6..dbc3c7e8fdc88 100644
--- a/gcc/ipa-inline.cc
+++ b/gcc/ipa-inline.cc
@@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "ipa-strub.h"
/* Inliner uses greedy algorithm to inline calls in a priority order.
Badness is used as the key in a Fibonacci heap which roughly corresponds
@@ -443,6 +444,11 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
inlinable = false;
}
+ if (inlinable && !strub_inlinable_to_p (callee, caller))
+ {
+ e->inline_failed = CIF_UNSPECIFIED;
+ inlinable = false;
+ }
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc
index 6730f4f9d0e31..1a7285ff5dcf8 100644
--- a/gcc/ipa-split.cc
+++ b/gcc/ipa-split.cc
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-fnsummary.h"
#include "cfgloop.h"
#include "attribs.h"
+#include "ipa-strub.h"
/* Per basic block info. */
@@ -1811,6 +1812,12 @@ execute_split_functions (void)
"section.\n");
return 0;
}
+ if (!strub_splittable_p (node))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not splitting: function is a strub context.\n");
+ return 0;
+ }
/* We enforce splitting after loop headers when profile info is not
available. */
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
new file mode 100644
index 0000000000000..612ece9f18552
--- /dev/null
+++ b/gcc/ipa-strub.cc
@@ -0,0 +1,3454 @@
+/* strub (stack scrubbing) support.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "tree-cfg.h"
+#include "cfghooks.h"
+#include "cfgloop.h"
+#include "cfgcleanup.h"
+#include "tree-eh.h"
+#include "except.h"
+#include "builtins.h"
+#include "attribs.h"
+#include "tree-inline.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "ipa-fnsummary.h"
+#include "gimple-fold.h"
+#include "fold-const.h"
+#include "gimple-walk.h"
+#include "tree-dfa.h"
+#include "langhooks.h"
+#include "calls.h"
+#include "vec.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "alias.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "ipa-strub.h"
+#include "symtab-thunks.h"
+#include "attr-fnspec.h"
+
+/* Const and pure functions that gain a watermark parameter for strub purposes
+ are still regarded as such, which may cause the inline expansions of the
+ __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
+ us to inform the backend about requirements and side effects of the call, but
+ call_fusage building in calls.c:expand_call does not even look at
+ attr_fnspec, so we resort to asm loads and updates to attain an equivalent
+ effect. Once expand_call gains the ability to issue extra memory uses and
+ clobbers based on pure/const function's fnspec, we can define this to 1. */
+#define ATTR_FNSPEC_DECONST_WATERMARK 0
+
+enum strub_mode {
+ /* This mode denotes a regular function, that does not require stack
+ scrubbing (strubbing). It may call any other functions, but if
+ it calls AT_CALLS (or WRAPPED) ones, strubbing logic is
+ automatically introduced around those calls (the latter, by
+ inlining INTERNAL wrappers). */
+ STRUB_DISABLED = 0,
+
+ /* This denotes a function whose signature is (to be) modified to
+ take an extra parameter, for stack use annotation, and its
+ callers must initialize and pass that argument, and perform the
+ strubbing. Functions that are explicitly marked with attribute
+ strub must have the mark visible wherever the function is,
+ including aliases, and overriders and overriding methods.
+ Functions that are implicitly marked for strubbing, for accessing
+ variables explicitly marked as such, will only select this
+ strubbing method if they are internal to a translation unit. It
+ can only be inlined into other strubbing functions, i.e.,
+ STRUB_AT_CALLS or STRUB_WRAPPED. */
+ STRUB_AT_CALLS = 1,
+
+ /* This denotes a function that is to perform strubbing internally,
+ without any changes to its interface (the function is turned into
+ a strubbing wrapper, and its original body is moved to a separate
+ STRUB_WRAPPED function, with a modified interface). Functions
+ may be explicitly marked with attribute strub(2), and the
+ attribute must be visible at the point of definition. Functions
+ that are explicitly marked for strubbing, for accessing variables
+ explicitly marked as such, may select this strubbing mode if
+ their interface cannot change, e.g. because its interface is
+ visible to other translation units, directly, by indirection
+ (having its address taken), inheritance, etc. Functions that use
+ this method must not have the noclone attribute, nor the noipa
+ one. Functions marked as always_inline may select this mode, but
+ they are NOT wrapped, they remain unchanged, and are only inlined
+ into strubbed contexts. Once non-always_inline functions are
+ wrapped, the wrapper becomes STRUB_WRAPPER, and the wrapped becomes
+ STRUB_WRAPPED. */
+ STRUB_INTERNAL = 2,
+
+ /* This denotes a function whose stack is not strubbed, but that is
+ nevertheless explicitly or implicitly marked as callable from strubbing
+ functions. Normally, only STRUB_AT_CALLS (and STRUB_INTERNAL ->
+ STRUB_WRAPPED) functions can be called from strubbing contexts (bodies of
+ STRUB_AT_CALLS, STRUB_INTERNAL and STRUB_WRAPPED functions), but attribute
+ strub(3) enables other functions to be (indirectly) called from these
+ contexts. Some builtins and internal functions may be implicitly marked as
+ STRUB_CALLABLE. */
+ STRUB_CALLABLE = 3,
+
+ /* This denotes the function that took over the body of a
+ STRUB_INTERNAL function. At first, it's only called by its
+ wrapper, but the wrapper may be inlined. The wrapped function,
+ in turn, can only be inlined into other functions whose stack
+ frames are strubbed, i.e., that are STRUB_WRAPPED or
+ STRUB_AT_CALLS. */
+ STRUB_WRAPPED = -1,
+
+ /* This denotes the wrapper function that replaced the STRUB_INTERNAL
+ function. This mode overrides the STRUB_INTERNAL mode at the time the
+ internal to-be-wrapped function becomes a wrapper, so that inlining logic
+ can tell one from the other. */
+ STRUB_WRAPPER = -2,
+
+ /* This denotes an always_inline function that requires strubbing. It can
+ only be called from, and inlined into, other strubbing contexts. */
+ STRUB_INLINABLE = -3,
+
+ /* This denotes a function that accesses strub variables, so it would call for
+ internal strubbing (whether or not it's eligible for that), but since
+ at-calls strubbing is viable, that's selected as an optimization. This
+ mode addresses the inconvenience that such functions may have different
+ modes selected depending on optimization flags, and get a different
+ callable status depending on that choice: if we assigned them
+ STRUB_AT_CALLS mode, they would be callable when optimizing, whereas
+ STRUB_INTERNAL would not be callable. */
+ STRUB_AT_CALLS_OPT = -4,
+
+};
+
+/* Look up a strub attribute in TYPE, and return it. */
+
+static tree
+get_strub_attr_from_type (tree type)
+{
+ return lookup_attribute ("strub", TYPE_ATTRIBUTES (type));
+}
+
+/* Look up a strub attribute in DECL or in its type, and return it. */
+
+static tree
+get_strub_attr_from_decl (tree decl)
+{
+ tree ret = lookup_attribute ("strub", DECL_ATTRIBUTES (decl));
+ if (ret)
+ return ret;
+ return get_strub_attr_from_type (TREE_TYPE (decl));
+}
+
+#define STRUB_ID_COUNT 8
+#define STRUB_IDENT_COUNT 3
+#define STRUB_TYPE_COUNT 5
+
+#define STRUB_ID_BASE 0
+#define STRUB_IDENT_BASE (STRUB_ID_BASE + STRUB_ID_COUNT)
+#define STRUB_TYPE_BASE (STRUB_IDENT_BASE + STRUB_IDENT_COUNT)
+#define STRUB_CACHE_SIZE (STRUB_TYPE_BASE + STRUB_TYPE_COUNT)
+
+/* Keep the strub mode and temp identifiers and types from being GC'd. */
+static GTY((deletable)) tree strub_cache[STRUB_CACHE_SIZE];
+
+/* Define a function to cache identifier ID, to be used as a strub attribute
+ parameter for a strub mode named after NAME. */
+#define DEF_STRUB_IDS(IDX, NAME, ID) \
+static inline tree get_strub_mode_id_ ## NAME () { \
+ int idx = STRUB_ID_BASE + IDX; \
+ tree identifier = strub_cache[idx]; \
+ if (!identifier) \
+ strub_cache[idx] = identifier = get_identifier (ID); \
+ return identifier; \
+}
+/* Same as DEF_STRUB_IDS, but use the string expansion of NAME as ID. */
+#define DEF_STRUB_ID(IDX, NAME) \
+ DEF_STRUB_IDS (IDX, NAME, #NAME)
+
+/* Define functions for each of the strub mode identifiers.
+ Expose dashes rather than underscores. */
+DEF_STRUB_ID (0, disabled)
+DEF_STRUB_IDS (1, at_calls, "at-calls")
+DEF_STRUB_ID (2, internal)
+DEF_STRUB_ID (3, callable)
+DEF_STRUB_ID (4, wrapped)
+DEF_STRUB_ID (5, wrapper)
+DEF_STRUB_ID (6, inlinable)
+DEF_STRUB_IDS (7, at_calls_opt, "at-calls-opt")
+
+/* Release the temporary macro names. */
+#undef DEF_STRUB_IDS
+#undef DEF_STRUB_ID
+
+/* Return the identifier corresponding to strub MODE. */
+
+static tree
+get_strub_mode_attr_parm (enum strub_mode mode)
+{
+ switch (mode)
+ {
+ case STRUB_DISABLED:
+ return get_strub_mode_id_disabled ();
+
+ case STRUB_AT_CALLS:
+ return get_strub_mode_id_at_calls ();
+
+ case STRUB_INTERNAL:
+ return get_strub_mode_id_internal ();
+
+ case STRUB_CALLABLE:
+ return get_strub_mode_id_callable ();
+
+ case STRUB_WRAPPED:
+ return get_strub_mode_id_wrapped ();
+
+ case STRUB_WRAPPER:
+ return get_strub_mode_id_wrapper ();
+
+ case STRUB_INLINABLE:
+ return get_strub_mode_id_inlinable ();
+
+ case STRUB_AT_CALLS_OPT:
+ return get_strub_mode_id_at_calls_opt ();
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the parmeters (TREE_VALUE) for a strub attribute of MODE.
+ We know we use a single parameter, so we bypass the creation of a
+ tree list. */
+
+static tree
+get_strub_mode_attr_value (enum strub_mode mode)
+{
+ return get_strub_mode_attr_parm (mode);
+}
+
+/* Determine whether ID is a well-formed strub mode-specifying attribute
+ parameter for a function (type). Only user-visible modes are accepted, and
+ ID must be non-NULL.
+
+ For unacceptable parms, return 0, otherwise a nonzero value as below.
+
+ If the parm enables strub, return positive, otherwise negative.
+
+ If the affected type must be a distinct, incompatible type,return an integer
+ of absolute value 2, otherwise 1. */
+
+int
+strub_validate_fn_attr_parm (tree id)
+{
+ int ret;
+ const char *s = NULL;
+ size_t len = 0;
+
+ /* do NOT test for NULL. This is only to be called with non-NULL arguments.
+ We assume that the strub parameter applies to a function, because only
+ functions accept an explicit argument. If we accepted NULL, and we
+ happened to be called to verify the argument for a variable, our return
+ values would be wrong. */
+ if (TREE_CODE (id) == STRING_CST)
+ {
+ s = TREE_STRING_POINTER (id);
+ len = TREE_STRING_LENGTH (id) - 1;
+ }
+ else if (TREE_CODE (id) == IDENTIFIER_NODE)
+ {
+ s = IDENTIFIER_POINTER (id);
+ len = IDENTIFIER_LENGTH (id);
+ }
+ else
+ return 0;
+
+ enum strub_mode mode;
+
+ if (len != 8)
+ return 0;
+
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ ret = -1;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ ret = 2;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ ret = 1;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ ret = -2;
+ break;
+
+ default:
+ /* Other parms are for internal use only. */
+ return 0;
+ }
+
+ tree mode_id = get_strub_mode_attr_parm (mode);
+
+ if (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id != mode_id
+ : strncmp (s, IDENTIFIER_POINTER (mode_id), len) != 0)
+ return 0;
+
+ return ret;
+}
+
+/* Return the strub mode from STRUB_ATTR. VAR_P should be TRUE if the attribute
+ is taken from a variable, rather than from a function, or a type thereof. */
+
+static enum strub_mode
+get_strub_mode_from_attr (tree strub_attr, bool var_p = false)
+{
+ enum strub_mode mode = STRUB_DISABLED;
+
+ if (strub_attr)
+ {
+ if (!TREE_VALUE (strub_attr))
+ mode = !var_p ? STRUB_AT_CALLS : STRUB_INTERNAL;
+ else
+ {
+ gcc_checking_assert (!var_p);
+ tree id = TREE_VALUE (strub_attr);
+ if (TREE_CODE (id) == TREE_LIST)
+ id = TREE_VALUE (id);
+ const char *s = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_POINTER (id)
+ : IDENTIFIER_POINTER (id));
+ size_t len = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_LENGTH (id) - 1
+ : IDENTIFIER_LENGTH (id));
+
+ switch (len)
+ {
+ case 7:
+ switch (s[6])
+ {
+ case 'r':
+ mode = STRUB_WRAPPER;
+ break;
+
+ case 'd':
+ mode = STRUB_WRAPPED;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 8:
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 9:
+ mode = STRUB_INLINABLE;
+ break;
+
+ case 12:
+ mode = STRUB_AT_CALLS_OPT;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id == get_strub_mode_attr_parm (mode)
+ : strncmp (IDENTIFIER_POINTER
+ (get_strub_mode_attr_parm (mode)),
+ s, len) == 0);
+ }
+ }
+
+ return mode;
+}
+
+/* Look up, decode and return the strub mode associated with FNDECL. */
+
+static enum strub_mode
+get_strub_mode_from_fndecl (tree fndecl)
+{
+ return get_strub_mode_from_attr (get_strub_attr_from_decl (fndecl));
+}
+
+/* Look up, decode and return the strub mode associated with NODE. */
+
+static enum strub_mode
+get_strub_mode (cgraph_node *node)
+{
+ return get_strub_mode_from_fndecl (node->decl);
+}
+
+/* Look up, decode and return the strub mode associated with TYPE. */
+
+static enum strub_mode
+get_strub_mode_from_type (tree type)
+{
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (type);
+ tree attr = get_strub_attr_from_type (type);
+
+ if (attr)
+ return get_strub_mode_from_attr (attr, var_p);
+
+ if (flag_strub >= -1 && !var_p)
+ return STRUB_CALLABLE;
+
+ return STRUB_DISABLED;
+}
+
+\f
+/* Return TRUE iff NODE calls builtin va_start. */
+
+static bool
+calls_builtin_va_start_p (cgraph_node *node)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (fndecl_built_in_p (cdecl, BUILT_IN_VA_START))
+ return true;
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE calls builtin apply_args, and optionally REPORT it. */
+
+static bool
+calls_builtin_apply_args_p (cgraph_node *node, bool report = false)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!fndecl_built_in_p (cdecl, BUILT_IN_APPLY_ARGS))
+ continue;
+
+ result = true;
+
+ if (!report)
+ break;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "at-calls %<strub%> does not support call to %qD",
+ cdecl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE carries the always_inline attribute. */
+
+static inline bool
+strub_always_inline_p (cgraph_node *node)
+{
+ return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
+}
+
+/* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
+ optionally REPORT the reasons for ineligibility. */
+
+static inline bool
+can_strub_p (cgraph_node *node, bool report = false)
+{
+ bool result = true;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<noipa%>",
+ node->decl);
+ }
+
+ /* We can't, and don't want to vectorize the watermark and other
+ strub-introduced parms. */
+ if (lookup_attribute ("simd", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<simd%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE is eligible for at-calls strub, and optionally REPORT
+ the reasons for ineligibility. Besides general non-eligibility for
+ strub-enabled modes, at-calls rules out calling builtin apply_args. */
+
+static bool
+can_strub_at_calls_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ return !calls_builtin_apply_args_p (node, report);
+}
+
+/* Return TRUE iff the called function (pointer or, if available,
+ decl) undergoes a significant type conversion for the call. Strub
+ mode changes between function types, and other non-useless type
+ conversions, are regarded as significant. When the function type
+ is overridden, the effective strub mode for the call is that of the
+ call fntype, rather than that of the pointer or of the decl.
+ Functions called with type overrides cannot undergo type changes;
+ it's as if their address was taken, so they're considered
+ non-viable for implicit at-calls strub mode. */
+
+static inline bool
+strub_call_fntype_override_p (const gcall *gs)
+{
+ if (gimple_call_internal_p (gs))
+ return false;
+ tree fn_type = TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+ if (tree decl = gimple_call_fndecl (gs))
+ fn_type = TREE_TYPE (decl);
+
+ /* We do NOT want to take the mode from the decl here. This
+ function is used to tell whether we can change the strub mode of
+ a function, and whether the effective mode for the call is to be
+ taken from the decl or from an overrider type. When the strub
+ mode is explicitly declared, or overridden with a type cast, the
+ difference will be noticed in function types. However, if the
+ strub mode is implicit due to e.g. strub variables or -fstrub=*
+ command-line flags, we will adjust call types along with function
+ types. In either case, the presence of type or strub mode
+ overriders in calls will prevent a function from having its strub
+ modes changed in ways that would imply type changes, but taking
+ strub modes from decls would defeat this, since we set strub
+ modes and then call this function to tell whether the original
+ type was overridden to decide whether to adjust the call. We
+ need the answer to be about the type, not the decl. */
+ enum strub_mode mode = get_strub_mode_from_type (fn_type);
+ return (get_strub_mode_from_type (gs->u.fntype) != mode
+ || !useless_type_conversion_p (gs->u.fntype, fn_type));
+}
+
+/* Return TRUE iff NODE is called directly with a type override. */
+
+static bool
+called_directly_with_type_override_p (cgraph_node *node, void *)
+{
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ if (e->call_stmt && strub_call_fntype_override_p (e->call_stmt))
+ return true;
+
+ return false;
+}
+
+/* Return TRUE iff NODE or any other nodes aliased to it are called
+ with type overrides. We can't safely change the type of such
+ functions. */
+
+static bool
+called_with_type_override_p (cgraph_node *node)
+{
+ return (node->call_for_symbol_thunks_and_aliases
+ (called_directly_with_type_override_p, NULL, true, true));
+}
+
+/* Symbolic macro for the max number of arguments that internal strub may add to
+ a function. */
+
+#define STRUB_INTERNAL_MAX_EXTRA_ARGS 3
+
+/* We can't perform internal strubbing if the function body involves certain
+ features:
+
+ - a non-default __builtin_va_start (e.g. x86's __builtin_ms_va_start) is
+ currently unsupported because we can't discover the corresponding va_copy and
+ va_end decls in the wrapper, and we don't convey the alternate variable
+ arguments ABI to the modified wrapped function. The default
+ __builtin_va_start is supported by calling va_start/va_end at the wrapper,
+ that takes variable arguments, passing a pointer to the va_list object to the
+ wrapped function, that runs va_copy from it where the original function ran
+ va_start.
+
+ __builtin_next_arg is currently unsupported because the wrapped function
+ won't be a variable argument function. We could process it in the wrapper,
+ that remains a variable argument function, and replace calls in the wrapped
+ body, but we currently don't.
+
+ __builtin_return_address is rejected because it's generally used when the
+ actual caller matters, and introducing a wrapper breaks such uses as those in
+ the unwinder. */
+
+static bool
+can_strub_internally_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ /* Since we're not changing the function identity proper, just
+ moving its full implementation, we *could* disable
+ fun->cannot_be_copied_reason and/or temporarily drop a noclone
+ attribute, but we'd have to prevent remapping of the labels. */
+ if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%>"
+ " because of attribute %<noclone%>",
+ node->decl);
+ }
+
+ if (node->has_gimple_body_p ())
+ {
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!((fndecl_built_in_p (cdecl, BUILT_IN_VA_START)
+ && cdecl != builtin_decl_explicit (BUILT_IN_VA_START))
+ || fndecl_built_in_p (cdecl, BUILT_IN_NEXT_ARG)
+ || fndecl_built_in_p (cdecl, BUILT_IN_RETURN_ADDRESS)))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it calls %qD",
+ node->decl, cdecl);
+ }
+
+ struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
+ if (fun->has_nonlocal_label)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it contains a non-local goto target",
+ node->decl);
+ }
+
+ if (fun->has_forced_label_in_static)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because the address of a local label escapes",
+ node->decl);
+ }
+
+ /* Catch any other case that would prevent versioning/cloning
+ so as to also have it covered above. */
+ gcc_checking_assert (!result /* || !node->has_gimple_body_p () */
+ || tree_versionable_function_p (node->decl));
+
+
+ /* Label values references are not preserved when copying. If referenced
+ in nested functions, as in 920415-1.c and 920721-4.c their decls get
+ remapped independently. The exclusion below might be too broad, in
+ that we might be able to support correctly cases in which the labels
+ are only used internally in a function, but disconnecting forced labels
+ from their original declarations is undesirable in general. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
+ tree target;
+
+ if (!label_stmt)
+ break;
+
+ target = gimple_label_label (label_stmt);
+
+ if (!FORCED_LABEL (target))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (gimple_location (label_stmt),
+ "internal %<strub%> does not support forced labels");
+ }
+ }
+
+ if (list_length (TYPE_ARG_TYPES (TREE_TYPE (node->decl)))
+ >= (((HOST_WIDE_INT) 1 << IPA_PARAM_MAX_INDEX_BITS)
+ - STRUB_INTERNAL_MAX_EXTRA_ARGS))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD has too many arguments for internal %<strub%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE has any strub-requiring local variable, or accesses (as
+ in reading) any variable through a strub-requiring type. */
+
+static bool
+strub_from_body_p (cgraph_node *node)
+{
+ if (!node->has_gimple_body_p ())
+ return false;
+
+ /* If any local variable is marked for strub... */
+ unsigned i;
+ tree var;
+ FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (node->decl),
+ i, var)
+ if (get_strub_mode_from_type (TREE_TYPE (var))
+ != STRUB_DISABLED)
+ return true;
+
+ /* Now scan the body for loads with strub-requiring types.
+ ??? Compound types don't propagate the strub requirement to
+ component types. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (!gimple_assign_load_p (stmt))
+ continue;
+
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if (get_strub_mode_from_type (TREE_TYPE (rhs))
+ != STRUB_DISABLED)
+ return true;
+ }
+
+ return false;
+}
+
+/* Return TRUE iff node is associated with a builtin that should be callable
+ from strub contexts. */
+
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* This temporarily allocates stack for the call, and we can't reasonably
+ update the watermark for that. Besides, we don't check the actual call
+ target, nor its signature, and it seems to be overkill to as much as
+ try to do so. */
+ case BUILT_IN_APPLY:
+ return false;
+
+ /* Conversely, this shouldn't be called from within strub contexts, since
+ the caller may have had its signature modified. STRUB_INTERNAL is ok,
+ the call will remain in the STRUB_WRAPPER, and removed from the
+ STRUB_WRAPPED clone. */
+ case BUILT_IN_APPLY_ARGS:
+ return false;
+
+ /* ??? Make all other builtins callable. We wish to make any builtin call
+ the compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
+/* Compute the strub mode to be used for NODE. STRUB_ATTR should be the strub
+ attribute,found for NODE, if any. */
+
+static enum strub_mode
+compute_strub_mode (cgraph_node *node, tree strub_attr)
+{
+ enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr);
+
+ gcc_checking_assert (flag_strub >= -2 && flag_strub <= 3);
+
+ /* Symbolic encodings of the -fstrub-* flags. */
+ /* Enable strub when explicitly requested through attributes to functions or
+ variables, reporting errors if the requests cannot be satisfied. */
+ const bool strub_flag_auto = flag_strub < 0;
+ /* strub_flag_auto with strub call verification; without this, functions are
+ implicitly callable. */
+ const bool strub_flag_strict = flag_strub < -1;
+ /* Disable strub altogether, ignore attributes entirely. */
+ const bool strub_flag_disabled = flag_strub == 0;
+ /* On top of _auto, also enable strub implicitly for functions that can
+ safely undergo at-calls strubbing. Internal mode will still be used in
+ functions that request it explicitly with attribute strub(2), or when the
+ function body requires strubbing and at-calls strubbing is not viable. */
+ const bool strub_flag_at_calls = flag_strub == 1;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo internal strubbing. At-calls mode will still be used in
+ functions that requiest it explicitly with attribute strub() or strub(1),
+ or when the function body requires strubbing and internal strubbing is not
+ viable. */
+ const bool strub_flag_internal = flag_strub == 2;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo strubbing in either mode. When both modes are viable,
+ at-calls is preferred. */
+ const bool strub_flag_either = flag_strub == 3;
+ /* Besides the default behavior, enable strub implicitly for all viable
+ functions. */
+ const bool strub_flag_viable = flag_strub > 0;
+
+ /* The consider_* variables should be TRUE if selecting the corresponding
+ strub modes would be consistent with requests from attributes and command
+ line flags. Attributes associated with functions pretty much mandate a
+ selection, and should report an error if not satisfied; strub_flag_auto
+ implicitly enables some viable strub mode if that's required by references
+ to variables marked for strub; strub_flag_viable enables strub if viable
+ (even when favoring one mode, body-requested strub can still be satisfied
+ by either mode), and falls back to callable, silently unless variables
+ require strubbing. */
+
+ const bool consider_at_calls
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_AT_CALLS
+ : true));
+ const bool consider_internal
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_INTERNAL
+ : true));
+
+ const bool consider_callable
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_CALLABLE
+ : (!strub_flag_strict
+ || strub_callable_builtin_p (node))));
+
+ /* This is a shorthand for either strub-enabled mode. */
+ const bool consider_strub
+ = (consider_at_calls || consider_internal);
+
+ /* We can cope with always_inline functions even with noipa and noclone,
+ because we just leave them alone. */
+ const bool is_always_inline
+ = strub_always_inline_p (node);
+
+ /* Strubbing in general, and each specific strub mode, may have its own set of
+ requirements. We require noipa for strubbing, either because of cloning
+ required for internal strub, or because of caller enumeration required for
+ at-calls strub. We don't consider the at-calls mode eligible if it's not
+ even considered, it has no further requirements. Internal mode requires
+ cloning and the absence of certain features in the body and, like at-calls,
+ it's not eligible if it's not even under consideration.
+
+ ??? Do we need target hooks for further constraints? E.g., x86's
+ "interrupt" attribute breaks internal strubbing because the wrapped clone
+ carries the attribute and thus isn't callable; in this case, we could use a
+ target hook to adjust the clone instead. */
+ const bool strub_eligible
+ = (consider_strub
+ && (is_always_inline || can_strub_p (node)));
+ const bool at_calls_eligible
+ = (consider_at_calls && strub_eligible
+ && can_strub_at_calls_p (node));
+ const bool internal_eligible
+ = (consider_internal && strub_eligible
+ && (is_always_inline
+ || can_strub_internally_p (node)));
+
+ /* In addition to the strict eligibility requirements, some additional
+ constraints are placed on implicit selection of certain modes. These do
+ not prevent the selection of a mode if explicitly specified as part of a
+ function interface (the strub attribute), but they may prevent modes from
+ being selected by the command line or by function bodies. The only actual
+ constraint is on at-calls mode: since we change the function's exposed
+ signature, we won't do it implicitly if the function can possibly be used
+ in ways that do not expect the signature change, e.g., if the function is
+ available to or interposable by other units, if its address is taken,
+ etc. */
+ const bool at_calls_viable
+ = (at_calls_eligible
+ && (strub_attr
+ || (node->has_gimple_body_p ()
+ && (!node->externally_visible
+ || (node->binds_to_current_def_p ()
+ && node->can_be_local_p ()))
+ && node->only_called_directly_p ()
+ && !called_with_type_override_p (node))));
+ const bool internal_viable
+ = (internal_eligible);
+
+ /* Shorthand. */
+ const bool strub_viable
+ = (at_calls_viable || internal_viable);
+
+ /* We wish to analyze the body, to look for implicit requests for strub, both
+ to implicitly enable it when the body calls for it, and to report errors if
+ the body calls for it but neither mode is viable (even if that follows from
+ non-eligibility because of the explicit specification of some non-strubbing
+ mode). We can refrain from scanning the body only in rare circumstances:
+ when strub is enabled by a function attribute (scanning might be redundant
+ in telling us to also enable it), and when we are enabling strub implicitly
+ but there are non-viable modes: we want to know whether strubbing is
+ required, to fallback to another mode, even if we're only enabling a
+ certain mode, or, when either mode would do, to report an error if neither
+ happens to be viable. */
+ const bool analyze_body
+ = (strub_attr
+ ? !consider_strub
+ : (strub_flag_auto
+ || (strub_flag_viable && (!at_calls_viable && !internal_viable))
+ || (strub_flag_either && !strub_viable)));
+
+ /* Cases in which strubbing is enabled or disabled by strub_flag_auto.
+ Unsatisfiable requests ought to be reported. */
+ const bool strub_required
+ = ((strub_attr && consider_strub)
+ || (analyze_body && strub_from_body_p (node)));
+
+ /* Besides the required cases, we want to abide by the requests to enabling on
+ an if-viable basis. */
+ const bool strub_enable
+ = (strub_required
+ || (strub_flag_at_calls && at_calls_viable)
+ || (strub_flag_internal && internal_viable)
+ || (strub_flag_either && strub_viable));
+
+ /* And now we're finally ready to select a mode that abides by the viability
+ and eligibility constraints, and that satisfies the strubbing requirements
+ and requests, subject to the constraints. If both modes are viable and
+ strub is to be enabled, pick STRUB_AT_CALLS unless STRUB_INTERNAL was named
+ as preferred. */
+ const enum strub_mode mode
+ = ((strub_enable && is_always_inline)
+ ? (strub_required ? STRUB_INLINABLE : STRUB_CALLABLE)
+ : (strub_enable && internal_viable
+ && (strub_flag_internal || !at_calls_viable))
+ ? STRUB_INTERNAL
+ : (strub_enable && at_calls_viable)
+ ? (strub_required && !strub_attr
+ ? STRUB_AT_CALLS_OPT
+ : STRUB_AT_CALLS)
+ : consider_callable
+ ? STRUB_CALLABLE
+ : STRUB_DISABLED);
+
+ switch (mode)
+ {
+ case STRUB_CALLABLE:
+ if (is_always_inline)
+ break;
+ /* Fall through. */
+
+ case STRUB_DISABLED:
+ if (strub_enable && !strub_attr)
+ {
+ gcc_checking_assert (analyze_body);
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD requires %<strub%>,"
+ " but no viable %<strub%> mode was found",
+ node->decl);
+ break;
+ }
+ /* Fall through. */
+
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ /* Differences from an mode requested through a function attribute are
+ reported in set_strub_mode_to. */
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ /* Functions that select this mode do so because of references to strub
+ variables. Even if we choose at-calls as an optimization, the
+ requirements for internal strub must still be satisfied. Optimization
+ options may render implicit at-calls strub not viable (-O0 sets
+ force_output for static non-inline functions), and it would not be good
+ if changing optimization options turned a well-formed into an
+ ill-formed one. */
+ if (!internal_viable)
+ can_strub_internally_p (node, true);
+ break;
+
+ case STRUB_WRAPPED:
+ case STRUB_WRAPPER:
+ default:
+ gcc_unreachable ();
+ }
+
+ return mode;
+}
+
+/* Set FNDT's strub mode to MODE; FNDT may be a function decl or
+ function type. If OVERRIDE, do not check whether a mode is already
+ set. */
+
+static void
+strub_set_fndt_mode_to (tree fndt, enum strub_mode mode, bool override)
+{
+ gcc_checking_assert (override
+ || !(DECL_P (fndt)
+ ? get_strub_attr_from_decl (fndt)
+ : get_strub_attr_from_type (fndt)));
+
+ tree attr = tree_cons (get_identifier ("strub"),
+ get_strub_mode_attr_value (mode),
+ NULL_TREE);
+ tree *attrp = NULL;
+ if (DECL_P (fndt))
+ {
+ gcc_checking_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndt)));
+ attrp = &DECL_ATTRIBUTES (fndt);
+ }
+ else if (FUNC_OR_METHOD_TYPE_P (fndt))
+ attrp = &TYPE_ATTRIBUTES (fndt);
+ else
+ gcc_unreachable ();
+
+ TREE_CHAIN (attr) = *attrp;
+ *attrp = attr;
+}
+
+/* Set FNDT's strub mode to callable.
+ FNDT may be a function decl or a function type. */
+
+void
+strub_make_callable (tree fndt)
+{
+ strub_set_fndt_mode_to (fndt, STRUB_CALLABLE, false);
+}
+
+/* Set NODE to strub MODE. Report incompatibilities between MODE and the mode
+ requested through explicit attributes, and cases of non-eligibility. */
+
+static void
+set_strub_mode_to (cgraph_node *node, enum strub_mode mode)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+ enum strub_mode req_mode = get_strub_mode_from_attr (attr);
+
+ if (attr)
+ {
+ /* Check for and report incompatible mode changes. */
+ if (mode != req_mode
+ && !(req_mode == STRUB_INTERNAL
+ && (mode == STRUB_WRAPPED
+ || mode == STRUB_WRAPPER))
+ && !((req_mode == STRUB_INTERNAL
+ || req_mode == STRUB_AT_CALLS
+ || req_mode == STRUB_CALLABLE)
+ && mode == STRUB_INLINABLE))
+ {
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<strub%> mode %qE selected for %qD, when %qE was requested",
+ get_strub_mode_attr_parm (mode),
+ node->decl,
+ get_strub_mode_attr_parm (req_mode));
+ if (node->alias)
+ {
+ cgraph_node *target = node->ultimate_alias_target ();
+ if (target != node)
+ error_at (DECL_SOURCE_LOCATION (target->decl),
+ "the incompatible selection was determined"
+ " by ultimate alias target %qD",
+ target->decl);
+ }
+
+ /* Report any incompatibilities with explicitly-requested strub. */
+ switch (req_mode)
+ {
+ case STRUB_AT_CALLS:
+ can_strub_at_calls_p (node, true);
+ break;
+
+ case STRUB_INTERNAL:
+ can_strub_internally_p (node, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Drop any incompatible strub attributes leading the decl attribute
+ chain. Return if we find one with the mode we need. */
+ for (;;)
+ {
+ if (mode == req_mode)
+ return;
+
+ if (DECL_ATTRIBUTES (node->decl) != attr)
+ break;
+
+ DECL_ATTRIBUTES (node->decl) = TREE_CHAIN (attr);
+ attr = get_strub_attr_from_decl (node->decl);
+ if (!attr)
+ break;
+
+ req_mode = get_strub_mode_from_attr (attr);
+ }
+ }
+ else if (mode == req_mode)
+ return;
+
+ strub_set_fndt_mode_to (node->decl, mode, attr);
+}
+
+/* Compute and set NODE's strub mode. */
+
+static void
+set_strub_mode (cgraph_node *node)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+
+ if (attr)
+ switch (get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ cgraph_node *xnode = node;
+ if (node->alias)
+ xnode = node->ultimate_alias_target ();
+ /* Weakrefs may remain unresolved (the above will return node) if
+ their targets are not defined, so make sure we compute a strub
+ mode for them, instead of defaulting to STRUB_DISABLED and
+ rendering them uncallable. */
+ enum strub_mode mode = (xnode != node && !xnode->alias
+ ? get_strub_mode (xnode)
+ : compute_strub_mode (node, attr));
+
+ set_strub_mode_to (node, mode);
+}
+
+\f
+/* Non-strub functions shouldn't be called from within strub contexts,
+ except through callable ones. Always inline strub functions can
+ only be called from strub functions. */
+
+static bool
+strub_callable_from_p (strub_mode caller_mode, strub_mode callee_mode)
+{
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ return callee_mode != STRUB_INLINABLE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return (flag_strub >= -1);
+
+ case STRUB_DISABLED:
+ return false;
+
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return TRUE iff CALLEE can be inlined into CALLER. We wish to avoid inlining
+ WRAPPED functions back into their WRAPPERs. More generally, we wish to avoid
+ inlining strubbed functions into non-strubbed ones. CALLER doesn't have to
+ be an immediate caller of CALLEE: the immediate caller may have already been
+ cloned for inlining, and then CALLER may be further up the original call
+ chain. ??? It would be nice if our own caller would retry inlining callee
+ if caller gets inlined. */
+
+bool
+strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller)
+{
+ strub_mode callee_mode = get_strub_mode (callee);
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ /* When we consider inlining, we've already verified callability, so we
+ can even inline callable and then disabled into a strub context. That
+ will get strubbed along with the context, so it's hopefully not a
+ problem. */
+ return true;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ strub_mode caller_mode = get_strub_mode (caller);
+
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return true;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+/* Check that types T1 and T2 are strub-compatible. Return 1 if the strub modes
+ are the same, 2 if they are interchangeable, and 0 otherwise. */
+
+int
+strub_comptypes (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
+
+ enum strub_mode m1 = get_strub_mode_from_type (t1);
+ enum strub_mode m2 = get_strub_mode_from_type (t2);
+
+ if (m1 == m2)
+ return 1;
+
+ /* We're dealing with types, so only strub modes that can be selected by
+ attributes in the front end matter. If either mode is at-calls (for
+ functions) or internal (for variables), the conversion is not
+ compatible. */
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (t1);
+ enum strub_mode mr = var_p ? STRUB_INTERNAL : STRUB_AT_CALLS;
+ if (m1 == mr || m2 == mr)
+ return 0;
+
+ return 2;
+}
+
+/* Return the effective strub mode used for CALL, and set *TYPEP to
+ the effective type used for the call. The effective type and mode
+ are those of the callee, unless the call involves a typecast. */
+
+static enum strub_mode
+effective_strub_mode_for_call (gcall *call, tree *typep)
+{
+ tree type;
+ enum strub_mode mode;
+
+ if (strub_call_fntype_override_p (call))
+ {
+ type = gimple_call_fntype (call);
+ mode = get_strub_mode_from_type (type);
+ }
+ else
+ {
+ type = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
+ tree decl = gimple_call_fndecl (call);
+ if (decl)
+ mode = get_strub_mode_from_fndecl (decl);
+ else
+ mode = get_strub_mode_from_type (type);
+ }
+
+ if (typep)
+ *typep = type;
+
+ return mode;
+}
+
+/* Create a distinct copy of the type of NODE's function, and change
+ the fntype of all calls to it with the same main type to the new
+ type. */
+
+static void
+distinctify_node_type (cgraph_node *node)
+{
+ tree old_type = TREE_TYPE (node->decl);
+ tree new_type = build_distinct_type_copy (old_type);
+ tree new_ptr_type = NULL_TREE;
+
+ /* Remap any calls to node->decl that use old_type, or a variant
+ thereof, to new_type as well. We don't look for aliases, their
+ declarations will have their types changed independently, and
+ we'll adjust their fntypes then. */
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->call_stmt)
+ continue;
+ tree fnaddr = gimple_call_fn (e->call_stmt);
+ gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
+ && TREE_OPERAND (fnaddr, 0) == node->decl);
+ if (strub_call_fntype_override_p (e->call_stmt))
+ continue;
+ if (!new_ptr_type)
+ new_ptr_type = build_pointer_type (new_type);
+ TREE_TYPE (fnaddr) = new_ptr_type;
+ gimple_call_set_fntype (e->call_stmt, new_type);
+ }
+
+ TREE_TYPE (node->decl) = new_type;
+}
+
+/* Return TRUE iff TYPE and any variants have the same strub mode. */
+
+static bool
+same_strub_mode_in_variants_p (tree type)
+{
+ enum strub_mode mode = get_strub_mode_from_type (type);
+
+ for (tree other = TYPE_MAIN_VARIANT (type);
+ other != NULL_TREE; other = TYPE_NEXT_VARIANT (other))
+ if (type != other && mode != get_strub_mode_from_type (other))
+ return false;
+
+ /* Check that the canonical type, if set, either is in the same
+ variant chain, or has the same strub mode as type. Also check
+ the variants of the canonical type. */
+ if (TYPE_CANONICAL (type)
+ && (TYPE_MAIN_VARIANT (TYPE_CANONICAL (type))
+ != TYPE_MAIN_VARIANT (type)))
+ {
+ if (mode != get_strub_mode_from_type (TYPE_CANONICAL (type)))
+ return false;
+ else
+ return same_strub_mode_in_variants_p (TYPE_CANONICAL (type));
+ }
+
+ return true;
+}
+
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ /* It's expected that check strub-wise pointer type compatibility of variables
+ and of functions is already taken care of by front-ends, on account of the
+ attribute's being marked as affecting type identity and of the creation of
+ distinct types. */
+
+ /* Check that call targets in strub contexts have strub-callable types. */
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, NULL);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-%<strub%> call in %<strub%> context %qD",
+ node->decl);
+ }
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ {
+ if (callee_mode == STRUB_INLINABLE)
+ error_at (gimple_location (e->call_stmt),
+ "calling %<always_inline%> %<strub%> %qD"
+ " in non-%<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else if (fndecl_built_in_p (e->callee->decl, BUILT_IN_APPLY_ARGS)
+ && caller_mode == STRUB_INTERNAL)
+ /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
+ from the STRUB_WRAPPED's strub context. */
+ continue;
+ else if (!strub_call_fntype_override_p (e->call_stmt))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-%<strub%> %qD in %<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else
+ error_at (gimple_location (e->call_stmt),
+ "calling %qD using non-%<strub%> type %qT"
+ " in %<strub%> context %qD",
+ e->callee->decl, callee_fntype, node->decl);
+ }
+ }
+ }
+}
+
+namespace {
+
+/* Define a pass to compute strub modes. */
+const pass_data pass_data_ipa_strub_mode = {
+ SIMPLE_IPA_PASS,
+ "strubm",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ 0, // properties_finish
+};
+
+class pass_ipa_strub_mode : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub_mode (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub_mode, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub_mode (m_ctxt); }
+ virtual bool gate (function *) {
+ /* In relaxed (-3) and strict (-4) settings, that only enable strub at a
+ function or variable attribute's request, the attribute handler changes
+ flag_strub to -1 or -2, respectively, if any strub-enabling occurence of
+ the attribute is found. Therefore, if it remains at -3 or -4, nothing
+ that would enable strub was found, so we can disable it and avoid the
+ overhead. */
+ if (flag_strub < -2)
+ flag_strub = 0;
+ return flag_strub;
+ }
+ virtual unsigned int execute (function *);
+};
+
+/* Define a pass to introduce strub transformations. */
+const pass_data pass_data_ipa_strub = {
+ SIMPLE_IPA_PASS,
+ "strub",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg | PROP_ssa, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ TODO_update_ssa
+ | TODO_cleanup_cfg
+ | TODO_rebuild_cgraph_edges
+ | TODO_verify_il, // properties_finish
+};
+
+class pass_ipa_strub : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub (m_ctxt); }
+ virtual bool gate (function *) { return flag_strub && !seen_error (); }
+ virtual unsigned int execute (function *);
+
+ /* Define on demand and cache some types we use often. */
+#define DEF_TYPE(IDX, NAME, INIT) \
+ static inline tree get_ ## NAME () { \
+ int idx = STRUB_TYPE_BASE + IDX; \
+ static tree type = strub_cache[idx]; \
+ if (!type) \
+ strub_cache[idx] = type = (INIT); \
+ return type; \
+ }
+
+ /* Use a distinct ptr_type_node to denote the watermark, so that we can
+ recognize it in arg lists and avoid modifying types twice. */
+ DEF_TYPE (0, wmt, build_variant_type_copy (ptr_type_node))
+
+ DEF_TYPE (1, pwmt, build_reference_type (get_wmt ()))
+
+ DEF_TYPE (2, qpwmt,
+ build_qualified_type (get_pwmt (),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+ DEF_TYPE (3, qptr,
+ build_qualified_type (ptr_type_node,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST))
+
+ DEF_TYPE (4, qpvalst,
+ build_qualified_type (build_reference_type
+ (va_list_type_node),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+#undef DEF_TYPE
+
+ /* Define non-strub builtins on demand. */
+#define DEF_NM_BUILTIN(NAME, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ decl = add_builtin_function \
+ ("__builtin_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ NULL, NULL); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_NM_BUILTIN (stack_address,
+ BUILT_IN_STACK_ADDRESS,
+ (ptr_type_node, NULL))
+
+#undef DEF_NM_BUILTIN
+
+ /* Define strub builtins on demand. */
+#define DEF_SS_BUILTIN(NAME, FNSPEC, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ tree attrs = NULL; \
+ if (FNSPEC) \
+ attrs = tree_cons (get_identifier ("fn spec"), \
+ build_tree_list \
+ (NULL_TREE, \
+ build_string (strlen (FNSPEC), \
+ (FNSPEC))), \
+ attrs); \
+ decl = add_builtin_function_ext_scope \
+ ("__builtin___strub_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ "__strub_" #NAME, attrs); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_SS_BUILTIN (enter, ". Ot",
+ BUILT_IN___STRUB_ENTER,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (update, ". Wt",
+ BUILT_IN___STRUB_UPDATE,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (leave, ". w ",
+ BUILT_IN___STRUB_LEAVE,
+ (void_type_node, get_qpwmt (), NULL))
+
+#undef DEF_SS_BUILTIN
+
+ /* Define strub identifiers on demand. */
+#define DEF_IDENT(IDX, NAME) \
+ static inline tree get_ ## NAME () { \
+ int idx = STRUB_IDENT_BASE + IDX; \
+ tree identifier = strub_cache[idx]; \
+ if (!identifier) \
+ strub_cache[idx] = identifier = get_identifier (".strub." #NAME); \
+ return identifier; \
+ }
+
+ DEF_IDENT (0, watermark_ptr)
+ DEF_IDENT (1, va_list_ptr)
+ DEF_IDENT (2, apply_args)
+
+#undef DEF_IDENT
+
+ static inline int adjust_at_calls_type (tree);
+ static inline void adjust_at_calls_call (cgraph_edge *, int, tree);
+ static inline void adjust_at_calls_calls (cgraph_node *);
+
+ /* Add to SEQ a call to the strub watermark update builtin, taking NODE's
+ location if given. Optionally add the corresponding edge from NODE, with
+ execution frequency COUNT. Return the modified SEQ. */
+
+ static inline gimple_seq
+ call_update_watermark (tree wmptr, cgraph_node *node, profile_count count,
+ gimple_seq seq = NULL)
+ {
+ tree uwm = get_update ();
+ gcall *update = gimple_build_call (uwm, 1, wmptr);
+ if (node)
+ gimple_set_location (update, DECL_SOURCE_LOCATION (node->decl));
+ gimple_seq_add_stmt (&seq, update);
+ if (node)
+ node->create_edge (cgraph_node::get_create (uwm), update, count, false);
+ return seq;
+ }
+
+};
+
+} // anon namespace
+
+/* Gather with this type a collection of parameters that we're turning into
+ explicit references. */
+
+typedef hash_set<tree> indirect_parms_t;
+
+/* Dereference OP's incoming turned-into-reference parm if it's an
+ INDIRECT_PARMS or an ADDR_EXPR thereof. Set *REC and return according to
+ gimple-walking expectations. */
+
+static tree
+maybe_make_indirect (indirect_parms_t &indirect_parms, tree op, int *rec)
+{
+ if (DECL_P (op))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (op))
+ {
+ tree ret = gimple_fold_indirect_ref (op);
+ if (!ret)
+ ret = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (op)),
+ op,
+ build_int_cst (TREE_TYPE (op), 0));
+ return ret;
+ }
+ }
+ else if (TREE_CODE (op) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (op, 0)))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (TREE_OPERAND (op, 0)))
+ {
+ op = TREE_OPERAND (op, 0);
+ return op;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that adds dereferencing to indirect parms. */
+
+static tree
+walk_make_indirect (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ indirect_parms_t &indirect_parms = *(indirect_parms_t *)wi->info;
+
+ if (!*op || TYPE_P (*op))
+ {
+ *rec = 0;
+ return NULL_TREE;
+ }
+
+ if (tree repl = maybe_make_indirect (indirect_parms, *op, rec))
+ {
+ *op = repl;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that turns any non-gimple-val ADDR_EXPRs into a
+ separate SSA. Though addresses of e.g. parameters, and of members thereof,
+ are gimple vals, turning parameters into references, with an extra layer of
+ indirection and thus explicit dereferencing, need to be regimplified. */
+
+static tree
+walk_regimplify_addr_expr (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ gimple_stmt_iterator &gsi = *(gimple_stmt_iterator *)wi->info;
+
+ *rec = 0;
+
+ if (!*op || TREE_CODE (*op) != ADDR_EXPR)
+ return NULL_TREE;
+
+ if (!is_gimple_val (*op))
+ {
+ tree ret = force_gimple_operand_gsi (&gsi, *op, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ gcc_assert (ret != *op);
+ *op = ret;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Turn STMT's PHI arg defs into separate SSA defs if they've become
+ non-gimple_val. Return TRUE if any edge insertions need to be committed. */
+
+static bool
+walk_regimplify_phi (gphi *stmt)
+{
+ bool needs_commit = false;
+
+ for (unsigned i = 0, n = gimple_phi_num_args (stmt); i < n; i++)
+ {
+ tree op = gimple_phi_arg_def (stmt, i);
+ if ((TREE_CODE (op) == ADDR_EXPR
+ && !is_gimple_val (op))
+ /* ??? A PARM_DECL that was addressable in the original function and
+ had its address in PHI nodes, but that became a reference in the
+ wrapped clone would NOT be updated by update_ssa in PHI nodes.
+ Alas, if we were to create a default def for it now, update_ssa
+ would complain that the symbol that needed rewriting already has
+ SSA names associated with it. OTOH, leaving the PARM_DECL alone,
+ it eventually causes errors because it remains unchanged in PHI
+ nodes, but it gets rewritten as expected if it appears in other
+ stmts. So we cheat a little here, and force the PARM_DECL out of
+ the PHI node and into an assignment. It's a little expensive,
+ because we insert it at the edge, which introduces a basic block
+ that's entirely unnecessary, but it works, and the block will be
+ removed as the default def gets propagated back into the PHI node,
+ so the final optimized code looks just as expected. */
+ || (TREE_CODE (op) == PARM_DECL
+ && !TREE_ADDRESSABLE (op)))
+ {
+ tree temp = make_ssa_name (TREE_TYPE (op), stmt);
+ if (TREE_CODE (op) == PARM_DECL)
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (temp, DECL_NAME (op));
+ SET_PHI_ARG_DEF (stmt, i, temp);
+
+ gimple *assign = gimple_build_assign (temp, op);
+ if (gimple_phi_arg_has_location (stmt, i))
+ gimple_set_location (assign, gimple_phi_arg_location (stmt, i));
+ gsi_insert_on_edge (gimple_phi_arg_edge (stmt, i), assign);
+ needs_commit = true;
+ }
+ }
+
+ return needs_commit;
+}
+
+/* Create a reference type to use for PARM when turning it into a reference.
+ NONALIASED causes the reference type to gain its own separate alias set, so
+ that accessing the indirectly-passed parm won'will not add aliasing
+ noise. */
+
+static tree
+build_ref_type_for (tree parm, bool nonaliased = true)
+{
+ gcc_checking_assert (TREE_CODE (parm) == PARM_DECL);
+
+ tree ref_type = build_reference_type (TREE_TYPE (parm));
+
+ if (!nonaliased)
+ return ref_type;
+
+ /* Each PARM turned indirect still points to the distinct memory area at the
+ wrapper, and the reference in unchanging, so we might qualify it, but...
+ const is not really important, since we're only using default defs for the
+ reference parm anyway, and not introducing any defs, and restrict seems to
+ cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that,
+ if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias
+ set seems to not run afoul of this problem, and it hopefully enables the
+ compiler to tell the pointers do point to objects that are not otherwise
+ aliased. */
+ tree qref_type = build_variant_type_copy (ref_type);
+
+ TYPE_ALIAS_SET (qref_type) = new_alias_set ();
+ record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type));
+
+ return qref_type;
+}
+
+/* Add cgraph edges from current_function_decl to callees in SEQ with frequency
+ COUNT, assuming all calls in SEQ are direct. */
+
+static void
+add_call_edges_for_seq (gimple_seq seq, profile_count count)
+{
+ cgraph_node *node = cgraph_node::get_create (current_function_decl);
+
+ for (gimple_stmt_iterator gsi = gsi_start (seq);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ if (!call)
+ continue;
+
+ tree callee = gimple_call_fndecl (call);
+ gcc_checking_assert (callee);
+ node->create_edge (cgraph_node::get_create (callee), call, count, false);
+ }
+}
+
+/* Insert SEQ after the call at GSI, as if the call was in a try block with SEQ
+ as finally, i.e., SEQ will run after the call whether it returns or
+ propagates an exception. This handles block splitting, EH edge and block
+ creation, noreturn and nothrow optimizations, and even throwing calls without
+ preexisting local handlers. */
+
+static void
+gsi_insert_finally_seq_after_call (gimple_stmt_iterator gsi, gimple_seq seq)
+{
+ if (!seq)
+ return;
+
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gimple_has_location (stmt))
+ annotate_all_with_location (seq, gimple_location (stmt));
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ bool noreturn_p = call && gimple_call_noreturn_p (call);
+ int eh_lp = lookup_stmt_eh_lp (stmt);
+ bool must_not_throw_p = eh_lp < 0;
+ bool nothrow_p = (must_not_throw_p
+ || (call && gimple_call_nothrow_p (call))
+ || (eh_lp <= 0
+ && (TREE_NOTHROW (cfun->decl)
+ || !flag_exceptions)));
+
+ if (noreturn_p && nothrow_p)
+ return;
+
+ /* Don't expect an EH edge if we're not to throw, or if we're not in an EH
+ region yet. */
+ bool no_eh_edge_p = (nothrow_p || !eh_lp);
+ bool must_end_bb = stmt_ends_bb_p (stmt);
+
+ edge eft = NULL, eeh = NULL;
+ if (must_end_bb && !(noreturn_p && no_eh_edge_p))
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->succs)
+ {
+ if ((e->flags & EDGE_EH))
+ {
+ gcc_checking_assert (!eeh);
+ eeh = e;
+#if !CHECKING_P
+ if (eft || noreturn_p)
+ break;
+#endif
+ }
+ if ((e->flags & EDGE_FALLTHRU))
+ {
+ gcc_checking_assert (!eft);
+ eft = e;
+#if !CHECKING_P
+ if (eeh || no_eh_edge_p)
+ break;
+#endif
+ }
+ }
+
+ gcc_checking_assert (!(eft && (eft->flags & EDGE_FALLTHRU))
+ == noreturn_p);
+ gcc_checking_assert (!(eeh && (eeh->flags & EDGE_EH))
+ == no_eh_edge_p);
+ gcc_checking_assert (eft != eeh);
+ }
+
+ if (!noreturn_p)
+ {
+ gimple_seq nseq = nothrow_p ? seq : gimple_seq_copy (seq);
+
+ if (must_end_bb)
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+ add_call_edges_for_seq (nseq, eft->count ());
+ gsi_insert_seq_on_edge_immediate (eft, nseq);
+ }
+ else
+ {
+ add_call_edges_for_seq (nseq, gsi_bb (gsi)->count);
+ gsi_insert_seq_after (&gsi, nseq, GSI_SAME_STMT);
+ }
+ }
+
+ if (nothrow_p)
+ return;
+
+ if (eh_lp)
+ {
+ add_call_edges_for_seq (seq, eeh->count ());
+ gsi_insert_seq_on_edge_immediate (eeh, seq);
+ return;
+ }
+
+ /* A throwing call may appear within a basic block in a function that doesn't
+ have any EH regions. We're going to add a cleanup if so, therefore the
+ block will have to be split. */
+ basic_block bb = gsi_bb (gsi);
+ if (!gsi_one_before_end_p (gsi))
+ split_block (bb, stmt);
+
+ /* Create a new block for the EH cleanup. */
+ basic_block bb_eh_cleanup = create_empty_bb (bb);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, bb_eh_cleanup, bb);
+ if (current_loops)
+ add_bb_to_loop (bb_eh_cleanup, current_loops->tree_root);
+
+ /* Make the new block an EH cleanup for the call. */
+ eh_region new_r = gen_eh_region_cleanup (NULL);
+ eh_landing_pad lp = gen_eh_landing_pad (new_r);
+ tree label = gimple_block_label (bb_eh_cleanup);
+ lp->post_landing_pad = label;
+ EH_LANDING_PAD_NR (label) = lp->index;
+ add_stmt_to_eh_lp (stmt, lp->index);
+
+ /* Add the cleanup code to the EH cleanup block. */
+ gsi = gsi_after_labels (bb_eh_cleanup);
+ gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+
+ /* And then propagate the exception further. */
+ gresx *resx = gimple_build_resx (new_r->index);
+ if (gimple_has_location (stmt))
+ gimple_set_location (resx, gimple_location (stmt));
+ gsi_insert_before (&gsi, resx, GSI_SAME_STMT);
+
+ /* Finally, wire the EH cleanup block into the CFG. */
+ edge neeh = make_eh_edges (stmt);
+ neeh->probability = profile_probability::never ();
+ gcc_checking_assert (neeh->dest == bb_eh_cleanup);
+ gcc_checking_assert (!neeh->dest->count.initialized_p ());
+ neeh->dest->count = neeh->count ();
+ add_call_edges_for_seq (seq, neeh->dest->count);
+}
+
+/* Copy the attribute list at *ATTRS, minus any NAME attributes, leaving
+ shareable trailing nodes alone. */
+
+static inline void
+remove_named_attribute_unsharing (const char *name, tree *attrs)
+{
+ while (tree found = lookup_attribute (name, *attrs))
+ {
+ /* Copy nodes up to the next NAME attribute. */
+ while (*attrs != found)
+ {
+ *attrs = tree_cons (TREE_PURPOSE (*attrs),
+ TREE_VALUE (*attrs),
+ TREE_CHAIN (*attrs));
+ attrs = &TREE_CHAIN (*attrs);
+ }
+ /* Then drop it. */
+ gcc_checking_assert (*attrs == found);
+ *attrs = TREE_CHAIN (*attrs);
+ }
+}
+
+/* Record the order of the last cgraph entry whose mode we've already set, so
+ that we can perform mode setting incrementally without duplication. */
+static int last_cgraph_order;
+
+/* Set strub modes for functions introduced since the last call. */
+
+static void
+ipa_strub_set_mode_for_new_functions ()
+{
+ if (symtab->order == last_cgraph_order)
+ return;
+
+ cgraph_node *node;
+
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
+ for (int aliases = 0; aliases <= 1; aliases++)
+ FOR_EACH_FUNCTION (node)
+ {
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ set_strub_mode (node);
+ }
+
+ last_cgraph_order = symtab->order;
+}
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+
+bool
+strub_splittable_p (cgraph_node *node)
+{
+ switch (get_strub_mode (node))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INLINABLE:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return false;
+
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */
+
+tree
+strub_watermark_parm (tree fndecl)
+{
+ switch (get_strub_mode_from_fndecl (fndecl))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ case STRUB_INLINABLE:
+ return NULL_TREE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+ /* The type (variant) compare finds the parameter even in a just-created
+ clone, before we set its name, but the type-based compare doesn't work
+ during builtin expansion within the lto compiler, because we'll have
+ created a separate variant in that run. */
+ if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()
+ || DECL_NAME (parm) == pass_ipa_strub::get_watermark_ptr ())
+ return parm;
+
+ gcc_unreachable ();
+}
+
+/* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it
+ hasn't been added yet. Return the named argument count. */
+
+int
+pass_ipa_strub::adjust_at_calls_type (tree type)
+{
+ int named_args = 0;
+
+ gcc_checking_assert (same_strub_mode_in_variants_p (type));
+
+ if (!TYPE_ARG_TYPES (type))
+ return named_args;
+
+ tree *tlist = &TYPE_ARG_TYPES (type);
+ tree qpwmptrt = get_qpwmt ();
+ while (*tlist && TREE_VALUE (*tlist) != void_type_node)
+ {
+ /* The type has already been adjusted. */
+ if (TREE_VALUE (*tlist) == qpwmptrt)
+ return named_args;
+ named_args++;
+ *tlist = tree_cons (TREE_PURPOSE (*tlist),
+ TREE_VALUE (*tlist),
+ TREE_CHAIN (*tlist));
+ tlist = &TREE_CHAIN (*tlist);
+ }
+
+ /* Add the new argument after all named arguments, so as to not mess with
+ attributes that reference parameters. */
+ *tlist = tree_cons (NULL_TREE, get_qpwmt (), *tlist);
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ if (!type_already_adjusted)
+ {
+ int flags = flags_from_decl_or_type (type);
+ tree fnspec = lookup_attribute ("fn spec", type);
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1;
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied, if needed, before adding
+ parameters. */
+ TYPE_ATTRIBUTES (type)
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (type));
+ }
+ }
+#endif
+
+ return named_args;
+}
+
+/* Adjust a call to an at-calls call target. Create a watermark local variable
+ if needed, initialize it before, pass it to the callee according to the
+ modified at-calls interface, and release the callee's stack space after the
+ call, if not deferred. If the call is const or pure, arrange for the
+ watermark to not be assumed unused or unchanged. */
+
+void
+pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
+ tree callee_fntype)
+{
+ gcc_checking_assert (e->call_stmt);
+ gcall *ocall = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (ocall);
+
+ /* Make sure we haven't modified this call yet. */
+ gcc_checking_assert (!(int (gimple_call_num_args (ocall)) > named_args
+ && (TREE_TYPE (gimple_call_arg (ocall, named_args))
+ == get_pwmt ())));
+
+ /* If we're already within a strub context, pass on the incoming watermark
+ pointer, and omit the enter and leave calls around the modified call, as an
+ optimization, or as a means to satisfy a tail-call requirement. */
+ tree swmp = ((optimize_size || optimize > 2
+ || gimple_call_must_tail_p (ocall)
+ || (optimize == 2 && gimple_call_tail_p (ocall)))
+ ? strub_watermark_parm (e->caller->decl)
+ : NULL_TREE);
+ bool omit_own_watermark = swmp;
+ tree swm = NULL_TREE;
+ if (!omit_own_watermark)
+ {
+ swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ /* Initialize the watermark before the call. */
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1,
+ unshare_expr (swmp));
+ if (gimple_has_location (ocall))
+ gimple_set_location (stptr, gimple_location (ocall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ e->caller->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+ }
+
+
+ /* Replace the call with one that passes the swmp argument first. */
+ gcall *wrcall;
+ { gcall *stmt = ocall;
+ // Mostly copied from gimple_call_copy_skip_args.
+ int i = 0;
+ int nargs = gimple_call_num_args (stmt);
+ auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
+ gcall *new_stmt;
+
+ /* pr71109.c calls a prototypeless function, then defines it with
+ additional arguments. It's ill-formed, but after it's inlined,
+ it somehow works out. */
+ for (; i < named_args && i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+ for (; i < named_args; i++)
+ vargs.quick_push (null_pointer_node);
+
+ vargs.quick_push (unshare_expr (swmp));
+
+ for (; i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+
+ if (gimple_call_internal_p (stmt))
+ gcc_unreachable ();
+ else
+ new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
+ gimple_call_set_fntype (new_stmt, callee_fntype);
+
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+ gimple_move_vops (new_stmt, stmt);
+
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gimple_call_copy_flags (new_stmt, stmt);
+ gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+
+ gimple_set_modified (new_stmt, true);
+
+ wrcall = new_stmt;
+ }
+
+ update_stmt (wrcall);
+ gsi_replace (&gsi, wrcall, true);
+ cgraph_edge::set_call_stmt (e, wrcall, false);
+
+ /* Insert the strub code after the call. */
+ gimple_seq seq = NULL;
+
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ if (!swm)
+ swm = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (swmp)),
+ swmp,
+ build_int_cst (TREE_TYPE (swmp), 0));
+
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ unshare_expr (swm)));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ if (gimple_has_location (wrcall))
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ if (!omit_own_watermark)
+ {
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+}
+
+/* Adjust all at-calls calls in NODE. */
+
+void
+pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
+{
+ /* Adjust unknown-callee indirect calls with STRUB_AT_CALLS types within
+ onode. */
+ if (node->indirect_calls)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+
+ if (node->callees)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+}
+
+/* The strubm (strub mode) pass computes a strub mode for each function in the
+ call graph, and checks, before any inlining, that strub callability
+ requirements in effect are satisfied. */
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ last_cgraph_order = 0;
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
+
+ return 0;
+}
+
+/* Create a strub mode pass. */
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub_mode (gcc::context *ctxt)
+{
+ return new pass_ipa_strub_mode (ctxt);
+}
+
+/* The strub pass proper adjusts types, signatures, and at-calls calls, and
+ splits internal-strub functions. */
+
+unsigned int
+pass_ipa_strub::execute (function *)
+{
+ cgraph_node *onode;
+
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* First, adjust the signature of at-calls functions. We adjust types of
+ at-calls functions first, so that we don't modify types in place unless
+ strub is explicitly requested. */
+ FOR_EACH_FUNCTION (onode)
+ {
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode == STRUB_AT_CALLS
+ || mode == STRUB_AT_CALLS_OPT)
+ {
+ /* Create a type variant if strubbing was not explicitly requested in
+ the function type. */
+ if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
+ distinctify_node_type (onode);
+
+ int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));
+
+ /* An external function explicitly declared with strub won't have a
+ body. Even with implicit at-calls strub, a function may have had its
+ body removed after we selected the mode, and then we have nothing
+ further to do. */
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ tree *pargs = &DECL_ARGUMENTS (onode->decl);
+
+ /* A noninterposable_alias reuses the same parm decl chain, don't add
+ the parm twice. */
+ bool aliased_parms = (onode->alias && *pargs
+ && DECL_CONTEXT (*pargs) != onode->decl);
+
+ if (aliased_parms)
+ continue;
+
+ for (int i = 0; i < named_args; i++)
+ pargs = &DECL_CHAIN (*pargs);
+
+ tree wmptr = build_decl (DECL_SOURCE_LOCATION (onode->decl),
+ PARM_DECL,
+ get_watermark_ptr (),
+ get_qpwmt ());
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_ARG_TYPE (wmptr) = get_qpwmt ();
+ DECL_CONTEXT (wmptr) = onode->decl;
+ TREE_USED (wmptr) = 1;
+ DECL_CHAIN (wmptr) = *pargs;
+ *pargs = wmptr;
+
+ if (onode->alias)
+ continue;
+
+ cgraph_node *nnode = onode;
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca)
+ {
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, cfun)
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+
+ if (!call)
+ continue;
+
+ if (gimple_alloca_call_p (call))
+ {
+ /* Capture stack growth. */
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)
+ ->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ }
+ }
+
+ pop_cfun ();
+ }
+ }
+
+ FOR_EACH_FUNCTION (onode)
+ {
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode != STRUB_INTERNAL)
+ {
+ adjust_at_calls_calls (onode);
+ continue;
+ }
+
+ bool is_stdarg = calls_builtin_va_start_p (onode);;
+ bool apply_args = calls_builtin_apply_args_p (onode);
+
+ vec<ipa_adjusted_param, va_gc> *nparms = NULL;
+ unsigned j = 0;
+ {
+ // The following loop copied from ipa-split.c:split_function.
+ for (tree parm = DECL_ARGUMENTS (onode->decl);
+ parm; parm = DECL_CHAIN (parm), j++)
+ {
+ ipa_adjusted_param adj = {};
+ adj.op = IPA_PARAM_OP_COPY;
+ adj.base_index = j;
+ adj.prev_clone_index = j;
+ vec_safe_push (nparms, adj);
+ }
+
+ if (apply_args)
+ {
+ ipa_adjusted_param aaadj = {};
+ aaadj.op = IPA_PARAM_OP_NEW;
+ aaadj.type = get_qptr ();
+ vec_safe_push (nparms, aaadj);
+ }
+
+ if (is_stdarg)
+ {
+ ipa_adjusted_param vladj = {};
+ vladj.op = IPA_PARAM_OP_NEW;
+ vladj.type = get_qpvalst ();
+ vec_safe_push (nparms, vladj);
+ }
+
+ ipa_adjusted_param wmadj = {};
+ wmadj.op = IPA_PARAM_OP_NEW;
+ wmadj.type = get_qpwmt ();
+ vec_safe_push (nparms, wmadj);
+ }
+ ipa_param_adjustments adj (nparms, -1, false);
+
+ cgraph_node *nnode = onode->create_version_clone_with_body
+ (auto_vec<cgraph_edge *> (0),
+ NULL, &adj, NULL, NULL, "strub", NULL);
+
+ if (!nnode)
+ {
+ error_at (DECL_SOURCE_LOCATION (onode->decl),
+ "failed to split %qD for %<strub%>",
+ onode->decl);
+ continue;
+ }
+
+ onode->split_part = true;
+ if (onode->calls_comdat_local)
+ nnode->add_to_same_comdat_group (onode);
+
+ set_strub_mode_to (onode, STRUB_WRAPPER);
+ set_strub_mode_to (nnode, STRUB_WRAPPED);
+
+ adjust_at_calls_calls (nnode);
+
+ /* Decide which of the wrapped function's parms we want to turn into
+ references to the argument passed to the wrapper. In general, we want to
+ copy small arguments, and avoid copying large ones. Variable-sized array
+ lengths given by other arguments, as in 20020210-1.c, would lead to
+ problems if passed by value, after resetting the original function and
+ dropping the length computation; passing them by reference works.
+ DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
+ anyway, but performed at the caller. */
+ indirect_parms_t indirect_nparms (3, false);
+ unsigned adjust_ftype = 0;
+ unsigned named_args = 0;
+ for (tree parm = DECL_ARGUMENTS (onode->decl),
+ nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
+ parm;
+ named_args++,
+ parm = DECL_CHAIN (parm),
+ nparm = DECL_CHAIN (nparm),
+ nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
+ if (!(0 /* DECL_BY_REFERENCE (narg) */
+ || is_gimple_reg_type (TREE_TYPE (nparm))
+ || VECTOR_TYPE_P (TREE_TYPE (nparm))
+ || TREE_CODE (TREE_TYPE (nparm)) == COMPLEX_TYPE
+ || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ && (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ <= 4 * UNITS_PER_WORD))))
+ {
+ indirect_nparms.add (nparm);
+
+ /* ??? Is there any case in which it is not safe to suggest the parms
+ turned indirect don't alias anything else? They are distinct,
+ unaliased memory in the wrapper, and the wrapped can't possibly
+ take pointers into them because none of the pointers passed to the
+ wrapper can alias other incoming parameters passed by value, even
+ if with transparent reference, and the wrapper doesn't take any
+ extra parms that could point into wrapper's parms. So we can
+ probably drop the TREE_ADDRESSABLE and keep the TRUE. */
+ tree ref_type = build_ref_type_for (nparm,
+ true
+ || !TREE_ADDRESSABLE (parm));
+
+ DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type;
+ relayout_decl (nparm);
+ TREE_ADDRESSABLE (nparm) = 0;
+ DECL_BY_REFERENCE (nparm) = 0;
+ DECL_NOT_GIMPLE_REG_P (nparm) = 0;
+ /* ??? This avoids mismatches in debug info bind stmts in
+ e.g. a-chahan . */
+ DECL_ABSTRACT_ORIGIN (nparm) = NULL;
+
+ if (nparmt)
+ adjust_ftype++;
+ }
+
+ /* Also adjust the wrapped function type, if needed. */
+ if (adjust_ftype)
+ {
+ tree nftype = TREE_TYPE (nnode->decl);
+
+ /* We always add at least one argument at the end of the signature, when
+ cloning the function, so we don't expect to need to duplicate the
+ type here. */
+ gcc_checking_assert (TYPE_ARG_TYPES (nftype)
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+
+ /* Check that fnspec still works for the modified function signature,
+ and drop it otherwise. */
+ bool drop_fnspec = false;
+ tree fnspec = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (nftype));
+ attr_fnspec spec = fnspec ? attr_fnspec (fnspec) : attr_fnspec ("");
+
+ unsigned retcopy;
+ if (!(fnspec && spec.returns_arg (&retcopy)))
+ retcopy = (unsigned) -1;
+
+ unsigned i = 0;
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (nftype);
+ adjust_ftype > 0;
+ i++, nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
+ if (indirect_nparms.contains (nparm))
+ {
+ TREE_VALUE (nparmt) = TREE_TYPE (nparm);
+ adjust_ftype--;
+
+ if (fnspec && !drop_fnspec)
+ {
+ if (i == retcopy)
+ drop_fnspec = true;
+ else if (spec.arg_specified_p (i))
+ {
+ /* Properties that apply to pointers only must not be
+ present, because we don't make pointers further
+ indirect. */
+ gcc_checking_assert
+ (!spec.arg_max_access_size_given_by_arg_p (i, NULL));
+ gcc_checking_assert (!spec.arg_copied_to_arg_p (i, NULL));
+
+ /* Any claim of direct access only is invalidated by
+ adding an indirection level. */
+ if (spec.arg_direct_p (i))
+ drop_fnspec = true;
+
+ /* If there's a claim the argument is not read from, the
+ added indirection invalidates it: if the argument is
+ used at all, then the pointer will necessarily be
+ read. */
+ if (!spec.arg_maybe_read_p (i)
+ && spec.arg_used_p (i))
+ drop_fnspec = true;
+ }
+ }
+ }
+
+ /* ??? Maybe we could adjust it instead. */
+ if (drop_fnspec)
+ remove_named_attribute_unsharing ("fn spec",
+ &TYPE_ATTRIBUTES (nftype));
+
+ TREE_TYPE (nnode->decl) = nftype;
+ }
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (nnode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1 + int (is_stdarg) + int (apply_args);
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ bool no_writes_p = true;
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
+ && curlen >= 2
+ && nspec[1] != 'c' && nspec[1] != 'C'
+ && nspec[1] != 'p' && nspec[1] != 'P')
+ no_writes_p = false;
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+
+ /* These extra args are unlikely to be present in const or pure
+ functions. It's conceivable that a function that takes variable
+ arguments, or that passes its arguments on to another function,
+ could be const or pure, but it would not modify the arguments, and,
+ being pure or const, it couldn't possibly modify or even access
+ memory referenced by them. But it can read from these internal
+ data structures created by the wrapper, and from any
+ argument-passing memory referenced by them, so we denote the
+ possibility of reading from multiple levels of indirection, but
+ only of reading because const/pure. */
+ if (apply_args)
+ {
+ nspec[curlen++] = 'r';
+ nspec[curlen++] = ' ';
+ }
+ if (is_stdarg)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
+ }
+ }
+#endif
+
+ {
+ tree decl = onode->decl;
+ cgraph_node *target = nnode;
+
+ { // copied from create_wrapper
+
+ /* Preserve DECL_RESULT so we get right by reference flag. */
+ tree decl_result = DECL_RESULT (decl);
+
+ /* Remove the function's body but keep arguments to be reused
+ for thunk. */
+ onode->release_body (true);
+ onode->reset (/* unlike create_wrapper: preserve_comdat_group = */true);
+
+ DECL_UNINLINABLE (decl) = false;
+ DECL_RESULT (decl) = decl_result;
+ DECL_INITIAL (decl) = NULL;
+ allocate_struct_function (decl, false);
+ set_cfun (NULL);
+
+ /* Turn alias into thunk and expand it into GIMPLE representation. */
+ onode->definition = true;
+
+ thunk_info::get_create (onode);
+ onode->thunk = true;
+ onode->create_edge (target, NULL, onode->count);
+ onode->callees->can_throw_external = !TREE_NOTHROW (target->decl);
+
+ tree arguments = DECL_ARGUMENTS (decl);
+
+ while (arguments)
+ {
+ TREE_ADDRESSABLE (arguments) = false;
+ arguments = TREE_CHAIN (arguments);
+ }
+
+ {
+ tree alias = onode->callees->callee->decl;
+ tree thunk_fndecl = decl;
+ tree a;
+
+ int nxargs = 1 + is_stdarg + apply_args;
+
+ { // Simplified from expand_thunk.
+ tree restype;
+ basic_block bb, then_bb, else_bb, return_bb;
+ gimple_stmt_iterator bsi;
+ int nargs = 0;
+ tree arg;
+ int i;
+ tree resdecl;
+ tree restmp = NULL;
+
+ gcall *call;
+ greturn *ret;
+ bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
+
+ a = DECL_ARGUMENTS (thunk_fndecl);
+
+ current_function_decl = thunk_fndecl;
+
+ /* Ensure thunks are emitted in their correct sections. */
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
+
+ bitmap_obstack_initialize (NULL);
+
+ /* Build the return declaration for the function. */
+ restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
+ if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
+ {
+ resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = thunk_fndecl;
+ DECL_RESULT (thunk_fndecl) = resdecl;
+ }
+ else
+ resdecl = DECL_RESULT (thunk_fndecl);
+
+ profile_count cfg_count = onode->count;
+ if (!cfg_count.initialized_p ())
+ cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
+
+ bb = then_bb = else_bb = return_bb
+ = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
+
+ bsi = gsi_start_bb (bb);
+
+ /* Build call to the function being thunked. */
+ if (!VOID_TYPE_P (restype)
+ && (!alias_is_noreturn
+ || TREE_ADDRESSABLE (restype)
+ || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
+ {
+ if (DECL_BY_REFERENCE (resdecl))
+ {
+ restmp = gimple_fold_indirect_ref (resdecl);
+ if (!restmp)
+ restmp = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (resdecl)),
+ resdecl,
+ build_int_cst (TREE_TYPE (resdecl), 0));
+ }
+ else if (!is_gimple_reg_type (restype))
+ {
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+ {
+ restmp = resdecl;
+
+ if (VAR_P (restmp))
+ {
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl))
+ = restmp;
+ }
+ }
+ else
+ restmp = create_tmp_var (restype, "retval");
+ }
+ else
+ restmp = create_tmp_reg (restype, "retval");
+ }
+
+ for (arg = a; arg; arg = DECL_CHAIN (arg))
+ nargs++;
+ auto_vec<tree> vargs (nargs + nxargs);
+ i = 0;
+ arg = a;
+
+ if (nargs)
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl);
+ i < nargs;
+ i++, arg = DECL_CHAIN (arg), nparm = DECL_CHAIN (nparm))
+ {
+ tree save_arg = arg;
+ tree tmp = arg;
+
+ /* Arrange to pass indirectly the parms, if we decided to do
+ so, and revert its type in the wrapper. */
+ if (indirect_nparms.contains (nparm))
+ {
+ tree ref_type = TREE_TYPE (nparm);
+ TREE_ADDRESSABLE (arg) = true;
+ tree addr = build1 (ADDR_EXPR, ref_type, arg);
+ tmp = arg = addr;
+ }
+ else
+ DECL_NOT_GIMPLE_REG_P (arg) = 0;
+
+ /* Convert the argument back to the type used by the calling
+ conventions, e.g. a non-prototyped float type is passed as
+ double, as in 930603-1.c, and needs to be converted back to
+ double to be passed on unchanged to the wrapped
+ function. */
+ if (TREE_TYPE (nparm) != DECL_ARG_TYPE (nparm))
+ arg = fold_convert (DECL_ARG_TYPE (nparm), arg);
+
+ if (!is_gimple_val (arg))
+ {
+ tmp = create_tmp_reg (TYPE_MAIN_VARIANT
+ (TREE_TYPE (arg)), "arg");
+ gimple *stmt = gimple_build_assign (tmp, arg);
+ gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
+ }
+ vargs.quick_push (tmp);
+ arg = save_arg;
+ }
+ /* These strub arguments are adjusted later. */
+ if (apply_args)
+ vargs.quick_push (null_pointer_node);
+ if (is_stdarg)
+ vargs.quick_push (null_pointer_node);
+ vargs.quick_push (null_pointer_node);
+ call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias),
+ vargs);
+ onode->callees->call_stmt = call;
+ // gimple_call_set_from_thunk (call, true);
+ if (DECL_STATIC_CHAIN (alias))
+ {
+ tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
+ tree type = TREE_TYPE (p);
+ tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ PARM_DECL, create_tmp_var_name ("CHAIN"),
+ type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_CONTEXT (decl) = thunk_fndecl;
+ DECL_ARG_TYPE (decl) = type;
+ TREE_READONLY (decl) = 1;
+
+ struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
+ sf->static_chain_decl = decl;
+
+ gimple_call_set_chain (call, decl);
+ }
+
+ /* Return slot optimization is always possible and in fact required to
+ return values with DECL_BY_REFERENCE. */
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+ && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+ || DECL_BY_REFERENCE (resdecl)))
+ gimple_call_set_return_slot_opt (call, true);
+
+ if (restmp)
+ {
+ gimple_call_set_lhs (call, restmp);
+ gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
+ TREE_TYPE (TREE_TYPE (alias))));
+ }
+ gsi_insert_after (&bsi, call, GSI_NEW_STMT);
+ if (!alias_is_noreturn)
+ {
+ /* Build return value. */
+ if (!DECL_BY_REFERENCE (resdecl))
+ ret = gimple_build_return (restmp);
+ else
+ ret = gimple_build_return (resdecl);
+
+ gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
+ }
+ else
+ {
+ remove_edge (single_succ_edge (bb));
+ }
+
+ cfun->gimple_df->in_ssa_p = true;
+ update_max_bb_count ();
+ profile_status_for_fn (cfun)
+ = cfg_count.initialized_p () && cfg_count.ipa_p ()
+ ? PROFILE_READ : PROFILE_GUESSED;
+ /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
+ // TREE_ASM_WRITTEN (thunk_fndecl) = false;
+ delete_unreachable_blocks ();
+ update_ssa (TODO_update_ssa);
+ checking_verify_flow_info ();
+ free_dominance_info (CDI_DOMINATORS);
+
+ /* Since we want to emit the thunk, we explicitly mark its name as
+ referenced. */
+ onode->thunk = false;
+ onode->lowered = true;
+ bitmap_obstack_release (NULL);
+ }
+ current_function_decl = NULL;
+ set_cfun (NULL);
+ }
+
+ thunk_info::remove (onode);
+
+ // some more of create_wrapper at the end of the next block.
+ }
+ }
+
+ {
+ tree aaval = NULL_TREE;
+ tree vaptr = NULL_TREE;
+ tree wmptr = NULL_TREE;
+ for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg))
+ {
+ aaval = vaptr;
+ vaptr = wmptr;
+ wmptr = arg;
+ }
+
+ if (!apply_args)
+ aaval = NULL_TREE;
+ /* The trailing args are [apply_args], [va_list_ptr], and
+ watermark. If we don't have a va_list_ptr, the penultimate
+ argument is apply_args.
+ */
+ else if (!is_stdarg)
+ aaval = vaptr;
+
+ if (!is_stdarg)
+ vaptr = NULL_TREE;
+
+ DECL_NAME (wmptr) = get_watermark_ptr ();
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_IGNORED_P (wmptr) = 1;
+ TREE_USED (wmptr) = 1;
+
+ if (is_stdarg)
+ {
+ DECL_NAME (vaptr) = get_va_list_ptr ();
+ DECL_ARTIFICIAL (vaptr) = 1;
+ DECL_IGNORED_P (vaptr) = 1;
+ TREE_USED (vaptr) = 1;
+ }
+
+ if (apply_args)
+ {
+ DECL_NAME (aaval) = get_apply_args ();
+ DECL_ARTIFICIAL (aaval) = 1;
+ DECL_IGNORED_P (aaval) = 1;
+ TREE_USED (aaval) = 1;
+ }
+
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ bool any_indirect = !indirect_nparms.is_empty ();
+
+ if (any_indirect)
+ {
+ basic_block bb;
+ bool needs_commit = false;
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
+ !gsi_end_p (gsi);
+ gsi_next_nonvirtual_phi (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed && !is_gimple_debug (gsi_stmt (gsi)))
+ if (walk_regimplify_phi (stmt))
+ needs_commit = true;
+ }
+
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed)
+ {
+ if (!is_gimple_debug (stmt))
+ {
+ wi.info = &gsi;
+ walk_gimple_op (stmt, walk_regimplify_addr_expr,
+ &wi);
+ }
+ update_stmt (stmt);
+ }
+ }
+ }
+ if (needs_commit)
+ gsi_commit_edge_inserts ();
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca
+ || is_stdarg || apply_args)
+ for (cgraph_edge *e = nnode->callees, *enext; e; e = enext)
+ {
+ if (!e->call_stmt)
+ continue;
+
+ gcall *call = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (call);
+ tree fndecl = e->callee->decl;
+
+ enext = e->next_callee;
+
+ if (gimple_alloca_call_p (call))
+ {
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ else if (fndecl && is_stdarg
+ && fndecl_built_in_p (fndecl, BUILT_IN_VA_START))
+ {
+ /* Using a non-default stdarg ABI makes the function ineligible
+ for internal strub. */
+ gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START)
+ == fndecl);
+ tree bvacopy = builtin_decl_explicit (BUILT_IN_VA_COPY);
+ gimple_call_set_fndecl (call, bvacopy);
+ tree arg = vaptr;
+ /* The va_copy source must be dereferenced, unless it's an array
+ type, that would have decayed to a pointer. */
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (vaptr))) != ARRAY_TYPE)
+ {
+ arg = gimple_fold_indirect_ref (vaptr);
+ if (!arg)
+ arg = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (vaptr)),
+ vaptr,
+ build_int_cst (TREE_TYPE (vaptr), 0));
+ if (!is_gimple_val (arg))
+ arg = force_gimple_operand_gsi (&gsi, arg, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ }
+ gimple_call_set_arg (call, 1, arg);
+ update_stmt (call);
+ e->redirect_callee (cgraph_node::get_create (bvacopy));
+ }
+ else if (fndecl && apply_args
+ && fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
+ {
+ tree lhs = gimple_call_lhs (call);
+ gimple *assign = (lhs
+ ? gimple_build_assign (lhs, aaval)
+ : gimple_build_nop ());
+ gsi_replace (&gsi, assign, true);
+ cgraph_edge::remove (e);
+ }
+ }
+
+ { // a little more copied from create_wrapper
+
+ /* Inline summary set-up. */
+ nnode->analyze ();
+ // inline_analyze_function (nnode);
+ }
+
+ pop_cfun ();
+ }
+
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (onode->decl));
+ gimple_stmt_iterator gsi
+ = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+
+ gcall *wrcall;
+ while (!(wrcall = dyn_cast <gcall *> (gsi_stmt (gsi))))
+ gsi_next (&gsi);
+
+ tree swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1, unshare_expr (swmp));
+ gimple_set_location (stptr, gimple_location (wrcall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+
+ int nargs = gimple_call_num_args (wrcall);
+
+ gimple_seq seq = NULL;
+
+ if (apply_args)
+ {
+ tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args");
+ tree bappargs = builtin_decl_explicit (BUILT_IN_APPLY_ARGS);
+ gcall *appargs = gimple_build_call (bappargs, 0);
+ gimple_call_set_lhs (appargs, aalst);
+ gimple_set_location (appargs, gimple_location (wrcall));
+ gsi_insert_before (&gsi, appargs, GSI_SAME_STMT);
+ gimple_call_set_arg (wrcall, nargs - 2 - is_stdarg, aalst);
+ onode->create_edge (cgraph_node::get_create (bappargs),
+ appargs, gsi_bb (gsi)->count, false);
+ }
+
+ if (is_stdarg)
+ {
+ tree valst = create_tmp_var (va_list_type_node, ".strub.va_list");
+ TREE_ADDRESSABLE (valst) = true;
+ tree vaptr = build1 (ADDR_EXPR,
+ build_pointer_type (va_list_type_node),
+ valst);
+ gimple_call_set_arg (wrcall, nargs - 2, unshare_expr (vaptr));
+
+ tree bvastart = builtin_decl_explicit (BUILT_IN_VA_START);
+ gcall *vastart = gimple_build_call (bvastart, 2,
+ unshare_expr (vaptr),
+ integer_zero_node);
+ gimple_set_location (vastart, gimple_location (wrcall));
+ gsi_insert_before (&gsi, vastart, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (bvastart),
+ vastart, gsi_bb (gsi)->count, false);
+
+ tree bvaend = builtin_decl_explicit (BUILT_IN_VA_END);
+ gcall *vaend = gimple_build_call (bvaend, 1, unshare_expr (vaptr));
+ gimple_set_location (vaend, gimple_location (wrcall));
+ gimple_seq_add_stmt (&seq, vaend);
+ }
+
+ gimple_call_set_arg (wrcall, nargs - 1, unshare_expr (swmp));
+ // gimple_call_set_tail (wrcall, false);
+ update_stmt (wrcall);
+
+ {
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+
+ /* For nnode, we don't rebuild edges because we wish to retain
+ any redirections copied to it from earlier passes, so we add
+ call graph edges explicitly there, but for onode, we create a
+ fresh function, so we may as well just issue the calls and
+ then rebuild all cgraph edges. */
+ // cgraph_edge::rebuild_edges ();
+ onode->analyze ();
+ // inline_analyze_function (onode);
+
+ pop_cfun ();
+ }
+ }
+
+ return 0;
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub (gcc::context *ctxt)
+{
+ return new pass_ipa_strub (ctxt);
+}
+
+#include "gt-ipa-strub.h"
diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h
new file mode 100644
index 0000000000000..29869fadfa6c9
--- /dev/null
+++ b/gcc/ipa-strub.h
@@ -0,0 +1,45 @@
+/* strub (stack scrubbing) infrastructure.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Return TRUE if CALLEE can be inlined into CALLER, as far as stack scrubbing
+ constraints are concerned. CALLEE doesn't have to be called directly by
+ CALLER, but the returned value says nothing about intervening functions. */
+extern bool strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller);
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+extern bool strub_splittable_p (cgraph_node *node);
+
+/* Locate and return the watermark_ptr parameter for FNDECL. If FNDECL is not a
+ strub context, return NULL. */
+extern tree strub_watermark_parm (tree fndecl);
+
+/* Make a function type or declaration callable. */
+extern void strub_make_callable (tree fndecl);
+
+/* Return zero iff ID is NOT an acceptable parameter for a user-supplied strub
+ attribute for a function. Otherwise, return >0 if it enables strub, <0 if it
+ does not. Return +/-1 if the attribute-modified type is compatible with the
+ type without the attribute, or +/-2 if it is not compatible. */
+extern int strub_validate_fn_attr_parm (tree id);
+
+/* Like comptypes, return 0 if t1 and t2 are not compatible, 1 if they are
+ compatible, and 2 if they are nearly compatible. Same strub mode is
+ compatible, interface-compatible strub modes are nearly compatible. */
+extern int strub_comptypes (tree t1, tree t2);
diff --git a/gcc/passes.def b/gcc/passes.def
index 1e1950bdb39cb..d515e77be0399 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
INSERT_PASSES_AFTER (all_small_ipa_passes)
NEXT_PASS (pass_ipa_free_lang_data);
NEXT_PASS (pass_ipa_function_and_variable_visibility);
+ NEXT_PASS (pass_ipa_strub_mode);
NEXT_PASS (pass_build_ssa_passes);
PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
NEXT_PASS (pass_fixup_cfg);
@@ -115,6 +116,7 @@ along with GCC; see the file COPYING3. If not see
POP_INSERT_PASSES ()
NEXT_PASS (pass_ipa_remove_symbols);
+ NEXT_PASS (pass_ipa_strub);
NEXT_PASS (pass_ipa_oacc);
PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc)
NEXT_PASS (pass_ipa_pta);
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
new file mode 100644
index 0000000000000..c7a79a6ea0d8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O0, none of the strub builtins are expanded inline. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
new file mode 100644
index 0000000000000..96285c975d98e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O1, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
new file mode 100644
index 0000000000000..8edc0d8aa1321
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O2, without -fno-inline, we fully expand enter and update, and add a test
+ around the leave call. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
new file mode 100644
index 0000000000000..c6d900cf3c45b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
new file mode 100644
index 0000000000000..33ee465e51cb6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
new file mode 100644
index 0000000000000..2936f82079e18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
new file mode 100644
index 0000000000000..479746e57d87e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Og, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
new file mode 100644
index 0000000000000..2241d4ea07f27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Os, without -fno-inline, we fully expand enter, and also update. The
+ expanded update might be larger than a call proper, but argument saving and
+ restoring required by the call will most often make it larger. The leave
+ call is left untouched. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
new file mode 100644
index 0000000000000..a322bcc5da606
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
new file mode 100644
index 0000000000000..db60026d0e080
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
+ is set for static non-inline functions when not optimizing, and that keeps
+ only_called_directly_p from returning true, which makes STRUB_AT_CALLS
+ non-viable. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
new file mode 100644
index 0000000000000..2f462adc1efe0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__ ("callable")))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0);
+}
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ void *args = __builtin_apply_args ();
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
new file mode 100644
index 0000000000000..a5d7551f5da5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+extern void __attribute__ ((__strub__))
+apply_function (void *args);
+
+void __attribute__ ((__strub__))
+apply_args (int i, int j, double d) /* { dg-error "selected" } */
+{
+ void *args = __builtin_apply_args (); /* { dg-message "does not support" } */
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
new file mode 100644
index 0000000000000..64422a0d1e880
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0); /* { dg-error "in .strub. context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
new file mode 100644
index 0000000000000..15ffaa031b899
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+
+/* Check that implicit enabling of strub mode selects internal strub when the
+ function uses __builtin_apply_args, that prevents the optimization to
+ at-calls mode. */
+
+int __attribute__ ((__strub__)) var;
+
+static inline void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+void f() {
+ apply_args (1, 2, 3);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
new file mode 100644
index 0000000000000..b70843b4215a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
new file mode 100644
index 0000000000000..97a3988a6b922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
+ force_output is set for static non-inline functions when not optimizing, and
+ that keeps only_called_directly_p from returning true, which makes
+ STRUB_AT_CALLS non-viable. It becomes STRUB_CALLABLE instead. */
+static void
+g() {
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
new file mode 100644
index 0000000000000..3d73431b3dcd3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O1" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O1. */
+
+#include "strub-defer-O2.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
new file mode 100644
index 0000000000000..fddf3c745e7e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O2" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O2. */
+
+#define EXPECT_DEFERRAL !
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
new file mode 100644
index 0000000000000..7ebc65b58dd72
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -0,0 +1,110 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O3" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -O3. */
+
+#ifndef EXPECT_DEFERRAL
+/* Other strub-defer*.c tests override this macro. */
+# define EXPECT_DEFERRAL
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char*)__builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+int
+look_for_string (char *e)
+{
+ char *p = (char*)__builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__strub__ ("at-calls"), __noinline__, __noclone__))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+deferred_at_calls ()
+{
+ char *ret;
+ int i = 1;
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ while (EXPECT_DEFERRAL !look_for_string ((ret = at_calls ())))
+ if (!i--) __builtin_abort ();
+ return ret;
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+deferred_internal ()
+{
+ int i = 1;
+ char *ret;
+ while (EXPECT_DEFERRAL !look_for_string ((ret = at_calls ())))
+ if (!i--) __builtin_abort ();
+ return ret;
+}
+
+int main ()
+{
+ int i = 1;
+ /* These calls should not be subject to spurious fails: whether or not some
+ asynchronous event overwrites the scrubbed stack space, the string won't
+ remain there. Unless the asynchronous event happens to write the string
+ where we look for it, but what are the odds? Anyway, it doesn't hurt to
+ retry, even if just for symmetry. */
+ while (look_for_string (deferred_at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (deferred_internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
new file mode 100644
index 0000000000000..fbaf85fe0fafe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -Os" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -Os. */
+
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
new file mode 100644
index 0000000000000..e9d7b7b9ee0a8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
new file mode 100644
index 0000000000000..8b8e15a51c71c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
new file mode 100644
index 0000000000000..0a4a7539d3489
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("internal")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("internal")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
new file mode 100644
index 0000000000000..147171d96d5a1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("at-calls")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("at-calls")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]* \[(\]struct large_arg la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("at-calls")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]* \[(\]int i, void \\* &\[^&,\]*.strub.watermark_ptr\[, .]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-not "va_copy \\(" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
new file mode 100644
index 0000000000000..4e92682895a43
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that uses of a strub variable implicitly enables internal strub for
+ publicly-visible functions, and causes the same transformations to their
+ signatures as those in strub-parms1.c. */
+
+#include <stdarg.h>
+
+int __attribute__ ((__strub__)) var;
+
+void
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void
+large_byref_arg (struct large_arg la)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ var++;
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
new file mode 100644
index 0000000000000..e2f9d8aebca58
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. Without the error,
+ inlining takes place. */
+
+#include "strub-strict1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
new file mode 100644
index 0000000000000..98474435d2e59
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. */
+
+#include "strub-strict2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
new file mode 100644
index 0000000000000..1de15342595e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 89 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
new file mode 100644
index 0000000000000..f9209c819004b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
new file mode 100644
index 0000000000000..bed1dcfb54a45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
new file mode 100644
index 0000000000000..6bf0071f52b93
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
new file mode 100644
index 0000000000000..4732f515bf70c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
new file mode 100644
index 0000000000000..8d6424c479a3a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
new file mode 100644
index 0000000000000..368522442066e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* h becomes STRUB_INLINABLE, because of the use of the strub variable,
+ and the always_inline flag. It would get inlined before pass_ipa_strub, if
+ it weren't for the error. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+ var++;
+}
+
+/* g becomes STRUB_AT_CALLS_OPT, because of the use of the strub variable, and
+ the viability of at-calls strubbing. Though internally a strub context, its
+ interface is not strub-enabled, so it's not callable from within strub
+ contexts. */
+static inline void
+g() {
+ var--;
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
new file mode 100644
index 0000000000000..b4f2888321821
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* g becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. It's not STRUB_AT_CALLS_OPT
+ because force_output is set for static non-inline functions when not
+ optimizing, and that keeps only_called_directly_p from returning true, which
+ makes STRUB_AT_CALLS[_OPT] non-viable. */
+static void
+g() {
+ var--;
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
new file mode 100644
index 0000000000000..e48e0610e079b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+#include "strub-tail-O2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
new file mode 100644
index 0000000000000..87cda7ab21b16
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued.
+ Tail calls are short-circuited at -O2+. */
+
+int __attribute__ ((__strub__))
+g (int i, int j) {
+ return g (i, j);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 0 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 0 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
new file mode 100644
index 0000000000000..eb6250fd39c90
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+
+int __attribute__ ((strub)) x;
+float __attribute__ ((strub)) f;
+double __attribute__ ((strub)) d;
+
+/* The attribute applies to the type of the declaration, i.e., to the pointer
+ variable p, not to the pointed-to integer. */
+int __attribute__ ((strub)) *
+p = &x; /* { dg-message "incompatible|invalid conversion" } */
+
+typedef int __attribute__ ((strub)) strub_int;
+strub_int *q = &x; /* Now this is compatible. */
+
+int __attribute__ ((strub))
+a[2]; /* { dg-warning "does not apply to elements" } */
+
+int __attribute__ ((vector_size (4 * sizeof (int))))
+ __attribute__ ((strub))
+v; /* { dg-warning "does not apply to elements" } */
+
+struct s {
+ int i, j;
+} __attribute__ ((strub)) w; /* { dg-warning "does not apply to fields" } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
new file mode 100644
index 0000000000000..b5e45ab0525ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that strub and non-strub functions can be called from non-strub
+ contexts, and that strub and callable functions can be called from strub
+ contexts. */
+
+#define OMIT_IMPERMISSIBLE_CALLS 1
+#include "strub-callable2.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
new file mode 100644
index 0000000000000..96aa7fe4b07f7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -0,0 +1,264 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that impermissible (cross-strub-context) calls are reported. */
+
+extern int __attribute__ ((__strub__ ("callable"))) xcallable (void);
+extern int __attribute__ ((__strub__ ("internal"))) xinternal (void);
+extern int __attribute__ ((__strub__ ("at-calls"))) xat_calls (void);
+extern int __attribute__ ((__strub__ ("disabled"))) xdisabled (void);
+
+int __attribute__ ((__strub__ ("callable"))) callable (void);
+int __attribute__ ((__strub__ ("internal"))) internal (void);
+int __attribute__ ((__strub__ ("at-calls"))) at_calls (void);
+int __attribute__ ((__strub__ ("disabled"))) disabled (void);
+
+int __attribute__ ((__strub__)) var;
+int var_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+icallable (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+iinternal (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+idisabled (void);
+static inline int __attribute__ ((__always_inline__))
+ivar_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+i_callable (void) { return 0; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+i_internal (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+i_at_calls (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+i_disabled (void) { return 0; }
+static inline int __attribute__ ((__always_inline__))
+i_var_user (void) { return var; }
+
+#define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## at_calls (); \
+ ret += i ## ISEP ## internal (); \
+ ret += i ## ISEP ## var_user (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \
+ do { \
+ ret += internal (); \
+ ret += disabled (); \
+ ret += var_user (); \
+ \
+ ret += i ## ISEP ## disabled (); \
+ \
+ ret += xinternal (); \
+ ret += xdisabled (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## callable (); \
+ \
+ ret += callable (); \
+ ret += at_calls (); \
+ \
+ ret += xat_calls (); \
+ ret += xcallable (); \
+ } while (0)
+
+/* Not a strub context, so it can call anything.
+ Explicitly declared as callable even from within strub contexts. */
+int __attribute__ ((__strub__ ("callable")))
+callable (void) {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+/* Internal strubbing means the body is a strub context, so it can only call
+ strub functions, and it's not itself callable from strub functions. */
+int __attribute__ ((__strub__ ("internal")))
+internal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("at-calls")))
+at_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+disabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+int
+var_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+icallable (void)
+{
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+iinternal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+idisabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+ivar_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
new file mode 100644
index 0000000000000..2857195706ed6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const function call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __const__))
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
new file mode 100644
index 0000000000000..98a92bc9eac2b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const function call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
new file mode 100644
index 0000000000000..5511a6e1e71d3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __const__))
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
new file mode 100644
index 0000000000000..47ee927964dff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const wrapping call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
new file mode 100644
index 0000000000000..7c27a2a1a6dca
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointed-to data enables strubbing if accessed. */
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
new file mode 100644
index 0000000000000..e66d903780afd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, enabling internal strubbing when
+ its value is used. */
+int __attribute__ ((__strub__)) *ptr;
+
+int *f() {
+ return ptr;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
new file mode 100644
index 0000000000000..5e08e0e58c658
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) var;
+
+void f() {
+ var = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
new file mode 100644
index 0000000000000..a818e7a38bb5f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) *ptr;
+
+void f() {
+ ptr = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
new file mode 100644
index 0000000000000..ddb0b5c0543b0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* It would be desirable to issue at least warnings for these. */
+
+typedef int __attribute__ ((__strub__)) strub_int;
+strub_int *ptr;
+
+int *f () {
+ return ptr; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+strub_int *g () {
+ return f (); /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
new file mode 100644
index 0000000000000..c165f312f16de
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype ();
+fntype (*ptr);
+
+void f() {
+ ptr ();
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(&\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
new file mode 100644
index 0000000000000..69fcff8d3763d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
new file mode 100644
index 0000000000000..ff006224909bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0, 1, 1);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+, 1, 1)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
new file mode 100644
index 0000000000000..614b02228ba29
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+inline void __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+}
+
+void
+bat (void)
+{
+ /* Not allowed, not a strub context. */
+ inl_int_ali (); /* { dg-error "context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
new file mode 100644
index 0000000000000..f9a6b4a16faf8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all" } */
+
+#include "strub-inlinable1.c"
+
+/* With -fstrub=all, the caller becomes a strub context, so the strub-inlinable
+ callee is not rejected. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
new file mode 100644
index 0000000000000..b4a7f3992bbaa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+typedef void ft (void);
+typedef void ft2 (int, int);
+extern ft __attribute__ ((__strub__)) fnac;
+
+ft * f (void) {
+ return fnac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
new file mode 100644
index 0000000000000..d9d2c0caec42d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+
+/* C++ does not warn about the partial incompatibilities.
+
+ The d_p () calls are actually rejected, even in C++, but they are XFAILed
+ here because we don't get far enough in the compilation as to observe them,
+ because the incompatibilities are errors without -fpermissive.
+ strub-ptrfn3.c uses -fpermissive to check those.
+ */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
new file mode 100644
index 0000000000000..e1f179e160e5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
+/* { dg-prune-output "command-line option .-fpermissive." } */
+
+/* See strub-ptrfn2.c. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
new file mode 100644
index 0000000000000..70b558afad040
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+/* This is strub-ptrfn2.c without -Wpedantic.
+
+ Even C doesn't report the (not-quite-)compatible conversions without it. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
new file mode 100644
index 0000000000000..a262a086837b2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure function call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
new file mode 100644
index 0000000000000..4c4bd50c209a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure function call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
new file mode 100644
index 0000000000000..ce195c6b1f1b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
new file mode 100644
index 0000000000000..75cd54ccb5b5d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
new file mode 100644
index 0000000000000..7458b3fb54da5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Avoid the use of red zones by avoiding
+ leaf functions. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char *) __builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
new file mode 100644
index 0000000000000..5d60a7775f4bb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -0,0 +1,84 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Allow red zones to be used. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ asm ("" : "+rm" (len));
+ char s[2 * PAD + 1][len];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
new file mode 100644
index 0000000000000..c2ad710858e87
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ char *s = (char *) __builtin_alloca (len);
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
new file mode 100644
index 0000000000000..3b36b8e5d68ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -0,0 +1,106 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that multi-level, multi-inlined functions still get cleaned up as
+ expected, without overwriting temporary stack allocations while they should
+ still be available. */
+
+#ifndef ATTR_STRUB_AT_CALLS
+# define ATTR_STRUB_AT_CALLS /* Defined in strub-run4d.c. */
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__))
+char *
+leak_string (void)
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+innermost ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = leak_string ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+intermediate ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = innermost ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return intermediate ();
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
new file mode 100644
index 0000000000000..57f9baf758ded
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=at-calls" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
new file mode 100644
index 0000000000000..08de3f1c3b17c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+#define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
new file mode 100644
index 0000000000000..459f6886c5499
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=internal" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
new file mode 100644
index 0000000000000..0d367fb83d09d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -0,0 +1,19 @@
+// { dg-do run }
+// { dg-options "-fstrub=internal" }
+
+// Check that we don't get extra copies.
+
+struct T {
+ T &self;
+ void check () const { if (&self != this) __builtin_abort (); }
+ T() : self (*this) { check (); }
+ T(const T& ck) : self (*this) { ck.check (); check (); }
+ ~T() { check (); }
+};
+
+T foo (T q) { q.check (); return T(); }
+T bar (T p) { p.check (); return foo (p); }
+
+int main () {
+ bar (T()).check ();
+}
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
new file mode 100644
index 0000000000000..c226ab10ff651
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ static int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
new file mode 100644
index 0000000000000..a7911f1fa7212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+static int x = initializer ();
+
+int f() {
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
new file mode 100644
index 0000000000000..6ebebcd01e8ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
new file mode 100644
index 0000000000000..29e6996ecf61c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+
+-- The main subprogram doesn't read from the automatic variable, but
+-- being an automatic variable, its presence should be enough for the
+-- procedure to get strub enabled.
+
+procedure Strub_Access is
+ type Strub_Int is new Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ X : aliased Strub_Int := 0;
+
+ function F (P : access Strub_Int) return Strub_Int is (P.all);
+
+begin
+ X := F (X'Access);
+end Strub_Access;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls-opt\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
new file mode 100644
index 0000000000000..dae4706016436
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed" }
+
+-- Check that we reject 'Access of a strub variable whose type does
+-- not carry a strub modifier.
+
+procedure Strub_Access1 is
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function F (P : access Integer) return Integer is (P.all);
+
+begin
+ X := F (X'Unchecked_access); -- OK.
+ X := F (X'Access); -- { dg-error "target access type drops .strub. mode" }
+end Strub_Access1;
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
new file mode 100644
index 0000000000000..10445d7cf8451
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -0,0 +1,37 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+
+package body Strub_Attr is
+ E : exception;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (F (X));
+ -- function G return Integer is (FP (X));
+ -- Calling G would likely raise an exception, because although FP
+ -- carries the strub at-calls attribute needed to call F, the
+ -- attribute is dropped from the type used for the call proper.
+end Strub_Attr;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 2 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 0 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark_ptr" 6 "strub" } }
+-- We have 1 at-calls subprogram (F) and 2 wrapped (P and G).
+-- For each of them, there's one match for the wrapped signature,
+-- and one for the update call.
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark" 27 "strub" } }
+-- The 6 matches above, plus:
+-- 5*2: wm var decl, enter, call, leave and clobber for each wrapper;
+-- 2*1: an extra leave and clobber for the exception paths in the wrappers.
+-- 7*1: for the F call in G, including EH path.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.ads b/gcc/testsuite/gnat.dg/strub_attr.ads
new file mode 100644
index 0000000000000..a94c23bf41833
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.ads
@@ -0,0 +1,12 @@
+package Strub_Attr is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function G return Integer;
+end Strub_Attr;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
new file mode 100644
index 0000000000000..3dbcc4a357cba
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -0,0 +1,64 @@
+-- { dg-do compile }
+
+procedure Strub_Disp is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X));
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Disp;
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
new file mode 100644
index 0000000000000..09756a74b7d81
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -0,0 +1,79 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls are transformed.
+
+procedure Strub_Disp1 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X)); -- strub-at-calls non-dispatching call
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X); -- strub-at-calls dispatching call.
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access); -- strub-at-calls non-dispatching call
+ I := I + F (XB'Access); -- strub-at-calls non-dispatching call
+
+ XC := XA'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+
+ XC := XB'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+end Strub_Disp1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 3 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
new file mode 100644
index 0000000000000..da56acaa957d2
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -0,0 +1,33 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but applying attributes to access types as well.
+-- That doesn't quite work yet, so we get an error we shouldn't get.
+
+package body Strub_Ind is
+ E : exception;
+
+ function G return Integer;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+
+ type GT_SAC is access function return Integer;
+ pragma Machine_Attribute (GT_SAC, "strub", "at-calls");
+
+ GP : GT_SAC := GT_SAC (GT'(G'Access)); -- { dg-error "incompatible" }
+ -- pragma Machine_Attribute (GP, "strub", "at-calls");
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind.ads b/gcc/testsuite/gnat.dg/strub_ind.ads
new file mode 100644
index 0000000000000..99a65fc24b1ec
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.ads
@@ -0,0 +1,17 @@
+package Strub_Ind is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ -- pragma Machine_Attribute (FP, "strub", "at-calls"); -- not needed
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
new file mode 100644
index 0000000000000..825e395e6819c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -0,0 +1,41 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind1 is
+ E : exception;
+
+ type Strub_Int is New Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "disabled");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "disabled");
+
+ type GT_SC is access function return Integer;
+ pragma Machine_Attribute (GT_SC, "strub", "callable");
+
+ GP : GT_SC := GT_SC (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "callable"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all;
+ end;
+
+end Strub_Ind1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]disabled\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.ads b/gcc/testsuite/gnat.dg/strub_ind1.ads
new file mode 100644
index 0000000000000..d3f1273b3a6b9
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.ads
@@ -0,0 +1,17 @@
+package Strub_Ind1 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind1;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
new file mode 100644
index 0000000000000..e918b39263117
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -0,0 +1,34 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind2 is
+ E : exception;
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "callable");
+
+ type GT_SD is access function return Integer;
+ pragma Machine_Attribute (GT_SD, "strub", "disabled");
+
+ GP : GT_SD := GT_SD (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "disabled"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all; -- { dg-error "using non-.strub. type" }
+ end;
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.ads b/gcc/testsuite/gnat.dg/strub_ind2.ads
new file mode 100644
index 0000000000000..e13865ec49c38
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.ads
@@ -0,0 +1,17 @@
+package Strub_Ind2 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
new file mode 100644
index 0000000000000..8f0212a75866f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -0,0 +1,93 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported.
+
+procedure Strub_Intf is
+ package Foo is
+ type TP is interface;
+ procedure P (I : Integer; X : TP) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type TF is interface;
+ function F (X : access TF) return Integer is abstract;
+
+ type TX is interface;
+ procedure P (I : Integer; X : TX) is abstract;
+
+ type TI is interface and TP and TF and TX;
+ -- When we freeze TI, we detect the mismatch between the
+ -- inherited P and another parent's P. Because TP appears
+ -- before TX, we inherit P from TP, and report the mismatch at
+ -- the pragma inherited from TP against TX's P. In contrast,
+ -- when we freeze TII below, since TX appears before TP, we
+ -- report the error at the line in which the inherited
+ -- subprogram is synthesized, namely the line below, against
+ -- the line of the pragma.
+
+ type TII is interface and TX and TP and TF; -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access TI) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type A is new TI with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer; -- { dg-error "requires the same .strub. mode" }
+
+ type B is new TI with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TI'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf;
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
new file mode 100644
index 0000000000000..bf77321cef790
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -0,0 +1,86 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls to interfaces are transformed.
+
+procedure Strub_Intf1 is
+ package Foo is
+ type TX is Interface;
+ procedure P (I : Integer; X : TX) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls");
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type A is new TX with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new TX with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 2 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
new file mode 100644
index 0000000000000..e8880dbc43730
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -0,0 +1,55 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported even when the overriders for an
+-- interface's subprograms are inherited from a type that is not a
+-- descendent of the interface.
+
+procedure Strub_Intf2 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer;
+
+ type TX is Interface;
+
+ procedure P (I : Integer; X : TX) is abstract;
+
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A and TX with null record; -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XB);
+
+ I := I + F (XB'Access);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf2;
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
new file mode 100644
index 0000000000000..217367e712d82
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+
+procedure Strub_Renm is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+ pragma Machine_Attribute (F, "strub", "internal");
+
+ procedure Q (X : Integer) renames P; -- { dg-error "requires the same .strub. mode" }
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "callable"); -- { dg-error "requires the same .strub. mode" }
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm;
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
new file mode 100644
index 0000000000000..a11adbfb5a9d6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+
+procedure Strub_Renm1 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "internal");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm1;
+
+-- This is for P; Q is an alias.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 1 "strub" } }
+
+-- This is *not* for G, but for Strub_Renm1.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapped\[)\]\[)\]" 1 "strub" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapper\[)\]\[)\]" 1 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
new file mode 100644
index 0000000000000..c488c20826fdb
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strub" }
+
+procedure Strub_Renm2 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ type T is access function return Integer;
+
+ type TC is access function return Integer;
+ pragma Machine_Attribute (TC, "strub", "callable");
+
+ FCptr : constant TC := TC (T'(F'Access));
+
+ function G return Integer renames FCptr.all;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F); -- { dg-error "calling non-.strub." }
+ Q (G); -- ok, G is callable.
+end Strub_Renm2;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
new file mode 100644
index 0000000000000..3d158de28031f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- We don't read from the automatic variable, but being an automatic
+-- variable, its presence should be enough for the procedure to get
+-- strub enabled.
+
+with Strub_Attr;
+procedure Strub_Var is
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+begin
+ X := Strub_Attr.F (0);
+end Strub_Var;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
new file mode 100644
index 0000000000000..6a504e09198b6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -0,0 +1,20 @@
+-- { dg-do compile }
+
+with Strub_Attr;
+procedure Strub_Var1 is
+ type TA -- { dg-warning "does not apply to elements" }
+ is array (1..2) of Integer;
+ pragma Machine_Attribute (TA, "strub");
+
+ A : TA := (0, 0); -- { dg-warning "does not apply to elements" }
+
+ type TR is record -- { dg-warning "does not apply to fields" }
+ M, N : Integer;
+ end record;
+ pragma Machine_Attribute (TR, "strub");
+
+ R : TR := (0, 0);
+
+begin
+ A(2) := Strub_Attr.F (A(1));
+end Strub_Var1;
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index ffeb20b717aea..f748ca8508940 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -5774,6 +5774,7 @@ gimple_verify_flow_info (void)
{
gimple *stmt = gsi_stmt (gsi);
+ /* Do NOT disregard debug stmts after found_ctrl_stmt. */
if (found_ctrl_stmt)
{
error ("control flow in the middle of basic block %d",
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 09e6ada5b2f91..36f955a0b37ee 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -510,8 +510,9 @@ extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
-extern simple_ipa_opt_pass
- *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tree_profile (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_auto_profile (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 1a555ae682638..03ff88afadddd 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -3073,7 +3073,9 @@ optimize_stack_restore (gimple_stmt_iterator i)
if (!callee
|| !fndecl_built_in_p (callee, BUILT_IN_NORMAL)
/* All regular builtins are ok, just obviously not alloca. */
- || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)))
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
+ /* Do not remove stack updates before strub leave. */
+ || fndecl_built_in_p (callee, BUILT_IN___STRUB_LEAVE))
return NULL_TREE;
if (fndecl_built_in_p (callee, BUILT_IN_STACK_RESTORE))
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 8dedd10f79a30..d8163c5af9903 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -433,6 +433,9 @@ LIB2ADD += enable-execute-stack.c
# Control Flow Redundancy hardening out-of-line checker.
LIB2ADD += $(srcdir)/hardcfr.c
+# Stack scrubbing infrastructure.
+LIB2ADD += $(srcdir)/strub.c
+
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
# instead of LIB2ADD because that's the way to be sure on some targets
# (e.g. *-*-darwin*) only one copy of it is linked.
diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h
index 06e26cad884b4..0b97eec472586 100644
--- a/libgcc/libgcc2.h
+++ b/libgcc/libgcc2.h
@@ -551,6 +551,10 @@ extern int __parityDI2 (UDWtype);
extern void __enable_execute_stack (void *);
+extern void __strub_enter (void **);
+extern void __strub_update (void**);
+extern void __strub_leave (void **);
+
#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
#endif
diff --git a/libgcc/strub.c b/libgcc/strub.c
new file mode 100644
index 0000000000000..2a2b930b6039d
--- /dev/null
+++ b/libgcc/strub.c
@@ -0,0 +1,149 @@
+/* Stack scrubbing infrastructure
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+#include "libgcc2.h"
+
+#ifndef STACK_GROWS_DOWNWARD
+# define TOPS >
+#else
+# define TOPS <
+#endif
+
+#define ATTRIBUTE_STRUB_CALLABLE __attribute__ ((__strub__ ("callable")))
+
+/* Enter a stack scrubbing context, initializing the watermark to the caller's
+ stack address. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_enter (void **watermark)
+{
+ *watermark = __builtin_frame_address (0);
+}
+
+/* Update the watermark within a stack scrubbing context with the current stack
+ pointer. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_update (void **watermark)
+{
+ void *sp = __builtin_frame_address (0);
+
+ if (sp TOPS *watermark)
+ *watermark = sp;
+}
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY && ! defined TARGET_STRUB_MAY_USE_MEMSET
+# define TARGET_STRUB_MAY_USE_MEMSET 1
+#endif
+
+#if defined __x86_64__ && __OPTIMIZE__
+# define TARGET_STRUB_DISABLE_RED_ZONE \
+ /* __attribute__ ((__target__ ("no-red-zone"))) // not needed when optimizing */
+#elif !defined RED_ZONE_SIZE || defined __i386__
+# define TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+
+#ifndef TARGET_STRUB_DISABLE_RED_ZONE
+/* Dummy function, called to force the caller to not be a leaf function, so
+ that it can't use the red zone. */
+static void ATTRIBUTE_STRUB_CALLABLE
+__attribute__ ((__noinline__, __noipa__))
+__strub_dummy_force_no_leaf (void)
+{
+}
+#endif
+
+/* Leave a stack scrubbing context, clearing the stack between its top and
+ *MARK. */
+void ATTRIBUTE_STRUB_CALLABLE
+#if ! TARGET_STRUB_MAY_USE_MEMSET
+__attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
+#endif
+#ifdef TARGET_STRUB_DISABLE_RED_ZONE
+TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+__strub_leave (void **mark)
+{
+ void *sp = __builtin_stack_address ();
+
+ void **base, **end;
+#ifndef STACK_GROWS_DOWNWARD
+ base = sp; /* ??? Do we need an offset here? */
+ end = *mark;
+#else
+ base = *mark;
+ end = sp; /* ??? Does any platform require an offset here? */
+#endif
+
+ if (! (base < end))
+ return;
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY
+ /* Compute the length without assuming the pointers are both sufficiently
+ aligned. They should be, but pointer differences expected to be exact may
+ yield unexpected results when the assumption doesn't hold. Given the
+ potential security implications, compute the length without that
+ expectation. If the pointers are misaligned, we may leave a partial
+ unscrubbed word behind. */
+ ptrdiff_t len = ((char *)end - (char *)base) / sizeof (void *);
+ /* Allocate a dynamically-sized array covering the desired range, so that we
+ can safely call memset on it. */
+ void *ptr[len];
+ base = &ptr[0];
+ end = &ptr[len];
+#elifndef TARGET_STRUB_DISABLE_RED_ZONE
+ /* Prevent the use of the red zone, by making this function non-leaf through
+ an unreachable call that, because of the asm stmt, the compiler will
+ consider reachable. */
+ asm goto ("" : : : : no_leaf);
+ if (0)
+ {
+ no_leaf:
+ __strub_dummy_force_no_leaf ();
+ return;
+ }
+#endif
+
+ /* ldist may turn these loops into a memset (thus the conditional
+ -fno-tree-loop-distribute-patterns above). Without the dynamic array
+ above, that call would likely be unsafe: possibly tail-called, and likely
+ scribbling over its own stack frame. */
+#ifndef STACK_GROWS_DOWNWARD
+ do
+ *base++ = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (end[0]));
+#else
+ do
+ *--end = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (base[0]));
+#endif
+}
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-10-20 6:03 ` [PATCH v4] " Alexandre Oliva
@ 2023-10-26 6:15 ` Alexandre Oliva
2023-11-20 12:40 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-10-26 6:15 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson, Jeff Law
Ping? https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633675.html
I'm combining the gcc/ipa-strub.cc bits from
https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633526.html
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-10-26 6:15 ` Alexandre Oliva
@ 2023-11-20 12:40 ` Alexandre Oliva
2023-11-22 14:14 ` Richard Biener
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-11-20 12:40 UTC (permalink / raw)
To: gcc-patches
Cc: Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Richard Biener, Jim Wilson, Jeff Law
On Oct 26, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
>> This is a refreshed and improved version of the version posted back in
>> June. https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621936.html
> Ping? https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633675.html
> I'm combining the gcc/ipa-strub.cc bits from
> https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633526.html
Ping?
Retested on x86_64-linux-gnu, with and without -fstrub=all.
>> This patch adds the strub attribute for function and variable types,
>> command-line options, passes and adjustments to implement it,
>> documentation, and tests.
>> Stack scrubbing is implemented in a machine-independent way: functions
...
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-20 12:40 ` Alexandre Oliva
@ 2023-11-22 14:14 ` Richard Biener
2023-11-23 10:56 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Richard Biener @ 2023-11-22 14:14 UTC (permalink / raw)
To: Alexandre Oliva
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Mon, Nov 20, 2023 at 1:40 PM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Oct 26, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
>
> >> This is a refreshed and improved version of the version posted back in
> >> June. https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621936.html
>
> > Ping? https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633675.html
> > I'm combining the gcc/ipa-strub.cc bits from
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633526.html
>
> Ping?
> Retested on x86_64-linux-gnu, with and without -fstrub=all.
@@ -898,7 +899,24 @@ decl_attributes (tree *node, tree attributes, int flags,
TYPE_NAME (tt) = *node;
}
- *anode = cur_and_last_decl[0];
+ if (*anode != cur_and_last_decl[0])
+ {
+ /* Even if !spec->function_type_required, allow the attribute
+ handler to request the attribute to be applied to the function
+ type, rather than to the function pointer type, by setting
+ cur_and_last_decl[0] to the function type. */
+ if (!fn_ptr_tmp
+ && POINTER_TYPE_P (*anode)
+ && TREE_TYPE (*anode) == cur_and_last_decl[0]
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+ {
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ }
+ *anode = cur_and_last_decl[0];
+ }
+
what is this a workaround for? Isn't there a suitable parsing position
for placing the attribute?
+#ifndef STACK_GROWS_DOWNWARD
+# define STACK_TOPS GT
+#else
+# define STACK_TOPS LT
+#endif
according to docs this is defined to 0 or 1 so the above looks wrong
(it's always defined).
+ if (optimize < 2 || optimize_size || flag_no_inline)
+ return NULL_RTX;
I'm wondering about these checks in the expansions of the builtins,
I think this is about inline expanding or emitting a libcall, right?
I wonder if you should use optimize_function_for_speed (cfun) instead?
Usually -fno-inline shouldn't affect such calls, but -fno-builtin-FOO would.
I have no strong opinion here though.
The new builtins seem undocumented - usually those are documented
within extend.texi - I guess placing __builtin___strub_enter calls in
the code manually will break in interesting ways - if that's not supposed
to happen the trick is to embed a space in the name of the built-in.
__builtin_stack_address looks like something users will pick up though
(and thus should be documented)?
-symtab_node::reset (void)
+symtab_node::reset (bool preserve_comdat_group)
not sure what for, I'll leave Honza to comment.
+/* Create a distinct copy of the type of NODE's function, and change
+ the fntype of all calls to it with the same main type to the new
+ type. */
+
+static void
+distinctify_node_type (cgraph_node *node)
+{
+ tree old_type = TREE_TYPE (node->decl);
+ tree new_type = build_distinct_type_copy (old_type);
+ tree new_ptr_type = NULL_TREE;
+
+ /* Remap any calls to node->decl that use old_type, or a variant
+ thereof, to new_type as well. We don't look for aliases, their
+ declarations will have their types changed independently, and
+ we'll adjust their fntypes then. */
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->call_stmt)
+ continue;
+ tree fnaddr = gimple_call_fn (e->call_stmt);
+ gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
+ && TREE_OPERAND (fnaddr, 0) == node->decl);
+ if (strub_call_fntype_override_p (e->call_stmt))
+ continue;
+ if (!new_ptr_type)
+ new_ptr_type = build_pointer_type (new_type);
+ TREE_TYPE (fnaddr) = new_ptr_type;
+ gimple_call_set_fntype (e->call_stmt, new_type);
+ }
+
+ TREE_TYPE (node->decl) = new_type;
it does feel like there's IPA mechanisms to deal with what you are trying to do
here (or in the caller(s)).
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ last_cgraph_order = 0;
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
if (flag_checking) verify_strub ();
please. I guess we talked about this last year - what's the reason to have both
an IPA pass and a simple IPA pass? IIRC the simple IPA pass is a simple
one because it wants to see inlined bodies and "fixes" those up? Some toplevel
comments explaining both passes in the ipa-strub.cc pass would be nice to
have. I guess I also asked before - did you try it with -flto?
+ /* Decide which of the wrapped function's parms we want to turn into
+ references to the argument passed to the wrapper. In general,
we want to
+ copy small arguments, and avoid copying large ones.
Variable-sized array
+ lengths given by other arguments, as in 20020210-1.c, would lead to
+ problems if passed by value, after resetting the original function and
+ dropping the length computation; passing them by reference works.
+ DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
+ anyway, but performed at the caller. */
+ indirect_parms_t indirect_nparms (3, false);
...
IMHO it's a bad idea, at least initially, to mess with the ABI in a heuristical
way this way. I see you need all sorts of "fixup", including re-gimplification
of stmts, etc., double-ugh. Ideally IPA-SRA can already do parts of those
transforms which would mean ipa-param-manipulation has generic code
to encode them? I realize you can't tail-call, but I wonder if some clever
machine-specific tricks would work, I guess it would need the wrapper
to be target generated of course.
As it's only for optimization, how much of the code would go away when
you avoid changing the parameters of the wrapped function? Could
one easily disable the optimization via a --param maybe?
There's still much commented code and FIXMEs in, a lot of cgraph
related code is used which I can't review very well.
I fear that -fstrub is going to be actually used by people - are you up
to the task fixing things?
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_enter (void **watermark)
+{
+ *watermark = __builtin_frame_address (0);
in your experience, do these (or the inline version) work reliably
when optimizations like omitting the frame pointer or shrink-wrapping
happen from a security point of view?
You are adding symbols to libgcc but I don't see you amending
libgcc/libgcc-std.ver.in?
Neither the documentation in extend.texi nor the one in invoke.texi
mentions the target audience of -fstrub - I suppose it is to ensure
secrets are erased from the stack in case they are stored into locals
or spilled and thus it complements -fzero-call-used-regs. The patches
mention the red zone, documenting the guarantees and caveats
would be nice to have. I think the documentation belongs to the
attribute documentation.
I hope Honza can have a quick look over the IPA passes. As said,
eliding the parmeter optimization from this patch, possibly
implementing missing pieces in ipa-param-manipulation might be
a better way than taking what is percieved as a huge ugly part
of the patch.
Thanks,
Richard.
> >> This patch adds the strub attribute for function and variable types,
> >> command-line options, passes and adjustments to implement it,
> >> documentation, and tests.
>
> >> Stack scrubbing is implemented in a machine-independent way: functions
> ...
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-22 14:14 ` Richard Biener
@ 2023-11-23 10:56 ` Alexandre Oliva
2023-11-23 12:05 ` Richard Biener
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-11-23 10:56 UTC (permalink / raw)
To: Richard Biener
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
Hello, Richi,
Thanks for the extensive review!
On Nov 22, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
> On Mon, Nov 20, 2023 at 1:40 PM Alexandre Oliva <oliva@adacore.com> wrote:
>>
>> On Oct 26, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
>>
>> >> This is a refreshed and improved version of the version posted back in
>> >> June. https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621936.html
>>
>> > Ping? https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633675.html
>> > I'm combining the gcc/ipa-strub.cc bits from
>> > https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633526.html
>>
>> Ping?
>> Retested on x86_64-linux-gnu, with and without -fstrub=all.
> @@ -898,7 +899,24 @@ decl_attributes (tree *node, tree attributes, int flags,
> TYPE_NAME (tt) = *node;
> }
> - *anode = cur_and_last_decl[0];
> + if (*anode != cur_and_last_decl[0])
> + {
> + /* Even if !spec->function_type_required, allow the attribute
> + handler to request the attribute to be applied to the function
> + type, rather than to the function pointer type, by setting
> + cur_and_last_decl[0] to the function type. */
> + if (!fn_ptr_tmp
> + && POINTER_TYPE_P (*anode)
> + && TREE_TYPE (*anode) == cur_and_last_decl[0]
> + && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
> + {
> + fn_ptr_tmp = TREE_TYPE (*anode);
> + fn_ptr_quals = TYPE_QUALS (*anode);
> + anode = &fn_ptr_tmp;
> + }
> + *anode = cur_and_last_decl[0];
> + }
> +
> what is this a workaround for?
For the fact that the strub attribute attaches to types, whether data or
function types, so we can't have fn_type_req, but when it's a function
or pointer-to-function type, we want to affect the function type, rather
than the pointer type, when the attribute has an argument. The argument
names the strub mode for a function; that only applies to function
types, never to data types.
The hunk above introduces the means for the attribute handler to choose
what to attach the attribute t.
> Isn't there a suitable parsing position for placing the attribute?
It's been a while, but IIRC the need for this first came up in Ada,
where attributes can't just go anywhere, and it was further complicated
by the fact that Ada doesn't have first-class function or procedure
types, only access-to-them, but we needed some means for the attributes
to apply to the function type.
> +#ifndef STACK_GROWS_DOWNWARD
> +# define STACK_TOPS GT
> +#else
> +# define STACK_TOPS LT
> +#endif
> according to docs this is defined to 0 or 1 so the above looks wrong
> (it's always defined).
Ugh. Thanks, will fix. (I'm pretty sure I had notes somewhere stating
that stack-grows-upwards hadn't been tested, and that was for the sheer
lack of platforms making that choice, but I hoped it wasn't that broken
:-(
> + if (optimize < 2 || optimize_size || flag_no_inline)
> + return NULL_RTX;
> I'm wondering about these checks in the expansions of the builtins,
> I think this is about inline expanding or emitting a libcall, right?
Yeah.
> I wonder if you should use optimize_function_for_speed (cfun) instead?
> Usually -fno-inline shouldn't affect such calls, but -fno-builtin-FOO would.
> I have no strong opinion here though.
I've occasionally wondered whether builtins were the best framework for
these semi-internal calls.
> The new builtins seem undocumented - usually those are documented
> within extend.texi
Erhm... Weird. I had documentation for them.
(checks)
No, it's there, in extend.texi, right after __builtin_stack_address.
It's admittedly a big patch :-/
> I guess placing __builtin___strub_enter calls in the code manually
> will break in interesting ways - if that's not supposed to happen the
> trick is to embed a space in the name of the built-in.
Yeah, I was a little torn between the choices here. On the one hand, I
needed visible symbols for the out-of-line implementations, so I figured
that trying to hide the builtins wouldn't bring any advantage.
However, I've also designed the builtins with interfaces that would
avoid disruption even with explicit calls. __strub_enter and
__strub_update only initialize or adjust a pointer handed to them.
__strub_leave will erase things from the top of the stack to the
pointer, so if the watermark is "active stack", nothing happens, and
things only get cleared if it points to "unused stack space". There's
potential for disruption if one passes a statically-allocated pointer to
it, but nothing much different from memsetting that memory range, core
wars-style.
> -symtab_node::reset (void)
> +symtab_node::reset (bool preserve_comdat_group)
> not sure what for, I'll leave Honza to comment.
This restores the possibility of getting the pre-PR107897 behavior, that
the strub wrapper/wrapped splitting relied on. Conceptually, the
original function becomes the wrapped one, and the wrapper that calls it
is kind of an implementation detail to preserve the exposed API/ABI
while introducing strubbing around the body, so preserving the comdat
group makes sense. ISTR getting strub regressions when the patch for
PR107897 was put in, but my notes don't detail what broke, alas.
> +/* Create a distinct copy of the type of NODE's function, and change
> + the fntype of all calls to it with the same main type to the new
> + type. */
> +
> +static void
> +distinctify_node_type (cgraph_node *node)
> +{
> + tree old_type = TREE_TYPE (node->decl);
> + tree new_type = build_distinct_type_copy (old_type);
> + tree new_ptr_type = NULL_TREE;
> +
> + /* Remap any calls to node->decl that use old_type, or a variant
> + thereof, to new_type as well. We don't look for aliases, their
> + declarations will have their types changed independently, and
> + we'll adjust their fntypes then. */
> + for (cgraph_edge *e = node->callers; e; e = e->next_caller)
> + {
> + if (!e->call_stmt)
> + continue;
> + tree fnaddr = gimple_call_fn (e->call_stmt);
> + gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
> + && TREE_OPERAND (fnaddr, 0) == node->decl);
> + if (strub_call_fntype_override_p (e->call_stmt))
> + continue;
> + if (!new_ptr_type)
> + new_ptr_type = build_pointer_type (new_type);
> + TREE_TYPE (fnaddr) = new_ptr_type;
> + gimple_call_set_fntype (e->call_stmt, new_type);
> + }
> +
> + TREE_TYPE (node->decl) = new_type;
> it does feel like there's IPA mechanisms to deal with what you are trying to do
> here (or in the caller(s)).
If there is, I couldn't find it. There are some vaguely similar
operations, but nothing that will modify the ABI of exported functions
like what strub-at-calls purports to do. A synthetic argument gets
added to the function's interface, but since that type could conceivably
have been associated/unified with non-strub types, or with similar types
with different strub modes that don't undergo such transformations, we
have to build a new type for the function, and adjust the type in the
call graph. IPA can do this as part of replacing calls with specialized
clones of a function, but here the attribute calls for an adjustment to
the function type, vaguely resembling the introduction of the implicit
'this' in non-static member functions in C++, but without much help from
the front-end, and without exposing the formal to the front-end. It
doesn't seem to me that IPA is willing to help with that, and even if it
were, it would require strub to become an actual IPA pass, which would
be a huge undertaking without clear benefit.
> +unsigned int
> +pass_ipa_strub_mode::execute (function *)
> +{
> + last_cgraph_order = 0;
> + ipa_strub_set_mode_for_new_functions ();
> +
> + /* Verify before any inlining or other transformations. */
> + verify_strub ();
> if (flag_checking) verify_strub ();
> please.
No, no, verify_strub is not an internal consistency check, it's part of
the implementation that verifies that strictness requirements have been
met WRT calls requested by the user. In strict mode, a strub function
can only call other strub functions or functions explicitly marked as
callable from strub contexts. This security requirement is to be
enforced, and diagnostics are to be issued in case of violation,
regardless of the self-checking mode of the compiler.
> I guess we talked about this last year - what's the reason to have both
> an IPA pass and a simple IPA pass?
We did. I didn't recall all the reasons on the spot when you asked, but
I followed up by email:
https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603255.html
The earlier pass, that must be placed before any inlining, is the simple
IPA one, and it only assigns modes.
It must be that early because strub-enabled functions must never be
inlined into strub-disabled ones. So we have to determine modes before
any sort of inlining.
But we can and want to inline strub-enabled functions into other
strub-enabled functions. But we don't want to inline a wrapped function
back into its wrapper, so we want to (early) inline functions before
they're split, and we also want to inline wrappers after they're split
if possible.
So the assignment pass has to be before any inlining, and the
wrapping/splitting (for internal strub) must be after some inlining but
before the last attempt at inlining.
> IIRC the simple IPA pass is a simple one because it wants to see
> inlined bodies and "fixes" those up? Some toplevel comments
> explaining both passes in the ipa-strub.cc pass would be nice to have.
ACK, will do.
> I guess I also asked before - did you try it with -flto?
Yeah, I've tested it extensively with -flto during development. I've
run the GCC testsuite with a patch equivalent to -fstrub=all enabled by
default during development, and I still do so occasionally. I didn't
before the ping, but prompted by you, I did again. Torture tests and
specific lto tests don't seem to face any trouble. And there's no
reason why they should. The spots in which the strub passes were
introduced involved exploring where they fit best, and adding calls such
as analyzing nodes. There are even commented-out vestigial calls of
inline_analyze_function, from a time when the pass was inserted at a
different spot and that call was required.
> + /* Decide which of the wrapped function's parms we want to turn into
> + references to the argument passed to the wrapper. In general,
> we want to
> + copy small arguments, and avoid copying large ones.
> Variable-sized array
> + lengths given by other arguments, as in 20020210-1.c, would lead to
> + problems if passed by value, after resetting the original function and
> + dropping the length computation; passing them by reference works.
> + DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
> + anyway, but performed at the caller. */
> + indirect_parms_t indirect_nparms (3, false);
> ...
> IMHO it's a bad idea, at least initially, to mess with the ABI in a heuristical
> way this way.
Do you realize that this is only about the wrapped ABI, used exclusively
by the wrapper, to avoid pointlessly copying large arguments twice? The
wrapper already needs a custom ABI, because of the added watermark
pointer, and va_list and whatnot when needed, so a little further
customization to avoid a quite significant overhead seemed desirable.
> I see you need all sorts of "fixup", including re-gimplification
> of stmts, etc., double-ugh.
*nod*, I've considered going the nested-function way, enabling the
wrapped function to access wrapper's variables directly, but (i) support
for nested functions isn't available everywhere, and (ii) strub
functions could already be nested functions, and the wrapped body would
need access to both enclosing contexts, so adjustments would have to be
made anyway.
> Ideally IPA-SRA can already do parts of those
> transforms which would mean ipa-param-manipulation has generic code
> to encode them?
You'd think so. I tried that, run into various issues, still have
pending patches I submitted separately to address them, but... at some
point I had to stop waiting for feedback and had make it work without
that. I figured what I was doing wasn't a good fit and moved on.
Now, it would be great if IPA could enable me to split the entire body
of a function *while* adding custom arguments, such as the watermark,
va_list, etc. It didn't look like it could or even wanted to, but maybe
the presence of a useful feature like stack scrubbing could motivate the
introduction of such infrastructure.
> I realize you can't tail-call, but I wonder if some clever
> machine-specific tricks would work, I guess it would need the wrapper
> to be target generated of course.
I'm not sure what you have in mind here, but one of the goals was to
introduce stack scrubbing without machine-dependent code.
We are considering an improvement for strub(internal) to do away with
wrappers given machine-specific prologue/epilogue support, but that's
not even in the roadmap, and it's not clear how that would interact with
exceptions, which was a primary driver for the currently-proposed
approaches.
> As it's only for optimization, how much of the code would go away when
> you avoid changing the parameters of the wrapped function?
We can't avoid changing them entirely, and IIRC some of the
infrastructure for regimplification was also used for va_list and
apply_args handling, so it wouldn't save all that much. It is an
important optimization, to avoid doubling the stack requirements for
parameters with -fstrub=internal (because wrapper passes arguments on to
wrapped body), and the optimization is already implemented, so it would
be a pity to take it out, and you wouldn't even get rid of any
significant amount of code.
> Could one easily disable the optimization via a --param maybe?
The param is not implemented, but guarding the loop you commented on by
it would accomplish it. You probably won't want to bootstrap GCC with
-fstrub=all along with it, though ;-)
> There's still much commented code and FIXMEs in, a lot of cgraph
> related code is used which I can't review very well.
Now that you mentioned it, I realize I hadn't yet dropped some of the
preprocessed-out bits when I posted v4. I did so afterwards. I was
trying to avoid posting such a monster patch again, but I guess I will
have to post at least another version :-(
But yeah, there are some wishlist items that remain, and some bits that
could probably go away.
> I fear that -fstrub is going to be actually used by people - are you up
> to the task fixing things?
I, for one, would welcome that, and I am (professionally) on the hook to
fix it, so I'd better be up to it ;-) Building it on top of
infrastructure I'm closely familiar with, rather than e.g. on IPA, that
I'm not so much, is a plus in this regard. That said, I've fixed bugs
in GCC most everywhere, from front-ends to back-ends, so I'm pretty sure
I've got it covered in terms of knowledge. As for time, if it gets too
much interest (is there such a thing? :-) I might have trouble keeping
up (there are only so many hours in the day), and it would likely be
wise then for others to become familiar with it. I'd be happy to share
knowledge, and I know I have support from my "employer" (in quotes
because I'm not formally employed, I'm a consultant) to maintain the
code I contribute to the community on its behalf, even having other work
and non-work commitments. So, bring them on, I say ;-)
> +void ATTRIBUTE_STRUB_CALLABLE
> +__strub_enter (void **watermark)
> +{
> + *watermark = __builtin_frame_address (0);
> in your experience, do these (or the inline version) work reliably
> when optimizations like omitting the frame pointer or shrink-wrapping
> happen from a security point of view?
Yeah. We're talking about the frame address for the current function
here, and the compiler knows what it is, even if it optimizes the heck
out of the function. In the builtin expansion, it's the top of the
stack instead, and the compiler also has to have a good grasp of where
that is. Red zones are a small complication, but not really much
trouble here: it's a watermark we're talking about, how high the stack
may have gotten, so we know we have to scrub no further than that. If
it goes too far (as it often does with red zones), we just scrub a
little too much. What shouldn't happen is not going far enough, but
since we rely on the stack frame address for __strub_update to update
the watermark, and the caller can't really misrepresent its own stack
use without risking the callee to corrupt it, this works really well.
If strub_update gets builtin-expanded inline, it uses the adjusted (for
red zone) stack pointer instead, after any internal stack allocation
(prologue and alloca), but it won't necessarily capture non-accumulated
outgoing args. The arguments passed to a callee are not regarded as
part of the caller stack frame, so that should be fine. In order to
cover them, one must have a strub-enabled caller and a strub(at-calls)
callee.
> You are adding symbols to libgcc but I don't see you amending
> libgcc/libgcc-std.ver.in?
That's a good catch, thanks.
hardcfr symbols are missing too.
Will fix.
> Neither the documentation in extend.texi nor the one in invoke.texi
> mentions the target audience of -fstrub
ACK, good point, despite all the detail, that is too implicit. Will
fix.
> The patches mention the red zone, documenting the guarantees and
> caveats would be nice to have. I think the documentation belongs to
> the attribute documentation.
It is kind of there, but since the details vary depending on the strub
mode, they're given where the modes are detailed, rather than as if
applying to all strub modes. (some of the modes are disabled and
callable, that don't do any strubbing whatsoever)
> I hope Honza can have a quick look over the IPA passes.
Likewise. I shall wait for further feedback before posting a huge v5,
but I'll be happy to refresh the users/aoliva/heads/strub branch in the
git repo as I adjust the patch if that helps. Currently the patch is in
users/aoliva/heads/testme.
> a better way than taking what is percieved as a huge ugly part
> of the patch.
ISTM you're misperceiving the amount of code involved in that
optimization. There is a significant amount of wrapper/wrapped
parameter manipulation that is *not* involved with the optimization, and
that was already there before the optimization was implemented. The
optimization was a tiny addition over it.
Thanks again,
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-23 10:56 ` Alexandre Oliva
@ 2023-11-23 12:05 ` Richard Biener
2023-11-29 8:53 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Richard Biener @ 2023-11-23 12:05 UTC (permalink / raw)
To: Alexandre Oliva
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Thu, Nov 23, 2023 at 11:56 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> Hello, Richi,
>
> Thanks for the extensive review!
>
> On Nov 22, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
>
> > On Mon, Nov 20, 2023 at 1:40 PM Alexandre Oliva <oliva@adacore.com> wrote:
> >>
> >> On Oct 26, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
> >>
> >> >> This is a refreshed and improved version of the version posted back in
> >> >> June. https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621936.html
> >>
> >> > Ping? https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633675.html
> >> > I'm combining the gcc/ipa-strub.cc bits from
> >> > https://gcc.gnu.org/pipermail/gcc-patches/2023-October/633526.html
> >>
> >> Ping?
> >> Retested on x86_64-linux-gnu, with and without -fstrub=all.
>
> > @@ -898,7 +899,24 @@ decl_attributes (tree *node, tree attributes, int flags,
> > TYPE_NAME (tt) = *node;
> > }
>
> > - *anode = cur_and_last_decl[0];
> > + if (*anode != cur_and_last_decl[0])
> > + {
> > + /* Even if !spec->function_type_required, allow the attribute
> > + handler to request the attribute to be applied to the function
> > + type, rather than to the function pointer type, by setting
> > + cur_and_last_decl[0] to the function type. */
> > + if (!fn_ptr_tmp
> > + && POINTER_TYPE_P (*anode)
> > + && TREE_TYPE (*anode) == cur_and_last_decl[0]
> > + && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
> > + {
> > + fn_ptr_tmp = TREE_TYPE (*anode);
> > + fn_ptr_quals = TYPE_QUALS (*anode);
> > + anode = &fn_ptr_tmp;
> > + }
> > + *anode = cur_and_last_decl[0];
> > + }
> > +
>
> > what is this a workaround for?
>
> For the fact that the strub attribute attaches to types, whether data or
> function types, so we can't have fn_type_req, but when it's a function
> or pointer-to-function type, we want to affect the function type, rather
> than the pointer type, when the attribute has an argument. The argument
> names the strub mode for a function; that only applies to function
> types, never to data types.
>
> The hunk above introduces the means for the attribute handler to choose
> what to attach the attribute t.
>
> > Isn't there a suitable parsing position for placing the attribute?
>
> It's been a while, but IIRC the need for this first came up in Ada,
> where attributes can't just go anywhere, and it was further complicated
> by the fact that Ada doesn't have first-class function or procedure
> types, only access-to-them, but we needed some means for the attributes
> to apply to the function type.
>
> > +#ifndef STACK_GROWS_DOWNWARD
> > +# define STACK_TOPS GT
> > +#else
> > +# define STACK_TOPS LT
> > +#endif
>
> > according to docs this is defined to 0 or 1 so the above looks wrong
> > (it's always defined).
>
> Ugh. Thanks, will fix. (I'm pretty sure I had notes somewhere stating
> that stack-grows-upwards hadn't been tested, and that was for the sheer
> lack of platforms making that choice, but I hoped it wasn't that broken
> :-(
>
> > + if (optimize < 2 || optimize_size || flag_no_inline)
> > + return NULL_RTX;
>
> > I'm wondering about these checks in the expansions of the builtins,
> > I think this is about inline expanding or emitting a libcall, right?
>
> Yeah.
>
> > I wonder if you should use optimize_function_for_speed (cfun) instead?
> > Usually -fno-inline shouldn't affect such calls, but -fno-builtin-FOO would.
> > I have no strong opinion here though.
>
> I've occasionally wondered whether builtins were the best framework for
> these semi-internal calls.
>
> > The new builtins seem undocumented - usually those are documented
> > within extend.texi
>
> Erhm... Weird. I had documentation for them.
>
> (checks)
>
> No, it's there, in extend.texi, right after __builtin_stack_address.
> It's admittedly a big patch :-/
>
> > I guess placing __builtin___strub_enter calls in the code manually
> > will break in interesting ways - if that's not supposed to happen the
> > trick is to embed a space in the name of the built-in.
>
> Yeah, I was a little torn between the choices here. On the one hand, I
> needed visible symbols for the out-of-line implementations, so I figured
> that trying to hide the builtins wouldn't bring any advantage.
>
> However, I've also designed the builtins with interfaces that would
> avoid disruption even with explicit calls. __strub_enter and
> __strub_update only initialize or adjust a pointer handed to them.
> __strub_leave will erase things from the top of the stack to the
> pointer, so if the watermark is "active stack", nothing happens, and
> things only get cleared if it points to "unused stack space". There's
> potential for disruption if one passes a statically-allocated pointer to
> it, but nothing much different from memsetting that memory range, core
> wars-style.
>
> > -symtab_node::reset (void)
> > +symtab_node::reset (bool preserve_comdat_group)
>
> > not sure what for, I'll leave Honza to comment.
>
> This restores the possibility of getting the pre-PR107897 behavior, that
> the strub wrapper/wrapped splitting relied on. Conceptually, the
> original function becomes the wrapped one, and the wrapper that calls it
> is kind of an implementation detail to preserve the exposed API/ABI
> while introducing strubbing around the body, so preserving the comdat
> group makes sense. ISTR getting strub regressions when the patch for
> PR107897 was put in, but my notes don't detail what broke, alas.
>
> > +/* Create a distinct copy of the type of NODE's function, and change
> > + the fntype of all calls to it with the same main type to the new
> > + type. */
> > +
> > +static void
> > +distinctify_node_type (cgraph_node *node)
> > +{
> > + tree old_type = TREE_TYPE (node->decl);
> > + tree new_type = build_distinct_type_copy (old_type);
> > + tree new_ptr_type = NULL_TREE;
> > +
> > + /* Remap any calls to node->decl that use old_type, or a variant
> > + thereof, to new_type as well. We don't look for aliases, their
> > + declarations will have their types changed independently, and
> > + we'll adjust their fntypes then. */
> > + for (cgraph_edge *e = node->callers; e; e = e->next_caller)
> > + {
> > + if (!e->call_stmt)
> > + continue;
> > + tree fnaddr = gimple_call_fn (e->call_stmt);
> > + gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
> > + && TREE_OPERAND (fnaddr, 0) == node->decl);
> > + if (strub_call_fntype_override_p (e->call_stmt))
> > + continue;
> > + if (!new_ptr_type)
> > + new_ptr_type = build_pointer_type (new_type);
> > + TREE_TYPE (fnaddr) = new_ptr_type;
> > + gimple_call_set_fntype (e->call_stmt, new_type);
> > + }
> > +
> > + TREE_TYPE (node->decl) = new_type;
>
> > it does feel like there's IPA mechanisms to deal with what you are trying to do
> > here (or in the caller(s)).
>
> If there is, I couldn't find it. There are some vaguely similar
> operations, but nothing that will modify the ABI of exported functions
> like what strub-at-calls purports to do. A synthetic argument gets
> added to the function's interface, but since that type could conceivably
> have been associated/unified with non-strub types, or with similar types
> with different strub modes that don't undergo such transformations, we
> have to build a new type for the function, and adjust the type in the
> call graph. IPA can do this as part of replacing calls with specialized
> clones of a function, but here the attribute calls for an adjustment to
> the function type, vaguely resembling the introduction of the implicit
> 'this' in non-static member functions in C++, but without much help from
> the front-end, and without exposing the formal to the front-end. It
> doesn't seem to me that IPA is willing to help with that, and even if it
> were, it would require strub to become an actual IPA pass, which would
> be a huge undertaking without clear benefit.
Conceptually it shouldn't be much different from what IPA-SRA does
which is cloning a function but with different arguments, the function
signature transform described in terms of ipa-param-manipulation bits.
I've talked with Martin and at least there's currently no
by-value-to-by-reference
"transform", but IPA-SRA can pass two registers instead of one aggregate
for example. There's IPA_PARAM_OP_NEW already to add a new param.
In principle the whole function rewriting (apart of recovering
from inlining) should be doable within this framework.
> > +unsigned int
> > +pass_ipa_strub_mode::execute (function *)
> > +{
> > + last_cgraph_order = 0;
> > + ipa_strub_set_mode_for_new_functions ();
> > +
> > + /* Verify before any inlining or other transformations. */
> > + verify_strub ();
>
> > if (flag_checking) verify_strub ();
>
> > please.
>
> No, no, verify_strub is not an internal consistency check, it's part of
> the implementation that verifies that strictness requirements have been
> met WRT calls requested by the user. In strict mode, a strub function
> can only call other strub functions or functions explicitly marked as
> callable from strub contexts. This security requirement is to be
> enforced, and diagnostics are to be issued in case of violation,
> regardless of the self-checking mode of the compiler.
>
> > I guess we talked about this last year - what's the reason to have both
> > an IPA pass and a simple IPA pass?
>
> We did. I didn't recall all the reasons on the spot when you asked, but
> I followed up by email:
> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603255.html
>
> The earlier pass, that must be placed before any inlining, is the simple
> IPA one, and it only assigns modes.
>
> It must be that early because strub-enabled functions must never be
> inlined into strub-disabled ones. So we have to determine modes before
> any sort of inlining.
>
> But we can and want to inline strub-enabled functions into other
> strub-enabled functions. But we don't want to inline a wrapped function
> back into its wrapper, so we want to (early) inline functions before
> they're split, and we also want to inline wrappers after they're split
> if possible.
>
> So the assignment pass has to be before any inlining, and the
> wrapping/splitting (for internal strub) must be after some inlining but
> before the last attempt at inlining.
>
> > IIRC the simple IPA pass is a simple one because it wants to see
> > inlined bodies and "fixes" those up? Some toplevel comments
> > explaining both passes in the ipa-strub.cc pass would be nice to have.
>
> ACK, will do.
>
> > I guess I also asked before - did you try it with -flto?
>
> Yeah, I've tested it extensively with -flto during development. I've
> run the GCC testsuite with a patch equivalent to -fstrub=all enabled by
> default during development, and I still do so occasionally. I didn't
> before the ping, but prompted by you, I did again. Torture tests and
> specific lto tests don't seem to face any trouble. And there's no
> reason why they should. The spots in which the strub passes were
> introduced involved exploring where they fit best, and adding calls such
> as analyzing nodes. There are even commented-out vestigial calls of
> inline_analyze_function, from a time when the pass was inserted at a
> different spot and that call was required.
>
> > + /* Decide which of the wrapped function's parms we want to turn into
> > + references to the argument passed to the wrapper. In general,
> > we want to
> > + copy small arguments, and avoid copying large ones.
> > Variable-sized array
> > + lengths given by other arguments, as in 20020210-1.c, would lead to
> > + problems if passed by value, after resetting the original function and
> > + dropping the length computation; passing them by reference works.
> > + DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
> > + anyway, but performed at the caller. */
> > + indirect_parms_t indirect_nparms (3, false);
> > ...
>
> > IMHO it's a bad idea, at least initially, to mess with the ABI in a heuristical
> > way this way.
>
> Do you realize that this is only about the wrapped ABI, used exclusively
> by the wrapper, to avoid pointlessly copying large arguments twice? The
> wrapper already needs a custom ABI, because of the added watermark
> pointer, and va_list and whatnot when needed, so a little further
> customization to avoid a quite significant overhead seemed desirable.
I understood the purpose of this, but I also saw it's only ever needed for
non-strict operation and I think that if you care about security you'd never
want to operate in a way that you don't absolutely know the function
you call isn't going to scrub your secrets ...
But yes, I also wondered why you even run into re-gimplification issues.
If you make sure to never pass things as reference that are registers
in the callee context then replacing the PARM_DECL there with
a MEM_REF (new-PARM_DECL) should work without re-gimplification.
OK, existing MEM_REFs need folding to be canonical again, but that
should be it.
Note I didn't look into the re-gimplification code much, I just saw
it and wondered, thinking this would be the reason for it?
> > I see you need all sorts of "fixup", including re-gimplification
> > of stmts, etc., double-ugh.
>
> *nod*, I've considered going the nested-function way, enabling the
> wrapped function to access wrapper's variables directly, but (i) support
> for nested functions isn't available everywhere, and (ii) strub
> functions could already be nested functions, and the wrapped body would
> need access to both enclosing contexts, so adjustments would have to be
> made anyway.
>
> > Ideally IPA-SRA can already do parts of those
> > transforms which would mean ipa-param-manipulation has generic code
> > to encode them?
>
> You'd think so. I tried that, run into various issues, still have
> pending patches I submitted separately to address them, but... at some
> point I had to stop waiting for feedback and had make it work without
> that. I figured what I was doing wasn't a good fit and moved on.
>
> Now, it would be great if IPA could enable me to split the entire body
> of a function *while* adding custom arguments, such as the watermark,
> va_list, etc. It didn't look like it could or even wanted to, but maybe
> the presence of a useful feature like stack scrubbing could motivate the
> introduction of such infrastructure.
>
> > I realize you can't tail-call, but I wonder if some clever
> > machine-specific tricks would work, I guess it would need the wrapper
> > to be target generated of course.
>
> I'm not sure what you have in mind here, but one of the goals was to
> introduce stack scrubbing without machine-dependent code.
>
> We are considering an improvement for strub(internal) to do away with
> wrappers given machine-specific prologue/epilogue support, but that's
> not even in the roadmap, and it's not clear how that would interact with
> exceptions, which was a primary driver for the currently-proposed
> approaches.
Understood. But I didn't remember seeing that you do sth like wrapping
each "strubbed call" inside a try { call(); } finally { do-strub } to
ensure this.
Guess it was well hidden in the large patch ;)
> > As it's only for optimization, how much of the code would go away when
> > you avoid changing the parameters of the wrapped function?
>
> We can't avoid changing them entirely, and IIRC some of the
> infrastructure for regimplification was also used for va_list and
> apply_args handling, so it wouldn't save all that much.
Ah, var-args ... indeed for simple forwarding it shouldn't be too bad.
I wonder if this were a way to remove the restriction on function
splitting of var-args functions - there's a recent bugreport about that
(before any va_arg () has been called, of course).
> It is an
> important optimization, to avoid doubling the stack requirements for
> parameters with -fstrub=internal (because wrapper passes arguments on to
> wrapped body), and the optimization is already implemented, so it would
> be a pity to take it out, and you wouldn't even get rid of any
> significant amount of code.
>
> > Could one easily disable the optimization via a --param maybe?
>
> The param is not implemented, but guarding the loop you commented on by
> it would accomplish it. You probably won't want to bootstrap GCC with
> -fstrub=all along with it, though ;-)
>
> > There's still much commented code and FIXMEs in, a lot of cgraph
> > related code is used which I can't review very well.
>
> Now that you mentioned it, I realize I hadn't yet dropped some of the
> preprocessed-out bits when I posted v4. I did so afterwards. I was
> trying to avoid posting such a monster patch again, but I guess I will
> have to post at least another version :-(
>
> But yeah, there are some wishlist items that remain, and some bits that
> could probably go away.
>
> > I fear that -fstrub is going to be actually used by people - are you up
> > to the task fixing things?
>
> I, for one, would welcome that, and I am (professionally) on the hook to
> fix it, so I'd better be up to it ;-) Building it on top of
> infrastructure I'm closely familiar with, rather than e.g. on IPA, that
> I'm not so much, is a plus in this regard. That said, I've fixed bugs
> in GCC most everywhere, from front-ends to back-ends, so I'm pretty sure
> I've got it covered in terms of knowledge. As for time, if it gets too
> much interest (is there such a thing? :-) I might have trouble keeping
> up (there are only so many hours in the day), and it would likely be
> wise then for others to become familiar with it. I'd be happy to share
> knowledge, and I know I have support from my "employer" (in quotes
> because I'm not formally employed, I'm a consultant) to maintain the
> code I contribute to the community on its behalf, even having other work
> and non-work commitments. So, bring them on, I say ;-)
>
> > +void ATTRIBUTE_STRUB_CALLABLE
> > +__strub_enter (void **watermark)
> > +{
> > + *watermark = __builtin_frame_address (0);
>
> > in your experience, do these (or the inline version) work reliably
> > when optimizations like omitting the frame pointer or shrink-wrapping
> > happen from a security point of view?
>
> Yeah. We're talking about the frame address for the current function
> here, and the compiler knows what it is, even if it optimizes the heck
> out of the function. In the builtin expansion, it's the top of the
> stack instead, and the compiler also has to have a good grasp of where
> that is. Red zones are a small complication, but not really much
> trouble here: it's a watermark we're talking about, how high the stack
> may have gotten, so we know we have to scrub no further than that. If
> it goes too far (as it often does with red zones), we just scrub a
> little too much. What shouldn't happen is not going far enough, but
> since we rely on the stack frame address for __strub_update to update
> the watermark, and the caller can't really misrepresent its own stack
> use without risking the callee to corrupt it, this works really well.
> If strub_update gets builtin-expanded inline, it uses the adjusted (for
> red zone) stack pointer instead, after any internal stack allocation
> (prologue and alloca), but it won't necessarily capture non-accumulated
> outgoing args. The arguments passed to a callee are not regarded as
> part of the caller stack frame, so that should be fine. In order to
> cover them, one must have a strub-enabled caller and a strub(at-calls)
> callee.
>
> > You are adding symbols to libgcc but I don't see you amending
> > libgcc/libgcc-std.ver.in?
>
> That's a good catch, thanks.
>
> hardcfr symbols are missing too.
>
> Will fix.
>
> > Neither the documentation in extend.texi nor the one in invoke.texi
> > mentions the target audience of -fstrub
>
> ACK, good point, despite all the detail, that is too implicit. Will
> fix.
>
> > The patches mention the red zone, documenting the guarantees and
> > caveats would be nice to have. I think the documentation belongs to
> > the attribute documentation.
>
> It is kind of there, but since the details vary depending on the strub
> mode, they're given where the modes are detailed, rather than as if
> applying to all strub modes. (some of the modes are disabled and
> callable, that don't do any strubbing whatsoever)
>
> > I hope Honza can have a quick look over the IPA passes.
>
> Likewise. I shall wait for further feedback before posting a huge v5,
> but I'll be happy to refresh the users/aoliva/heads/strub branch in the
> git repo as I adjust the patch if that helps. Currently the patch is in
> users/aoliva/heads/testme.
>
> > a better way than taking what is percieved as a huge ugly part
> > of the patch.
>
> ISTM you're misperceiving the amount of code involved in that
> optimization. There is a significant amount of wrapper/wrapped
> parameter manipulation that is *not* involved with the optimization, and
> that was already there before the optimization was implemented. The
> optimization was a tiny addition over it.
I see.
Thanks,
Richard.
> Thanks again,
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-23 12:05 ` Richard Biener
@ 2023-11-29 8:53 ` Alexandre Oliva
2023-11-29 12:48 ` Richard Biener
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-11-29 8:53 UTC (permalink / raw)
To: Richard Biener
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Nov 23, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
> Conceptually it shouldn't be much different from what IPA-SRA does
> which is cloning a function but with different arguments, the function
> signature transform described in terms of ipa-param-manipulation bits.
> I've talked with Martin and at least there's currently no
> by-value-to-by-reference
> "transform", but IPA-SRA can pass two registers instead of one aggregate
> for example. There's IPA_PARAM_OP_NEW already to add a new param.
> In principle the whole function rewriting (apart of recovering
> from inlining) should be doable within this framework.
I agree, but my attempts to do so have been unfruitful, and hit various
very obscure issues that made it unworkable. Maybe someone smarter than
I am, or with more time than I had, can make the conversion. The uses
of IPA_PARAM_OP_NEW for the cloning are there, and the more conservative
choices I made got it to work reliably, unlike the more adventurous
alternatives I tried. One of the obscure issues I recall hitting was
this one. I can probably still locate the early strub patch that hit
the described issue back then, if there's interest.
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575044.html
>> The
>> wrapper already needs a custom ABI, because of the added watermark
>> pointer, and va_list and whatnot when needed, so a little further
>> customization to avoid a quite significant overhead seemed desirable.
> I understood the purpose of this, but I also saw it's only ever needed for
> non-strict operation
Erhm... I suppose you're not talking about -fstrub=strict, because I
can't see how this relates with the by-reference argument passing from
wrapper to wrapped in internal strubbing.
> and I think that if you care about security you'd never
> want to operate in a way that you don't absolutely know the function
> you call isn't going to scrub your secrets ...
The ABI between wrapper and wrapped function splitting in internal strub
doesn't change this.
> But yes, I also wondered why you even run into re-gimplification issues.
Because &arg_#(D)[n_#] is good gimple, but &(*byref_arg_#(D))[n_#] isn't.
Maybe instead of going through regimplify, we could explicitly create an
SSA name for the indirection load, so that the purpose is made more
explicit.
> replacing the PARM_DECL there with a MEM_REF (new-PARM_DECL) should
> work without re-gimplification.
FWIW, I thought so as well ;-)
> I didn't remember seeing that you do sth like wrapping
> each "strubbed call" inside a try { call(); } finally { do-strub } to
> ensure this.
> Guess it was well hidden in the large patch ;)
Indeed, gsi_insert_finally_seq_after_call is where this is taken care of.
>> > As it's only for optimization, how much of the code would go away when
>> > you avoid changing the parameters of the wrapped function?
>>
>> We can't avoid changing them entirely, and IIRC some of the
>> infrastructure for regimplification was also used for va_list and
>> apply_args handling, so it wouldn't save all that much.
> Ah, var-args ... indeed for simple forwarding it shouldn't be too bad.
> I wonder if this were a way to remove the restriction on function
> splitting of var-args functions - there's a recent bugreport about that
> (before any va_arg () has been called, of course).
If running va_start unconditionally in varargs functions is generally
acceptable, then the method I've used for wrapping varargs functions
should work generally, yeah. The trick was to turn:
foo (...)
{
va_list ap;
...
va_start (&ap, <ignored>);
...
}
into
wrapped_foo (va_list &wrap)
{
va_list ap;
...
va_copy (ap, wrap);
...
}
foo (...)
{
va_list wrap;
va_start (wrap, <also ignored>);
wrapped_foo (wrap);
va_end (wrap);
}
Here's the opening comment I added to ipa-strub.cc:
/* This file introduces two passes that, together, implement
machine-independent stack scrubbing, strub for short. It arranges
for stack frames that have strub enabled to be zeroed-out after
relinquishing control to a caller, whether by returning or by
propagating an exception. This admittedly unusual design decision
was driven by exception support (one needs a stack frame to be
active to propagate exceptions out of it), and it enabled an
implementation that is entirely machine-independent (no custom
epilogue code is required).
Strub modes can be selected for stack frames by attaching attribute
strub to functions or to variables (to their types, actually).
Different strub modes, with different implementation details, are
available, and they can be selected by an argument to the strub
attribute. When enabled by strub-enabled variables, whether by
accessing (as in reading from) statically-allocated ones, or by
introducing (as in declaring) automatically-allocated ones, a
suitable mode is selected automatically.
At-calls mode modifies the interface of a function, adding a stack
watermark argument, that callers use to clean up the stack frame of
the called function. Because of the interface change, it can only
be used when explicitly selected, or when a function is internal to
a translation unit. Strub-at-calls function types are distinct
from their original types (they're not modified in-place), and they
are not interchangeable with other function types.
Internal mode, in turn, does not modify the type or the interface
of a function. It is currently implemented by turning the function
into a wrapper, moving the function body to a separate wrapped
function, and scrubbing the wrapped body's stack in the wrapper.
Internal-strub function types are mostly interface-compatible with
other strub modes, namely callable (from strub functions, though
not strub-enabled) and disabled (not callable from strub
functions).
Always_inline functions can be strub functions, but they can only
be called from other strub functions, because strub functions must
never be inlined into non-strub functions. Internal and at-calls
modes are indistinguishable when it comes to always_inline
functions: they will necessarily be inlined into another strub
function, and will thus be integrated into the caller's stack
frame, whatever the mode. (Contrast with non-always_inline strub
functions: an at-calls function can be called from other strub
functions, ensuring no discontinuity in stack erasing, whereas an
internal-strub function can only be called from other strub
functions if it happens to be inlined, or if -fstrub=relaxed mode
is in effect (that's the default). In -fstrub=strict mode,
internal-strub functions are not callable from strub functions,
because the wrapper itself is not strubbed.
The implementation involves two simple-IPA passes. The earliest
one, strub-mode, assigns strub modes to functions. It needs to run
before any inlining, so that we can prevent inlining of strub
functions into non-strub functions. It notes explicit strub mode
requests, enables strub in response to strub variables and testing
options, and flags unsatisfiable requests.
Three possibilities of unsatisfiable requests come to mind: (a)
when a strub mode is explicitly selected, but the function uses
features that make it ineligible for that mode (e.g. at-calls rules
out calling __builtin_apply_args, because of the interface changes,
and internal mode rules out noclone or otherwise non-versionable
functions, non-default varargs, non-local or forced labels, and
functions with far too many arguments); (b) when some strub mode
must be enabled because of a strub variable, but the function is
not eligible or not viable for any mode; and (c) when
-fstrub=strict is enabled, and calls are found in strub functions
to functions that are not callable from strub contexts.
compute_strub_mode implements (a) and (b), and verify_strub
implements (c).
The second IPA pass modifies interfaces of at-calls-strub functions
and types, introduces strub calls in and around them. and splits
internal-strub functions. It is placed after early inlining, so
that even internal-strub functions get a chance of being inlined
into other strub functions, but before non-early inlining, so that
internal-strub wrapper functions still get a chance of inlining
after splitting.
Wrappers avoid duplicating the copying of large arguments again by
passing them by reference to the wrapped bodies. This involves
occasional SSA rewriting of address computations, because of the
additional indirection. Besides these changes, and the
introduction of the stack watermark parameter, wrappers and wrapped
functions cooperate to handle variable argument lists (performing
va_start in the wrapper, passing the list as an argument, and
replacing va_start calls in the wrapped body with va_copy), and
__builtin_apply_args (also called in the wrapper and passed to the
wrapped body as an argument).
Strub bodies (both internal-mode wrapped bodies, and at-calls
functions) always start by adjusting the watermark parameter, by
calling __builtin___strub_update. The compiler inserts them in the
main strub pass. Allocations of additional stack space for the
frame (__builtin_alloca) are also followed by watermark updates.
Stack space temporarily allocated to pass arguments to other
functions, released right after the call, is not regarded as part
of the frame. Around calls to them, i.e., in internal-mode
wrappers and at-calls callers (even calls through pointers), calls
to __builtin___strub_enter and __builtin___strub_leave are
inserted, the latter as a __finally block, so that it runs at
regular and exceptional exit paths. strub_enter only initializes
the stack watermark, and strub_leave is where the scrubbing takes
place, overwriting with zeros the stack space from the top of the
stack to the watermark.
These calls can be optimized in various cases. In
pass_ipa_strub::adjust_at_calls_call, for example, we enable
tail-calling and other optimized calls from one strub body to
another by passing on the watermark parameter. The builtins
themselves may undergo inline substitution during expansion,
dependign on optimization levels. This involves dealing with stack
red zones (when the builtins are called out-of-line, the red zone
cannot be used) and other ugly details related with inlining strub
bodies into other strub bodies (see expand_builtin_strub_update).
expand_builtin_strub_leave may even perform partial inline
substitution. */
The type attribute description now starts like this:
@cindex @code{strub} type attribute
@item strub
This attribute defines stack-scrubbing properties of functions and
variables, so that functions that access sensitive data can have their
stack frames zeroed-out upon returning or propagating exceptions. This
may be enabled explicitly, by selecting certain @code{strub} modes for
specific functions, or implicitly, by means of @code{strub} variables.
And I've fixed the symbol versioning for strub and hardcfr functions.
I've just pushed the base strub patch and the recent incremental changes
(and some commits used for testing) to refs/users/aoliva/heads/strub.
Here are changes.html entries for this and for the other newly-added
features:
new AdaCore-contributed hardening features in gcc 13 and 14
Mention hardening of conditionals (added in gcc 13), control flow
redundancy, hardened booleans, and stack scrubbing.
Also cover forced inlining of string operations while at that.
---
htdocs/gcc-13/changes.html | 6 ++++++
htdocs/gcc-14/changes.html | 29 +++++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/htdocs/gcc-13/changes.html b/htdocs/gcc-13/changes.html
index 8ef3d63952daf..c1dea18caf59b 100644
--- a/htdocs/gcc-13/changes.html
+++ b/htdocs/gcc-13/changes.html
@@ -168,6 +168,12 @@ You may also want to check out our
been added, see also
<a href="https://gcc.gnu.org/onlinedocs/gcc/Freestanding-Environments.html">Profiling and Test Coverage in Freestanding Environments</a>.
</li>
+ <li>
+ New options <code>-fharden-compares</code>
+ and <code>-fharden-conditional-branches</code> to verify compares
+ and conditional branches, to detect some power-deprivation
+ hardware attacks, using reversed conditions.
+ </li>
</ul>
diff --git a/htdocs/gcc-14/changes.html b/htdocs/gcc-14/changes.html
index 2088ee91a34e1..cb92f8d8095c3 100644
--- a/htdocs/gcc-14/changes.html
+++ b/htdocs/gcc-14/changes.html
@@ -109,6 +109,35 @@ a work-in-progress.</p>
of hardening flags. The options it enables can be displayed using the
<code>--help=hardened</code> option.
</li>
+ <li>
+ New option <code>-fharden-control-flow-redundancy</code>, to
+ verify, at the end of functions, that the visited basic blocks
+ correspond to a legitimate execution path, so as to detect and
+ prevent attacks that transfer control into the middle of
+ functions.
+ </li>
+ <li>
+ New type attribute <code>hardbool</code>, for C and Ada. Hardened
+ booleans take user-specified representations for <code>true</code>
+ and <code>false</code>, presumably with higher hamming distance
+ than standard booleans, and get verified at every use, detecting
+ memory corruption and some malicious attacks.
+ </li>
+ <li>
+ New type attribute <code>strub</code> to control stack scrubbing
+ properties of functions and variables. The stack frame used by
+ functions marked with the attribute gets zeroed-out upon returning
+ or exception escaping. Scalar variables marked with the attribute
+ cause functions contaning or accessing them to get stack scrubbing
+ enabled implicitly.
+ </li>
+ <li>
+ New option <code>-finline-stringops</code>, to force inline
+ expansion of <code>memcmp</code>, <code>memcpy</code>,
+ <code>memmove</code> and <code>memset</code>, even when that is
+ not an optimization, to avoid relying on library
+ implementations.
+ </li>
</ul>
<!-- .................................................................. -->
<h2 id="languages">New Languages and Language specific improvements</h2>
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-29 8:53 ` Alexandre Oliva
@ 2023-11-29 12:48 ` Richard Biener
2023-11-30 4:13 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Richard Biener @ 2023-11-29 12:48 UTC (permalink / raw)
To: Alexandre Oliva
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Wed, Nov 29, 2023 at 9:53 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Nov 23, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
>
> > Conceptually it shouldn't be much different from what IPA-SRA does
> > which is cloning a function but with different arguments, the function
> > signature transform described in terms of ipa-param-manipulation bits.
> > I've talked with Martin and at least there's currently no
> > by-value-to-by-reference
> > "transform", but IPA-SRA can pass two registers instead of one aggregate
> > for example. There's IPA_PARAM_OP_NEW already to add a new param.
> > In principle the whole function rewriting (apart of recovering
> > from inlining) should be doable within this framework.
>
> I agree, but my attempts to do so have been unfruitful, and hit various
> very obscure issues that made it unworkable. Maybe someone smarter than
> I am, or with more time than I had, can make the conversion. The uses
> of IPA_PARAM_OP_NEW for the cloning are there, and the more conservative
> choices I made got it to work reliably, unlike the more adventurous
> alternatives I tried. One of the obscure issues I recall hitting was
> this one. I can probably still locate the early strub patch that hit
> the described issue back then, if there's interest.
> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575044.html
>
> >> The
> >> wrapper already needs a custom ABI, because of the added watermark
> >> pointer, and va_list and whatnot when needed, so a little further
> >> customization to avoid a quite significant overhead seemed desirable.
>
> > I understood the purpose of this, but I also saw it's only ever needed for
> > non-strict operation
>
> Erhm... I suppose you're not talking about -fstrub=strict, because I
> can't see how this relates with the by-reference argument passing from
> wrapper to wrapped in internal strubbing.
>
> > and I think that if you care about security you'd never
> > want to operate in a way that you don't absolutely know the function
> > you call isn't going to scrub your secrets ...
>
> The ABI between wrapper and wrapped function splitting in internal strub
> doesn't change this.
>
> > But yes, I also wondered why you even run into re-gimplification issues.
>
> Because &arg_#(D)[n_#] is good gimple, but &(*byref_arg_#(D))[n_#] isn't.
'arg_#(D)' looks like a SSA name, and no, taking the address doesn't work,
so I assume it was &MEM[arg_(D)][n_#] which is indeed OK. But you
shouldn't need to change a pointer argument to be passed by reference,
do you? As said, you want to restrict by-reference passing to arguments
that are !is_gimple_reg_type (). Everywhere where a plain PARM_DECL
was valid a *ptr indirection is as well.
> Maybe instead of going through regimplify, we could explicitly create an
> SSA name for the indirection load, so that the purpose is made more
> explicit.
>
> > replacing the PARM_DECL there with a MEM_REF (new-PARM_DECL) should
> > work without re-gimplification.
>
> FWIW, I thought so as well ;-)
>
> > I didn't remember seeing that you do sth like wrapping
> > each "strubbed call" inside a try { call(); } finally { do-strub } to
> > ensure this.
> > Guess it was well hidden in the large patch ;)
>
> Indeed, gsi_insert_finally_seq_after_call is where this is taken care of.
>
> >> > As it's only for optimization, how much of the code would go away when
> >> > you avoid changing the parameters of the wrapped function?
> >>
> >> We can't avoid changing them entirely, and IIRC some of the
> >> infrastructure for regimplification was also used for va_list and
> >> apply_args handling, so it wouldn't save all that much.
>
> > Ah, var-args ... indeed for simple forwarding it shouldn't be too bad.
> > I wonder if this were a way to remove the restriction on function
> > splitting of var-args functions - there's a recent bugreport about that
> > (before any va_arg () has been called, of course).
>
> If running va_start unconditionally in varargs functions is generally
> acceptable, then the method I've used for wrapping varargs functions
> should work generally, yeah. The trick was to turn:
>
> foo (...)
> {
> va_list ap;
>
> ...
> va_start (&ap, <ignored>);
> ...
> }
>
> into
>
> wrapped_foo (va_list &wrap)
> {
> va_list ap;
>
> ...
> va_copy (ap, wrap);
> ...
> }
>
> foo (...)
> {
> va_list wrap;
>
> va_start (wrap, <also ignored>);
> wrapped_foo (wrap);
> va_end (wrap);
> }
Ah, nice trick indeed. I think that should work, it might not
be optimal (I don't think we will optimize the va_copy).
>
> Here's the opening comment I added to ipa-strub.cc:
>
> /* This file introduces two passes that, together, implement
> machine-independent stack scrubbing, strub for short. It arranges
> for stack frames that have strub enabled to be zeroed-out after
> relinquishing control to a caller, whether by returning or by
> propagating an exception. This admittedly unusual design decision
> was driven by exception support (one needs a stack frame to be
> active to propagate exceptions out of it), and it enabled an
> implementation that is entirely machine-independent (no custom
> epilogue code is required).
>
> Strub modes can be selected for stack frames by attaching attribute
> strub to functions or to variables (to their types, actually).
> Different strub modes, with different implementation details, are
> available, and they can be selected by an argument to the strub
> attribute. When enabled by strub-enabled variables, whether by
> accessing (as in reading from) statically-allocated ones, or by
> introducing (as in declaring) automatically-allocated ones, a
> suitable mode is selected automatically.
>
> At-calls mode modifies the interface of a function, adding a stack
> watermark argument, that callers use to clean up the stack frame of
> the called function. Because of the interface change, it can only
> be used when explicitly selected, or when a function is internal to
> a translation unit. Strub-at-calls function types are distinct
> from their original types (they're not modified in-place), and they
> are not interchangeable with other function types.
>
> Internal mode, in turn, does not modify the type or the interface
> of a function. It is currently implemented by turning the function
> into a wrapper, moving the function body to a separate wrapped
> function, and scrubbing the wrapped body's stack in the wrapper.
> Internal-strub function types are mostly interface-compatible with
> other strub modes, namely callable (from strub functions, though
> not strub-enabled) and disabled (not callable from strub
> functions).
>
> Always_inline functions can be strub functions, but they can only
> be called from other strub functions, because strub functions must
> never be inlined into non-strub functions. Internal and at-calls
> modes are indistinguishable when it comes to always_inline
> functions: they will necessarily be inlined into another strub
> function, and will thus be integrated into the caller's stack
> frame, whatever the mode. (Contrast with non-always_inline strub
> functions: an at-calls function can be called from other strub
> functions, ensuring no discontinuity in stack erasing, whereas an
> internal-strub function can only be called from other strub
> functions if it happens to be inlined, or if -fstrub=relaxed mode
> is in effect (that's the default). In -fstrub=strict mode,
> internal-strub functions are not callable from strub functions,
> because the wrapper itself is not strubbed.
>
> The implementation involves two simple-IPA passes. The earliest
> one, strub-mode, assigns strub modes to functions. It needs to run
> before any inlining, so that we can prevent inlining of strub
> functions into non-strub functions. It notes explicit strub mode
> requests, enables strub in response to strub variables and testing
> options, and flags unsatisfiable requests.
>
> Three possibilities of unsatisfiable requests come to mind: (a)
> when a strub mode is explicitly selected, but the function uses
> features that make it ineligible for that mode (e.g. at-calls rules
> out calling __builtin_apply_args, because of the interface changes,
> and internal mode rules out noclone or otherwise non-versionable
> functions, non-default varargs, non-local or forced labels, and
> functions with far too many arguments); (b) when some strub mode
> must be enabled because of a strub variable, but the function is
> not eligible or not viable for any mode; and (c) when
> -fstrub=strict is enabled, and calls are found in strub functions
> to functions that are not callable from strub contexts.
> compute_strub_mode implements (a) and (b), and verify_strub
> implements (c).
>
> The second IPA pass modifies interfaces of at-calls-strub functions
> and types, introduces strub calls in and around them. and splits
> internal-strub functions. It is placed after early inlining, so
> that even internal-strub functions get a chance of being inlined
> into other strub functions, but before non-early inlining, so that
> internal-strub wrapper functions still get a chance of inlining
> after splitting.
>
> Wrappers avoid duplicating the copying of large arguments again by
> passing them by reference to the wrapped bodies. This involves
> occasional SSA rewriting of address computations, because of the
> additional indirection. Besides these changes, and the
> introduction of the stack watermark parameter, wrappers and wrapped
> functions cooperate to handle variable argument lists (performing
> va_start in the wrapper, passing the list as an argument, and
> replacing va_start calls in the wrapped body with va_copy), and
> __builtin_apply_args (also called in the wrapper and passed to the
> wrapped body as an argument).
>
> Strub bodies (both internal-mode wrapped bodies, and at-calls
> functions) always start by adjusting the watermark parameter, by
> calling __builtin___strub_update. The compiler inserts them in the
> main strub pass. Allocations of additional stack space for the
> frame (__builtin_alloca) are also followed by watermark updates.
> Stack space temporarily allocated to pass arguments to other
> functions, released right after the call, is not regarded as part
> of the frame. Around calls to them, i.e., in internal-mode
> wrappers and at-calls callers (even calls through pointers), calls
> to __builtin___strub_enter and __builtin___strub_leave are
> inserted, the latter as a __finally block, so that it runs at
> regular and exceptional exit paths. strub_enter only initializes
> the stack watermark, and strub_leave is where the scrubbing takes
> place, overwriting with zeros the stack space from the top of the
> stack to the watermark.
>
> These calls can be optimized in various cases. In
> pass_ipa_strub::adjust_at_calls_call, for example, we enable
> tail-calling and other optimized calls from one strub body to
> another by passing on the watermark parameter. The builtins
> themselves may undergo inline substitution during expansion,
> dependign on optimization levels. This involves dealing with stack
> red zones (when the builtins are called out-of-line, the red zone
> cannot be used) and other ugly details related with inlining strub
> bodies into other strub bodies (see expand_builtin_strub_update).
> expand_builtin_strub_leave may even perform partial inline
> substitution. */
Thanks.
> The type attribute description now starts like this:
>
> @cindex @code{strub} type attribute
> @item strub
> This attribute defines stack-scrubbing properties of functions and
> variables, so that functions that access sensitive data can have their
> stack frames zeroed-out upon returning or propagating exceptions. This
> may be enabled explicitly, by selecting certain @code{strub} modes for
> specific functions, or implicitly, by means of @code{strub} variables.
>
> And I've fixed the symbol versioning for strub and hardcfr functions.
>
> I've just pushed the base strub patch and the recent incremental changes
> (and some commits used for testing) to refs/users/aoliva/heads/strub.
>
>
> Here are changes.html entries for this and for the other newly-added
> features:
>
> new AdaCore-contributed hardening features in gcc 13 and 14
>
> Mention hardening of conditionals (added in gcc 13), control flow
> redundancy, hardened booleans, and stack scrubbing.
>
> Also cover forced inlining of string operations while at that.
> ---
> htdocs/gcc-13/changes.html | 6 ++++++
> htdocs/gcc-14/changes.html | 29 +++++++++++++++++++++++++++++
> 2 files changed, 35 insertions(+)
>
> diff --git a/htdocs/gcc-13/changes.html b/htdocs/gcc-13/changes.html
> index 8ef3d63952daf..c1dea18caf59b 100644
> --- a/htdocs/gcc-13/changes.html
> +++ b/htdocs/gcc-13/changes.html
> @@ -168,6 +168,12 @@ You may also want to check out our
> been added, see also
> <a href="https://gcc.gnu.org/onlinedocs/gcc/Freestanding-Environments.html">Profiling and Test Coverage in Freestanding Environments</a>.
> </li>
> + <li>
> + New options <code>-fharden-compares</code>
> + and <code>-fharden-conditional-branches</code> to verify compares
> + and conditional branches, to detect some power-deprivation
> + hardware attacks, using reversed conditions.
> + </li>
> </ul>
>
>
> diff --git a/htdocs/gcc-14/changes.html b/htdocs/gcc-14/changes.html
> index 2088ee91a34e1..cb92f8d8095c3 100644
> --- a/htdocs/gcc-14/changes.html
> +++ b/htdocs/gcc-14/changes.html
> @@ -109,6 +109,35 @@ a work-in-progress.</p>
> of hardening flags. The options it enables can be displayed using the
> <code>--help=hardened</code> option.
> </li>
> + <li>
> + New option <code>-fharden-control-flow-redundancy</code>, to
> + verify, at the end of functions, that the visited basic blocks
> + correspond to a legitimate execution path, so as to detect and
> + prevent attacks that transfer control into the middle of
> + functions.
> + </li>
> + <li>
> + New type attribute <code>hardbool</code>, for C and Ada. Hardened
> + booleans take user-specified representations for <code>true</code>
> + and <code>false</code>, presumably with higher hamming distance
> + than standard booleans, and get verified at every use, detecting
> + memory corruption and some malicious attacks.
> + </li>
> + <li>
> + New type attribute <code>strub</code> to control stack scrubbing
> + properties of functions and variables. The stack frame used by
> + functions marked with the attribute gets zeroed-out upon returning
> + or exception escaping. Scalar variables marked with the attribute
> + cause functions contaning or accessing them to get stack scrubbing
> + enabled implicitly.
> + </li>
> + <li>
> + New option <code>-finline-stringops</code>, to force inline
> + expansion of <code>memcmp</code>, <code>memcpy</code>,
> + <code>memmove</code> and <code>memset</code>, even when that is
> + not an optimization, to avoid relying on library
> + implementations.
> + </li>
> </ul>
> <!-- .................................................................. -->
> <h2 id="languages">New Languages and Language specific improvements</h2>
LGTM.
Can you check on the pass-by-reference thing again please?
Let's see if Honza or Martin have any comments on the IPA bits, I just
mentioned what I think should be doable ...
Thanks,
Richard.
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-29 12:48 ` Richard Biener
@ 2023-11-30 4:13 ` Alexandre Oliva
2023-11-30 12:00 ` Richard Biener
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-11-30 4:13 UTC (permalink / raw)
To: Richard Biener
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Nov 29, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
>> Because &arg_#(D)[n_#] is good gimple, but &(*byref_arg_#(D))[n_#] isn't.
> 'arg_#(D)' looks like a SSA name, and no, taking the address doesn't work,
> so I assume it was &MEM[arg_(D)][n_#] which is indeed OK.
Yeah.
> But you shouldn't need to change a pointer argument to be passed by
> reference, do you?
True, my attempt to simplify the example moved it past the breaking point.
IIRC the actual situations I hit involved computing address of members
of compound objects, such as struct members, even array elements
thereof. They became problematic after replacing the object with a
dereference in gimple stmts. The (effectively) offsetting operation is
well-formed gimple, but IIRC adding dereferencing to it made it
malformed gimple. I don't immediately see why this should be the case,
since it's still offsetting, so perhaps I misremember.
> As said, you want to restrict by-reference passing to arguments
> that are !is_gimple_reg_type ()
*nod*, it was already there:
if (!(0 /* DECL_BY_REFERENCE (narg) */
|| is_gimple_reg_type (TREE_TYPE (nparm))
...
{
indirect_nparms.add (nparm);
>> Here are changes.html entries for this and for the other newly-added
>> features:
> LGTM.
Was that an ok to install, once the relevant pieces are in?
> Can you check on the pass-by-reference thing again please?
Sure. I'll get back to you shortly.
If argument indirection becomes the only blocking issue, I'd be happy to
disable it, or even split out the patch that introduces it, so that the
bulk of the feature can go in while we sort out these details.
Disabling it is as simple as:
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b885..90770202fb851 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -2831,6 +2831,7 @@ pass_ipa_strub::execute (function *)
parm = DECL_CHAIN (parm),
nparm = DECL_CHAIN (nparm),
nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
+ if (true) ; else // ??? Disable parm indirection for now.
if (!(0 /* DECL_BY_REFERENCE (narg) */
|| is_gimple_reg_type (TREE_TYPE (nparm))
|| VECTOR_TYPE_P (TREE_TYPE (nparm))
> Let's see if Honza or Martin have any comments on the IPA bits, I just
> mentioned what I think should be doable ...
I'm curious as to what you're hoping for. I mean, I am using
create_version_clone_with_body, adding the new params and copying the
preexisting ones, and modifying some argument types for indirection
after cloning. The problems I faced were as I tried to replace params
with their indirected versions. According to my notes and my
recollection, that's where I hit most of the trouble. But what would
this really buy us? Do you envision a possibility of actually splitting
out the original function body, so that IPA takes care of the whole
wrapping? AFAICT that would require a lot more infrastructure to deal
with new and modified parameters, though the details of what I learned
about this API back then, and that made it clear I wouldn't be able to
use it, seem to have faded away from my memory.
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing
2023-11-30 4:13 ` Alexandre Oliva
@ 2023-11-30 12:00 ` Richard Biener
2023-12-02 17:56 ` [PATCH v5] " Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Richard Biener @ 2023-11-30 12:00 UTC (permalink / raw)
To: Alexandre Oliva
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Thu, Nov 30, 2023 at 5:13 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Nov 29, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
>
> >> Because &arg_#(D)[n_#] is good gimple, but &(*byref_arg_#(D))[n_#] isn't.
>
> > 'arg_#(D)' looks like a SSA name, and no, taking the address doesn't work,
> > so I assume it was &MEM[arg_(D)][n_#] which is indeed OK.
>
> Yeah.
>
> > But you shouldn't need to change a pointer argument to be passed by
> > reference, do you?
>
> True, my attempt to simplify the example moved it past the breaking point.
>
> IIRC the actual situations I hit involved computing address of members
> of compound objects, such as struct members, even array elements
> thereof. They became problematic after replacing the object with a
> dereference in gimple stmts. The (effectively) offsetting operation is
> well-formed gimple, but IIRC adding dereferencing to it made it
> malformed gimple. I don't immediately see why this should be the case,
> since it's still offsetting, so perhaps I misremember.
>
> > As said, you want to restrict by-reference passing to arguments
> > that are !is_gimple_reg_type ()
>
> *nod*, it was already there:
>
> if (!(0 /* DECL_BY_REFERENCE (narg) */
> || is_gimple_reg_type (TREE_TYPE (nparm))
> ...
> {
> indirect_nparms.add (nparm);
>
> >> Here are changes.html entries for this and for the other newly-added
> >> features:
>
> > LGTM.
>
> Was that an ok to install, once the relevant pieces are in?
See below.
> > Can you check on the pass-by-reference thing again please?
>
> Sure. I'll get back to you shortly.
>
> If argument indirection becomes the only blocking issue, I'd be happy to
> disable it, or even split out the patch that introduces it, so that the
> bulk of the feature can go in while we sort out these details.
> Disabling it is as simple as:
>
> diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
> index 293bec132b885..90770202fb851 100644
> --- a/gcc/ipa-strub.cc
> +++ b/gcc/ipa-strub.cc
> @@ -2831,6 +2831,7 @@ pass_ipa_strub::execute (function *)
> parm = DECL_CHAIN (parm),
> nparm = DECL_CHAIN (nparm),
> nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
> + if (true) ; else // ??? Disable parm indirection for now.
> if (!(0 /* DECL_BY_REFERENCE (narg) */
> || is_gimple_reg_type (TREE_TYPE (nparm))
> || VECTOR_TYPE_P (TREE_TYPE (nparm))
>
>
> > Let's see if Honza or Martin have any comments on the IPA bits, I just
> > mentioned what I think should be doable ...
>
> I'm curious as to what you're hoping for. I mean, I am using
> create_version_clone_with_body, adding the new params and copying the
> preexisting ones, and modifying some argument types for indirection
> after cloning. The problems I faced were as I tried to replace params
> with their indirected versions. According to my notes and my
> recollection, that's where I hit most of the trouble. But what would
> this really buy us? Do you envision a possibility of actually splitting
> out the original function body, so that IPA takes care of the whole
> wrapping? AFAICT that would require a lot more infrastructure to deal
> with new and modified parameters, though the details of what I learned
> about this API back then, and that made it clear I wouldn't be able to
> use it, seem to have faded away from my memory.
In the end I was hoping for general comments on the cgraph usage
and for the specifics indeed being able to use IPA mechanisms
to perform the stmt re-writing (and re-gimplification) for the value to
by-reference replacement. The core copy_body mechanism
might support it by simply registering *new_param as replacement
for 'old_param' in the copy_body_data decl_map.
Iff the IPA folks (Honza or Martin) don't have any further comments
the patch is OK to install by next Monday.
Thanks,
Richard.
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH v5] Introduce strub: machine-independent stack scrubbing
2023-11-30 12:00 ` Richard Biener
@ 2023-12-02 17:56 ` Alexandre Oliva
2023-12-06 8:36 ` Causes to nvptx bootstrap fail: " Tobias Burnus
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-12-02 17:56 UTC (permalink / raw)
To: Richard Biener
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
On Nov 30, 2023, Richard Biener <richard.guenther@gmail.com> wrote:
> On Thu, Nov 30, 2023 at 5:13 AM Alexandre Oliva <oliva@adacore.com> wrote:
>> >> Here are changes.html entries for this and for the other newly-added
>> >> features:
>>
>> > LGTM.
>>
>> Was that an ok to install, once the relevant pieces are in?
> See below.
FWIW, I meant specifically about the web site changes.html patch in the
question above.
> In the end I was hoping for general comments on the cgraph usage
> and for the specifics indeed being able to use IPA mechanisms
> to perform the stmt re-writing (and re-gimplification) for the value to
> by-reference replacement. The core copy_body mechanism
> might support it by simply registering *new_param as replacement
> for 'old_param' in the copy_body_data decl_map.
I see. That's indeed a good direction for evolution, that I'd like us
to take, and having the base code in with some more manageable way to
experiment smaller changes will make this transition significantly
easier IMHO. But that kind of infrastructure change would also likely
be stage1 material.
> Iff the IPA folks (Honza or Martin) don't have any further comments
> the patch is OK to install by next Monday.
Thanks, here's the consolidated patch that I hope to install by Monday.
Introduce strub: machine-independent stack scrubbing
This patch adds the strub attribute for function and variable types,
command-line options, passes and adjustments to implement it,
documentation, and tests.
Stack scrubbing is implemented in a machine-independent way: functions
with strub enabled are modified so that they take an extra stack
watermark argument, that they update with their stack use, and the
caller can then zero it out once it regains control, whether by return
or exception. There are two ways to go about it: at-calls, that
modifies the visible interface (signature) of the function, and
internal, in which the body is moved to a clone, the clone undergoes
the interface change, and the function becomes a wrapper, preserving
its original interface, that calls the clone and then clears the stack
used by it.
Variables can also be annotated with the strub attribute, so that
functions that read from them get stack scrubbing enabled implicitly,
whether at-calls, for functions only usable within a translation unit,
or internal, for functions whose interfaces must not be modified.
There is a strict mode, in which functions that have their stack
scrubbed can only call other functions with stack-scrubbing
interfaces, or those explicitly marked as callable from strub
contexts, so that an entire call chain gets scrubbing, at once or
piecemeal depending on optimization levels. In the default mode,
relaxed, this requirement is not enforced by the compiler.
The implementation adds two IPA passes, one that assigns strub modes
early on, another that modifies interfaces and adds calls to the
builtins that jointly implement stack scrubbing. Another builtin,
that obtains the stack pointer, is added for use in the implementation
of the builtins, whether expanded inline or called in libgcc.
There are new command-line options to change operation modes and to
force the feature disabled; it is enabled by default, but it has no
effect and is implicitly disabled if the strub attribute is never
used. There are also options meant to use for testing the feature,
enabling different strubbing modes for all (viable) functions.
for gcc/ChangeLog
* Makefile.in (OBJS): Add ipa-strub.o.
(GTFILES): Add ipa-strub.cc.
* builtins.def (BUILT_IN_STACK_ADDRESS): New.
(BUILT_IN___STRUB_ENTER): New.
(BUILT_IN___STRUB_UPDATE): New.
(BUILT_IN___STRUB_LEAVE): New.
* builtins.cc: Include ipa-strub.h.
(STACK_STOPS, STACK_UNSIGNED): Define.
(expand_builtin_stack_address): New.
(expand_builtin_strub_enter): New.
(expand_builtin_strub_update): New.
(expand_builtin_strub_leave): New.
(expand_builtin): Call them.
* common.opt (fstrub=*): New options.
* doc/extend.texi (strub): New type attribute.
(__builtin_stack_address): New function.
(Stack Scrubbing): New section.
* doc/invoke.texi (-fstrub=*): New options.
(-fdump-ipa-*): New passes.
* gengtype-lex.l: Ignore multi-line pp-directives.
* ipa-inline.cc: Include ipa-strub.h.
(can_inline_edge_p): Test strub_inlinable_to_p.
* ipa-split.cc: Include ipa-strub.h.
(execute_split_functions): Test strub_splittable_p.
* ipa-strub.cc, ipa-strub.h: New.
* passes.def: Add strub_mode and strub passes.
* tree-cfg.cc (gimple_verify_flow_info): Note on debug stmts.
* tree-pass.h (make_pass_ipa_strub_mode): Declare.
(make_pass_ipa_strub): Declare.
(make_pass_ipa_function_and_variable_visibility): Fix
formatting.
* tree-ssa-ccp.cc (optimize_stack_restore): Keep restores
before strub leave.
* multiple_target.cc (pass_target_clone::gate): Test seen_error.
* attribs.cc: Include ipa-strub.h.
(decl_attributes): Support applying attributes to function
type, rather than pointer type, at handler's request.
(comp_type_attributes): Combine strub_comptypes and target
comp_type results.
* doc/tm.texi.in (TARGET_STRUB_USE_DYNAMIC_ARRAY): New.
(TARGET_STRUB_MAY_USE_MEMSET): New.
* doc/tm.texi: Rebuilt.
* cgraph.h (symtab_node::reset): Add preserve_comdat_group
param, with a default.
* cgraphunit.cc (symtab_node::reset): Use it.
for gcc/c-family/ChangeLog
* c-attribs.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(c_common_attribute_table): Add strub.
for gcc/ada/ChangeLog
* gcc-interface/trans.cc: Include ipa-strub.h.
(gigi): Make internal decls for targets of compiler-generated
calls strub-callable too.
(build_raise_check): Likewise.
* gcc-interface/utils.cc: Include ipa-strub.h.
(handle_strub_attribute): New.
(gnat_internal_attribute_table): Add strub.
for gcc/testsuite/ChangeLog
* c-c++-common/strub-O0.c: New.
* c-c++-common/strub-O1.c: New.
* c-c++-common/strub-O2.c: New.
* c-c++-common/strub-O2fni.c: New.
* c-c++-common/strub-O3.c: New.
* c-c++-common/strub-O3fni.c: New.
* c-c++-common/strub-Og.c: New.
* c-c++-common/strub-Os.c: New.
* c-c++-common/strub-all1.c: New.
* c-c++-common/strub-all2.c: New.
* c-c++-common/strub-apply1.c: New.
* c-c++-common/strub-apply2.c: New.
* c-c++-common/strub-apply3.c: New.
* c-c++-common/strub-apply4.c: New.
* c-c++-common/strub-at-calls1.c: New.
* c-c++-common/strub-at-calls2.c: New.
* c-c++-common/strub-defer-O1.c: New.
* c-c++-common/strub-defer-O2.c: New.
* c-c++-common/strub-defer-O3.c: New.
* c-c++-common/strub-defer-Os.c: New.
* c-c++-common/strub-internal1.c: New.
* c-c++-common/strub-internal2.c: New.
* c-c++-common/strub-parms1.c: New.
* c-c++-common/strub-parms2.c: New.
* c-c++-common/strub-parms3.c: New.
* c-c++-common/strub-relaxed1.c: New.
* c-c++-common/strub-relaxed2.c: New.
* c-c++-common/strub-short-O0-exc.c: New.
* c-c++-common/strub-short-O0.c: New.
* c-c++-common/strub-short-O1.c: New.
* c-c++-common/strub-short-O2.c: New.
* c-c++-common/strub-short-O3.c: New.
* c-c++-common/strub-short-Os.c: New.
* c-c++-common/strub-strict1.c: New.
* c-c++-common/strub-strict2.c: New.
* c-c++-common/strub-tail-O1.c: New.
* c-c++-common/strub-tail-O2.c: New.
* c-c++-common/torture/strub-callable1.c: New.
* c-c++-common/torture/strub-callable2.c: New.
* c-c++-common/torture/strub-const1.c: New.
* c-c++-common/torture/strub-const2.c: New.
* c-c++-common/torture/strub-const3.c: New.
* c-c++-common/torture/strub-const4.c: New.
* c-c++-common/torture/strub-data1.c: New.
* c-c++-common/torture/strub-data2.c: New.
* c-c++-common/torture/strub-data3.c: New.
* c-c++-common/torture/strub-data4.c: New.
* c-c++-common/torture/strub-data5.c: New.
* c-c++-common/torture/strub-indcall1.c: New.
* c-c++-common/torture/strub-indcall2.c: New.
* c-c++-common/torture/strub-indcall3.c: New.
* c-c++-common/torture/strub-inlinable1.c: New.
* c-c++-common/torture/strub-inlinable2.c: New.
* c-c++-common/torture/strub-ptrfn1.c: New.
* c-c++-common/torture/strub-ptrfn2.c: New.
* c-c++-common/torture/strub-ptrfn3.c: New.
* c-c++-common/torture/strub-ptrfn4.c: New.
* c-c++-common/torture/strub-pure1.c: New.
* c-c++-common/torture/strub-pure2.c: New.
* c-c++-common/torture/strub-pure3.c: New.
* c-c++-common/torture/strub-pure4.c: New.
* c-c++-common/torture/strub-run1.c: New.
* c-c++-common/torture/strub-run2.c: New.
* c-c++-common/torture/strub-run3.c: New.
* c-c++-common/torture/strub-run4.c: New.
* c-c++-common/torture/strub-run4c.c: New.
* c-c++-common/torture/strub-run4d.c: New.
* c-c++-common/torture/strub-run4i.c: New.
* g++.dg/strub-run1.C: New.
* g++.dg/torture/strub-init1.C: New.
* g++.dg/torture/strub-init2.C: New.
* g++.dg/torture/strub-init3.C: New.
* gnat.dg/strub_attr.adb, gnat.dg/strub_attr.ads: New.
* gnat.dg/strub_ind.adb, gnat.dg/strub_ind.ads: New.
for libgcc/ChangeLog
* Makefile.in (LIB2ADD): Add strub.c.
* libgcc2.h (__strub_enter, __strub_update, __strub_leave):
Declare.
* strub.c: New.
* libgcc-std.ver.in (__strub_enter): Add to GCC_14.0.0.
(__strub_update, __strub_leave): Likewise.
---
gcc/Makefile.in | 2
gcc/ada/gcc-interface/trans.cc | 18
gcc/ada/gcc-interface/utils.cc | 73
gcc/attribs.cc | 37
gcc/builtins.cc | 269 ++
gcc/builtins.def | 4
gcc/c-family/c-attribs.cc | 82
gcc/cgraph.h | 2
gcc/cgraphunit.cc | 5
gcc/common.opt | 29
gcc/doc/extend.texi | 312 ++
gcc/doc/invoke.texi | 60
gcc/doc/tm.texi | 19
gcc/doc/tm.texi.in | 19
gcc/gengtype-lex.l | 3
gcc/ipa-inline.cc | 6
gcc/ipa-split.cc | 7
gcc/ipa-strub.cc | 3573 ++++++++++++++++++++
gcc/ipa-strub.h | 45
gcc/passes.def | 2
gcc/testsuite/c-c++-common/strub-O0.c | 14
gcc/testsuite/c-c++-common/strub-O1.c | 15
gcc/testsuite/c-c++-common/strub-O2.c | 16
gcc/testsuite/c-c++-common/strub-O2fni.c | 15
gcc/testsuite/c-c++-common/strub-O3.c | 12
gcc/testsuite/c-c++-common/strub-O3fni.c | 15
gcc/testsuite/c-c++-common/strub-Og.c | 16
gcc/testsuite/c-c++-common/strub-Os.c | 18
gcc/testsuite/c-c++-common/strub-all1.c | 32
gcc/testsuite/c-c++-common/strub-all2.c | 24
gcc/testsuite/c-c++-common/strub-apply1.c | 15
gcc/testsuite/c-c++-common/strub-apply2.c | 12
gcc/testsuite/c-c++-common/strub-apply3.c | 8
gcc/testsuite/c-c++-common/strub-apply4.c | 21
gcc/testsuite/c-c++-common/strub-at-calls1.c | 30
gcc/testsuite/c-c++-common/strub-at-calls2.c | 23
gcc/testsuite/c-c++-common/strub-defer-O1.c | 7
gcc/testsuite/c-c++-common/strub-defer-O2.c | 8
gcc/testsuite/c-c++-common/strub-defer-O3.c | 110 +
gcc/testsuite/c-c++-common/strub-defer-Os.c | 7
gcc/testsuite/c-c++-common/strub-internal1.c | 31
gcc/testsuite/c-c++-common/strub-internal2.c | 21
gcc/testsuite/c-c++-common/strub-parms1.c | 48
gcc/testsuite/c-c++-common/strub-parms2.c | 36
gcc/testsuite/c-c++-common/strub-parms3.c | 58
gcc/testsuite/c-c++-common/strub-relaxed1.c | 18
gcc/testsuite/c-c++-common/strub-relaxed2.c | 14
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 10
gcc/testsuite/c-c++-common/strub-short-O0.c | 10
gcc/testsuite/c-c++-common/strub-short-O1.c | 10
gcc/testsuite/c-c++-common/strub-short-O2.c | 10
gcc/testsuite/c-c++-common/strub-short-O3.c | 12
gcc/testsuite/c-c++-common/strub-short-Os.c | 12
gcc/testsuite/c-c++-common/strub-strict1.c | 36
gcc/testsuite/c-c++-common/strub-strict2.c | 25
gcc/testsuite/c-c++-common/strub-tail-O1.c | 8
gcc/testsuite/c-c++-common/strub-tail-O2.c | 14
gcc/testsuite/c-c++-common/strub-var1.c | 24
.../c-c++-common/torture/strub-callable1.c | 9
.../c-c++-common/torture/strub-callable2.c | 264 +
gcc/testsuite/c-c++-common/torture/strub-const1.c | 18
gcc/testsuite/c-c++-common/torture/strub-const2.c | 22
gcc/testsuite/c-c++-common/torture/strub-const3.c | 13
gcc/testsuite/c-c++-common/torture/strub-const4.c | 17
gcc/testsuite/c-c++-common/torture/strub-data1.c | 13
gcc/testsuite/c-c++-common/torture/strub-data2.c | 14
gcc/testsuite/c-c++-common/torture/strub-data3.c | 14
gcc/testsuite/c-c++-common/torture/strub-data4.c | 14
gcc/testsuite/c-c++-common/torture/strub-data5.c | 15
.../c-c++-common/torture/strub-indcall1.c | 14
.../c-c++-common/torture/strub-indcall2.c | 14
.../c-c++-common/torture/strub-indcall3.c | 14
.../c-c++-common/torture/strub-inlinable1.c | 16
.../c-c++-common/torture/strub-inlinable2.c | 7
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 10
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 55
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 50
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 43
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17
gcc/testsuite/c-c++-common/torture/strub-run1.c | 95 +
gcc/testsuite/c-c++-common/torture/strub-run2.c | 84
gcc/testsuite/c-c++-common/torture/strub-run3.c | 80
gcc/testsuite/c-c++-common/torture/strub-run4.c | 106 +
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 5
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 7
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 5
gcc/testsuite/g++.dg/strub-run1.C | 19
gcc/testsuite/g++.dg/torture/strub-init1.C | 13
gcc/testsuite/g++.dg/torture/strub-init2.C | 14
gcc/testsuite/g++.dg/torture/strub-init3.C | 13
gcc/testsuite/gnat.dg/strub_access.adb | 21
gcc/testsuite/gnat.dg/strub_access1.adb | 16
gcc/testsuite/gnat.dg/strub_attr.adb | 37
gcc/testsuite/gnat.dg/strub_attr.ads | 12
gcc/testsuite/gnat.dg/strub_disp.adb | 64
gcc/testsuite/gnat.dg/strub_disp1.adb | 79
gcc/testsuite/gnat.dg/strub_ind.adb | 33
gcc/testsuite/gnat.dg/strub_ind.ads | 17
gcc/testsuite/gnat.dg/strub_ind1.adb | 41
gcc/testsuite/gnat.dg/strub_ind1.ads | 17
gcc/testsuite/gnat.dg/strub_ind2.adb | 34
gcc/testsuite/gnat.dg/strub_ind2.ads | 17
gcc/testsuite/gnat.dg/strub_intf.adb | 93 +
gcc/testsuite/gnat.dg/strub_intf1.adb | 86
gcc/testsuite/gnat.dg/strub_intf2.adb | 55
gcc/testsuite/gnat.dg/strub_renm.adb | 21
gcc/testsuite/gnat.dg/strub_renm1.adb | 32
gcc/testsuite/gnat.dg/strub_renm2.adb | 32
gcc/testsuite/gnat.dg/strub_var.adb | 16
gcc/testsuite/gnat.dg/strub_var1.adb | 20
gcc/tree-cfg.cc | 1
gcc/tree-pass.h | 5
gcc/tree-ssa-ccp.cc | 4
libgcc/Makefile.in | 3
libgcc/libgcc-std.ver.in | 3
libgcc/libgcc2.h | 4
libgcc/strub.c | 149 +
120 files changed, 7429 insertions(+), 12 deletions(-)
create mode 100644 gcc/ipa-strub.cc
create mode 100644 gcc/ipa-strub.h
create mode 100644 gcc/testsuite/c-c++-common/strub-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O2fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-O3fni.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Og.c
create mode 100644 gcc/testsuite/c-c++-common/strub-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-all2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-apply4.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-at-calls2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-defer-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-internal2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-parms3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-relaxed2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0-exc.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O0.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-O3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-short-Os.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-strict2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O1.c
create mode 100644 gcc/testsuite/c-c++-common/strub-tail-O2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-var1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-callable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-const4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-data5.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-indcall3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-pure4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run1.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run2.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run3.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4c.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4d.c
create mode 100644 gcc/testsuite/c-c++-common/torture/strub-run4i.c
create mode 100644 gcc/testsuite/g++.dg/strub-run1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init1.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init2.C
create mode 100644 gcc/testsuite/g++.dg/torture/strub-init3.C
create mode 100644 gcc/testsuite/gnat.dg/strub_access.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_access1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_attr.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_disp.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_disp1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind1.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_ind2.ads
create mode 100644 gcc/testsuite/gnat.dg/strub_intf.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_intf2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm1.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_renm2.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var.adb
create mode 100644 gcc/testsuite/gnat.dg/strub_var1.adb
create mode 100644 libgcc/strub.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e154f7c0055f9..68410a86af5a9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1557,6 +1557,7 @@ OBJS = \
ipa-reference.o \
ipa-ref.o \
ipa-utils.o \
+ ipa-strub.o \
ipa.o \
ira.o \
ira-build.o \
@@ -2879,6 +2880,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/sanopt.cc \
$(srcdir)/sancov.cc \
$(srcdir)/ipa-devirt.cc \
+ $(srcdir)/ipa-strub.cc \
$(srcdir)/internal-fn.h \
$(srcdir)/calls.cc \
$(srcdir)/omp-general.h \
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index 9c418beda9643..5e9e92d8b7257 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -69,6 +69,21 @@
#include "ada-tree.h"
#include "gigi.h"
+/* The following #include is for strub_make_callable.
+
+ This function marks a function as safe to call from strub contexts. We mark
+ Ada subprograms that may be called implicitly by the compiler, and that won't
+ leave on the stack caller data passed to them. This stops implicit calls
+ introduced in subprograms that have their stack scrubbed from being flagged
+ as unsafe, even in -fstrub=strict mode.
+
+ These subprograms are also marked with the strub(callable) attribute in Ada
+ sources, but their declarations aren't necessarily imported by GNAT, or made
+ visible to gigi, in units that end up relying on them. So when gigi
+ introduces their declarations on its own, it must also add the attribute, by
+ calling strub_make_callable. */
+#include "ipa-strub.h"
+
/* We should avoid allocating more than ALLOCA_THRESHOLD bytes via alloca,
for fear of running out of stack space. If we need more, we use xmalloc
instead. */
@@ -454,6 +469,7 @@ gigi (Node_Id gnat_root,
int64_type, NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv64_decl);
if (Enable_128bit_Types)
{
@@ -466,6 +482,7 @@ gigi (Node_Id gnat_root,
NULL_TREE),
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (mulv128_decl);
}
/* Name of the _Parent field in tagged record types. */
@@ -722,6 +739,7 @@ build_raise_check (int check, enum exception_info_kind kind)
= create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype,
NULL_TREE, is_default, true, true, true, false,
false, NULL, Empty);
+ strub_make_callable (result);
set_call_expr_flags (result, ECF_NORETURN | ECF_XTHROW);
return result;
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index f46454d6545a2..8d1237fdbb3e2 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -39,6 +39,7 @@
#include "varasm.h"
#include "toplev.h"
#include "opts.h"
+#include "ipa-strub.h"
#include "output.h"
#include "debug.h"
#include "convert.h"
@@ -6742,9 +6743,77 @@ handle_no_stack_protector_attribute (tree *node, tree name, tree, int,
struct attribute_spec.handler. */
static tree
-handle_strub_attribute (tree *, tree, tree, int, bool *no_add_attrs)
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
- *no_add_attrs = true;
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
return NULL_TREE;
}
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index eff99002fbb92..dd0408635670f 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "attribs.h"
#include "fold-const.h"
+#include "ipa-strub.h"
#include "stor-layout.h"
#include "langhooks.h"
#include "plugin.h"
@@ -789,8 +790,8 @@ decl_attributes (tree *node, tree attributes, int flags,
flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
}
- if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
+ if (spec->function_type_required
+ && !FUNC_OR_METHOD_TYPE_P (*anode))
{
if (TREE_CODE (*anode) == POINTER_TYPE
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
@@ -905,7 +906,24 @@ decl_attributes (tree *node, tree attributes, int flags,
TYPE_NAME (tt) = *node;
}
- *anode = cur_and_last_decl[0];
+ if (*anode != cur_and_last_decl[0])
+ {
+ /* Even if !spec->function_type_required, allow the attribute
+ handler to request the attribute to be applied to the function
+ type, rather than to the function pointer type, by setting
+ cur_and_last_decl[0] to the function type. */
+ if (!fn_ptr_tmp
+ && POINTER_TYPE_P (*anode)
+ && TREE_TYPE (*anode) == cur_and_last_decl[0]
+ && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+ {
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ }
+ *anode = cur_and_last_decl[0];
+ }
+
if (ret == error_mark_node)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1508,9 +1526,20 @@ comp_type_attributes (const_tree type1, const_tree type2)
if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
return 0;
+ int strub_ret = strub_comptypes (CONST_CAST_TREE (type1),
+ CONST_CAST_TREE (type2));
+ if (strub_ret == 0)
+ return strub_ret;
/* As some type combinations - like default calling-convention - might
be compatible, we have to call the target hook to get the final result. */
- return targetm.comp_type_attributes (type1, type2);
+ int target_ret = targetm.comp_type_attributes (type1, type2);
+ if (target_ret == 0)
+ return target_ret;
+ if (strub_ret == 2 || target_ret == 2)
+ return 2;
+ if (strub_ret == 1 && target_ret == 1)
+ return 1;
+ gcc_unreachable ();
}
/* PREDICATE acts as a function of type:
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 4fc58a0bda9b8..555d2897938ca 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "intl.h"
#include "file-prefix-map.h" /* remap_macro_filename() */
+#include "ipa-strub.h" /* strub_watermark_parm() */
#include "gomp-constants.h"
#include "omp-general.h"
#include "tree-dfa.h"
@@ -151,6 +152,7 @@ static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
static rtx expand_builtin_alloca (tree);
static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
+static rtx expand_builtin_stack_address ();
static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx);
static rtx expand_builtin_expect_with_probability (tree, rtx);
@@ -5370,6 +5372,252 @@ expand_builtin_frame_address (tree fndecl, tree exp)
}
}
+#if ! STACK_GROWS_DOWNWARD
+# define STACK_TOPS GT
+#else
+# define STACK_TOPS LT
+#endif
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+# define STACK_UNSIGNED POINTERS_EXTEND_UNSIGNED
+#else
+# define STACK_UNSIGNED true
+#endif
+
+/* Expand a call to builtin function __builtin_stack_address. */
+
+static rtx
+expand_builtin_stack_address ()
+{
+ return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
+ STACK_UNSIGNED);
+}
+
+/* Expand a call to builtin function __builtin_strub_enter. */
+
+static rtx
+expand_builtin_strub_enter (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 1 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ emit_move_insn (wmark, stktop);
+
+ return const0_rtx;
+}
+
+/* Expand a call to builtin function __builtin_strub_update. */
+
+static rtx
+expand_builtin_strub_update (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = expand_builtin_stack_address ();
+
+#ifdef RED_ZONE_SIZE
+ /* Here's how the strub enter, update and leave functions deal with red zones.
+
+ If it weren't for red zones, update, called from within a strub context,
+ would bump the watermark to the top of the stack. Enter and leave, running
+ in the caller, would use the caller's top of stack address both to
+ initialize the watermark passed to the callee, and to start strubbing the
+ stack afterwards.
+
+ Ideally, we'd update the watermark so as to cover the used amount of red
+ zone, and strub starting at the caller's other end of the (presumably
+ unused) red zone. Normally, only leaf functions use the red zone, but at
+ this point we can't tell whether a function is a leaf, nor can we tell how
+ much of the red zone it uses. Furthermore, some strub contexts may have
+ been inlined so that update and leave are called from the same stack frame,
+ and the strub builtins may all have been inlined, turning a strub function
+ into a leaf.
+
+ So cleaning the range from the caller's stack pointer (one end of the red
+ zone) to the (potentially inlined) callee's (other end of the) red zone
+ could scribble over the caller's own red zone.
+
+ We avoid this possibility by arranging for callers that are strub contexts
+ to use their own watermark as the strub starting point. So, if A calls B,
+ and B calls C, B will tell A to strub up to the end of B's red zone, and
+ will strub itself only the part of C's stack frame and red zone that
+ doesn't overlap with B's. With that, we don't need to know who's leaf and
+ who isn't: inlined calls will shrink their strub window to zero, each
+ remaining call will strub some portion of the stack, and eventually the
+ strub context will return to a caller that isn't a strub context itself,
+ that will therefore use its own stack pointer as the strub starting point.
+ It's not a leaf, because strub contexts can't be inlined into non-strub
+ contexts, so it doesn't use the red zone, and it will therefore correctly
+ strub up the callee's stack frame up to the end of the callee's red zone.
+ Neat! */
+ if (true /* (flags_from_decl_or_type (current_function_decl) & ECF_LEAF) */)
+ {
+ poly_int64 red_zone_size = RED_ZONE_SIZE;
+#if STACK_GROWS_DOWNWARD
+ red_zone_size = -red_zone_size;
+#endif
+ stktop = plus_constant (ptr_mode, stktop, red_zone_size);
+ stktop = force_reg (ptr_mode, stktop);
+ }
+#endif
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+ rtx_code_label *lab = gen_label_rtx ();
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+
+ /* If this is an inlined strub function, also bump the watermark for the
+ enclosing function. This avoids a problem with the following scenario: A
+ calls B and B calls C, and both B and C get inlined into A. B allocates
+ temporary stack space before calling C. If we don't update A's watermark,
+ we may use an outdated baseline for the post-C strub_leave, erasing B's
+ temporary stack allocation. We only need this if we're fully expanding
+ strub_leave inline. */
+ tree xwmptr = (optimize > 2
+ ? strub_watermark_parm (current_function_decl)
+ : wmptr);
+ if (wmptr != xwmptr)
+ {
+ wmptr = xwmptr;
+ wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ wmarkr = force_reg (ptr_mode, wmark);
+
+ do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, lab, NULL,
+ profile_probability::very_likely ());
+ emit_move_insn (wmark, stktop);
+ }
+
+ emit_label (lab);
+
+ return const0_rtx;
+}
+
+
+/* Expand a call to builtin function __builtin_strub_leave. */
+
+static rtx
+expand_builtin_strub_leave (tree exp)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ if (optimize < 2 || optimize_size || flag_no_inline)
+ return NULL_RTX;
+
+ rtx stktop = NULL_RTX;
+
+ if (tree wmptr = (optimize
+ ? strub_watermark_parm (current_function_decl)
+ : NULL_TREE))
+ {
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+ stktop = force_reg (ptr_mode, wmark);
+ }
+
+ if (!stktop)
+ stktop = expand_builtin_stack_address ();
+
+ tree wmptr = CALL_EXPR_ARG (exp, 0);
+ tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
+ tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
+ build_int_cst (TREE_TYPE (wmptr), 0));
+ rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+
+ rtx wmarkr = force_reg (ptr_mode, wmark);
+
+#if ! STACK_GROWS_DOWNWARD
+ rtx base = stktop;
+ rtx end = wmarkr;
+#else
+ rtx base = wmarkr;
+ rtx end = stktop;
+#endif
+
+ /* We're going to modify it, so make sure it's not e.g. the stack pointer. */
+ base = copy_to_reg (base);
+
+ rtx_code_label *done = gen_label_rtx ();
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ ptr_mode, NULL_RTX, done, NULL,
+ profile_probability::very_likely ());
+
+ if (optimize < 3)
+ expand_call (exp, NULL_RTX, true);
+ else
+ {
+ /* Ok, now we've determined we want to copy the block, so convert the
+ addresses to Pmode, as needed to dereference them to access ptr_mode
+ memory locations, so that we don't have to convert anything within the
+ loop. */
+ base = memory_address (ptr_mode, base);
+ end = memory_address (ptr_mode, end);
+
+ rtx zero = force_operand (const0_rtx, NULL_RTX);
+ int ulen = GET_MODE_SIZE (ptr_mode);
+
+ /* ??? It would be nice to use setmem or similar patterns here,
+ but they do not necessarily obey the stack growth direction,
+ which has security implications. We also have to avoid calls
+ (memset, bzero or any machine-specific ones), which are
+ likely unsafe here (see TARGET_STRUB_MAY_USE_MEMSET). */
+#if ! STACK_GROWS_DOWNWARD
+ rtx incr = plus_constant (Pmode, base, ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, base);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (dstm, zero);
+ emit_move_insn (base, force_operand (incr, NULL_RTX));
+#else
+ rtx decr = plus_constant (Pmode, end, -ulen);
+ rtx dstm = gen_rtx_MEM (ptr_mode, end);
+
+ rtx_code_label *loop = gen_label_rtx ();
+ emit_label (loop);
+ emit_move_insn (end, force_operand (decr, NULL_RTX));
+ emit_move_insn (dstm, zero);
+#endif
+ do_compare_rtx_and_jump (base, end, LT, STACK_UNSIGNED,
+ Pmode, NULL_RTX, NULL, loop,
+ profile_probability::very_likely ());
+ }
+
+ emit_label (done);
+
+ return const0_rtx;
+}
+
/* Expand EXP, a call to the alloca builtin. Return NULL_RTX if we
failed and the caller should emit a normal call. */
@@ -7705,6 +7953,27 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
case BUILT_IN_RETURN_ADDRESS:
return expand_builtin_frame_address (fndecl, exp);
+ case BUILT_IN_STACK_ADDRESS:
+ return expand_builtin_stack_address ();
+
+ case BUILT_IN___STRUB_ENTER:
+ target = expand_builtin_strub_enter (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_UPDATE:
+ target = expand_builtin_strub_update (exp);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN___STRUB_LEAVE:
+ target = expand_builtin_strub_leave (exp);
+ if (target)
+ return target;
+ break;
+
/* Returns the address of the area where the structure is returned.
0 otherwise. */
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 33e6cad8ce14f..f03df32f98013 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -999,6 +999,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_
DEF_GCC_BUILTIN (BUILT_IN_FFSG, "ffsg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
+DEF_GCC_BUILTIN (BUILT_IN_STACK_ADDRESS, "stack_address", BT_FN_PTR, ATTR_NULL)
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_ENTER, "__builtin___strub_enter")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_UPDATE, "__builtin___strub_update")
+DEF_BUILTIN_STUB (BUILT_IN___STRUB_LEAVE, "__builtin___strub_leave")
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
DEF_LIB_BUILTIN (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 45af07453ea3c..acc09e4b27a5b 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "common/common-target.h"
#include "langhooks.h"
#include "tree-inline.h"
+#include "ipa-strub.h"
#include "toplev.h"
#include "tree-iterator.h"
#include "opts.h"
@@ -69,6 +70,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_stack_protector_function_attribute (tree *, tree,
tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -322,6 +324,8 @@ const struct attribute_spec c_common_gnu_attributes[] =
{ "no_stack_protector", 0, 0, true, false, false, false,
handle_no_stack_protector_function_attribute,
attr_stack_protect_exclusions },
+ { "strub", 0, 1, false, true, false, true,
+ handle_strub_attribute, NULL },
{ "noinline", 0, 0, true, false, false, false,
handle_noinline_attribute,
attr_noinline_exclusions },
@@ -1489,6 +1493,84 @@ handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
return NULL_TREE;
}
+/* Handle a "strub" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+ tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ bool enable = true;
+
+ if (args && FUNCTION_POINTER_TYPE_P (*node))
+ *node = TREE_TYPE (*node);
+
+ if (args && FUNC_OR_METHOD_TYPE_P (*node))
+ {
+ switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+ {
+ case 1:
+ case 2:
+ enable = true;
+ break;
+
+ case 0:
+ warning (OPT_Wattributes,
+ "%qE attribute ignored because of argument %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ break;
+
+ case -1:
+ case -2:
+ enable = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ args = TREE_CHAIN (args);
+ }
+
+ if (args)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attribute %qE because of excess arguments"
+ " starting at %qE",
+ name, TREE_VALUE (args));
+ *no_add_attrs = true;
+ enable = false;
+ }
+
+ /* Warn about unmet expectations that the strub attribute works like a
+ qualifier. ??? Could/should we extend it to the element/field types
+ here? */
+ if (TREE_CODE (*node) == ARRAY_TYPE
+ || VECTOR_TYPE_P (*node)
+ || TREE_CODE (*node) == COMPLEX_TYPE)
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to elements"
+ " of non-scalar type %qT",
+ name, *node);
+ else if (RECORD_OR_UNION_TYPE_P (*node))
+ warning (OPT_Wattributes,
+ "attribute %qE does not apply to fields"
+ " of aggregate type %qT",
+ name, *node);
+
+ /* If we see a strub-enabling attribute, and we're at the default setting,
+ implicitly or explicitly, note that the attribute was seen, so that we can
+ reduce the compile-time overhead to nearly zero when the strub feature is
+ not used. */
+ if (enable && flag_strub < -2)
+ flag_strub += 2;
+
+ return NULL_TREE;
+}
+
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cfdd9f693a889..2b32055761688 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -153,7 +153,7 @@ public:
void remove (void);
/* Undo any definition or use of the symbol. */
- void reset (void);
+ void reset (bool preserve_comdat_group = false);
/* Dump symtab node to F. */
void dump (FILE *f);
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index bccd2f2abb5a3..9a550a5cce645 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -384,7 +384,7 @@ symbol_table::process_new_functions (void)
functions or variables. */
void
-symtab_node::reset (void)
+symtab_node::reset (bool preserve_comdat_group)
{
/* Reset our data structures so we can analyze the function again. */
analyzed = false;
@@ -395,7 +395,8 @@ symtab_node::reset (void)
cpp_implicit_alias = false;
remove_all_references ();
- remove_from_same_comdat_group ();
+ if (!preserve_comdat_group)
+ remove_from_same_comdat_group ();
if (cgraph_node *cn = dyn_cast <cgraph_node *> (this))
{
diff --git a/gcc/common.opt b/gcc/common.opt
index 161a035d736a3..f070aff8cbc1b 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2917,6 +2917,35 @@ fstrict-overflow
Common
Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer.
+fstrub=disable
+Common RejectNegative Var(flag_strub, 0)
+Disable stack scrub entirely, disregarding strub attributes.
+
+fstrub=strict
+Common RejectNegative Var(flag_strub, -4)
+Enable stack scrub as per attributes, with strict call checking.
+
+; If any strub-enabling attribute is seen when the default or strict
+; initializer values are in effect, flag_strub is bumped up by 2. The
+; scrub mode gate function will then bump these initializer values to
+; 0 if no strub-enabling attribute is seen. This minimizes the strub
+; overhead.
+fstrub=relaxed
+Common RejectNegative Var(flag_strub, -3) Init(-3)
+Restore default strub mode: as per attributes, with relaxed checking.
+
+fstrub=all
+Common RejectNegative Var(flag_strub, 3)
+Enable stack scrubbing for all viable functions.
+
+fstrub=at-calls
+Common RejectNegative Var(flag_strub, 1)
+Enable at-calls stack scrubbing for all viable functions.
+
+fstrub=internal
+Common RejectNegative Var(flag_strub, 2)
+Enable internal stack scrubbing for all viable functions.
+
fsync-libcalls
Common Var(flag_sync_libcalls) Init(1)
Implement __atomic operations via libcalls to legacy __sync functions.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9592cfee1d279..e9bc9c4fe84c8 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -77,6 +77,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Function Names:: Printable strings which are the name of the current
function.
* Return Address:: Getting the return or frame address of a function.
+* Stack Scrubbing:: Stack scrubbing internal interfaces.
* Vector Extensions:: Using vector instructions through built-in functions.
* Offsetof:: Special syntax for implementing @code{offsetof}.
* __sync Builtins:: Legacy built-in functions for atomic memory access.
@@ -9225,6 +9226,268 @@ pid_t wait (wait_status_ptr_t p)
@}
@end smallexample
+@cindex @code{strub} type attribute
+@item strub
+This attribute defines stack-scrubbing properties of functions and
+variables, so that functions that access sensitive data can have their
+stack frames zeroed-out upon returning or propagating exceptions. This
+may be enabled explicitly, by selecting certain @code{strub} modes for
+specific functions, or implicitly, by means of @code{strub} variables.
+
+Being a type attribute, it attaches to types, even when specified in
+function and variable declarations. When applied to function types, it
+takes an optional string argument. When applied to a
+pointer-to-function type, if the optional argument is given, it gets
+propagated to the function type.
+
+@smallexample
+/* A strub variable. */
+int __attribute__ ((strub)) var;
+/* A strub variable that happens to be a pointer. */
+__attribute__ ((strub)) int *strub_ptr_to_int;
+/* A pointer type that may point to a strub variable. */
+typedef int __attribute__ ((strub)) *ptr_to_strub_int_type;
+
+/* A declaration of a strub function. */
+extern int __attribute__ ((strub)) foo (void);
+/* A pointer to that strub function. */
+int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo;
+@end smallexample
+
+A function associated with @code{at-calls} @code{strub} mode
+(@code{strub("at-calls")}, or just @code{strub}) undergoes interface
+changes. Its callers are adjusted to match the changes, and to scrub
+(overwrite with zeros) the stack space used by the called function after
+it returns. The interface change makes the function type incompatible
+with an unadorned but otherwise equivalent type, so @emph{every}
+declaration and every type that may be used to call the function must be
+associated with this strub mode.
+
+A function associated with @code{internal} @code{strub} mode
+(@code{strub("internal")}) retains an unmodified, type-compatible
+interface, but it may be turned into a wrapper that calls the wrapped
+body using a custom interface. The wrapper then scrubs the stack space
+used by the wrapped body. Though the wrapped body has its stack space
+scrubbed, the wrapper does not, so arguments and return values may
+remain unscrubbed even when such a function is called by another
+function that enables @code{strub}. This is why, when compiling with
+@option{-fstrub=strict}, a @code{strub} context is not allowed to call
+@code{internal} @code{strub} functions.
+
+@smallexample
+/* A declaration of an internal-strub function. */
+extern int __attribute__ ((strub ("internal"))) bar (void);
+
+int __attribute__ ((strub))
+baz (void)
+@{
+ /* Ok, foo was declared above as an at-calls strub function. */
+ foo ();
+ /* Not allowed in strict mode, otherwise allowed. */
+ bar ();
+@}
+@end smallexample
+
+An automatically-allocated variable associated with the @code{strub}
+attribute causes the (immediately) enclosing function to have
+@code{strub} enabled.
+
+A statically-allocated variable associated with the @code{strub}
+attribute causes functions that @emph{read} it, through its @code{strub}
+data type, to have @code{strub} enabled. Reading data by dereferencing
+a pointer to a @code{strub} data type has the same effect. Note: The
+attribute does not carry over from a composite type to the types of its
+components, so the intended effect may not be obtained with non-scalar
+types.
+
+When selecting a @code{strub}-enabled mode for a function that is not
+explicitly associated with one, because of @code{strub} variables or
+data pointers, the function must satisfy @code{internal} mode viability
+requirements (see below), even when @code{at-calls} mode is also viable
+and, being more efficient, ends up selected as an optimization.
+
+@smallexample
+/* zapme is implicitly strub-enabled because of strub variables.
+ Optimization may change its strub mode, but not the requirements. */
+static int
+zapme (int i)
+@{
+ /* A local strub variable enables strub. */
+ int __attribute__ ((strub)) lvar;
+ /* Reading strub data through a pointer-to-strub enables strub. */
+ lvar = * (ptr_to_strub_int_type) &i;
+ /* Writing to a global strub variable does not enable strub. */
+ var = lvar;
+ /* Reading from a global strub variable enables strub. */
+ return var;
+@}
+@end smallexample
+
+A @code{strub} context is the body (as opposed to the interface) of a
+function that has @code{strub} enabled, be it explicitly, by
+@code{at-calls} or @code{internal} mode, or implicitly, due to
+@code{strub} variables or command-line options.
+
+A function of a type associated with the @code{disabled} @code{strub}
+mode (@code{strub("disabled")} will not have its own stack space
+scrubbed. Such functions @emph{cannot} be called from within
+@code{strub} contexts.
+
+In order to enable a function to be called from within @code{strub}
+contexts without having its stack space scrubbed, associate it with the
+@code{callable} @code{strub} mode (@code{strub("callable")}).
+
+When a function is not assigned a @code{strub} mode, explicitly or
+implicitly, the mode defaults to @code{callable}, except when compiling
+with @option{-fstrub=strict}, that causes @code{strub} mode to default
+to @code{disabled}.
+
+@example
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+ /* Implicitly disabled with -fstrub=strict, otherwise callable. */
+extern int bah (void);
+
+int __attribute__ ((strub))
+bal (void)
+@{
+ /* Not allowed, bad is not strub-callable. */
+ bad ();
+ /* Ok, bac is strub-callable. */
+ bac ();
+ /* Not allowed with -fstrub=strict, otherwise allowed. */
+ bah ();
+@}
+@end example
+
+Function types marked @code{callable} and @code{disabled} are not
+mutually compatible types, but the underlying interfaces are compatible,
+so it is safe to convert pointers between them, and to use such pointers
+or alternate declarations to call them. Interfaces are also
+interchangeable between them and @code{internal} (but not
+@code{at-calls}!), but adding @code{internal} to a pointer type will not
+cause the pointed-to function to perform stack scrubbing.
+
+@example
+void __attribute__ ((strub))
+bap (void)
+@{
+ /* Assign a callable function to pointer-to-disabled.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac;
+ /* Not allowed: calls disabled type in a strub context. */
+ d_p ();
+
+ /* Assign a disabled function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an internal function to pointer-to-callable.
+ Flagged as not quite compatible with -Wpedantic. */
+ c_p = bar;
+ /* Ok, safe. */
+ c_p ();
+
+ /* Assign an at-calls function to pointer-to-callable.
+ Flaggged as incompatible. */
+ c_p = bal;
+ /* The call through an interface-incompatible type will not use the
+ modified interface expected by the at-calls function, so it is
+ likely to misbehave at runtime. */
+ c_p ();
+@}
+@end example
+
+@code{Strub} contexts are never inlined into non-@code{strub} contexts.
+When an @code{internal}-strub function is split up, the wrapper can
+often be inlined, but the wrapped body @emph{never} is. A function
+marked as @code{always_inline}, even if explicitly assigned
+@code{internal} strub mode, will not undergo wrapping, so its body gets
+inlined as required.
+
+@example
+inline int __attribute__ ((strub ("at-calls")))
+inl_atc (void)
+@{
+ /* This body may get inlined into strub contexts. */
+@}
+
+inline int __attribute__ ((strub ("internal")))
+inl_int (void)
+@{
+ /* This body NEVER gets inlined, though its wrapper may. */
+@}
+
+inline int __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+@{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+@}
+
+void __attribute__ ((strub ("disabled")))
+bat (void)
+@{
+ /* Not allowed, cannot inline into a non-strub context. */
+ inl_int_ali ();
+@}
+@end example
+
+@cindex strub eligibility and viability
+Some @option{-fstrub=*} command line options enable @code{strub} modes
+implicitly where viable. A @code{strub} mode is only viable for a
+function if the function is eligible for that mode, and if other
+conditions, detailed below, are satisfied. If it's not eligible for a
+mode, attempts to explicitly associate it with that mode are rejected
+with an error message. If it is eligible, that mode may be assigned
+explicitly through this attribute, but implicit assignment through
+command-line options may involve additional viability requirements.
+
+A function is ineligible for @code{at-calls} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, if attribute
+@code{noipa} is present, or if it calls @code{__builtin_apply_args}.
+@code{At-calls} @code{strub} mode, if not requested through the function
+type, is only viable for an eligible function if the function is not
+visible to other translation units, if it doesn't have its address
+taken, and if it is never called with a function type overrider.
+
+@smallexample
+/* bar is eligible for at-calls strub mode,
+ but not viable for that mode because it is visible to other units.
+ It is eligible and viable for internal strub mode. */
+void bav () @{@}
+
+/* setp is eligible for at-calls strub mode,
+ but not viable for that mode because its address is taken.
+ It is eligible and viable for internal strub mode. */
+void setp (void) @{ static void (*p)(void); = setp; @}
+@end smallexample
+
+A function is ineligible for @code{internal} @code{strub} mode if a
+different @code{strub} mode is explicitly requested, or if attribute
+@code{noipa} is present. For an @code{always_inline} function, meeting
+these requirements is enough to make it eligible. Any function that has
+attribute @code{noclone}, that uses such extensions as non-local labels,
+computed gotos, alternate variable argument passing interfaces,
+@code{__builtin_next_arg}, or @code{__builtin_return_address}, or that
+takes too many (about 64Ki) arguments is ineligible, unless it is
+@code{always_inline}. For @code{internal} @code{strub} mode, all
+eligible functions are viable.
+
+@smallexample
+/* flop is not eligible, thus not viable, for at-calls strub mode.
+ Likewise for internal strub mode. */
+__attribute__ ((noipa)) void flop (void) @{@}
+
+/* flip is eligible and viable for at-calls strub mode.
+ It would be ineligible for internal strub mode, because of noclone,
+ if it weren't for always_inline. With always_inline, noclone is not
+ an obstacle, so it is also eligible and viable for internal strub mode. */
+inline __attribute__ ((noclone, always_inline)) void flip (void) @{@}
+@end smallexample
+
@cindex @code{unused} type attribute
@item unused
When attached to a type (including a @code{union} or a @code{struct}),
@@ -12375,6 +12638,55 @@ option is in effect. Such calls should only be made in debugging
situations.
@enddefbuiltin
+@deftypefn {Built-in Function} {void *} __builtin_stack_address ()
+This function returns the value of the stack pointer register.
+@end deftypefn
+
+@node Stack Scrubbing
+@section Stack scrubbing internal interfaces
+
+Stack scrubbing involves cooperation between a @code{strub} context,
+i.e., a function whose stack frame is to be zeroed-out, and its callers.
+The caller initializes a stack watermark, the @code{strub} context
+updates the watermark according to its stack use, and the caller zeroes
+it out once it regains control, whether by the callee's returning or by
+an exception.
+
+Each of these steps is performed by a different builtin function call.
+Calls to these builtins are introduced automatically, in response to
+@code{strub} attributes and command-line options; they are not expected
+to be explicitly called by source code.
+
+The functions that implement the builtins are available in libgcc but,
+depending on optimization levels, they are expanded internally, adjusted
+to account for inlining, and sometimes combined/deferred (e.g. passing
+the caller-supplied watermark on to callees, refraining from erasing
+stack areas that the caller will) to enable tail calls and to optimize
+for code size.
+
+@deftypefn {Built-in Function} {void} __builtin___strub_enter (void **@var{wmptr})
+This function initializes a stack @var{watermark} variable with the
+current top of the stack. A call to this builtin function is introduced
+before entering a @code{strub} context. It remains as a function call
+if optimization is not enabled.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_update (void **@var{wmptr})
+This function updates a stack @var{watermark} variable with the current
+top of the stack, if it tops the previous watermark. A call to this
+builtin function is inserted within @code{strub} contexts, whenever
+additional stack space may have been used. It remains as a function
+call at optimization levels lower than 2.
+@end deftypefn
+
+@deftypefn {Built-in Function} {void} __builtin___strub_leave (void **@var{wmptr})
+This function overwrites the memory area between the current top of the
+stack, and the @var{watermark}ed address. A call to this builtin
+function is inserted after leaving a @code{strub} context. It remains
+as a function call at optimization levels lower than 3, and it is guarded by
+a condition at level 2.
+@end deftypefn
+
@node Vector Extensions
@section Using Vector Instructions through Built-in Functions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2fab4c5d71fd0..04d7ecd4593e1 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -654,6 +654,8 @@ Objective-C and Objective-C++ Dialects}.
-fstack-protector-explicit -fstack-check
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
-fno-stack-limit -fsplit-stack
+-fstrub=disable -fstrub=strict -fstrub=relaxed
+-fstrub=all -fstrub=at-calls -fstrub=internal
-fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
-fvtv-counts -fvtv-debug
-finstrument-functions -finstrument-functions-once
@@ -17890,6 +17892,56 @@ without @option{-fsplit-stack} always has a large stack. Support for
this is implemented in the gold linker in GNU binutils release 2.21
and later.
+@opindex -fstrub=disable
+@item -fstrub=disable
+Disable stack scrubbing entirely, ignoring any @code{strub} attributes.
+See @xref{Common Type Attributes}.
+
+@opindex fstrub=strict
+@item -fstrub=strict
+Functions default to @code{strub} mode @code{disabled}, and apply
+@option{strict}ly the restriction that only functions associated with
+@code{strub}-@code{callable} modes (@code{at-calls}, @code{callable} and
+@code{always_inline} @code{internal}) are @code{callable} by functions
+with @code{strub}-enabled modes (@code{at-calls} and @code{internal}).
+
+@opindex fstrub=relaxed
+@item -fstrub=relaxed
+Restore the default stack scrub (@code{strub}) setting, namely,
+@code{strub} is only enabled as required by @code{strub} attributes
+associated with function and data types. @code{Relaxed} means that
+strub contexts are only prevented from calling functions explicitly
+associated with @code{strub} mode @code{disabled}. This option is only
+useful to override other @option{-fstrub=*} options that precede it in
+the command line.
+
+@opindex fstrub=at-calls
+@item -fstrub=at-calls
+Enable @code{at-calls} @code{strub} mode where viable. The primary use
+of this option is for testing. It exercises the @code{strub} machinery
+in scenarios strictly local to a translation unit. This @code{strub}
+mode modifies function interfaces, so any function that is visible to
+other translation units, or that has its address taken, will @emph{not}
+be affected by this option. Optimization options may also affect
+viability. See the @code{strub} attribute documentation for details on
+viability and eligibility requirements.
+
+@opindex fstrub=internal
+@item -fstrub=internal
+Enable @code{internal} @code{strub} mode where viable. The primary use
+of this option is for testing. This option is intended to exercise
+thoroughly parts of the @code{strub} machinery that implement the less
+efficient, but interface-preserving @code{strub} mode. Functions that
+would not be affected by this option are quite uncommon.
+
+@opindex fstrub=all
+@item -fstrub=all
+Enable some @code{strub} mode where viable. When both strub modes are
+viable, @code{at-calls} is preferred. @option{-fdump-ipa-strubm} adds
+function attributes that tell which mode was selected for each function.
+The primary use of this option is for testing, to exercise thoroughly
+the @code{strub} machinery.
+
@opindex fvtable-verify
@item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]}
This option is only available when compiling C++ code.
@@ -19809,6 +19861,14 @@ and inlining decisions.
@item inline
Dump after function inlining.
+@item strubm
+Dump after selecting @code{strub} modes, and recording the selections as
+function attributes.
+
+@item strub
+Dump @code{strub} transformations: interface changes, function wrapping,
+and insertion of builtin calls for stack scrubbing and watermarking.
+
@end table
Additionally, the options @option{-optimized}, @option{-missed},
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 7c5d2e523601d..c4b2ee4b8091a 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index c24493add5748..9cbde5f8b740a 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,25 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
+If defined to nonzero, @code{__strub_leave} will allocate a dynamic
+array covering the stack range that needs scrubbing before clearing it.
+Allocating the array tends to make scrubbing slower, but it enables the
+scrubbing to be safely implemented with a @code{memset} call, which
+could make up for the difference.
+@end defmac
+
+@defmac TARGET_STRUB_MAY_USE_MEMSET
+If defined to nonzero, enable @code{__strub_leave} to be optimized so as
+to call @code{memset} for stack scrubbing. This is only enabled by
+default if @code{TARGET_STRUB_USE_DYNAMIC_ARRAY} is enabled; it's not
+advisable to enable it otherwise, since @code{memset} would then likely
+overwrite its own stack frame, but it might work if the target ABI
+enables @code{memset} to not use the stack at all, not even for
+arguments or its return address, and its implementation is trivial
+enough that it doesn't use a stack frame.
+@end defmac
+
@node Exception Handling
@subsection Exception Handling Support
@cindex exception handling
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index 34837d9dc9a8f..a7bb44cf2b9ad 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -165,6 +165,9 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|m
[(){},*:<>;=%/|+\!\?\.-] { return yytext[0]; }
/* ignore pp-directives */
+^{HWS}"#"{HWS}[a-z_]+([^\n]*"\\"\n)+[^\n]*\n {
+ update_lineno (yytext, yyleng);
+}
^{HWS}"#"{HWS}[a-z_]+[^\n]*\n {lexer_line.line++;}
. {
diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc
index dc120e6da5af6..dbc3c7e8fdc88 100644
--- a/gcc/ipa-inline.cc
+++ b/gcc/ipa-inline.cc
@@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "ipa-strub.h"
/* Inliner uses greedy algorithm to inline calls in a priority order.
Badness is used as the key in a Fibonacci heap which roughly corresponds
@@ -443,6 +444,11 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
inlinable = false;
}
+ if (inlinable && !strub_inlinable_to_p (callee, caller))
+ {
+ e->inline_failed = CIF_UNSPECIFIED;
+ inlinable = false;
+ }
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc
index 6730f4f9d0e31..1a7285ff5dcf8 100644
--- a/gcc/ipa-split.cc
+++ b/gcc/ipa-split.cc
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-fnsummary.h"
#include "cfgloop.h"
#include "attribs.h"
+#include "ipa-strub.h"
/* Per basic block info. */
@@ -1811,6 +1812,12 @@ execute_split_functions (void)
"section.\n");
return 0;
}
+ if (!strub_splittable_p (node))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not splitting: function is a strub context.\n");
+ return 0;
+ }
/* We enforce splitting after loop headers when profile info is not
available. */
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
new file mode 100644
index 0000000000000..293bec132b885
--- /dev/null
+++ b/gcc/ipa-strub.cc
@@ -0,0 +1,3573 @@
+/* strub (stack scrubbing) support.
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "tree-cfg.h"
+#include "cfghooks.h"
+#include "cfgloop.h"
+#include "cfgcleanup.h"
+#include "tree-eh.h"
+#include "except.h"
+#include "builtins.h"
+#include "attribs.h"
+#include "tree-inline.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "ipa-fnsummary.h"
+#include "gimple-fold.h"
+#include "fold-const.h"
+#include "gimple-walk.h"
+#include "tree-dfa.h"
+#include "langhooks.h"
+#include "calls.h"
+#include "vec.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "alias.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "ipa-strub.h"
+#include "symtab-thunks.h"
+#include "attr-fnspec.h"
+
+/* This file introduces two passes that, together, implement
+ machine-independent stack scrubbing, strub for short. It arranges
+ for stack frames that have strub enabled to be zeroed-out after
+ relinquishing control to a caller, whether by returning or by
+ propagating an exception. This admittedly unusual design decision
+ was driven by exception support (one needs a stack frame to be
+ active to propagate exceptions out of it), and it enabled an
+ implementation that is entirely machine-independent (no custom
+ epilogue code is required).
+
+ Strub modes can be selected for stack frames by attaching attribute
+ strub to functions or to variables (to their types, actually).
+ Different strub modes, with different implementation details, are
+ available, and they can be selected by an argument to the strub
+ attribute. When enabled by strub-enabled variables, whether by
+ accessing (as in reading from) statically-allocated ones, or by
+ introducing (as in declaring) automatically-allocated ones, a
+ suitable mode is selected automatically.
+
+ At-calls mode modifies the interface of a function, adding a stack
+ watermark argument, that callers use to clean up the stack frame of
+ the called function. Because of the interface change, it can only
+ be used when explicitly selected, or when a function is internal to
+ a translation unit. Strub-at-calls function types are distinct
+ from their original types (they're not modified in-place), and they
+ are not interchangeable with other function types.
+
+ Internal mode, in turn, does not modify the type or the interface
+ of a function. It is currently implemented by turning the function
+ into a wrapper, moving the function body to a separate wrapped
+ function, and scrubbing the wrapped body's stack in the wrapper.
+ Internal-strub function types are mostly interface-compatible with
+ other strub modes, namely callable (from strub functions, though
+ not strub-enabled) and disabled (not callable from strub
+ functions).
+
+ Always_inline functions can be strub functions, but they can only
+ be called from other strub functions, because strub functions must
+ never be inlined into non-strub functions. Internal and at-calls
+ modes are indistinguishable when it comes to always_inline
+ functions: they will necessarily be inlined into another strub
+ function, and will thus be integrated into the caller's stack
+ frame, whatever the mode. (Contrast with non-always_inline strub
+ functions: an at-calls function can be called from other strub
+ functions, ensuring no discontinuity in stack erasing, whereas an
+ internal-strub function can only be called from other strub
+ functions if it happens to be inlined, or if -fstrub=relaxed mode
+ is in effect (that's the default). In -fstrub=strict mode,
+ internal-strub functions are not callable from strub functions,
+ because the wrapper itself is not strubbed.
+
+ The implementation involves two simple-IPA passes. The earliest
+ one, strub-mode, assigns strub modes to functions. It needs to run
+ before any inlining, so that we can prevent inlining of strub
+ functions into non-strub functions. It notes explicit strub mode
+ requests, enables strub in response to strub variables and testing
+ options, and flags unsatisfiable requests.
+
+ Three possibilities of unsatisfiable requests come to mind: (a)
+ when a strub mode is explicitly selected, but the function uses
+ features that make it ineligible for that mode (e.g. at-calls rules
+ out calling __builtin_apply_args, because of the interface changes,
+ and internal mode rules out noclone or otherwise non-versionable
+ functions, non-default varargs, non-local or forced labels, and
+ functions with far too many arguments); (b) when some strub mode
+ must be enabled because of a strub variable, but the function is
+ not eligible or not viable for any mode; and (c) when
+ -fstrub=strict is enabled, and calls are found in strub functions
+ to functions that are not callable from strub contexts.
+ compute_strub_mode implements (a) and (b), and verify_strub
+ implements (c).
+
+ The second IPA pass modifies interfaces of at-calls-strub functions
+ and types, introduces strub calls in and around them. and splits
+ internal-strub functions. It is placed after early inlining, so
+ that even internal-strub functions get a chance of being inlined
+ into other strub functions, but before non-early inlining, so that
+ internal-strub wrapper functions still get a chance of inlining
+ after splitting.
+
+ Wrappers avoid duplicating the copying of large arguments again by
+ passing them by reference to the wrapped bodies. This involves
+ occasional SSA rewriting of address computations, because of the
+ additional indirection. Besides these changes, and the
+ introduction of the stack watermark parameter, wrappers and wrapped
+ functions cooperate to handle variable argument lists (performing
+ va_start in the wrapper, passing the list as an argument, and
+ replacing va_start calls in the wrapped body with va_copy), and
+ __builtin_apply_args (also called in the wrapper and passed to the
+ wrapped body as an argument).
+
+ Strub bodies (both internal-mode wrapped bodies, and at-calls
+ functions) always start by adjusting the watermark parameter, by
+ calling __builtin___strub_update. The compiler inserts them in the
+ main strub pass. Allocations of additional stack space for the
+ frame (__builtin_alloca) are also followed by watermark updates.
+ Stack space temporarily allocated to pass arguments to other
+ functions, released right after the call, is not regarded as part
+ of the frame. Around calls to them, i.e., in internal-mode
+ wrappers and at-calls callers (even calls through pointers), calls
+ to __builtin___strub_enter and __builtin___strub_leave are
+ inserted, the latter as a __finally block, so that it runs at
+ regular and exceptional exit paths. strub_enter only initializes
+ the stack watermark, and strub_leave is where the scrubbing takes
+ place, overwriting with zeros the stack space from the top of the
+ stack to the watermark.
+
+ These calls can be optimized in various cases. In
+ pass_ipa_strub::adjust_at_calls_call, for example, we enable
+ tail-calling and other optimized calls from one strub body to
+ another by passing on the watermark parameter. The builtins
+ themselves may undergo inline substitution during expansion,
+ dependign on optimization levels. This involves dealing with stack
+ red zones (when the builtins are called out-of-line, the red zone
+ cannot be used) and other ugly details related with inlining strub
+ bodies into other strub bodies (see expand_builtin_strub_update).
+ expand_builtin_strub_leave may even perform partial inline
+ substitution. */
+
+/* Const and pure functions that gain a watermark parameter for strub purposes
+ are still regarded as such, which may cause the inline expansions of the
+ __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
+ us to inform the backend about requirements and side effects of the call, but
+ call_fusage building in calls.c:expand_call does not even look at
+ attr_fnspec, so we resort to asm loads and updates to attain an equivalent
+ effect. Once expand_call gains the ability to issue extra memory uses and
+ clobbers based on pure/const function's fnspec, we can define this to 1. */
+#define ATTR_FNSPEC_DECONST_WATERMARK 0
+
+enum strub_mode {
+ /* This mode denotes a regular function, that does not require stack
+ scrubbing (strubbing). It may call any other functions, but if
+ it calls AT_CALLS (or WRAPPED) ones, strubbing logic is
+ automatically introduced around those calls (the latter, by
+ inlining INTERNAL wrappers). */
+ STRUB_DISABLED = 0,
+
+ /* This denotes a function whose signature is (to be) modified to
+ take an extra parameter, for stack use annotation, and its
+ callers must initialize and pass that argument, and perform the
+ strubbing. Functions that are explicitly marked with attribute
+ strub must have the mark visible wherever the function is,
+ including aliases, and overriders and overriding methods.
+ Functions that are implicitly marked for strubbing, for accessing
+ variables explicitly marked as such, will only select this
+ strubbing method if they are internal to a translation unit. It
+ can only be inlined into other strubbing functions, i.e.,
+ STRUB_AT_CALLS or STRUB_WRAPPED. */
+ STRUB_AT_CALLS = 1,
+
+ /* This denotes a function that is to perform strubbing internally,
+ without any changes to its interface (the function is turned into
+ a strubbing wrapper, and its original body is moved to a separate
+ STRUB_WRAPPED function, with a modified interface). Functions
+ may be explicitly marked with attribute strub(2), and the
+ attribute must be visible at the point of definition. Functions
+ that are explicitly marked for strubbing, for accessing variables
+ explicitly marked as such, may select this strubbing mode if
+ their interface cannot change, e.g. because its interface is
+ visible to other translation units, directly, by indirection
+ (having its address taken), inheritance, etc. Functions that use
+ this method must not have the noclone attribute, nor the noipa
+ one. Functions marked as always_inline may select this mode, but
+ they are NOT wrapped, they remain unchanged, and are only inlined
+ into strubbed contexts. Once non-always_inline functions are
+ wrapped, the wrapper becomes STRUB_WRAPPER, and the wrapped becomes
+ STRUB_WRAPPED. */
+ STRUB_INTERNAL = 2,
+
+ /* This denotes a function whose stack is not strubbed, but that is
+ nevertheless explicitly or implicitly marked as callable from strubbing
+ functions. Normally, only STRUB_AT_CALLS (and STRUB_INTERNAL ->
+ STRUB_WRAPPED) functions can be called from strubbing contexts (bodies of
+ STRUB_AT_CALLS, STRUB_INTERNAL and STRUB_WRAPPED functions), but attribute
+ strub(3) enables other functions to be (indirectly) called from these
+ contexts. Some builtins and internal functions may be implicitly marked as
+ STRUB_CALLABLE. */
+ STRUB_CALLABLE = 3,
+
+ /* This denotes the function that took over the body of a
+ STRUB_INTERNAL function. At first, it's only called by its
+ wrapper, but the wrapper may be inlined. The wrapped function,
+ in turn, can only be inlined into other functions whose stack
+ frames are strubbed, i.e., that are STRUB_WRAPPED or
+ STRUB_AT_CALLS. */
+ STRUB_WRAPPED = -1,
+
+ /* This denotes the wrapper function that replaced the STRUB_INTERNAL
+ function. This mode overrides the STRUB_INTERNAL mode at the time the
+ internal to-be-wrapped function becomes a wrapper, so that inlining logic
+ can tell one from the other. */
+ STRUB_WRAPPER = -2,
+
+ /* This denotes an always_inline function that requires strubbing. It can
+ only be called from, and inlined into, other strubbing contexts. */
+ STRUB_INLINABLE = -3,
+
+ /* This denotes a function that accesses strub variables, so it would call for
+ internal strubbing (whether or not it's eligible for that), but since
+ at-calls strubbing is viable, that's selected as an optimization. This
+ mode addresses the inconvenience that such functions may have different
+ modes selected depending on optimization flags, and get a different
+ callable status depending on that choice: if we assigned them
+ STRUB_AT_CALLS mode, they would be callable when optimizing, whereas
+ STRUB_INTERNAL would not be callable. */
+ STRUB_AT_CALLS_OPT = -4,
+
+};
+
+/* Look up a strub attribute in TYPE, and return it. */
+
+static tree
+get_strub_attr_from_type (tree type)
+{
+ return lookup_attribute ("strub", TYPE_ATTRIBUTES (type));
+}
+
+/* Look up a strub attribute in DECL or in its type, and return it. */
+
+static tree
+get_strub_attr_from_decl (tree decl)
+{
+ tree ret = lookup_attribute ("strub", DECL_ATTRIBUTES (decl));
+ if (ret)
+ return ret;
+ return get_strub_attr_from_type (TREE_TYPE (decl));
+}
+
+#define STRUB_ID_COUNT 8
+#define STRUB_IDENT_COUNT 3
+#define STRUB_TYPE_COUNT 5
+
+#define STRUB_ID_BASE 0
+#define STRUB_IDENT_BASE (STRUB_ID_BASE + STRUB_ID_COUNT)
+#define STRUB_TYPE_BASE (STRUB_IDENT_BASE + STRUB_IDENT_COUNT)
+#define STRUB_CACHE_SIZE (STRUB_TYPE_BASE + STRUB_TYPE_COUNT)
+
+/* Keep the strub mode and temp identifiers and types from being GC'd. */
+static GTY((deletable)) tree strub_cache[STRUB_CACHE_SIZE];
+
+/* Define a function to cache identifier ID, to be used as a strub attribute
+ parameter for a strub mode named after NAME. */
+#define DEF_STRUB_IDS(IDX, NAME, ID) \
+static inline tree get_strub_mode_id_ ## NAME () { \
+ int idx = STRUB_ID_BASE + IDX; \
+ tree identifier = strub_cache[idx]; \
+ if (!identifier) \
+ strub_cache[idx] = identifier = get_identifier (ID); \
+ return identifier; \
+}
+/* Same as DEF_STRUB_IDS, but use the string expansion of NAME as ID. */
+#define DEF_STRUB_ID(IDX, NAME) \
+ DEF_STRUB_IDS (IDX, NAME, #NAME)
+
+/* Define functions for each of the strub mode identifiers.
+ Expose dashes rather than underscores. */
+DEF_STRUB_ID (0, disabled)
+DEF_STRUB_IDS (1, at_calls, "at-calls")
+DEF_STRUB_ID (2, internal)
+DEF_STRUB_ID (3, callable)
+DEF_STRUB_ID (4, wrapped)
+DEF_STRUB_ID (5, wrapper)
+DEF_STRUB_ID (6, inlinable)
+DEF_STRUB_IDS (7, at_calls_opt, "at-calls-opt")
+
+/* Release the temporary macro names. */
+#undef DEF_STRUB_IDS
+#undef DEF_STRUB_ID
+
+/* Return the identifier corresponding to strub MODE. */
+
+static tree
+get_strub_mode_attr_parm (enum strub_mode mode)
+{
+ switch (mode)
+ {
+ case STRUB_DISABLED:
+ return get_strub_mode_id_disabled ();
+
+ case STRUB_AT_CALLS:
+ return get_strub_mode_id_at_calls ();
+
+ case STRUB_INTERNAL:
+ return get_strub_mode_id_internal ();
+
+ case STRUB_CALLABLE:
+ return get_strub_mode_id_callable ();
+
+ case STRUB_WRAPPED:
+ return get_strub_mode_id_wrapped ();
+
+ case STRUB_WRAPPER:
+ return get_strub_mode_id_wrapper ();
+
+ case STRUB_INLINABLE:
+ return get_strub_mode_id_inlinable ();
+
+ case STRUB_AT_CALLS_OPT:
+ return get_strub_mode_id_at_calls_opt ();
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the parmeters (TREE_VALUE) for a strub attribute of MODE.
+ We know we use a single parameter, so we bypass the creation of a
+ tree list. */
+
+static tree
+get_strub_mode_attr_value (enum strub_mode mode)
+{
+ return get_strub_mode_attr_parm (mode);
+}
+
+/* Determine whether ID is a well-formed strub mode-specifying attribute
+ parameter for a function (type). Only user-visible modes are accepted, and
+ ID must be non-NULL.
+
+ For unacceptable parms, return 0, otherwise a nonzero value as below.
+
+ If the parm enables strub, return positive, otherwise negative.
+
+ If the affected type must be a distinct, incompatible type,return an integer
+ of absolute value 2, otherwise 1. */
+
+int
+strub_validate_fn_attr_parm (tree id)
+{
+ int ret;
+ const char *s = NULL;
+ size_t len = 0;
+
+ /* do NOT test for NULL. This is only to be called with non-NULL arguments.
+ We assume that the strub parameter applies to a function, because only
+ functions accept an explicit argument. If we accepted NULL, and we
+ happened to be called to verify the argument for a variable, our return
+ values would be wrong. */
+ if (TREE_CODE (id) == STRING_CST)
+ {
+ s = TREE_STRING_POINTER (id);
+ len = TREE_STRING_LENGTH (id) - 1;
+ }
+ else if (TREE_CODE (id) == IDENTIFIER_NODE)
+ {
+ s = IDENTIFIER_POINTER (id);
+ len = IDENTIFIER_LENGTH (id);
+ }
+ else
+ return 0;
+
+ enum strub_mode mode;
+
+ if (len != 8)
+ return 0;
+
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ ret = -1;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ ret = 2;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ ret = 1;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ ret = -2;
+ break;
+
+ default:
+ /* Other parms are for internal use only. */
+ return 0;
+ }
+
+ tree mode_id = get_strub_mode_attr_parm (mode);
+
+ if (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id != mode_id
+ : strncmp (s, IDENTIFIER_POINTER (mode_id), len) != 0)
+ return 0;
+
+ return ret;
+}
+
+/* Return the strub mode from STRUB_ATTR. VAR_P should be TRUE if the attribute
+ is taken from a variable, rather than from a function, or a type thereof. */
+
+static enum strub_mode
+get_strub_mode_from_attr (tree strub_attr, bool var_p = false)
+{
+ enum strub_mode mode = STRUB_DISABLED;
+
+ if (strub_attr)
+ {
+ if (!TREE_VALUE (strub_attr))
+ mode = !var_p ? STRUB_AT_CALLS : STRUB_INTERNAL;
+ else
+ {
+ gcc_checking_assert (!var_p);
+ tree id = TREE_VALUE (strub_attr);
+ if (TREE_CODE (id) == TREE_LIST)
+ id = TREE_VALUE (id);
+ const char *s = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_POINTER (id)
+ : IDENTIFIER_POINTER (id));
+ size_t len = (TREE_CODE (id) == STRING_CST
+ ? TREE_STRING_LENGTH (id) - 1
+ : IDENTIFIER_LENGTH (id));
+
+ switch (len)
+ {
+ case 7:
+ switch (s[6])
+ {
+ case 'r':
+ mode = STRUB_WRAPPER;
+ break;
+
+ case 'd':
+ mode = STRUB_WRAPPED;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 8:
+ switch (s[0])
+ {
+ case 'd':
+ mode = STRUB_DISABLED;
+ break;
+
+ case 'a':
+ mode = STRUB_AT_CALLS;
+ break;
+
+ case 'i':
+ mode = STRUB_INTERNAL;
+ break;
+
+ case 'c':
+ mode = STRUB_CALLABLE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 9:
+ mode = STRUB_INLINABLE;
+ break;
+
+ case 12:
+ mode = STRUB_AT_CALLS_OPT;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert (TREE_CODE (id) == IDENTIFIER_NODE
+ ? id == get_strub_mode_attr_parm (mode)
+ : strncmp (IDENTIFIER_POINTER
+ (get_strub_mode_attr_parm (mode)),
+ s, len) == 0);
+ }
+ }
+
+ return mode;
+}
+
+/* Look up, decode and return the strub mode associated with FNDECL. */
+
+static enum strub_mode
+get_strub_mode_from_fndecl (tree fndecl)
+{
+ return get_strub_mode_from_attr (get_strub_attr_from_decl (fndecl));
+}
+
+/* Look up, decode and return the strub mode associated with NODE. */
+
+static enum strub_mode
+get_strub_mode (cgraph_node *node)
+{
+ return get_strub_mode_from_fndecl (node->decl);
+}
+
+/* Look up, decode and return the strub mode associated with TYPE. */
+
+static enum strub_mode
+get_strub_mode_from_type (tree type)
+{
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (type);
+ tree attr = get_strub_attr_from_type (type);
+
+ if (attr)
+ return get_strub_mode_from_attr (attr, var_p);
+
+ if (flag_strub >= -1 && !var_p)
+ return STRUB_CALLABLE;
+
+ return STRUB_DISABLED;
+}
+
+\f
+/* Return TRUE iff NODE calls builtin va_start. */
+
+static bool
+calls_builtin_va_start_p (cgraph_node *node)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (fndecl_built_in_p (cdecl, BUILT_IN_VA_START))
+ return true;
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE calls builtin apply_args, and optionally REPORT it. */
+
+static bool
+calls_builtin_apply_args_p (cgraph_node *node, bool report = false)
+{
+ bool result = false;
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!fndecl_built_in_p (cdecl, BUILT_IN_APPLY_ARGS))
+ continue;
+
+ result = true;
+
+ if (!report)
+ break;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "at-calls %<strub%> does not support call to %qD",
+ cdecl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE carries the always_inline attribute. */
+
+static inline bool
+strub_always_inline_p (cgraph_node *node)
+{
+ return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
+}
+
+/* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
+ optionally REPORT the reasons for ineligibility. */
+
+static inline bool
+can_strub_p (cgraph_node *node, bool report = false)
+{
+ bool result = true;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<noipa%>",
+ node->decl);
+ }
+
+ /* We can't, and don't want to vectorize the watermark and other
+ strub-introduced parms. */
+ if (lookup_attribute ("simd", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because of attribute %<simd%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE is eligible for at-calls strub, and optionally REPORT
+ the reasons for ineligibility. Besides general non-eligibility for
+ strub-enabled modes, at-calls rules out calling builtin apply_args. */
+
+static bool
+can_strub_at_calls_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ return !calls_builtin_apply_args_p (node, report);
+}
+
+/* Return TRUE iff the called function (pointer or, if available,
+ decl) undergoes a significant type conversion for the call. Strub
+ mode changes between function types, and other non-useless type
+ conversions, are regarded as significant. When the function type
+ is overridden, the effective strub mode for the call is that of the
+ call fntype, rather than that of the pointer or of the decl.
+ Functions called with type overrides cannot undergo type changes;
+ it's as if their address was taken, so they're considered
+ non-viable for implicit at-calls strub mode. */
+
+static inline bool
+strub_call_fntype_override_p (const gcall *gs)
+{
+ if (gimple_call_internal_p (gs))
+ return false;
+ tree fn_type = TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+ if (tree decl = gimple_call_fndecl (gs))
+ fn_type = TREE_TYPE (decl);
+
+ /* We do NOT want to take the mode from the decl here. This
+ function is used to tell whether we can change the strub mode of
+ a function, and whether the effective mode for the call is to be
+ taken from the decl or from an overrider type. When the strub
+ mode is explicitly declared, or overridden with a type cast, the
+ difference will be noticed in function types. However, if the
+ strub mode is implicit due to e.g. strub variables or -fstrub=*
+ command-line flags, we will adjust call types along with function
+ types. In either case, the presence of type or strub mode
+ overriders in calls will prevent a function from having its strub
+ modes changed in ways that would imply type changes, but taking
+ strub modes from decls would defeat this, since we set strub
+ modes and then call this function to tell whether the original
+ type was overridden to decide whether to adjust the call. We
+ need the answer to be about the type, not the decl. */
+ enum strub_mode mode = get_strub_mode_from_type (fn_type);
+ return (get_strub_mode_from_type (gs->u.fntype) != mode
+ || !useless_type_conversion_p (gs->u.fntype, fn_type));
+}
+
+/* Return TRUE iff NODE is called directly with a type override. */
+
+static bool
+called_directly_with_type_override_p (cgraph_node *node, void *)
+{
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ if (e->call_stmt && strub_call_fntype_override_p (e->call_stmt))
+ return true;
+
+ return false;
+}
+
+/* Return TRUE iff NODE or any other nodes aliased to it are called
+ with type overrides. We can't safely change the type of such
+ functions. */
+
+static bool
+called_with_type_override_p (cgraph_node *node)
+{
+ return (node->call_for_symbol_thunks_and_aliases
+ (called_directly_with_type_override_p, NULL, true, true));
+}
+
+/* Symbolic macro for the max number of arguments that internal strub may add to
+ a function. */
+
+#define STRUB_INTERNAL_MAX_EXTRA_ARGS 3
+
+/* We can't perform internal strubbing if the function body involves certain
+ features:
+
+ - a non-default __builtin_va_start (e.g. x86's __builtin_ms_va_start) is
+ currently unsupported because we can't discover the corresponding va_copy and
+ va_end decls in the wrapper, and we don't convey the alternate variable
+ arguments ABI to the modified wrapped function. The default
+ __builtin_va_start is supported by calling va_start/va_end at the wrapper,
+ that takes variable arguments, passing a pointer to the va_list object to the
+ wrapped function, that runs va_copy from it where the original function ran
+ va_start.
+
+ __builtin_next_arg is currently unsupported because the wrapped function
+ won't be a variable argument function. We could process it in the wrapper,
+ that remains a variable argument function, and replace calls in the wrapped
+ body, but we currently don't.
+
+ __builtin_return_address is rejected because it's generally used when the
+ actual caller matters, and introducing a wrapper breaks such uses as those in
+ the unwinder. */
+
+static bool
+can_strub_internally_p (cgraph_node *node, bool report = false)
+{
+ bool result = !report || can_strub_p (node, report);
+
+ if (!result && !report)
+ return result;
+
+ if (!report && strub_always_inline_p (node))
+ return result;
+
+ /* Since we're not changing the function identity proper, just
+ moving its full implementation, we *could* disable
+ fun->cannot_be_copied_reason and/or temporarily drop a noclone
+ attribute, but we'd have to prevent remapping of the labels. */
+ if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%>"
+ " because of attribute %<noclone%>",
+ node->decl);
+ }
+
+ if (node->has_gimple_body_p ())
+ {
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ tree cdecl = e->callee->decl;
+ if (!((fndecl_built_in_p (cdecl, BUILT_IN_VA_START)
+ && cdecl != builtin_decl_explicit (BUILT_IN_VA_START))
+ || fndecl_built_in_p (cdecl, BUILT_IN_NEXT_ARG)
+ || fndecl_built_in_p (cdecl, BUILT_IN_RETURN_ADDRESS)))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (e->call_stmt
+ ? gimple_location (e->call_stmt)
+ : DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it calls %qD",
+ node->decl, cdecl);
+ }
+
+ struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
+ if (fun->has_nonlocal_label)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because it contains a non-local goto target",
+ node->decl);
+ }
+
+ if (fun->has_forced_label_in_static)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for internal %<strub%> "
+ "because the address of a local label escapes",
+ node->decl);
+ }
+
+ /* Catch any other case that would prevent versioning/cloning
+ so as to also have it covered above. */
+ gcc_checking_assert (!result /* || !node->has_gimple_body_p () */
+ || tree_versionable_function_p (node->decl));
+
+
+ /* Label values references are not preserved when copying. If referenced
+ in nested functions, as in 920415-1.c and 920721-4.c their decls get
+ remapped independently. The exclusion below might be too broad, in
+ that we might be able to support correctly cases in which the labels
+ are only used internally in a function, but disconnecting forced labels
+ from their original declarations is undesirable in general. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
+ tree target;
+
+ if (!label_stmt)
+ break;
+
+ target = gimple_label_label (label_stmt);
+
+ if (!FORCED_LABEL (target))
+ continue;
+
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (gimple_location (label_stmt),
+ "internal %<strub%> does not support forced labels");
+ }
+ }
+
+ if (list_length (TYPE_ARG_TYPES (TREE_TYPE (node->decl)))
+ >= (((HOST_WIDE_INT) 1 << IPA_PARAM_MAX_INDEX_BITS)
+ - STRUB_INTERNAL_MAX_EXTRA_ARGS))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD has too many arguments for internal %<strub%>",
+ node->decl);
+ }
+
+ return result;
+}
+
+/* Return TRUE iff NODE has any strub-requiring local variable, or accesses (as
+ in reading) any variable through a strub-requiring type. */
+
+static bool
+strub_from_body_p (cgraph_node *node)
+{
+ if (!node->has_gimple_body_p ())
+ return false;
+
+ /* If any local variable is marked for strub... */
+ unsigned i;
+ tree var;
+ FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (node->decl),
+ i, var)
+ if (get_strub_mode_from_type (TREE_TYPE (var))
+ != STRUB_DISABLED)
+ return true;
+
+ /* Now scan the body for loads with strub-requiring types.
+ ??? Compound types don't propagate the strub requirement to
+ component types. */
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (!gimple_assign_load_p (stmt))
+ continue;
+
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if (get_strub_mode_from_type (TREE_TYPE (rhs))
+ != STRUB_DISABLED)
+ return true;
+ }
+
+ return false;
+}
+
+/* Return TRUE iff node is associated with a builtin that should be callable
+ from strub contexts. */
+
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* This temporarily allocates stack for the call, and we can't reasonably
+ update the watermark for that. Besides, we don't check the actual call
+ target, nor its signature, and it seems to be overkill to as much as
+ try to do so. */
+ case BUILT_IN_APPLY:
+ return false;
+
+ /* Conversely, this shouldn't be called from within strub contexts, since
+ the caller may have had its signature modified. STRUB_INTERNAL is ok,
+ the call will remain in the STRUB_WRAPPER, and removed from the
+ STRUB_WRAPPED clone. */
+ case BUILT_IN_APPLY_ARGS:
+ return false;
+
+ /* ??? Make all other builtins callable. We wish to make any builtin call
+ the compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
+/* Compute the strub mode to be used for NODE. STRUB_ATTR should be the strub
+ attribute,found for NODE, if any. */
+
+static enum strub_mode
+compute_strub_mode (cgraph_node *node, tree strub_attr)
+{
+ enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr);
+
+ gcc_checking_assert (flag_strub >= -2 && flag_strub <= 3);
+
+ /* Symbolic encodings of the -fstrub-* flags. */
+ /* Enable strub when explicitly requested through attributes to functions or
+ variables, reporting errors if the requests cannot be satisfied. */
+ const bool strub_flag_auto = flag_strub < 0;
+ /* strub_flag_auto with strub call verification; without this, functions are
+ implicitly callable. */
+ const bool strub_flag_strict = flag_strub < -1;
+ /* Disable strub altogether, ignore attributes entirely. */
+ const bool strub_flag_disabled = flag_strub == 0;
+ /* On top of _auto, also enable strub implicitly for functions that can
+ safely undergo at-calls strubbing. Internal mode will still be used in
+ functions that request it explicitly with attribute strub(2), or when the
+ function body requires strubbing and at-calls strubbing is not viable. */
+ const bool strub_flag_at_calls = flag_strub == 1;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo internal strubbing. At-calls mode will still be used in
+ functions that requiest it explicitly with attribute strub() or strub(1),
+ or when the function body requires strubbing and internal strubbing is not
+ viable. */
+ const bool strub_flag_internal = flag_strub == 2;
+ /* On top of default, also enable strub implicitly for functions that can
+ safely undergo strubbing in either mode. When both modes are viable,
+ at-calls is preferred. */
+ const bool strub_flag_either = flag_strub == 3;
+ /* Besides the default behavior, enable strub implicitly for all viable
+ functions. */
+ const bool strub_flag_viable = flag_strub > 0;
+
+ /* The consider_* variables should be TRUE if selecting the corresponding
+ strub modes would be consistent with requests from attributes and command
+ line flags. Attributes associated with functions pretty much mandate a
+ selection, and should report an error if not satisfied; strub_flag_auto
+ implicitly enables some viable strub mode if that's required by references
+ to variables marked for strub; strub_flag_viable enables strub if viable
+ (even when favoring one mode, body-requested strub can still be satisfied
+ by either mode), and falls back to callable, silently unless variables
+ require strubbing. */
+
+ const bool consider_at_calls
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_AT_CALLS
+ : true));
+ const bool consider_internal
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_INTERNAL
+ : true));
+
+ const bool consider_callable
+ = (!strub_flag_disabled
+ && (strub_attr
+ ? req_mode == STRUB_CALLABLE
+ : (!strub_flag_strict
+ || strub_callable_builtin_p (node))));
+
+ /* This is a shorthand for either strub-enabled mode. */
+ const bool consider_strub
+ = (consider_at_calls || consider_internal);
+
+ /* We can cope with always_inline functions even with noipa and noclone,
+ because we just leave them alone. */
+ const bool is_always_inline
+ = strub_always_inline_p (node);
+
+ /* Strubbing in general, and each specific strub mode, may have its own set of
+ requirements. We require noipa for strubbing, either because of cloning
+ required for internal strub, or because of caller enumeration required for
+ at-calls strub. We don't consider the at-calls mode eligible if it's not
+ even considered, it has no further requirements. Internal mode requires
+ cloning and the absence of certain features in the body and, like at-calls,
+ it's not eligible if it's not even under consideration.
+
+ ??? Do we need target hooks for further constraints? E.g., x86's
+ "interrupt" attribute breaks internal strubbing because the wrapped clone
+ carries the attribute and thus isn't callable; in this case, we could use a
+ target hook to adjust the clone instead. */
+ const bool strub_eligible
+ = (consider_strub
+ && (is_always_inline || can_strub_p (node)));
+ const bool at_calls_eligible
+ = (consider_at_calls && strub_eligible
+ && can_strub_at_calls_p (node));
+ const bool internal_eligible
+ = (consider_internal && strub_eligible
+ && (is_always_inline
+ || can_strub_internally_p (node)));
+
+ /* In addition to the strict eligibility requirements, some additional
+ constraints are placed on implicit selection of certain modes. These do
+ not prevent the selection of a mode if explicitly specified as part of a
+ function interface (the strub attribute), but they may prevent modes from
+ being selected by the command line or by function bodies. The only actual
+ constraint is on at-calls mode: since we change the function's exposed
+ signature, we won't do it implicitly if the function can possibly be used
+ in ways that do not expect the signature change, e.g., if the function is
+ available to or interposable by other units, if its address is taken,
+ etc. */
+ const bool at_calls_viable
+ = (at_calls_eligible
+ && (strub_attr
+ || (node->has_gimple_body_p ()
+ && (!node->externally_visible
+ || (node->binds_to_current_def_p ()
+ && node->can_be_local_p ()))
+ && node->only_called_directly_p ()
+ && !called_with_type_override_p (node))));
+ const bool internal_viable
+ = (internal_eligible);
+
+ /* Shorthand. */
+ const bool strub_viable
+ = (at_calls_viable || internal_viable);
+
+ /* We wish to analyze the body, to look for implicit requests for strub, both
+ to implicitly enable it when the body calls for it, and to report errors if
+ the body calls for it but neither mode is viable (even if that follows from
+ non-eligibility because of the explicit specification of some non-strubbing
+ mode). We can refrain from scanning the body only in rare circumstances:
+ when strub is enabled by a function attribute (scanning might be redundant
+ in telling us to also enable it), and when we are enabling strub implicitly
+ but there are non-viable modes: we want to know whether strubbing is
+ required, to fallback to another mode, even if we're only enabling a
+ certain mode, or, when either mode would do, to report an error if neither
+ happens to be viable. */
+ const bool analyze_body
+ = (strub_attr
+ ? !consider_strub
+ : (strub_flag_auto
+ || (strub_flag_viable && (!at_calls_viable && !internal_viable))
+ || (strub_flag_either && !strub_viable)));
+
+ /* Cases in which strubbing is enabled or disabled by strub_flag_auto.
+ Unsatisfiable requests ought to be reported. */
+ const bool strub_required
+ = ((strub_attr && consider_strub)
+ || (analyze_body && strub_from_body_p (node)));
+
+ /* Besides the required cases, we want to abide by the requests to enabling on
+ an if-viable basis. */
+ const bool strub_enable
+ = (strub_required
+ || (strub_flag_at_calls && at_calls_viable)
+ || (strub_flag_internal && internal_viable)
+ || (strub_flag_either && strub_viable));
+
+ /* And now we're finally ready to select a mode that abides by the viability
+ and eligibility constraints, and that satisfies the strubbing requirements
+ and requests, subject to the constraints. If both modes are viable and
+ strub is to be enabled, pick STRUB_AT_CALLS unless STRUB_INTERNAL was named
+ as preferred. */
+ const enum strub_mode mode
+ = ((strub_enable && is_always_inline)
+ ? (strub_required ? STRUB_INLINABLE : STRUB_CALLABLE)
+ : (strub_enable && internal_viable
+ && (strub_flag_internal || !at_calls_viable))
+ ? STRUB_INTERNAL
+ : (strub_enable && at_calls_viable)
+ ? (strub_required && !strub_attr
+ ? STRUB_AT_CALLS_OPT
+ : STRUB_AT_CALLS)
+ : consider_callable
+ ? STRUB_CALLABLE
+ : STRUB_DISABLED);
+
+ switch (mode)
+ {
+ case STRUB_CALLABLE:
+ if (is_always_inline)
+ break;
+ /* Fall through. */
+
+ case STRUB_DISABLED:
+ if (strub_enable && !strub_attr)
+ {
+ gcc_checking_assert (analyze_body);
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD requires %<strub%>,"
+ " but no viable %<strub%> mode was found",
+ node->decl);
+ break;
+ }
+ /* Fall through. */
+
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ /* Differences from an mode requested through a function attribute are
+ reported in set_strub_mode_to. */
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ /* Functions that select this mode do so because of references to strub
+ variables. Even if we choose at-calls as an optimization, the
+ requirements for internal strub must still be satisfied. Optimization
+ options may render implicit at-calls strub not viable (-O0 sets
+ force_output for static non-inline functions), and it would not be good
+ if changing optimization options turned a well-formed into an
+ ill-formed one. */
+ if (!internal_viable)
+ can_strub_internally_p (node, true);
+ break;
+
+ case STRUB_WRAPPED:
+ case STRUB_WRAPPER:
+ default:
+ gcc_unreachable ();
+ }
+
+ return mode;
+}
+
+/* Set FNDT's strub mode to MODE; FNDT may be a function decl or
+ function type. If OVERRIDE, do not check whether a mode is already
+ set. */
+
+static void
+strub_set_fndt_mode_to (tree fndt, enum strub_mode mode, bool override)
+{
+ gcc_checking_assert (override
+ || !(DECL_P (fndt)
+ ? get_strub_attr_from_decl (fndt)
+ : get_strub_attr_from_type (fndt)));
+
+ tree attr = tree_cons (get_identifier ("strub"),
+ get_strub_mode_attr_value (mode),
+ NULL_TREE);
+ tree *attrp = NULL;
+ if (DECL_P (fndt))
+ {
+ gcc_checking_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndt)));
+ attrp = &DECL_ATTRIBUTES (fndt);
+ }
+ else if (FUNC_OR_METHOD_TYPE_P (fndt))
+ attrp = &TYPE_ATTRIBUTES (fndt);
+ else
+ gcc_unreachable ();
+
+ TREE_CHAIN (attr) = *attrp;
+ *attrp = attr;
+}
+
+/* Set FNDT's strub mode to callable.
+ FNDT may be a function decl or a function type. */
+
+void
+strub_make_callable (tree fndt)
+{
+ strub_set_fndt_mode_to (fndt, STRUB_CALLABLE, false);
+}
+
+/* Set NODE to strub MODE. Report incompatibilities between MODE and the mode
+ requested through explicit attributes, and cases of non-eligibility. */
+
+static void
+set_strub_mode_to (cgraph_node *node, enum strub_mode mode)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+ enum strub_mode req_mode = get_strub_mode_from_attr (attr);
+
+ if (attr)
+ {
+ /* Check for and report incompatible mode changes. */
+ if (mode != req_mode
+ && !(req_mode == STRUB_INTERNAL
+ && (mode == STRUB_WRAPPED
+ || mode == STRUB_WRAPPER))
+ && !((req_mode == STRUB_INTERNAL
+ || req_mode == STRUB_AT_CALLS
+ || req_mode == STRUB_CALLABLE)
+ && mode == STRUB_INLINABLE))
+ {
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<strub%> mode %qE selected for %qD, when %qE was requested",
+ get_strub_mode_attr_parm (mode),
+ node->decl,
+ get_strub_mode_attr_parm (req_mode));
+ if (node->alias)
+ {
+ cgraph_node *target = node->ultimate_alias_target ();
+ if (target != node)
+ error_at (DECL_SOURCE_LOCATION (target->decl),
+ "the incompatible selection was determined"
+ " by ultimate alias target %qD",
+ target->decl);
+ }
+
+ /* Report any incompatibilities with explicitly-requested strub. */
+ switch (req_mode)
+ {
+ case STRUB_AT_CALLS:
+ can_strub_at_calls_p (node, true);
+ break;
+
+ case STRUB_INTERNAL:
+ can_strub_internally_p (node, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Drop any incompatible strub attributes leading the decl attribute
+ chain. Return if we find one with the mode we need. */
+ for (;;)
+ {
+ if (mode == req_mode)
+ return;
+
+ if (DECL_ATTRIBUTES (node->decl) != attr)
+ break;
+
+ DECL_ATTRIBUTES (node->decl) = TREE_CHAIN (attr);
+ attr = get_strub_attr_from_decl (node->decl);
+ if (!attr)
+ break;
+
+ req_mode = get_strub_mode_from_attr (attr);
+ }
+ }
+ else if (mode == req_mode)
+ return;
+
+ strub_set_fndt_mode_to (node->decl, mode, attr);
+}
+
+/* Compute and set NODE's strub mode. */
+
+static void
+set_strub_mode (cgraph_node *node)
+{
+ tree attr = get_strub_attr_from_decl (node->decl);
+
+ if (attr)
+ switch (get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ cgraph_node *xnode = node;
+ if (node->alias)
+ xnode = node->ultimate_alias_target ();
+ /* Weakrefs may remain unresolved (the above will return node) if
+ their targets are not defined, so make sure we compute a strub
+ mode for them, instead of defaulting to STRUB_DISABLED and
+ rendering them uncallable. */
+ enum strub_mode mode = (xnode != node && !xnode->alias
+ ? get_strub_mode (xnode)
+ : compute_strub_mode (node, attr));
+
+ set_strub_mode_to (node, mode);
+}
+
+\f
+/* Non-strub functions shouldn't be called from within strub contexts,
+ except through callable ones. Always inline strub functions can
+ only be called from strub functions. */
+
+static bool
+strub_callable_from_p (strub_mode caller_mode, strub_mode callee_mode)
+{
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ return callee_mode != STRUB_INLINABLE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INLINABLE:
+ break;
+
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return (flag_strub >= -1);
+
+ case STRUB_DISABLED:
+ return false;
+
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return TRUE iff CALLEE can be inlined into CALLER. We wish to avoid inlining
+ WRAPPED functions back into their WRAPPERs. More generally, we wish to avoid
+ inlining strubbed functions into non-strubbed ones. CALLER doesn't have to
+ be an immediate caller of CALLEE: the immediate caller may have already been
+ cloned for inlining, and then CALLER may be further up the original call
+ chain. ??? It would be nice if our own caller would retry inlining callee
+ if caller gets inlined. */
+
+bool
+strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller)
+{
+ strub_mode callee_mode = get_strub_mode (callee);
+
+ switch (callee_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ /* When we consider inlining, we've already verified callability, so we
+ can even inline callable and then disabled into a strub context. That
+ will get strubbed along with the context, so it's hopefully not a
+ problem. */
+ return true;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ strub_mode caller_mode = get_strub_mode (caller);
+
+ switch (caller_mode)
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_INLINABLE:
+ case STRUB_AT_CALLS_OPT:
+ return true;
+
+ case STRUB_WRAPPER:
+ case STRUB_DISABLED:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+/* Check that types T1 and T2 are strub-compatible. Return 1 if the strub modes
+ are the same, 2 if they are interchangeable, and 0 otherwise. */
+
+int
+strub_comptypes (tree t1, tree t2)
+{
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
+
+ enum strub_mode m1 = get_strub_mode_from_type (t1);
+ enum strub_mode m2 = get_strub_mode_from_type (t2);
+
+ if (m1 == m2)
+ return 1;
+
+ /* We're dealing with types, so only strub modes that can be selected by
+ attributes in the front end matter. If either mode is at-calls (for
+ functions) or internal (for variables), the conversion is not
+ compatible. */
+ bool var_p = !FUNC_OR_METHOD_TYPE_P (t1);
+ enum strub_mode mr = var_p ? STRUB_INTERNAL : STRUB_AT_CALLS;
+ if (m1 == mr || m2 == mr)
+ return 0;
+
+ return 2;
+}
+
+/* Return the effective strub mode used for CALL, and set *TYPEP to
+ the effective type used for the call. The effective type and mode
+ are those of the callee, unless the call involves a typecast. */
+
+static enum strub_mode
+effective_strub_mode_for_call (gcall *call, tree *typep)
+{
+ tree type;
+ enum strub_mode mode;
+
+ if (strub_call_fntype_override_p (call))
+ {
+ type = gimple_call_fntype (call);
+ mode = get_strub_mode_from_type (type);
+ }
+ else
+ {
+ type = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
+ tree decl = gimple_call_fndecl (call);
+ if (decl)
+ mode = get_strub_mode_from_fndecl (decl);
+ else
+ mode = get_strub_mode_from_type (type);
+ }
+
+ if (typep)
+ *typep = type;
+
+ return mode;
+}
+
+/* Create a distinct copy of the type of NODE's function, and change
+ the fntype of all calls to it with the same main type to the new
+ type. */
+
+static void
+distinctify_node_type (cgraph_node *node)
+{
+ tree old_type = TREE_TYPE (node->decl);
+ tree new_type = build_distinct_type_copy (old_type);
+ tree new_ptr_type = NULL_TREE;
+
+ /* Remap any calls to node->decl that use old_type, or a variant
+ thereof, to new_type as well. We don't look for aliases, their
+ declarations will have their types changed independently, and
+ we'll adjust their fntypes then. */
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ {
+ if (!e->call_stmt)
+ continue;
+ tree fnaddr = gimple_call_fn (e->call_stmt);
+ gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
+ && TREE_OPERAND (fnaddr, 0) == node->decl);
+ if (strub_call_fntype_override_p (e->call_stmt))
+ continue;
+ if (!new_ptr_type)
+ new_ptr_type = build_pointer_type (new_type);
+ TREE_TYPE (fnaddr) = new_ptr_type;
+ gimple_call_set_fntype (e->call_stmt, new_type);
+ }
+
+ TREE_TYPE (node->decl) = new_type;
+}
+
+/* Return TRUE iff TYPE and any variants have the same strub mode. */
+
+static bool
+same_strub_mode_in_variants_p (tree type)
+{
+ enum strub_mode mode = get_strub_mode_from_type (type);
+
+ for (tree other = TYPE_MAIN_VARIANT (type);
+ other != NULL_TREE; other = TYPE_NEXT_VARIANT (other))
+ if (type != other && mode != get_strub_mode_from_type (other))
+ return false;
+
+ /* Check that the canonical type, if set, either is in the same
+ variant chain, or has the same strub mode as type. Also check
+ the variants of the canonical type. */
+ if (TYPE_CANONICAL (type)
+ && (TYPE_MAIN_VARIANT (TYPE_CANONICAL (type))
+ != TYPE_MAIN_VARIANT (type)))
+ {
+ if (mode != get_strub_mode_from_type (TYPE_CANONICAL (type)))
+ return false;
+ else
+ return same_strub_mode_in_variants_p (TYPE_CANONICAL (type));
+ }
+
+ return true;
+}
+
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ /* It's expected that check strub-wise pointer type compatibility of variables
+ and of functions is already taken care of by front-ends, on account of the
+ attribute's being marked as affecting type identity and of the creation of
+ distinct types. */
+
+ /* Check that call targets in strub contexts have strub-callable types. */
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, NULL);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-%<strub%> call in %<strub%> context %qD",
+ node->decl);
+ }
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (!strub_callable_from_p (caller_mode, callee_mode))
+ {
+ if (callee_mode == STRUB_INLINABLE)
+ error_at (gimple_location (e->call_stmt),
+ "calling %<always_inline%> %<strub%> %qD"
+ " in non-%<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else if (fndecl_built_in_p (e->callee->decl, BUILT_IN_APPLY_ARGS)
+ && caller_mode == STRUB_INTERNAL)
+ /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
+ from the STRUB_WRAPPED's strub context. */
+ continue;
+ else if (!strub_call_fntype_override_p (e->call_stmt))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-%<strub%> %qD in %<strub%> context %qD",
+ e->callee->decl, node->decl);
+ else
+ error_at (gimple_location (e->call_stmt),
+ "calling %qD using non-%<strub%> type %qT"
+ " in %<strub%> context %qD",
+ e->callee->decl, callee_fntype, node->decl);
+ }
+ }
+ }
+}
+
+namespace {
+
+/* Define a pass to compute strub modes. */
+const pass_data pass_data_ipa_strub_mode = {
+ SIMPLE_IPA_PASS,
+ "strubm",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ 0, // properties_finish
+};
+
+class pass_ipa_strub_mode : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub_mode (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub_mode, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub_mode (m_ctxt); }
+ virtual bool gate (function *) {
+ /* In relaxed (-3) and strict (-4) settings, that only enable strub at a
+ function or variable attribute's request, the attribute handler changes
+ flag_strub to -1 or -2, respectively, if any strub-enabling occurence of
+ the attribute is found. Therefore, if it remains at -3 or -4, nothing
+ that would enable strub was found, so we can disable it and avoid the
+ overhead. */
+ if (flag_strub < -2)
+ flag_strub = 0;
+ return flag_strub;
+ }
+ virtual unsigned int execute (function *);
+};
+
+/* Define a pass to introduce strub transformations. */
+const pass_data pass_data_ipa_strub = {
+ SIMPLE_IPA_PASS,
+ "strub",
+ OPTGROUP_NONE,
+ TV_NONE,
+ PROP_cfg | PROP_ssa, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // properties_start
+ TODO_update_ssa
+ | TODO_cleanup_cfg
+ | TODO_rebuild_cgraph_edges
+ | TODO_verify_il, // properties_finish
+};
+
+class pass_ipa_strub : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_strub (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_strub, ctxt)
+ {}
+ opt_pass *clone () { return new pass_ipa_strub (m_ctxt); }
+ virtual bool gate (function *) { return flag_strub && !seen_error (); }
+ virtual unsigned int execute (function *);
+
+ /* Define on demand and cache some types we use often. */
+#define DEF_TYPE(IDX, NAME, INIT) \
+ static inline tree get_ ## NAME () { \
+ int idx = STRUB_TYPE_BASE + IDX; \
+ static tree type = strub_cache[idx]; \
+ if (!type) \
+ strub_cache[idx] = type = (INIT); \
+ return type; \
+ }
+
+ /* Use a distinct ptr_type_node to denote the watermark, so that we can
+ recognize it in arg lists and avoid modifying types twice. */
+ DEF_TYPE (0, wmt, build_variant_type_copy (ptr_type_node))
+
+ DEF_TYPE (1, pwmt, build_reference_type (get_wmt ()))
+
+ DEF_TYPE (2, qpwmt,
+ build_qualified_type (get_pwmt (),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+ DEF_TYPE (3, qptr,
+ build_qualified_type (ptr_type_node,
+ TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_CONST))
+
+ DEF_TYPE (4, qpvalst,
+ build_qualified_type (build_reference_type
+ (va_list_type_node),
+ TYPE_QUAL_RESTRICT
+ /* | TYPE_QUAL_CONST */))
+
+#undef DEF_TYPE
+
+ /* Define non-strub builtins on demand. */
+#define DEF_NM_BUILTIN(NAME, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ decl = add_builtin_function \
+ ("__builtin_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ NULL, NULL); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_NM_BUILTIN (stack_address,
+ BUILT_IN_STACK_ADDRESS,
+ (ptr_type_node, NULL))
+
+#undef DEF_NM_BUILTIN
+
+ /* Define strub builtins on demand. */
+#define DEF_SS_BUILTIN(NAME, FNSPEC, CODE, FNTYPELIST) \
+ static tree get_ ## NAME () { \
+ tree decl = builtin_decl_explicit (CODE); \
+ if (!decl) \
+ { \
+ tree type = build_function_type_list FNTYPELIST; \
+ tree attrs = NULL; \
+ if (FNSPEC) \
+ attrs = tree_cons (get_identifier ("fn spec"), \
+ build_tree_list \
+ (NULL_TREE, \
+ build_string (strlen (FNSPEC), \
+ (FNSPEC))), \
+ attrs); \
+ decl = add_builtin_function_ext_scope \
+ ("__builtin___strub_" #NAME, \
+ type, CODE, BUILT_IN_NORMAL, \
+ "__strub_" #NAME, attrs); \
+ TREE_NOTHROW (decl) = true; \
+ set_builtin_decl ((CODE), decl, true); \
+ } \
+ return decl; \
+ }
+
+ DEF_SS_BUILTIN (enter, ". Ot",
+ BUILT_IN___STRUB_ENTER,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (update, ". Wt",
+ BUILT_IN___STRUB_UPDATE,
+ (void_type_node, get_qpwmt (), NULL))
+ DEF_SS_BUILTIN (leave, ". w ",
+ BUILT_IN___STRUB_LEAVE,
+ (void_type_node, get_qpwmt (), NULL))
+
+#undef DEF_SS_BUILTIN
+
+ /* Define strub identifiers on demand. */
+#define DEF_IDENT(IDX, NAME) \
+ static inline tree get_ ## NAME () { \
+ int idx = STRUB_IDENT_BASE + IDX; \
+ tree identifier = strub_cache[idx]; \
+ if (!identifier) \
+ strub_cache[idx] = identifier = get_identifier (".strub." #NAME); \
+ return identifier; \
+ }
+
+ DEF_IDENT (0, watermark_ptr)
+ DEF_IDENT (1, va_list_ptr)
+ DEF_IDENT (2, apply_args)
+
+#undef DEF_IDENT
+
+ static inline int adjust_at_calls_type (tree);
+ static inline void adjust_at_calls_call (cgraph_edge *, int, tree);
+ static inline void adjust_at_calls_calls (cgraph_node *);
+
+ /* Add to SEQ a call to the strub watermark update builtin, taking NODE's
+ location if given. Optionally add the corresponding edge from NODE, with
+ execution frequency COUNT. Return the modified SEQ. */
+
+ static inline gimple_seq
+ call_update_watermark (tree wmptr, cgraph_node *node, profile_count count,
+ gimple_seq seq = NULL)
+ {
+ tree uwm = get_update ();
+ gcall *update = gimple_build_call (uwm, 1, wmptr);
+ if (node)
+ gimple_set_location (update, DECL_SOURCE_LOCATION (node->decl));
+ gimple_seq_add_stmt (&seq, update);
+ if (node)
+ node->create_edge (cgraph_node::get_create (uwm), update, count, false);
+ return seq;
+ }
+
+};
+
+} // anon namespace
+
+/* Gather with this type a collection of parameters that we're turning into
+ explicit references. */
+
+typedef hash_set<tree> indirect_parms_t;
+
+/* Dereference OP's incoming turned-into-reference parm if it's an
+ INDIRECT_PARMS or an ADDR_EXPR thereof. Set *REC and return according to
+ gimple-walking expectations. */
+
+static tree
+maybe_make_indirect (indirect_parms_t &indirect_parms, tree op, int *rec)
+{
+ if (DECL_P (op))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (op))
+ {
+ tree ret = gimple_fold_indirect_ref (op);
+ if (!ret)
+ ret = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (op)),
+ op,
+ build_int_cst (TREE_TYPE (op), 0));
+ return ret;
+ }
+ }
+ else if (TREE_CODE (op) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (op, 0)))
+ {
+ *rec = 0;
+ if (indirect_parms.contains (TREE_OPERAND (op, 0)))
+ {
+ op = TREE_OPERAND (op, 0);
+ return op;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that adds dereferencing to indirect parms. */
+
+static tree
+walk_make_indirect (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ indirect_parms_t &indirect_parms = *(indirect_parms_t *)wi->info;
+
+ if (!*op || TYPE_P (*op))
+ {
+ *rec = 0;
+ return NULL_TREE;
+ }
+
+ if (tree repl = maybe_make_indirect (indirect_parms, *op, rec))
+ {
+ *op = repl;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* A gimple-walking function that turns any non-gimple-val ADDR_EXPRs into a
+ separate SSA. Though addresses of e.g. parameters, and of members thereof,
+ are gimple vals, turning parameters into references, with an extra layer of
+ indirection and thus explicit dereferencing, need to be regimplified. */
+
+static tree
+walk_regimplify_addr_expr (tree *op, int *rec, void *arg)
+{
+ walk_stmt_info *wi = (walk_stmt_info *)arg;
+ gimple_stmt_iterator &gsi = *(gimple_stmt_iterator *)wi->info;
+
+ *rec = 0;
+
+ if (!*op || TREE_CODE (*op) != ADDR_EXPR)
+ return NULL_TREE;
+
+ if (!is_gimple_val (*op))
+ {
+ tree ret = force_gimple_operand_gsi (&gsi, *op, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ gcc_assert (ret != *op);
+ *op = ret;
+ wi->changed = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Turn STMT's PHI arg defs into separate SSA defs if they've become
+ non-gimple_val. Return TRUE if any edge insertions need to be committed. */
+
+static bool
+walk_regimplify_phi (gphi *stmt)
+{
+ bool needs_commit = false;
+
+ for (unsigned i = 0, n = gimple_phi_num_args (stmt); i < n; i++)
+ {
+ tree op = gimple_phi_arg_def (stmt, i);
+ if ((TREE_CODE (op) == ADDR_EXPR
+ && !is_gimple_val (op))
+ /* ??? A PARM_DECL that was addressable in the original function and
+ had its address in PHI nodes, but that became a reference in the
+ wrapped clone would NOT be updated by update_ssa in PHI nodes.
+ Alas, if we were to create a default def for it now, update_ssa
+ would complain that the symbol that needed rewriting already has
+ SSA names associated with it. OTOH, leaving the PARM_DECL alone,
+ it eventually causes errors because it remains unchanged in PHI
+ nodes, but it gets rewritten as expected if it appears in other
+ stmts. So we cheat a little here, and force the PARM_DECL out of
+ the PHI node and into an assignment. It's a little expensive,
+ because we insert it at the edge, which introduces a basic block
+ that's entirely unnecessary, but it works, and the block will be
+ removed as the default def gets propagated back into the PHI node,
+ so the final optimized code looks just as expected. */
+ || (TREE_CODE (op) == PARM_DECL
+ && !TREE_ADDRESSABLE (op)))
+ {
+ tree temp = make_ssa_name (TREE_TYPE (op), stmt);
+ if (TREE_CODE (op) == PARM_DECL)
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (temp, DECL_NAME (op));
+ SET_PHI_ARG_DEF (stmt, i, temp);
+
+ gimple *assign = gimple_build_assign (temp, op);
+ if (gimple_phi_arg_has_location (stmt, i))
+ gimple_set_location (assign, gimple_phi_arg_location (stmt, i));
+ gsi_insert_on_edge (gimple_phi_arg_edge (stmt, i), assign);
+ needs_commit = true;
+ }
+ }
+
+ return needs_commit;
+}
+
+/* Create a reference type to use for PARM when turning it into a reference.
+ NONALIASED causes the reference type to gain its own separate alias set, so
+ that accessing the indirectly-passed parm won'will not add aliasing
+ noise. */
+
+static tree
+build_ref_type_for (tree parm, bool nonaliased = true)
+{
+ gcc_checking_assert (TREE_CODE (parm) == PARM_DECL);
+
+ tree ref_type = build_reference_type (TREE_TYPE (parm));
+
+ if (!nonaliased)
+ return ref_type;
+
+ /* Each PARM turned indirect still points to the distinct memory area at the
+ wrapper, and the reference in unchanging, so we might qualify it, but...
+ const is not really important, since we're only using default defs for the
+ reference parm anyway, and not introducing any defs, and restrict seems to
+ cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that,
+ if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias
+ set seems to not run afoul of this problem, and it hopefully enables the
+ compiler to tell the pointers do point to objects that are not otherwise
+ aliased. */
+ tree qref_type = build_variant_type_copy (ref_type);
+
+ TYPE_ALIAS_SET (qref_type) = new_alias_set ();
+ record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type));
+
+ return qref_type;
+}
+
+/* Add cgraph edges from current_function_decl to callees in SEQ with frequency
+ COUNT, assuming all calls in SEQ are direct. */
+
+static void
+add_call_edges_for_seq (gimple_seq seq, profile_count count)
+{
+ cgraph_node *node = cgraph_node::get_create (current_function_decl);
+
+ for (gimple_stmt_iterator gsi = gsi_start (seq);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ if (!call)
+ continue;
+
+ tree callee = gimple_call_fndecl (call);
+ gcc_checking_assert (callee);
+ node->create_edge (cgraph_node::get_create (callee), call, count, false);
+ }
+}
+
+/* Insert SEQ after the call at GSI, as if the call was in a try block with SEQ
+ as finally, i.e., SEQ will run after the call whether it returns or
+ propagates an exception. This handles block splitting, EH edge and block
+ creation, noreturn and nothrow optimizations, and even throwing calls without
+ preexisting local handlers. */
+
+static void
+gsi_insert_finally_seq_after_call (gimple_stmt_iterator gsi, gimple_seq seq)
+{
+ if (!seq)
+ return;
+
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (gimple_has_location (stmt))
+ annotate_all_with_location (seq, gimple_location (stmt));
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+ bool noreturn_p = call && gimple_call_noreturn_p (call);
+ int eh_lp = lookup_stmt_eh_lp (stmt);
+ bool must_not_throw_p = eh_lp < 0;
+ bool nothrow_p = (must_not_throw_p
+ || (call && gimple_call_nothrow_p (call))
+ || (eh_lp <= 0
+ && (TREE_NOTHROW (cfun->decl)
+ || !flag_exceptions)));
+
+ if (noreturn_p && nothrow_p)
+ return;
+
+ /* Don't expect an EH edge if we're not to throw, or if we're not in an EH
+ region yet. */
+ bool no_eh_edge_p = (nothrow_p || !eh_lp);
+ bool must_end_bb = stmt_ends_bb_p (stmt);
+
+ edge eft = NULL, eeh = NULL;
+ if (must_end_bb && !(noreturn_p && no_eh_edge_p))
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->succs)
+ {
+ if ((e->flags & EDGE_EH))
+ {
+ gcc_checking_assert (!eeh);
+ eeh = e;
+#if !CHECKING_P
+ if (eft || noreturn_p)
+ break;
+#endif
+ }
+ if ((e->flags & EDGE_FALLTHRU))
+ {
+ gcc_checking_assert (!eft);
+ eft = e;
+#if !CHECKING_P
+ if (eeh || no_eh_edge_p)
+ break;
+#endif
+ }
+ }
+
+ gcc_checking_assert (!(eft && (eft->flags & EDGE_FALLTHRU))
+ == noreturn_p);
+ gcc_checking_assert (!(eeh && (eeh->flags & EDGE_EH))
+ == no_eh_edge_p);
+ gcc_checking_assert (eft != eeh);
+ }
+
+ if (!noreturn_p)
+ {
+ gimple_seq nseq = nothrow_p ? seq : gimple_seq_copy (seq);
+
+ if (must_end_bb)
+ {
+ gcc_checking_assert (gsi_one_before_end_p (gsi));
+ add_call_edges_for_seq (nseq, eft->count ());
+ gsi_insert_seq_on_edge_immediate (eft, nseq);
+ }
+ else
+ {
+ add_call_edges_for_seq (nseq, gsi_bb (gsi)->count);
+ gsi_insert_seq_after (&gsi, nseq, GSI_SAME_STMT);
+ }
+ }
+
+ if (nothrow_p)
+ return;
+
+ if (eh_lp)
+ {
+ add_call_edges_for_seq (seq, eeh->count ());
+ gsi_insert_seq_on_edge_immediate (eeh, seq);
+ return;
+ }
+
+ /* A throwing call may appear within a basic block in a function that doesn't
+ have any EH regions. We're going to add a cleanup if so, therefore the
+ block will have to be split. */
+ basic_block bb = gsi_bb (gsi);
+ if (!gsi_one_before_end_p (gsi))
+ split_block (bb, stmt);
+
+ /* Create a new block for the EH cleanup. */
+ basic_block bb_eh_cleanup = create_empty_bb (bb);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, bb_eh_cleanup, bb);
+ if (current_loops)
+ add_bb_to_loop (bb_eh_cleanup, current_loops->tree_root);
+
+ /* Make the new block an EH cleanup for the call. */
+ eh_region new_r = gen_eh_region_cleanup (NULL);
+ eh_landing_pad lp = gen_eh_landing_pad (new_r);
+ tree label = gimple_block_label (bb_eh_cleanup);
+ lp->post_landing_pad = label;
+ EH_LANDING_PAD_NR (label) = lp->index;
+ add_stmt_to_eh_lp (stmt, lp->index);
+
+ /* Add the cleanup code to the EH cleanup block. */
+ gsi = gsi_after_labels (bb_eh_cleanup);
+ gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+
+ /* And then propagate the exception further. */
+ gresx *resx = gimple_build_resx (new_r->index);
+ if (gimple_has_location (stmt))
+ gimple_set_location (resx, gimple_location (stmt));
+ gsi_insert_before (&gsi, resx, GSI_SAME_STMT);
+
+ /* Finally, wire the EH cleanup block into the CFG. */
+ edge neeh = make_eh_edge (stmt);
+ neeh->probability = profile_probability::never ();
+ gcc_checking_assert (neeh->dest == bb_eh_cleanup);
+ gcc_checking_assert (!neeh->dest->count.initialized_p ());
+ neeh->dest->count = neeh->count ();
+ add_call_edges_for_seq (seq, neeh->dest->count);
+}
+
+/* Copy the attribute list at *ATTRS, minus any NAME attributes, leaving
+ shareable trailing nodes alone. */
+
+static inline void
+remove_named_attribute_unsharing (const char *name, tree *attrs)
+{
+ while (tree found = lookup_attribute (name, *attrs))
+ {
+ /* Copy nodes up to the next NAME attribute. */
+ while (*attrs != found)
+ {
+ *attrs = tree_cons (TREE_PURPOSE (*attrs),
+ TREE_VALUE (*attrs),
+ TREE_CHAIN (*attrs));
+ attrs = &TREE_CHAIN (*attrs);
+ }
+ /* Then drop it. */
+ gcc_checking_assert (*attrs == found);
+ *attrs = TREE_CHAIN (*attrs);
+ }
+}
+
+/* Record the order of the last cgraph entry whose mode we've already set, so
+ that we can perform mode setting incrementally without duplication. */
+static int last_cgraph_order;
+
+/* Set strub modes for functions introduced since the last call. */
+
+static void
+ipa_strub_set_mode_for_new_functions ()
+{
+ if (symtab->order == last_cgraph_order)
+ return;
+
+ cgraph_node *node;
+
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
+ for (int aliases = 0; aliases <= 1; aliases++)
+ FOR_EACH_FUNCTION (node)
+ {
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ set_strub_mode (node);
+ }
+
+ last_cgraph_order = symtab->order;
+}
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+
+bool
+strub_splittable_p (cgraph_node *node)
+{
+ switch (get_strub_mode (node))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ case STRUB_INLINABLE:
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ return false;
+
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return true;
+}
+
+/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */
+
+tree
+strub_watermark_parm (tree fndecl)
+{
+ switch (get_strub_mode_from_fndecl (fndecl))
+ {
+ case STRUB_WRAPPED:
+ case STRUB_AT_CALLS:
+ case STRUB_AT_CALLS_OPT:
+ break;
+
+ case STRUB_INTERNAL:
+ case STRUB_WRAPPER:
+ case STRUB_CALLABLE:
+ case STRUB_DISABLED:
+ case STRUB_INLINABLE:
+ return NULL_TREE;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+ /* The type (variant) compare finds the parameter even in a just-created
+ clone, before we set its name, but the type-based compare doesn't work
+ during builtin expansion within the lto compiler, because we'll have
+ created a separate variant in that run. */
+ if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()
+ || DECL_NAME (parm) == pass_ipa_strub::get_watermark_ptr ())
+ return parm;
+
+ gcc_unreachable ();
+}
+
+/* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it
+ hasn't been added yet. Return the named argument count. */
+
+int
+pass_ipa_strub::adjust_at_calls_type (tree type)
+{
+ int named_args = 0;
+
+ gcc_checking_assert (same_strub_mode_in_variants_p (type));
+
+ if (!TYPE_ARG_TYPES (type))
+ return named_args;
+
+ tree *tlist = &TYPE_ARG_TYPES (type);
+ tree qpwmptrt = get_qpwmt ();
+ while (*tlist && TREE_VALUE (*tlist) != void_type_node)
+ {
+ /* The type has already been adjusted. */
+ if (TREE_VALUE (*tlist) == qpwmptrt)
+ return named_args;
+ named_args++;
+ *tlist = tree_cons (TREE_PURPOSE (*tlist),
+ TREE_VALUE (*tlist),
+ TREE_CHAIN (*tlist));
+ tlist = &TREE_CHAIN (*tlist);
+ }
+
+ /* Add the new argument after all named arguments, so as to not mess with
+ attributes that reference parameters. */
+ *tlist = tree_cons (NULL_TREE, get_qpwmt (), *tlist);
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ if (!type_already_adjusted)
+ {
+ int flags = flags_from_decl_or_type (type);
+ tree fnspec = lookup_attribute ("fn spec", type);
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1;
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied, if needed, before adding
+ parameters. */
+ TYPE_ATTRIBUTES (type)
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (type));
+ }
+ }
+#endif
+
+ return named_args;
+}
+
+/* Adjust a call to an at-calls call target. Create a watermark local variable
+ if needed, initialize it before, pass it to the callee according to the
+ modified at-calls interface, and release the callee's stack space after the
+ call, if not deferred. If the call is const or pure, arrange for the
+ watermark to not be assumed unused or unchanged. */
+
+void
+pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
+ tree callee_fntype)
+{
+ gcc_checking_assert (e->call_stmt);
+ gcall *ocall = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (ocall);
+
+ /* Make sure we haven't modified this call yet. */
+ gcc_checking_assert (!(int (gimple_call_num_args (ocall)) > named_args
+ && (TREE_TYPE (gimple_call_arg (ocall, named_args))
+ == get_pwmt ())));
+
+ /* If we're already within a strub context, pass on the incoming watermark
+ pointer, and omit the enter and leave calls around the modified call, as an
+ optimization, or as a means to satisfy a tail-call requirement. */
+ tree swmp = ((optimize_size || optimize > 2
+ || gimple_call_must_tail_p (ocall)
+ || (optimize == 2 && gimple_call_tail_p (ocall)))
+ ? strub_watermark_parm (e->caller->decl)
+ : NULL_TREE);
+ bool omit_own_watermark = swmp;
+ tree swm = NULL_TREE;
+ if (!omit_own_watermark)
+ {
+ swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ /* Initialize the watermark before the call. */
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1,
+ unshare_expr (swmp));
+ if (gimple_has_location (ocall))
+ gimple_set_location (stptr, gimple_location (ocall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ e->caller->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+ }
+
+
+ /* Replace the call with one that passes the swmp argument first. */
+ gcall *wrcall;
+ { gcall *stmt = ocall;
+ // Mostly copied from gimple_call_copy_skip_args.
+ int i = 0;
+ int nargs = gimple_call_num_args (stmt);
+ auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
+ gcall *new_stmt;
+
+ /* pr71109.c calls a prototypeless function, then defines it with
+ additional arguments. It's ill-formed, but after it's inlined,
+ it somehow works out. */
+ for (; i < named_args && i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+ for (; i < named_args; i++)
+ vargs.quick_push (null_pointer_node);
+
+ vargs.quick_push (unshare_expr (swmp));
+
+ for (; i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+
+ if (gimple_call_internal_p (stmt))
+ gcc_unreachable ();
+ else
+ new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
+ gimple_call_set_fntype (new_stmt, callee_fntype);
+
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+ gimple_move_vops (new_stmt, stmt);
+
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gimple_call_copy_flags (new_stmt, stmt);
+ gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+
+ gimple_set_modified (new_stmt, true);
+
+ wrcall = new_stmt;
+ }
+
+ update_stmt (wrcall);
+ gsi_replace (&gsi, wrcall, true);
+ cgraph_edge::set_call_stmt (e, wrcall, false);
+
+ /* Insert the strub code after the call. */
+ gimple_seq seq = NULL;
+
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ if (!swm)
+ swm = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (swmp)),
+ swmp,
+ build_int_cst (TREE_TYPE (swmp), 0));
+
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ unshare_expr (swm)));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ unshare_expr (swm)));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ if (gimple_has_location (wrcall))
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ if (!omit_own_watermark)
+ {
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+}
+
+/* Adjust all at-calls calls in NODE. */
+
+void
+pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
+{
+ /* Adjust unknown-callee indirect calls with STRUB_AT_CALLS types within
+ onode. */
+ if (node->indirect_calls)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+ {
+ gcc_checking_assert (e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+
+ if (node->callees)
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ {
+ gcc_checking_assert (!e->indirect_unknown_callee);
+
+ if (!e->call_stmt)
+ continue;
+
+ tree callee_fntype;
+ enum strub_mode callee_mode
+ = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
+
+ if (callee_mode != STRUB_AT_CALLS
+ && callee_mode != STRUB_AT_CALLS_OPT)
+ continue;
+
+ int named_args = adjust_at_calls_type (callee_fntype);
+
+ adjust_at_calls_call (e, named_args, callee_fntype);
+ }
+ pop_cfun ();
+ }
+}
+
+/* The strubm (strub mode) pass computes a strub mode for each function in the
+ call graph, and checks, before any inlining, that strub callability
+ requirements in effect are satisfied. */
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ last_cgraph_order = 0;
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
+
+ return 0;
+}
+
+/* Create a strub mode pass. */
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub_mode (gcc::context *ctxt)
+{
+ return new pass_ipa_strub_mode (ctxt);
+}
+
+/* The strub pass proper adjusts types, signatures, and at-calls calls, and
+ splits internal-strub functions. */
+
+unsigned int
+pass_ipa_strub::execute (function *)
+{
+ cgraph_node *onode;
+
+ ipa_strub_set_mode_for_new_functions ();
+
+ /* First, adjust the signature of at-calls functions. We adjust types of
+ at-calls functions first, so that we don't modify types in place unless
+ strub is explicitly requested. */
+ FOR_EACH_FUNCTION (onode)
+ {
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode == STRUB_AT_CALLS
+ || mode == STRUB_AT_CALLS_OPT)
+ {
+ /* Create a type variant if strubbing was not explicitly requested in
+ the function type. */
+ if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
+ distinctify_node_type (onode);
+
+ int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));
+
+ /* An external function explicitly declared with strub won't have a
+ body. Even with implicit at-calls strub, a function may have had its
+ body removed after we selected the mode, and then we have nothing
+ further to do. */
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ tree *pargs = &DECL_ARGUMENTS (onode->decl);
+
+ /* A noninterposable_alias reuses the same parm decl chain, don't add
+ the parm twice. */
+ bool aliased_parms = (onode->alias && *pargs
+ && DECL_CONTEXT (*pargs) != onode->decl);
+
+ if (aliased_parms)
+ continue;
+
+ for (int i = 0; i < named_args; i++)
+ pargs = &DECL_CHAIN (*pargs);
+
+ tree wmptr = build_decl (DECL_SOURCE_LOCATION (onode->decl),
+ PARM_DECL,
+ get_watermark_ptr (),
+ get_qpwmt ());
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_ARG_TYPE (wmptr) = get_qpwmt ();
+ DECL_CONTEXT (wmptr) = onode->decl;
+ TREE_USED (wmptr) = 1;
+ DECL_CHAIN (wmptr) = *pargs;
+ *pargs = wmptr;
+
+ if (onode->alias)
+ continue;
+
+ cgraph_node *nnode = onode;
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca)
+ {
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, cfun)
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ gcall *call = dyn_cast <gcall *> (stmt);
+
+ if (!call)
+ continue;
+
+ if (gimple_alloca_call_p (call))
+ {
+ /* Capture stack growth. */
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)
+ ->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ }
+ }
+
+ pop_cfun ();
+ }
+ }
+
+ FOR_EACH_FUNCTION (onode)
+ {
+ if (!onode->has_gimple_body_p ())
+ continue;
+
+ enum strub_mode mode = get_strub_mode (onode);
+
+ if (mode != STRUB_INTERNAL)
+ {
+ adjust_at_calls_calls (onode);
+ continue;
+ }
+
+ bool is_stdarg = calls_builtin_va_start_p (onode);;
+ bool apply_args = calls_builtin_apply_args_p (onode);
+
+ vec<ipa_adjusted_param, va_gc> *nparms = NULL;
+ unsigned j = 0;
+ {
+ // The following loop copied from ipa-split.c:split_function.
+ for (tree parm = DECL_ARGUMENTS (onode->decl);
+ parm; parm = DECL_CHAIN (parm), j++)
+ {
+ ipa_adjusted_param adj = {};
+ adj.op = IPA_PARAM_OP_COPY;
+ adj.base_index = j;
+ adj.prev_clone_index = j;
+ vec_safe_push (nparms, adj);
+ }
+
+ if (apply_args)
+ {
+ ipa_adjusted_param aaadj = {};
+ aaadj.op = IPA_PARAM_OP_NEW;
+ aaadj.type = get_qptr ();
+ vec_safe_push (nparms, aaadj);
+ }
+
+ if (is_stdarg)
+ {
+ ipa_adjusted_param vladj = {};
+ vladj.op = IPA_PARAM_OP_NEW;
+ vladj.type = get_qpvalst ();
+ vec_safe_push (nparms, vladj);
+ }
+
+ ipa_adjusted_param wmadj = {};
+ wmadj.op = IPA_PARAM_OP_NEW;
+ wmadj.type = get_qpwmt ();
+ vec_safe_push (nparms, wmadj);
+ }
+ ipa_param_adjustments adj (nparms, -1, false);
+
+ cgraph_node *nnode = onode->create_version_clone_with_body
+ (auto_vec<cgraph_edge *> (0),
+ NULL, &adj, NULL, NULL, "strub", NULL);
+
+ if (!nnode)
+ {
+ error_at (DECL_SOURCE_LOCATION (onode->decl),
+ "failed to split %qD for %<strub%>",
+ onode->decl);
+ continue;
+ }
+
+ onode->split_part = true;
+ if (onode->calls_comdat_local)
+ nnode->add_to_same_comdat_group (onode);
+
+ set_strub_mode_to (onode, STRUB_WRAPPER);
+ set_strub_mode_to (nnode, STRUB_WRAPPED);
+
+ adjust_at_calls_calls (nnode);
+
+ /* Decide which of the wrapped function's parms we want to turn into
+ references to the argument passed to the wrapper. In general, we want to
+ copy small arguments, and avoid copying large ones. Variable-sized array
+ lengths given by other arguments, as in 20020210-1.c, would lead to
+ problems if passed by value, after resetting the original function and
+ dropping the length computation; passing them by reference works.
+ DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
+ anyway, but performed at the caller. */
+ indirect_parms_t indirect_nparms (3, false);
+ unsigned adjust_ftype = 0;
+ unsigned named_args = 0;
+ for (tree parm = DECL_ARGUMENTS (onode->decl),
+ nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
+ parm;
+ named_args++,
+ parm = DECL_CHAIN (parm),
+ nparm = DECL_CHAIN (nparm),
+ nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
+ if (!(0 /* DECL_BY_REFERENCE (narg) */
+ || is_gimple_reg_type (TREE_TYPE (nparm))
+ || VECTOR_TYPE_P (TREE_TYPE (nparm))
+ || TREE_CODE (TREE_TYPE (nparm)) == COMPLEX_TYPE
+ || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ && (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
+ <= 4 * UNITS_PER_WORD))))
+ {
+ indirect_nparms.add (nparm);
+
+ /* ??? Is there any case in which it is not safe to suggest the parms
+ turned indirect don't alias anything else? They are distinct,
+ unaliased memory in the wrapper, and the wrapped can't possibly
+ take pointers into them because none of the pointers passed to the
+ wrapper can alias other incoming parameters passed by value, even
+ if with transparent reference, and the wrapper doesn't take any
+ extra parms that could point into wrapper's parms. So we can
+ probably drop the TREE_ADDRESSABLE and keep the TRUE. */
+ tree ref_type = build_ref_type_for (nparm,
+ true
+ || !TREE_ADDRESSABLE (parm));
+
+ DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type;
+ relayout_decl (nparm);
+ TREE_ADDRESSABLE (nparm) = 0;
+ DECL_BY_REFERENCE (nparm) = 0;
+ DECL_NOT_GIMPLE_REG_P (nparm) = 0;
+ /* ??? This avoids mismatches in debug info bind stmts in
+ e.g. a-chahan . */
+ DECL_ABSTRACT_ORIGIN (nparm) = NULL;
+
+ if (nparmt)
+ adjust_ftype++;
+ }
+
+ /* Also adjust the wrapped function type, if needed. */
+ if (adjust_ftype)
+ {
+ tree nftype = TREE_TYPE (nnode->decl);
+
+ /* We always add at least one argument at the end of the signature, when
+ cloning the function, so we don't expect to need to duplicate the
+ type here. */
+ gcc_checking_assert (TYPE_ARG_TYPES (nftype)
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+
+ /* Check that fnspec still works for the modified function signature,
+ and drop it otherwise. */
+ bool drop_fnspec = false;
+ tree fnspec = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (nftype));
+ attr_fnspec spec = fnspec ? attr_fnspec (fnspec) : attr_fnspec ("");
+
+ unsigned retcopy;
+ if (!(fnspec && spec.returns_arg (&retcopy)))
+ retcopy = (unsigned) -1;
+
+ unsigned i = 0;
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl),
+ nparmt = TYPE_ARG_TYPES (nftype);
+ adjust_ftype > 0;
+ i++, nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
+ if (indirect_nparms.contains (nparm))
+ {
+ TREE_VALUE (nparmt) = TREE_TYPE (nparm);
+ adjust_ftype--;
+
+ if (fnspec && !drop_fnspec)
+ {
+ if (i == retcopy)
+ drop_fnspec = true;
+ else if (spec.arg_specified_p (i))
+ {
+ /* Properties that apply to pointers only must not be
+ present, because we don't make pointers further
+ indirect. */
+ gcc_checking_assert
+ (!spec.arg_max_access_size_given_by_arg_p (i, NULL));
+ gcc_checking_assert (!spec.arg_copied_to_arg_p (i, NULL));
+
+ /* Any claim of direct access only is invalidated by
+ adding an indirection level. */
+ if (spec.arg_direct_p (i))
+ drop_fnspec = true;
+
+ /* If there's a claim the argument is not read from, the
+ added indirection invalidates it: if the argument is
+ used at all, then the pointer will necessarily be
+ read. */
+ if (!spec.arg_maybe_read_p (i)
+ && spec.arg_used_p (i))
+ drop_fnspec = true;
+ }
+ }
+ }
+
+ /* ??? Maybe we could adjust it instead. */
+ if (drop_fnspec)
+ remove_named_attribute_unsharing ("fn spec",
+ &TYPE_ATTRIBUTES (nftype));
+
+ TREE_TYPE (nnode->decl) = nftype;
+ }
+
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (nnode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1 + int (is_stdarg) + int (apply_args);
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ bool no_writes_p = true;
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
+ && curlen >= 2
+ && nspec[1] != 'c' && nspec[1] != 'C'
+ && nspec[1] != 'p' && nspec[1] != 'P')
+ no_writes_p = false;
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+
+ /* These extra args are unlikely to be present in const or pure
+ functions. It's conceivable that a function that takes variable
+ arguments, or that passes its arguments on to another function,
+ could be const or pure, but it would not modify the arguments, and,
+ being pure or const, it couldn't possibly modify or even access
+ memory referenced by them. But it can read from these internal
+ data structures created by the wrapper, and from any
+ argument-passing memory referenced by them, so we denote the
+ possibility of reading from multiple levels of indirection, but
+ only of reading because const/pure. */
+ if (apply_args)
+ {
+ nspec[curlen++] = 'r';
+ nspec[curlen++] = ' ';
+ }
+ if (is_stdarg)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
+ }
+ }
+#endif
+
+ {
+ tree decl = onode->decl;
+ cgraph_node *target = nnode;
+
+ { // copied from create_wrapper
+
+ /* Preserve DECL_RESULT so we get right by reference flag. */
+ tree decl_result = DECL_RESULT (decl);
+
+ /* Remove the function's body but keep arguments to be reused
+ for thunk. */
+ onode->release_body (true);
+ onode->reset (/* unlike create_wrapper: preserve_comdat_group = */true);
+
+ DECL_UNINLINABLE (decl) = false;
+ DECL_RESULT (decl) = decl_result;
+ DECL_INITIAL (decl) = NULL;
+ allocate_struct_function (decl, false);
+ set_cfun (NULL);
+
+ /* Turn alias into thunk and expand it into GIMPLE representation. */
+ onode->definition = true;
+
+ thunk_info::get_create (onode);
+ onode->thunk = true;
+ onode->create_edge (target, NULL, onode->count);
+ onode->callees->can_throw_external = !TREE_NOTHROW (target->decl);
+
+ tree arguments = DECL_ARGUMENTS (decl);
+
+ while (arguments)
+ {
+ TREE_ADDRESSABLE (arguments) = false;
+ arguments = TREE_CHAIN (arguments);
+ }
+
+ {
+ tree alias = onode->callees->callee->decl;
+ tree thunk_fndecl = decl;
+ tree a;
+
+ int nxargs = 1 + is_stdarg + apply_args;
+
+ { // Simplified from expand_thunk.
+ tree restype;
+ basic_block bb, then_bb, else_bb, return_bb;
+ gimple_stmt_iterator bsi;
+ int nargs = 0;
+ tree arg;
+ int i;
+ tree resdecl;
+ tree restmp = NULL;
+
+ gcall *call;
+ greturn *ret;
+ bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
+
+ a = DECL_ARGUMENTS (thunk_fndecl);
+
+ current_function_decl = thunk_fndecl;
+
+ /* Ensure thunks are emitted in their correct sections. */
+ resolve_unique_section (thunk_fndecl, 0,
+ flag_function_sections);
+
+ bitmap_obstack_initialize (NULL);
+
+ /* Build the return declaration for the function. */
+ restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
+ if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
+ {
+ resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = thunk_fndecl;
+ DECL_RESULT (thunk_fndecl) = resdecl;
+ }
+ else
+ resdecl = DECL_RESULT (thunk_fndecl);
+
+ profile_count cfg_count = onode->count;
+ if (!cfg_count.initialized_p ())
+ cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
+
+ bb = then_bb = else_bb = return_bb
+ = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
+
+ bsi = gsi_start_bb (bb);
+
+ /* Build call to the function being thunked. */
+ if (!VOID_TYPE_P (restype)
+ && (!alias_is_noreturn
+ || TREE_ADDRESSABLE (restype)
+ || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
+ {
+ if (DECL_BY_REFERENCE (resdecl))
+ {
+ restmp = gimple_fold_indirect_ref (resdecl);
+ if (!restmp)
+ restmp = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (resdecl)),
+ resdecl,
+ build_int_cst (TREE_TYPE (resdecl), 0));
+ }
+ else if (!is_gimple_reg_type (restype))
+ {
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
+ {
+ restmp = resdecl;
+
+ if (VAR_P (restmp))
+ {
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl))
+ = restmp;
+ }
+ }
+ else
+ restmp = create_tmp_var (restype, "retval");
+ }
+ else
+ restmp = create_tmp_reg (restype, "retval");
+ }
+
+ for (arg = a; arg; arg = DECL_CHAIN (arg))
+ nargs++;
+ auto_vec<tree> vargs (nargs + nxargs);
+ i = 0;
+ arg = a;
+
+ if (nargs)
+ for (tree nparm = DECL_ARGUMENTS (nnode->decl);
+ i < nargs;
+ i++, arg = DECL_CHAIN (arg), nparm = DECL_CHAIN (nparm))
+ {
+ tree save_arg = arg;
+ tree tmp = arg;
+
+ /* Arrange to pass indirectly the parms, if we decided to do
+ so, and revert its type in the wrapper. */
+ if (indirect_nparms.contains (nparm))
+ {
+ tree ref_type = TREE_TYPE (nparm);
+ TREE_ADDRESSABLE (arg) = true;
+ tree addr = build1 (ADDR_EXPR, ref_type, arg);
+ tmp = arg = addr;
+ }
+ else
+ DECL_NOT_GIMPLE_REG_P (arg) = 0;
+
+ /* Convert the argument back to the type used by the calling
+ conventions, e.g. a non-prototyped float type is passed as
+ double, as in 930603-1.c, and needs to be converted back to
+ double to be passed on unchanged to the wrapped
+ function. */
+ if (TREE_TYPE (nparm) != DECL_ARG_TYPE (nparm))
+ arg = fold_convert (DECL_ARG_TYPE (nparm), arg);
+
+ if (!is_gimple_val (arg))
+ {
+ tmp = create_tmp_reg (TYPE_MAIN_VARIANT
+ (TREE_TYPE (arg)), "arg");
+ gimple *stmt = gimple_build_assign (tmp, arg);
+ gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
+ }
+ vargs.quick_push (tmp);
+ arg = save_arg;
+ }
+ /* These strub arguments are adjusted later. */
+ if (apply_args)
+ vargs.quick_push (null_pointer_node);
+ if (is_stdarg)
+ vargs.quick_push (null_pointer_node);
+ vargs.quick_push (null_pointer_node);
+ call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias),
+ vargs);
+ onode->callees->call_stmt = call;
+ // gimple_call_set_from_thunk (call, true);
+ if (DECL_STATIC_CHAIN (alias))
+ {
+ tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
+ tree type = TREE_TYPE (p);
+ tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ PARM_DECL, create_tmp_var_name ("CHAIN"),
+ type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_CONTEXT (decl) = thunk_fndecl;
+ DECL_ARG_TYPE (decl) = type;
+ TREE_READONLY (decl) = 1;
+
+ struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
+ sf->static_chain_decl = decl;
+
+ gimple_call_set_chain (call, decl);
+ }
+
+ /* Return slot optimization is always possible and in fact required to
+ return values with DECL_BY_REFERENCE. */
+ if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
+ && (!is_gimple_reg_type (TREE_TYPE (resdecl))
+ || DECL_BY_REFERENCE (resdecl)))
+ gimple_call_set_return_slot_opt (call, true);
+
+ if (restmp)
+ {
+ gimple_call_set_lhs (call, restmp);
+ gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
+ TREE_TYPE (TREE_TYPE (alias))));
+ }
+ gsi_insert_after (&bsi, call, GSI_NEW_STMT);
+ if (!alias_is_noreturn)
+ {
+ /* Build return value. */
+ if (!DECL_BY_REFERENCE (resdecl))
+ ret = gimple_build_return (restmp);
+ else
+ ret = gimple_build_return (resdecl);
+
+ gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
+ }
+ else
+ {
+ remove_edge (single_succ_edge (bb));
+ }
+
+ cfun->gimple_df->in_ssa_p = true;
+ update_max_bb_count ();
+ profile_status_for_fn (cfun)
+ = cfg_count.initialized_p () && cfg_count.ipa_p ()
+ ? PROFILE_READ : PROFILE_GUESSED;
+ /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
+ // TREE_ASM_WRITTEN (thunk_fndecl) = false;
+ delete_unreachable_blocks ();
+ update_ssa (TODO_update_ssa);
+ checking_verify_flow_info ();
+ free_dominance_info (CDI_DOMINATORS);
+
+ /* Since we want to emit the thunk, we explicitly mark its name as
+ referenced. */
+ onode->thunk = false;
+ onode->lowered = true;
+ bitmap_obstack_release (NULL);
+ }
+ current_function_decl = NULL;
+ set_cfun (NULL);
+ }
+
+ thunk_info::remove (onode);
+
+ // some more of create_wrapper at the end of the next block.
+ }
+ }
+
+ {
+ tree aaval = NULL_TREE;
+ tree vaptr = NULL_TREE;
+ tree wmptr = NULL_TREE;
+ for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg))
+ {
+ aaval = vaptr;
+ vaptr = wmptr;
+ wmptr = arg;
+ }
+
+ if (!apply_args)
+ aaval = NULL_TREE;
+ /* The trailing args are [apply_args], [va_list_ptr], and
+ watermark. If we don't have a va_list_ptr, the penultimate
+ argument is apply_args.
+ */
+ else if (!is_stdarg)
+ aaval = vaptr;
+
+ if (!is_stdarg)
+ vaptr = NULL_TREE;
+
+ DECL_NAME (wmptr) = get_watermark_ptr ();
+ DECL_ARTIFICIAL (wmptr) = 1;
+ DECL_IGNORED_P (wmptr) = 1;
+ TREE_USED (wmptr) = 1;
+
+ if (is_stdarg)
+ {
+ DECL_NAME (vaptr) = get_va_list_ptr ();
+ DECL_ARTIFICIAL (vaptr) = 1;
+ DECL_IGNORED_P (vaptr) = 1;
+ TREE_USED (vaptr) = 1;
+ }
+
+ if (apply_args)
+ {
+ DECL_NAME (aaval) = get_apply_args ();
+ DECL_ARTIFICIAL (aaval) = 1;
+ DECL_IGNORED_P (aaval) = 1;
+ TREE_USED (aaval) = 1;
+ }
+
+ push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
+
+ {
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_seq seq = call_update_watermark (wmptr, nnode, e->src->count);
+ gsi_insert_seq_on_edge_immediate (e, seq);
+ }
+
+ bool any_indirect = !indirect_nparms.is_empty ();
+
+ if (any_indirect)
+ {
+ basic_block bb;
+ bool needs_commit = false;
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
+ !gsi_end_p (gsi);
+ gsi_next_nonvirtual_phi (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed && !is_gimple_debug (gsi_stmt (gsi)))
+ if (walk_regimplify_phi (stmt))
+ needs_commit = true;
+ }
+
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ walk_stmt_info wi = {};
+ wi.info = &indirect_nparms;
+ walk_gimple_op (stmt, walk_make_indirect, &wi);
+ if (wi.changed)
+ {
+ if (!is_gimple_debug (stmt))
+ {
+ wi.info = &gsi;
+ walk_gimple_op (stmt, walk_regimplify_addr_expr,
+ &wi);
+ }
+ update_stmt (stmt);
+ }
+ }
+ }
+ if (needs_commit)
+ gsi_commit_edge_inserts ();
+ }
+
+ if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca
+ || is_stdarg || apply_args)
+ for (cgraph_edge *e = nnode->callees, *enext; e; e = enext)
+ {
+ if (!e->call_stmt)
+ continue;
+
+ gcall *call = e->call_stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (call);
+ tree fndecl = e->callee->decl;
+
+ enext = e->next_callee;
+
+ if (gimple_alloca_call_p (call))
+ {
+ gimple_seq seq = call_update_watermark (wmptr, NULL,
+ gsi_bb (gsi)->count);
+ gsi_insert_finally_seq_after_call (gsi, seq);
+ }
+ else if (fndecl && is_stdarg
+ && fndecl_built_in_p (fndecl, BUILT_IN_VA_START))
+ {
+ /* Using a non-default stdarg ABI makes the function ineligible
+ for internal strub. */
+ gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START)
+ == fndecl);
+ tree bvacopy = builtin_decl_explicit (BUILT_IN_VA_COPY);
+ gimple_call_set_fndecl (call, bvacopy);
+ tree arg = vaptr;
+ /* The va_copy source must be dereferenced, unless it's an array
+ type, that would have decayed to a pointer. */
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (vaptr))) != ARRAY_TYPE)
+ {
+ arg = gimple_fold_indirect_ref (vaptr);
+ if (!arg)
+ arg = build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (vaptr)),
+ vaptr,
+ build_int_cst (TREE_TYPE (vaptr), 0));
+ if (!is_gimple_val (arg))
+ arg = force_gimple_operand_gsi (&gsi, arg, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ }
+ gimple_call_set_arg (call, 1, arg);
+ update_stmt (call);
+ e->redirect_callee (cgraph_node::get_create (bvacopy));
+ }
+ else if (fndecl && apply_args
+ && fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
+ {
+ tree lhs = gimple_call_lhs (call);
+ gimple *assign = (lhs
+ ? gimple_build_assign (lhs, aaval)
+ : gimple_build_nop ());
+ gsi_replace (&gsi, assign, true);
+ cgraph_edge::remove (e);
+ }
+ }
+
+ { // a little more copied from create_wrapper
+
+ /* Inline summary set-up. */
+ nnode->analyze ();
+ // inline_analyze_function (nnode);
+ }
+
+ pop_cfun ();
+ }
+
+ {
+ push_cfun (DECL_STRUCT_FUNCTION (onode->decl));
+ gimple_stmt_iterator gsi
+ = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+
+ gcall *wrcall;
+ while (!(wrcall = dyn_cast <gcall *> (gsi_stmt (gsi))))
+ gsi_next (&gsi);
+
+ tree swm = create_tmp_var (get_wmt (), ".strub.watermark");
+ TREE_ADDRESSABLE (swm) = true;
+ tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
+
+ tree enter = get_enter ();
+ gcall *stptr = gimple_build_call (enter, 1, unshare_expr (swmp));
+ gimple_set_location (stptr, gimple_location (wrcall));
+ gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (enter),
+ stptr, gsi_bb (gsi)->count, false);
+
+ int nargs = gimple_call_num_args (wrcall);
+
+ gimple_seq seq = NULL;
+
+ if (apply_args)
+ {
+ tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args");
+ tree bappargs = builtin_decl_explicit (BUILT_IN_APPLY_ARGS);
+ gcall *appargs = gimple_build_call (bappargs, 0);
+ gimple_call_set_lhs (appargs, aalst);
+ gimple_set_location (appargs, gimple_location (wrcall));
+ gsi_insert_before (&gsi, appargs, GSI_SAME_STMT);
+ gimple_call_set_arg (wrcall, nargs - 2 - is_stdarg, aalst);
+ onode->create_edge (cgraph_node::get_create (bappargs),
+ appargs, gsi_bb (gsi)->count, false);
+ }
+
+ if (is_stdarg)
+ {
+ tree valst = create_tmp_var (va_list_type_node, ".strub.va_list");
+ TREE_ADDRESSABLE (valst) = true;
+ tree vaptr = build1 (ADDR_EXPR,
+ build_pointer_type (va_list_type_node),
+ valst);
+ gimple_call_set_arg (wrcall, nargs - 2, unshare_expr (vaptr));
+
+ tree bvastart = builtin_decl_explicit (BUILT_IN_VA_START);
+ gcall *vastart = gimple_build_call (bvastart, 2,
+ unshare_expr (vaptr),
+ integer_zero_node);
+ gimple_set_location (vastart, gimple_location (wrcall));
+ gsi_insert_before (&gsi, vastart, GSI_SAME_STMT);
+ onode->create_edge (cgraph_node::get_create (bvastart),
+ vastart, gsi_bb (gsi)->count, false);
+
+ tree bvaend = builtin_decl_explicit (BUILT_IN_VA_END);
+ gcall *vaend = gimple_build_call (bvaend, 1, unshare_expr (vaptr));
+ gimple_set_location (vaend, gimple_location (wrcall));
+ gimple_seq_add_stmt (&seq, vaend);
+ }
+
+ gimple_call_set_arg (wrcall, nargs - 1, unshare_expr (swmp));
+ // gimple_call_set_tail (wrcall, false);
+ update_stmt (wrcall);
+
+ {
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gimple_set_location (force_store, gimple_location (wrcall));
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
+#endif
+
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
+ gimple_seq_add_stmt (&seq, sleave);
+
+ gassign *clobber = gimple_build_assign (swm,
+ build_clobber
+ (TREE_TYPE (swm)));
+ gimple_seq_add_stmt (&seq, clobber);
+ }
+
+ gsi_insert_finally_seq_after_call (gsi, seq);
+
+ /* For nnode, we don't rebuild edges because we wish to retain
+ any redirections copied to it from earlier passes, so we add
+ call graph edges explicitly there, but for onode, we create a
+ fresh function, so we may as well just issue the calls and
+ then rebuild all cgraph edges. */
+ // cgraph_edge::rebuild_edges ();
+ onode->analyze ();
+ // inline_analyze_function (onode);
+
+ pop_cfun ();
+ }
+ }
+
+ return 0;
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_strub (gcc::context *ctxt)
+{
+ return new pass_ipa_strub (ctxt);
+}
+
+#include "gt-ipa-strub.h"
diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h
new file mode 100644
index 0000000000000..f367a4a0ef827
--- /dev/null
+++ b/gcc/ipa-strub.h
@@ -0,0 +1,45 @@
+/* strub (stack scrubbing) infrastructure.
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Return TRUE if CALLEE can be inlined into CALLER, as far as stack scrubbing
+ constraints are concerned. CALLEE doesn't have to be called directly by
+ CALLER, but the returned value says nothing about intervening functions. */
+extern bool strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller);
+
+/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
+extern bool strub_splittable_p (cgraph_node *node);
+
+/* Locate and return the watermark_ptr parameter for FNDECL. If FNDECL is not a
+ strub context, return NULL. */
+extern tree strub_watermark_parm (tree fndecl);
+
+/* Make a function type or declaration callable. */
+extern void strub_make_callable (tree fndecl);
+
+/* Return zero iff ID is NOT an acceptable parameter for a user-supplied strub
+ attribute for a function. Otherwise, return >0 if it enables strub, <0 if it
+ does not. Return +/-1 if the attribute-modified type is compatible with the
+ type without the attribute, or +/-2 if it is not compatible. */
+extern int strub_validate_fn_attr_parm (tree id);
+
+/* Like comptypes, return 0 if t1 and t2 are not compatible, 1 if they are
+ compatible, and 2 if they are nearly compatible. Same strub mode is
+ compatible, interface-compatible strub modes are nearly compatible. */
+extern int strub_comptypes (tree t1, tree t2);
diff --git a/gcc/passes.def b/gcc/passes.def
index 1e1950bdb39cb..d515e77be0399 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
INSERT_PASSES_AFTER (all_small_ipa_passes)
NEXT_PASS (pass_ipa_free_lang_data);
NEXT_PASS (pass_ipa_function_and_variable_visibility);
+ NEXT_PASS (pass_ipa_strub_mode);
NEXT_PASS (pass_build_ssa_passes);
PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
NEXT_PASS (pass_fixup_cfg);
@@ -115,6 +116,7 @@ along with GCC; see the file COPYING3. If not see
POP_INSERT_PASSES ()
NEXT_PASS (pass_ipa_remove_symbols);
+ NEXT_PASS (pass_ipa_strub);
NEXT_PASS (pass_ipa_oacc);
PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc)
NEXT_PASS (pass_ipa_pta);
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
new file mode 100644
index 0000000000000..c7a79a6ea0d8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O0, none of the strub builtins are expanded inline. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
new file mode 100644
index 0000000000000..96285c975d98e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O1, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
new file mode 100644
index 0000000000000..8edc0d8aa1321
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -O2, without -fno-inline, we fully expand enter and update, and add a test
+ around the leave call. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
new file mode 100644
index 0000000000000..c6d900cf3c45b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
new file mode 100644
index 0000000000000..33ee465e51cb6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_leave" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
new file mode 100644
index 0000000000000..2936f82079e18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+
+/* With -fno-inline, none of the strub builtins are inlined. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
new file mode 100644
index 0000000000000..479746e57d87e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Og, without -fno-inline, we fully expand enter, but neither update nor
+ leave. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
new file mode 100644
index 0000000000000..2241d4ea07f27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+
+/* At -Os, without -fno-inline, we fully expand enter, and also update. The
+ expanded update might be larger than a call proper, but argument saving and
+ restoring required by the call will most often make it larger. The leave
+ call is left untouched. */
+
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */
+/* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */
+/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
new file mode 100644
index 0000000000000..a322bcc5da606
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
new file mode 100644
index 0000000000000..db60026d0e080
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
+ is set for static non-inline functions when not optimizing, and that keeps
+ only_called_directly_p from returning true, which makes STRUB_AT_CALLS
+ non-viable. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
new file mode 100644
index 0000000000000..2f462adc1efe0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__ ("callable")))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0);
+}
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ void *args = __builtin_apply_args ();
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
new file mode 100644
index 0000000000000..a5d7551f5da5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+extern void __attribute__ ((__strub__))
+apply_function (void *args);
+
+void __attribute__ ((__strub__))
+apply_args (int i, int j, double d) /* { dg-error "selected" } */
+{
+ void *args = __builtin_apply_args (); /* { dg-message "does not support" } */
+ apply_function (args);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
new file mode 100644
index 0000000000000..64422a0d1e880
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+void __attribute__ ((__strub__))
+apply_function (void *args)
+{
+ __builtin_apply (0, args, 0); /* { dg-error "in .strub. context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
new file mode 100644
index 0000000000000..15ffaa031b899
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+
+/* Check that implicit enabling of strub mode selects internal strub when the
+ function uses __builtin_apply_args, that prevents the optimization to
+ at-calls mode. */
+
+int __attribute__ ((__strub__)) var;
+
+static inline void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+void f() {
+ apply_args (1, 2, 3);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
new file mode 100644
index 0000000000000..b70843b4215a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_AT_CALLS, because of the flag. */
+static inline void
+g() {
+ h();
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
new file mode 100644
index 0000000000000..97a3988a6b922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
+ force_output is set for static non-inline functions when not optimizing, and
+ that keeps only_called_directly_p from returning true, which makes
+ STRUB_AT_CALLS non-viable. It becomes STRUB_CALLABLE instead. */
+static void
+g() {
+}
+
+/* f does NOT become STRUB_AT_CALLS because it is visible; it becomes
+ STRUB_CALLABLE. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
new file mode 100644
index 0000000000000..3d73431b3dcd3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O1" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O1. */
+
+#include "strub-defer-O2.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
new file mode 100644
index 0000000000000..fddf3c745e7e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O2" } */
+
+/* Check that a strub function called by another strub function does NOT defer
+ the strubbing to its caller at -O2. */
+
+#define EXPECT_DEFERRAL !
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
new file mode 100644
index 0000000000000..7ebc65b58dd72
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -0,0 +1,110 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -O3" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -O3. */
+
+#ifndef EXPECT_DEFERRAL
+/* Other strub-defer*.c tests override this macro. */
+# define EXPECT_DEFERRAL
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char*)__builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+int
+look_for_string (char *e)
+{
+ char *p = (char*)__builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__strub__ ("at-calls"), __noinline__, __noclone__))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+deferred_at_calls ()
+{
+ char *ret;
+ int i = 1;
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ while (EXPECT_DEFERRAL !look_for_string ((ret = at_calls ())))
+ if (!i--) __builtin_abort ();
+ return ret;
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+deferred_internal ()
+{
+ int i = 1;
+ char *ret;
+ while (EXPECT_DEFERRAL !look_for_string ((ret = at_calls ())))
+ if (!i--) __builtin_abort ();
+ return ret;
+}
+
+int main ()
+{
+ int i = 1;
+ /* These calls should not be subject to spurious fails: whether or not some
+ asynchronous event overwrites the scrubbed stack space, the string won't
+ remain there. Unless the asynchronous event happens to write the string
+ where we look for it, but what are the odds? Anyway, it doesn't hurt to
+ retry, even if just for symmetry. */
+ while (look_for_string (deferred_at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (deferred_internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
new file mode 100644
index 0000000000000..fbaf85fe0fafe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict -Os" } */
+
+/* Check that a strub function called by another strub function defers the
+ strubbing to its caller at -Os. */
+
+#include "strub-defer-O3.c"
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
new file mode 100644
index 0000000000000..e9d7b7b9ee0a8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
+ strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+}
+
+/* g becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+static inline void
+g() {
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]callable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
new file mode 100644
index 0000000000000..8b8e15a51c71c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* g becomes STRUB_INTERNAL, because of the flag. */
+static void
+g() {
+}
+
+/* f becomes STRUB_INTERNAL because of the flag, and gets split into
+ STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ g();
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
new file mode 100644
index 0000000000000..0a4a7539d3489
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("internal")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("internal")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void __attribute__ ((__strub__ ("internal")))
+apply_args (int i, int j, double d)
+{
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
new file mode 100644
index 0000000000000..147171d96d5a1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+#include <stdarg.h>
+
+void __attribute__ ((__strub__ ("at-calls")))
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void __attribute__ ((__strub__ ("at-calls")))
+large_byref_arg (struct large_arg la)
+{
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]* \[(\]struct large_arg la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+
+void __attribute__ ((__strub__ ("at-calls")))
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]* \[(\]int i, void \\* &\[^&,\]*.strub.watermark_ptr\[, .]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-not "va_copy \\(" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
new file mode 100644
index 0000000000000..4e92682895a43
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that uses of a strub variable implicitly enables internal strub for
+ publicly-visible functions, and causes the same transformations to their
+ signatures as those in strub-parms1.c. */
+
+#include <stdarg.h>
+
+int __attribute__ ((__strub__)) var;
+
+void
+small_args (int i, long long l, void *p, void **q, double d, char c)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*small_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+
+struct large_arg {
+ int x[128];
+};
+
+void
+large_byref_arg (struct large_arg la)
+{
+ var++;
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*large_byref_arg\[^ \]*.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+
+void
+std_arg (int i, ...)
+{
+ va_list vl;
+ va_start (vl, i);
+ var++;
+ va_end (vl);
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*std_arg\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */
+
+void
+apply_args (int i, int j, double d)
+{
+ var++;
+ __builtin_apply_args ();
+}
+
+/* { dg-final { scan-ipa-dump "\n(void )?\[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */
+/* { dg-final { scan-ipa-dump " \[^ \]*apply_args\[^ \]*.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
new file mode 100644
index 0000000000000..e2f9d8aebca58
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. Without the error,
+ inlining takes place. */
+
+#include "strub-strict1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 1 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
new file mode 100644
index 0000000000000..98474435d2e59
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+
+/* The difference between relaxed and strict in this case is that we accept the
+ call from one internal-strub function to another. */
+
+#include "strub-strict2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapped\[)\]" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]wrapper\[)\]" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
new file mode 100644
index 0000000000000..1de15342595e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 89 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
new file mode 100644
index 0000000000000..f9209c819004b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
new file mode 100644
index 0000000000000..bed1dcfb54a45
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
new file mode 100644
index 0000000000000..6bf0071f52b93
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
new file mode 100644
index 0000000000000..4732f515bf70c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
new file mode 100644
index 0000000000000..8d6424c479a3a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
+ enter and leave calls within strub contexts, passing on the enclosing
+ watermark. */
+
+#include "torture/strub-callable1.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 15 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 15 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
new file mode 100644
index 0000000000000..368522442066e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* h becomes STRUB_INLINABLE, because of the use of the strub variable,
+ and the always_inline flag. It would get inlined before pass_ipa_strub, if
+ it weren't for the error. */
+static inline void
+__attribute__ ((__always_inline__))
+h() {
+ var++;
+}
+
+/* g becomes STRUB_AT_CALLS_OPT, because of the use of the strub variable, and
+ the viability of at-calls strubbing. Though internally a strub context, its
+ interface is not strub-enabled, so it's not callable from within strub
+ contexts. */
+static inline void
+g() {
+ var--;
+ h();
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 3 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]inlinable\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]at-calls-opt\[)\]" 1 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 1 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
new file mode 100644
index 0000000000000..b4f2888321821
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+
+static int __attribute__ ((__strub__)) var;
+
+/* g becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. It's not STRUB_AT_CALLS_OPT
+ because force_output is set for static non-inline functions when not
+ optimizing, and that keeps only_called_directly_p from returning true, which
+ makes STRUB_AT_CALLS[_OPT] non-viable. */
+static void
+g() {
+ var--;
+}
+
+/* f becomes STRUB_INTERNAL because of the use of the strub variable, and gets
+ split into STRUB_WRAPPER and STRUB_WRAPPED. */
+void
+f() {
+ var++;
+ g(); /* { dg-error "calling non-.strub." } */
+}
+
+/* { dg-final { scan-ipa-dump-times "strub \[(\]" 2 "strubm" } } */
+/* { dg-final { scan-ipa-dump-times "strub \[(\]internal\[)\]" 2 "strubm" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
new file mode 100644
index 0000000000000..e48e0610e079b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+#include "strub-tail-O2.c"
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
new file mode 100644
index 0000000000000..87cda7ab21b16
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+
+/* Check that the expected strub calls are issued.
+ Tail calls are short-circuited at -O2+. */
+
+int __attribute__ ((__strub__))
+g (int i, int j) {
+ return g (i, j);
+}
+
+/* { dg-final { scan-ipa-dump-times "strub_enter" 0 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_update" 2 "strub" } } */
+/* { dg-final { scan-ipa-dump-times "strub_leave" 0 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
new file mode 100644
index 0000000000000..eb6250fd39c90
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+
+int __attribute__ ((strub)) x;
+float __attribute__ ((strub)) f;
+double __attribute__ ((strub)) d;
+
+/* The attribute applies to the type of the declaration, i.e., to the pointer
+ variable p, not to the pointed-to integer. */
+int __attribute__ ((strub)) *
+p = &x; /* { dg-message "incompatible|invalid conversion" } */
+
+typedef int __attribute__ ((strub)) strub_int;
+strub_int *q = &x; /* Now this is compatible. */
+
+int __attribute__ ((strub))
+a[2]; /* { dg-warning "does not apply to elements" } */
+
+int __attribute__ ((vector_size (4 * sizeof (int))))
+ __attribute__ ((strub))
+v; /* { dg-warning "does not apply to elements" } */
+
+struct s {
+ int i, j;
+} __attribute__ ((strub)) w; /* { dg-warning "does not apply to fields" } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
new file mode 100644
index 0000000000000..b5e45ab0525ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that strub and non-strub functions can be called from non-strub
+ contexts, and that strub and callable functions can be called from strub
+ contexts. */
+
+#define OMIT_IMPERMISSIBLE_CALLS 1
+#include "strub-callable2.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
new file mode 100644
index 0000000000000..96aa7fe4b07f7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -0,0 +1,264 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that impermissible (cross-strub-context) calls are reported. */
+
+extern int __attribute__ ((__strub__ ("callable"))) xcallable (void);
+extern int __attribute__ ((__strub__ ("internal"))) xinternal (void);
+extern int __attribute__ ((__strub__ ("at-calls"))) xat_calls (void);
+extern int __attribute__ ((__strub__ ("disabled"))) xdisabled (void);
+
+int __attribute__ ((__strub__ ("callable"))) callable (void);
+int __attribute__ ((__strub__ ("internal"))) internal (void);
+int __attribute__ ((__strub__ ("at-calls"))) at_calls (void);
+int __attribute__ ((__strub__ ("disabled"))) disabled (void);
+
+int __attribute__ ((__strub__)) var;
+int var_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+icallable (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+iinternal (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void);
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+idisabled (void);
+static inline int __attribute__ ((__always_inline__))
+ivar_user (void);
+
+static inline int __attribute__ ((__always_inline__, __strub__ ("callable")))
+i_callable (void) { return 0; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("internal")))
+i_internal (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+i_at_calls (void) { return var; }
+static inline int __attribute__ ((__always_inline__, __strub__ ("disabled")))
+i_disabled (void) { return 0; }
+static inline int __attribute__ ((__always_inline__))
+i_var_user (void) { return var; }
+
+#define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## at_calls (); \
+ ret += i ## ISEP ## internal (); \
+ ret += i ## ISEP ## var_user (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \
+ do { \
+ ret += internal (); \
+ ret += disabled (); \
+ ret += var_user (); \
+ \
+ ret += i ## ISEP ## disabled (); \
+ \
+ ret += xinternal (); \
+ ret += xdisabled (); \
+ } while (0)
+
+#define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \
+ do { \
+ ret += i ## ISEP ## callable (); \
+ \
+ ret += callable (); \
+ ret += at_calls (); \
+ \
+ ret += xat_calls (); \
+ ret += xcallable (); \
+ } while (0)
+
+/* Not a strub context, so it can call anything.
+ Explicitly declared as callable even from within strub contexts. */
+int __attribute__ ((__strub__ ("callable")))
+callable (void) {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+/* Internal strubbing means the body is a strub context, so it can only call
+ strub functions, and it's not itself callable from strub functions. */
+int __attribute__ ((__strub__ ("internal")))
+internal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("at-calls")))
+at_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+disabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += iat_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += iinternal (); /* { dg-error "in non-.strub. context" } */
+ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT();
+
+ return ret;
+}
+
+int
+var_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT();
+ CALLS_GOOD_FOR_EITHER_CONTEXT();
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += idisabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+icallable (void)
+{
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+iinternal (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int __attribute__ ((__always_inline__, __strub__ ("at-calls")))
+iat_calls (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
+
+int
+idisabled () {
+ int ret = 0;
+
+ /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */
+ ret += i_internal (); /* { dg-error "in non-.strub. context" } */
+ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */
+#endif
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_);
+
+ return ret;
+}
+
+int
+ivar_user (void) {
+ int ret = var;
+
+ CALLS_GOOD_FOR_STRUB_CONTEXT(_);
+ CALLS_GOOD_FOR_EITHER_CONTEXT(_);
+ /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */
+#if !OMIT_IMPERMISSIBLE_CALLS
+ ret += internal (); /* { dg-error "in .strub. context" } */
+ ret += disabled (); /* { dg-error "in .strub. context" } */
+ ret += var_user (); /* { dg-error "in .strub. context" } */
+
+ ret += i_disabled (); /* { dg-error "in .strub. context" } */
+
+ ret += xinternal (); /* { dg-error "in .strub. context" } */
+ ret += xdisabled (); /* { dg-error "in .strub. context" } */
+#endif
+
+ return ret;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
new file mode 100644
index 0000000000000..2857195706ed6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const function call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __const__))
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
new file mode 100644
index 0000000000000..98a92bc9eac2b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const function call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
new file mode 100644
index 0000000000000..5511a6e1e71d3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub const wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is held in memory before the call,
+ and another to make sure it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __const__))
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
new file mode 100644
index 0000000000000..47ee927964dff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-const wrapping call, we issue an
+ asm statement to make sure the watermark passed to it is held in memory
+ before the call, and another to make sure it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__
+__attribute__ ((__const__))
+#endif
+f() {
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
new file mode 100644
index 0000000000000..7c27a2a1a6dca
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointed-to data enables strubbing if accessed. */
+int __attribute__ ((__strub__)) var;
+
+int f() {
+ return var;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
new file mode 100644
index 0000000000000..e66d903780afd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, enabling internal strubbing when
+ its value is used. */
+int __attribute__ ((__strub__)) *ptr;
+
+int *f() {
+ return ptr;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
new file mode 100644
index 0000000000000..5e08e0e58c658
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) var;
+
+void f() {
+ var = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
new file mode 100644
index 0000000000000..a818e7a38bb5f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* The pointer itself is a strub variable, that would enable internal strubbing
+ if its value was used. Here, it's only overwritten, so no strub. */
+int __attribute__ ((__strub__)) *ptr;
+
+void f() {
+ ptr = 0;
+}
+
+/* { dg-final { scan-ipa-dump-not "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
new file mode 100644
index 0000000000000..ddb0b5c0543b0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+/* It would be desirable to issue at least warnings for these. */
+
+typedef int __attribute__ ((__strub__)) strub_int;
+strub_int *ptr;
+
+int *f () {
+ return ptr; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+strub_int *g () {
+ return f (); /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
new file mode 100644
index 0000000000000..c165f312f16de
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype ();
+fntype (*ptr);
+
+void f() {
+ ptr ();
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(&\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
new file mode 100644
index 0000000000000..69fcff8d3763d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
new file mode 100644
index 0000000000000..ff006224909bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
+fntype (*ptr);
+
+void f() {
+ ptr (0, 0, 1, 1);
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "(0, 0, &\.strub\.watermark\.\[0-9\]\+, 1, 1)" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
new file mode 100644
index 0000000000000..614b02228ba29
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+inline void __attribute__ ((strub ("internal"), always_inline))
+inl_int_ali (void)
+{
+ /* No internal wrapper, so this body ALWAYS gets inlined,
+ but it cannot be called from non-strub contexts. */
+}
+
+void
+bat (void)
+{
+ /* Not allowed, not a strub context. */
+ inl_int_ali (); /* { dg-error "context" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
new file mode 100644
index 0000000000000..f9a6b4a16faf8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=all" } */
+
+#include "strub-inlinable1.c"
+
+/* With -fstrub=all, the caller becomes a strub context, so the strub-inlinable
+ callee is not rejected. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
new file mode 100644
index 0000000000000..b4a7f3992bbaa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict" } */
+
+typedef void ft (void);
+typedef void ft2 (int, int);
+extern ft __attribute__ ((__strub__)) fnac;
+
+ft * f (void) {
+ return fnac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
new file mode 100644
index 0000000000000..d9d2c0caec42d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+
+/* C++ does not warn about the partial incompatibilities.
+
+ The d_p () calls are actually rejected, even in C++, but they are XFAILed
+ here because we don't get far enough in the compilation as to observe them,
+ because the incompatibilities are errors without -fpermissive.
+ strub-ptrfn3.c uses -fpermissive to check those.
+ */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" "" { xfail c++ } } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
new file mode 100644
index 0000000000000..e1f179e160e5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
+/* { dg-prune-output "command-line option .-fpermissive." } */
+
+/* See strub-ptrfn2.c. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bad; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bar; /* { dg-warning "not quite compatible" "" { xfail c++ } } */
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+
+ d_p (); /* { dg-error "indirect non-.strub. call in .strub. context" } */
+ c_p ();
+ a_p ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
new file mode 100644
index 0000000000000..70b558afad040
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=relaxed" } */
+
+/* This is strub-ptrfn2.c without -Wpedantic.
+
+ Even C doesn't report the (not-quite-)compatible conversions without it. */
+
+extern int __attribute__ ((strub ("callable"))) bac (void);
+extern int __attribute__ ((strub ("disabled"))) bad (void);
+extern int __attribute__ ((strub ("internal"))) bar (void);
+extern int __attribute__ ((strub ("at-calls"))) bal (void);
+
+void __attribute__ ((strub))
+bap (void)
+{
+ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bad;
+ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bac;
+ int __attribute__ ((strub ("at-calls"))) (*a_p) (void) = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
+
+void __attribute__ ((strub))
+baP (void)
+{
+ typedef int __attribute__ ((strub ("disabled"))) d_fn_t (void);
+ typedef int __attribute__ ((strub ("callable"))) c_fn_t (void);
+ typedef int __attribute__ ((strub ("at-calls"))) a_fn_t (void);
+
+ d_fn_t *d_p = bad;
+ c_fn_t *c_p = bac;
+ a_fn_t *a_p = bal;
+
+ d_p = bac;
+ c_p = bad;
+ c_p = bar;
+ c_p = bal; /* { dg-message "incompatible|invalid conversion" } */
+ a_p = bac; /* { dg-message "incompatible|invalid conversion" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
new file mode 100644
index 0000000000000..a262a086837b2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure function call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__, __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
new file mode 100644
index 0000000000000..4c4bd50c209a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure function call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+int
+g() {
+ return f();
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
new file mode 100644
index 0000000000000..ce195c6b1f1b6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub pure wrapping call, we issue an asm statement
+ to make sure the watermark passed to it is not assumed to be unchanged. */
+
+int __attribute__ ((__strub__ ("internal"), __pure__))
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
new file mode 100644
index 0000000000000..75cd54ccb5b5d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
+ statement to make sure the watermark passed to it is not assumed to be
+ unchanged. */
+
+int __attribute__ ((__strub__ ("internal")))
+#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */
+__attribute__ ((__pure__))
+#endif
+f() {
+ static int i; /* Stop it from being detected as const. */
+ return i;
+}
+
+/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
new file mode 100644
index 0000000000000..7458b3fb54da5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Avoid the use of red zones by avoiding
+ leaf functions. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ /* We use this variable to avoid any stack red zone. Stack scrubbing covers
+ it, but __builtin_stack_address, that we take as a reference, doesn't, so
+ if e.g. callable() were to store the string in the red zone, we wouldn't
+ find it because it would be outside the range we searched. */
+ typedef void __attribute__ ((__strub__ ("callable"))) callable_t (char *);
+ callable_t *f = 0;
+
+ char s[2 * PAD + 1][sizeof (test_string)];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s), "+r" (f));
+
+ if (__builtin_expect (!f, 1))
+ return (char *) __builtin_stack_address ();
+
+ f (s[PAD]);
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
new file mode 100644
index 0000000000000..5d60a7775f4bb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -0,0 +1,84 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. Allow red zones to be used. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+/* Pad before and after the string on the stack, so that it's not overwritten by
+ regular stack use. */
+#define PAD 7
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ asm ("" : "+rm" (len));
+ char s[2 * PAD + 1][len];
+ __builtin_strcpy (s[PAD], test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
new file mode 100644
index 0000000000000..c2ad710858e87
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that a non-strub function leaves a string behind in the stack, and that
+ equivalent strub functions don't. */
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__, __strub__ ("callable")))
+char *
+leak_string (void)
+{
+ int len = sizeof (test_string);
+ char *s = (char *) __builtin_alloca (len);
+ __builtin_strcpy (s, test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static __attribute__ ((__noinline__, __noclone__))
+char *
+callable ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("at-calls")))
+char *
+at_calls ()
+{
+ return leak_string ();
+}
+
+static __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return leak_string ();
+}
+
+int main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (!look_for_string (callable ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (at_calls ()))
+ if (!i--) __builtin_abort ();
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
new file mode 100644
index 0000000000000..3b36b8e5d68ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -0,0 +1,106 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target alloca } */
+
+/* Check that multi-level, multi-inlined functions still get cleaned up as
+ expected, without overwriting temporary stack allocations while they should
+ still be available. */
+
+#ifndef ATTR_STRUB_AT_CALLS
+# define ATTR_STRUB_AT_CALLS /* Defined in strub-run4d.c. */
+#endif
+
+const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa";
+
+static inline __attribute__ ((__always_inline__))
+char *
+leak_string (void)
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ return (char *) __builtin_stack_address ();
+}
+
+static inline __attribute__ ((__always_inline__))
+int
+look_for_string (char *e)
+{
+ char *p = (char *) __builtin_stack_address ();
+
+ if (p == e)
+ __builtin_abort ();
+
+ if (p > e)
+ {
+ char *q = p;
+ p = e;
+ e = q;
+ }
+
+ for (char *re = e - sizeof (test_string); p < re; p++)
+ for (int i = 0; p[i] == test_string[i]; i++)
+ if (i == sizeof (test_string) - 1)
+ return i;
+
+ return 0;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+innermost ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = leak_string ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline ATTR_STRUB_AT_CALLS
+char *
+intermediate ()
+{
+ int __attribute__ ((__strub__)) len = 512;
+ asm ("" : "+r" (len));
+ char s[len];
+ __builtin_strcpy (s, test_string);
+ __builtin_strcpy (s + len - sizeof (test_string), test_string);
+ asm ("" : "+m" (s));
+ char *ret = innermost ();
+ if (__builtin_strcmp (s, test_string) != 0)
+ __builtin_abort ();
+ if (__builtin_strcmp (s + len - sizeof (test_string), test_string) != 0)
+ __builtin_abort ();
+ return ret;
+}
+
+static inline __attribute__ ((__strub__ ("internal")))
+char *
+internal ()
+{
+ return intermediate ();
+}
+
+int __attribute__ ((__strub__ ("disabled")))
+main ()
+{
+ /* Since these test check stack contents above the top of the stack, an
+ unexpected asynchronous signal or interrupt might overwrite the bits we
+ expect to find and cause spurious fails. Tolerate one such overall
+ spurious fail by retrying. */
+ int i = 1;
+ while (look_for_string (internal ()))
+ if (!i--) __builtin_abort ();
+ __builtin_exit (0);
+}
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
new file mode 100644
index 0000000000000..57f9baf758ded
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=at-calls" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
new file mode 100644
index 0000000000000..08de3f1c3b17c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target alloca } */
+
+#define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
new file mode 100644
index 0000000000000..459f6886c5499
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-fstrub=internal" } */
+/* { dg-require-effective-target alloca } */
+
+#include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
new file mode 100644
index 0000000000000..0d367fb83d09d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -0,0 +1,19 @@
+// { dg-do run }
+// { dg-options "-fstrub=internal" }
+
+// Check that we don't get extra copies.
+
+struct T {
+ T &self;
+ void check () const { if (&self != this) __builtin_abort (); }
+ T() : self (*this) { check (); }
+ T(const T& ck) : self (*this) { ck.check (); check (); }
+ ~T() { check (); }
+};
+
+T foo (T q) { q.check (); return T(); }
+T bar (T p) { p.check (); return foo (p); }
+
+int main () {
+ bar (T()).check ();
+}
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
new file mode 100644
index 0000000000000..c226ab10ff651
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ static int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
new file mode 100644
index 0000000000000..a7911f1fa7212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+static int x = initializer ();
+
+int f() {
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
new file mode 100644
index 0000000000000..6ebebcd01e8ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+
+extern int __attribute__((__strub__)) initializer ();
+
+int f() {
+ int x = initializer ();
+ return x;
+}
+
+/* { dg-final { scan-ipa-dump "strub_enter" "strub" } } */
+/* { dg-final { scan-ipa-dump "strub_leave" "strub" } } */
+/* { dg-final { scan-ipa-dump-not "strub_update" "strub" } } */
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
new file mode 100644
index 0000000000000..29e6996ecf61c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+
+-- The main subprogram doesn't read from the automatic variable, but
+-- being an automatic variable, its presence should be enough for the
+-- procedure to get strub enabled.
+
+procedure Strub_Access is
+ type Strub_Int is new Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ X : aliased Strub_Int := 0;
+
+ function F (P : access Strub_Int) return Strub_Int is (P.all);
+
+begin
+ X := F (X'Access);
+end Strub_Access;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls-opt\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
new file mode 100644
index 0000000000000..dae4706016436
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed" }
+
+-- Check that we reject 'Access of a strub variable whose type does
+-- not carry a strub modifier.
+
+procedure Strub_Access1 is
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function F (P : access Integer) return Integer is (P.all);
+
+begin
+ X := F (X'Unchecked_access); -- OK.
+ X := F (X'Access); -- { dg-error "target access type drops .strub. mode" }
+end Strub_Access1;
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
new file mode 100644
index 0000000000000..10445d7cf8451
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -0,0 +1,37 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+
+package body Strub_Attr is
+ E : exception;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (F (X));
+ -- function G return Integer is (FP (X));
+ -- Calling G would likely raise an exception, because although FP
+ -- carries the strub at-calls attribute needed to call F, the
+ -- attribute is dropped from the type used for the call proper.
+end Strub_Attr;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 2 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 0 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark_ptr" 6 "strub" } }
+-- We have 1 at-calls subprogram (F) and 2 wrapped (P and G).
+-- For each of them, there's one match for the wrapped signature,
+-- and one for the update call.
+
+-- { dg-final { scan-ipa-dump-times "strub.watermark" 27 "strub" } }
+-- The 6 matches above, plus:
+-- 5*2: wm var decl, enter, call, leave and clobber for each wrapper;
+-- 2*1: an extra leave and clobber for the exception paths in the wrappers.
+-- 7*1: for the F call in G, including EH path.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.ads b/gcc/testsuite/gnat.dg/strub_attr.ads
new file mode 100644
index 0000000000000..a94c23bf41833
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_attr.ads
@@ -0,0 +1,12 @@
+package Strub_Attr is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ function G return Integer;
+end Strub_Attr;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
new file mode 100644
index 0000000000000..3dbcc4a357cba
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -0,0 +1,64 @@
+-- { dg-do compile }
+
+procedure Strub_Disp is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X));
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Disp;
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
new file mode 100644
index 0000000000000..09756a74b7d81
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -0,0 +1,79 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls are transformed.
+
+procedure Strub_Disp1 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ P (I, A (X)); -- strub-at-calls non-dispatching call
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : A'Class) is
+ begin
+ P (-1, X); -- strub-at-calls dispatching call.
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access A'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access); -- strub-at-calls non-dispatching call
+ I := I + F (XB'Access); -- strub-at-calls non-dispatching call
+
+ XC := XA'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+
+ XC := XB'Access;
+ I := I + F (XC); -- strub-at-calls dispatching call.
+end Strub_Disp1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 3 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
new file mode 100644
index 0000000000000..da56acaa957d2
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -0,0 +1,33 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but applying attributes to access types as well.
+-- That doesn't quite work yet, so we get an error we shouldn't get.
+
+package body Strub_Ind is
+ E : exception;
+
+ function G return Integer;
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * X;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+
+ type GT_SAC is access function return Integer;
+ pragma Machine_Attribute (GT_SAC, "strub", "at-calls");
+
+ GP : GT_SAC := GT_SAC (GT'(G'Access)); -- { dg-error "incompatible" }
+ -- pragma Machine_Attribute (GP, "strub", "at-calls");
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind.ads b/gcc/testsuite/gnat.dg/strub_ind.ads
new file mode 100644
index 0000000000000..99a65fc24b1ec
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind.ads
@@ -0,0 +1,17 @@
+package Strub_Ind is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ -- pragma Machine_Attribute (FP, "strub", "at-calls"); -- not needed
+
+end Strub_Ind;
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
new file mode 100644
index 0000000000000..825e395e6819c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -0,0 +1,41 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind1 is
+ E : exception;
+
+ type Strub_Int is New Integer;
+ pragma Machine_Attribute (Strub_Int, "strub");
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "disabled");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "disabled");
+
+ type GT_SC is access function return Integer;
+ pragma Machine_Attribute (GT_SC, "strub", "callable");
+
+ GP : GT_SC := GT_SC (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "callable"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all;
+ end;
+
+end Strub_Ind1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]disabled\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.ads b/gcc/testsuite/gnat.dg/strub_ind1.ads
new file mode 100644
index 0000000000000..d3f1273b3a6b9
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind1.ads
@@ -0,0 +1,17 @@
+package Strub_Ind1 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : aliased Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind1;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
new file mode 100644
index 0000000000000..e918b39263117
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -0,0 +1,34 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict" }
+
+-- This is essentially the same test as strub_attr.adb,
+-- but with an explicit conversion.
+
+package body Strub_Ind2 is
+ E : exception;
+
+ function G return Integer;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is
+ begin
+ raise E;
+ end;
+
+ function G return Integer is (FP (X));
+
+ type GT is access function return Integer;
+ pragma Machine_Attribute (GT, "strub", "callable");
+
+ type GT_SD is access function return Integer;
+ pragma Machine_Attribute (GT_SD, "strub", "disabled");
+
+ GP : GT_SD := GT_SD (GT'(G'Access));
+ -- pragma Machine_Attribute (GP, "strub", "disabled"); -- not needed.
+
+ function F (X : Integer) return Integer is
+ begin
+ return X * GP.all; -- { dg-error "using non-.strub. type" }
+ end;
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.ads b/gcc/testsuite/gnat.dg/strub_ind2.ads
new file mode 100644
index 0000000000000..e13865ec49c38
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_ind2.ads
@@ -0,0 +1,17 @@
+package Strub_Ind2 is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "internal");
+
+ function F (X : Integer) return Integer;
+ pragma Machine_Attribute (F, "strub");
+
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+
+ type FT is access function (X : Integer) return Integer;
+ pragma Machine_Attribute (FT, "strub", "at-calls");
+
+ FP : FT := F'Access;
+ pragma Machine_Attribute (FP, "strub", "at-calls");
+
+end Strub_Ind2;
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
new file mode 100644
index 0000000000000..8f0212a75866f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -0,0 +1,93 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported.
+
+procedure Strub_Intf is
+ package Foo is
+ type TP is interface;
+ procedure P (I : Integer; X : TP) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type TF is interface;
+ function F (X : access TF) return Integer is abstract;
+
+ type TX is interface;
+ procedure P (I : Integer; X : TX) is abstract;
+
+ type TI is interface and TP and TF and TX;
+ -- When we freeze TI, we detect the mismatch between the
+ -- inherited P and another parent's P. Because TP appears
+ -- before TX, we inherit P from TP, and report the mismatch at
+ -- the pragma inherited from TP against TX's P. In contrast,
+ -- when we freeze TII below, since TX appears before TP, we
+ -- report the error at the line in which the inherited
+ -- subprogram is synthesized, namely the line below, against
+ -- the line of the pragma.
+
+ type TII is interface and TX and TP and TF; -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access TI) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ type A is new TI with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer; -- { dg-error "requires the same .strub. mode" }
+
+ type B is new TI with null record;
+
+ overriding
+ procedure P (I : Integer; X : B); -- { dg-error "requires the same .strub. mode" }
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TI'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf;
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
new file mode 100644
index 0000000000000..bf77321cef790
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -0,0 +1,86 @@
+-- { dg-do compile }
+-- { dg-options "-fdump-ipa-strub" }
+
+-- Check that at-calls dispatching calls to interfaces are transformed.
+
+procedure Strub_Intf1 is
+ package Foo is
+ type TX is Interface;
+ procedure P (I : Integer; X : TX) is abstract;
+ pragma Machine_Attribute (P, "strub", "at-calls");
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type A is new TX with null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F (X : access A) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new TX with null record;
+
+ overriding
+ procedure P (I : Integer; X : B);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ overriding
+ function F (X : access B) return Integer;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ overriding
+ procedure P (I : Integer; X : B) is
+ begin
+ null;
+ end;
+
+ overriding
+ function F (X : access B) return Integer is (1);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XA : aliased A;
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XA);
+ Q (XB);
+
+ I := I + F (XA'Access);
+ I := I + F (XB'Access);
+
+ XC := XA'Access;
+ I := I + F (XC);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf1;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 4 "strub" } }
+
+-- Count the strub-at-calls non-dispatching calls
+-- (+ 2 each, for the matching prototypes)
+-- { dg-final { scan-ipa-dump-times "foo\.p \[(\]\[^\n\]*watermark" 2 "strub" } }
+-- { dg-final { scan-ipa-dump-times "foo\.f \[(\]\[^\n\]*watermark" 4 "strub" } }
+
+-- Count the strub-at-calls dispatching calls.
+-- { dg-final { scan-ipa-dump-times "_\[0-9\]* \[(\]\[^\n\]*watermark" 3 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
new file mode 100644
index 0000000000000..e8880dbc43730
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -0,0 +1,55 @@
+-- { dg-do compile }
+
+-- Check that strub mode mismatches between overrider and overridden
+-- subprograms are reported even when the overriders for an
+-- interface's subprograms are inherited from a type that is not a
+-- descendent of the interface.
+
+procedure Strub_Intf2 is
+ package Foo is
+ type A is tagged null record;
+
+ procedure P (I : Integer; X : A);
+ pragma Machine_Attribute (P, "strub", "at-calls"); -- { dg-error "requires the same .strub. mode" }
+
+ function F (X : access A) return Integer;
+
+ type TX is Interface;
+
+ procedure P (I : Integer; X : TX) is abstract;
+
+ function F (X : access TX) return Integer is abstract;
+ pragma Machine_Attribute (F, "strub", "at-calls");
+
+ type B is new A and TX with null record; -- { dg-error "requires the same .strub. mode" }
+
+ end Foo;
+
+ package body Foo is
+ procedure P (I : Integer; X : A) is
+ begin
+ null;
+ end;
+
+ function F (X : access A) return Integer is (0);
+
+ end Foo;
+
+ use Foo;
+
+ procedure Q (X : TX'Class) is
+ begin
+ P (-1, X);
+ end;
+
+ XB : aliased B;
+ I : Integer := 0;
+ XC : access TX'Class;
+begin
+ Q (XB);
+
+ I := I + F (XB'Access);
+
+ XC := XB'Access;
+ I := I + F (XC);
+end Strub_Intf2;
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
new file mode 100644
index 0000000000000..217367e712d82
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -0,0 +1,21 @@
+-- { dg-do compile }
+
+procedure Strub_Renm is
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+ pragma Machine_Attribute (F, "strub", "internal");
+
+ procedure Q (X : Integer) renames P; -- { dg-error "requires the same .strub. mode" }
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "callable"); -- { dg-error "requires the same .strub. mode" }
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm;
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
new file mode 100644
index 0000000000000..a11adbfb5a9d6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+
+procedure Strub_Renm1 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ function G return Integer renames F;
+ pragma Machine_Attribute (G, "strub", "internal");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F);
+ Q (G);
+end Strub_Renm1;
+
+-- This is for P; Q is an alias.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]at-calls\[)\]\[)\]" 1 "strub" } }
+
+-- This is *not* for G, but for Strub_Renm1.
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapped\[)\]\[)\]" 1 "strub" } }
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]wrapper\[)\]\[)\]" 1 "strub" } }
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
new file mode 100644
index 0000000000000..c488c20826fdb
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strub" }
+
+procedure Strub_Renm2 is
+ V : Integer := 0;
+ pragma Machine_Attribute (V, "strub");
+
+ procedure P (X : Integer);
+ pragma Machine_Attribute (P, "strub", "at-calls");
+
+ function F return Integer;
+
+ procedure Q (X : Integer) renames P;
+ pragma Machine_Attribute (Q, "strub", "at-calls");
+
+ type T is access function return Integer;
+
+ type TC is access function return Integer;
+ pragma Machine_Attribute (TC, "strub", "callable");
+
+ FCptr : constant TC := TC (T'(F'Access));
+
+ function G return Integer renames FCptr.all;
+ pragma Machine_Attribute (G, "strub", "callable");
+
+ procedure P (X : Integer) is null;
+ function F return Integer is (0);
+
+begin
+ P (F); -- { dg-error "calling non-.strub." }
+ Q (G); -- ok, G is callable.
+end Strub_Renm2;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
new file mode 100644
index 0000000000000..3d158de28031f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+
+-- We don't read from the automatic variable, but being an automatic
+-- variable, its presence should be enough for the procedure to get
+-- strub enabled.
+
+with Strub_Attr;
+procedure Strub_Var is
+ X : Integer := 0;
+ pragma Machine_Attribute (X, "strub");
+begin
+ X := Strub_Attr.F (0);
+end Strub_Var;
+
+-- { dg-final { scan-ipa-dump-times "\[(\]strub \[(\]internal\[)\]\[)\]" 1 "strubm" } }
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
new file mode 100644
index 0000000000000..6a504e09198b6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -0,0 +1,20 @@
+-- { dg-do compile }
+
+with Strub_Attr;
+procedure Strub_Var1 is
+ type TA -- { dg-warning "does not apply to elements" }
+ is array (1..2) of Integer;
+ pragma Machine_Attribute (TA, "strub");
+
+ A : TA := (0, 0); -- { dg-warning "does not apply to elements" }
+
+ type TR is record -- { dg-warning "does not apply to fields" }
+ M, N : Integer;
+ end record;
+ pragma Machine_Attribute (TR, "strub");
+
+ R : TR := (0, 0);
+
+begin
+ A(2) := Strub_Attr.F (A(1));
+end Strub_Var1;
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index a30a2de33a106..cefbb86be7bb4 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -5790,6 +5790,7 @@ gimple_verify_flow_info (void)
{
gimple *stmt = gsi_stmt (gsi);
+ /* Do NOT disregard debug stmts after found_ctrl_stmt. */
if (found_ctrl_stmt)
{
error ("control flow in the middle of basic block %d",
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 09e6ada5b2f91..36f955a0b37ee 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -510,8 +510,9 @@ extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
-extern simple_ipa_opt_pass
- *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_strub (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tree_profile (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_auto_profile (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 1a555ae682638..03ff88afadddd 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -3073,7 +3073,9 @@ optimize_stack_restore (gimple_stmt_iterator i)
if (!callee
|| !fndecl_built_in_p (callee, BUILT_IN_NORMAL)
/* All regular builtins are ok, just obviously not alloca. */
- || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)))
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
+ /* Do not remove stack updates before strub leave. */
+ || fndecl_built_in_p (callee, BUILT_IN___STRUB_LEAVE))
return NULL_TREE;
if (fndecl_built_in_p (callee, BUILT_IN_STACK_RESTORE))
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 8dedd10f79a30..d8163c5af9903 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -433,6 +433,9 @@ LIB2ADD += enable-execute-stack.c
# Control Flow Redundancy hardening out-of-line checker.
LIB2ADD += $(srcdir)/hardcfr.c
+# Stack scrubbing infrastructure.
+LIB2ADD += $(srcdir)/strub.c
+
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
# instead of LIB2ADD because that's the way to be sure on some targets
# (e.g. *-*-darwin*) only one copy of it is linked.
diff --git a/libgcc/libgcc-std.ver.in b/libgcc/libgcc-std.ver.in
index de00db647570c..a6b89632cae3e 100644
--- a/libgcc/libgcc-std.ver.in
+++ b/libgcc/libgcc-std.ver.in
@@ -1957,4 +1957,7 @@ GCC_14.0.0 {
__PFX__floatbitintsf
__PFX__floatbitintdf
__PFX__hardcfr_check
+ __PFX__strub_enter
+ __PFX__strub_update
+ __PFX__strub_leave
}
diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h
index 7e6696d7ab14a..750670e8caaf3 100644
--- a/libgcc/libgcc2.h
+++ b/libgcc/libgcc2.h
@@ -554,6 +554,10 @@ extern int __parityDI2 (UDWtype);
extern void __enable_execute_stack (void *);
+extern void __strub_enter (void **);
+extern void __strub_update (void**);
+extern void __strub_leave (void **);
+
#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
#endif
diff --git a/libgcc/strub.c b/libgcc/strub.c
new file mode 100644
index 0000000000000..b0f990d9deebb
--- /dev/null
+++ b/libgcc/strub.c
@@ -0,0 +1,149 @@
+/* Stack scrubbing infrastructure
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@adacore.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+#include "libgcc2.h"
+
+#if ! STACK_GROWS_DOWNWARD
+# define TOPS >
+#else
+# define TOPS <
+#endif
+
+#define ATTRIBUTE_STRUB_CALLABLE __attribute__ ((__strub__ ("callable")))
+
+/* Enter a stack scrubbing context, initializing the watermark to the caller's
+ stack address. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_enter (void **watermark)
+{
+ *watermark = __builtin_frame_address (0);
+}
+
+/* Update the watermark within a stack scrubbing context with the current stack
+ pointer. */
+void ATTRIBUTE_STRUB_CALLABLE
+__strub_update (void **watermark)
+{
+ void *sp = __builtin_frame_address (0);
+
+ if (sp TOPS *watermark)
+ *watermark = sp;
+}
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY && ! defined TARGET_STRUB_MAY_USE_MEMSET
+# define TARGET_STRUB_MAY_USE_MEMSET 1
+#endif
+
+#if defined __x86_64__ && __OPTIMIZE__
+# define TARGET_STRUB_DISABLE_RED_ZONE \
+ /* __attribute__ ((__target__ ("no-red-zone"))) // not needed when optimizing */
+#elif !defined RED_ZONE_SIZE || defined __i386__
+# define TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+
+#ifndef TARGET_STRUB_DISABLE_RED_ZONE
+/* Dummy function, called to force the caller to not be a leaf function, so
+ that it can't use the red zone. */
+static void ATTRIBUTE_STRUB_CALLABLE
+__attribute__ ((__noinline__, __noipa__))
+__strub_dummy_force_no_leaf (void)
+{
+}
+#endif
+
+/* Leave a stack scrubbing context, clearing the stack between its top and
+ *MARK. */
+void ATTRIBUTE_STRUB_CALLABLE
+#if ! TARGET_STRUB_MAY_USE_MEMSET
+__attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
+#endif
+#ifdef TARGET_STRUB_DISABLE_RED_ZONE
+TARGET_STRUB_DISABLE_RED_ZONE
+#endif
+__strub_leave (void **mark)
+{
+ void *sp = __builtin_stack_address ();
+
+ void **base, **end;
+#if ! STACK_GROWS_DOWNWARD
+ base = sp; /* ??? Do we need an offset here? */
+ end = *mark;
+#else
+ base = *mark;
+ end = sp; /* ??? Does any platform require an offset here? */
+#endif
+
+ if (! (base < end))
+ return;
+
+#if TARGET_STRUB_USE_DYNAMIC_ARRAY
+ /* Compute the length without assuming the pointers are both sufficiently
+ aligned. They should be, but pointer differences expected to be exact may
+ yield unexpected results when the assumption doesn't hold. Given the
+ potential security implications, compute the length without that
+ expectation. If the pointers are misaligned, we may leave a partial
+ unscrubbed word behind. */
+ ptrdiff_t len = ((char *)end - (char *)base) / sizeof (void *);
+ /* Allocate a dynamically-sized array covering the desired range, so that we
+ can safely call memset on it. */
+ void *ptr[len];
+ base = &ptr[0];
+ end = &ptr[len];
+#elifndef TARGET_STRUB_DISABLE_RED_ZONE
+ /* Prevent the use of the red zone, by making this function non-leaf through
+ an unreachable call that, because of the asm stmt, the compiler will
+ consider reachable. */
+ asm goto ("" : : : : no_leaf);
+ if (0)
+ {
+ no_leaf:
+ __strub_dummy_force_no_leaf ();
+ return;
+ }
+#endif
+
+ /* ldist may turn these loops into a memset (thus the conditional
+ -fno-tree-loop-distribute-patterns above). Without the dynamic array
+ above, that call would likely be unsafe: possibly tail-called, and likely
+ scribbling over its own stack frame. */
+#if ! STACK_GROWS_DOWNWARD
+ do
+ *base++ = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (end[0]));
+#else
+ do
+ *--end = 0;
+ while (base < end);
+ /* Make sure the stack overwrites are not optimized away. */
+ asm ("" : : "m" (base[0]));
+#endif
+}
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Causes to nvptx bootstrap fail: [PATCH v5] Introduce strub: machine-independent stack scrubbing
2023-12-02 17:56 ` [PATCH v5] " Alexandre Oliva
@ 2023-12-06 8:36 ` Tobias Burnus
2023-12-06 11:32 ` Thomas Schwinge
0 siblings, 1 reply; 521+ messages in thread
From: Tobias Burnus @ 2023-12-06 8:36 UTC (permalink / raw)
To: Alexandre Oliva, Richard Biener, Thomas Schwinge
Cc: gcc-patches, Jeremy Bennett, Craig Blackmore, Graham Markall,
Martin Jambor, Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek
Hi,
CC'd Thomas.
FYI the newly added file libgcc/strub.c of this patch (aka commit r14-6201-gf0a90c7d7333fc )
causes that nvptx does not bootstrap, failing with:
./gcc/as -v -o strub.o strub.s
Verifying sm_30 code with sm_50 code generation.
ptxas -c -o /dev/null strub.o --gpu-name sm_50 -O0
ptxas strub.o, line 22; error : Arguments mismatch for instruction 'st'
ptxas strub.o, line 22; error : Unknown symbol '%frame'
ptxas strub.o, line 37; error : Arguments mismatch for instruction 'setp'
ptxas strub.o, line 40; error : Arguments mismatch for instruction 'st'
ptxas strub.o, line 37; error : Unknown symbol '%frame'
ptxas strub.o, line 40; error : Unknown symbol '%frame'
ptxas strub.o, line 59; error : Arguments mismatch for instruction 'mov'
ptxas strub.o, line 67; error : Arguments mismatch for instruction 'setp'
ptxas strub.o, line 59; error : Unknown symbol '%stack'
ptxas strub.o, line 67; error : Unknown symbol '%stack'
ptxas fatal : Ptx assembly aborted due to errors
nvptx-as: ptxas returned 255 exit status
That's
.visible .func __strub_enter (.param.u64 %in_ar0)
{
.reg.u64 %ar0;
ld.param.u64 %ar0, [%in_ar0];
.reg.u64 %r23;
mov.u64 %r23, %ar0;
st.u64 [%r23], %frame;
...
setp.le.u64 %r26, %r25, %frame;
...
Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Causes to nvptx bootstrap fail: [PATCH v5] Introduce strub: machine-independent stack scrubbing
2023-12-06 8:36 ` Causes to nvptx bootstrap fail: " Tobias Burnus
@ 2023-12-06 11:32 ` Thomas Schwinge
2023-12-06 22:12 ` Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Thomas Schwinge @ 2023-12-06 11:32 UTC (permalink / raw)
To: Alexandre Oliva
Cc: Tobias Burnus, Richard Biener, gcc-patches, Jeremy Bennett,
Craig Blackmore, Graham Markall, Martin Jambor, Jan Hubicka,
Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
Hi Alexandre!
On 2023-12-06T09:36:33+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
> FYI the newly added file libgcc/strub.c of this patch (aka commit r14-6201-gf0a90c7d7333fc )
> causes that nvptx does not bootstrap, failing with:
('s%bootstrap%build'.)
> ./gcc/as -v -o strub.o strub.s
> Verifying sm_30 code with sm_50 code generation.
> ptxas -c -o /dev/null strub.o --gpu-name sm_50 -O0
> ptxas strub.o, line 22; error : Arguments mismatch for instruction 'st'
> ptxas strub.o, line 22; error : Unknown symbol '%frame'
> [...]
Per commit r14-6201-gf0a90c7d7333fc7f554b906245c84bdf04d716d7
"Introduce strub: machine-independent stack scrubbing", we have:
A function associated with @code{at-calls} @code{strub} mode
(@code{strub("at-calls")}, or just @code{strub}) undergoes interface
changes. Its callers are adjusted to match the changes, and to scrub
(overwrite with zeros) the stack space used by the called function after
it returns.
As I understand things, this cannot be implemented (at the call site) for
nvptx, given that the callee's stack is not visible there: PTX is unusual
in that the concept of a "standard" stack isn't exposed.
Instead of allowing "strub" pieces that can be implemented, should this
whole machinery generally be disabled (forced '-fstrub=disable', or via a
new target hook?)? The libgcc functions should then not get defined
(thus, linker error upon accidental use), or should just '__builtin_trap'
if that makes more sense? Need an effective-target for the test cases.
Alternatively, we may also leave the generic middle end handling alive,
and 'sorry' (or similar) in the nvptx back end, as necessary?
Grüße
Thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: Causes to nvptx bootstrap fail: [PATCH v5] Introduce strub: machine-independent stack scrubbing
2023-12-06 11:32 ` Thomas Schwinge
@ 2023-12-06 22:12 ` Alexandre Oliva
2023-12-07 3:33 ` [PATCH] strub: enable conditional support Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-12-06 22:12 UTC (permalink / raw)
To: Thomas Schwinge
Cc: Tobias Burnus, Richard Biener, gcc-patches, Jeremy Bennett,
Craig Blackmore, Graham Markall, Martin Jambor, Jan Hubicka,
Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
On Dec 6, 2023, Thomas Schwinge <thomas@codesourcery.com> wrote:
> As I understand things, this cannot be implemented (at the call site) for
> nvptx, given that the callee's stack is not visible there: PTX is unusual
> in that the concept of a "standard" stack isn't exposed.
Not even when one PTX function calls another? Interesting. I'd hoped
that with control over entering and leaving strub contexts, one could
(manually) ensure they'd run in the same execution domain. But if not
even that is possible, it will render the current strub implementation
entirely unusable for this target indeed.
Now, it doesn't seem to me that the build errors being experienced have
to do with that, but rather with lack of or incomplete support for
__builtin_{frame,stack}_address(). Are those errors expected when using
these builtins on this target? I'd have expected them to compile, even
if something went wrong at runtime.
> Instead of allowing "strub" pieces that can be implemented, should this
> whole machinery generally be disabled (forced '-fstrub=disable', or via a
> new target hook?)? The libgcc functions should then not get defined
> (thus, linker error upon accidental use), or should just '__builtin_trap'
> if that makes more sense? Need an effective-target for the test cases.
> Alternatively, we may also leave the generic middle end handling alive,
> and 'sorry' (or similar) in the nvptx back end, as necessary?
Disabling the runtime bits is easy, once we determine what condition we
wish to test for. I suppose testing for target support in the compiler,
issuing a 'sorry' in case the feature is required, would provide
something for libgcc configure and testsuite effective-target to test
for and decide whether to enable runtime support and run the tests.
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH] strub: enable conditional support
2023-12-06 22:12 ` Alexandre Oliva
@ 2023-12-07 3:33 ` Alexandre Oliva
2023-12-07 16:44 ` Thomas Schwinge
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-12-07 3:33 UTC (permalink / raw)
To: Thomas Schwinge
Cc: Tobias Burnus, Richard Biener, gcc-patches, Jeremy Bennett,
Craig Blackmore, Graham Markall, Martin Jambor, Jan Hubicka,
Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
On Dec 6, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
> Disabling the runtime bits is easy, once we determine what condition we
> wish to test for. I suppose testing for target support in the compiler,
> issuing a 'sorry' in case the feature is required, would provide
> something for libgcc configure and testsuite effective-target to test
> for and decide whether to enable runtime support and run the tests.
Instead of doing something equivalent to an implicit -fstrub=disable,
that would quietly compile without stack scrubbing, I thought it would
be safer to be noisy if the feature is used (requested, really) when
support is not available.
Targets that don't expose callee stacks to callers, such as nvptx, as
well as -fsplit-stack compilations, violate fundamental assumptions of
the current strub implementation. This patch enables targets to
disable strub, and disables it when -fsplit-stack is enabled.
When strub support is disabled, the testsuite will now skip strub
tests, and libgcc will not build the strub runtime components.
Regstrapped on x86_64-linux-gnu. Also tested with an additional patch
for i386.cc that mirrors the nvptx.cc change, to check that strub gets
disabled without noisy test results. Ok to install?
for gcc/ChangeLog
* target.def (have_strub_support_for): New hook.
* doc/tm.texi.in: Document it.
* doc/tm.texi: Rebuild.
* ipa-strub.cc: Include target.h.
(strub_target_support_p): New.
(can_strub_p): Call it. Test for no flag_split_stack.
(pass_ipa_strub::adjust_at_calls_call): Check for target
support.
* config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
Disable.
* doc/sourcebuild.texi (strub): Document new effective
target.
for gcc/testsuite/ChangeLog
* gcc.dg/strub-split-stack.c: New.
* gcc.dg/strub-unsupported.c: New.
* gcc.dg/strub-unsupported-2.c: New.
* gcc.dg/strub-unsupported-3.c: New.
* lib/target-supports.exp (check_effective_target_strub): New.
* c-c++-common/strub-O0.c: Require effective target strub.
* c-c++-common/strub-O1.c: Likewise.
* c-c++-common/strub-O2.c: Likewise.
* c-c++-common/strub-O2fni.c: Likewise.
* c-c++-common/strub-O3.c: Likewise.
* c-c++-common/strub-O3fni.c: Likewise.
* c-c++-common/strub-Og.c: Likewise.
* c-c++-common/strub-Os.c: Likewise.
* c-c++-common/strub-all1.c: Likewise.
* c-c++-common/strub-all2.c: Likewise.
* c-c++-common/strub-apply1.c: Likewise.
* c-c++-common/strub-apply2.c: Likewise.
* c-c++-common/strub-apply3.c: Likewise.
* c-c++-common/strub-apply4.c: Likewise.
* c-c++-common/strub-at-calls1.c: Likewise.
* c-c++-common/strub-at-calls2.c: Likewise.
* c-c++-common/strub-defer-O1.c: Likewise.
* c-c++-common/strub-defer-O2.c: Likewise.
* c-c++-common/strub-defer-O3.c: Likewise.
* c-c++-common/strub-defer-Os.c: Likewise.
* c-c++-common/strub-internal1.c: Likewise.
* c-c++-common/strub-internal2.c: Likewise.
* c-c++-common/strub-parms1.c: Likewise.
* c-c++-common/strub-parms2.c: Likewise.
* c-c++-common/strub-parms3.c: Likewise.
* c-c++-common/strub-relaxed1.c: Likewise.
* c-c++-common/strub-relaxed2.c: Likewise.
* c-c++-common/strub-short-O0-exc.c: Likewise.
* c-c++-common/strub-short-O0.c: Likewise.
* c-c++-common/strub-short-O1.c: Likewise.
* c-c++-common/strub-short-O2.c: Likewise.
* c-c++-common/strub-short-O3.c: Likewise.
* c-c++-common/strub-short-Os.c: Likewise.
* c-c++-common/strub-strict1.c: Likewise.
* c-c++-common/strub-strict2.c: Likewise.
* c-c++-common/strub-tail-O1.c: Likewise.
* c-c++-common/strub-tail-O2.c: Likewise.
* c-c++-common/strub-var1.c: Likewise.
* c-c++-common/torture/strub-callable1.c: Likewise.
* c-c++-common/torture/strub-callable2.c: Likewise.
* c-c++-common/torture/strub-const1.c: Likewise.
* c-c++-common/torture/strub-const2.c: Likewise.
* c-c++-common/torture/strub-const3.c: Likewise.
* c-c++-common/torture/strub-const4.c: Likewise.
* c-c++-common/torture/strub-data1.c: Likewise.
* c-c++-common/torture/strub-data2.c: Likewise.
* c-c++-common/torture/strub-data3.c: Likewise.
* c-c++-common/torture/strub-data4.c: Likewise.
* c-c++-common/torture/strub-data5.c: Likewise.
* c-c++-common/torture/strub-indcall1.c: Likewise.
* c-c++-common/torture/strub-indcall2.c: Likewise.
* c-c++-common/torture/strub-indcall3.c: Likewise.
* c-c++-common/torture/strub-inlinable1.c: Likewise.
* c-c++-common/torture/strub-inlinable2.c: Likewise.
* c-c++-common/torture/strub-ptrfn1.c: Likewise.
* c-c++-common/torture/strub-ptrfn2.c: Likewise.
* c-c++-common/torture/strub-ptrfn3.c: Likewise.
* c-c++-common/torture/strub-ptrfn4.c: Likewise.
* c-c++-common/torture/strub-pure1.c: Likewise.
* c-c++-common/torture/strub-pure2.c: Likewise.
* c-c++-common/torture/strub-pure3.c: Likewise.
* c-c++-common/torture/strub-pure4.c: Likewise.
* c-c++-common/torture/strub-run1.c: Likewise.
* c-c++-common/torture/strub-run2.c: Likewise.
* c-c++-common/torture/strub-run3.c: Likewise.
* c-c++-common/torture/strub-run4.c: Likewise.
* c-c++-common/torture/strub-run4c.c: Likewise.
* c-c++-common/torture/strub-run4d.c: Likewise.
* c-c++-common/torture/strub-run4i.c: Likewise.
* g++.dg/strub-run1.C: Likewise.
* g++.dg/torture/strub-init1.C: Likewise.
* g++.dg/torture/strub-init2.C: Likewise.
* g++.dg/torture/strub-init3.C: Likewise.
* gnat.dg/strub_attr.adb: Likewise.
* gnat.dg/strub_ind.adb: Likewise.
* gnat.dg/strub_access.adb: Likewise.
* gnat.dg/strub_access1.adb: Likewise.
* gnat.dg/strub_disp.adb: Likewise.
* gnat.dg/strub_disp1.adb: Likewise.
* gnat.dg/strub_ind1.adb: Likewise.
* gnat.dg/strub_ind2.adb: Likewise.
* gnat.dg/strub_intf.adb: Likewise.
* gnat.dg/strub_intf1.adb: Likewise.
* gnat.dg/strub_intf2.adb: Likewise.
* gnat.dg/strub_renm.adb: Likewise.
* gnat.dg/strub_renm1.adb: Likewise.
* gnat.dg/strub_renm2.adb: Likewise.
* gnat.dg/strub_var.adb: Likewise.
* gnat.dg/strub_var1.adb: Likewise.
for libgcc/ChangeLog
* configure.ac: Check for strub support.
* configure: Rebuilt.
* Makefile.in: Compile strub.c conditionally.
---
gcc/config/nvptx/nvptx.cc | 3 +
gcc/doc/sourcebuild.texi | 3 +
gcc/doc/tm.texi | 6 ++
gcc/doc/tm.texi.in | 2 +
gcc/ipa-strub.cc | 54 +++++++++++++++++++-
gcc/target.def | 8 +++
gcc/testsuite/c-c++-common/strub-O0.c | 1
gcc/testsuite/c-c++-common/strub-O1.c | 1
gcc/testsuite/c-c++-common/strub-O2.c | 1
gcc/testsuite/c-c++-common/strub-O2fni.c | 1
gcc/testsuite/c-c++-common/strub-O3.c | 1
gcc/testsuite/c-c++-common/strub-O3fni.c | 1
gcc/testsuite/c-c++-common/strub-Og.c | 1
gcc/testsuite/c-c++-common/strub-Os.c | 1
gcc/testsuite/c-c++-common/strub-all1.c | 1
gcc/testsuite/c-c++-common/strub-all2.c | 1
gcc/testsuite/c-c++-common/strub-apply1.c | 1
gcc/testsuite/c-c++-common/strub-apply2.c | 1
gcc/testsuite/c-c++-common/strub-apply3.c | 1
gcc/testsuite/c-c++-common/strub-apply4.c | 1
gcc/testsuite/c-c++-common/strub-at-calls1.c | 1
gcc/testsuite/c-c++-common/strub-at-calls2.c | 1
gcc/testsuite/c-c++-common/strub-defer-O1.c | 1
gcc/testsuite/c-c++-common/strub-defer-O2.c | 1
gcc/testsuite/c-c++-common/strub-defer-O3.c | 1
gcc/testsuite/c-c++-common/strub-defer-Os.c | 1
gcc/testsuite/c-c++-common/strub-internal1.c | 1
gcc/testsuite/c-c++-common/strub-internal2.c | 1
gcc/testsuite/c-c++-common/strub-parms1.c | 1
gcc/testsuite/c-c++-common/strub-parms2.c | 1
gcc/testsuite/c-c++-common/strub-parms3.c | 1
gcc/testsuite/c-c++-common/strub-relaxed1.c | 1
gcc/testsuite/c-c++-common/strub-relaxed2.c | 1
gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 1
gcc/testsuite/c-c++-common/strub-short-O0.c | 1
gcc/testsuite/c-c++-common/strub-short-O1.c | 1
gcc/testsuite/c-c++-common/strub-short-O2.c | 1
gcc/testsuite/c-c++-common/strub-short-O3.c | 1
gcc/testsuite/c-c++-common/strub-short-Os.c | 1
gcc/testsuite/c-c++-common/strub-split-stack.c | 10 ++++
gcc/testsuite/c-c++-common/strub-strict1.c | 1
gcc/testsuite/c-c++-common/strub-strict2.c | 1
gcc/testsuite/c-c++-common/strub-tail-O1.c | 1
gcc/testsuite/c-c++-common/strub-tail-O2.c | 1
gcc/testsuite/c-c++-common/strub-unsupported-2.c | 13 +++++
gcc/testsuite/c-c++-common/strub-unsupported-3.c | 18 +++++++
gcc/testsuite/c-c++-common/strub-unsupported.c | 21 ++++++++
gcc/testsuite/c-c++-common/strub-var1.c | 1
.../c-c++-common/torture/strub-callable1.c | 1
.../c-c++-common/torture/strub-callable2.c | 1
gcc/testsuite/c-c++-common/torture/strub-const1.c | 1
gcc/testsuite/c-c++-common/torture/strub-const2.c | 1
gcc/testsuite/c-c++-common/torture/strub-const3.c | 1
gcc/testsuite/c-c++-common/torture/strub-const4.c | 1
gcc/testsuite/c-c++-common/torture/strub-data1.c | 1
gcc/testsuite/c-c++-common/torture/strub-data2.c | 1
gcc/testsuite/c-c++-common/torture/strub-data3.c | 1
gcc/testsuite/c-c++-common/torture/strub-data4.c | 1
gcc/testsuite/c-c++-common/torture/strub-data5.c | 1
.../c-c++-common/torture/strub-indcall1.c | 1
.../c-c++-common/torture/strub-indcall2.c | 1
.../c-c++-common/torture/strub-indcall3.c | 1
.../c-c++-common/torture/strub-inlinable1.c | 1
.../c-c++-common/torture/strub-inlinable2.c | 1
gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 1
gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 1
gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 1
gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 1
gcc/testsuite/c-c++-common/torture/strub-pure1.c | 1
gcc/testsuite/c-c++-common/torture/strub-pure2.c | 1
gcc/testsuite/c-c++-common/torture/strub-pure3.c | 1
gcc/testsuite/c-c++-common/torture/strub-pure4.c | 1
gcc/testsuite/c-c++-common/torture/strub-run1.c | 1
gcc/testsuite/c-c++-common/torture/strub-run2.c | 1
gcc/testsuite/c-c++-common/torture/strub-run3.c | 1
gcc/testsuite/c-c++-common/torture/strub-run4.c | 1
gcc/testsuite/c-c++-common/torture/strub-run4c.c | 1
gcc/testsuite/c-c++-common/torture/strub-run4d.c | 1
gcc/testsuite/c-c++-common/torture/strub-run4i.c | 1
gcc/testsuite/g++.dg/strub-run1.C | 1
gcc/testsuite/g++.dg/torture/strub-init1.C | 1
gcc/testsuite/g++.dg/torture/strub-init2.C | 1
gcc/testsuite/g++.dg/torture/strub-init3.C | 1
gcc/testsuite/gnat.dg/strub_access.adb | 1
gcc/testsuite/gnat.dg/strub_access1.adb | 1
gcc/testsuite/gnat.dg/strub_attr.adb | 1
gcc/testsuite/gnat.dg/strub_disp.adb | 1
gcc/testsuite/gnat.dg/strub_disp1.adb | 1
gcc/testsuite/gnat.dg/strub_ind.adb | 1
gcc/testsuite/gnat.dg/strub_ind1.adb | 1
gcc/testsuite/gnat.dg/strub_ind2.adb | 1
gcc/testsuite/gnat.dg/strub_intf.adb | 1
gcc/testsuite/gnat.dg/strub_intf1.adb | 1
gcc/testsuite/gnat.dg/strub_intf2.adb | 1
gcc/testsuite/gnat.dg/strub_renm.adb | 1
gcc/testsuite/gnat.dg/strub_renm1.adb | 1
gcc/testsuite/gnat.dg/strub_renm2.adb | 1
gcc/testsuite/gnat.dg/strub_var.adb | 1
gcc/testsuite/gnat.dg/strub_var1.adb | 1
gcc/testsuite/lib/target-supports.exp | 7 +++
libgcc/Makefile.in | 2 -
libgcc/configure | 26 ++++++++++
libgcc/configure.ac | 13 +++++
103 files changed, 272 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/strub-split-stack.c
create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported-2.c
create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported-3.c
create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported.c
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index ae20802c87996..3fb1deb70fda1 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
#undef TARGET_LIBC_HAS_FUNCTION
#define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
+#undef TARGET_HAVE_STRUB_SUPPORT_FOR
+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-nvptx.h"
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index c990902685417..26a7e9c350703 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
@item string_merging
Target supports merging string constants at link time.
+@item strub
+Target supports attribute @code{strub} for stack scrubbing.
+
@item ucn
Target supports compiling and assembling UCN.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 89a1735dd7992..768ada0af5222 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3450,6 +3450,12 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
+Returns true if the target supports stack scrubbing for the given function
+or type, otherwise return false. The default implementation always returns
+true.
+@end deftypefn
+
@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
If defined to nonzero, @code{__strub_leave} will allocate a dynamic
array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index ebc1d3de5caaa..4fe0805394ea4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2686,6 +2686,8 @@ in DWARF 2 debug information. The default is zero. A different value
may reduce the size of debug information on some ports.
@end defmac
+@hook TARGET_HAVE_STRUB_SUPPORT_FOR
+
@defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
If defined to nonzero, @code{__strub_leave} will allocate a dynamic
array covering the stack range that needs scrubbing before clearing it.
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 293bec132b885..2afb7a455751d 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-strub.h"
#include "symtab-thunks.h"
#include "attr-fnspec.h"
+#include "target.h"
/* This file introduces two passes that, together, implement
machine-independent stack scrubbing, strub for short. It arranges
@@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
}
+/* Return TRUE iff the target has strub support for T, a function
+ decl, or a type used in an indirect call, and optionally REPORT the
+ reasons for ineligibility. If T is a type and error REPORTing is
+ enabled, the LOCation (of the indirect call) should be provided. */
+static inline bool
+strub_target_support_p (tree t, bool report = false,
+ location_t loc = UNKNOWN_LOCATION)
+{
+ bool result = true;
+
+ if (!targetm.have_strub_support_for (t))
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ if (DECL_P (t))
+ sorry_at (DECL_SOURCE_LOCATION (t),
+ "%qD is not eligible for %<strub%>"
+ " on the target system", t);
+ else
+ sorry_at (loc,
+ "unsupported %<strub%> call"
+ " on the target system");
+ }
+
+ return result;
+}
+
/* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
optionally REPORT the reasons for ineligibility. */
static inline bool
can_strub_p (cgraph_node *node, bool report = false)
{
- bool result = true;
+ bool result = strub_target_support_p (node->decl, report);
- if (!report && strub_always_inline_p (node))
+ if (!report && (!result || strub_always_inline_p (node)))
return result;
+ if (flag_split_stack)
+ {
+ result = false;
+
+ if (!report)
+ return result;
+
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%qD is not eligible for %<strub%>"
+ " because %<-fsplit-stack%> is enabled",
+ node->decl);
+ }
+
if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
{
result = false;
@@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
&& (TREE_TYPE (gimple_call_arg (ocall, named_args))
== get_pwmt ())));
+ tree tsup;
+ if (!(tsup = gimple_call_fndecl (ocall)))
+ tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
+ if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
+ return;
+
/* If we're already within a strub context, pass on the incoming watermark
pointer, and omit the enter and leave calls around the modified call, as an
optimization, or as a means to satisfy a tail-call requirement. */
diff --git a/gcc/target.def b/gcc/target.def
index 52b83e091b94b..08218f3a42adf 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4457,6 +4457,14 @@ otherwise return false. The default implementation always returns true.",
bool, (void),
hook_bool_void_true)
+DEFHOOK
+(have_strub_support_for,
+ "Returns true if the target supports stack scrubbing for the given function\n\
+or type, otherwise return false. The default implementation always returns\n\
+true.",
+ bool, (tree),
+ hook_bool_tree_true)
+
DEFHOOK
(have_speculation_safe_value,
"This hook is used to determine the level of target support for\n\
diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
index c7a79a6ea0d8a..f0a3f7b4c6f9a 100644
--- a/gcc/testsuite/c-c++-common/strub-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-O0.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
/* At -O0, none of the strub builtins are expanded inline. */
diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
index 96285c975d98e..50403426b18f2 100644
--- a/gcc/testsuite/c-c++-common/strub-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-O1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
/* At -O1, without -fno-inline, we fully expand enter, but neither update nor
leave. */
diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
index 8edc0d8aa1321..37e02998e318e 100644
--- a/gcc/testsuite/c-c++-common/strub-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-O2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
/* At -O2, without -fno-inline, we fully expand enter and update, and add a test
around the leave call. */
diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
index c6d900cf3c45b..905e2c6b2ffca 100644
--- a/gcc/testsuite/c-c++-common/strub-O2fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
/* With -fno-inline, none of the strub builtins are inlined. */
diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
index 33ee465e51cb6..3bbf132bdf1ea 100644
--- a/gcc/testsuite/c-c++-common/strub-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-O3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
index 2936f82079e18..c46fce38e5c91 100644
--- a/gcc/testsuite/c-c++-common/strub-O3fni.c
+++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
+/* { dg-require-effective-target strub } */
/* With -fno-inline, none of the strub builtins are inlined. */
diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
index 479746e57d87e..3b8eb19765cd6 100644
--- a/gcc/testsuite/c-c++-common/strub-Og.c
+++ b/gcc/testsuite/c-c++-common/strub-Og.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
/* At -Og, without -fno-inline, we fully expand enter, but neither update nor
leave. */
diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
index 2241d4ea07f27..8cfb253d6764c 100644
--- a/gcc/testsuite/c-c++-common/strub-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-Os.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
+/* { dg-require-effective-target strub } */
/* At -Os, without -fno-inline, we fully expand enter, and also update. The
expanded update might be larger than a call proper, but argument saving and
diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
index a322bcc5da606..2037f681f2973 100644
--- a/gcc/testsuite/c-c++-common/strub-all1.c
+++ b/gcc/testsuite/c-c++-common/strub-all1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
index db60026d0e080..c026e7d9d289b 100644
--- a/gcc/testsuite/c-c++-common/strub-all2.c
+++ b/gcc/testsuite/c-c++-common/strub-all2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
is set for static non-inline functions when not optimizing, and that keeps
diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
index 2f462adc1efe0..3edc89c54eea1 100644
--- a/gcc/testsuite/c-c++-common/strub-apply1.c
+++ b/gcc/testsuite/c-c++-common/strub-apply1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
void __attribute__ ((__strub__ ("callable")))
apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
index a5d7551f5da5c..838fc75273450 100644
--- a/gcc/testsuite/c-c++-common/strub-apply2.c
+++ b/gcc/testsuite/c-c++-common/strub-apply2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
extern void __attribute__ ((__strub__))
apply_function (void *args);
diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
index 64422a0d1e880..0206e4d930e7d 100644
--- a/gcc/testsuite/c-c++-common/strub-apply3.c
+++ b/gcc/testsuite/c-c++-common/strub-apply3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
void __attribute__ ((__strub__))
apply_function (void *args)
diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
index 15ffaa031b899..e82504728b2c6 100644
--- a/gcc/testsuite/c-c++-common/strub-apply4.c
+++ b/gcc/testsuite/c-c++-common/strub-apply4.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
/* Check that implicit enabling of strub mode selects internal strub when the
function uses __builtin_apply_args, that prevents the optimization to
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
index b70843b4215a4..a20acc0a48a58 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
index 97a3988a6b922..7915b33a39a0a 100644
--- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
+++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
force_output is set for static non-inline functions when not optimizing, and
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
index 3d73431b3dcd3..3689998b5a323 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict -O1" } */
+/* { dg-require-effective-target strub } */
/* Check that a strub function called by another strub function does NOT defer
the strubbing to its caller at -O1. */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
index fddf3c745e7e6..9e01949db6be9 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict -O2" } */
+/* { dg-require-effective-target strub } */
/* Check that a strub function called by another strub function does NOT defer
the strubbing to its caller at -O2. */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
index 7ebc65b58dd72..40ee8edd1e0e6 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict -O3" } */
+/* { dg-require-effective-target strub } */
/* Check that a strub function called by another strub function defers the
strubbing to its caller at -O3. */
diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
index fbaf85fe0fafe..67ea9f0463975 100644
--- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict -Os" } */
+/* { dg-require-effective-target strub } */
/* Check that a strub function called by another strub function defers the
strubbing to its caller at -Os. */
diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
index e9d7b7b9ee0a8..d17254904e50a 100644
--- a/gcc/testsuite/c-c++-common/strub-internal1.c
+++ b/gcc/testsuite/c-c++-common/strub-internal1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
index 8b8e15a51c71c..afc9189701f82 100644
--- a/gcc/testsuite/c-c++-common/strub-internal2.c
+++ b/gcc/testsuite/c-c++-common/strub-internal2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* g becomes STRUB_INTERNAL, because of the flag. */
static void
diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
index 0a4a7539d3489..f410b268971a6 100644
--- a/gcc/testsuite/c-c++-common/strub-parms1.c
+++ b/gcc/testsuite/c-c++-common/strub-parms1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include <stdarg.h>
diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
index 147171d96d5a1..6f572115a88c3 100644
--- a/gcc/testsuite/c-c++-common/strub-parms2.c
+++ b/gcc/testsuite/c-c++-common/strub-parms2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include <stdarg.h>
diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
index 4e92682895a43..7383fea9ce881 100644
--- a/gcc/testsuite/c-c++-common/strub-parms3.c
+++ b/gcc/testsuite/c-c++-common/strub-parms3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that uses of a strub variable implicitly enables internal strub for
publicly-visible functions, and causes the same transformations to their
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
index e2f9d8aebca58..d2b4b52c51e60 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The difference between relaxed and strict in this case is that we accept the
call from one internal-strub function to another. Without the error,
diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
index 98474435d2e59..9e5a8e76b6c3d 100644
--- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
+++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The difference between relaxed and strict in this case is that we accept the
call from one internal-strub function to another. */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
index 1de15342595e4..aaeba2a2159a9 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
index f9209c819004b..30cbdd819f176 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O0.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
index bed1dcfb54a45..911fdfb6db9a5 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
index 6bf0071f52b93..9b23ee3ac3312 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. */
diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
index 4732f515bf70c..4b3a8f843ea19 100644
--- a/gcc/testsuite/c-c++-common/strub-short-O3.c
+++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
index 8d6424c479a3a..3627a2406000b 100644
--- a/gcc/testsuite/c-c++-common/strub-short-Os.c
+++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued. At -O3 and -Os, we omit
enter and leave calls within strub contexts, passing on the enclosing
diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
new file mode 100644
index 0000000000000..7a030cdb9e9e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsplit-stack" } */
+/* { dg-require-effective-target strub } */
+/* { dg-require-effective-target split_stack } */
+
+void __attribute__ ((__strub__))
+f () {} /* { dg-message "not eligible|requested" } */
+
+void __attribute__ ((__strub__ ("internal")))
+g () {} /* { dg-message "not eligible|requested" } */
diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
index 368522442066e..503eb1734e36f 100644
--- a/gcc/testsuite/c-c++-common/strub-strict1.c
+++ b/gcc/testsuite/c-c++-common/strub-strict1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
static int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
index b4f2888321821..3bf1aa30b4af1 100644
--- a/gcc/testsuite/c-c++-common/strub-strict2.c
+++ b/gcc/testsuite/c-c++-common/strub-strict2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
+/* { dg-require-effective-target strub } */
static int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
index e48e0610e079b..ba4b1623e281a 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
#include "strub-tail-O2.c"
diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
index 87cda7ab21b16..043813b1de467 100644
--- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
+++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that the expected strub calls are issued.
Tail calls are short-circuited at -O2+. */
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
new file mode 100644
index 0000000000000..3586f4f679dfe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+ strub above), we report when pointers to strub functions are called. This
+ cannot be part of strub-unsupported.c because errors in the strub-mode pass
+ prevent the main strub pass, where errors at calls are detected, from
+ running. */
+
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+void m () {
+ p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
new file mode 100644
index 0000000000000..d6fb4c525c4a6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+ strub above), we report when strub functions that are not defined are
+ called. This cannot be part of strub-unsupported-2.c because errors in the
+ strub-mode pass prevent the main strub pass, where errors at calls are
+ detected, from running. */
+
+extern void __attribute__ ((__strub__))
+s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void m () {
+ s ();
+ t ();
+}
diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
new file mode 100644
index 0000000000000..cb5c4049495c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Check that, when strub is not supported (so no dg-required-effective-target
+ strub above), we report when strub functions are defined, and when they're
+ called in ways that would require changes. */
+
+void __attribute__ ((__strub__))
+f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+void __attribute__ ((__strub__ ("internal")))
+g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
+
+/* This only gets an error when called, see strub-unsupported-2.c. */
+void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
+
+/* These too, see strub-unsupported-3.c. */
+extern void __attribute__ ((__strub__))
+s (void);
+
+extern void __attribute__ ((__strub__ ("internal")))
+t (void);
diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
index eb6250fd39c90..67014aa5de84a 100644
--- a/gcc/testsuite/c-c++-common/strub-var1.c
+++ b/gcc/testsuite/c-c++-common/strub-var1.c
@@ -1,4 +1,5 @@
/* { dg-do compile } */
+/* { dg-require-effective-target strub } */
int __attribute__ ((strub)) x;
float __attribute__ ((strub)) f;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
index b5e45ab0525ad..86dbee6746d1b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* Check that strub and non-strub functions can be called from non-strub
contexts, and that strub and callable functions can be called from strub
diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
index 96aa7fe4b07f7..9da120f615645 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* Check that impermissible (cross-strub-context) calls are reported. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
index 5e956cb1a9b6b..22056713cce4b 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub const function call, we issue an asm
statement to make sure the watermark passed to it is held in memory before
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
index 73d650292dfbf..a105c66d7a9c9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub implicitly-const function call, we issue an
asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
index 2584f1f974a58..386200c2784a4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub const wrapping call, we issue an asm statement
to make sure the watermark passed to it is held in memory before the call,
diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
index d819f54ec0230..817e9fa2118b6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub implicitly-const wrapping call, we issue an
asm statement to make sure the watermark passed to it is held in memory
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
index 7c27a2a1a6dca..132ab63ef733a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The pointed-to data enables strubbing if accessed. */
int __attribute__ ((__strub__)) var;
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
index e66d903780afd..b660702d26e75 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The pointer itself is a strub variable, enabling internal strubbing when
its value is used. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
index 5e08e0e58c658..fc44eef6f8fb5 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The pointer itself is a strub variable, that would enable internal strubbing
if its value was used. Here, it's only overwritten, so no strub. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
index a818e7a38bb5f..85e2f59055b57 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* The pointer itself is a strub variable, that would enable internal strubbing
if its value was used. Here, it's only overwritten, so no strub. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
index ddb0b5c0543b0..0a5edac414df1 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* It would be desirable to issue at least warnings for these. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
index c165f312f16de..988954e7ed6bc 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype ();
fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
index 69fcff8d3763d..d3ca91389a700 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype (int, int);
fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
index ff006224909bd..89b5979cf7b78 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
fntype (*ptr);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
index 614b02228ba29..4917dda8826d9 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
inline void __attribute__ ((strub ("internal"), always_inline))
inl_int_ali (void)
diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
index f9a6b4a16faf8..c45903856d4ff 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=all" } */
+/* { dg-require-effective-target strub } */
#include "strub-inlinable1.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
index b4a7f3992bbaa..b0d6139f0a870 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
typedef void ft (void);
typedef void ft2 (int, int);
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
index ef634d351265f..1148c246f2059 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed -Wpedantic" } */
+/* { dg-require-effective-target strub } */
/* C++ does not warn about the partial incompatibilities.
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
index e1f179e160e5c..06a72d86d2c58 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
@@ -1,6 +1,7 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
/* { dg-prune-output "command-line option .-fpermissive." } */
+/* { dg-require-effective-target strub } */
/* See strub-ptrfn2.c. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
index 70b558afad040..83ea1af7056e7 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=relaxed" } */
+/* { dg-require-effective-target strub } */
/* This is strub-ptrfn2.c without -Wpedantic.
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
index a262a086837b2..2643136f178cc 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub pure function call, we issue an asm statement
to make sure the watermark passed to it is not assumed to be unchanged. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
index 4c4bd50c209a0..8bda129b77dc6 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub implicitly-pure function call, we issue an asm
statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
index ce195c6b1f1b6..00bcbdd097af8 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub pure wrapping call, we issue an asm statement
to make sure the watermark passed to it is not assumed to be unchanged. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
index 75cd54ccb5b5d..ea7c40e7912b4 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+/* { dg-require-effective-target strub } */
/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
statement to make sure the watermark passed to it is not assumed to be
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
index 7458b3fb54da5..fdf100428631d 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* Check that a non-strub function leaves a string behind in the stack, and that
equivalent strub functions don't. Avoid the use of red zones by avoiding
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
index 5d60a7775f4bb..1228a66599721 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict" } */
+/* { dg-require-effective-target strub } */
/* Check that a non-strub function leaves a string behind in the stack, and that
equivalent strub functions don't. Allow red zones to be used. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
index c2ad710858e87..e5047a988f5bf 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
@@ -1,6 +1,7 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
/* Check that a non-strub function leaves a string behind in the stack, and that
equivalent strub functions don't. */
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
index 3b36b8e5d68ef..0e84a4bab80fc 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
@@ -1,6 +1,7 @@
/* { dg-do run } */
/* { dg-options "-fstrub=all" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
/* Check that multi-level, multi-inlined functions still get cleaned up as
expected, without overwriting temporary stack allocations while they should
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
index 57f9baf758ded..edc98486dc93a 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=at-calls" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
#include "strub-run4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
index 08de3f1c3b17c..487ed08bb6606 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
@@ -1,6 +1,7 @@
/* { dg-do run } */
/* { dg-options "-fstrub=strict" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
#define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
index 459f6886c5499..a85447ffabfae 100644
--- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
+++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
/* { dg-options "-fstrub=internal" } */
/* { dg-require-effective-target alloca } */
+/* { dg-require-effective-target strub } */
#include "strub-run4.c"
diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
index 0d367fb83d09d..beb8b811f8fca 100644
--- a/gcc/testsuite/g++.dg/strub-run1.C
+++ b/gcc/testsuite/g++.dg/strub-run1.C
@@ -1,5 +1,6 @@
// { dg-do run }
// { dg-options "-fstrub=internal" }
+// { dg-require-effective-target strub }
// Check that we don't get extra copies.
diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
index c226ab10ff651..6ae45fadd70ba 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init1.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
index a7911f1fa7212..8f4849c7fde78 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init2.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
index 6ebebcd01e8ea..14f28e3c276bd 100644
--- a/gcc/testsuite/g++.dg/torture/strub-init3.C
+++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
@@ -1,5 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
+// { dg-require-effective-target strub }
extern int __attribute__((__strub__)) initializer ();
diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
index 29e6996ecf61c..488a2d64afe31 100644
--- a/gcc/testsuite/gnat.dg/strub_access.adb
+++ b/gcc/testsuite/gnat.dg/strub_access.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
+-- { dg-require-effective-target strub }
-- The main subprogram doesn't read from the automatic variable, but
-- being an automatic variable, its presence should be enough for the
diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
index dae4706016436..4a8653c4d843f 100644
--- a/gcc/testsuite/gnat.dg/strub_access1.adb
+++ b/gcc/testsuite/gnat.dg/strub_access1.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=relaxed" }
+-- { dg-require-effective-target strub }
-- Check that we reject 'Access of a strub variable whose type does
-- not carry a strub modifier.
diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
index 10445d7cf8451..eb7826dc990f4 100644
--- a/gcc/testsuite/gnat.dg/strub_attr.adb
+++ b/gcc/testsuite/gnat.dg/strub_attr.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
package body Strub_Attr is
E : exception;
diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
index 3dbcc4a357cba..f23d4675def38 100644
--- a/gcc/testsuite/gnat.dg/strub_disp.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp.adb
@@ -1,4 +1,5 @@
-- { dg-do compile }
+-- { dg-require-effective-target strub }
procedure Strub_Disp is
package Foo is
diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
index 09756a74b7d81..9c4c7f696371d 100644
--- a/gcc/testsuite/gnat.dg/strub_disp1.adb
+++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
-- Check that at-calls dispatching calls are transformed.
diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
index da56acaa957d2..613db69305e05 100644
--- a/gcc/testsuite/gnat.dg/strub_ind.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict" }
+-- { dg-require-effective-target strub }
-- This is essentially the same test as strub_attr.adb,
-- but applying attributes to access types as well.
diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
index 825e395e6819c..245b0a830f691 100644
--- a/gcc/testsuite/gnat.dg/strub_ind1.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+-- { dg-require-effective-target strub }
-- This is essentially the same test as strub_attr.adb,
-- but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
index e918b39263117..b9bfe50e9296e 100644
--- a/gcc/testsuite/gnat.dg/strub_ind2.adb
+++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict" }
+-- { dg-require-effective-target strub }
-- This is essentially the same test as strub_attr.adb,
-- but with an explicit conversion.
diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
index 8f0212a75866f..f43854705d073 100644
--- a/gcc/testsuite/gnat.dg/strub_intf.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf.adb
@@ -1,4 +1,5 @@
-- { dg-do compile }
+-- { dg-require-effective-target strub }
-- Check that strub mode mismatches between overrider and overridden
-- subprograms are reported.
diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
index bf77321cef790..7a38a4c49ba8d 100644
--- a/gcc/testsuite/gnat.dg/strub_intf1.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
-- Check that at-calls dispatching calls to interfaces are transformed.
diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
index e8880dbc43730..7992b7344fb87 100644
--- a/gcc/testsuite/gnat.dg/strub_intf2.adb
+++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
@@ -1,4 +1,5 @@
-- { dg-do compile }
+-- { dg-require-effective-target strub }
-- Check that strub mode mismatches between overrider and overridden
-- subprograms are reported even when the overriders for an
diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
index 217367e712d82..abfb120b51468 100644
--- a/gcc/testsuite/gnat.dg/strub_renm.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm.adb
@@ -1,4 +1,5 @@
-- { dg-do compile }
+-- { dg-require-effective-target strub }
procedure Strub_Renm is
procedure P (X : Integer);
diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
index a11adbfb5a9d6..68d3230b5356c 100644
--- a/gcc/testsuite/gnat.dg/strub_renm1.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
procedure Strub_Renm1 is
V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
index c488c20826fdb..3cb81ea03f763 100644
--- a/gcc/testsuite/gnat.dg/strub_renm2.adb
+++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict -fdump-ipa-strub" }
+-- { dg-require-effective-target strub }
procedure Strub_Renm2 is
V : Integer := 0;
diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
index 3d158de28031f..7c6affa06d4ab 100644
--- a/gcc/testsuite/gnat.dg/strub_var.adb
+++ b/gcc/testsuite/gnat.dg/strub_var.adb
@@ -1,5 +1,6 @@
-- { dg-do compile }
-- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
+-- { dg-require-effective-target strub }
-- We don't read from the automatic variable, but being an automatic
-- variable, its presence should be enough for the procedure to get
diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
index 6a504e09198b6..64b7e65fe9b0f 100644
--- a/gcc/testsuite/gnat.dg/strub_var1.adb
+++ b/gcc/testsuite/gnat.dg/strub_var1.adb
@@ -1,4 +1,5 @@
-- { dg-do compile }
+-- { dg-require-effective-target strub }
with Strub_Attr;
procedure Strub_Var1 is
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 3fcce6be49d6f..40a60c198cfe8 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
} "$stack_opt"]
}
+# Return 1 if the target supports stack scrubbing.
+proc check_effective_target_strub {} {
+ return [check_no_compiler_messages strub assembly {
+ void __attribute__ ((__strub__)) fn (void) {}
+ } ""]
+}
+
# Return 1 if compilation with -freorder-blocks-and-partition is error-free
# for trivial code, 0 otherwise. As some targets (ARM for example) only
# warn when -fprofile-use is also supplied we test that combination too.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d8163c5af9903..3f77283490ef6 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
LIB2ADD += $(srcdir)/hardcfr.c
# Stack scrubbing infrastructure.
-LIB2ADD += $(srcdir)/strub.c
+@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
# instead of LIB2ADD because that's the way to be sure on some targets
diff --git a/libgcc/configure b/libgcc/configure
index cf149209652e3..567158955a329 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -593,6 +593,7 @@ asm_hidden_op
extra_parts
cpu_type
get_gcc_base_ver
+HAVE_STRUB_SUPPORT
thread_header
tm_defines
tm_file
@@ -5702,6 +5703,31 @@ esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
+$as_echo_n "checking for strub support... " >&6; }
+if ${libgcc_cv_strub_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+void __attribute__ ((__strub__)) fn (void) {}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgcc_cv_strub_support=yes
+else
+ libgcc_cv_strub_support=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
+$as_echo "$libgcc_cv_strub_support" >&6; }
+if test "x$libgcc_cv_strub_support" != xno; then
+ HAVE_STRUB_SUPPORT=
+else
+ HAVE_STRUB_SUPPORT='# '
+fi
+
+
# Determine what GCC version number to use in filesystem paths.
get_gcc_base_ver="cat"
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 2fc9d5d7c93e9..9c0e415501a80 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
# Map from thread model to thread header.
GCC_AC_THREAD_HEADER([$target_thread_file])
+AC_CACHE_CHECK([for strub support],
+ [libgcc_cv_strub_support],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
+ [libgcc_cv_strub_support=yes],
+ [libgcc_cv_strub_support=no])])
+if test "x$libgcc_cv_strub_support" != xno; then
+ HAVE_STRUB_SUPPORT=
+else
+ HAVE_STRUB_SUPPORT='# '
+fi
+AC_SUBST(HAVE_STRUB_SUPPORT)
+
# Determine what GCC version number to use in filesystem paths.
GCC_BASE_VER
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH] strub: enable conditional support
2023-12-07 3:33 ` [PATCH] strub: enable conditional support Alexandre Oliva
@ 2023-12-07 16:44 ` Thomas Schwinge
2023-12-07 17:52 ` [PATCH] Alexandre Oliva
0 siblings, 1 reply; 521+ messages in thread
From: Thomas Schwinge @ 2023-12-07 16:44 UTC (permalink / raw)
To: Alexandre Oliva
Cc: Tobias Burnus, Richard Biener, gcc-patches, Jeremy Bennett,
Craig Blackmore, Graham Markall, Martin Jambor, Jan Hubicka,
Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
Hi Alexandre!
Thank you for looking into this so promptly!
On 2023-12-07T00:33:59-0300, Alexandre Oliva <oliva@adacore.com> wrote:
> On Dec 6, 2023, Alexandre Oliva <oliva@adacore.com> wrote:
>
>> Disabling the runtime bits is easy, once we determine what condition we
>> wish to test for. I suppose testing for target support in the compiler,
>> issuing a 'sorry' in case the feature is required, would provide
>> something for libgcc configure and testsuite effective-target to test
>> for and decide whether to enable runtime support and run the tests.
>
> Instead of doing something equivalent to an implicit -fstrub=disable,
> that would quietly compile without stack scrubbing, I thought it would
> be safer to be noisy if the feature is used (requested, really) when
> support is not available.
>
>
> Targets that don't expose callee stacks to callers, such as nvptx, as
> well as -fsplit-stack compilations, violate fundamental assumptions of
> the current strub implementation. This patch enables targets to
> disable strub, and disables it when -fsplit-stack is enabled.
>
> When strub support is disabled, the testsuite will now skip strub
> tests, and libgcc will not build the strub runtime components.
>
> Regstrapped on x86_64-linux-gnu. Also tested with an additional patch
> for i386.cc that mirrors the nvptx.cc change, to check that strub gets
> disabled without noisy test results. Ok to install?
GCC/nvptx target again builds as before, and testing just completed: as
expected, the "strub" test cases generally UNSUPPORTED, just something's
wrong with two of the 'c-c++-common/strub-unsupported*.c' test cases:
+PASS: c-c++-common/strub-unsupported-2.c -Wc++-compat (test for warnings, line 12)
+PASS: c-c++-common/strub-unsupported-2.c -Wc++-compat (test for excess errors)
+FAIL: c-c++-common/strub-unsupported-3.c -Wc++-compat (internal compiler error: in verify_curr_properties, at passes.cc:2198)
+PASS: c-c++-common/strub-unsupported-3.c -Wc++-compat (test for warnings, line 10)
+PASS: c-c++-common/strub-unsupported-3.c -Wc++-compat (test for warnings, line 13)
+FAIL: c-c++-common/strub-unsupported-3.c -Wc++-compat (test for excess errors)
+FAIL: c-c++-common/strub-unsupported.c -Wc++-compat (internal compiler error: in verify_curr_properties, at passes.cc:2198)
+PASS: c-c++-common/strub-unsupported.c -Wc++-compat (test for warnings, line 8)
+PASS: c-c++-common/strub-unsupported.c -Wc++-compat (test for warnings, line 11)
+FAIL: c-c++-common/strub-unsupported.c -Wc++-compat (test for excess errors)
Similar for C++ testing.
The ICE is:
during IPA pass: emutls
[...]/source-gcc/gcc/testsuite/c-c++-common/strub-unsupported-3.c:18:1: internal compiler error: in verify_curr_properties, at passes.cc:2198
0x10b671db verify_curr_properties
[...]/source-gcc/gcc/passes.cc:2198
0x10b67ca3 do_per_function
[...]/source-gcc/gcc/passes.cc:1694
I'm certainly fine if we deal with that one incrementally.
I'll answer your (quite right) '__builtin_{frame,stack}_address' remarks
(earlier email) separately, later on.
Grüße
Thomas
> for gcc/ChangeLog
>
> * target.def (have_strub_support_for): New hook.
> * doc/tm.texi.in: Document it.
> * doc/tm.texi: Rebuild.
> * ipa-strub.cc: Include target.h.
> (strub_target_support_p): New.
> (can_strub_p): Call it. Test for no flag_split_stack.
> (pass_ipa_strub::adjust_at_calls_call): Check for target
> support.
> * config/nvptx/nvptx.cc (TARGET_HAVE_STRUB_SUPPORT_FOR):
> Disable.
> * doc/sourcebuild.texi (strub): Document new effective
> target.
>
> for gcc/testsuite/ChangeLog
>
> * gcc.dg/strub-split-stack.c: New.
> * gcc.dg/strub-unsupported.c: New.
> * gcc.dg/strub-unsupported-2.c: New.
> * gcc.dg/strub-unsupported-3.c: New.
> * lib/target-supports.exp (check_effective_target_strub): New.
> * c-c++-common/strub-O0.c: Require effective target strub.
> * c-c++-common/strub-O1.c: Likewise.
> * c-c++-common/strub-O2.c: Likewise.
> * c-c++-common/strub-O2fni.c: Likewise.
> * c-c++-common/strub-O3.c: Likewise.
> * c-c++-common/strub-O3fni.c: Likewise.
> * c-c++-common/strub-Og.c: Likewise.
> * c-c++-common/strub-Os.c: Likewise.
> * c-c++-common/strub-all1.c: Likewise.
> * c-c++-common/strub-all2.c: Likewise.
> * c-c++-common/strub-apply1.c: Likewise.
> * c-c++-common/strub-apply2.c: Likewise.
> * c-c++-common/strub-apply3.c: Likewise.
> * c-c++-common/strub-apply4.c: Likewise.
> * c-c++-common/strub-at-calls1.c: Likewise.
> * c-c++-common/strub-at-calls2.c: Likewise.
> * c-c++-common/strub-defer-O1.c: Likewise.
> * c-c++-common/strub-defer-O2.c: Likewise.
> * c-c++-common/strub-defer-O3.c: Likewise.
> * c-c++-common/strub-defer-Os.c: Likewise.
> * c-c++-common/strub-internal1.c: Likewise.
> * c-c++-common/strub-internal2.c: Likewise.
> * c-c++-common/strub-parms1.c: Likewise.
> * c-c++-common/strub-parms2.c: Likewise.
> * c-c++-common/strub-parms3.c: Likewise.
> * c-c++-common/strub-relaxed1.c: Likewise.
> * c-c++-common/strub-relaxed2.c: Likewise.
> * c-c++-common/strub-short-O0-exc.c: Likewise.
> * c-c++-common/strub-short-O0.c: Likewise.
> * c-c++-common/strub-short-O1.c: Likewise.
> * c-c++-common/strub-short-O2.c: Likewise.
> * c-c++-common/strub-short-O3.c: Likewise.
> * c-c++-common/strub-short-Os.c: Likewise.
> * c-c++-common/strub-strict1.c: Likewise.
> * c-c++-common/strub-strict2.c: Likewise.
> * c-c++-common/strub-tail-O1.c: Likewise.
> * c-c++-common/strub-tail-O2.c: Likewise.
> * c-c++-common/strub-var1.c: Likewise.
> * c-c++-common/torture/strub-callable1.c: Likewise.
> * c-c++-common/torture/strub-callable2.c: Likewise.
> * c-c++-common/torture/strub-const1.c: Likewise.
> * c-c++-common/torture/strub-const2.c: Likewise.
> * c-c++-common/torture/strub-const3.c: Likewise.
> * c-c++-common/torture/strub-const4.c: Likewise.
> * c-c++-common/torture/strub-data1.c: Likewise.
> * c-c++-common/torture/strub-data2.c: Likewise.
> * c-c++-common/torture/strub-data3.c: Likewise.
> * c-c++-common/torture/strub-data4.c: Likewise.
> * c-c++-common/torture/strub-data5.c: Likewise.
> * c-c++-common/torture/strub-indcall1.c: Likewise.
> * c-c++-common/torture/strub-indcall2.c: Likewise.
> * c-c++-common/torture/strub-indcall3.c: Likewise.
> * c-c++-common/torture/strub-inlinable1.c: Likewise.
> * c-c++-common/torture/strub-inlinable2.c: Likewise.
> * c-c++-common/torture/strub-ptrfn1.c: Likewise.
> * c-c++-common/torture/strub-ptrfn2.c: Likewise.
> * c-c++-common/torture/strub-ptrfn3.c: Likewise.
> * c-c++-common/torture/strub-ptrfn4.c: Likewise.
> * c-c++-common/torture/strub-pure1.c: Likewise.
> * c-c++-common/torture/strub-pure2.c: Likewise.
> * c-c++-common/torture/strub-pure3.c: Likewise.
> * c-c++-common/torture/strub-pure4.c: Likewise.
> * c-c++-common/torture/strub-run1.c: Likewise.
> * c-c++-common/torture/strub-run2.c: Likewise.
> * c-c++-common/torture/strub-run3.c: Likewise.
> * c-c++-common/torture/strub-run4.c: Likewise.
> * c-c++-common/torture/strub-run4c.c: Likewise.
> * c-c++-common/torture/strub-run4d.c: Likewise.
> * c-c++-common/torture/strub-run4i.c: Likewise.
> * g++.dg/strub-run1.C: Likewise.
> * g++.dg/torture/strub-init1.C: Likewise.
> * g++.dg/torture/strub-init2.C: Likewise.
> * g++.dg/torture/strub-init3.C: Likewise.
> * gnat.dg/strub_attr.adb: Likewise.
> * gnat.dg/strub_ind.adb: Likewise.
> * gnat.dg/strub_access.adb: Likewise.
> * gnat.dg/strub_access1.adb: Likewise.
> * gnat.dg/strub_disp.adb: Likewise.
> * gnat.dg/strub_disp1.adb: Likewise.
> * gnat.dg/strub_ind1.adb: Likewise.
> * gnat.dg/strub_ind2.adb: Likewise.
> * gnat.dg/strub_intf.adb: Likewise.
> * gnat.dg/strub_intf1.adb: Likewise.
> * gnat.dg/strub_intf2.adb: Likewise.
> * gnat.dg/strub_renm.adb: Likewise.
> * gnat.dg/strub_renm1.adb: Likewise.
> * gnat.dg/strub_renm2.adb: Likewise.
> * gnat.dg/strub_var.adb: Likewise.
> * gnat.dg/strub_var1.adb: Likewise.
>
> for libgcc/ChangeLog
>
> * configure.ac: Check for strub support.
> * configure: Rebuilt.
> * Makefile.in: Compile strub.c conditionally.
> ---
> gcc/config/nvptx/nvptx.cc | 3 +
> gcc/doc/sourcebuild.texi | 3 +
> gcc/doc/tm.texi | 6 ++
> gcc/doc/tm.texi.in | 2 +
> gcc/ipa-strub.cc | 54 +++++++++++++++++++-
> gcc/target.def | 8 +++
> gcc/testsuite/c-c++-common/strub-O0.c | 1
> gcc/testsuite/c-c++-common/strub-O1.c | 1
> gcc/testsuite/c-c++-common/strub-O2.c | 1
> gcc/testsuite/c-c++-common/strub-O2fni.c | 1
> gcc/testsuite/c-c++-common/strub-O3.c | 1
> gcc/testsuite/c-c++-common/strub-O3fni.c | 1
> gcc/testsuite/c-c++-common/strub-Og.c | 1
> gcc/testsuite/c-c++-common/strub-Os.c | 1
> gcc/testsuite/c-c++-common/strub-all1.c | 1
> gcc/testsuite/c-c++-common/strub-all2.c | 1
> gcc/testsuite/c-c++-common/strub-apply1.c | 1
> gcc/testsuite/c-c++-common/strub-apply2.c | 1
> gcc/testsuite/c-c++-common/strub-apply3.c | 1
> gcc/testsuite/c-c++-common/strub-apply4.c | 1
> gcc/testsuite/c-c++-common/strub-at-calls1.c | 1
> gcc/testsuite/c-c++-common/strub-at-calls2.c | 1
> gcc/testsuite/c-c++-common/strub-defer-O1.c | 1
> gcc/testsuite/c-c++-common/strub-defer-O2.c | 1
> gcc/testsuite/c-c++-common/strub-defer-O3.c | 1
> gcc/testsuite/c-c++-common/strub-defer-Os.c | 1
> gcc/testsuite/c-c++-common/strub-internal1.c | 1
> gcc/testsuite/c-c++-common/strub-internal2.c | 1
> gcc/testsuite/c-c++-common/strub-parms1.c | 1
> gcc/testsuite/c-c++-common/strub-parms2.c | 1
> gcc/testsuite/c-c++-common/strub-parms3.c | 1
> gcc/testsuite/c-c++-common/strub-relaxed1.c | 1
> gcc/testsuite/c-c++-common/strub-relaxed2.c | 1
> gcc/testsuite/c-c++-common/strub-short-O0-exc.c | 1
> gcc/testsuite/c-c++-common/strub-short-O0.c | 1
> gcc/testsuite/c-c++-common/strub-short-O1.c | 1
> gcc/testsuite/c-c++-common/strub-short-O2.c | 1
> gcc/testsuite/c-c++-common/strub-short-O3.c | 1
> gcc/testsuite/c-c++-common/strub-short-Os.c | 1
> gcc/testsuite/c-c++-common/strub-split-stack.c | 10 ++++
> gcc/testsuite/c-c++-common/strub-strict1.c | 1
> gcc/testsuite/c-c++-common/strub-strict2.c | 1
> gcc/testsuite/c-c++-common/strub-tail-O1.c | 1
> gcc/testsuite/c-c++-common/strub-tail-O2.c | 1
> gcc/testsuite/c-c++-common/strub-unsupported-2.c | 13 +++++
> gcc/testsuite/c-c++-common/strub-unsupported-3.c | 18 +++++++
> gcc/testsuite/c-c++-common/strub-unsupported.c | 21 ++++++++
> gcc/testsuite/c-c++-common/strub-var1.c | 1
> .../c-c++-common/torture/strub-callable1.c | 1
> .../c-c++-common/torture/strub-callable2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-const1.c | 1
> gcc/testsuite/c-c++-common/torture/strub-const2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-const3.c | 1
> gcc/testsuite/c-c++-common/torture/strub-const4.c | 1
> gcc/testsuite/c-c++-common/torture/strub-data1.c | 1
> gcc/testsuite/c-c++-common/torture/strub-data2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-data3.c | 1
> gcc/testsuite/c-c++-common/torture/strub-data4.c | 1
> gcc/testsuite/c-c++-common/torture/strub-data5.c | 1
> .../c-c++-common/torture/strub-indcall1.c | 1
> .../c-c++-common/torture/strub-indcall2.c | 1
> .../c-c++-common/torture/strub-indcall3.c | 1
> .../c-c++-common/torture/strub-inlinable1.c | 1
> .../c-c++-common/torture/strub-inlinable2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c | 1
> gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c | 1
> gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c | 1
> gcc/testsuite/c-c++-common/torture/strub-pure1.c | 1
> gcc/testsuite/c-c++-common/torture/strub-pure2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-pure3.c | 1
> gcc/testsuite/c-c++-common/torture/strub-pure4.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run1.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run2.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run3.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run4.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run4c.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run4d.c | 1
> gcc/testsuite/c-c++-common/torture/strub-run4i.c | 1
> gcc/testsuite/g++.dg/strub-run1.C | 1
> gcc/testsuite/g++.dg/torture/strub-init1.C | 1
> gcc/testsuite/g++.dg/torture/strub-init2.C | 1
> gcc/testsuite/g++.dg/torture/strub-init3.C | 1
> gcc/testsuite/gnat.dg/strub_access.adb | 1
> gcc/testsuite/gnat.dg/strub_access1.adb | 1
> gcc/testsuite/gnat.dg/strub_attr.adb | 1
> gcc/testsuite/gnat.dg/strub_disp.adb | 1
> gcc/testsuite/gnat.dg/strub_disp1.adb | 1
> gcc/testsuite/gnat.dg/strub_ind.adb | 1
> gcc/testsuite/gnat.dg/strub_ind1.adb | 1
> gcc/testsuite/gnat.dg/strub_ind2.adb | 1
> gcc/testsuite/gnat.dg/strub_intf.adb | 1
> gcc/testsuite/gnat.dg/strub_intf1.adb | 1
> gcc/testsuite/gnat.dg/strub_intf2.adb | 1
> gcc/testsuite/gnat.dg/strub_renm.adb | 1
> gcc/testsuite/gnat.dg/strub_renm1.adb | 1
> gcc/testsuite/gnat.dg/strub_renm2.adb | 1
> gcc/testsuite/gnat.dg/strub_var.adb | 1
> gcc/testsuite/gnat.dg/strub_var1.adb | 1
> gcc/testsuite/lib/target-supports.exp | 7 +++
> libgcc/Makefile.in | 2 -
> libgcc/configure | 26 ++++++++++
> libgcc/configure.ac | 13 +++++
> 103 files changed, 272 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/strub-split-stack.c
> create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported-2.c
> create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported-3.c
> create mode 100644 gcc/testsuite/c-c++-common/strub-unsupported.c
>
> diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
> index ae20802c87996..3fb1deb70fda1 100644
> --- a/gcc/config/nvptx/nvptx.cc
> +++ b/gcc/config/nvptx/nvptx.cc
> @@ -7789,6 +7789,9 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
> #undef TARGET_LIBC_HAS_FUNCTION
> #define TARGET_LIBC_HAS_FUNCTION nvptx_libc_has_function
>
> +#undef TARGET_HAVE_STRUB_SUPPORT_FOR
> +#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false
> +
> struct gcc_target targetm = TARGET_INITIALIZER;
>
> #include "gt-nvptx.h"
> diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
> index c990902685417..26a7e9c350703 100644
> --- a/gcc/doc/sourcebuild.texi
> +++ b/gcc/doc/sourcebuild.texi
> @@ -2983,6 +2983,9 @@ Target supports statically linking @samp{libgfortran}.
> @item string_merging
> Target supports merging string constants at link time.
>
> +@item strub
> +Target supports attribute @code{strub} for stack scrubbing.
> +
> @item ucn
> Target supports compiling and assembling UCN.
>
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 89a1735dd7992..768ada0af5222 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -3450,6 +3450,12 @@ in DWARF 2 debug information. The default is zero. A different value
> may reduce the size of debug information on some ports.
> @end defmac
>
> +@deftypefn {Target Hook} bool TARGET_HAVE_STRUB_SUPPORT_FOR (tree)
> +Returns true if the target supports stack scrubbing for the given function
> +or type, otherwise return false. The default implementation always returns
> +true.
> +@end deftypefn
> +
> @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
> If defined to nonzero, @code{__strub_leave} will allocate a dynamic
> array covering the stack range that needs scrubbing before clearing it.
> diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
> index ebc1d3de5caaa..4fe0805394ea4 100644
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -2686,6 +2686,8 @@ in DWARF 2 debug information. The default is zero. A different value
> may reduce the size of debug information on some ports.
> @end defmac
>
> +@hook TARGET_HAVE_STRUB_SUPPORT_FOR
> +
> @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY
> If defined to nonzero, @code{__strub_leave} will allocate a dynamic
> array covering the stack range that needs scrubbing before clearing it.
> diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
> index 293bec132b885..2afb7a455751d 100644
> --- a/gcc/ipa-strub.cc
> +++ b/gcc/ipa-strub.cc
> @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
> #include "ipa-strub.h"
> #include "symtab-thunks.h"
> #include "attr-fnspec.h"
> +#include "target.h"
>
> /* This file introduces two passes that, together, implement
> machine-independent stack scrubbing, strub for short. It arranges
> @@ -631,17 +632,60 @@ strub_always_inline_p (cgraph_node *node)
> return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
> }
>
> +/* Return TRUE iff the target has strub support for T, a function
> + decl, or a type used in an indirect call, and optionally REPORT the
> + reasons for ineligibility. If T is a type and error REPORTing is
> + enabled, the LOCation (of the indirect call) should be provided. */
> +static inline bool
> +strub_target_support_p (tree t, bool report = false,
> + location_t loc = UNKNOWN_LOCATION)
> +{
> + bool result = true;
> +
> + if (!targetm.have_strub_support_for (t))
> + {
> + result = false;
> +
> + if (!report)
> + return result;
> +
> + if (DECL_P (t))
> + sorry_at (DECL_SOURCE_LOCATION (t),
> + "%qD is not eligible for %<strub%>"
> + " on the target system", t);
> + else
> + sorry_at (loc,
> + "unsupported %<strub%> call"
> + " on the target system");
> + }
> +
> + return result;
> +}
> +
> /* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
> optionally REPORT the reasons for ineligibility. */
>
> static inline bool
> can_strub_p (cgraph_node *node, bool report = false)
> {
> - bool result = true;
> + bool result = strub_target_support_p (node->decl, report);
>
> - if (!report && strub_always_inline_p (node))
> + if (!report && (!result || strub_always_inline_p (node)))
> return result;
>
> + if (flag_split_stack)
> + {
> + result = false;
> +
> + if (!report)
> + return result;
> +
> + sorry_at (DECL_SOURCE_LOCATION (node->decl),
> + "%qD is not eligible for %<strub%>"
> + " because %<-fsplit-stack%> is enabled",
> + node->decl);
> + }
> +
> if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
> {
> result = false;
> @@ -2417,6 +2461,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
> && (TREE_TYPE (gimple_call_arg (ocall, named_args))
> == get_pwmt ())));
>
> + tree tsup;
> + if (!(tsup = gimple_call_fndecl (ocall)))
> + tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
> + if (!strub_target_support_p (tsup, true, gimple_location (ocall)))
> + return;
> +
> /* If we're already within a strub context, pass on the incoming watermark
> pointer, and omit the enter and leave calls around the modified call, as an
> optimization, or as a means to satisfy a tail-call requirement. */
> diff --git a/gcc/target.def b/gcc/target.def
> index 52b83e091b94b..08218f3a42adf 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -4457,6 +4457,14 @@ otherwise return false. The default implementation always returns true.",
> bool, (void),
> hook_bool_void_true)
>
> +DEFHOOK
> +(have_strub_support_for,
> + "Returns true if the target supports stack scrubbing for the given function\n\
> +or type, otherwise return false. The default implementation always returns\n\
> +true.",
> + bool, (tree),
> + hook_bool_tree_true)
> +
> DEFHOOK
> (have_speculation_safe_value,
> "This hook is used to determine the level of target support for\n\
> diff --git a/gcc/testsuite/c-c++-common/strub-O0.c b/gcc/testsuite/c-c++-common/strub-O0.c
> index c7a79a6ea0d8a..f0a3f7b4c6f9a 100644
> --- a/gcc/testsuite/c-c++-common/strub-O0.c
> +++ b/gcc/testsuite/c-c++-common/strub-O0.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O0 -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> /* At -O0, none of the strub builtins are expanded inline. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-O1.c b/gcc/testsuite/c-c++-common/strub-O1.c
> index 96285c975d98e..50403426b18f2 100644
> --- a/gcc/testsuite/c-c++-common/strub-O1.c
> +++ b/gcc/testsuite/c-c++-common/strub-O1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O1 -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> /* At -O1, without -fno-inline, we fully expand enter, but neither update nor
> leave. */
> diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c
> index 8edc0d8aa1321..37e02998e318e 100644
> --- a/gcc/testsuite/c-c++-common/strub-O2.c
> +++ b/gcc/testsuite/c-c++-common/strub-O2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> /* At -O2, without -fno-inline, we fully expand enter and update, and add a test
> around the leave call. */
> diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c
> index c6d900cf3c45b..905e2c6b2ffca 100644
> --- a/gcc/testsuite/c-c++-common/strub-O2fni.c
> +++ b/gcc/testsuite/c-c++-common/strub-O2fni.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O2 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
> +/* { dg-require-effective-target strub } */
>
> /* With -fno-inline, none of the strub builtins are inlined. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-O3.c b/gcc/testsuite/c-c++-common/strub-O3.c
> index 33ee465e51cb6..3bbf132bdf1ea 100644
> --- a/gcc/testsuite/c-c++-common/strub-O3.c
> +++ b/gcc/testsuite/c-c++-common/strub-O3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> int __attribute__ ((__strub__)) var;
>
> diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c
> index 2936f82079e18..c46fce38e5c91 100644
> --- a/gcc/testsuite/c-c++-common/strub-O3fni.c
> +++ b/gcc/testsuite/c-c++-common/strub-O3fni.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O3 -fstrub=strict -fdump-rtl-expand -fno-inline" } */
> +/* { dg-require-effective-target strub } */
>
> /* With -fno-inline, none of the strub builtins are inlined. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c
> index 479746e57d87e..3b8eb19765cd6 100644
> --- a/gcc/testsuite/c-c++-common/strub-Og.c
> +++ b/gcc/testsuite/c-c++-common/strub-Og.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-Og -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> /* At -Og, without -fno-inline, we fully expand enter, but neither update nor
> leave. */
> diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c
> index 2241d4ea07f27..8cfb253d6764c 100644
> --- a/gcc/testsuite/c-c++-common/strub-Os.c
> +++ b/gcc/testsuite/c-c++-common/strub-Os.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-Os -fstrub=strict -fdump-rtl-expand" } */
> +/* { dg-require-effective-target strub } */
>
> /* At -Os, without -fno-inline, we fully expand enter, and also update. The
> expanded update might be larger than a call proper, but argument saving and
> diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c
> index a322bcc5da606..2037f681f2973 100644
> --- a/gcc/testsuite/c-c++-common/strub-all1.c
> +++ b/gcc/testsuite/c-c++-common/strub-all1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
> strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
> diff --git a/gcc/testsuite/c-c++-common/strub-all2.c b/gcc/testsuite/c-c++-common/strub-all2.c
> index db60026d0e080..c026e7d9d289b 100644
> --- a/gcc/testsuite/c-c++-common/strub-all2.c
> +++ b/gcc/testsuite/c-c++-common/strub-all2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=all -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* g becomes STRUB_INTERNAL, because of the flag. Without inline, force_output
> is set for static non-inline functions when not optimizing, and that keeps
> diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c
> index 2f462adc1efe0..3edc89c54eea1 100644
> --- a/gcc/testsuite/c-c++-common/strub-apply1.c
> +++ b/gcc/testsuite/c-c++-common/strub-apply1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> void __attribute__ ((__strub__ ("callable")))
> apply_function (void *args)
> diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c
> index a5d7551f5da5c..838fc75273450 100644
> --- a/gcc/testsuite/c-c++-common/strub-apply2.c
> +++ b/gcc/testsuite/c-c++-common/strub-apply2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> extern void __attribute__ ((__strub__))
> apply_function (void *args);
> diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c
> index 64422a0d1e880..0206e4d930e7d 100644
> --- a/gcc/testsuite/c-c++-common/strub-apply3.c
> +++ b/gcc/testsuite/c-c++-common/strub-apply3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> void __attribute__ ((__strub__))
> apply_function (void *args)
> diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c
> index 15ffaa031b899..e82504728b2c6 100644
> --- a/gcc/testsuite/c-c++-common/strub-apply4.c
> +++ b/gcc/testsuite/c-c++-common/strub-apply4.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O2 -fstrub=strict -fdump-ipa-strubm" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that implicit enabling of strub mode selects internal strub when the
> function uses __builtin_apply_args, that prevents the optimization to
> diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c
> index b70843b4215a4..a20acc0a48a58 100644
> --- a/gcc/testsuite/c-c++-common/strub-at-calls1.c
> +++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
> strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
> diff --git a/gcc/testsuite/c-c++-common/strub-at-calls2.c b/gcc/testsuite/c-c++-common/strub-at-calls2.c
> index 97a3988a6b922..7915b33a39a0a 100644
> --- a/gcc/testsuite/c-c++-common/strub-at-calls2.c
> +++ b/gcc/testsuite/c-c++-common/strub-at-calls2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=at-calls -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* g does NOT become STRUB_AT_CALLS because it's not viable. Without inline,
> force_output is set for static non-inline functions when not optimizing, and
> diff --git a/gcc/testsuite/c-c++-common/strub-defer-O1.c b/gcc/testsuite/c-c++-common/strub-defer-O1.c
> index 3d73431b3dcd3..3689998b5a323 100644
> --- a/gcc/testsuite/c-c++-common/strub-defer-O1.c
> +++ b/gcc/testsuite/c-c++-common/strub-defer-O1.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict -O1" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a strub function called by another strub function does NOT defer
> the strubbing to its caller at -O1. */
> diff --git a/gcc/testsuite/c-c++-common/strub-defer-O2.c b/gcc/testsuite/c-c++-common/strub-defer-O2.c
> index fddf3c745e7e6..9e01949db6be9 100644
> --- a/gcc/testsuite/c-c++-common/strub-defer-O2.c
> +++ b/gcc/testsuite/c-c++-common/strub-defer-O2.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict -O2" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a strub function called by another strub function does NOT defer
> the strubbing to its caller at -O2. */
> diff --git a/gcc/testsuite/c-c++-common/strub-defer-O3.c b/gcc/testsuite/c-c++-common/strub-defer-O3.c
> index 7ebc65b58dd72..40ee8edd1e0e6 100644
> --- a/gcc/testsuite/c-c++-common/strub-defer-O3.c
> +++ b/gcc/testsuite/c-c++-common/strub-defer-O3.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict -O3" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a strub function called by another strub function defers the
> strubbing to its caller at -O3. */
> diff --git a/gcc/testsuite/c-c++-common/strub-defer-Os.c b/gcc/testsuite/c-c++-common/strub-defer-Os.c
> index fbaf85fe0fafe..67ea9f0463975 100644
> --- a/gcc/testsuite/c-c++-common/strub-defer-Os.c
> +++ b/gcc/testsuite/c-c++-common/strub-defer-Os.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict -Os" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a strub function called by another strub function defers the
> strubbing to its caller at -Os. */
> diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c
> index e9d7b7b9ee0a8..d17254904e50a 100644
> --- a/gcc/testsuite/c-c++-common/strub-internal1.c
> +++ b/gcc/testsuite/c-c++-common/strub-internal1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the
> strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */
> diff --git a/gcc/testsuite/c-c++-common/strub-internal2.c b/gcc/testsuite/c-c++-common/strub-internal2.c
> index 8b8e15a51c71c..afc9189701f82 100644
> --- a/gcc/testsuite/c-c++-common/strub-internal2.c
> +++ b/gcc/testsuite/c-c++-common/strub-internal2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=internal -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* g becomes STRUB_INTERNAL, because of the flag. */
> static void
> diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c
> index 0a4a7539d3489..f410b268971a6 100644
> --- a/gcc/testsuite/c-c++-common/strub-parms1.c
> +++ b/gcc/testsuite/c-c++-common/strub-parms1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> #include <stdarg.h>
>
> diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c
> index 147171d96d5a1..6f572115a88c3 100644
> --- a/gcc/testsuite/c-c++-common/strub-parms2.c
> +++ b/gcc/testsuite/c-c++-common/strub-parms2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> #include <stdarg.h>
>
> diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c
> index 4e92682895a43..7383fea9ce881 100644
> --- a/gcc/testsuite/c-c++-common/strub-parms3.c
> +++ b/gcc/testsuite/c-c++-common/strub-parms3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that uses of a strub variable implicitly enables internal strub for
> publicly-visible functions, and causes the same transformations to their
> diff --git a/gcc/testsuite/c-c++-common/strub-relaxed1.c b/gcc/testsuite/c-c++-common/strub-relaxed1.c
> index e2f9d8aebca58..d2b4b52c51e60 100644
> --- a/gcc/testsuite/c-c++-common/strub-relaxed1.c
> +++ b/gcc/testsuite/c-c++-common/strub-relaxed1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The difference between relaxed and strict in this case is that we accept the
> call from one internal-strub function to another. Without the error,
> diff --git a/gcc/testsuite/c-c++-common/strub-relaxed2.c b/gcc/testsuite/c-c++-common/strub-relaxed2.c
> index 98474435d2e59..9e5a8e76b6c3d 100644
> --- a/gcc/testsuite/c-c++-common/strub-relaxed2.c
> +++ b/gcc/testsuite/c-c++-common/strub-relaxed2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed -fdump-ipa-strubm -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The difference between relaxed and strict in this case is that we accept the
> call from one internal-strub function to another. */
> diff --git a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
> index 1de15342595e4..aaeba2a2159a9 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-O0-exc.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O0 -fstrub=strict -fexceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-short-O0.c b/gcc/testsuite/c-c++-common/strub-short-O0.c
> index f9209c819004b..30cbdd819f176 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-O0.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-O0.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O0 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-short-O1.c b/gcc/testsuite/c-c++-common/strub-short-O1.c
> index bed1dcfb54a45..911fdfb6db9a5 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-O1.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-O1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-short-O2.c b/gcc/testsuite/c-c++-common/strub-short-O2.c
> index 6bf0071f52b93..9b23ee3ac3312 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-O2.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-O2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. */
>
> diff --git a/gcc/testsuite/c-c++-common/strub-short-O3.c b/gcc/testsuite/c-c++-common/strub-short-O3.c
> index 4732f515bf70c..4b3a8f843ea19 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-O3.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-O3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O3 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. At -O3 and -Os, we omit
> enter and leave calls within strub contexts, passing on the enclosing
> diff --git a/gcc/testsuite/c-c++-common/strub-short-Os.c b/gcc/testsuite/c-c++-common/strub-short-Os.c
> index 8d6424c479a3a..3627a2406000b 100644
> --- a/gcc/testsuite/c-c++-common/strub-short-Os.c
> +++ b/gcc/testsuite/c-c++-common/strub-short-Os.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-Os -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued. At -O3 and -Os, we omit
> enter and leave calls within strub contexts, passing on the enclosing
> diff --git a/gcc/testsuite/c-c++-common/strub-split-stack.c b/gcc/testsuite/c-c++-common/strub-split-stack.c
> new file mode 100644
> index 0000000000000..7a030cdb9e9e6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/strub-split-stack.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fsplit-stack" } */
> +/* { dg-require-effective-target strub } */
> +/* { dg-require-effective-target split_stack } */
> +
> +void __attribute__ ((__strub__))
> +f () {} /* { dg-message "not eligible|requested" } */
> +
> +void __attribute__ ((__strub__ ("internal")))
> +g () {} /* { dg-message "not eligible|requested" } */
> diff --git a/gcc/testsuite/c-c++-common/strub-strict1.c b/gcc/testsuite/c-c++-common/strub-strict1.c
> index 368522442066e..503eb1734e36f 100644
> --- a/gcc/testsuite/c-c++-common/strub-strict1.c
> +++ b/gcc/testsuite/c-c++-common/strub-strict1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
> +/* { dg-require-effective-target strub } */
>
> static int __attribute__ ((__strub__)) var;
>
> diff --git a/gcc/testsuite/c-c++-common/strub-strict2.c b/gcc/testsuite/c-c++-common/strub-strict2.c
> index b4f2888321821..3bf1aa30b4af1 100644
> --- a/gcc/testsuite/c-c++-common/strub-strict2.c
> +++ b/gcc/testsuite/c-c++-common/strub-strict2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strubm" } */
> +/* { dg-require-effective-target strub } */
>
> static int __attribute__ ((__strub__)) var;
>
> diff --git a/gcc/testsuite/c-c++-common/strub-tail-O1.c b/gcc/testsuite/c-c++-common/strub-tail-O1.c
> index e48e0610e079b..ba4b1623e281a 100644
> --- a/gcc/testsuite/c-c++-common/strub-tail-O1.c
> +++ b/gcc/testsuite/c-c++-common/strub-tail-O1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O1 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> #include "strub-tail-O2.c"
>
> diff --git a/gcc/testsuite/c-c++-common/strub-tail-O2.c b/gcc/testsuite/c-c++-common/strub-tail-O2.c
> index 87cda7ab21b16..043813b1de467 100644
> --- a/gcc/testsuite/c-c++-common/strub-tail-O2.c
> +++ b/gcc/testsuite/c-c++-common/strub-tail-O2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-O2 -fstrub=strict -fno-exceptions -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that the expected strub calls are issued.
> Tail calls are short-circuited at -O2+. */
> diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-2.c b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
> new file mode 100644
> index 0000000000000..3586f4f679dfe
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/strub-unsupported-2.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +
> +/* Check that, when strub is not supported (so no dg-required-effective-target
> + strub above), we report when pointers to strub functions are called. This
> + cannot be part of strub-unsupported.c because errors in the strub-mode pass
> + prevent the main strub pass, where errors at calls are detected, from
> + running. */
> +
> +void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
> +
> +void m () {
> + p (); /* { dg-message "unsupported" "" { target { ! strub } } } */
> +}
> diff --git a/gcc/testsuite/c-c++-common/strub-unsupported-3.c b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
> new file mode 100644
> index 0000000000000..d6fb4c525c4a6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/strub-unsupported-3.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +
> +/* Check that, when strub is not supported (so no dg-required-effective-target
> + strub above), we report when strub functions that are not defined are
> + called. This cannot be part of strub-unsupported-2.c because errors in the
> + strub-mode pass prevent the main strub pass, where errors at calls are
> + detected, from running. */
> +
> +extern void __attribute__ ((__strub__))
> +s (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
> +
> +extern void __attribute__ ((__strub__ ("internal")))
> +t (void); /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
> +
> +void m () {
> + s ();
> + t ();
> +}
> diff --git a/gcc/testsuite/c-c++-common/strub-unsupported.c b/gcc/testsuite/c-c++-common/strub-unsupported.c
> new file mode 100644
> index 0000000000000..cb5c4049495c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/strub-unsupported.c
> @@ -0,0 +1,21 @@
> +/* { dg-do compile } */
> +
> +/* Check that, when strub is not supported (so no dg-required-effective-target
> + strub above), we report when strub functions are defined, and when they're
> + called in ways that would require changes. */
> +
> +void __attribute__ ((__strub__))
> +f (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
> +
> +void __attribute__ ((__strub__ ("internal")))
> +g (void) {} /* { dg-message "not eligible|requested" "" { target { ! strub } } } */
> +
> +/* This only gets an error when called, see strub-unsupported-2.c. */
> +void __attribute__ ((__strub__ ("at-calls"))) (*p) (void);
> +
> +/* These too, see strub-unsupported-3.c. */
> +extern void __attribute__ ((__strub__))
> +s (void);
> +
> +extern void __attribute__ ((__strub__ ("internal")))
> +t (void);
> diff --git a/gcc/testsuite/c-c++-common/strub-var1.c b/gcc/testsuite/c-c++-common/strub-var1.c
> index eb6250fd39c90..67014aa5de84a 100644
> --- a/gcc/testsuite/c-c++-common/strub-var1.c
> +++ b/gcc/testsuite/c-c++-common/strub-var1.c
> @@ -1,4 +1,5 @@
> /* { dg-do compile } */
> +/* { dg-require-effective-target strub } */
>
> int __attribute__ ((strub)) x;
> float __attribute__ ((strub)) f;
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
> index b5e45ab0525ad..86dbee6746d1b 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-callable1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that strub and non-strub functions can be called from non-strub
> contexts, and that strub and callable functions can be called from strub
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
> index 96aa7fe4b07f7..9da120f615645 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-callable2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that impermissible (cross-strub-context) calls are reported. */
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c
> index 5e956cb1a9b6b..22056713cce4b 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-const1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub const function call, we issue an asm
> statement to make sure the watermark passed to it is held in memory before
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c
> index 73d650292dfbf..a105c66d7a9c9 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-const2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub implicitly-const function call, we issue an
> asm statement to make sure the watermark passed to it is held in memory
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c
> index 2584f1f974a58..386200c2784a4 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-const3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub const wrapping call, we issue an asm statement
> to make sure the watermark passed to it is held in memory before the call,
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c
> index d819f54ec0230..817e9fa2118b6 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-const4.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub implicitly-const wrapping call, we issue an
> asm statement to make sure the watermark passed to it is held in memory
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-data1.c b/gcc/testsuite/c-c++-common/torture/strub-data1.c
> index 7c27a2a1a6dca..132ab63ef733a 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-data1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-data1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The pointed-to data enables strubbing if accessed. */
> int __attribute__ ((__strub__)) var;
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-data2.c b/gcc/testsuite/c-c++-common/torture/strub-data2.c
> index e66d903780afd..b660702d26e75 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-data2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-data2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The pointer itself is a strub variable, enabling internal strubbing when
> its value is used. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-data3.c b/gcc/testsuite/c-c++-common/torture/strub-data3.c
> index 5e08e0e58c658..fc44eef6f8fb5 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-data3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-data3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The pointer itself is a strub variable, that would enable internal strubbing
> if its value was used. Here, it's only overwritten, so no strub. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-data4.c b/gcc/testsuite/c-c++-common/torture/strub-data4.c
> index a818e7a38bb5f..85e2f59055b57 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-data4.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-data4.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* The pointer itself is a strub variable, that would enable internal strubbing
> if its value was used. Here, it's only overwritten, so no strub. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c
> index ddb0b5c0543b0..0a5edac414df1 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-data5.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> /* It would be desirable to issue at least warnings for these. */
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
> index c165f312f16de..988954e7ed6bc 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-indcall1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> typedef void __attribute__ ((__strub__)) fntype ();
> fntype (*ptr);
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
> index 69fcff8d3763d..d3ca91389a700 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-indcall2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> typedef void __attribute__ ((__strub__)) fntype (int, int);
> fntype (*ptr);
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
> index ff006224909bd..89b5979cf7b78 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-indcall3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> typedef void __attribute__ ((__strub__)) fntype (int, int, ...);
> fntype (*ptr);
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
> index 614b02228ba29..4917dda8826d9 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed" } */
> +/* { dg-require-effective-target strub } */
>
> inline void __attribute__ ((strub ("internal"), always_inline))
> inl_int_ali (void)
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
> index f9a6b4a16faf8..c45903856d4ff 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-inlinable2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=all" } */
> +/* { dg-require-effective-target strub } */
>
> #include "strub-inlinable1.c"
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
> index b4a7f3992bbaa..b0d6139f0a870 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> typedef void ft (void);
> typedef void ft2 (int, int);
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
> index ef634d351265f..1148c246f2059 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed -Wpedantic" } */
> +/* { dg-require-effective-target strub } */
>
> /* C++ does not warn about the partial incompatibilities.
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
> index e1f179e160e5c..06a72d86d2c58 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn3.c
> @@ -1,6 +1,7 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed -Wpedantic -fpermissive" } */
> /* { dg-prune-output "command-line option .-fpermissive." } */
> +/* { dg-require-effective-target strub } */
>
> /* See strub-ptrfn2.c. */
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
> index 70b558afad040..83ea1af7056e7 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-ptrfn4.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=relaxed" } */
> +/* { dg-require-effective-target strub } */
>
> /* This is strub-ptrfn2.c without -Wpedantic.
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
> index a262a086837b2..2643136f178cc 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-pure1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub pure function call, we issue an asm statement
> to make sure the watermark passed to it is not assumed to be unchanged. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
> index 4c4bd50c209a0..8bda129b77dc6 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-pure2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub implicitly-pure function call, we issue an asm
> statement to make sure the watermark passed to it is not assumed to be
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
> index ce195c6b1f1b6..00bcbdd097af8 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-pure3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub pure wrapping call, we issue an asm statement
> to make sure the watermark passed to it is not assumed to be unchanged. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
> index 75cd54ccb5b5d..ea7c40e7912b4 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-pure4.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that, along with a strub implicitly-pure wrapping call, we issue an asm
> statement to make sure the watermark passed to it is not assumed to be
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c
> index 7458b3fb54da5..fdf100428631d 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run1.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a non-strub function leaves a string behind in the stack, and that
> equivalent strub functions don't. Avoid the use of red zones by avoiding
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c
> index 5d60a7775f4bb..1228a66599721 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run2.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict" } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a non-strub function leaves a string behind in the stack, and that
> equivalent strub functions don't. Allow red zones to be used. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c
> index c2ad710858e87..e5047a988f5bf 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run3.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c
> @@ -1,6 +1,7 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict" } */
> /* { dg-require-effective-target alloca } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that a non-strub function leaves a string behind in the stack, and that
> equivalent strub functions don't. */
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4.c b/gcc/testsuite/c-c++-common/torture/strub-run4.c
> index 3b36b8e5d68ef..0e84a4bab80fc 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run4.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run4.c
> @@ -1,6 +1,7 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=all" } */
> /* { dg-require-effective-target alloca } */
> +/* { dg-require-effective-target strub } */
>
> /* Check that multi-level, multi-inlined functions still get cleaned up as
> expected, without overwriting temporary stack allocations while they should
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4c.c b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
> index 57f9baf758ded..edc98486dc93a 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run4c.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run4c.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=at-calls" } */
> /* { dg-require-effective-target alloca } */
> +/* { dg-require-effective-target strub } */
>
> #include "strub-run4.c"
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4d.c b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
> index 08de3f1c3b17c..487ed08bb6606 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run4d.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run4d.c
> @@ -1,6 +1,7 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=strict" } */
> /* { dg-require-effective-target alloca } */
> +/* { dg-require-effective-target strub } */
>
> #define ATTR_STRUB_AT_CALLS __attribute__ ((__strub__ ("at-calls")))
>
> diff --git a/gcc/testsuite/c-c++-common/torture/strub-run4i.c b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
> index 459f6886c5499..a85447ffabfae 100644
> --- a/gcc/testsuite/c-c++-common/torture/strub-run4i.c
> +++ b/gcc/testsuite/c-c++-common/torture/strub-run4i.c
> @@ -1,5 +1,6 @@
> /* { dg-do run } */
> /* { dg-options "-fstrub=internal" } */
> /* { dg-require-effective-target alloca } */
> +/* { dg-require-effective-target strub } */
>
> #include "strub-run4.c"
> diff --git a/gcc/testsuite/g++.dg/strub-run1.C b/gcc/testsuite/g++.dg/strub-run1.C
> index 0d367fb83d09d..beb8b811f8fca 100644
> --- a/gcc/testsuite/g++.dg/strub-run1.C
> +++ b/gcc/testsuite/g++.dg/strub-run1.C
> @@ -1,5 +1,6 @@
> // { dg-do run }
> // { dg-options "-fstrub=internal" }
> +// { dg-require-effective-target strub }
>
> // Check that we don't get extra copies.
>
> diff --git a/gcc/testsuite/g++.dg/torture/strub-init1.C b/gcc/testsuite/g++.dg/torture/strub-init1.C
> index c226ab10ff651..6ae45fadd70ba 100644
> --- a/gcc/testsuite/g++.dg/torture/strub-init1.C
> +++ b/gcc/testsuite/g++.dg/torture/strub-init1.C
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +// { dg-require-effective-target strub }
>
> extern int __attribute__((__strub__)) initializer ();
>
> diff --git a/gcc/testsuite/g++.dg/torture/strub-init2.C b/gcc/testsuite/g++.dg/torture/strub-init2.C
> index a7911f1fa7212..8f4849c7fde78 100644
> --- a/gcc/testsuite/g++.dg/torture/strub-init2.C
> +++ b/gcc/testsuite/g++.dg/torture/strub-init2.C
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +// { dg-require-effective-target strub }
>
> extern int __attribute__((__strub__)) initializer ();
>
> diff --git a/gcc/testsuite/g++.dg/torture/strub-init3.C b/gcc/testsuite/g++.dg/torture/strub-init3.C
> index 6ebebcd01e8ea..14f28e3c276bd 100644
> --- a/gcc/testsuite/g++.dg/torture/strub-init3.C
> +++ b/gcc/testsuite/g++.dg/torture/strub-init3.C
> @@ -1,5 +1,6 @@
> /* { dg-do compile } */
> /* { dg-options "-fstrub=strict -fdump-ipa-strub" } */
> +// { dg-require-effective-target strub }
>
> extern int __attribute__((__strub__)) initializer ();
>
> diff --git a/gcc/testsuite/gnat.dg/strub_access.adb b/gcc/testsuite/gnat.dg/strub_access.adb
> index 29e6996ecf61c..488a2d64afe31 100644
> --- a/gcc/testsuite/gnat.dg/strub_access.adb
> +++ b/gcc/testsuite/gnat.dg/strub_access.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=relaxed -fdump-ipa-strubm" }
> +-- { dg-require-effective-target strub }
>
> -- The main subprogram doesn't read from the automatic variable, but
> -- being an automatic variable, its presence should be enough for the
> diff --git a/gcc/testsuite/gnat.dg/strub_access1.adb b/gcc/testsuite/gnat.dg/strub_access1.adb
> index dae4706016436..4a8653c4d843f 100644
> --- a/gcc/testsuite/gnat.dg/strub_access1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_access1.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=relaxed" }
> +-- { dg-require-effective-target strub }
>
> -- Check that we reject 'Access of a strub variable whose type does
> -- not carry a strub modifier.
> diff --git a/gcc/testsuite/gnat.dg/strub_attr.adb b/gcc/testsuite/gnat.dg/strub_attr.adb
> index 10445d7cf8451..eb7826dc990f4 100644
> --- a/gcc/testsuite/gnat.dg/strub_attr.adb
> +++ b/gcc/testsuite/gnat.dg/strub_attr.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict -fdump-ipa-strubm -fdump-ipa-strub" }
> +-- { dg-require-effective-target strub }
>
> package body Strub_Attr is
> E : exception;
> diff --git a/gcc/testsuite/gnat.dg/strub_disp.adb b/gcc/testsuite/gnat.dg/strub_disp.adb
> index 3dbcc4a357cba..f23d4675def38 100644
> --- a/gcc/testsuite/gnat.dg/strub_disp.adb
> +++ b/gcc/testsuite/gnat.dg/strub_disp.adb
> @@ -1,4 +1,5 @@
> -- { dg-do compile }
> +-- { dg-require-effective-target strub }
>
> procedure Strub_Disp is
> package Foo is
> diff --git a/gcc/testsuite/gnat.dg/strub_disp1.adb b/gcc/testsuite/gnat.dg/strub_disp1.adb
> index 09756a74b7d81..9c4c7f696371d 100644
> --- a/gcc/testsuite/gnat.dg/strub_disp1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_disp1.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fdump-ipa-strub" }
> +-- { dg-require-effective-target strub }
>
> -- Check that at-calls dispatching calls are transformed.
>
> diff --git a/gcc/testsuite/gnat.dg/strub_ind.adb b/gcc/testsuite/gnat.dg/strub_ind.adb
> index da56acaa957d2..613db69305e05 100644
> --- a/gcc/testsuite/gnat.dg/strub_ind.adb
> +++ b/gcc/testsuite/gnat.dg/strub_ind.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict" }
> +-- { dg-require-effective-target strub }
>
> -- This is essentially the same test as strub_attr.adb,
> -- but applying attributes to access types as well.
> diff --git a/gcc/testsuite/gnat.dg/strub_ind1.adb b/gcc/testsuite/gnat.dg/strub_ind1.adb
> index 825e395e6819c..245b0a830f691 100644
> --- a/gcc/testsuite/gnat.dg/strub_ind1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_ind1.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
> +-- { dg-require-effective-target strub }
>
> -- This is essentially the same test as strub_attr.adb,
> -- but with an explicit conversion.
> diff --git a/gcc/testsuite/gnat.dg/strub_ind2.adb b/gcc/testsuite/gnat.dg/strub_ind2.adb
> index e918b39263117..b9bfe50e9296e 100644
> --- a/gcc/testsuite/gnat.dg/strub_ind2.adb
> +++ b/gcc/testsuite/gnat.dg/strub_ind2.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict" }
> +-- { dg-require-effective-target strub }
>
> -- This is essentially the same test as strub_attr.adb,
> -- but with an explicit conversion.
> diff --git a/gcc/testsuite/gnat.dg/strub_intf.adb b/gcc/testsuite/gnat.dg/strub_intf.adb
> index 8f0212a75866f..f43854705d073 100644
> --- a/gcc/testsuite/gnat.dg/strub_intf.adb
> +++ b/gcc/testsuite/gnat.dg/strub_intf.adb
> @@ -1,4 +1,5 @@
> -- { dg-do compile }
> +-- { dg-require-effective-target strub }
>
> -- Check that strub mode mismatches between overrider and overridden
> -- subprograms are reported.
> diff --git a/gcc/testsuite/gnat.dg/strub_intf1.adb b/gcc/testsuite/gnat.dg/strub_intf1.adb
> index bf77321cef790..7a38a4c49ba8d 100644
> --- a/gcc/testsuite/gnat.dg/strub_intf1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_intf1.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fdump-ipa-strub" }
> +-- { dg-require-effective-target strub }
>
> -- Check that at-calls dispatching calls to interfaces are transformed.
>
> diff --git a/gcc/testsuite/gnat.dg/strub_intf2.adb b/gcc/testsuite/gnat.dg/strub_intf2.adb
> index e8880dbc43730..7992b7344fb87 100644
> --- a/gcc/testsuite/gnat.dg/strub_intf2.adb
> +++ b/gcc/testsuite/gnat.dg/strub_intf2.adb
> @@ -1,4 +1,5 @@
> -- { dg-do compile }
> +-- { dg-require-effective-target strub }
>
> -- Check that strub mode mismatches between overrider and overridden
> -- subprograms are reported even when the overriders for an
> diff --git a/gcc/testsuite/gnat.dg/strub_renm.adb b/gcc/testsuite/gnat.dg/strub_renm.adb
> index 217367e712d82..abfb120b51468 100644
> --- a/gcc/testsuite/gnat.dg/strub_renm.adb
> +++ b/gcc/testsuite/gnat.dg/strub_renm.adb
> @@ -1,4 +1,5 @@
> -- { dg-do compile }
> +-- { dg-require-effective-target strub }
>
> procedure Strub_Renm is
> procedure P (X : Integer);
> diff --git a/gcc/testsuite/gnat.dg/strub_renm1.adb b/gcc/testsuite/gnat.dg/strub_renm1.adb
> index a11adbfb5a9d6..68d3230b5356c 100644
> --- a/gcc/testsuite/gnat.dg/strub_renm1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_renm1.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=relaxed -fdump-ipa-strub" }
> +-- { dg-require-effective-target strub }
>
> procedure Strub_Renm1 is
> V : Integer := 0;
> diff --git a/gcc/testsuite/gnat.dg/strub_renm2.adb b/gcc/testsuite/gnat.dg/strub_renm2.adb
> index c488c20826fdb..3cb81ea03f763 100644
> --- a/gcc/testsuite/gnat.dg/strub_renm2.adb
> +++ b/gcc/testsuite/gnat.dg/strub_renm2.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict -fdump-ipa-strub" }
> +-- { dg-require-effective-target strub }
>
> procedure Strub_Renm2 is
> V : Integer := 0;
> diff --git a/gcc/testsuite/gnat.dg/strub_var.adb b/gcc/testsuite/gnat.dg/strub_var.adb
> index 3d158de28031f..7c6affa06d4ab 100644
> --- a/gcc/testsuite/gnat.dg/strub_var.adb
> +++ b/gcc/testsuite/gnat.dg/strub_var.adb
> @@ -1,5 +1,6 @@
> -- { dg-do compile }
> -- { dg-options "-fstrub=strict -fdump-ipa-strubm" }
> +-- { dg-require-effective-target strub }
>
> -- We don't read from the automatic variable, but being an automatic
> -- variable, its presence should be enough for the procedure to get
> diff --git a/gcc/testsuite/gnat.dg/strub_var1.adb b/gcc/testsuite/gnat.dg/strub_var1.adb
> index 6a504e09198b6..64b7e65fe9b0f 100644
> --- a/gcc/testsuite/gnat.dg/strub_var1.adb
> +++ b/gcc/testsuite/gnat.dg/strub_var1.adb
> @@ -1,4 +1,5 @@
> -- { dg-do compile }
> +-- { dg-require-effective-target strub }
>
> with Strub_Attr;
> procedure Strub_Var1 is
> diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
> index 3fcce6be49d6f..40a60c198cfe8 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -1302,6 +1302,13 @@ proc check_stack_check_available { stack_kind } {
> } "$stack_opt"]
> }
>
> +# Return 1 if the target supports stack scrubbing.
> +proc check_effective_target_strub {} {
> + return [check_no_compiler_messages strub assembly {
> + void __attribute__ ((__strub__)) fn (void) {}
> + } ""]
> +}
> +
> # Return 1 if compilation with -freorder-blocks-and-partition is error-free
> # for trivial code, 0 otherwise. As some targets (ARM for example) only
> # warn when -fprofile-use is also supplied we test that combination too.
> diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
> index d8163c5af9903..3f77283490ef6 100644
> --- a/libgcc/Makefile.in
> +++ b/libgcc/Makefile.in
> @@ -434,7 +434,7 @@ LIB2ADD += enable-execute-stack.c
> LIB2ADD += $(srcdir)/hardcfr.c
>
> # Stack scrubbing infrastructure.
> -LIB2ADD += $(srcdir)/strub.c
> +@HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c
>
> # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
> # instead of LIB2ADD because that's the way to be sure on some targets
> diff --git a/libgcc/configure b/libgcc/configure
> index cf149209652e3..567158955a329 100755
> --- a/libgcc/configure
> +++ b/libgcc/configure
> @@ -593,6 +593,7 @@ asm_hidden_op
> extra_parts
> cpu_type
> get_gcc_base_ver
> +HAVE_STRUB_SUPPORT
> thread_header
> tm_defines
> tm_file
> @@ -5702,6 +5703,31 @@ esac
>
>
>
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strub support" >&5
> +$as_echo_n "checking for strub support... " >&6; }
> +if ${libgcc_cv_strub_support+:} false; then :
> + $as_echo_n "(cached) " >&6
> +else
> + cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h. */
> +void __attribute__ ((__strub__)) fn (void) {}
> +_ACEOF
> +if ac_fn_c_try_compile "$LINENO"; then :
> + libgcc_cv_strub_support=yes
> +else
> + libgcc_cv_strub_support=no
> +fi
> +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_strub_support" >&5
> +$as_echo "$libgcc_cv_strub_support" >&6; }
> +if test "x$libgcc_cv_strub_support" != xno; then
> + HAVE_STRUB_SUPPORT=
> +else
> + HAVE_STRUB_SUPPORT='# '
> +fi
> +
> +
> # Determine what GCC version number to use in filesystem paths.
>
> get_gcc_base_ver="cat"
> diff --git a/libgcc/configure.ac b/libgcc/configure.ac
> index 2fc9d5d7c93e9..9c0e415501a80 100644
> --- a/libgcc/configure.ac
> +++ b/libgcc/configure.ac
> @@ -694,6 +694,19 @@ AC_SUBST(tm_defines)
> # Map from thread model to thread header.
> GCC_AC_THREAD_HEADER([$target_thread_file])
>
> +AC_CACHE_CHECK([for strub support],
> + [libgcc_cv_strub_support],
> + [AC_COMPILE_IFELSE(
> + [AC_LANG_SOURCE([void __attribute__ ((__strub__)) fn (void) {}])],
> + [libgcc_cv_strub_support=yes],
> + [libgcc_cv_strub_support=no])])
> +if test "x$libgcc_cv_strub_support" != xno; then
> + HAVE_STRUB_SUPPORT=
> +else
> + HAVE_STRUB_SUPPORT='# '
> +fi
> +AC_SUBST(HAVE_STRUB_SUPPORT)
> +
> # Determine what GCC version number to use in filesystem paths.
> GCC_BASE_VER
>
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
^ permalink raw reply [flat|nested] 521+ messages in thread
* [PATCH]
2023-12-07 16:44 ` Thomas Schwinge
@ 2023-12-07 17:52 ` Alexandre Oliva
2023-12-08 6:46 ` [PATCH] Richard Biener
0 siblings, 1 reply; 521+ messages in thread
From: Alexandre Oliva @ 2023-12-07 17:52 UTC (permalink / raw)
To: Thomas Schwinge, FX Coudert
Cc: Tobias Burnus, Richard Biener, gcc-patches, Jeremy Bennett,
Craig Blackmore, Graham Markall, Martin Jambor, Jan Hubicka,
Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
On Dec 7, 2023, Thomas Schwinge <thomas@codesourcery.com> wrote:
> Thank you for looking into this so promptly!
You're welcome ;-)
> during IPA pass: emutls
> [...]/source-gcc/gcc/testsuite/c-c++-common/strub-unsupported-3.c:18:1: internal compiler error: in verify_curr_properties, at passes.cc:2198
Aah, this smells a lot like the issue that François-Xavier reported,
that the following patch is expected to fix. I'm still regstrapping it
on x86_64-linux-gnu, after checking that it addressed the symptom on a
cross compiler to the target for which it had originally been reported.
Ok to install, once you confirm that it cures these ICEs?
strub: skip emutls after strubm errors
The emutls pass requires PROP_ssa, but if the strubm pass (or any
other pre-SSA pass) issues errors, all of the build_ssa_passes are
skipped, so the property is not set, but emutls still attempts to run,
on targets that use it, despite earlier errors, so it hits the
unsatisfied requirement.
Adjust emutls to be skipped in case of earlier errors.
for gcc/ChangeLog
* tree-emutls.cc: Include diagnostic-core.h.
(pass_ipa_lower_emutls::gate): Skip if errors were seen.
---
gcc/tree-emutls.cc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gcc/tree-emutls.cc b/gcc/tree-emutls.cc
index 5dca5a8291356..38de202717a1a 100644
--- a/gcc/tree-emutls.cc
+++ b/gcc/tree-emutls.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "tree-iterator.h"
#include "gimplify.h"
+#include "diagnostic-core.h" /* for seen_error */
/* Whenever a target does not support thread-local storage (TLS) natively,
we can emulate it with some run-time support in libgcc. This will in
@@ -841,7 +842,7 @@ public:
bool gate (function *) final override
{
/* If the target supports TLS natively, we need do nothing here. */
- return !targetm.have_tls;
+ return !targetm.have_tls && !seen_error ();
}
unsigned int execute (function *) final override
--
Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
Free Software Activist GNU Toolchain Engineer
More tolerance and less prejudice are key for inclusion and diversity
Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread
* Re: [PATCH]
2023-12-07 17:52 ` [PATCH] Alexandre Oliva
@ 2023-12-08 6:46 ` Richard Biener
0 siblings, 0 replies; 521+ messages in thread
From: Richard Biener @ 2023-12-08 6:46 UTC (permalink / raw)
To: Alexandre Oliva
Cc: Thomas Schwinge, FX Coudert, Tobias Burnus, gcc-patches,
Jeremy Bennett, Craig Blackmore, Graham Markall, Martin Jambor,
Jan Hubicka, Jim Wilson, Jeff Law, Jakub Jelinek, Tom de Vries
On Thu, Dec 7, 2023 at 6:52 PM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Dec 7, 2023, Thomas Schwinge <thomas@codesourcery.com> wrote:
>
> > Thank you for looking into this so promptly!
>
> You're welcome ;-)
>
>
> > during IPA pass: emutls
> > [...]/source-gcc/gcc/testsuite/c-c++-common/strub-unsupported-3.c:18:1: internal compiler error: in verify_curr_properties, at passes.cc:2198
>
> Aah, this smells a lot like the issue that François-Xavier reported,
> that the following patch is expected to fix. I'm still regstrapping it
> on x86_64-linux-gnu, after checking that it addressed the symptom on a
> cross compiler to the target for which it had originally been reported.
> Ok to install, once you confirm that it cures these ICEs?
>
>
> strub: skip emutls after strubm errors
>
> The emutls pass requires PROP_ssa, but if the strubm pass (or any
> other pre-SSA pass) issues errors, all of the build_ssa_passes are
> skipped, so the property is not set, but emutls still attempts to run,
> on targets that use it, despite earlier errors, so it hits the
> unsatisfied requirement.
>
> Adjust emutls to be skipped in case of earlier errors.
OK.
>
> for gcc/ChangeLog
>
> * tree-emutls.cc: Include diagnostic-core.h.
> (pass_ipa_lower_emutls::gate): Skip if errors were seen.
> ---
> gcc/tree-emutls.cc | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/tree-emutls.cc b/gcc/tree-emutls.cc
> index 5dca5a8291356..38de202717a1a 100644
> --- a/gcc/tree-emutls.cc
> +++ b/gcc/tree-emutls.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
> #include "langhooks.h"
> #include "tree-iterator.h"
> #include "gimplify.h"
> +#include "diagnostic-core.h" /* for seen_error */
>
> /* Whenever a target does not support thread-local storage (TLS) natively,
> we can emulate it with some run-time support in libgcc. This will in
> @@ -841,7 +842,7 @@ public:
> bool gate (function *) final override
> {
> /* If the target supports TLS natively, we need do nothing here. */
> - return !targetm.have_tls;
> + return !targetm.have_tls && !seen_error ();
> }
>
> unsigned int execute (function *) final override
>
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive
^ permalink raw reply [flat|nested] 521+ messages in thread