Hi guys,<div><br></div><div>I have begun a modification to the invoke/unwind instructions. The following .ll file demonstrates the change.</div><div><font class="Apple-style-span" face="'courier new', monospace"><br>
</font></div><div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">define</font></font><font class="Apple-style-span" face="'courier new', monospace"> </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">@v(</font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%o) {</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%r = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">icmp eq</font></font><font class="Apple-style-span" face="'courier new', monospace"> </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%o, </font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">0</font></font></div>
<div><span class="Apple-tab-span" style="white-space: pre; "><font class="Apple-style-span" face="'courier new', monospace">  </font></span></div><div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>br </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i1 </font></font><font class="Apple-style-span" face="'courier new', monospace">%r, </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%raise, </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%ok</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">ok:</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%m = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">mul </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%o, </font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">2</font></font></div>
<div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>ret </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%m</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">raise:</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%ex = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">inttoptr </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">255</font></font><font class="Apple-style-span" face="'courier new', monospace"> </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">to </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i8 </font></font><font class="Apple-style-span" face="'courier new', monospace">*</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><span class="Apple-style-span" style="color: rgb(0, 102, 0); "><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>; unwind now takes an i8* "exception" pointer</font></span></div>
<div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>unwind </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i8</font></font><font class="Apple-style-span" face="'courier new', monospace">* %ex</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">}</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">define </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">@g(</font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%o) {</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">entry:</font></div><div><font class="Apple-style-span" color="#006600"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>; invoke produces a different value depending on whether if</font></font></div>
<div><font class="Apple-style-span" color="#006600"><span class="Apple-style-span" style="color: rgb(0, 0, 0); "><font class="Apple-style-span" color="#006600"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>; </font></font></span></font><span class="Apple-style-span" style="color: rgb(0, 102, 0); "><font class="Apple-style-span" face="'courier new', monospace">branches to the success case or the failure case.</font></span></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%s = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">invoke </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">@v(</font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%o) </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">to </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%ok</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">                  </span> </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">unwind </font></font><font class="Apple-style-span" face="'courier new', monospace">%x </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">to </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%catch</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">ok:</font></div><div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>ret </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%s</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">catch:</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%v = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">ptrtoint </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i8 </font></font><font class="Apple-style-span" face="'courier new', monospace">* %x </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">to </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32</font></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="white-space: pre; ">  </span>%r = </font><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace">icmp eq </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" face="'courier new', monospace">%v, </font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">255</font></font></div>
<div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>br </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i1 </font></font><font class="Apple-style-span" face="'courier new', monospace">%r, </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%bad, </font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">label </font></font><font class="Apple-style-span" face="'courier new', monospace">%worse</font></div>
<div><span class="Apple-tab-span" style="white-space: pre; "><font class="Apple-style-span" face="'courier new', monospace">  </font></span></div><div><font class="Apple-style-span" face="'courier new', monospace">bad:</font></div>
<div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>ret </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">-1</font></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">worse:</font></div><div><font class="Apple-style-span" color="#3333FF"><font class="Apple-style-span" face="'courier new', monospace"><font class="Apple-style-span" color="#000000"><span class="Apple-style-span" style="white-space: pre; ">  </span></font>ret </font></font><font class="Apple-style-span" color="#993399"><font class="Apple-style-span" face="'courier new', monospace">i32 </font></font><font class="Apple-style-span" color="#993300"><font class="Apple-style-span" face="'courier new', monospace">-2</font></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">}</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">With my current change, the unwind instruction is able to pass a value to the unwind branch of the invoke instruction. I was able to coax LLVM into generating correct code for this using the LowerInvoke pass generating expensive but correct code via setjmp/longjmp.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">The unwind instruction now takes a single i8* parameter. This value is propagated to the nearest invoke instruction that generated the call to the function containing the unwind instruction.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">The invoke instruction now generated one of two different values depending on how the call exits. If the call exits via a return instruction, the invoke instruction generates a return value (denoted by %s in the sample code). If the call exits via an unwind instruction, the invoke generates an exception value (denoted by %x in the sample code). The return value is only valid if the invoke branches to the return branch. The exception value is only valid if the invoke instruction branches to the unwind branch.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">For sources that are not attempting to integrate into a third parting exception handling mechanism (gcc, or SEH), this would be enough to implement exception handling. When integrating into external exception handling mechanisms, the "exception" value generated from the invoke instruction would replace the call the 'eh.exception' intrinsic, and would have the benefit of making it much easier for analysis passes to associate this value with the invoke that generated it. For the unwind, if all thats needed is an exception pointer than an unwind instruction could be used, and lowered to the appropriate runtime library.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">To make this work, the fundamental concept that an instruction always produces a single value needs to change. This concept was already somewhat violated by the invoke instruction since if it branched to the unwind block, the return value was not actually generated. But in its existing form, it looks like it only generates one value. As far as SSA is concerned, I don't see any problem with an operation generating multiple values under different circumstances since there is still only one source for any value. As long as the block being branched to dominates any usage of the respective value I think its correct and optimizations should be able to perform correctly.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">Unfortunately, the fact that a value and the instruction that generates it are one and the same makes it very difficult to generate a representation where a single instruction can generate more that one value. My current solution (which feels wrong) is to have the invoke instruction own an additional "exception" value that represents the value that is generated when continuing via the unwind branch. This value is quite different from other values and therefore inherits directly from llvm::Value. When lowering the invoke instruction the LowerInvoke pass replaces usage of this "exception" value with the return value of the setjmp call after is has been determined that the setjmp returned from a longjmp. </font><span class="Apple-style-span" style="font-family: arial, helvetica, sans-serif; ">When lowering the unwind instruction the LowerInvoke pass puts the argument to the unwind instruction as the value parameter to the longjmp call.</span></div>
<div><span class="Apple-style-span" style="font-family: arial, helvetica, sans-serif; "><br></span></div><div><span class="Apple-style-span" style="font-family: arial, helvetica, sans-serif; ">While the lowering of this representation seemed natural, parsing it has proven difficult. This "exception" value must be in the functions symbol table, but in the current structure of the parser, the name of the instructions value is not and cannot be set until after it has been added to the containing basic block. The problem is that at that point, the parser doesn't know that the instruction produces another value, and even if it did, it has lost the needed information to properly register the name with the symbol table. To get past this point, I put a nasty hack in place. I gave LLParser permission to see the internals of instruction so I could temporarily assign the invoke instructions parent pointer ahead of time so that the call to setName on the "exception" value could succeed. Once this value is in the symbol table, there is currently no way to get it out. The code that removes an Instruction's entry from the symbol table is unaware of the additional value that needs to be removed. This causes a seemingly benign assertion at shutdown about the symbol table not being empty.</span></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">Bitcode I/O is also another problem, in my current build, it is broken. There is currently no way to bind to the "exception" value of the invoke instruction. I have yet to look into this in any way as it was not needed to get my sample code through to the code generator.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">In closing, I am looking for some feedback as the whether this approach makes sense. I would also like to know if anyone has any suggestions on how to deal with some of the issues. I have included a patch with the changes I have made so far. It is still very rough but I though it might be usefull.</font></div>
<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">-Nathan</font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br>
</font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br>
</font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br>
</font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br>
</font></div>