{"id":18,"date":"2011-07-03T13:43:00","date_gmt":"2011-07-03T17:43:00","guid":{"rendered":"http:\/\/brian.digitalmaddox.com\/blog\/?p=18"},"modified":"2014-07-08T16:45:48","modified_gmt":"2014-07-08T20:45:48","slug":"fun-with-compilers-2-optimizations","status":"publish","type":"post","link":"https:\/\/brian.digitalmaddox.com\/blog\/?p=18","title":{"rendered":"Fun with Compilers 2: Optimizations"},"content":{"rendered":"<p>For my second post about compilers, I thought I&#8217;d show what happens with various optimization levels in <a href=\"http:\/\/gcc.gnu.org\/\">GCC<\/a>. \u00a0Note I&#8217;m still focusing on gcc because I&#8217;m too lazy to fire up VirtualBox and Windows right now.<\/p>\n<p>As a reminder from the first, here&#8217;s my wonderfully useless sample program. \u00a0All it does is go through a loop and does not use the output.<\/p>\n<blockquote><p><span>int main(int argc, char* argv[])<br \/>{<br \/>\u00a0 int i = 0;<br \/>\u00a0 int loop;<br \/>\u00a0<br \/>\u00a0 for (loop = 0; loop < 50; loop++)<br \/>\u00a0 \u00a0 ++i;<br \/>\u00a0 return 0;<br \/>}<\/span><\/p><\/blockquote>\n<div>So last time they were purposely compiled without optimization as I just wanted a quick and dirty assembler output. \u00a0Below we&#8217;ll examine the assembly output at different optimization levels of just the main function, as that&#8217;s the one we&#8217;re more interested in (there are actually more sections in an <a href=\"http:\/\/en.wikipedia.org\/wiki\/Executable_and_Linkable_Format\">ELF<\/a> executable, but that&#8217;s a story for another day).<\/div>\n<p>The option flag -O1 turns on the first level of optimizations in gcc\/g++. \u00a0Instead of copying them here, I&#8217;ll refer you to the GNU <a href=\"http:\/\/gcc.gnu.org\/onlinedocs\/gcc-4.5.3\/gcc\/Optimize-Options.html#Optimize-Options\">manpage<\/a> for optimizations for gcc\/g++.<\/p>\n<p><i><b>gcc -O1 main.c -o main_c1<\/b><\/i><\/p>\n<blockquote><p><span>main():<br \/>55 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>push \u00a0 ebp<br \/>89 e5 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span> <\/span>mov \u00a0 \u00a0ebp,esp<br \/>b8 32 00 00 00 \u00a0 \u00a0 \u00a0 <span> <\/span>mov \u00a0 \u00a0eax,0x32<br \/>83 e8 01 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>sub \u00a0 \u00a0eax,0x1<br \/>75 fb \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span> <\/span>jne \u00a0 \u00a0804839c <main+0x8><br \/>b8 00 00 00 00 \u00a0 \u00a0 \u00a0 <span> <\/span>mov \u00a0 \u00a0eax,0x0<br \/>5d \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>pop \u00a0 \u00a0ebp<br \/>c3 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>ret \u00a0 <br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>90 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<\/span><\/p><\/blockquote>\n<p>Compared to the previous post (no optimization), we see here that the assembly is better optimized. \u00a0This version does not allocate space for the local variables <i>i<\/i> and <i>loop,<\/i>set them to zero,\u00a0\u00a0and increment <i>loop<\/i> and <i>i<\/i> at each pass. Instead, it loads 50 into the EAX register, subtracts 1, and checks if the zero flag is set. \u00a0If not, it loops back to the subtraction and continues until it reaches zero. \u00a0It then nukes it&#8217;s local stack and returns while being padded out (again, I&#8217;ll go over that another day). \u00a0As we turn more optimization on, the compiler does more analysis and realizes that it doesn&#8217;t need to increment the variables since we&#8217;re not doing anything with them. \u00a0For brevity, note that the assembly output from g++ is identical to the main function from gcc.<\/p>\n<p><b>gcc -O2 main.c -o main_c1<\/b><\/p>\n<p>At -O2, the compiler does even more analysis and has more &#8220;smarts&#8221; turned on. \u00a0Let&#8217;s look at the assembler output below.<\/p>\n<blockquote><p><span>main():<br \/>\u00a055 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>push \u00a0 ebp<br \/>\u00a031 c0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span> <\/span>xor \u00a0 \u00a0eax,eax<br \/>\u00a089 e5 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span> <\/span>mov \u00a0 \u00a0ebp,esp<br \/>\u00a05d \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>pop \u00a0 \u00a0ebp<br \/>\u00a0c3 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>ret \u00a0 <br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<br \/>\u00a090 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span> <\/span>nop<\/span><\/p><\/blockquote>\n<p>Here the compiler realized that nothing is done with the variables, and nothing was done with the output. \u00a0So, the compiler doesn&#8217;t even do the loop any more. \u00a0It still pushes the stack frame pointer. \u00a0It moves 0 into EAX (the <i>xor eax,eax<\/i> generates shorter op codes and is a touch faster than actually pushing zero there). \u00a0It still sets up the stack frame (main is a function after all) and then brings back the previous frame and returns. \u00a0Again, with optimization the g++ assembly matches the gcc output for main(). \u00a0gcc\/g++ -O3 generates the same output as -O2. <\/p>\n<p>You might ask yourself &#8220;Why do the compilers even set up the stack frame for the main function?&#8221; \u00a0The answer is, they have to. \u00a0main() HAS to exist in a C or C++ program, even if it really doesn&#8217;t do anything.<\/p>\n<p>So have fun, and poke around your programs to see what all gets generated from the compiler. \u00a0You&#8217;ll see that there&#8217;s a lot more in your program than you realized. \u00a0Plus, the <a href=\"http:\/\/webster.cs.ucr.edu\/AoA\/Linux\/PDFs\/0_PDFIndexLinux.html\">Art of Assembly Language is now available in a Linux version<\/a> if you want a decent reference to learn assembler.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For my second post about compilers, I thought I&#8217;d show what happens with various optimization levels in GCC. \u00a0Note I&#8217;m still focusing on gcc because I&#8217;m too lazy to fire up VirtualBox and Windows right now. As a reminder from &hellip; <a href=\"https:\/\/brian.digitalmaddox.com\/blog\/?p=18\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-18","post","type-post","status-publish","format-standard","hentry","category-compilers-g-gcc"],"_links":{"self":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/18","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=18"}],"version-history":[{"count":0,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/18\/revisions"}],"wp:attachment":[{"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=18"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=18"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brian.digitalmaddox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}