Re: Bootstrap failed on i386-pc-solaris2.10
That is what I missed. Thanks. This patch should work. Sure, but it makes the mess even worse. You should instead: - in config/t-svr4, change the two CFLAGS assignments to use += - in config/i386/t-sol2, change the CRTSTUFF_T_CFLAGS assignment to "+= -O2" and remove the TARGET_LIBGCC2_CFLAGS assignment - in config.gcc, change tmake_file="t-sol2 i386/t-sol2 t-svr4" to tmake_file="${tmake_file} t-sol2 i386/t-sol2 t-svr4" and move it at the end of the case stanza, i.e. before ;; i[34567]86-*-sysv5*) # Intel x86 on System V Release 5 Paolo
Re: Bootstrap failed on i386-pc-solaris2.10
On Wed, Aug 08, 2007 at 10:06:03AM +0200, Paolo Bonzini wrote: > > >That is what I missed. Thanks. > > > >This patch should work. > > Sure, but it makes the mess even worse. You should instead: > > - in config/t-svr4, change the two CFLAGS assignments to use += There is CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC How do you use +=? > - in config/i386/t-sol2, change the CRTSTUFF_T_CFLAGS assignment to "+= > -O2" and remove the TARGET_LIBGCC2_CFLAGS assignment > - in config.gcc, change > > tmake_file="t-sol2 i386/t-sol2 t-svr4" > > to > > tmake_file="${tmake_file} t-sol2 i386/t-sol2 t-svr4" > > and move it at the end of the case stanza, i.e. before > > ;; > i[34567]86-*-sysv5*) # Intel x86 on System V Release 5 > There are so many changes and I can't test any of them. I will leave them to someone who can test. I will be happy to back out: - tmake_file="$tmake_file i386/t-sol2-10" + tmake_file="$tmake_file i386/t-crtstuff i386/t-sol2-10" in the mean time. H.J.
Re: Bootstrap failed on i386-pc-solaris2.10
CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC How do you use +=? Sorry, I was looking at an old checkout. Could you simply test patching config/i386/t-crtstuff like this: -CRTSTUFF_T_CFLAGS = -fno-omit-frame-pointer -fno-asynchronous-unwind-tables +CRTSTUFF_T_CFLAGS += -fno-omit-frame-pointer -fno-asynchronous-unwind-tables (It would be great if you, H.J., tested on Linux, and Art tested on Solaris 10). Thanks, Paolo
[tuples] gimplification of other FEs and platforms
I've updated http://gcc.gnu.org/wiki/tuples to show the items we still have to go through. To avoid stepping on each other's toes, please claim the items you are working (or plan to work on) in the list. I've arranged the items in the plan to reflect the critical path that should take us to bootstrap C on our desktops. If you notice anything missing please add it to the list. I've marked the major milestones in bold. Thanks.
RE: Bootstrap failed on i386-pc-solaris2.10
> -Original Message- > [ ... snip ... ] > > > CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC > > > > How do you use +=? > > Sorry, I was looking at an old checkout. > > Could you simply test patching config/i386/t-crtstuff like this: > > -CRTSTUFF_T_CFLAGS = -fno-omit-frame-pointer > -fno-asynchronous-unwind-tables > +CRTSTUFF_T_CFLAGS += -fno-omit-frame-pointer > -fno-asynchronous-unwind-tables > > (It would be great if you, H.J., tested on Linux, and Art tested on > Solaris 10). > > Thanks, > > Paolo Hi. Making the change above results in a successful build. Quite a difference what a '+' can make. Art Haas
Re: Bootstrap failed on i386-pc-solaris2.10
On Wed, Aug 08, 2007 at 09:45:00AM -0500, Arthur Haas wrote: > > > -Original Message- > > [ ... snip ... ] > > > > > CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC > > > > > > How do you use +=? > > > > Sorry, I was looking at an old checkout. > > > > Could you simply test patching config/i386/t-crtstuff like this: > > > > -CRTSTUFF_T_CFLAGS = -fno-omit-frame-pointer > > -fno-asynchronous-unwind-tables > > +CRTSTUFF_T_CFLAGS += -fno-omit-frame-pointer > > -fno-asynchronous-unwind-tables > > > > (It would be great if you, H.J., tested on Linux, and Art tested on > > Solaris 10). > > > > Thanks, > > > > Paolo > > Hi. > > Making the change above results in a successful build. Quite a > difference what a '+' can make. > This patch works fine on Linux/x86 and Linux/x86-64. H.J. --- 2007-08-08 Paolo Bonzini <[EMAIL PROTECTED]> * config/i386/t-crtstuff (CRTSTUFF_T_CFLAGS): Use +=. --- gcc/config/i386/t-crtstuff.sol2 2007-08-06 17:05:40.0 -0700 +++ gcc/config/i386/t-crtstuff 2007-08-08 06:56:17.0 -0700 @@ -4,4 +4,4 @@ # section. -fno-asynchronous-unwind-tables is off by default for i386 # and is on by default for x86-64. We turn it off for both i386 and # x86-64. -CRTSTUFF_T_CFLAGS = -fno-omit-frame-pointer -fno-asynchronous-unwind-tables +CRTSTUFF_T_CFLAGS += -fno-omit-frame-pointer -fno-asynchronous-unwind-tables
Re: Bootstrap failed on i386-pc-solaris2.10
Making the change above results in a successful build. Quite a difference what a '+' can make. This patch works fine on Linux/x86 and Linux/x86-64. Thanks! Paolo
Re: [RFC] Migrate pointers to members to the middle end
Hi, On Tue, 7 Aug 2007, Ollie Wild wrote: > In response to a suggestion from Mark Mitchell, I've been attempting to > migrate pointers to members to the GCC middle end. The goal of this is > twofold: (a) to enable conversion of pointer to member dereferences to > direct function calls and member accesses when analysis determines this > is unambiguous and (b) to obsolete the need for the expand_constant > language hook. > > Under my current approach, I've added the following new nodes to > gcc/tree.def: > > DEFTREECODE (PTRMEM_TYPE, "ptrmem_type", tcc_type, 0) > DEFTREECODE (PTRMEM_CST, "ptrmem_cst", tcc_constant, 0) > DEFTREECODE (PTRMEM_PLUS_EXPR, "ptrmem_plus_expr", tcc_binary, 2) > DEFTREECODE (PTRMEM_REF, "ptrmem_ref", tcc_reference, 2) > > I then modify the C++ front end to instantiate the new nodes, expand > them inside expand_expr_real_1 and output_constant, and perform > folding in the various fold-const functions. So those tree expressions would live throughout the middle-end and only then become lowered to RTL directly? I'm not sure that's worthwhile. E.g. I'm not sure why there's a need to really get rid of the expand_constant langhook. It's only important that it isn't called too late, i.e. ideally during gimplification. It seems it only makes use of type information which should be available at that time, so if it currently is called too late (interfering with LTO in the future) it should be possible to move it earlier. I have a conceptual problem with moving pointer to members into the middle-end: my mental model of what the middle-end should be concerned about is complete expressions/constants/types, like adding two numbers, accessing an integer two words away from that address (i.e. you see I already sort of decompose structures in my mental model). Pointers to members is a very different beast: they can't be accessed without a real object, yet they can be stored into objects themself (sort of an incomplete memory reference). If anything they simply resemble offsets (perhaps variable ones), so you might perhaps model them as such. Conversions between them sometimes requires adjustments to 'this', resulting in real operations (the delta field of the struct, how pointer to member values are currently modelled). IMHO it would be wrong if we wouldn't make those adjustments explicit in the middle end. So, why do you think you need the PTRMEM_TYPE in the middle end? And why the PTRMEM_CST (i.e. why couldn't it be lowered to some explicit constant during gimplificaton)? Same for PTRMEM_PLUS_EXPR, why is (PTR_)PLUS_EXPR not enough, if the semantic is only to add the integer argument to the pointer argument (is that even an operation which can be done to pointers to members?)? Also PTRMEM_REF seems to equivalent to a normal COMPONENT_REF, just that the second operand is a funny "offset" specification instead of a simple field decl. > However, pointers to virtual functions are turning out to be > problematic. As far I can tell, the middle end has no concept of > virtual functions and virtual function tables: they appear to be > implemented solely in the C++ front end. This suggests that a migration > of the virtual function machinery is a necessary precondition to pointer > to member migration. Ugh, I wouldn't like that either. I have the feeling that it would drag too much specifics of C++ into the middle end. After all e.g. the virtual tables have to follow a certain layout according to the C++ ABI, which needn't be the right one for other languages. I think you need only one feature, namely given a definite class type and an offset into the vtable, what definite FUNCTION_DECL that corresponds too. I can't think of many places where you'd like to have this information, as the most interesting user of it would be the inliner. There aren't that many transformations which make a former indefinite class type definite, and most of them can be done when the C++ frontend is still around to ask. If you were to implement something like virtual functions into the middle end, it should be expressed in a fairly low level way IMHO. E.g. a virtual table simply being a vector of pointers to function decls (which we can express already just fine). That way they could also be written out for LTO and read back in, and the question what function decl is connected to what slot can also be answered trivially. Then definite class type merely has the characteristic that they can point to such a function table, whereas indefinite class types (i.e. those whose runtime type can be any derived one) can not. E.g. I wouldn't try to model the inheritance relationship. But even with that I don't really see the need for new tree nodes. Pointer to members are a fancy offset, so why not model them as such? It's obviously possible I'm missing something, in that case, please educate me where the problems are ... :-) Ciao, Michael.
Re: ICE on valid code, cse related
Hi, > Pranav, although there is indeed a bug in the mid-end here, from your point > of view the simple and effective workaround should be to implement a movdi > pattern (and movsf and movdf if you don't have them yet: it's an absolute > requirement to implement movMM for any modes you expect your machine to > handle) in the backend. This won't fix the underlying bug, but it'll stop it > from affecting you, and you'll get better codegen all round into the bargain > if you expand movdi early. It worked!!! I implemented the movsf pattern ( and also movdf so that the absence of a movdf also doesnt wont affect me in the future). Due to the movsf pattern, the return value is now restored with (insn 17 16 18 testcase-min.i:8 (set (reg:SF 139) (mem/c/i:SF (reg/f:SI 129 virtual-stack-vars) [2 S4 A32])) -1 (expr_list:REG_LIBCALL_ID (const_int 1 [0x1]) (insn_list:REG_RETVAL 14 (expr_list:REG_EQUAL (float:SF (reg:SI 138)) (nil) i.e. there is no subreg in the destination. Later in cse when the above REG_EQUAL (float:SF (reg:SI 138) note is converted into REG_EQUAL (const_double:SF 0 [0x0] 0.0 [0x0.0p+0] , It doesnt replace (subreg:SI (reg:SF 139) 0) in the insn (set (reg:SI 141) (xor:SI (subreg:SI (reg:SF 139) 0) (reg:SI 140))) 65 {xorsi3} (expr_list:REG_EQUAL (const_double:SF 0 [0x0] -0.0 [-0x0.0p+0]) (nil))) and the compiler doesnt crash :) Thanks Dave and Ian for your help!! cheers! Pranav
x86_64 ABI
with reference to the following: struct data { data (long v) : m_data (v) {} data (const data&) {} long m_data; }; data foo (data v) { return v; } my reading of the x86_64 ABI (v .98, sept 2006) on page 17 is that data should have class MEMORY when passed as argument to function foo. This because it has a non-trivial copy constructor (it is not implicitely declared). But GCC 4.1.1 and a more recent version from svn give (for foo): .globl _Z3foo4data .type _Z3foo4data, @function _Z3foo4data: .LFB8: movq%rdi, %rax ret .LFE8: [so v is passed in a register] The gimple dump (from the svn version) is: data::data(long int) (this, v) { this->m_data = v; } data::data(const data&) (this, D.2481) { } data foo(data) (v) { struct data & D.2509; D.2509 = ; __comp_ctor (D.2509, v); return ; } which seems to confirm v in a register. So the question is whether my reading of the ABI is wrong (and why). Thanks a lot and best regards, Maurizio
Fixed function compilation order
Hello everyone, I am currently trying to enable GCC to perform compilation without having to respect any compilation order, i.e. execute some pass to any function at any time (it is not only pass reordering). As what I have seen from (trunk version of) GCC, it doesn't seem an easy task to be achieved and it might traduce in many complications later in development. In that sense I would like to have some opinions and suggestions from you all: - Imagining I am able to change the function context by updating cfun, etc. Will passes (all_passes) execute without missing/wrong data, i.e. is all shared data between passes accessed/ updated thought pointers such as cfun, etc. ? - What should I initialise/finalise to be able to perform the function context change ? I would like to have your opinion and tips on how to approach it and which problems I might expect to have later. Thanks in advance, Cupertino Miranda
Re: Fixed function compilation order
On 8/8/07, Cupertino Miranda <[EMAIL PROTECTED]> wrote: > Hello everyone, > > I am currently trying to enable GCC to perform compilation without > having to respect any compilation order, i.e. execute some pass to > any function at any time (it is not only pass reordering). > > As what I have seen from (trunk version of) GCC, it doesn't seem an > easy task to be achieved and it might traduce in many complications > later in development. > In that sense I would like to have some opinions and suggestions from > you all: For tree level optimization, this is really not difficult. For RTL, this is probably going to be really hard. > > - Imagining I am able to change the function context by updating > cfun, etc. Will passes (all_passes) execute without > missing/wrong data, i.e. is all shared data between passes accessed/ > updated thought pointers such as cfun, etc. ? What do you mean "missing/wrong" data. > - What should I initialise/finalise to be able to perform the > function context change ? See any IPA pass > > I would like to have your opinion and tips on how to approach it and > which problems I might expect to have later. > > Thanks in advance, > Cupertino Miranda > >
Re: x86_64 ABI
Hi, On Wed, 8 Aug 2007, Maurizio Vitale wrote: > with reference to the following: > > struct data { > data (long v) : m_data (v) {} > data (const data&) {} > long m_data; > }; > > data foo (data v) { > return v; > } > > my reading of the x86_64 ABI (v .98, sept 2006) on page 17 is that > data should have class MEMORY when passed as argument to function foo. > This because it has a non-trivial copy constructor > (it is not implicitely declared). That is correct. > But GCC 4.1.1 and a more recent version from svn give (for foo): > > .globl _Z3foo4data > .type _Z3foo4data, @function > _Z3foo4data: > .LFB8: > movq%rdi, %rax > ret > .LFE8: That is also correct. > [so v is passed in a register] But this conclusion isn't. In short: that's the address of the return slot. Longr version: Your confusion stems from the fact, that your copy-ctor is empty (so it's code can't be seen in the asm dump), and that also your return type of 'foo' is data, which also needs to be returned by memory. Returning in memory is done by the caller allocating the place for the return value on its stack, and giving the address of that to-be-written-to place as implicit first argument to the function. That address is then also returned in %rax. So what's placed in %rdi here is not 'v' itself, but some place on it's callers stack, which is also to be returned in %rax. As you have an empty copy-ctor you also don't see any other interesting access to 'v' itself, so the asm is confusing because nothing hints at the fact that %rdi really only holds the address of the return slot. Look at some arbitrary caller of your foo function. For clarity I've also removed the empty body of of cctor, so that calls to external functions remain: data foo (data v) { return v; } void callfoo() { data d(32); foo (d); } callfoo now looks like so: Z7callfoov: pushq %rbx subq$48, %rsp leaq16(%rsp), %rbx leaq32(%rsp), %rsi movq$32, 32(%rsp) movq%rbx, %rdi call_ZN4dataC1ERKS_ movq%rsp, %rdi movq%rbx, %rsi call_Z3foo4data addq$48, %rsp popq%rbx ret You can see three objects overall allocated on the stack (%rsp,%rsp+16,%rsp+32). In particular the one at %rsp is used for the return slot for the call of 'foo'. foo itself is given the address of that return slot, and it's input argument 'd', placed in memory at %rsp+16 (initialised by the cctor from the object at %rsp+32). So it's passed and return in memory, as defined by the ABI. The passing by memory can be seen easier by actually accessing something in the object, like here: long access (data v) { return v.m_data; } That's assembled into _Z6access4data: movq(%rdi), %rax ret I.e. accessing the m_data member of 'v', which is given only as its address in %rdi, i.e. passed by memory. All as intended. Ciao, Michael.
Zdenek Dvorak appointed loop infrastructure maintainer
I am pleased to announce that the GCC Steering Committee has promoted Zdenek Dvorak to full maintainership of all of the GCC loop infrastructure. Please join me in congratulating Zdenek on his new role. Zdenek, please update your listing in the MAINTAINERS file. Happy hacking! David
Re: [RFC] Migrate pointers to members to the middle end
Michael Matz <[EMAIL PROTECTED]> writes: > If you were to implement something like virtual functions into the middle > end, it should be expressed in a fairly low level way IMHO. E.g. a > virtual table simply being a vector of pointers to function decls (which > we can express already just fine). That way they could also be written > out for LTO and read back in, and the question what function decl is > connected to what slot can also be answered trivially. Then definite > class type merely has the characteristic that they can point to such a > function table, whereas indefinite class types (i.e. those whose runtime > type can be any derived one) can not. E.g. I wouldn't try to model the > inheritance relationship. There is some advantage to knowing class heirarchy relationships in LTO. Some C++ programs implement different virtual subclasses in different files. LTO can put those together. When the compiler can then determine that a variable definitely has a particular subclass, it can devirtualize the virtual calls, turning an indirect function call into a direct function calls, also exposing inlining opportunities. I don't know how important an optimization this is, but it seems like a real one, and one which is only available if the LTO middle-end knows something about class relationships. Ian
Re: [RFC] Migrate pointers to members to the middle end
On 08 Aug 2007 17:36:43 -0700, Ian Lance Taylor <[EMAIL PROTECTED]> wrote: > Michael Matz <[EMAIL PROTECTED]> writes: > > > If you were to implement something like virtual functions into the middle > > end, it should be expressed in a fairly low level way IMHO. E.g. a > > virtual table simply being a vector of pointers to function decls (which > > we can express already just fine). That way they could also be written > > out for LTO and read back in, and the question what function decl is > > connected to what slot can also be answered trivially. Then definite > > class type merely has the characteristic that they can point to such a > > function table, whereas indefinite class types (i.e. those whose runtime > > type can be any derived one) can not. E.g. I wouldn't try to model the > > inheritance relationship. > > There is some advantage to knowing class heirarchy relationships in > LTO. Some C++ programs implement different virtual subclasses in > different files. LTO can put those together. When the compiler can > then determine that a variable definitely has a particular subclass, > it can devirtualize the virtual calls, turning an indirect function > call into a direct function calls, also exposing inlining > opportunities. > > I don't know how important an optimization this is, but it seems like > a real one, and one which is only available if the LTO middle-end > knows something about class relationships. I believe we do want to have this info in the middle end, but i don't necessarily believe what Ollie's current approach is the best one. It looks like all the code is still C++ specific, and it's semantics are only defined by how they get generated in cp/* I'd rather see us go the route of deciding what the semantics *should be*, which of these tree codes are *actually necessary*, then make cp/* gimplify it to what we've got. The semantics should also be completely documented independently of the C++ FE (even if we were decide to give the middle end codes the exact same semantics as C++) For example, I see no reason for PTRMEM_PLUS_EXPR. To put it concretely, i think the proposal has gone backwards, and worked from "we have an implementation of something in the C++ FE, let's move it to the middle end" instead of "we have a design for something we want to do in the middle end, let's make the C++ FE/gimplifier do it". It's not at all clear to me from the current proposal where/when/how these tree codes occur in the normal GIMPLE datastream, how I would handle them in points-to analysis, etc. Note that to directly adress your point, the middle end *already does* have a notion of class relationships. The BINFO_* (base class information) is already common to the middle-end. This is how the ipa-cha stuff that was submitted a while ago knows how to find base classes. Besides type-based devirt, you will also get a lot out of points-to based devirt, because it can do without the whole program, whereas type-based devirt cannot. --Dan
Re: [RFC] Migrate pointers to members to the middle end
Hi, On Thu, 8 Aug 2007, Ian Lance Taylor wrote: those whose runtime type can be any derived one) can not. E.g. I wouldn't try to model the inheritance relationship. There is some advantage to knowing class heirarchy relationships in LTO. Some C++ programs implement different virtual subclasses in different files. LTO can put those together. When the compiler can then determine that a variable definitely has a particular subclass, it can devirtualize the virtual calls, turning an indirect function call into a direct function calls, also exposing inlining opportunities. Yes, devirtualization. But I wonder if you really need class hierarchies for this (actually I'm fairly sure you don't). In effect you only need to determine where this virtual call, when you know the definite runtime type of the object pointer, points to, i.e. to which function decl. For that you don't need the class hierarchy (i.e. the edges in the inheritance graph, or in fact any information about what base classes might or might exist or about other classes), but simply a list of all slot-number -> function-decls mappings for that type, i.e. the vtable (but let's call it different to not confuse it with the C++-ABI thingy which actually is written to the .o file). As the middle end should have all thunks already also 'this' pointer adjusting virtual calls should be taken care of (i.e. the slot->function mapping should already have the thunks referenced). Then you just need a way to get from a definite type to that slot->function mapping. As the LTO frontend needs to emit something similar anyway somewhere (as it needs to express all C++ types in some lowered form appropriate for the LTO reader), it will be available somehow, presumably hanging off the RECORD_TYPE. If you have the definite runtime type of the pointer, you also have that RECORD_TYPE, hence the slot->function mapping, the slot number from the virtual call itself, and ergo the finally called function_decl. No need for hierarchies. There were also other patches already floating around which (tried to) implement devirtualization (via profile feedback testing at runtime if a pointer was of certain type), which didn't need real inheritance hierarchies in the middle-end, so it can be done. We also need to make sure to not munge together too many of these not entirely trivial topics. We have pointer to members (IMHO just fancy offsets) and virtual function calls (for devirtualization) up to now. They only relate via pointer to virtual member functions, which still are only fancy offsets (referring to a slot number, not a byte offset). So IMHO the C++ frontend should lower all these constructs as much as possible and try to express them in basic types and expressions, instead of pulling the whole hair into the middle end. If something is right now not possible in the middle-end, then we should try to carefully add the necessary information (and only that) to enable whatever we want. For devirtualization I think I pointed out one possibility. I'm not sure what else we want. Surely I've seen nothing which would make me think "hell, yes, let's pull pointer to members into the middle end, and as we are at it, let's add virtual functions right away too" ;-) Ciao, Michael. PS: From time to time I'm forced to dive into either of these areas of cp/*.[ch] and it has some very complex code. Most of it really front-end related I know, but intertwined with the code generation and layouting code. I'm fairly certain that this all should stay in cp/ .
bootstrap failure on hppa-unknown-linux-gnu
In stage2, ../../gcc/gcc/tree.c:7694: error: passing argument 1 of 'fixed_zerop' discards qualifiers from pointer target type Dave -- J. David Anglin [EMAIL PROTECTED] National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
Re: [RFC] Migrate pointers to members to the middle end
On 8/8/07, Michael Matz <[EMAIL PROTECTED]> wrote: > So those tree expressions would live throughout the middle-end and only > then become lowered to RTL directly? I'm not sure that's worthwhile. > E.g. I'm not sure why there's a need to really get rid of the > expand_constant langhook. It's only important that it isn't called too > late, i.e. ideally during gimplification. It seems it only makes use of > type information which should be available at that time, so if it > currently is called too late (interfering with LTO in the future) it > should be possible to move it earlier. You're correct. It is possible to remove the expand_constant language hook without supporting pointers to members in the middle end. In fact, I submitted such a patch back in March (http://gcc.gnu.org/ml/gcc-patches/2007-03/msg01819.html). The various follow-up emails illustrate some of the reasons why migrating pointers to members to the middle end is a good thing (at least for C++). It would have been more accurate for me to describe the language hooks removal as a jumping off point. Strictly speaking, the middle end migration is only necessary for language hook removal if the C++ maintainers won't approve my patch. :) That said, I think there is real value in moving pointers to members to the middle end. Keep reading. > I have a conceptual problem with moving pointer to members into the > middle-end: my mental model of what the middle-end should be concerned > about is complete expressions/constants/types, like adding two numbers, > accessing an integer two words away from that address (i.e. you see I > already sort of decompose structures in my mental model). Pointers to > members is a very different beast: they can't be accessed without a real > object, yet they can be stored into objects themself (sort of an > incomplete memory reference). If anything they simply resemble offsets > (perhaps variable ones), so you might perhaps model them as such. > Conversions between them sometimes requires adjustments to 'this', > resulting in real operations (the delta field of the struct, how pointer > to member values are currently modelled). IMHO it would be wrong if we > wouldn't make those adjustments explicit in the middle end. I think the primary purpose of the middle end is to provide a representation which captures the semantics of a program at a sufficiently high level to enable efficient optimization. COMPLEX_CST and COMPLEX_TYPE are a good example. In theory, the middle end has enough information to optimize complex arithmetic based solely on the constituent operations on real and imaginary components, but it's easier to deal with the complex number as an atomic unit. Similarly, consider the following code fragment: struct S { virtual void f(); }; typedef void (S::*P)(void); const P p = &S::f, NULL; void g(S s) { (s.*p)(); } GCC should be able to optimize g() to call s.S::f() directly. In theory, it can optimize out the null pointer to member check, the virtual bit check, and the vtable lookup, but that's a lot of work. Right now, GCC can't do it. > So, why do you think you need the PTRMEM_TYPE in the middle end? And why > the PTRMEM_CST (i.e. why couldn't it be lowered to some explicit constant > during gimplificaton)? Same for PTRMEM_PLUS_EXPR, why is (PTR_)PLUS_EXPR > not enough, if the semantic is only to add the integer argument to the > pointer argument (is that even an operation which can be done to pointers > to members?)? Also PTRMEM_REF seems to equivalent to a normal > COMPONENT_REF, just that the second operand is a funny "offset" > specification instead of a simple field decl. The implementation is certainly negotiable. That's part of why I sent out this email. For pointers to data members, PTRMEM_CST doesn't give much information that isn't already provided by integers of OFFSET_TYPE (It does explicitly indicate NULL pointers to members, which offsets do not. In fact, GCC currently handles NULL pointer to member casts incorrectly, as it fails to preserve NULLs). However, for pointers to member functions, it bypasses the need to decode an architecture-dependent virtual bit, and replaces the virtual function offset with FUNCTION_DECL, which means we don't need to decode vtable lookups in order to inline function calls. PTRMEM_PLUS_EXPR is supposed to represent casts (CAST_EXPR didn't seem appropriate, but I could be convinced otherwise). It expands to a conditional which propagates NULL or increments the offset. I don't think PTR_PLUS_EXPR checks for NULL, and it's designed to increment pointers. A pointer to data member expands to an offset, and a pointer to member function expands to a fairly complex structure. In fact, for some architectures, the offset field is shifted, so PTRMEM_PLUS_EXPR (p, 1), would actually have to add 2 to the offset. Take a look at the expand_ptrmemfunc_cst() and build_ptrmemfunc1() calls inside cplus_expand_constant(). Now reverse that to
Re: [RFC] Migrate pointers to members to the middle end
Ollie Wild wrote: > On 8/8/07, Michael Matz <[EMAIL PROTECTED]> wrote: Ollie, thanks for patiently trying out different approaches. > I think the primary purpose of the middle end is to provide a > representation which captures the semantics of a program at a > sufficiently high level to enable efficient optimization. COMPLEX_CST > and COMPLEX_TYPE are a good example. In theory, the middle end has > enough information to optimize complex arithmetic based solely on the > constituent operations on real and imaginary components, but it's > easier to deal with the complex number as an atomic unit. I agree. When I discussed this with Ollie, my feeling was that, yes, it's possible to express all this stuff in terms of GIMPLE (in fact, we already do, aside from PTRMEM_CST itself!), but we're essentially obfuscating information and then trying to get it back. Creating RECORD_TYPE instances to represent pointers-to-member-functions and then hoping that the middle end will scalarize the struct, fold all the tests for virtual-ness, dereference the virtual table entry, etc. seems like a lot of work to do de-virtualization. But, the information is in fact there, so I guess we could go that way. Michael and Danny have expressed opinions; does anyone else have one? Thanks, -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: [RFC] Migrate pointers to members to the middle end
On 8/8/07, Mark Mitchell <[EMAIL PROTECTED]> wrote: > Ollie Wild wrote: > > On 8/8/07, Michael Matz <[EMAIL PROTECTED]> wrote: > > Ollie, thanks for patiently trying out different approaches. > > > I think the primary purpose of the middle end is to provide a > > representation which captures the semantics of a program at a > > sufficiently high level to enable efficient optimization. COMPLEX_CST > > and COMPLEX_TYPE are a good example. In theory, the middle end has > > enough information to optimize complex arithmetic based solely on the > > constituent operations on real and imaginary components, but it's > > easier to deal with the complex number as an atomic unit. > > I agree. > > When I discussed this with Ollie, my feeling was that, yes, it's > possible to express all this stuff in terms of GIMPLE (in fact, we > already do, aside from PTRMEM_CST itself!), but we're essentially > obfuscating information and then trying to get it back. This is true of all the lowering we perform (loops->gotos, for example) > Creating > RECORD_TYPE instances to represent pointers-to-member-functions and then > hoping that the middle end will scalarize the struct, fold all the tests > for virtual-ness, dereference the virtual table entry, etc. seems like a > lot of work to do de-virtualization. > But, the information is in fact > there, so I guess we could go that way. > We have no need for scalarization to occur to perform points-to *or* type based devirtualization. Dereferencing is just a call, it is always there anyway. Folding is something we have to be doing anyway. I just don't see this as as much work as you do. Both the type-based that was posted before, and the points-to based one, are just not that large in terms of code. I also haven't necessarily said what Ollie has proposed is a bad idea. I have simply said the way he has come up with what he proposed is not the way we should go about this. It may turn out he has come up with exactly the representation we want (though I doubt this, for various reasons).The specification given also doesn't even explain where/how these operations can occur in GIMPLE, and what they do other than "a C++ something something". Also given that someone already wrote a type-based devirtualizer that worked fine, and i don't see how a points-to one is much work, I'd like to see more justification for things like PTRMEM_PLUS_EXPR than "hey, the C++ FE generates this internally". So i have no real objection to either the type or the CST, I just want to see semantics that are actually described in terms of our language independent intermediate language, not in terms "what the C++ FE does". Example: "* A pointer-to-member constant. TREE_PTRMEM_CST_MEMBER is the _DECL for the member. TREE_PTRMEM_CST_OFFSET takes on different interpretations depending on the type of the member. If the member is NULL, it is ignored. If the member is a FIELD_DECL it refers to the field offset. Otherwise, it refers to the offset of the this pointer passed to methods. */" No justification was given why there is a member and an offset, what is allowed to be the _DECL for the member, why member is allowed to be null, why member would sometimes be a FIELD_DECL, sometimes NULL, and apparently sometimes neither NULL nor a FIELD_DECL, how to find the this pointer offset refers to (only sometimes, apparently!), etc. As I said, i'm really not necessarily opposed to seeing pointer to members in the middle end, i'd just rather not see us underspecify it and just take what the C++ FE currently does as "the word of the lord". > Michael and Danny have expressed opinions; does anyone else have one? > > Thanks, > > -- > Mark Mitchell > CodeSourcery > [EMAIL PROTECTED] > (650) 331-3385 x713 >
Re: [RFC] Migrate pointers to members to the middle end
On 8/8/07, Daniel Berlin <[EMAIL PROTECTED]> wrote: > I also haven't necessarily said what Ollie has proposed is a bad idea. > I have simply said the way he has come up with what he proposed is > not the way we should go about this. It may turn out he has come up > with exactly the representation we want (though I doubt this, for > various reasons).The specification given also doesn't even explain > where/how these operations can occur in GIMPLE, and what they do other > than "a C++ something something". > > Also given that someone already wrote a type-based devirtualizer that > worked fine, and i don't see how a points-to one is much work, I'd > like to see more justification for things like PTRMEM_PLUS_EXPR than > "hey, the C++ FE generates this internally". OK. It sounds like I need to go into a lot more detail. The new nodes I've proposed aren't actually motivated by the C++ front end, but rather by a consideration of the semantics dictated by the C++ standard. Naturally, this gives rise to some similarity, but for instance, there is no PTRMEM_PLUS_EXPR in the C++ front end, and my definition of PTRMEM_CST disagrees with the current node of the same name. Let's walk through them: PTRMEM_TYPE Contains the types of the member (TREE_TYPE) and class (TYPE_PTRMEM_BASETYPE) of this pointer to member. This is hopefully self-explanatory. In the language of the C++ standard, it is the type of a "pointer to member of class TYPE_PTRMEM_BASETYPE of type TREE_TYPE." This is the type of PTRMEM_CST's, PTRMEM_PLUS_EXPR's, and various variable types (VAR_DECL, FIELD_DECL, PARM_DECL, etc.). PTRMEM_CST The C++ front end already has a PTRMEM_CST node. However, the existing node only contains a class (PTRMEM_CST_CLASS) and member (PTRMEM_CST_MEMBER), and is unable to represent an arbitrary pointer to member value. This is especially evident when dealing with multiple inheritance. Consider the following example: struct B { int f (); }; struct L : B {}; struct R : B {};; struct D : L, R {}; int (B::*pb)() = &B::f; int (L::*pl)() = pb; int (R::*pr)() = pb; int (D::*pd[2])() = { pl, pr }; In this case, pd[0] and pd[1] both have the same type and point to the same member of the same class (B::f), but they point to different base class instances of B. To represent this, we need an offset. Now, one might argue that rather than a numeric offset, we should point to the _DECL of the base class subobject, but that breaks down because the following is also legal: struct B {}; struct D : B { int f (); }; int (D::*pd)() = &D::f; int (B::*pb)() = static_cast(pd); In this case, pb points to D::f in the derived class. Since there is no subobject to point to, we see that a numeric offset representation is required. This leads to the definition of PTRMEM_CST which I have adopted. Since the class type is already provided in its type, we store the member (TREE_PTRMEM_CST_MEMBER) and numeric offset (TREE_PTRMEM_CST_OFFSET). The member is one of NULL (for NULL pointers to members), a FIELD_DECL (for non-NULL pointers to data members), or a FUNCTION_DECL (for non-NULL pointers to member functions). I've chosen the offset value according to convenience. For NULL pointers to members, it's irrelevant. For pointers to data members, it's the offset of the member relative to the current class (as determined by any type conversions). For pointers to member functions, it's the offset to the this pointer which must be passed to the function. PTRMEM_PLUS_EXPR >From the discussion above, it's clear that type conversions on pointers to members require adjustments to the offsets (to fields or this pointers). We could handle this via CONVERT_EXPRs, but that has two shortcomings: (1) it requires the middle end to compute offsets to base class subobjects, and (2) as the first code example above illustrates, multiple CONVERT_EXPRs cannot be folded together. To work around these issues, I've implemented the PTRMEM_PLUS_EXPR. It's a binary expression which takes two arguments, a PTRMEM_TYPE object, and an integral offset expression. These can be nicely constant folded, either with other PTRMEM_PLUS_EXPRs or with PTRMEM_CSTs. There's also an added benefit when dealing with NULL pointers to members. Consider the following code: struct B { int a; }; struct L : B {}; struct R : B {};; struct D : L, R {}; int B::*pb = NULL; int L::*pl = pb; int R::*pr = pb; int D::*pd[2] = { pl, pr }; The C++ standard states that pd[0] == pd[1] since all NULL pointers to members of the same type compare equal. However, the current GCC implementation gets this wrong because the C++ front end implements pointer to data member via simple addition. In practice, it needs to check for NULL first. However, folding stacked conversions then requires optimizing code like: if (d != NULL_MARKER) d += offset1; if (d != NULL_MARKER) d += offset2; if (d != NULL_MARKER) d += offset3; to if (d!= NULL_MA