<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 29, 2017 at 6:14 PM, Dimitri Racordon via llvm-dev <span dir="ltr"><<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">



<div style="word-wrap:break-word">
<div dir="auto" style="word-wrap:break-word">
<div>Hi all,</div>
<div><br>
</div>
<div>I’m pretty new to the list, and to LLVM in general, so please excuse my extreme newbiesness.</div>
<div><br>
</div>
<div>I’m trying to figure out what would be the appropriate way to implement move semantics.</div>
<div>I’ve been trying to dump the IR produced by clang with some basic C++ snippet, but I’m afraid it didn’t help me much.</div></div></div></blockquote><div><br></div><div>Move semantics in C++ are just a mechanism to use overload resolution to select a different overload (see <a href="http://en.cppreference.com/w/cpp/language/move_constructor">http://en.cppreference.com/w/cpp/language/move_constructor</a>). For example, if you think about how to map your example C++ code down to equivalent C, you'll see that in that process you have fully resolved the "move semantics". At the LLVM level (or the C level), there are no "move semantics". std::move is basically just a cast that creates a `S&&` which will then select the right overload.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div dir="auto" style="word-wrap:break-word">
<div><br>
</div>
<div>Here’s the example I’ve been playing with (in C++):</div>
<div><br>
</div>
<div>
<div><font face="Menlo">struct S {</font></div>
<div><font face="Menlo">  S() noexcept: x(new int) {}</font></div>
<div><font face="Menlo">  S(S&& other) {</font></div>
<div><font face="Menlo">    x = other.x</font></div>
<div><font face="Menlo">    other.x = nullptr;</font></div>
<div><font face="Menlo">  }</font></div>
<div><font face="Menlo">  ~S() {</font></div>
<div><font face="Menlo">    delete x;</font></div>
<div><font face="Menlo">  }</font></div>
<div><font face="Menlo">};</font></div>
<div><font face="Menlo"><br>
</font></div>
<div><font face="Menlo">S f1() {</font></div>
<div><font face="Menlo">  auto s = S();</font></div>
<div><font face="Menlo">  return s;</font></div>
<div><font face="Menlo">}</font></div>
<div><font face="Menlo"><br>
</font></div>
<div>
<div><font face="Menlo">S f2() {</font></div>
<div><font face="Menlo">  auto s = S();</font></div>
<div><font face="Menlo">  return std::move(s);</font></div>
<div><font face="Menlo">}</font></div>
</div>
</div>
<div><br>
</div>
<div>This of course produces a lot of LLVM code (with -O0), but I think I may have figured out most of what’s what. In particular, I’ve been able to identify the IR code for `f1` and `f2`, but to my surprise, neither of those return a value. Both take
 a pointer to `S` as parameter, which in turn gets passed to the constructor of `S`, and return void.</div>
<div><br>
</div>
<div>This leaves me with two main questions:</div>
<div>
<ul class="gmail-m_3659424811896651911MailOutline">
<li>First, is the use of a pointer to S as parameter a specificity of clang, or generally the way to go? I’ve seen in the language reference that one could return a struct with a simple ret instruction, so I’m surprised not to see it for the version
 that doesn’t use move semantics.</li></ul></div></div></div></blockquote><div>This a language ABI question. There's really nothing LLVM-specific about it. I would recommend thinking about it in terms of how to map C++ to C. As Davide pointed out, RVO is one reason to choose this particular lowering. These decisions are made inside Clang (not LLVM) and are mandated by the ABI (all compilers must implement them the same way for code to be able to be linked together and work). If you want all the gory details, the itanium C++ ABI is documented at <a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html">https://itanium-cxx-abi.github.io/cxx-abi/abi.html</a> (this is the C++ ABI used on basically all platforms except MSVC; there's a historical connection to itanium but nothing specific to that processor about it).</div><div><br></div><div>In particular, the description of how to lower return values is <a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#return-value">https://itanium-cxx-abi.github.io/cxx-abi/abi.html#return-value</a></div><div><br></div><div>Note that the C++ ABI is phrased in terms of the underlying C ABI (which is processor-specific (and generally not OS-specific unless you care about Windows vs non-Windows)), so familiarity with the C ABI is useful too; documents for the C ABI of different processors can be found in <a href="http://llvm.org/docs/CompilerWriterInfo.html">http://llvm.org/docs/CompilerWriterInfo.html</a> e.g. the "X86 and X86-64 SysV psABI". The C ABI may seem overwhelming (lots of processor details, corner cases, etc.), but the basic gist is that there's a list of registers and each argument is assigned in turn from that list (if the register list is exhausted, the rest are passed through memory). This is easy as long as everything (return value and argument types) are int, long, pointer, or some other primitive type that fits in a register. Struct types are decomposed into multiple primitive types according to certain rules, until everything is in terms of primitive types.</div><div><br></div><div>e.g. if you understand the examples in <a href="https://godbolt.org/g/qSdzHj">https://godbolt.org/g/qSdzHj</a> then you pretty much have a basic understanding of the C parameter passing ABI. The register lists for x86-64 are rdi, rsi, ... for arguments and rax, rdx, ... for return values . (Also look at the corresponding LLVM IR).</div><div><br></div><div>Very few people actually know the precise rules in detail. However, basically all LLVM developers (or more generally toolchain developers: compiler, linker, debugger, etc.) will know the basic rules (like the examples I linked above) and will know how to look up specifics in the psABI document as needed (and probably 90% of the time just looking at Clang's output on an example will answer a particular question; for example, I forgot that it as rdx as the second register for return values; all I remembered was that there were two return registers and the first was rax).</div><div><br></div><div><div>If you're interested, these are the notes I took when I was initially learning about this: <a href="https://github.com/chisophugis/x64-Forth/blob/master/abi.txt">https://github.com/chisophugis/x64-Forth/blob/master/abi.txt</a></div><div>(woah this takes me back)</div><div>That Forth implementation doesn't actually call any external libraries, so the only external ABI it cares about is the Linux syscall ABI, which I recorded in this comment for my own memory <a href="https://github.com/chisophugis/x64-Forth/blob/master/compile4.asm#L13">https://github.com/chisophugis/x64-Forth/blob/master/compile4.asm#L13</a></div><div>(yes, this was before I learned to use version control...)</div><div>The internal "ABI" used by this small Forth implementation is described in <a href="https://github.com/chisophugis/x64-Forth/blob/master/compile4.asm#L6">https://github.com/chisophugis/x64-Forth/blob/master/compile4.asm#L6</a></div></div><div>(forth is a very low-level language so it needs its own processor-specific ABI; most languages essentially just piggy-back on the C ABI for processor-specific stuff)</div><div><br></div><div><div>LLVM handles all of this C ABI stuff for you (and there's other aspects of the C ABI like stack alignment/layout, TLS access, relocations, etc.). There's quite a bit of essential complexity, but as long as you stick to the simple cases where the mapping from C is trivial, it's easy to understand. There's a pretty deep rabbit hole though if you start getting into complicated cases, but it's all just a relatively simple extension of the cases that map trivially to C. For the most part, you're only interaction with the rabbit hole will be needing to debug when things go wrong, which will require understanding the basic concepts (which can be understood via simple C examples) and then drill down as needed (e.g. looking at what clang does, looking at the standard docs, etc.). This is in some sense simple even for complex cases in that it doesn't require any complex insight to understand harder cases; you're just verifying assumptions against a list of rules.</div></div><div><br></div><div>That may sound scary, but as long as the IR your frontend generates is internally consistent at the LLVM IR level it will be ABI compatible with itself (modulo bugs in LLVM), so you can basically ignore it. You'll have to have some familiarity with the C ABI in order to e.g. call an external function like malloc in libc, but again, as long as the parameter types are "simple" then the mapping between C and LLVM IR is very simple; you'll need to have a basic understanding though in order to verify this though and debug any think-o's.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div dir="auto" style="word-wrap:break-word"><div><ul class="gmail-m_3659424811896651911MailOutline"><li>Second, would I use a non-void ret instruction to return the result of an alloca, when would the latter be destroyed? Would that involve a copy from the runtime stack of the callee to that of the caller?</li></ul></div></div></div></blockquote><div>The result of an alloca is a pointer to the stack frame of the current function, so returning it doesn't make sense (like returning the address of a local variable in C). Again, this problem isn't really related to LLVM per se and the easiest way to think about it is in terms of how to lower to C.</div><div>Decisions about object destruction are up to the frontend. At the C or LLVM level they just turn into function calls or whatever you use to implement the semantics that the frontend requires. In other words, if you want an object to be destroyed, it's up to your frontend to emit code to perform the destruction wherever the destruction is expected to occur.</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div dir="auto" style="word-wrap:break-word"><div>
<div><br>
</div>
</div>
<div>Thank you very much for your time and your answer,</div>
<div><br>
</div>
<div>Best,</div>
<div><br>
</div>
<br>
<div>
<div style="color:rgb(0,0,0);letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;word-wrap:break-word">
Dimitri Racordon<br>
CUI, Université de Genève<br>
7, route de Drize, CH-1227 Carouge - Switzerland<br>
Phone: <a href="tel:+41%2022%20379%2001%2024" value="+41223790124" target="_blank">+41 22 379 01 24</a>
<div><br>
</div>
</div>
<br class="gmail-m_3659424811896651911Apple-interchange-newline">
<br class="gmail-m_3659424811896651911Apple-interchange-newline">
</div>
<br>
</div>
</div>

<br>______________________________<wbr>_________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-dev</a><br>
<br></blockquote></div><br></div></div>