<p dir="auto">I was tracking down an issue in my <a href="https://github.com/tpapp/julia-repl/issues/2" data-hovercard-type="issue" data-hovercard-url="/tpapp/julia-repl/issues/2/hovercard">Emacs-based Julia REPL</a>, which uses Emacs's <code class="notranslate">ansi-term</code>. The issue was that <code class="notranslate">Base.Terminals.cmove_col</code> <a href="https://github.com/JuliaLang/julia/blob/master/base/Terminals.jl#L116">emits</a> <code class="notranslate">\E[$(n)G</code>, which <code class="notranslate">ansi-term</code> did not know how to deal with. Apparently this concrete issue will be fixed with the next Emacs release, but strictly speaking <code class="notranslate">ansi-term</code> was behaving correctly, because its <code class="notranslate">terminfo</code> entry did not report supporting <code class="notranslate">CHA</code> (Cursor Horizontal Absolute), so the Julia REPL should not have used it.</p>
<p dir="auto">I don't know what the right approach would be to replace hardcoded sequences. For a fully general solution, one could parse <code class="notranslate">terminfo</code>, and then emit escape sequences accordingly, emulating missing ones, but that involves a lot of tedious work duplicated in eg <code class="notranslate">ncurses</code>, OTOH that using the latter would be overkill.</p>
<p dir="auto">I'm using <code class="notranslate">llvmcall</code> to hook-up certain intrinsics to Julia, but ran into the issue that intrinsics need to be declared, and this is currently not supported (for example, see <a href="https://groups.google.com/forum/#!topic/julia-dev/X0k-AErZBYk" rel="nofollow">this thread</a>). I have two possible solutions for this problem, but I'd like some feedback before cleaning it up and sending a PR.</p>
<p dir="auto">My first idea was to do as <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Keno/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Keno">@Keno</a> proposed, automatically adding declarations for intrinsics. This proved messy, because I could not find a way to use the existing LLVM parsing machinery because of the missing declarations immediately aborting the parser/lexer. Duplicating this functionality seems hopeless, especially for complex declarations (<code class="notranslate">addrspace</code> annotations, function pointers, ...). Anyway,  for very simple declarations it looked like this:</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Parse identifiers in the assembly
llvm::StringRef irstring(jl_string_data(ir));
llvm::SmallVector&lt;StringRef, 2&gt; Matches;
llvm::Regex re(&quot;[a-zA-Z_0-9]+ @[a-zA-Z$._][a-zA-Z$._0-9]*&quot;);
if (re.match(irstring, &amp;Matches)) {
    for (llvm::SmallVector&lt;StringRef, 2&gt;::const_iterator MI =
        Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
             std::pair&lt;llvm::StringRef, llvm::StringRef&gt; Identifier =
                 MI-&gt;split(' ');
             llvm::Type *T =
                 llvm::StringSwitch&lt;llvm::Type*&gt;(Identifier.first)
                     .Case(&quot;i32&quot;, Type::getInt32Ty(getGlobalContext()))
                     .Case(&quot;float&quot;, Type::getFloatTy(getGlobalContext()))
                     .Case(&quot;double&quot;, Type::getDoubleTy(getGlobalContext()))
                     .Default(NULL);
             if (T == NULL)
                 jl_error(&quot;Unknown type in LLVM assembly&quot;);
             parent_Module-&gt;getOrInsertFunction(
                 Identifier.second.substr(1), T, NULL);
         }
}"><pre class="notranslate"><span class="pl-c"><span class="pl-c">//</span> Parse identifiers in the assembly</span>
llvm::StringRef <span class="pl-en">irstring</span>(jl_string_data(ir));
llvm::SmallVector&lt;StringRef, <span class="pl-c1">2</span>&gt; Matches;
llvm::Regex <span class="pl-en">re</span>(<span class="pl-s"><span class="pl-pds">"</span>[a-zA-Z_0-9]+ @[a-zA-Z$._][a-zA-Z$._0-9]*<span class="pl-pds">"</span></span>);
<span class="pl-k">if</span> (re.match(irstring, &amp;Matches)) {
    <span class="pl-k">for</span> (llvm::SmallVector&lt;StringRef, <span class="pl-c1">2</span>&gt;::const_iterator MI =
        Matches.<span class="pl-c1">begin</span>(), ME = Matches.<span class="pl-c1">end</span>(); MI != ME; ++MI) {
             std::pair&lt;llvm::StringRef, llvm::StringRef&gt; Identifier =
                 MI-&gt;<span class="pl-c1">split</span>(<span class="pl-s"><span class="pl-pds">'</span> <span class="pl-pds">'</span></span>);
             llvm::Type *T =
                 llvm::StringSwitch&lt;llvm::Type*&gt;(Identifier.<span class="pl-smi">first</span>)
                     .<span class="pl-c1">Case</span>(<span class="pl-s"><span class="pl-pds">"</span>i32<span class="pl-pds">"</span></span>, <span class="pl-c1">Type::getInt32Ty</span>(<span class="pl-c1">getGlobalContext</span>()))
                     .<span class="pl-c1">Case</span>(<span class="pl-s"><span class="pl-pds">"</span>float<span class="pl-pds">"</span></span>, <span class="pl-c1">Type::getFloatTy</span>(<span class="pl-c1">getGlobalContext</span>()))
                     .<span class="pl-c1">Case</span>(<span class="pl-s"><span class="pl-pds">"</span>double<span class="pl-pds">"</span></span>, <span class="pl-c1">Type::getDoubleTy</span>(<span class="pl-c1">getGlobalContext</span>()))
                     .<span class="pl-c1">Default</span>(<span class="pl-c1">NULL</span>);
             <span class="pl-k">if</span> (T == <span class="pl-c1">NULL</span>)
                 <span class="pl-c1">jl_error</span>(<span class="pl-s"><span class="pl-pds">"</span>Unknown type in LLVM assembly<span class="pl-pds">"</span></span>);
             parent_Module-&gt;<span class="pl-c1">getOrInsertFunction</span>(
                 Identifier.<span class="pl-smi">second</span>.<span class="pl-c1">substr</span>(<span class="pl-c1">1</span>), T, <span class="pl-c1">NULL</span>);
         }
}</pre></div>
<p dir="auto">What seemed like a more flexible solution, is to extend <code class="notranslate">llvmcall</code> such that the user can pass arbitrary declarations, which get pasted before the function definition when called for the first time. By allowing the <code class="notranslate">ir</code> argument to be a tuple of <code class="notranslate">(decls, ir)</code>, this is backwards compatible. Disadvantage: the addition of global state, to check whether a certain (arbitrary) declaration has been added already (because redeclaring identifiers is invalid, and trips the parser). I haven't found another way of checking whether certain declarations have been added to the module already (or we'd need to parse the declarations). This allows using <code class="notranslate">llvmcall</code> as follows:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="sync_threads() = Base.llvmcall(
  (&quot;&quot;&quot;declare void @llvm.nvvm.barrier0()&quot;&quot;&quot;,
   &quot;&quot;&quot;call void @llvm.nvvm.barrier0()
      ret void&quot;&quot;&quot;),
  Void, ())"><pre class="notranslate"><span class="pl-en">sync_threads</span>() <span class="pl-k">=</span> Base<span class="pl-k">.</span><span class="pl-c1">llvmcall</span>(
  (<span class="pl-s"><span class="pl-pds">"""</span>declare void @llvm.nvvm.barrier0()<span class="pl-pds">"""</span></span>,
   <span class="pl-s"><span class="pl-pds">"""</span>call void @llvm.nvvm.barrier0()</span>
<span class="pl-s">      ret void<span class="pl-pds">"""</span></span>),
  Void, ())</pre></div>
<p dir="auto">Any comments?</p>