Romanova, Katya
2015-Feb-23 21:04 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
Hello, I encountered a problem triggered by Jump-Threading optimization. This pass is creating an unreachable block with an instruction that is not well formed, which then causes the subsequent GVN pass to enter an infinite loop. I have submitted a bug report and proposed fix to llvm-commits. This bug opened a can of worms. I was asked to move the discussion to llvm-dev to reach for a wider audience.>> Can we move the general discussion to llvm-dev? This probably warrants a wider audience.Here is the original post and a couple of replies from last week: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150216/261330.html Here is a thread of replies from today: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150223/261463.html Katya. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150223/880ddf55/attachment.html>
Chandler Carruth
2015-Feb-24 04:32 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
So, first things first. Handling unreachable code is annoying. I agree. However, its important to characterize how annoying. Most code is not unreachable, and we're (obviously) fine just bailing on such crazy code paths. So in practice the common cost is keeping a local set to detect cycles in the graph where we aren't expecting them. We are essentially always traversing a linked list representing this graph. Because these linked list nodes don't have any particular reason to have high locality, we have a cache-hostile traversal where we have to do primarily local and cache friendly book-keeping at each step to catch duplication. I suspect that this has a very small (but non-zero) impact on compile time. Handling unreachable code is also error prone. We have had a long history of bugs here. So if it were free to get rid of unreachable code, that would be super awesome. The first problem to realize is that for a large chunk of LLVM, we can't actually get rid of handling unreachable code. Passes are quite likely to create unreachable code while running, and that will mean that all of the utilities will end up needing to be conservatively correct and handle unreachable code even when they don't need to. =/ The second problem is that cleaning up unreachable code isn't free. The code which is most likely to create unreachable code is similarly likely to destroy the analysis information we would use to remove it cheaply. And even then, just walking lists of basic blocks as we go out of the function is going to dirty cache lines that we might not have any other reason to look at. I can genuinely imagine cases where batching this will be beneficial. Will it outstrip the cost of handling it? I don't know. But I think it will mitigate the gains, especially if the gains aren't as significant as we might naively think. The third problem I have is that this makes it much harder to constructively produce a correct IR transformation pass. When transforming the IR we must never forget about regions we have made unreachable. A single mistake here will cascade to a verification failure. This is the reverse of the problem we have today where your pass must *accept* unreachable IR. But I think the constructive reasoning is much easier. It makes it harder to have a bug through omission of a case. The fourth problem I have is related to the third problem. How do we gain confidence in the correctness of any IR transformation? We must construct test cases that we believe will exercise the system. It seems *incredibly* easier to construct test cases with interesting unreachable IR patterns that should all be handled, than to construct test cases where the pass will happen to form unreachable IR patterns in each way and ensure that none escape the pass. One is essentially covering input diversity, the other has to cover *output* diversity, and must prove the negative. We fundamentally must gain confidence that the pass *never* produces unreachable IR. This seems much harder than demonstrating that it does handle unreachable IR. The fifth problem I have is also related to the third and fourth problems. Precluding unreachable code seems likely to make tools like delta test case reduction dramatically less effective. Now, when cutting edges in the CFG to minimize a test case they must actually build the graph and prune all unreachable code. All of these problems seem surmountable, but in aggregate, they make me strongly doubt that the benefit is worth the cost. -Chandler On Mon, Feb 23, 2015 at 1:04 PM, Romanova, Katya < Katya_Romanova at playstation.sony.com> wrote:> Hello, > > I encountered a problem triggered by Jump-Threading optimization. This > pass is creating an unreachable block with an instruction that is not well > formed, which then causes the subsequent GVN pass to enter an infinite loop. > > > > I have submitted a bug report and proposed fix to llvm-commits. This bug > opened a can of worms. I was asked to move the discussion to llvm-dev to > reach for a wider audience. > > > > >> Can we move the general discussion to llvm-dev? This probably warrants > a wider audience. > > > > Here is the original post and a couple of replies from last week: > > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150216/261330.html > > > > Here is a thread of replies from today: > > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150223/261463.html > > > > Katya. > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150223/e86f1b09/attachment.html>
Chandler Carruth
2015-Feb-24 04:38 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
On Mon, Feb 23, 2015 at 8:32 PM, Chandler Carruth <chandlerc at google.com> wrote:> Handling unreachable code is annoying. I agree. However, its important to > characterize how annoying. Most code is not unreachable, and we're > (obviously) fine just bailing on such crazy code paths. So in practice the > common cost is keeping a local set to detect cycles in the graph where we > aren't expecting them. We are essentially always traversing a linked list > representing this graph. Because these linked list nodes don't have any > particular reason to have high locality, we have a cache-hostile traversal > where we have to do primarily local and cache friendly book-keeping at each > step to catch duplication. I suspect that this has a very small (but > non-zero) impact on compile time.The other thing I meant to include here but forgot... Another reason why handling these cases has a tendency to be less expensive than you might expect is that we very often already have a set-like structure in place to remove *duplication*, and it is often very easy to re-use it to avoid cycles. So we won't be able to completely remove many of the sets you might expect to remove, they would just be narrower in scope due to not needing to handle cycles. My strong suspicion is that that narrower scope does not in fact translate to a significant efficiency gain. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150223/afefc3c7/attachment.html>
Hal Finkel
2015-Feb-24 04:45 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
----- Original Message -----> From: "Chandler Carruth" <chandlerc at google.com> > To: "Katya Romanova" <Katya_Romanova at playstation.sony.com>, "Nick Lewycky" <nlewycky at google.com> > Cc: llvmdev at cs.uiuc.edu, "Philip Reames" <listmail at philipreames.com>, "Hal Finkel" <hfinkel at anl.gov>, "Rafael > Espindola" <rafael_espindola at playstation.sony.com>, "Sanjoy Das" <sanjoy at playingwithpointers.com>, "David Majnemer" > <david.majnemer at gmail.com> > Sent: Monday, February 23, 2015 10:32:30 PM > Subject: Re: Jump Theading/GVN bug - moving discussion to llvm-dev > > > So, first things first. > > > Handling unreachable code is annoying. I agree. However, its > important to characterize how annoying. Most code is not > unreachable, and we're (obviously) fine just bailing on such crazy > code paths. So in practice the common cost is keeping a local set to > detect cycles in the graph where we aren't expecting them. We are > essentially always traversing a linked list representing this graph. > Because these linked list nodes don't have any particular reason to > have high locality, we have a cache-hostile traversal where we have > to do primarily local and cache friendly book-keeping at each step > to catch duplication. I suspect that this has a very small (but > non-zero) impact on compile time. > > > Handling unreachable code is also error prone. We have had a long > history of bugs here. So if it were free to get rid of unreachable > code, that would be super awesome. > > > > > The first problem to realize is that for a large chunk of LLVM, we > can't actually get rid of handling unreachable code. Passes are > quite likely to create unreachable code while running, and that will > mean that all of the utilities will end up needing to be > conservatively correct and handle unreachable code even when they > don't need to. =/ > > > > > The second problem is that cleaning up unreachable code isn't free. > The code which is most likely to create unreachable code is > similarly likely to destroy the analysis information we would use to > remove it cheaply. And even then, just walking lists of basic blocks > as we go out of the function is going to dirty cache lines that we > might not have any other reason to look at. I can genuinely imagine > cases where batching this will be beneficial. Will it outstrip the > cost of handling it? I don't know. But I think it will mitigate the > gains, especially if the gains aren't as significant as we might > naively think. > > > > > The third problem I have is that this makes it much harder to > constructively produce a correct IR transformation pass. When > transforming the IR we must never forget about regions we have made > unreachable. A single mistake here will cascade to a verification > failure. This is the reverse of the problem we have today where your > pass must *accept* unreachable IR. But I think the constructive > reasoning is much easier. It makes it harder to have a bug through > omission of a case. > > > > > The fourth problem I have is related to the third problem. How do we > gain confidence in the correctness of any IR transformation? We must > construct test cases that we believe will exercise the system. It > seems *incredibly* easier to construct test cases with interesting > unreachable IR patterns that should all be handled, than to > construct test cases where the pass will happen to form unreachable > IR patterns in each way and ensure that none escape the pass. One is > essentially covering input diversity, the other has to cover > *output* diversity, and must prove the negative. We fundamentally > must gain confidence that the pass *never* produces unreachable IR. > This seems much harder than demonstrating that it does handle > unreachable IR. > > > > > The fifth problem I have is also related to the third and fourth > problems. Precluding unreachable code seems likely to make tools > like delta test case reduction dramatically less effective. Now, > when cutting edges in the CFG to minimize a test case they must > actually build the graph and prune all unreachable code. > > All of these problems seem surmountable, but in aggregate, they make > me strongly doubt that the benefit is worth the cost.I don't disagree with this, but I think there are two (separable) issues here: 1. Should transformations produce unreachable code? On the face of it, they must be able to, because the problem of determining dynamic reachability is generally undecidable. Should passes produce trivially dead code? Well, probably not if they avoid it. Even this is not locally decidable, and so you're right, removing it will add extra expense (but also provide savings, so we'd need to experiment). 2. Should unreachable code be allowed to contain nonsense (like instructions that depend on themselves)? To this, I believe the answer is no. We currently permit this, and I think that a lot of the bugs regarding unreachable code some from this. I've yet to hear a good argument why, for example, JumpThreading must produce self-referential instructions in trivially-dead regions. -Hal> > > -Chandler > > > > On Mon, Feb 23, 2015 at 1:04 PM, Romanova, Katya < > Katya_Romanova at playstation.sony.com > wrote: > > > > > > > Hello, > > I encountered a problem triggered by Jump-Threading optimization. > This pass is creating an unreachable block with an instruction that > is not well formed, which then causes the subsequent GVN pass to > enter an infinite loop. > > > > I have submitted a bug report and proposed fix to llvm-commits. This > bug opened a can of worms. I was asked to move the discussion to > llvm-dev to reach for a wider audience. > > > > >> Can we move the general discussion to llvm-dev? This probably > >> warrants a wider audience. > > > > Here is the original post and a couple of replies from last week: > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150216/261330.html > > > > Here is a thread of replies from today: > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150223/261463.html > > > > Katya. > > >-- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory
Sanjoy Das
2015-Feb-24 04:56 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
> Handling unreachable code is annoying. I agree. However, its important to > characterize how annoying. Most code is not unreachable, and we're > (obviously) fine just bailing on such crazy code paths. So in practice the > common cost is keeping a local set to detect cycles in the graph where we > aren't expecting them. We are essentially always traversing a linked list > representing this graph. Because these linked list nodes don't have any > particular reason to have high locality, we have a cache-hostile traversal > where we have to do primarily local and cache friendly book-keeping at each > step to catch duplication. I suspect that this has a very small (but > non-zero) impact on compile time.Why not have an analysis pass that does a DFS starting from the entry block? Is that likely to be very costly? Having an analysis pass is attractive because that allows some transformation passes to put in some extra work to preserve it if they so desire. The analysis pass does not have to be clever at all, since the verifier (rightly, I think) considers a block reachable even if it is predicated on a literal false -- the following IR does not verify: define void @f() { entry: br i1 false, label %t, label %f t: ret void f: %m = add i32 %m, 1 ret void } -- Sanjoy
Daniel Berlin
2015-Feb-24 06:02 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
On Mon, Feb 23, 2015 at 8:32 PM, Chandler Carruth <chandlerc at google.com> wrote:> So, first things first. > > Handling unreachable code is annoying. I agree. However, its important to > characterize how annoying. Most code is not unreachable, and we're > (obviously) fine just bailing on such crazy code paths. So in practice the > common cost is keeping a local set to detect cycles in the graph where we > aren't expecting them. We are essentially always traversing a linked list > representing this graph. Because these linked list nodes don't have any > particular reason to have high locality, we have a cache-hostile traversal > where we have to do primarily local and cache friendly book-keeping at each > step to catch duplication. I suspect that this has a very small (but > non-zero) impact on compile time. > >So it's worse than this. It also means that doing something like "walk the graph" is no longer sufficient to generate correct code. It's not just about cycles. Let's take an example: PromoteMemoryToRegisters has a rename pass. This rename pass walks blocks from entry, following successors, renaming values to use the nearest definition. After this is done, it's done. Except, it isn't. Because you see, then it has to go and see whether it missed some alloca's, because they were unreachable. And then it has to go and see if any of the blocks ended up with phi nodes that have predecessors that are unreachable, , because it has to replace those with undef. And so on. (It actually turns out this is not enough, and this handling is buggy).> Handling unreachable code is also error prone. We have had a long history > of bugs here. So if it were free to get rid of unreachable code, that would > be super awesome. > > > The first problem to realize is that for a large chunk of LLVM, we can't > actually get rid of handling unreachable code. Passes are quite likely to > create unreachable code while running >Which passes, exactly? I am going to assert, based on experience writing almost all of the opt passes llvm has (except a vectorizer :P), that it is entirely possible, and not even difficult, to avoid creating unreachable code in these passes. I'm also going to point out that *roughly all the other compilers in the world* do not allow it either :) Or at least, not have it at the point at which you need to call a utility or another pass. So i would say your assertion that things are quite likely to create it is wrong. Things may temporarily create it, but there is simply no need, at all, to expose it to *anything else*. , and that will mean that all of the utilities will end up needing to be> conservatively correct and handle unreachable code even when they don't > need to. =/ >So i strongly disagree with this. This is an assertion based on the way the world is now, where things willy-nilly create unreachable code and expect the rest of the world to deal with it. I don't believe it is even that difficult to get to a world where this isn't treat.> > The second problem is that cleaning up unreachable code isn't free. The > code which is most likely to create unreachable code is similarly likely to > destroy the analysis information we would use to remove it cheaply. >I disbelieve this :)> And even then, just walking lists of basic blocks as we go out of the > function is going to dirty cache lines that we might not have any other > reason to look at. I can genuinely imagine cases where batching this will > be beneficial. Will it outstrip the cost of handling it? I don't know. But > I think it will mitigate the gains, especially if the gains aren't as > significant as we might naively think. > > > The third problem I have is that this makes it much harder to > constructively produce a correct IR transformation pass. When transforming > the IR we must never forget about regions we have made unreachable. >Almost all algorithms i can think of already expect to have to clean up unreachable regions and delete dead blocks. It's only LLVM that doesn't do it.> A single mistake here will cascade to a verification failure. This is the > reverse of the problem we have today where your pass must *accept* > unreachable IR. >But is also *much* easier to verify, because the number of points in which predecessors are modified, or edges redirected, is actually not that large. At worst, *those* are the only places that can create forward-unreachable code. So you have some bounded test test. On the other hand, accepting "whatever input" is not a bounded problem. People can come up with crazier and crazier input you must accept.> But I think the constructive reasoning is much easier. It makes it harder > to have a bug through omission of a case. > > > The fourth problem I have is related to the third problem. How do we gain > confidence in the correctness of any IR transformation? We must construct > test cases that we believe will exercise the system. It seems *incredibly* > easier to construct test cases with interesting unreachable IR patterns > that should all be handled, than to construct test cases where the pass > will happen to form unreachable IR patterns in each way and ensure that > none escape the pass. >I fundamentally do not understand why you believe this. The number of places that create unreachable code is finite, bounded, and testable. You cannot create unreachable code out of magic. You are right that it is easier to create test cases ith interesting unreachable IR patterns, but there is an infinite number of them.> One is essentially covering input diversity, the other has to cover > *output* diversity, and must prove the negative. We fundamentally must gain > confidence that the pass *never* produces unreachable IR. This seems much > harder than demonstrating that it does handle unreachable IR. > > > The fifth problem I have is also related to the third and fourth problems. > Precluding unreachable code seems likely to make tools like delta test case > reduction dramatically less effective. Now, when cutting edges in the CFG > to minimize a test case they must actually build the graph and prune all > unreachable code. >Again, this is just "not hard". All the other compilers in the world do this, and do it cheaply.> >> > All of these problems seem surmountable, but in aggregate, they make me > strongly doubt that the benefit is worth the cost. > > -Chandler > > > > > On Mon, Feb 23, 2015 at 1:04 PM, Romanova, Katya < > Katya_Romanova at playstation.sony.com> wrote: > >> Hello, >> >> I encountered a problem triggered by Jump-Threading optimization. This >> pass is creating an unreachable block with an instruction that is not well >> formed, which then causes the subsequent GVN pass to enter an infinite loop. >> >> >> >> I have submitted a bug report and proposed fix to llvm-commits. This bug >> opened a can of worms. I was asked to move the discussion to llvm-dev to >> reach for a wider audience. >> >> >> >> >> Can we move the general discussion to llvm-dev? This probably >> warrants a wider audience. >> >> >> >> Here is the original post and a couple of replies from last week: >> >> >> http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150216/261330.html >> >> >> >> Here is a thread of replies from today: >> >> >> http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150223/261463.html >> >> >> >> Katya. >> >> >> > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150223/266352b2/attachment.html>
Philip Reames
2015-Feb-24 18:45 UTC
[LLVMdev] Jump Theading/GVN bug - moving discussion to llvm-dev
Whatever we end up deciding, I think we do need to preserve the ability of a language frontend to generate complete garbage in the form of unreachable code. If we decide to move in the direction of disallowing the production of unreachable code, we need to write a canonicalization pass that runs first thing in the pipeline. A frontend should be able to produce unreachable code. This enables important simplifications in the frontend. I happen to agree with Chandler, but I don't have a strong opinion either way. His testing point in particular is one that resonates with me. I'll, in practice, take testability over verification any day. :) Sanjoy's suggestion of having an "unreachable code analysis" might be a way to split the difference. Every pass could depend on it. If it doesn't report "no unreachable code", the pass calls a cleanup transform utility. Any pass that wanted to spend time to "preserve" the analysis (by making sure there was no unreachable code), could do so. Everything would "just work". Do we have a set of unreachable, but otherwise valid, code examples? It doesn't seem to hard to write extra run lines for each pass. The corpus of valid but problematic examples should be common to all passes. Philip On 02/23/2015 08:32 PM, Chandler Carruth wrote:> So, first things first. > > Handling unreachable code is annoying. I agree. However, its important > to characterize how annoying. Most code is not unreachable, and we're > (obviously) fine just bailing on such crazy code paths. So in practice > the common cost is keeping a local set to detect cycles in the graph > where we aren't expecting them. We are essentially always traversing a > linked list representing this graph. Because these linked list nodes > don't have any particular reason to have high locality, we have a > cache-hostile traversal where we have to do primarily local and cache > friendly book-keeping at each step to catch duplication. I suspect > that this has a very small (but non-zero) impact on compile time. > > Handling unreachable code is also error prone. We have had a long > history of bugs here. So if it were free to get rid of unreachable > code, that would be super awesome. > > > The first problem to realize is that for a large chunk of LLVM, we > can't actually get rid of handling unreachable code. Passes are quite > likely to create unreachable code while running, and that will mean > that all of the utilities will end up needing to be conservatively > correct and handle unreachable code even when they don't need to. =/ > > > The second problem is that cleaning up unreachable code isn't free. > The code which is most likely to create unreachable code is similarly > likely to destroy the analysis information we would use to remove it > cheaply. And even then, just walking lists of basic blocks as we go > out of the function is going to dirty cache lines that we might not > have any other reason to look at. I can genuinely imagine cases where > batching this will be beneficial. Will it outstrip the cost of > handling it? I don't know. But I think it will mitigate the gains, > especially if the gains aren't as significant as we might naively think. > > > The third problem I have is that this makes it much harder to > constructively produce a correct IR transformation pass. When > transforming the IR we must never forget about regions we have made > unreachable. A single mistake here will cascade to a verification > failure. This is the reverse of the problem we have today where your > pass must *accept* unreachable IR. But I think the constructive > reasoning is much easier. It makes it harder to have a bug through > omission of a case. > > > The fourth problem I have is related to the third problem. How do we > gain confidence in the correctness of any IR transformation? We must > construct test cases that we believe will exercise the system. It > seems *incredibly* easier to construct test cases with interesting > unreachable IR patterns that should all be handled, than to construct > test cases where the pass will happen to form unreachable IR patterns > in each way and ensure that none escape the pass. One is essentially > covering input diversity, the other has to cover *output* diversity, > and must prove the negative. We fundamentally must gain confidence > that the pass *never* produces unreachable IR. This seems much harder > than demonstrating that it does handle unreachable IR. > > > The fifth problem I have is also related to the third and fourth > problems. Precluding unreachable code seems likely to make tools like > delta test case reduction dramatically less effective. Now, when > cutting edges in the CFG to minimize a test case they must actually > build the graph and prune all unreachable code. > > > All of these problems seem surmountable, but in aggregate, they make > me strongly doubt that the benefit is worth the cost. > > -Chandler > > > > > On Mon, Feb 23, 2015 at 1:04 PM, Romanova, Katya > <Katya_Romanova at playstation.sony.com > <mailto:Katya_Romanova at playstation.sony.com>> wrote: > > Hello, > > I encountered a problem triggered by Jump-Threading optimization. > This pass is creating an unreachable block with an instruction > that is not well formed, which then causes the subsequent GVN pass > to enter an infinite loop. > > I have submitted a bug report and proposed fix to llvm-commits. > This bug opened a can of worms. I was asked to move the discussion > to llvm-dev to reach for a wider audience. > > >> Can we move the general discussion to llvm-dev? This probably > warrants a wider audience. > > Here is the original post and a couple of replies from last week: > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150216/261330.html > > Here is a thread of replies from today: > > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150223/261463.html > > Katya. > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150224/f9a40877/attachment.html>