<p dir="auto">I've recently experimenting with <code class="notranslate">llvm.expect</code> to see if I can squeeze the last bit of performance for error throwing (rather the non-error path). I would like to use <code class="notranslate">llvmcall</code> but the simplest implementation gives me an error that <code class="notranslate">@llvm.expect.i1</code> is not defined. Would it be possible to add another parameter for <code class="notranslate">llvmcall</code> so that declaration is allowed?</p>
<p dir="auto">I'm asking because</p>
<ol dir="auto">
<li>It seems that <a href="https://github.com/maleadt/CUDA.jl/blob/e72e54caf9ba60ad59ffd2545250cda4187b0b65/src/native/intrinsics.jl#L118"><code class="notranslate">CUDA.jl</code> is using a form that allows it</a> although when I tried that it didn't work.</li>
<li>After reading the codegen for <code class="notranslate">llvmcall</code> I came up with a hack to do what I want (see below). So I think it would be nice to add explicit support for sth useful that is possible to do with a hack.</li>
</ol>
<p dir="auto">It seems pretty straightforward to implement such function but I don't want to go ahead and do it myself now because IIRC <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> has a more complete implementation of it that is not in the <code class="notranslate">Base</code> yet (and that <code class="notranslate">CUDA.jl</code> seems to be using sth similar). Is there any plan to get it in?</p>
<p dir="auto">The hacky implementation is like this. The llvm code correctly contains the <code class="notranslate">expect</code> call. This doesn't seems to affect the assembly but similar code in c compiled with <code class="notranslate">clang</code> or <code class="notranslate">gcc</code> emit identical assembly as well so that's probably normal.</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function likely(x::Bool)
    Base.llvmcall(&quot;&quot;&quot;
                  %2 = tail call i1 @llvm.expect.i1(i1 %0, i1 true)
                  ret i1 %2
                  }
                  declare i1 @llvm.expect.i1(i1, i1)
                  define void @likely_dummy() {
                  ret void
                  &quot;&quot;&quot;, Bool, Tuple{Bool}, x)
end

function unlikely(x::Bool)
    Base.llvmcall(&quot;&quot;&quot;
                  %2 = tail call i1 @llvm.expect.i1(i1 %0, i1 false)
                  ret i1 %2
                  }
                  declare i1 @llvm.expect.i1(i1, i1)
                  define void @unlikely_dummy() {
                  ret void
                  &quot;&quot;&quot;, Bool, Tuple{Bool}, x)
end

function f1(x::Int)
    if x &gt; 0
        x
    else
        2
    end
end

function f2(x::Int)
    if likely(x &gt; 0)
        x
    else
        2
    end
end

function f3(x::Int)
    if unlikely(x &gt; 0)
        x
    else
        2
    end
end

@code_llvm f1(1)
@code_llvm f2(1)
@code_llvm f3(1)

# @code_native f1(1)
# @code_native f2(1)
# @code_native f3(1)"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">likely</span>(x<span class="pl-k">::</span><span class="pl-c1">Bool</span>)
    Base<span class="pl-k">.</span><span class="pl-c1">llvmcall</span>(<span class="pl-s"><span class="pl-pds">"""</span></span>
<span class="pl-s">                  %2 = tail call i1 @llvm.expect.i1(i1 %0, i1 true)</span>
<span class="pl-s">                  ret i1 %2</span>
<span class="pl-s">                  }</span>
<span class="pl-s">                  declare i1 @llvm.expect.i1(i1, i1)</span>
<span class="pl-s">                  define void @likely_dummy() {</span>
<span class="pl-s">                  ret void</span>
<span class="pl-s">                  <span class="pl-pds">"""</span></span>, Bool, Tuple{Bool}, x)
<span class="pl-k">end</span>

<span class="pl-k">function</span> <span class="pl-en">unlikely</span>(x<span class="pl-k">::</span><span class="pl-c1">Bool</span>)
    Base<span class="pl-k">.</span><span class="pl-c1">llvmcall</span>(<span class="pl-s"><span class="pl-pds">"""</span></span>
<span class="pl-s">                  %2 = tail call i1 @llvm.expect.i1(i1 %0, i1 false)</span>
<span class="pl-s">                  ret i1 %2</span>
<span class="pl-s">                  }</span>
<span class="pl-s">                  declare i1 @llvm.expect.i1(i1, i1)</span>
<span class="pl-s">                  define void @unlikely_dummy() {</span>
<span class="pl-s">                  ret void</span>
<span class="pl-s">                  <span class="pl-pds">"""</span></span>, Bool, Tuple{Bool}, x)
<span class="pl-k">end</span>

<span class="pl-k">function</span> <span class="pl-en">f1</span>(x<span class="pl-k">::</span><span class="pl-c1">Int</span>)
    <span class="pl-k">if</span> x <span class="pl-k">&gt;</span> <span class="pl-c1">0</span>
        x
    <span class="pl-k">else</span>
        <span class="pl-c1">2</span>
    <span class="pl-k">end</span>
<span class="pl-k">end</span>

<span class="pl-k">function</span> <span class="pl-en">f2</span>(x<span class="pl-k">::</span><span class="pl-c1">Int</span>)
    <span class="pl-k">if</span> <span class="pl-c1">likely</span>(x <span class="pl-k">&gt;</span> <span class="pl-c1">0</span>)
        x
    <span class="pl-k">else</span>
        <span class="pl-c1">2</span>
    <span class="pl-k">end</span>
<span class="pl-k">end</span>

<span class="pl-k">function</span> <span class="pl-en">f3</span>(x<span class="pl-k">::</span><span class="pl-c1">Int</span>)
    <span class="pl-k">if</span> <span class="pl-c1">unlikely</span>(x <span class="pl-k">&gt;</span> <span class="pl-c1">0</span>)
        x
    <span class="pl-k">else</span>
        <span class="pl-c1">2</span>
    <span class="pl-k">end</span>
<span class="pl-k">end</span>

<span class="pl-c1">@code_llvm</span> <span class="pl-c1">f1</span>(<span class="pl-c1">1</span>)
<span class="pl-c1">@code_llvm</span> <span class="pl-c1">f2</span>(<span class="pl-c1">1</span>)
<span class="pl-c1">@code_llvm</span> <span class="pl-c1">f3</span>(<span class="pl-c1">1</span>)

<span class="pl-c"><span class="pl-c">#</span> @code_native f1(1)</span>
<span class="pl-c"><span class="pl-c">#</span> @code_native f2(1)</span>
<span class="pl-c"><span class="pl-c">#</span> @code_native f3(1)</span></pre></div>
<p dir="auto">The script prints</p>
<div class="highlight highlight-source-llvm notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="define i64 @julia_f1_20826(i64) {
top:
  %1 = icmp slt i64 %0, 1
  br i1 %1, label %L, label %if

if:                                               ; preds = %top
  ret i64 %0

L:                                                ; preds = %top
  ret i64 2
}

define i64 @julia_f2_20829(i64) {
top:
  %1 = icmp sgt i64 %0, 0
  %2 = call i1 @llvm.expect.i1(i1 %1, i1 true)
  br i1 %2, label %if, label %L

if:                                               ; preds = %top
  ret i64 %0

L:                                                ; preds = %top
  ret i64 2
}

define i64 @julia_f3_20830(i64) {
top:
  %1 = icmp sgt i64 %0, 0
  %2 = call i1 @llvm.expect.i1(i1 %1, i1 false)
  br i1 %2, label %if, label %L

if:                                               ; preds = %top
  ret i64 %0

L:                                                ; preds = %top
  ret i64 2
}"><pre class="notranslate"><span class="pl-k">define</span> <span class="pl-k">i64</span> <span class="pl-c1">@julia_f1_20826</span>(<span class="pl-k">i64</span>) {
top:
  <span class="pl-c1">%1</span> = <span class="pl-k">icmp</span> <span class="pl-k">slt</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>, <span class="pl-c1">1</span>
  <span class="pl-k">br</span> <span class="pl-k">i1</span> <span class="pl-c1">%1</span>, <span class="pl-k">label</span> <span class="pl-c1">%L</span>, <span class="pl-k">label</span> <span class="pl-c1">%if</span>

if:                                               <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>

L:                                                <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">2</span>
}

<span class="pl-k">define</span> <span class="pl-k">i64</span> <span class="pl-c1">@julia_f2_20829</span>(<span class="pl-k">i64</span>) {
top:
  <span class="pl-c1">%1</span> = <span class="pl-k">icmp</span> <span class="pl-k">sgt</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>, <span class="pl-c1">0</span>
  <span class="pl-c1">%2</span> = <span class="pl-k">call</span> <span class="pl-k">i1</span> <span class="pl-c1">@llvm.expect.i1</span>(<span class="pl-k">i1</span> <span class="pl-c1">%1</span>, <span class="pl-k">i1</span> <span class="pl-k">true</span>)
  <span class="pl-k">br</span> <span class="pl-k">i1</span> <span class="pl-c1">%2</span>, <span class="pl-k">label</span> <span class="pl-c1">%if</span>, <span class="pl-k">label</span> <span class="pl-c1">%L</span>

if:                                               <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>

L:                                                <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">2</span>
}

<span class="pl-k">define</span> <span class="pl-k">i64</span> <span class="pl-c1">@julia_f3_20830</span>(<span class="pl-k">i64</span>) {
top:
  <span class="pl-c1">%1</span> = <span class="pl-k">icmp</span> <span class="pl-k">sgt</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>, <span class="pl-c1">0</span>
  <span class="pl-c1">%2</span> = <span class="pl-k">call</span> <span class="pl-k">i1</span> <span class="pl-c1">@llvm.expect.i1</span>(<span class="pl-k">i1</span> <span class="pl-c1">%1</span>, <span class="pl-k">i1</span> <span class="pl-k">false</span>)
  <span class="pl-k">br</span> <span class="pl-k">i1</span> <span class="pl-c1">%2</span>, <span class="pl-k">label</span> <span class="pl-c1">%if</span>, <span class="pl-k">label</span> <span class="pl-c1">%L</span>

if:                                               <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">%0</span>

L:                                                <span class="pl-c">; preds = %top</span>
  <span class="pl-k">ret</span> <span class="pl-k">i64</span> <span class="pl-c1">2</span>
}</pre></div>
<p dir="auto">Basically sugar, but would be cool to compose functions with the pipeline op. Could possibly help with <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="26355302" data-permission-text="Title is private" data-url="https://github.com/JuliaLang/julia/issues/5571" data-hovercard-type="issue" data-hovercard-url="/JuliaLang/julia/issues/5571/hovercard" href="https://github.com/JuliaLang/julia/issues/5571">#5571</a>.</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="f(x) = x |&gt; factor |&gt; keys |&gt; length

f = factor |&gt; keys |&gt; length
# ERROR: no method keys(Function,)
#  in |&gt; at operators.jl:159"><pre class="notranslate"><span class="pl-en">f</span>(x) <span class="pl-k">=</span> x <span class="pl-k">|&gt;</span> factor <span class="pl-k">|&gt;</span> keys <span class="pl-k">|&gt;</span> length

f <span class="pl-k">=</span> factor <span class="pl-k">|&gt;</span> keys <span class="pl-k">|&gt;</span> length
<span class="pl-c"><span class="pl-c">#</span> ERROR: no method keys(Function,)</span>
<span class="pl-c"><span class="pl-c">#</span>  in |&gt; at operators.jl:159</span></pre></div>
<p dir="auto">I think the relevant code is </p><div class="Box Box--condensed my-2">
  <div class="Box-header f6">
    <p class="mb-0 text-bold">
      <a href="https://github.com/JuliaLang/julia/blob/a26f03ea141ae93587bd90c9755796b5eeb82ece/base/operators.jl#L159">julia/base/operators.jl</a>
    </p>
    <p class="mb-0 color-fg-muted">
         Line 159
      in
      <a data-pjax="true" class="commit-tease-sha" href="/JuliaLang/julia/commit/a26f03ea141ae93587bd90c9755796b5eeb82ece">a26f03e</a>
    </p>
  </div>
  <div itemprop="text" class="Box-body p-0 blob-wrapper blob-wrapper-embedded data">
    <table class="highlight tab-size mb-0 js-file-line-container" data-tab-size="8" data-paste-markdown-skip="">

        <tbody><tr class="border-0">
          <td id="L159" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="159"></td>
          <td id="LC159" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">|&gt;</span>(x, f<span class="pl-k">::</span><span class="pl-c1">Function</span>) <span class="pl-k">=</span> <span class="pl-c1">f</span>(x) </td>
        </tr>
    </tbody></table>
  </div>
</div>
.<p></p>
<p dir="auto">Something like this?</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="|&gt;(f1::Function, f2:Function) = x -&gt; f1(f2(x))"><pre class="notranslate"><span class="pl-k">|&gt;</span>(f1<span class="pl-k">::</span><span class="pl-c1">Function</span>, f2<span class="pl-k">:</span>Function) <span class="pl-k">=</span> x <span class="pl-k">-&gt;</span> <span class="pl-c1">f1</span>(<span class="pl-c1">f2</span>(x))</pre></div>
<p dir="auto">Down to figure out how to write a test n such, just let me know.</p>