<p>I've been working on a draft of a Trilangle compiler using LLVM. Out of curiosity, I took the generated IR (given the Trilangle program <code>?!oi@</code>) and plugged it into Godbolt, and this is what I see for main:</p>
<pre><code>main:                                   # @main
        sub     rsp, 24
        mov     rdi, rsp
        call    _stack_ctor
        mov     rdi, rsp
        call    _get_int
        mov     rdi, rsp
        call    _print_int
        mov     rdi, rsp
        call    _get_unichar
        mov     rdi, rsp
        call    _print_unichar
        mov     rdi, rsp
        call    _stack_dtor
        xor     eax, eax
        add     rsp, 24
        ret
</code></pre>
<p>Nothing I do seems to inline any of that. <code>_stack_dtor</code> is the most egregious, because its implementation is just</p>
<pre class="lang-c prettyprint-override"><code>inline void _stack_dtor(stack* self) {
  free(*self);
}
</code></pre>
<p>As can be confirmed by the assembly:</p>
<pre><code>_stack_dtor:                            # @_stack_dtor
        mov     rdi, qword ptr [rdi]
        jmp     free@PLT                        # TAILCALL
</code></pre>
<p>Some things I have tried that seem to not work, at least in Godbolt:</p>
<ul>
<li>Setting <code>-inline-threshold</code> and/or <code>-inlinehint-threshold</code> to a very high or very low value</li>
<li>Replacing the <code>inlinehint</code> attribute with <code>alwaysinline</code> or <code>alwaysinline &quot;nooutline&quot;</code></li>
<li>Specifying an optimization level in the flags, e.g. <code>-O3</code></li>
<li>Removing <code>comdat</code> specifiers</li>
<li>Changing the functions from <code>linkonce_odr dsolocal</code> to <code>private</code></li>
<li>Marking the functions <code>hot</code></li>
</ul>
<p>All of these seem to produce the same assembly (though <code>private</code> changes the label name): <a href="https://godbolt.org/z/hxj15dMnW" rel="noreferrer">https://godbolt.org/z/hxj15dMnW</a></p>
<p>How do I make LLVM inline <em>anything</em>?</p>

<compilers><llvm><inlining>
How do I make LLVM actually inline anything?
CC BY-SA 4.0
2023-06-15T02:34:16.983Z
Interesting... I suspected that `_stack_dtor` *cannot* be inlined because it `jmp`s to `free@PLT` by tail call (in my view, inlining it requires that the call to `_stack_dtor` must be a tail call too, which is not satisfied in the call site). But changing it (`tail call` to simply `call`) and giving opt levels didn't work either.
Bubbler
CC BY-SA 4.0
2023-06-15T02:37:37.617Z
I'll also note that `_stack_ctor` `tail call`s `calloc`, but the emitted assembly definitely doesn't have a tail call there. Similarly, `_stack_pop`, `tail call`s `llvm.assume`, which doesn't make any sense if interpreted literally.
Bbrk24
CC BY-SA 4.0
2023-06-15T08:29:33.220Z
Have you tried running `opt` manually with inline and always_inline passes? Also, mark the functions as always_inline.
SK-logic
CC BY-SA 4.0
2023-06-15T12:50:41.790Z
@SK-logic Admittedly no, but I'm not even sure I have that installed, given that I _only_ have `clang` and not a standalone `llc` on my machine. Clang can still compile and link LLVM IR, so I haven't had any major problems with that.
Bbrk24
CC BY-SA 4.0
2023-06-15T13:35:46.767Z
how do you produce LLVM IR then if you don't have the libraries?
SK-logic
CC BY-SA 4.0
2023-06-15T13:38:26.940Z
`clang -emit-llvm` works well enough.
Bbrk24
CC BY-SA 4.0
2023-06-15T14:27:11.017Z
I mean, how do you produce IR from your compiler, if you're not using llvm libraries directly? If it's in a text form, you're doing it wrong.
SK-logic
CC BY-SA 4.0
2023-06-15T15:36:39.280Z
@SK-logic I am generating it in text format: https://github.com/bbrk24/Trilangle/blob/a62939e052830516c788467d4926bfef62c69189/llvm/README.md I figured that would make it easier to see what it's doing in case something goes wrong.
Bbrk24
CC BY-SA 4.0
2023-06-15T16:08:27.797Z
LLVM IR change too often, and it's always recommended to construct it using the API. You can always dump it in a text form later if you want to debug it. If you're using a language that does not do C++ interop well, there is an `llvm-c` layer that is more than enough for constructing all the IR features and is bindable to virtually anything.
SK-logic
<h1>Use <code>clang</code> instead of <code>llc</code></h1>
<p>Clang can handle LLVM IR files, though you may need to use the <code>-xir</code> flag for it to recognize them as such. When using clang, any optimization level besides <code>-O0</code> causes inlining to occur: <a href="https://godbolt.org/z/6PvGezPsP" rel="nofollow noreferrer">https://godbolt.org/z/6PvGezPsP</a></p>
<p>I'm still unsure as to <em>why</em> <code>llc</code> doesn't inline anything, but at least this serves as a workaround.</p>

CC BY-SA 4.0
2023-06-15T13:19:19.383Z
2023-06-15T13:19:19.383Z
Bbrk24
# How do I make LLVM actually inline anything?
Posted by: username_0 on 2023-06-15
I've been working on a draft of a Trilangle compiler using LLVM. Out of curiosity, I took the generated IR (given the Trilangle program ?!oi@) and plugged it into Godbolt, and this is what I see for main:
main:                                   # @main
        sub     rsp, 24
        mov     rdi, rsp
        call    _stack_ctor
        mov     rdi, rsp
        call    _get_int
        mov     rdi, rsp
        call    _print_int
        mov     rdi, rsp
        call    _get_unichar
        mov     rdi, rsp
        call    _print_unichar
        mov     rdi, rsp
        call    _stack_dtor
        xor     eax, eax
        add     rsp, 24
        ret

Nothing I do seems to inline any of that. _stack_dtor is the most egregious, because its implementation is just
inline void _stack_dtor(stack* self) {
  free(*self);
}

As can be confirmed by the assembly:
_stack_dtor:                            # @_stack_dtor
        mov     rdi, qword ptr [rdi]
        jmp     free@PLT                        # TAILCALL

Some things I have tried that seem to not work, at least in Godbolt:

Setting -inline-threshold and/or -inlinehint-threshold to a very high or very low value
Replacing the inlinehint attribute with alwaysinline or alwaysinline "nooutline"
Specifying an optimization level in the flags, e.g. -O3
Removing comdat specifiers
Changing the functions from linkonce_odr dsolocal to private
Marking the functions hot

All of these seem to produce the same assembly (though private changes the label name): https://godbolt.org/z/hxj15dMnW
How do I make LLVM inline anything?
**Tags:** compilers llvm inlining
> **Comments:**
> **username_1**: Interesting... I suspected that `_stack_dtor` *cannot* be inlined because it `jmp`s to `free@PLT` by tail call (in my view, inlining it requires that the call to `_stack_dtor` must be a tail call too, which is not satisfied in the call site). But changing it (`tail call` to simply `call`) and giving opt levels didn't work either.  
> **username_0**: I'll also note that `_stack_ctor` `tail call`s `calloc`, but the emitted assembly definitely doesn't have a tail call there. Similarly, `_stack_pop`, `tail call`s `llvm.assume`, which doesn't make any sense if interpreted literally.  
> **username_2**: Have you tried running `opt` manually with inline and always_inline passes? Also, mark the functions as always_inline.  
> **username_0**: @SK-logic Admittedly no, but I'm not even sure I have that installed, given that I _only_ have `clang` and not a standalone `llc` on my machine. Clang can still compile and link LLVM IR, so I haven't had any major problems with that.  
> **username_2**: how do you produce LLVM IR then if you don't have the libraries?  
> **username_0**: `clang -emit-llvm` works well enough.  
> **username_2**: I mean, how do you produce IR from your compiler, if you're not using llvm libraries directly? If it's in a text form, you're doing it wrong.  
> **username_0**: @SK-logic I am generating it in text format: https://github.com/bbrk24/Trilangle/blob/a62939e052830516c788467d4926bfef62c69189/llvm/README.md I figured that would make it easier to see what it's doing in case something goes wrong.  
> **username_2**: LLVM IR change too often, and it's always recommended to construct it using the API. You can always dump it in a text form later if you want to debug it. If you're using a language that does not do C++ interop well, there is an `llvm-c` layer that is more than enough for constructing all the IR features and is bindable to virtually anything.  
---
## 1 answers
### Answer by username_0 on 2023-06-15. Score: 2
# Use `clang` instead of `llc`

Clang can handle LLVM IR files, though you may need to use the `-xir` flag for it to recognize them as such. When using clang, any optimization level besides `-O0` causes inlining to occur: <https://godbolt.org/z/6PvGezPsP>

I'm still unsure as to *why* `llc` doesn't inline anything, but at least this serves as a workaround.
---
