Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1041 lines (990 sloc) 40.4 KB
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Compiler Explorer</title>
<link rel="stylesheet" href="reveal.js/css/reveal.css">
<link rel="stylesheet" href="godbolt.css">
<style>
.faded {
opacity: 0.5;
}
span.opt {
font-size: 70%;
vertical-align: sub;
}
img.logo {
padding: 5px;
}
div.coinbase {
fill: white;
background: linear-gradient(rgb(15, 98, 189) 24%, rgb(10, 64, 122) 168%);
}
div.footnote {
margin-top: 2em;
font-size: smaller;
font-style: italic;
}
#sum td {
border: 1px solid black;
}
#sum tr {
border: 1px solid black;
}
code.smaller {
font-size: smaller;
}
#registers th {
font-size: 30px;
text-align: center;
}
#registers td {
text-align: center;
}
#registers td.register {
border: 1px solid black;
}
#registers td.rax {
background: rgb(141, 211, 199);
}
#registers td.eax {
background: rgb(255, 255, 179);
}
#registers td.ax {
background: rgb(190, 186, 218);
}
#registers td.ah {
background: rgb(251, 128, 114);
}
#registers td.al {
background: rgb(128, 177, 211);
}
#registers td.regnote {
font-size: smaller;
font-style: italic;
}
div.left-pane {
width: 50%;
float: left;
}
div.right-pane {
width: 50%;
float: right;
}
</style>
<link rel="stylesheet" href="reveal.js/lib/css/zenburn.css">
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match(/print-pdf/gi) ? 'reveal.js/css/print/pdf.css' : 'reveal.js/css/print/paper.css';
document.getElementsByTagName('head')[0].appendChild(link);
</script>
</head>
<body>
<div class="reveal">
<section class="slides">
<section id="title">
<h2>What Else Has My Compiler Done for Me Lately?</h2>
<h5>Unbolting the Compiler's Lid...again</h5>
<em><a href="https://xania.org/">Matt Godbolt</a></em>
<br>
<em>
<a href="https://twitter.com/mattgodbolt">@mattgodbolt</a><br>
<a href="mailto:matt@godbolt.org">matt@godbolt.org</a>
</em>
</section>
<!------------------------------------------------------>
<section id="why">
<!--<section>
<h3>About me</h3>
<div class="fragment">
<img src="images/6502_z80.jpg" height="160">
<img src="images/ARM_610.jpg" height="160">
<img src="images/red_dog.png" height="160">
</div>
<div class="fragment">
<img class="logo" src="images/profactor.jpg" height="30">
<img class="logo" src="images/google.png" height="30">
<img class="logo" src="images/DRWSmallLogo.png" height="30">
</div>
<div class="logo fragment coinbase">
<svg height="30" width="130">
<path fill-rule="evenodd"
d="M10.34 23.89c.93 0 1.8-.17 2.62-.5 0 .03 1.67 2.62 1.7 2.63a9.88 9.88 0 0 1-4.81 1.17C4.72 27.2 1 23.81 1 18.42c0-5.43 3.9-8.8 8.85-8.8 1.75 0 3.14.38 4.53 1.12l-1.6 2.7c-.84-.33-1.7-.48-2.6-.48-3.03 0-5.38 1.93-5.38 5.46 0 3.34 2.27 5.47 5.54 5.47zM23.27 9.62c5.04 0 8.69 3.57 8.69 8.8 0 5.2-3.65 8.77-8.7 8.77-5 0-8.65-3.57-8.65-8.77 0-5.23 3.65-8.8 8.66-8.8zm0 3.22c-2.81 0-4.86 2.17-4.86 5.58 0 3.38 2.05 5.55 4.86 5.55 2.88 0 4.9-2.17 4.9-5.55 0-3.41-2.02-5.58-4.9-5.58zm11.08 13.97V10h3.76V26.8h-3.76zm-.5-21.98a2.36 2.36 0 0 1 4.71 0 2.4 2.4 0 0 1-2.35 2.4 2.4 2.4 0 0 1-2.35-2.4zm7.54 6.23a22.54 22.54 0 0 1 7.7-1.44c4.3 0 7.02 1.63 7.02 6.37v10.82H52.4V16.34c0-2.43-1.51-3.3-3.6-3.3-1.33 0-2.66.18-3.65.49V26.8H41.4V11.06zM59.26 1h3.76v9.45c.8-.42 2.35-.83 3.83-.83 4.86 0 8.5 3.1 8.5 8.5 0 5.43-3.6 9.07-9.82 9.07-2.43 0-4.56-.5-6.27-1.1V1zm3.76 22.62c.72.23 1.67.35 2.62.35 3.45 0 5.92-1.9 5.92-5.77 0-3.27-2.32-5.2-5.16-5.2-1.48 0-2.62.38-3.38.8v9.82zm23.2-8.08c0-1.82-1.38-2.66-3.24-2.66-1.93 0-3.45.57-4.85 1.37v-3.27a11.21 11.21 0 0 1 5.46-1.36c3.68 0 6.3 1.52 6.3 5.73v11.12c-1.6.42-3.87.68-5.77.68-4.36 0-7.55-1.32-7.55-5.12 0-3.42 2.92-5.09 7.78-5.09h1.86v-1.4zm0 3.9h-1.6c-2.62 0-4.33.77-4.33 2.48 0 1.74 1.6 2.42 3.87 2.42.57 0 1.37-.07 2.05-.18v-4.71zm6.4 2.82a8.82 8.82 0 0 0 5.13 1.9c1.67 0 2.77-.57 2.77-1.9 0-1.37-.99-1.86-3.15-2.43-3.5-.8-4.97-2.2-4.97-5.13 0-3.41 2.58-5.08 6-5.08 1.9 0 3.41.41 4.82 1.29v3.45a7.79 7.79 0 0 0-4.71-1.7c-1.63 0-2.5.8-2.5 1.9 0 1.1.71 1.66 2.65 2.2 3.84.83 5.5 2.27 5.5 5.3 0 3.54-2.69 5.13-6.33 5.13a9.87 9.87 0 0 1-5.2-1.36v-3.57zm16.69-3v.07c.23 3 2.8 4.64 5.43 4.64 2.31 0 3.98-.54 5.65-1.64v3.3c-1.52 1.07-3.76 1.56-5.92 1.56-5.24 0-8.8-3.34-8.8-8.65 0-5.35 3.49-8.92 8.12-8.92 4.9 0 7.21 3.15 7.21 7.74v1.9h-11.7zm8.16-2.43c-.08-2.62-1.37-4.06-3.8-4.06-2.16 0-3.75 1.52-4.25 4.06h8.05z"></path>
</svg>
</div>
<aside class="notes">
<h4>Potted history:</h4>
<ul>
<li>Learned Z80, 6502 assembly in the 80s to write my own games</li>
<li>Moved on to ARM assembly</li>
<li>Wrote full functioned IRC client in ARM asm</li>
<li>Dismissed C as just a macro assembler</li>
<li>Learned C to write a MUD at Uni</li>
<li>Eventually moved on to C++</li>
<li>Got a job making games, high performance stuff</li>
<li>Co-ran C++ tools company</li>
<li>Google; occasional performance stuff for cellphones</li>
<li>7 years at DRW doing performance stuff for trading systems</li>
<li>Off to start a new adventure in July</li>
<li>Still an asm hacker at heart though don't touch it so more</li>
</ul>
<p>Amazing opportunity to talk to lots of C++ programmers at all levels. My passion.</p>
</aside>
</section>-->
<!--
<section>
<h3>My goals</h3>
<ul>
<li>Un-scary-fy assembler</li>
<li>Appreciate your compiler!</li>
</ul>
</section>
-->
<section>
<h3>Outline</h3>
<ul>
<li>Compiler Explorer story</li>
<li>Assembly 101</li>
<li>What else has my compiler done for me lately?</li>
<li>Behind the scenes of Compiler Explorer</li>
</ul>
</section>
</section>
<!------------------------------------------------------>
<section id="backstory">
<section>
<h3>Backstory</h3>
<pre><code data-trim class="cpp">
int sum(const vector&lt;int> &v) {
int result = 0;
for (size_t i = 0; i < v.size(); ++i)
result += v[i];
return result;
}</code></pre>
<pre class="fragment"><code data-trim class="cpp">
int sum(const vector&lt;int> &v) {
int result = 0;
for (int x : v) result += x;
return result;
}</code></pre>
<div class="fragment">Is one better than the other?</div>
<div class="fragment">Look at compiler output!</div>
<aside class="notes">
<ul>
<li>2012, C++11isms, range-for</li>
</ul>
</aside>
</section>
<section>
<h3>WARNING</h3>
<!-- latency vs throughput ? -->
<ul>
<li>Reading assembly alone can be misleading</li>
<li><em>Always</em> measure too</li>
<li>Google Benchmark</li>
<li><a href="http://www.quick-bench.com/">quick-bench.com</a></li>
</ul>
<aside class="notes">
Shout out to google benchmarking tool. Microbenchmarks, perils.
But always measure end-to-end perf if you can too.
</aside>
</section>
</section>
<!------------------------------------------------------->
<section id="asm101">
<section>
<h3>x86 Assembly 101</h3>
</section>
<section>
<!-- TODO Mighty Boosh? -->
<h3>Registers</h3>
<ul>
<li><code>rax</code>, <code>rbx</code>, <code>rcx</code>, <code>rdx</code>, <code>rsp</code>,
<code>rbp</code>, <code>rsi</code>, <code>rdi</code>, <code>r8</code>-<code>r15</code></li>
<li><code>xmm0</code>-<code>xmm15</code></li>
<li><code>rdi</code>, <code>rsi</code>, <code>rdx</code>... arguments</li>
<li><code>rax</code> is return value</li>
</ul>
</section>
<section>
<h3>Registers</h3>
<table id="registers">
<thead>
<tr>
<th>63...56</th>
<th>55...48</th>
<th>47...40</th>
<th>39...32</th>
<th>31...24</th>
<th>23...16</th>
<th>15...8</th>
<th>7...0</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="8" class="register rax">rax</td>
</tr>
<tr>
<td colspan="4" class="regnote">(zeroed on write)</td>
<td colspan="4" class="register eax">eax</td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="2" class="register ax">ax</td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="1" class="register ah">ah</td>
<td colspan="1"></td>
</tr>
<tr>
<td colspan="7"></td>
<td colspan="1" class="register al">al</td>
</tr>
</tbody>
</table>
<div class="fragment">And so on for rdi, rsi, rcx, rdx...</div>
</section>
<section>
<h3>Instructions</h3>
<pre><code data-trim class="x86asm">
op
op dest
op dest, src
op dest, src1, src2
</code></pre>
<ul>
<li><code>op</code> is e.g. <code>call</code>, <code>ret</code>, <code>add</code>, <code>sub</code>,
<code>cmp</code>...
</li>
<li><code>dest</code>, <code>src</code> is register or memory reference:<br>
<code class="smaller">[base + reg1<span class="opt">opt</span> + reg2*(1, 2, 4 or 8)<span
class="opt">opt</span>]</code>
</li>
</ul>
<div class="footnote">(Intel asm syntax)</div>
</section>
<section>
<h3>Instructions</h3>
<div class="left-pane">
<pre class="smaller"><code data-trim class="x86asm">
mov eax, DWORD PTR [r14]
add rax, rdi
add eax, DWORD PTR [r14+4]
sub eax, DWORD PTR [r14+4*rbx]
lea rax, [r14+4*rbx]
xor edx, edx
</code></pre>
</div>
<div class="right-pane">
<pre class="fragment smaller"><code data-trim class="cpp">
int eax = *r14; // int *r14;
rax += rdi;
eax += r14[1];
eax -= r14[rbx];
int *rax = &r14[rbx];
edx = 0;
</code></pre>
</div>
</section>
<section>
<h3>Summary</h3>
<ul>
<li>Registers: <code>rax</code>, <code>rbx</code>, <code>rcx</code> ...</li>
<li>Size: <code>rax</code>, <code>eax</code>, <code>ax</code> ...</li>
<li>Params: <code>rdi</code>, <code>rsi</code>, <code>rdx</code>, <code>rcx</code> ...</li>
<li>Result: <code>rax</code></li>
<li><code>op dest, src</code></li>
<li><code>dest</code>, <code>src</code> are registers or memory</li>
</ul>
</section>
</section>
<!------------------------------------------------------->
<section id="back2backstory">
<section>
<h3>Where were we?</h3>
<pre><code data-trim class="cpp">
int sum(const vector&lt;int> &v) {
int result = 0;
for (size_t i = 0; i < v.size(); ++i)
result += v[i];
return result;
}</code></pre>
<pre><code data-trim class="cpp">
int sum(const vector&lt;int> &v) {
int result = 0;
for (int x : v) result += x;
return result;
}</code></pre>
<div class="fragment">Which is better?</div>
</section>
<section>
<h3>Compiler Explorer v0.1</h3>
<pre><code data-noescape data-trim class="bash">
$ g++ /tmp/test.cc -O2 -c -S -o - -masm=intel \
| c++filt \
| grep -vE '\s+\.'
</code></pre>
<pre><code class="x86asm" data-trim>
sum(std::vector&lt;int, std::allocator&lt;int> > const&):
.LFB786:
mov rcx, QWORD PTR [rdi]
mov rax, QWORD PTR 8[rdi]
sub rax, rcx
shr rax, 2
mov rsi, rax
...</code></pre>
</section>
<section><h3>Compiler Explorer v0.1</h3>
<div>Not very pretty</div>
<h5 class="fragment" data-fragment-index="1">To the web!</h5>
<img src="images/CE.svg" height="200" class="fragment" data-fragment-index="1">
</section>
</section>
<!------------------------------------------------------->
<section id="andNow">
<section>
<h3>Demo</h3>
<pre class="ce">
/// g81:-O2 -std=c++1z -march=haswell
// setup
#include &lt;numeric>
#include &lt;vector>
using namespace std;
int sum(const vector&lt;int> &v) {
int result = 0;
for (size_t i = 0; i < v.size(); ++i)
result += v[i];
return result;
}</pre>
<aside class="notes">
<ul>
<li>Pop out</li>
<li>Show code</li>
<li>Show optimizer off</li>
<li>Show diff</li>
</ul>
</aside>
</section>
<section>
<h3>Walkthrough</h3>
<pre><code data-trim class="cpp">
int sum(const vector&lt;int> &v) {
</code></pre>
<pre><code data-trim class="x86asm">
; rdi = const vector&lt;int> *
mov rdx, QWORD PTR [rdi] ; rdx = *rdi &equiv; begin()
mov rcx, QWORD PTR [rdi+8] ; rcx = *(rdi+8) &equiv; end()
</code></pre>
<pre class="fragment"><code data-trim class="cpp">
template&lt;typename T> struct _Vector_impl {
T *_M_start;
T *_M_finish;
T *_M_end_of_storage;
};
</code></pre>
</section>
<section>
<div class="left-pane">
<h5>Traditional</h5>
<pre class="smaller"><code data-trim class="x86asm">
sub rcx, rdx ; rcx = end-begin
mov rax, rcx
shr rax, 2 ; (end-begin)/4
je .L4
add rcx, rdx
xor eax, eax
</code></pre>
<pre class="fragment smaller"><code data-trim class="cpp">
size_t size() const noexcept {
return _M_finish - _M_start;
}</code></pre>
</div>
<div class="right-pane">
<h5>Range</h5>
<pre><code data-trim class="x86asm">
xor eax, eax
cmp rdx, rcx ; begin==end?
je .L4
</code></pre>
<pre class="fragment"><code data-trim class="cpp">
auto __begin = begin(v);
auto __end = end(v);
for (auto __it = __begin;
__it != __end;
++it)
</code></pre>
</div>
</section>
<section>
<h3>Walkthrough</h3>
<pre><code data-trim class="x86asm">
; rcx &equiv; end, rdx = begin, eax = 0
.L3:
add eax, DWORD PTR [rdx] ; eax += *rdx
add rdx, 4 ; rdx += sizeof(int)
cmp rdx, rcx ; is rdx == end?
jne .L3 ; if not, loop
ret ; we're done
</code></pre>
</section>
<section><h3>Backstory</h3>
<h5>So, which approach is best?</h5></section>
<section>
<h3>Also</h3>
<ul>
<li>Optimizer settings are important</li>
<li><code>std::accumulate</code></li>
</ul>
</section>
</section>
<!------------------------------------------------------->
<section id="compilersAreSuperSmart1">
<section><h3>What has my compiler<br>done for me lately?</h3></section>
<section>
<h3>Multiplication</h3>
<div class="left-pane">
<pre><code class="cpp ce" data-trim>
/// g81:-O2 -std=c++1z -march=haswell
int mulByY(int x, int y) {
return x * y;
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-trim>
mulByY(int, int):
mov eax, edi
imul eax, esi
ret
</code></pre>
</div>
</section>
<!--
<section>
<h3>Multiplication</h3>
<pre>
1101 (13)
x 0101 (5)
&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;
1101
0000
1101
+ 0000
&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;
01000001 (65)</pre>
<div class="fragment">That's a lot of additions!</div>
<div class="fragment">Haswell 32-bit multiply - 4 cycles</div>
</section>
-->
<section>
<h3>Multiplication</h3>
<pre><code class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
int mulByConstant(int x) { return x * 2; }
</code></pre>
</section>
<section>
<h3>Multiplication</h3>
<pre><code class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
int mulBy65599(int a) {
return (a << 16) + (a << 6) - a;
// ^ ^
// a * 65536 |
// a * 64
// 65536a + 64a - 1a = 65599a
} </code></pre>
<aside class="notes">
<pre>-march=i486 -m32</pre>
shows up what you asked
</aside>
</section>
<section>
<h3>Division</h3>
<div class="left-pane">
<!---/// g81:-O2 -std=c++1z -->
<pre><code class="cpp ce" data-trim>
int divByY(int x, int y) {
return x / y;
}
int modByY(int x, int y) {
return x % y;
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-trim>
divByY(int, int):
mov eax, edi
cdq
idiv esi
ret
modByY(int, int):
mov eax, edi
cdq
idiv esi
mov eax, edx
ret
</code></pre>
</div>
<div class="fragment">Haswell 32-bit divide - 22-29 cycles!</div>
<aside class="notes">
<code>cdq</code> does sign expansion into registers. <code>div</code> divides eax:edx with the
operand, results in
eax (divisor) and edx (dividend).
<code>cdq</code> sign extends eax into edx, ready for a div
</aside>
</section>
<section>
<h3>Division</h3>
<pre><code class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
unsigned divByConstant(unsigned x) { return x / 2; }
</code></pre>
</section>
<section>
<h3>Division</h3>
<!-- TODO C implementaiton? -->
<pre><code class="x86asm" data-trim>
mov eax, edi ; eax = x
mov edx, 0xaaaaaaab
mul edx ; eax:edx = x * 0xaaaaaaab
mov eax, edx ; (x * 0xaaaaaaab) >> 32
; &equiv; (x * 0xaaaaaaab) / 0x10000000
; &equiv; x * 0.6666666667
shr eax ; x * 0.333333333
ret
</code></pre>
</section>
<section>
<h3>Modulus</h3>
<div class="left-pane">
<!---/// g81:-O2 -std=c++1z -->
<pre><code class="cpp ce" data-trim>
int modBy3(unsigned x) {
return x % 3;
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-noescape data-trim>
<span class="faded">mov eax, edi
mov edx, 0xaaaaaaab
mul edx
mov eax, edx
shr eax
</span>lea eax, [rdx+rdx*2]
sub edi, eax
mov eax, edi
<span class="faded">ret</span>
</code></pre>
</div>
</section>
<section>
<h3>Why modulus?</h3>
<ul>
<li>
<a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:1.6,j:1,source:'//+setup%0A++%23include+%3Cunordered_map%3E%0A++using+namespace+std%3B%0A%0Aint+lookupOr0(int+i,%0A+++++++++++const+unordered_map%3Cint,+int%3E+%26m)+%7B%0A++if+(auto+it+%3D+m.find(i)%3B+it+!!%3D+m.end())%0A++++return+it-%3Esecond%3B%0A++return+0%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:gsnapshot,filters:(___0:(),b:'0',commentOnly:'0',directives:'0',intel:'0',jquery:'3.2.1',length:1,prevObject:(___0:(sizzle1504548572380:(undefined:(legend:!(5,0,'1')))),length:1,prevObject:(___0:(jQuery3210165493275017513991:(display:''),sizzle1504548572380:(undefined:(legend:!(5,0,'1')))),length:1)),trim:'0'),fontScale:1.8,options:'-O2+-std%3Dc%2B%2B1z+-march%3Dhaswell',source:1),l:'5',n:'0',o:'x86-64+gcc+(snapshot)+(Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4">
Bucket selection in hash maps</a></li>
<li>
<a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:1.6,j:1,source:'//+setup%0A++%23include+%3Cunordered_map%3E%0A++using+namespace+std%3B%0A%0Aint+lookupOr0(int+i,%0A+++++++++++const+unordered_map%3Cint,+int%3E+%26m)+%7B%0A++if+(auto+it+%3D+m.find(i)%3B+it+!!%3D+m.end())%0A++++return+it-%3Esecond%3B%0A++return+0%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang_trunk,filters:(___0:(),b:'0',commentOnly:'0',directives:'0',intel:'0',jquery:'3.2.1',length:1,prevObject:(___0:(sizzle1504548572380:(undefined:(legend:!(5,0,'1')))),length:1,prevObject:(___0:(jQuery3210165493275017513991:(display:''),sizzle1504548572380:(undefined:(legend:!(5,0,'1')))),length:1)),trim:'0'),fontScale:1.8,options:'-O2+-std%3Dc%2B%2B1z+-march%3Dhaswell+-stdlib%3Dlibc%2B%2B',source:1),l:'5',n:'0',o:'x86-64+clang+(trunk)+(Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4">
libc++</a> special-cases power-of-two
</li>
<li>boost multi_index</li>
</ul>
</section>
<section><h3>Counting bits</h3>
<pre><code class="ce">
/// g81:-O2 -std=c++1z -march=haswell
int countSetBits(int a) {
int count = 0;
while (a) {
count++;
a &amp;= (a-1);
}
return count;
}
</code></pre>
<aside class="notes">
Explain a &amp; (a - 1)
</aside>
</section>
<section>
<h3>Summation</h3>
<pre><code data-trim class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
constexpr int sumTo(int x) {
int sum = 0;
for (int i = 0; i &lt;= x; ++i)
sum += i;
return sum;
}
int main(int argc, const char *argv[]) {
return sumTo(20);
}
</code></pre>
<aside class="notes">
<ul>
<li>Show code</li>
<li>Modify code to show how to make it depend on argc/argv</li>
<li>Show clang's cleverness</li>
<li>Show clang's weirdness if starting at 1 instead of 0</li>
</ul>
</aside>
</section>
<section>
<h3>Sum(x)</h3>
<div>\[
\begin{aligned}
\sum_{n=0}^{x}n &amp;&equiv; \frac{x(x + 1)}{2} \\
&amp;&equiv; x + \frac{x(x - 1)}{2}
\end{aligned}
\]
</div>
</section>
</section>
<section id="compilersAreSuperSmart2">
<section><h3>What else has my compiler<br>done for me lately?</h3></section>
<section>
<h3>Functions</h3>
<div class="left-pane">
<pre><code class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
// setup
#include &lt;vector>
using namespace std;
int someFunc(int);
int sum(const vector&lt;int> &v) {
int result = 0;
for (size_t i = 0;
i &lt; v.size(); ++i)
result += someFunc(v[i]);
return result;
}</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-trim>
.L3:
mov edi, DWORD PTR [rdx+rbx*4]
inc rbx
call someFunc(int)
mov rdx, QWORD PTR [rbp+0]
add r12d, eax
mov rax, QWORD PTR [rbp+8]
sub rax, rdx
sar rax, 2
cmp rbx, rax
jb .L3
</code></pre>
</div>
<a class="fragment" target="_blank"
href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:2.5,j:1,lang:c%2B%2B,source:'//+setup%0A++%23include+%3Cvector%3E%0A++%23include+%3Cnumeric%3E%0A++using+namespace+std%3B%0Aint+someFunc(int)%3B%0Aint+sum(const+vector%3Cint%3E+%26v)+%7B%0A++return+accumulate(%0A++++begin(v),+end(v),+0,%0A++++%5B%5D(int+x,+int+y)+%7B+%0A++++++return+x+%2B+someFunc(y)%3B+%0A++%7D)%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g81,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',trim:'0'),fontScale:3,lang:c%2B%2B,libs:!(),options:'-O2+-std%3Dc%2B%2B1z+-march%3Dhaswell',source:1),l:'5',n:'0',o:'x86-64+gcc+8.1+(Editor+%231,+Compiler+%231)+C%2B%2B',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4">Accumulate
version</a>
<aside class="notes">
Compiler can't make any assumptions about someFunc. So has to reload size.
Even though vector is const, compiler can't assume it's not going to change.
Using range-for fixes issue as range-for is defined to copy the extents of the iterand outside of
loop.
</aside>
</section>
<section>
<h3>Aliasing 1/2</h3>
<div class="left-pane">
<pre><code class="cpp ce" data-noescape>
/// g81:-O2 -std=c++1z -march=haswell
// Worst API ever...
void sumToFirstZero(
int *first, int &num,
int &sum) {
sum = 0;
int i;
for (i = 0; i < num; ++i) {
if (first[i] == 0) break;
sum += first[i];
}
num = i;
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-trim>
.L4:
inc rax
mov ecx, DWORD PTR [rdi-4+rax*4]
test ecx, ecx
je .L2
.L3:
add r8d, ecx
mov r9d, eax
mov DWORD PTR [rdx], r8d
cmp DWORD PTR [rsi], eax
jg .L4
</code></pre>
</div>
<a class="fragment" target="_blank"
href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:2.5,j:1,lang:c%2B%2B,source:'struct+Result+%7B%0A++int+sum%3B%0A++int+lastNonZero%3B%0A%7D%3B%0AResult+sumToFirstZero(%0A++++const+int+*first,+int+num)+%7B%0A++Result+r%7B0,0%7D%3B%0A++int+i%3B%0A++for+(i+%3D+0%3B+i+%3C+num%3B+%2B%2Bi)+%7B%0A++++if+(first%5Bi%5D+%3D%3D+0)+break%3B%0A++++r.sum+%2B%3D+first%5Bi%5D%3B%0A++%7D%0A++r.lastNonZero+%3D+i%3B%0A++return+r%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g81,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',trim:'0'),fontScale:3,lang:c%2B%2B,libs:!(),options:'-O2+-std%3Dc%2B%2B1z+-march%3Dhaswell',source:1),l:'5',n:'0',o:'x86-64+gcc+8.1+(Editor+%231,+Compiler+%231)+C%2B%2B',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4">Alternative
implementation</a>
</section>
<section>
<h3>Aliasing 2/2</h3>
<div class="left-pane">
<pre><code class="cpp ce" data-noescape>
/// g81:-O3 -std=c++1z -march=haswell
void maxArray(double* x, double* y) {
for (int i = 0; i < 65536; i++) {
if (y[i] > x[i])
x[i] = y[i];
}
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-trim>
maxArray(double*, double*):
lea rax, [rsi+32]
cmp rdi, rax
jnb .L10
lea rax, [rdi+32]
cmp rsi, rax
jb .L9
...
</code></pre>
</div>
<a class="fragment" target="_blank"
href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:2.5,j:1,lang:c%2B%2B,source:'void+maxArray(double*+__restrict+x,%0A++++++++++++++double*+__restrict+y)+%7B%0A++for+(int+i+%3D+0%3B+i+%3C+65536%3B+i%2B%2B)+%7B%0A++++x%5Bi%5D+%3D+((y%5Bi%5D+%3E+x%5Bi%5D)+%3F+y%5Bi%5D+:+x%5Bi%5D)%3B%0A++%7D%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g81,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',trim:'0'),fontScale:3,lang:c%2B%2B,libs:!(),options:'-O3+-std%3Dc%2B%2B1z+-march%3Dhaswell',source:1),l:'5',n:'0',o:'x86-64+gcc+8.1+(Editor+%231,+Compiler+%231)+C%2B%2B',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4">Better</a>
</section>
<section><h3>Heap elision</h3>
<pre><code data-trim class="cpp ce">
/// g81:-O2 -std=c++1z -march=haswell
// setup
#include &lt;memory>
using namespace std;
int func() {
auto a = make_unique&lt;int>(42);
auto b = make_unique&lt;int>(24);
return *a + *b;
}
</code></pre>
</section>
<section><h3>Ternary operator</h3>
<div class="left-pane">
<pre><code class="cpp ce" data-trim>
/// g81:-O2 -std=c++1z -march=haswell
int func(int i) {
return (i < 0) ? 1234 : 5678;
}
</code></pre>
</div>
<div class="right-pane">
<pre><code class="x86asm" data-noescape data-trim>
func(int):
mov eax, edi
sar eax, 31
and eax, -4444
add eax, 5678
ret
</code></pre>
</div>
</section>
<section><h3>Virtual methods</h3>
<pre><code class="cpp ce">
/// g81:-O2 -std=c++1z
// setup
#include &lt;vector>
using namespace std;
struct Coster { virtual int costFor(int x) = 0; };
int totalCost(Coster &coster,
const vector&lt;int> &v) {
int result = 0;
for (auto i : v)
result += coster.costFor(i);
return result;
}
</code></pre>
</section>
<section>
<h3>What has my compiler done for me lately?</h3>
<div class="fragment">A lot!</div>
</section>
</section>
<!------------------------------------------------------->
<section id="howitworks">
<section>
<h3>How it works</h3>
<img src="images/kirk.jpeg" height="600px">
</section>
<section>
<h3>How it works - Backend</h3>
<ul>
<li>Written in <code>node.js</code></li>
<li>Runs on Amazon</li>
</ul>
</section>
<section>
<h3><code>node.js</code></h3>
<pre class="smaller"><code class="javascript" data-trim>
function compile(req, res, next) {
// exec compiler, feed it req.body, parse output
}
var webServer = express();
var apiHandler = express.Router();
apiHandler.param('compiler',
function (req, res, next, compiler) {
req.compiler = compiler;
next();
});
apiHandler.post('/compiler/:compiler/compile', compile);
webServer.use('/api', apiHandler);
webServer.listen(10240);
</code></pre>
</section>
<section>
<h3>Amazon EC2</h3>
<ul>
<li>Edge cache</li>
<li>Load balancer</li>
<li>Virtual machines</li>
<li>Docker images</li>
<li>Shared compiler storage</li>
</ul>
</section>
<section>
<h3>Amazon EC2</h3>
<img src="images/EC2.png">
</section>
<section>
<h3>The compilers</h3>
<ul>
<li>Built through docker images</li>
<li>Compilers stored on S3</li>
<li>OSS ones publically available</li>
<li>MS compilers via WINE</li>
</ul>
<aside class="notes">
60+ GB of compilers currently
</aside>
</section>
<section>
<h3>How it works - security</h3>
<ul>
<li>Compilers: huge attack vector</li>
<li>Principle of "what's the worst could happen"</li>
<li>Docker</li>
<li><code>LD_PRELOAD</code></li>
</ul>
<aside class="notes">
Known attacks:
* crash clang leaving temporary file, filename in crash dump, load temporary file using compiler
plugin
* crash compiler with temporary file (the input) in /tmp, use it as a specs file
</aside>
</section>
<section>
<h3>How it works - Frontend</h3>
<ul>
<li>Microsoft's Monaco</li>
<li>GoldenLayout</li>
</ul>
</section>
<section>
<h3>The code</h3>
<ul>
<li>
<a href="https://github.com/mattgodbolt/compiler-explorer">github.com/mattgodbolt/compiler-explorer</a>
</li>
<li><a href="https://github.com/mattgodbolt/compiler-explorer-image">github.com/mattgodbolt/compiler-explorer-image</a>
</li>
<li class="fragment">Running locally is easy!<br>
<pre>$ make</pre>
</li>
</ul>
</section>
</section>
<!------------------------------------------------------->
<section id="conclusions">
<section>
<h3>Usage</h3>
<iframe src="https://www.stathat.com/s/QM805B71geQ0" width="800px" height="500px"></iframe>
</section>
<section>
<h3>Other uses</h3>
<ul>
<li>Code pastebin</li>
<li>Compiler development</li>
<li>C++ REPL</li>
<li>Training resource</li>
</ul>
<aside class="notes">
<ul>
<li>160 bugs in GCC tracker refer to godbolt.org</li>
<li>104 in clang</li>
</ul>
</aside>
</section>
<section>
<h3>Coming soon...</h3>
<ul>
<li>Execution support</li>
</ul>
</section>
<section>
<h3>Thanks</h3>
<ul>
<li>Thanks to contributors:
<ul>
<li>Rubén Rincón</li>
<li>Jared Wyles, Partouf, Simon Brand, Chedy Najjar,<br>
Filipe Cabecinhas, Johan Engelen...and the rest!</li>
</ul>
</li>
<li>Thanks to Patreon folks</li>
<li>Thanks to awesome C++ community</li>
<li class="fragment">Thanks to you!</li>
</ul>
</section>
<section>
<h3>Go read some assembly!</h3>
<br>
<div>
<a href="https://godbolt.org/">godbolt.org</a>
</div>
<div class="footnote fragment"><h6>(And thank a compiler developer)</h6></div>
</section>
</section>
</section>
</div>
<script src="reveal.js/lib/js/head.min.js"></script>
<script src="reveal.js/js/reveal.js"></script>
<script>
Reveal.initialize({
transition: 'none',
history: true,
slideNumber: true,
width: 1280,
height: 720,
math: {config: 'TeX-AMS_HTML-full'},
dependencies: [
{src: 'reveal.js/plugin/markdown/marked.js'},
{src: 'reveal.js/plugin/markdown/markdown.js'},
{src: 'reveal.js/plugin/math/math.js'},
{src: 'reveal.js/plugin/notes/notes.js', async: true},
{
src: 'reveal.js/plugin/highlight/highlight.js', async: true,
callback: function () {
hljs.initHighlightingOnLoad();
}
},
{
src: 'compiler-explorer.js',
async: true
}
]
});
</script>
</body>
</html>