Un Callee-Saved Register, también conocido como 'non-volatile register' o 'preserved register', es un registro de la CPU que, según la convención de llamada (calling convention) de una arquitectura de procesador, debe ser preservado por la función que lo utiliza (la 'callee'). Esto significa que si una función llamada necesita usar uno de estos registros, debe guardar su valor original en la pila (stack) al inicio de su ejecución y restaurarlo desde la pila antes de retornar al llamador (caller). Esta convención contrasta con los 'Caller-Saved Registers', donde es responsabilidad del llamador preservar los valores si los necesita después de la llamada.
Este concepto es fundamental en la implementación de compiladores y sistemas operativos para arquitecturas como x86-64 (AMD64) y ARM. Por ejemplo, en x86-64, registros como RBX, RBP, R12, R13, R14 y R15 son Callee-Saved según la System V AMD64 ABI (Application Binary Interface) utilizada en Linux y macOS. En ARM, registros como R4-R11 son típicamente Callee-Saved. Los compiladores, como GCC o LLVM, generan código que sigue estas convenciones para asegurar la correcta ejecución de programas y la interoperabilidad entre módulos compilados independientemente. Los sistemas operativos, en su gestión de contextos de procesos y threads, también deben adherirse estrictamente a estas reglas al realizar cambios de contexto.
Para un Arquitecto de Sistemas, entender los Callee-Saved Registers es crucial para optimizar el rendimiento y garantizar la estabilidad. La elección de qué registros son Callee-Saved y cuáles Caller-Saved es un trade-off de diseño en la ABI. Si hay demasiados Callee-Saved Registers, las funciones pequeñas que no los necesitan incurrirán en la sobrecarga de guardar y restaurar registros innecesariamente. Si hay muy pocos, las funciones que sí los necesitan incurrirán en la sobrecarga de guardar y restaurar más registros. Esto impacta directamente en el rendimiento de las llamadas a funciones, la eficiencia del uso de la pila y la latencia en operaciones críticas del kernel, como los cambios de contexto. Un arquitecto debe considerar cómo estas convenciones afectan el diseño de APIs de bajo nivel, la interoperabilidad con código ensamblador y la eficiencia general del sistema, especialmente en entornos con restricciones de recursos o requisitos de baja latencia.