c++ - Dirección de etiquetas(MSVC)
assembly label (3)
Eche un vistazo a lo que Erlang hace para construir en Windows. Usan MSVC para la mayor parte de la compilación, y luego GCC para un archivo para hacer uso de la extensión labels-as-values. El código objeto resultante se piratea para que sea compatible con el enlazador MSVC.
http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html
Estamos escribiendo un código de bytes para un lenguaje compilado de alto nivel, y después de un poco de perfilado y optimización, quedó claro que la sobrecarga de rendimiento más grande actual es la declaración de cambio que estamos usando para saltar a los casos de código de bytes.
Investigamos la extracción de la dirección de cada etiqueta de caso y la almacenamos en el flujo del código de bytes, en lugar de la ID de la instrucción que usualmente encendemos. Si lo hacemos, podemos omitir la tabla de salto y saltar directamente a la ubicación del código de la instrucción que se está ejecutando actualmente. Esto funciona fantásticamente en GCC, sin embargo, MSVC no parece ser compatible con una característica como esta.
Intentamos usar el ensamblaje en línea para tomar la dirección de las etiquetas (y saltar a ellas), y funciona, sin embargo, al usar el ensamblaje en línea, el optimizador de MSVC evita toda la función.
¿Hay alguna forma de permitir que el optimizador siga ejecutándose sobre el código? Desafortunadamente, no podemos extraer el ensamblaje en línea en otra función que no sea aquella en la que se hicieron las etiquetas, ya que no hay forma de hacer referencia a una etiqueta para otra función incluso en el ensamblaje en línea. ¿Algún pensamiento o idea? Su opinión es muy apreciada, ¡gracias!
La única forma de hacerlo en MSVC es mediante el ensamblaje en línea (que básicamente te molesta para x64):
int _tmain(int argc, _TCHAR* argv[])
{
case_1:
void* p;
__asm{ mov [p],offset case_1 }
printf("0x%p/n",p);
return 0;
}
Si planeas hacer algo como esto, la mejor manera sería escribir todo el intérprete en ensamblaje y luego vincularlo al binario principal a través del enlazador (esto es lo que hizo LuaJIT, y es la razón principal por la que la VM es tan deslumbrantemente rápido, cuando no está ejecutando el código JIT que es).
LuaJIT es de código abierto , por lo que puede obtener algunos consejos si sigue esa ruta. Alternativamente, es posible que desee buscar en la fuente de cuarta (cuyo creador desarrolló el principio que está tratando de usar), si hay una compilación de MSVC puede ver cómo lo lograron, de lo contrario está atrapado con GCC (que no es es malo, funciona en todas las plataformas principales).
Parece que podrías mover el código real a funciones, en lugar de etiquetas de casos. El código de bytes puede transformarse trivialmente en llamadas directas. Es decir, el código de bytes 1 se traduciría a CALL BC1
. Como está generando llamadas directas, no tiene la sobrecarga de los punteros de función. Los conductos de la mayoría de las CPU pueden seguir tales ramas directas incondicionales.
Como resultado, las implementaciones reales de cada código de bytes se optimizan, y la conversión de código de bytes a código de máquina es una conversión trivial 1: 1. Obtienes un poco de expansión de código ya que cada CALL
es de 5 bytes (suponiendo x86-32) pero es poco probable que sea un problema importante.