<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>48Bits Blog &#187; compiladores</title>
	<atom:link href="http://blog.48bits.com/category/compiladores/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.48bits.com</link>
	<description>48Bits ... The one and a half architecture land.</description>
	<lastBuildDate>Sun, 29 Aug 2010 13:02:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Código muerto</title>
		<link>http://blog.48bits.com/2009/11/07/codigo-muerto/</link>
		<comments>http://blog.48bits.com/2009/11/07/codigo-muerto/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 09:53:34 +0000</pubDate>
		<dc:creator>erg0t</dc:creator>
				<category><![CDATA[compiladores]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=730</guid>
		<description><![CDATA[Hola amigos digitales, hoy vamos a hablar de un pequeño problema de optimización en Visual C. Seguramente ya conozcan lo que es la eliminación de código muerto, pero por las dudas (y para que este post llegue al menos a las 10 lineas) voy a hacer una breve explicación. Dead code elimination es una optimización [...]]]></description>
			<content:encoded><![CDATA[<p>Hola amigos digitales, hoy vamos a hablar de un pequeño problema de optimización en Visual C.</p>
<p>Seguramente ya conozcan lo que es la eliminación de código muerto, pero por las dudas (y para que este post llegue al menos a las 10 lineas) voy a hacer una breve explicación.</p>
<p><strong>Dead code elimination</strong> es una optimización muy utilizada que se encarga de eliminar código que realmente no afecta al programa. Por ejemplo, si tenemos:</p>
<div class="dean_ch" style="white-space: wrap;">
x |= <span class="nu0">1</span>;<br />
x &gt;&gt;= <span class="nu0">1</span>;<br />
&nbsp;</div>
<p>El compilador eliminara el or ya que ese bit se perderá cuando se realice el shift. Entendido esto sigamos con los nuestro&#8230;</p>
<p><span id="more-730"></span>A partir de C99 (o por extensiones en algunos compiladores) existe el tipo &#8220;long long&#8221; que es de al menos 64bits. El tema es que en arquitecturas de 32bits el compilador debe seccionar este tipo en dos y generar código para trabajar como si se tratase de un solo valor de 64bits.<br />
Curiosamente parece que el VC no se preocupa mucho por optimizar este tipo de código, consideremos el siguiente ejemplo:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &lt;stdio.h&gt;</span></p>
<p><span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">char</span> *argv<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> x = atoi<span class="br0">&#40;</span>argv<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw4">unsigned</span> __int64 y, z = strtoui64<span class="br0">&#40;</span>argv<span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>, <span class="kw2">NULL</span>, <span class="nu0">10</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; y = <span class="br0">&#40;</span><span class="kw4">unsigned</span> __int64<span class="br0">&#41;</span> x;<br />
&nbsp; z -= <span class="nu0">2</span>;</p>
<p>&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>z &lt; y<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span>;</p>
<p>&nbsp; <span class="kw1">return</span> <span class="nu0">0</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>He utilizado las llamadas a atoi y strtoui64 por no poner valores constantes, ya que necesitamos compilar el código con optimizaciones y si se aplica propagación de valores se terminaría eliminando todo el código.</p>
<p>En este ejemplo se toma un entero de 32 bits y se convierte a un entero sin signo de 64bits, luego te toma otro entero sin signo de 64 y se le resta 2, por útlimo se comparan las dos variables.</p>
<p>Utilizando Visual Studio 2k8 y compilando con /O2, se genera el siguiente código:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co1">; Line 4</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">esi</span><br />
<span class="co1">; Line 5</span><br />
<span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">esi</span>, <span class="kw5">DWORD</span> <span class="kw4">PTR</span> _argv$<span class="br0">&#91;</span><span class="kw3">esp</span><span class="br0">&#93;</span><br />
<span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="br0">&#91;</span>esi<span class="nu0">+4</span><span class="br0">&#93;</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">edi</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">eax</span><br />
<span class="kw1">call</span> &nbsp; &nbsp;_atoi<br />
<span class="co1">; Line 6</span><br />
<span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">ecx</span>, <span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="br0">&#91;</span>esi<span class="nu0">+8</span><span class="br0">&#93;</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="nu0">10</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">; 0000000aH</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="nu0">0</span><br />
<span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">ecx</span><br />
<span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">edi</span>, <span class="kw3">eax</span><br />
<span class="kw1">call</span> &nbsp; &nbsp;_strtoui64<br />
<span class="co1">; Line 11</span><br />
<span class="kw1">cdq</span><br />
<span class="kw1">add</span> &nbsp; &nbsp; <span class="kw3">esp</span>, <span class="nu0">16</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">; 00000010H</span><br />
<span class="kw1">add</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="nu0">-2</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">; fffffffeH</span><br />
<span class="kw1">adc</span> &nbsp; &nbsp; <span class="kw3">edx</span>, <span class="nu0">-1</span><br />
<span class="kw1">xor</span> &nbsp; &nbsp; <span class="kw3">ecx</span>, <span class="kw3">ecx</span><br />
<span class="kw1">cmp</span> &nbsp; &nbsp; <span class="kw3">edx</span>, <span class="kw3">ecx</span><br />
<span class="kw1">ja</span> &nbsp; &nbsp; &nbsp;<span class="kw4">SHORT</span> $LN1@main<br />
<span class="kw1">jb</span> &nbsp; &nbsp; &nbsp;<span class="kw4">SHORT</span> $LN4@main<br />
<span class="kw1">cmp</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="kw3">edi</span><br />
<span class="kw1">jae</span> &nbsp; &nbsp; <span class="kw4">SHORT</span> $LN1@main<br />
$LN4@main:<br />
<span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">edi</span><br />
<span class="co1">; Line 12</span><br />
<span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="nu0">1</span><br />
<span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">esi</span><br />
<span class="co1">; Line 15</span><br />
<span class="kw1">ret</span> &nbsp; &nbsp; <span class="nu0">0</span><br />
$LN1@main:<br />
<span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">edi</span><br />
<span class="co1">; Line 14</span><br />
<span class="kw1">xor</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="kw3">eax</span><br />
<span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">esi</span><br />
<span class="co1">; Line 15</span><br />
<span class="kw1">ret</span> &nbsp; &nbsp; <span class="nu0">0</span><br />
&nbsp;</div>
<p>Podemos observar que el par <strong><span style="color: #800000;">edx:eax</span></strong> representa <strong><span style="color: #800000;">z</span></strong>, <strong><span style="color: #000080;">edi</span></strong> representa <strong><span style="color: #000080;">x</span></strong> y <strong><span style="color: #008000;">ecx:edi</span></strong> a <strong><span style="color: #008000;">y</span></strong>. Por lo tanto la expresión <strong>z &lt; y</strong> es equivalente a <strong>edx:eax &lt; ecx:edi</strong>.</p>
<p>Para realizar la comparación tenemos realmente un máximo de tres expresiones a evaluar:</p>
<ul>
<li><strong>edx &gt; ecx</strong>: si la expresión es verdadera evitamos el resto de las comparaciones.</li>
<li><strong>edx &lt; ecx</strong>: si la expresión es verdadera sabemos evitamos la comparación final.</li>
</ul>
<p>En este punto sabemos que <strong>edx == ecx</strong> y procedemos a comparar la parte menos significativa de las dos variables:</p>
<ul>
<li><strong>eax &lt; edi</strong>: el resultado de esta expresión determinara si <strong>z &lt; y</strong>.</li>
</ul>
<p>Hasta aquí todo perfecto para comparar dos variables de 64bits, el problema es que el VC no se da cuenta de algunos casos particulares, como el de este ejemplo donde uno de los valores se obtiene a partir de un cast de un valor de 32bits. El cast garantiza que la parte alta va a ser siempre cero por lo que se puede reducir la cantidad de expresiones. VC no solo no se da cuenta, sino que ademas genera el caso imposible <strong>edx &lt; 0</strong>.</p>
<p>Para este tipo de casos el compilador debería reducir el código a un máximo de dos expresiones:</p>
<ul>
<li><strong>edx != 0</strong>: si es verdadero se evita la segunda comparación.</li>
<li><strong>eax &lt; edi</strong></li>
</ul>
<p>Para cerrar, he probado un código similar en gcc 4.3.3 con flag -O2:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &lt;stdio.h&gt;</span></p>
<p><span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">char</span> *argv<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> x = atoi<span class="br0">&#40;</span>argv<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> y, z = atoll<span class="br0">&#40;</span>argv<span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; y = <span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span><span class="br0">&#41;</span> x;<br />
&nbsp; z -= <span class="nu0">2</span>;</p>
<p>&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>z &lt; y<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span>;</p>
<p>&nbsp; <span class="kw1">return</span> <span class="nu0">0</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>El resultado fue:</p>
<div class="dean_ch" style="white-space: wrap;">
main:<br />
leal &nbsp; &nbsp;<span class="nu0">4</span><span class="br0">&#40;</span>%<span class="kw3">esp</span><span class="br0">&#41;</span>, %<span class="kw3">ecx</span><br />
andl &nbsp; &nbsp;$<span class="nu0">-16</span>, %<span class="kw3">esp</span><br />
pushl &nbsp; <span class="nu0">-4</span><span class="br0">&#40;</span>%<span class="kw3">ecx</span><span class="br0">&#41;</span><br />
pushl &nbsp; %<span class="kw3">ebp</span><br />
movl &nbsp; &nbsp;%<span class="kw3">esp</span>, %<span class="kw3">ebp</span><br />
subl &nbsp; &nbsp;$<span class="nu0">24</span>, %<span class="kw3">esp</span><br />
movl &nbsp; &nbsp;%<span class="kw3">ecx</span>, <span class="nu0">-12</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span><br />
movl &nbsp; &nbsp;%<span class="kw3">esi</span>, <span class="nu0">-4</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span><br />
movl &nbsp; &nbsp;%<span class="kw3">ebx</span>, <span class="nu0">-8</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span><br />
movl &nbsp; &nbsp;<span class="nu0">4</span><span class="br0">&#40;</span>%<span class="kw3">ecx</span><span class="br0">&#41;</span>, %<span class="kw3">ebx</span><br />
movl &nbsp; &nbsp;<span class="nu0">4</span><span class="br0">&#40;</span>%<span class="kw3">ebx</span><span class="br0">&#41;</span>, %<span class="kw3">eax</span><br />
movl &nbsp; &nbsp;%<span class="kw3">eax</span>, <span class="br0">&#40;</span>%<span class="kw3">esp</span><span class="br0">&#41;</span><br />
<span class="kw1">call</span> &nbsp; &nbsp;atoi<br />
movl &nbsp; &nbsp;%<span class="kw3">eax</span>, %<span class="kw3">esi</span><br />
movl &nbsp; &nbsp;<span class="nu0">8</span><span class="br0">&#40;</span>%<span class="kw3">ebx</span><span class="br0">&#41;</span>, %<span class="kw3">eax</span><br />
movl &nbsp; &nbsp;%<span class="kw3">eax</span>, <span class="br0">&#40;</span>%<span class="kw3">esp</span><span class="br0">&#41;</span><br />
<span class="kw1">call</span> &nbsp; &nbsp;atoll<br />
movl &nbsp; &nbsp;$<span class="nu0">1</span>, %<span class="kw3">ecx</span><br />
movl &nbsp; &nbsp;%<span class="kw3">eax</span>, %<span class="kw3">edx</span><br />
sarl &nbsp; &nbsp;$<span class="nu0">31</span>, %<span class="kw3">edx</span><br />
addl &nbsp; &nbsp;$<span class="nu0">-2</span>, %<span class="kw3">eax</span><br />
adcl &nbsp; &nbsp;$<span class="nu0">-1</span>, %<span class="kw3">edx</span><br />
testl &nbsp; %<span class="kw3">edx</span>, %<span class="kw3">edx</span><br />
<span class="kw1">jne</span> &nbsp; &nbsp; .L3<br />
cmpl &nbsp; &nbsp;%<span class="kw3">eax</span>, %<span class="kw3">esi</span><br />
<span class="kw1">jbe</span> &nbsp; &nbsp; .L3<br />
.L2:<br />
movl &nbsp; &nbsp;%<span class="kw3">ecx</span>, %<span class="kw3">eax</span><br />
movl &nbsp; &nbsp;<span class="nu0">-12</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span>, %<span class="kw3">ecx</span><br />
movl &nbsp; &nbsp;<span class="nu0">-8</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span>, %<span class="kw3">ebx</span><br />
movl &nbsp; &nbsp;<span class="nu0">-4</span><span class="br0">&#40;</span>%<span class="kw3">ebp</span><span class="br0">&#41;</span>, %<span class="kw3">esi</span><br />
movl &nbsp; &nbsp;%<span class="kw3">ebp</span>, %<span class="kw3">esp</span><br />
popl &nbsp; &nbsp;%<span class="kw3">ebp</span><br />
leal &nbsp; &nbsp;<span class="nu0">-4</span><span class="br0">&#40;</span>%<span class="kw3">ecx</span><span class="br0">&#41;</span>, %<span class="kw3">esp</span><br />
<span class="kw1">ret</span><br />
.p2align <span class="nu0">4</span>,,<span class="nu0">7</span><br />
.p2align <span class="nu0">3</span><br />
.L3:<br />
xorl &nbsp; &nbsp;%<span class="kw3">ecx</span>, %<span class="kw3">ecx</span><br />
<span class="kw1">jmp</span> &nbsp; &nbsp; .L2<br />
&nbsp;</div>
<p>Como se puede observar el gcc realiza este tipo de optimizaciones.<br />
Bueno eso fue todo el trolling por hoy, saludos digitales <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2009/11/07/codigo-muerto/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
