es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué GCC emite una salida más grande para una copia byte a byte en comparación con memcpy?

El siguiente programa en C11 extrae la representación de bits de un número de punto flotante en un uint32_t de dos formas diferentes.

#include <stdint.h>

_Static_assert(sizeof(float) == sizeof(uint32_t));

uint32_t f2i_char(float f) {
  uint32_t x;
  char const *src = (char const *)&f;
  char *dst = (char *)&x;
  *dst++ = *src++;
  *dst++ = *src++;
  *dst++ = *src++;
  *dst++ = *src++;
  return x;
}

uint32_t f2i_memcpy(float f) {
  uint32_t x;
  memcpy(&x, &f, sizeof(x));
  return x;
}

El ensamblaje resultante, compilado con armgcc 10.2.1 (none eabi), es muy diferente, incluso con las optimizaciones -Os o -O3 aplicadas:

Estoy compilando con:
-mcpu=cortex-m4 -std=c11 -mfpu=fpv4-sp-d16 -mfloat-abi=hard

f2i_char:
  sub sp, sp, #16
  vstr.32 s0, [sp, #4]
  ldr r3, [sp, #4]
  strb r3, [sp, #12]
  ubfx r2, r3, #8, #8
  strb r2, [sp, #13]
  ubfx r2, r3, #16, #8
  ubfx r3, r3, #24, #8
  strb r2, [sp, #14]
  strb r3, [sp, #15]
  ldr r0, [sp, #12]
  add sp, sp, #16
  bx lr
f2i_memcpy:
  sub sp, sp, #8
  vstr.32 s0, [sp, #4]
  ldr r0, [sp, #4]
  add sp, sp, #8
  bx lr

¿Por qué gcc no genera el mismo ensamblaje para ambas funciones?

Enlace de ejemplo en Godbolt</stdint.h>

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    La razón por la que gcc genera un código de ensamblador diferente para las funciones f2i_char y f2i_memcpy es porque utilizan diferentes técnicas para extraer la representación en bits de un número de punto flotante y almacenarlo en un tipo uint32_t.

    f2i_char utiliza aritmética de punteros para extraer cada byte del número de punto flotante y almacenarlo en un tipo uint32_t, mientras que f2i_memcpy utiliza la función memcpy para copiar el número de punto flotante completo en una variable uint32_t.

    El compilador optimiza cada función de manera diferente según su implementación, lo que resulta en una salida de ensamblador diferente. No es raro que diferentes implementaciones de código tengan diferentes optimizaciones, incluso cuando realizan la misma tarea.

    En general, es mejor confiar en las optimizaciones del compilador para generar un código eficiente en lugar de intentar optimizar el código manualmente, a menos que sea absolutamente necesario.

Comments are closed.