Un 'caller-saved register' (también conocido como 'volatile register' o 'scratch register') es un registro de la CPU cuyo contenido no está garantizado que se preserve a través de una llamada a función. Esto significa que si la función que realiza la llamada (the caller) necesita el valor de este registro después de que la función llamada (the callee) retorne, es responsabilidad del 'caller' guardar explícitamente el valor en la pila antes de la llamada y restaurarlo después. La función llamada (the callee) es libre de usar estos registros sin necesidad de guardarlos o restaurarlos, ya que se asume que el 'caller' ya ha tomado las precauciones necesarias.
Este concepto es fundamental en las 'calling conventions' de la mayoría de las arquitecturas de CPU modernas, como x86-64 (donde registros como RAX, RCX, RDX, R8-R11 son típicamente caller-saved) y ARM64 (registros X0-X15). Compiladores como GCC, Clang y MSVC implementan estas convenciones para generar código ensamblador optimizado. Por ejemplo, en C/C++, cuando una función llama a otra, el compilador se adhiere a la 'Application Binary Interface' (ABI) específica de la plataforma para gestionar qué registros son 'caller-saved' y cuáles son 'callee-saved'. Esto permite que las funciones llamadas utilicen un conjunto de registros sin la sobrecarga de guardarlos y restaurarlos, mejorando la eficiencia en escenarios donde el 'caller' no necesita preservar esos valores.
Para un Arquitecto de Sistemas, entender los 'caller-saved registers' es crucial para optimizar el rendimiento y la eficiencia del código a bajo nivel, especialmente en el desarrollo de sistemas operativos, drivers o bibliotecas de alto rendimiento. La elección de qué registros son 'caller-saved' y cuáles 'callee-saved' en una ABI es un 'trade-off' de diseño: los 'caller-saved' reducen la sobrecarga para el 'callee' (útil para funciones pequeñas o de hoja que no llaman a otras), mientras que los 'callee-saved' reducen la sobrecarga para el 'caller' (útil cuando el 'caller' tiene muchos valores vivos que necesita preservar). Una comprensión profunda permite evaluar el impacto de las 'calling conventions' en el rendimiento de 'hot paths', el uso de la pila y la latencia de las llamadas a funciones, informando decisiones sobre la optimización del compilador, el diseño de la ABI para subsistemas críticos o incluso la implementación de 'context switching' en kernels.