El problema que se obtiene con la optimización de que el código es:
08000328 <mul_test01>:
8000328: f04f 5000 mov.w r0, #536870912 ; 0x20000000
800032c: 4770 bx lr
800032e: bf00 nop
su doesnt código de tiempo de ejecución hacer nada por lo que el optimizador solo puede calcular la respuesta final.
esto:
.thumb_func
.globl mul_test02
mul_test02:
smull r2,r3,r0,r1
mov r0,r3
bx lr
llamada con esto:
c = mul_test02(0x40000000,0x40000000);
da 0x10000000
UMULL da el mismo resultado porque está utilizando números positivos, los operandos y los resultados son positivos por lo no entra en las diferencias firmadas/sin firmar.
Hmm, bueno me tienes en este. Leería su código diciéndole al compilador que promoviera la multiplicación a 64 bits. smull es dos operandos de 32 bits que dan un resultado de 64 bits, que no es lo que tu código está pidiendo ... pero tanto gcc como clang usaron el smull de todos modos, incluso si lo dejé como una función no llamada, por lo que no lo sabía Tiempo de compilación en el que los operandos no tenían dígitos significativos por encima de 32, todavía usaban smull.
Tal vez el cambio fue la razón.
Sí, eso fue todo ..
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
da
tanto gcc y sonido metálico (bien sonido metálico recicla r0 y r1 en lugar de utilizar r2 y r3)
08000340 <mul_test04>:
8000340: fb81 2300 smull r2, r3, r1, r0
8000344: 0fd0 lsrs r0, r2, #31
8000346: ea40 0043 orr.w r0, r0, r3, lsl #1
800034a: 4770 bx lr
pero esto
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b);
return(c);
}
da esta
gcc:
08000340 <mul_test04>:
8000340: fb00 f001 mul.w r0, r0, r1
8000344: 4770 bx lr
8000346: bf00 nop
sonido metálico:
0800048c <mul_test04>:
800048c: 4348 muls r0, r1
800048e: 4770 bx lr
Así que con el desplazamiento de bit los compiladores se dan cuenta de que sólo está interesado en la parte superior de los resultados para que puedan desprenderse de la parte superior de los operandos que significa Smull puede ser usado.
Ahora bien, si usted hace esto:
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 32;
return(c);
}
los compiladores se ponen aún más inteligente, en particular sonido metálico:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 4770 bx lr
gcc:
08000340 <mul_test04>:
8000340: fb81 0100 smull r0, r1, r1, r0
8000344: 4608 mov r0, r1
8000346: 4770 bx lr
puedo ver que 0x40000000 considerados como un flotador donde se realiza un seguimiento del lugar decimal, y ese lugar es una ubicación fija. 0x20000000 tendría sentido como la respuesta. Todavía no puedo decidir si ese cambio de 31 bits funciona universalmente o solo para este caso.
Un ejemplo completo utilizado para el anterior es que aquí
https://github.com/dwelch67/stm32vld/tree/master/stm32f4d/sample01
y lo hice ejecutarlo en un stm32f4 para verificar su funcionamiento y los resultados.
EDIT:
Si sale de los parámetros en la función en lugar de codificar dentro de la función:
int myfun (int a, int b)
{
return(a+b);
}
El compilador se ve obligado a hacer que el código de tiempo de ejecución en lugar de a optimizar la respuesta en tiempo de compilación.
Ahora bien, si se llama a esa función desde otra función con números codificados:
...
c=myfun(0x1234,0x5678);
...
En esta función que llama el compilador puede elegir para calcular la respuesta y simplemente colocarlo allí en tiempo de compilación. Si la función myfun() es global (no está declarada como estática) el compilador no sabe si algún otro código que se va a vincular posteriormente lo usará, por lo que incluso cerca del punto de llamada en este archivo optimiza una respuesta que todavía tiene que producir la función real y dejarlo en el objeto para que llame otro código en otros archivos, por lo que aún puede examinar lo que el compilador/optimizador hace con ese código en C. A menos que utilice llvm, por ejemplo, donde puede optimizar todo el proyecto (a través de archivos), el código externo que llama a esta función utilizará la función real y no una respuesta calculada en tiempo de compilación.
Tanto gcc como clang hicieron lo que describo, dejó el código de tiempo de ejecución para la función como función global, pero dentro del archivo calculó la respuesta en tiempo de compilación y colocó la respuesta codificada en el código en lugar de llamar a la función:
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
en otra función en el mismo archivo:
hexstring(mul_test04(0x40000000,0x40000000),1);
la propia función se implementa en el código:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 0fc9 lsrs r1, r1, #31
8000492: ea41 0040 orr.w r0, r1, r0, lsl #1
8000496: 4770 bx lr
pero donde se llama han hardcoded la respuesta porque tenían toda la información necesaria para hacerlo:
8000520: f04f 5000 mov.w r0, #536870912 ; 0x20000000
8000524: 2101 movs r1, #1
8000526: f7ff fe73 bl 8000210 <hexstring>
Si no quieres la respuesta codificada es necesario utilizar una función que no está en el mismo pase de optimización.
La manipulación del compilador y el optimizador se reduce a mucha práctica y no es una ciencia exacta ya que los compiladores y optimizadores están en constante evolución (para bien o para mal).
Al aislar un pequeño bit de código en una función, está causando problemas de otra manera, es más probable que las funciones más grandes necesiten un marco de pila y desalojen las variables de los registros a la pila, las funciones más pequeñas pueden no necesitar hacer eso y los optimizadores pueden cambiar cómo se implementa el código como resultado. Probarás el fragmento de código de una manera para ver qué está haciendo el compilador, luego lo usarás en una función más grande y no obtendrás el resultado que deseas. Si hay una instrucción exacta o una secuencia de instrucciones que desea implementar ... impleméntelas en ensamblador. Si estaba apuntando a un conjunto específico de instrucciones en un conjunto de instrucciones/procesador específico, entonces evite el juego, evite que su código cambie cuando cambie las computadoras/compiladores/etc, y simplemente use el ensamblador para ese objetivo. si es necesario ifdef o use opciones de compilación condicional para construir para diferentes objetivos sin el ensamblador.
¿Está compilando con optimización? Si su compilador no está generando un código óptimo, puede escribir una pequeña función de ensamblaje o usar un ensamblado en línea de C. – TJD