On Wed, Oct 13, 2010 at 12:45 AM, Nick Lewycky <nicholas at mxc.ca> wrote:> Kenneth Uildriks wrote: >>> >>> You're right, I hadn't thought this through. The whole point of making >>> them >>> local is to say that "I'm sure these callees won't modify that memory" >>> regardless of what functions actually get called, even indirectly. We >>> can't >>> know that they won't modify the vptr in advance, so invariant doesn't >>> work >>> here. Making it non-local just means that we would need to know the >>> static >>> call graph, which we don't because we haven't devirtualized yet so all >>> the >>> calls are indirect. >>> Nick >> >> So that means you're now saying that llvm.invariant.end ought to be >> left the way it is, right? > > I have no idea how to make use of llvm.invariant to help devirtualization. > If no use or other use case for them can be found, maybe they should be > removed.Apply invariant to the vtpr as long as the corresponding instance pointer is in use within a function. With an invariant vtpr (and better invariant support, and a front-end that uses it), devirtualization happens more or less automatically with -std-compile-opts. Do the same wherever an instance pointer is passed. Mark its corresponding vtpr invariant from the beginning of the entry block until right after the last use of the instance pointer. Then a few simple improvements to inlining & partial specialization will give you some interprocedural devirtualization. Anyway, you convinced me a few messages ago that invariant.end really should be left the way it is. Especially since assuming invariance hasn't ended when it has is unsafe... we *must* be able to match an invariance start to its corresponding invariance end in all cases.
On Oct 13, 2010, at 4:35 AM, Kenneth Uildriks wrote:> On Wed, Oct 13, 2010 at 12:45 AM, Nick Lewycky <nicholas at mxc.ca> wrote: >> Kenneth Uildriks wrote: >>>> >>>> You're right, I hadn't thought this through. The whole point of making >>>> them >>>> local is to say that "I'm sure these callees won't modify that memory" >>>> regardless of what functions actually get called, even indirectly. We >>>> can't >>>> know that they won't modify the vptr in advance, so invariant doesn't >>>> work >>>> here. Making it non-local just means that we would need to know the >>>> static >>>> call graph, which we don't because we haven't devirtualized yet so all >>>> the >>>> calls are indirect. >>>> Nick >>> >>> So that means you're now saying that llvm.invariant.end ought to be >>> left the way it is, right? >> >> I have no idea how to make use of llvm.invariant to help devirtualization. >> If no use or other use case for them can be found, maybe they should be >> removed. > > Apply invariant to the vtpr as long as the corresponding instance > pointer is in use within a function. With an invariant vtpr (and > better invariant support, and a front-end that uses it), > devirtualization happens more or less automatically with > -std-compile-opts.Even if this works, it still requires us to inline the constructor to do any good. And as long as llvm.invariant is defined in terms of memory (in C++ standards parlance, "storage"), it won't work, because the language doesn't actually guarantee that the memory is invariant. John.
On Wed, Oct 13, 2010 at 6:49 PM, John McCall <rjmccall at apple.com> wrote:> > On Oct 13, 2010, at 4:35 AM, Kenneth Uildriks wrote: > >> On Wed, Oct 13, 2010 at 12:45 AM, Nick Lewycky <nicholas at mxc.ca> wrote: >>> Kenneth Uildriks wrote: >>>>> >>>>> You're right, I hadn't thought this through. The whole point of making >>>>> them >>>>> local is to say that "I'm sure these callees won't modify that memory" >>>>> regardless of what functions actually get called, even indirectly. We >>>>> can't >>>>> know that they won't modify the vptr in advance, so invariant doesn't >>>>> work >>>>> here. Making it non-local just means that we would need to know the >>>>> static >>>>> call graph, which we don't because we haven't devirtualized yet so all >>>>> the >>>>> calls are indirect. >>>>> Nick >>>> >>>> So that means you're now saying that llvm.invariant.end ought to be >>>> left the way it is, right? >>> >>> I have no idea how to make use of llvm.invariant to help devirtualization. >>> If no use or other use case for them can be found, maybe they should be >>> removed. >> >> Apply invariant to the vtpr as long as the corresponding instance >> pointer is in use within a function. With an invariant vtpr (and >> better invariant support, and a front-end that uses it), >> devirtualization happens more or less automatically with >> -std-compile-opts. > > Even if this works, it still requires us to inline the constructor to do any good. > And as long as llvm.invariant is defined in terms of memory (in C++ standards > parlance, "storage"), it won't work, because the language doesn't actually > guarantee that the memory is invariant. > > John.But I believe the language does allow "undefined behavior" if there's a use of pT when the pointed-to object isn't actually of type T. It's an invalid use in that case, right?
Kenneth Uildriks wrote:> On Wed, Oct 13, 2010 at 12:45 AM, Nick Lewycky<nicholas at mxc.ca> wrote: >> Kenneth Uildriks wrote: >>>> >>>> You're right, I hadn't thought this through. The whole point of making >>>> them >>>> local is to say that "I'm sure these callees won't modify that memory" >>>> regardless of what functions actually get called, even indirectly. We >>>> can't >>>> know that they won't modify the vptr in advance, so invariant doesn't >>>> work >>>> here. Making it non-local just means that we would need to know the >>>> static >>>> call graph, which we don't because we haven't devirtualized yet so all >>>> the >>>> calls are indirect. >>>> Nick >>> >>> So that means you're now saying that llvm.invariant.end ought to be >>> left the way it is, right? >> >> I have no idea how to make use of llvm.invariant to help devirtualization. >> If no use or other use case for them can be found, maybe they should be >> removed. > > Apply invariant to the vtpr as long as the corresponding instance > pointer is in use within a function. With an invariant vtpr (and > better invariant support, and a front-end that uses it), > devirtualization happens more or less automatically with > -std-compile-opts.That's not valid. Each function called through the pointer could change the vptr. Yes, you can do this in a defined way in C++, for example, by calling the destructor and then placement-new'ing an object of a derived type with the same size in its place. Nick> > Do the same wherever an instance pointer is passed. Mark its > corresponding vtpr invariant from the beginning of the entry block > until right after the last use of the instance pointer. Then a few > simple improvements to inlining& partial specialization will give you > some interprocedural devirtualization. > > Anyway, you convinced me a few messages ago that invariant.end really > should be left the way it is. Especially since assuming invariance > hasn't ended when it has is unsafe... we *must* be able to match an > invariance start to its corresponding invariance end in all cases. >
On Wed, Oct 13, 2010 at 11:16 PM, Nick Lewycky <nicholas at mxc.ca> wrote:> Kenneth Uildriks wrote: >> >> On Wed, Oct 13, 2010 at 12:45 AM, Nick Lewycky<nicholas at mxc.ca> wrote: >>> >>> Kenneth Uildriks wrote: >>>>> >>>>> You're right, I hadn't thought this through. The whole point of making >>>>> them >>>>> local is to say that "I'm sure these callees won't modify that memory" >>>>> regardless of what functions actually get called, even indirectly. We >>>>> can't >>>>> know that they won't modify the vptr in advance, so invariant doesn't >>>>> work >>>>> here. Making it non-local just means that we would need to know the >>>>> static >>>>> call graph, which we don't because we haven't devirtualized yet so all >>>>> the >>>>> calls are indirect. >>>>> Nick >>>> >>>> So that means you're now saying that llvm.invariant.end ought to be >>>> left the way it is, right? >>> >>> I have no idea how to make use of llvm.invariant to help >>> devirtualization. >>> If no use or other use case for them can be found, maybe they should be >>> removed. >> >> Apply invariant to the vtpr as long as the corresponding instance >> pointer is in use within a function. With an invariant vtpr (and >> better invariant support, and a front-end that uses it), >> devirtualization happens more or less automatically with >> -std-compile-opts. > > That's not valid. Each function called through the pointer could change the > vptr. Yes, you can do this in a defined way in C++, for example, by calling > the destructor and then placement-new'ing an object of a derived type with > the same size in its place. > > NickBut unless you placement-new'd an object of the exact same type in its place, you're not allowed to use the original pointer to make any more virtual calls on it. At least that's how I understand John's message from a few days ago.