On Thu, Apr 21, 2011 at 2:43 PM, Eric Christopher <span dir="ltr"><<a href="mailto:echristo@apple.com">echristo@apple.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<div class="im"><br>
On Apr 20, 2011, at 4:34 PM, Talin wrote:<br>
<br>
> Also, looking in the SVN repo, it appears that some of the files in include/llvm/ExecutionEngine have not been touched in a long time, and that scares me a bit - what's the current state of the LLVM interpreter?<br>


><br>
> Anyway, my main question to the list is - does this sound like a viable plan, or am I heading down the path of madness and frustration?<br>
><br>
<br>
</div>The current interpreter works on llvm IR, but in general invokes the JIT instead of just interpreting. I don't know that anyone has tested the interpreter path in some time, but it should largely just work. The JIT itself is undergoing a bit of rewriting for MC, but most of the idea is to leave the existing API intact if at all possible.<br>


<br>
It sounds like you're not completely lowering to llvm IR though? That you want to change that is a bit of a source of worry, what do you have in mind? I read your email, but a more concrete example would help.<br>
<br>
Thanks!<br></blockquote><div><br></div><div>Sure thing. Here's an imaginary example - say we want to implement something like LLVM's CommandLine library, only using reflection. So we'll define a class containing some variables, and annotate those variables which correspond to command-line parameters:</div>

<div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">   class CommandArgs {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">     @ProgramArgument("input", "i", "the input file")</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">     var inputFile:String;</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><meta charset="utf-8"><div>

<font class="Apple-style-span" face="'courier new', monospace">     @ProgramArgument("output", "o", "the output file")</font></div><div><font class="Apple-style-span" face="'courier new', monospace">     var outputFile:String;</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">   }</font></div><div><br></div><div>When the program starts up, we'll create an instance of CommandArgs and pass it to the argument parser. The parser looks up the reflection information for the object, and searches for members that have a ProgramArgument annotation. It then populates those member fields by mapping the input command arguments onto the annotated members.</div>

<div><br></div><div>Now, ProgramArgument is just a regular class that has a constructor that takes several arguments - in this case, the long name, short name, and help text. In fact it looks like this:</div><div><br></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  @Attribute</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  class ProgramArgument {</font></div><div>
<font class="Apple-style-span" face="'courier new', monospace">    private {</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">      let longName:String;</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      let shortName:String;</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      let helpText:String;</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="'courier new', monospace">    def construct(longName:String, shortName:String="", helpText:String="") {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      self.longName = longName;</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      self.shortName = shortName;</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      self.helpText = helpText;</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">    }</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  }</font></div><div><br></div><div>OK so when we compile the class CommandArgs, we want to save out the annotations on the class, along with the class metadata. The class metadata is made up of LLVM Constants, so the annotations need to be Constants as well.</div>

<div><br></div><div>So basically what I want to do here is to evaluate the ProgramArgument constructor in the compiler, and then convert the output into LLVM constants. The way I currently do this is that I have an interpreter inside my compiler that operates on my high-level CFG graph - given an expression tree, it can produce the result of evaluating that expression. In the case of the ProgramArgument annotation, what the evaluator gives back is a data structure that is essentially an array of 4 constants, the first being a pointer to the ProgramArgument type and the remaining 3 being the contents of the data members of class ProgramArgument. This data structure can easily be transformed into LLVM constants, and those constants inserted into the module before it is written out as a bitcode file.</div>

<div><br></div><div>However, there's a drawback to this method which is that the module now contains two versions of every function - one version in the form of LLVM IR instructions, and another version in the form of a serialized high-level CFG. It would be better if I could just store the IR and use that.</div>

<div><br></div><div>The problem with using the IR, however, is that the compiled IR code for ProgramArgument.construct() expects to see the 'self' variable pointing to a flat buffer of memory, and not an array of llvm Value* pointers. Storing the value of the Nth member field is not done by writing to the Nth element of an array, instead it is done by computing an address that is an offset from the start of the object.</div>

<div><br></div><div>Moreover, I can't serialize this buffer and add it as a constant static global, instead it has to somehow be converted back into LLVM Constants before I can do that. Bare integers need to converted back to llvm::ConstantInt, bare floats to llvm::ConstantFP, and so on. Only then can it be serialized as bitcode.</div>

<div><br></div><div>So it sounds like if I want to be able to run LLVM IR in the compiler, I'm going to have to write my own interpreter.</div></div>-- <br>-- Talin<br>