Lamento elgarbe por desvirtuarte el tema y espero que Bruno le guste el ASM xD
Jugando ahora si con las compilaciones..
Bruno, Cree el codigo que me dijiste, en realidad hice esto en CCS (TI tiene su propio compilador), NO ES GCC pero es lo que mas tenia a mano. Y es para un ARMv7-M ( M4F )
Una cosa mas.. puede que los resultados no sean exactos en la parte con optimizacion, especialmente en la parte de volatile, por que la funcion que cree Explota() en si no sirve para nada. Y que tal ves eso es lo que hace que quite esta funcion. Mas adelante voy a crear otra funcion Explota() y veremos la diferencia.
#include <stdint.h>
void Explota(void);
volatile uint8_t activarBomba = 0;
void main(void) {
while(1)
{
activarBomba = 0;
if(activarBomba)
{
Explota();
}
}
}
void Explota(void)
{
int i = 3;
int j = 1;
i += j;
j += i;
}
static void IntDefaultHandler(void)
{
activarBomba = 1;
}
--------------------------------------
Luego de creado el C, compilado con distintas versiones y optimizaciones , procedi a hacerle un dissasembly con el objdump, a la derecha estan los comentarios intentando traducirlo a "C", obtuve lo siguiente:
Sin optimizaciones (CON volatile): (Si quieren omitan estos 2 que son largos y procedan al resultado)
00000498 <main>: ; void main(void) {
498: b508 push {r3, lr} ;
49a: ea4f 0808 mov.w r8, r8 ;
49e: 46c0 nop ;
4a0: f240 2114 movw r1, #532 ; while(1) {
4a4: 2000 movs r0, #0 ;
4a6: f2c2 0100 movt r1, #8192 ;
4aa: 7008 strb r0, [r1, #0] ; activaBomba = 0;
4ac: f240 2014 movw r0, #532 ;
4b0: f2c2 0000 movt r0, #8192 ;
4b4: 7800 ldrb r0, [r0, #0] ; <-- lee de memoria
4b6: 2800 cmp r0, #0 ; if(activaBomba)
4b8: d0f2 beq.n 4a0 <main+0x8> ; activaBomba es 0 salta a 0x4A0
4ba: f000 f801 bl 4c0 <Explota> ; activaBomba es 1 salta a 0x4C0 ( Explota )
4be: e7ef b.n 4a0 <main+0x8> ; } Fin del while(1)
000004c0 <Explota>: ; void Explota(void) {
4c0: f1ad 0d08 sub.w sp, sp, #8 ; // Espacio para las variables
4c4: 2003 movs r0, #3 ; i = 3;
4c6: 9000 str r0, [sp, #0] ;
4c8: 2001 movs r0, #1 ; j = 1;
4ca: 9001 str r0, [sp, #4] ;
4cc: 9900 ldr r1, [sp, #0] ;
4ce: 9801 ldr r0, [sp, #4] ;
4d0: 1840 adds r0, r0, r1 ; j += i;
4d2: 9000 str r0, [sp, #0] ;
4d4: 9901 ldr r1, [sp, #4] ;
4d6: 9800 ldr r0, [sp, #0] ;
4d8: 1840 adds r0, r0, r1 ; i += j ;
4da: 9001 str r0, [sp, #4] ;
4dc: b002 add sp, #8 ; // Retorno el Stack Pointer al lugar de antes
4de: 4770 bx lr ; } // Fin Explota();
00000540 <IntDefaultHandler>:
540: f240 2114 movw r1, #532 ; Interrupcion() {
544: 2001 movs r0, #1 ;
546: f2c2 0100 movt r1, #8192 ;
54a: 7008 strb r0, [r1, #0] ; activaBomba = 1;
54c: 4770 bx lr ; }
--------------------------------------------
Sin optimizaciones ( SIN volatile )00000498 <main>: ; void main(void) {
498: b508 push {r3, lr}
49a: ea4f 0808 mov.w r8, r8
49e: 46c0 nop ;
4a0: f240 2114 movw r1, #532 ; while(1) {
4a4: 2000 movs r0, #0 ;
4a6: f2c2 0100 movt r1, #8192 ;
4aa: 7008 strb r0, [r1, #0] ; activaBomba = 0;
4ac: f240 2014 movw r0, #532 ;
4b0: f2c2 0000 movt r0, #8192 ;
4b4: 7800 ldrb r0, [r0, #0] ; <-- lee de memoria
4b6: 2800 cmp r0, #0 ; if (activaBomba) {
4b8: d0f2 beq.n 4a0 <main+0x8> ; Igual a 0: Comienza el while de nuevo
4ba: f000 f801 bl 4c0 <Explota> ; Igual a 1: Explota
4be: e7ef b.n 4a0 <main+0x8> ; } Fin del while } Fin de main
000004c0 <Explota>: ; void Explota(void) {
4c0: f1ad 0d08 sub.w sp, sp, #8 ;
4c4: 2003 movs r0, #3
4c6: 9000 str r0, [sp, #0] ; i = 3;
4c8: 2001 movs r0, #1
4ca: 9001 str r0, [sp, #4] ; j = 1
4cc: 9900 ldr r1, [sp, #0]
4ce: 9801 ldr r0, [sp, #4]
4d0: 1840 adds r0, r0, r1 ; j += i;
4d2: 9000 str r0, [sp, #0]
4d4: 9901 ldr r1, [sp, #4]
4d6: 9800 ldr r0, [sp, #0]
4d8: 1840 adds r0, r0, r1 ; i += j;
4da: 9001 str r0, [sp, #4]
4dc: b002 add sp, #8
4de: 4770 bx lr ; } Fin Explota()
00000540 <IntDefaultHandler>: ; void Interrupt() {
540: f240 2114 movw r1, #532 ;
544: 2001 movs r0, #1
546: f2c2 0100 movt r1, #8192 ; 0x2000
54a: 7008 strb r0, [r1, #0] ; activaBomba = 1;
54c: 4770 bx lr ; }
Resultado: Hasta aqui se puede ver que SIN o CON volatile , si uno NO usa las optimizaciones es lo mismo. Y el codigo definitivamente es HORRIBLE.
----------------------------------------------
Optimizacion maxima y optimizado a velocidad , SIN volatile000004e0 <IntDefaultHandler>: ; void Interrupt() {
4e0: f240 2114 movw r1, #532 ;
4e4: 2001 movs r0, #1
4e6: f2c2 0100 movt r1, #8192 ;
4ea: 7008 strb r0, [r1, #0] ; activaBomba = 1
4ec: 4770 bx lr
4ee: 46c0 nop ; }
00000520 <main>: ; void main() {
520: e7fe b.n 520 <main> ; while(1); } // Fin de main
Resultado: Esta fue la mas reveladora. el main, esta formado por un while(true) nomas. Se observa ademas que Explota() desaparecio, ni siquiera existe. Ya que lo unico que hacia era poner una crear 2 varaibles dentro del scope de la funcion sumarlas y nada mas, es decir no se usaban para nada. Y el optimizador procedio a eliminarlas.
---------------------------------------------
Optimizacion maxima y optimizado a velocidad , CON volatile000004e0 <IntDefaultHandler>: ; void Interrupt(void) {
4e0: f240 2114 movw r1, #532 ;
4e4: 2001 movs r0, #1
4e6: f2c2 0100 movt r1, #8192 ;
4ea: 7008 strb r0, [r1, #0] ; activaBomba = 1
4ec: 4770 bx lr
4ee: 46c0 nop ; }
00000510 <main>: ; void main(void) {
510: f240 2114 movw r1, #532 ; 0x214
514: 2200 movs r2, #0
516: f2c2 0100 movt r1, #8192 ; 0x2000
51a: ea4f 0808 mov.w r8, r8
51e: 46c0 nop ;
520: 700a strb r2, [r1, #0] ; while(1) {
522: 7808 ldrb r0, [r1, #0] ; activaBomba=0; R0 = ???? pero que no lleva a ningun lado
524: e7fc b.n 520 <main+0x10> ; }
Resultado: Con volatile cambia, Esta ves pone nuestra variable en 0, pero imagino que debido a que Explota() es una funcion sin "sentido" por lo que explique antes, lo elimino. Y por ende el if() quedaba vacio dentro, por lo cual procedio tambien procedio a eliminarlo.
EDIT: Por favor leer la respuesta de BrunoF luego de este post, explicando esta instruccionDel ASM lo unico que no puedo identificar es que esta tomando y poniendo en R0, ya que en 0x214 hay una instruccion y no un dato:
214: 0783 lsls r3, r0, #30
De todas formas no usa R0 dentro del loop del while(1) y queda como una instruccion "extra", tal ves sea por el pipeline y no tener intruccion-salto-intruccion-salto.
------------------------------------------------------------------------
Para probar el tema de que pasaria si tenemos realmente una funcion buena, voy a cambiar Explota() por :
void Explota(void)
{
activarBomba = 0;
}
Asi de esta forma no lo "optimiza" (es decir elimina por completo ) y ver si procede a dejar el if() esta ves.
Luego de compilado me encuentro con lo siguiente:
- La rutina de interrupcion no cambia.
- Explota() no aparece
- Solo cambio el main()
000004f8 <main>: ; void main(void) {
4f8: f240 2114 movw r1, #532 ;
4fc: 2200 movs r2, #0
4fe: f2c2 0100 movt r1, #8192 ;
502: ea4f 0808 mov.w r8, r8
506: 46c0 nop ;
508: 700a strb r2, [r1, #0] ; while(1) { activaBomba = 0
50a: 7808 ldrb r0, [r1, #0] ; <- Toma directo de memoria
50c: 2800 cmp r0, #0 ; if(activaBomba)
50e: d0fb beq.n 508 <main+0x10> ; Si es 0, vuelve al while(1)
510: 700a strb r2, [r1, #0] ; activaBomba = 0; // Esto de Explota();
512: e7f9 b.n 508 <main+0x10> ; } // Fin del while } Fin del main
Resultado: El optimizador hizo de Explota() una funcion inline. Es decir puso el activarBomba=0; en la rutina de main. Pero esta ves ahora si procede a realizarse el if.
Comprobando lo que habia dicho antes
Activar la optimizacion te puede borrar una funcion si no posee sentido. Volatile evita la optimizacion sobre la variable y por ende termina realizando lo que debe.
Ademas hace uso de mas registros del core, sin optimizacion se ve que no sale de R0 y R1, con optimizacion llego a usar R2 ( creo que hasta R7 usa con optimizacion si no mal recuerdo y hasta R3 sin optimizacion en programas mas demandantes ).