diff options
author | Chris Lattner <sabre@nondot.org> | 2009-06-30 17:10:19 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-06-30 17:10:19 +0000 |
commit | 2c6f9f7227897e0487917f454200a9d167bcda2f (patch) | |
tree | 576d5f3c6dec82db5db6d33475a0e9b6f16bba86 /docs/FAQ.html | |
parent | 5217007006e91fa4bbfe88fde5149f5db293b247 (diff) | |
download | external_llvm-2c6f9f7227897e0487917f454200a9d167bcda2f.zip external_llvm-2c6f9f7227897e0487917f454200a9d167bcda2f.tar.gz external_llvm-2c6f9f7227897e0487917f454200a9d167bcda2f.tar.bz2 |
add a FAQ.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74538 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'docs/FAQ.html')
-rw-r--r-- | docs/FAQ.html | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/docs/FAQ.html b/docs/FAQ.html index 7e15df2..1ba7123 100644 --- a/docs/FAQ.html +++ b/docs/FAQ.html @@ -124,6 +124,10 @@ <li><a href="#undef">What is this "<tt>undef</tt>" thing that shows up in my code?</a></li> + + <li><a href="#callconvwrong">Why does instcombine + simplifycfg turn + a call to a function with a mismatched calling convention into "unreachable"? + Why not make the verifier reject it?</a></li> </ol> </li> </ol> @@ -780,6 +784,143 @@ int X() { int i; return i; } value specified for it.</p> </div> +<!--=========================================================================--> + +<div class="question"> +<p><a name="callconvwrong">Why does instcombine + simplifycfg turn + a call to a function with a mismatched calling convention into "unreachable"? + Why not make the verifier reject it?</a></p> +</div> + +<div class="answer"> +<p>This is a common problem run into by authors of front-ends that are using +custom calling conventions: you need to make sure to set the right calling +convention on both the function and on each call to the function. For example, +this code:</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} +define void @bar() { + call void @foo( ) + ret void +} +</pre> + +<p>Is optimized to:</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} +define void @bar() { + unreachable +} +</pre> + +<p>... with "opt -instcombine -simplifycfg". This often bites people because +"all their code disappears". Setting the calling convention on the caller and +callee is required for indirect calls to work, so people often ask why not make +the verifier reject this sort of thing.</p> + +<p>The answer is that this code has undefined behavior, but it is not illegal. +If we made it illegal, then every transformation that could potentially create +this would have to ensure that it doesn't, and there is valid code that can +create this sort of construct (in dead code). The sorts of things that can +cause this to happen are fairly contrived, but we still need to accept them. +Here's an example:</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} +define internal void @bar(void()* %FP, i1 %cond) { + br i1 %cond, label %T, label %F +T: + call void %FP() + ret void +F: + call fastcc void %FP() + ret void +} +define void @test() { + %X = or i1 false, false + call void @bar(void()* @foo, i1 %X) + ret void +} +</pre> + +<p>In this example, "test" always passes @foo/false into bar, which ensures that + it is dynamically called with the right calling conv (thus, the code is + perfectly well defined). If you run this through the inliner, you get this + (the explicit "or" is there so that the inliner doesn't dead code eliminate + a bunch of stuff): +</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} +define void @test() { + %X = or i1 false, false + br i1 %X, label %T.i, label %F.i +T.i: + call void @foo() + br label %bar.exit +F.i: + call fastcc void @foo() + br label %bar.exit +bar.exit: + ret void +} +</pre> + +<p>Here you can see that the inlining pass made an undefined call to @foo with + the wrong calling convention. We really don't want to make the inliner have + to know about this sort of thing, so it needs to be valid code. In this case, + dead code elimination can trivially remove the undefined code. However, if %X + was an input argument to @test, the inliner would produce this: +</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} + +define void @test(i1 %X) { + br i1 %X, label %T.i, label %F.i +T.i: + call void @foo() + br label %bar.exit +F.i: + call fastcc void @foo() + br label %bar.exit +bar.exit: + ret void +} +</pre> + +<p>The interesting thing about this is that %X <em>must</em> be false for the +code to be well-defined, but no amount of dead code elimination will be able to +delete the broken call as unreachable. However, since instcombine/simplifycfg +turns the undefined call into unreachable, we end up with a branch on a +condition that goes to unreachable: a branch to unreachable can never happen, so +"-inline -instcombine -simplifycfg" is able to produce:</p> + +<pre class="doc_code"> +define fastcc void @foo() { + ret void +} +define void @test(i1 %X) { +F.i: + call fastcc void @foo() + ret void +} +</pre> + +</div> + <!-- *********************************************************************** --> <hr> |