# Riesgo (informática)

En arquitectura de computadores, un riesgo es un problema potencial que puede ocurrir en un procesador segmentado. Típicamente los riesgos se clasifican en tres tipos: riesgos de datos, riesgos de salto o de control y riesgos estructurales.
Las instrucciones de un procesador segmentado son ejecutadas en varias etapas, de modo que en un momento dado se encuentran en proceso varias instrucciones, y puede que éstas no sean completadas en el orden deseado.
Un riesgo aparece cuando dos o más de estas instrucciones simultáneas (posiblemente fuera de orden) entran en conflicto.

## Riesgos de datos

Los riesgos de datos ocurren cuando éstos son modificados. El ignorar riesgos de datos potenciales puede resultar en condiciones de carrera (a veces llamadas riesgos de carrera). Hay tres situaciones en las que puede aparecer un riesgo de datos:
* Read after Write (RAW) o dependencia verdadera: Un operando es modificado para ser leído posteriormente. Si la primera instrucción no ha terminado de escribir el operando, la segunda estará utilizando datos incorrectos.
* Write after Read (WAR) o anti-dependencia: Leer un operando y escribir en él en poco tiempo. Si la escritura finaliza antes que la lectura, la instrucción de lectura utilizará el nuevo valor y no el antiguo.
* Write after Write (WAW) o dependencia de salida: Dos instrucciones que escriben en un mismo operando. La primera en ser emitida puede que finalice en segundo lugar, de modo que el operando final no tenga el valor adecuado.
Los operandos envueltos en riesgos de datos pueden residir en memoria o en registros.

## Riesgos estructurales

Un riesgo estructural sucede cuando parte del hardware del procesador es necesario para ejecutar dos o más instrucciones a la vez. Puede ocurrir, por ejemplo, si un programa intenta ejecutar una instrucción de salto seguida de una operación matemática. Puesto que son ejecutadas de forma paralela y los saltos son típicamente lentos (requieren realizar una comparación, operar matemáticamente sobre el contador de programa y escribir en registros), es bastante posible (dependiendo de la arquitectura) que la instrucción de computación y la de salto requieran la ALU (unidad aritmético lógica) al mismo tiempo.

## Riesgos de salto o de control

Los riesgos de salto o de control ocurren cuando el procesador se ve obligado a saltar a una instrucción que no tiene por qué ser necesariamente la inmediatamente siguiente en el código. En ese caso, el procesador no puede saber por adelantado si debería ejecutar la siguiente instrucción u otra situada más lejos en el código.
Esto puede resultar en acciones no deseadas por parte de la CPU.

## Eliminación de riesgos

Existen varias técnicas para tanto previenir riesgos como para solucionar los problemas derivados de su aparición.

### Inserción de burbujas

    La inserción de burbujas es un método para prevenir la aparición de riesgos de datos, estructurales y de salto. Una vez que las instrucciones son capturadas, la lógica de control determina si podría o va a ocurrir un riesgo. Si es cierto, la lógica de control inserta una instrucción NOP (No Operation). De esta manera, antes de la instrucción siguiente (la que causa el riesgo) sea ejecutada, la anterior tendrá tiempo suficiente para completarse y prevenir el riesgo. Si el número de NOP insertadas es igual al número de etapas de la segmentación, el procesador puede trabajar sin amenazas de riesgos.

### Eliminación de riesgos de datos
#### Anticipación

    La anticipación implica suministrar los datos de salida en una etapa previa a la correspondiente de la segmentación. Por ejemplo, si se quiere escribir el número 3 en el registro $1 (que ya contiene un 6), para luego añadir 7 al registro $1 y almacenar el resultado en el registro $2, i.e.:
    Instrucción 0: $1 = 6
    Instrucción 1: $1 = 3
    Instrucción 2: $2 = $1 + 7 = 10
    En la siguiente ejecución, el registro $2 debería contener un 10. Sin embargo, si la instrucción 1 (escribir 3 en el registro $1) no se completa antes de que la segunda instrucción empiece, el registro $1 no contendrá el valor 3 cuando la instrucción 2 realice la suma. Del mismo modo, la instrucción 2 suma 7 al valor antiguo del registro $1 (6), y así el registro $2 contendría el 13, esto es:
    Instrucción 0: $1 = 6
    Instrucción 1: $1 = 3
    Instrucción 2: $2 = $1 + 7 = 13
    Este error ocurre porque la instrucción 2 lee el registro $1 antes de que la instrucción 1 haya escrito el resultado de su operación al registro $1. Así cuando la instrucción 2 esté leyendo los contenidos del registro $1, éste aún contendrá un 6 y no un 3.
    La anticipación ayuda a corregir este tipo de errores, tal y como se puede observar en el hecho de que la salida de la instrucción 1 (que es 3) puede ser utilizada por instrucciones siguientes antes de que dicho valor sea escrito en el registro $1.
    La anticipación, se implementa retroalimentado la salida de una instrucción a la etapa o etapas previas de la segmentación tan pronto como la salida de esa instrucción está disponible. Aplicada al ejemplo, significa que no se espera a que la salida de la instrucción 1 sea escrita en el registro $1 (en este caso, 3), sino que la salida ya está a disposición de las instrucciones siguientes (en este caso, la instrucción 2). El efecto consiste en que la instrucción 2 utiliza el valor correcto (el más reciente) del registro $1.
    Con la anticipación activada, la etapa ID/EX de la segmentación tiene ahora dos entradas: el valor leído del registro especificado (en el ejemplo, el valor 6 del registro $1), y al nuevo valor del registro $1 (en el ejemplo, 3) el cual es enviado desde la etapa siguiente (EX/MEM). Para determinar qué entrada es la correcta es necesaria lógica de control adicional.
    Véase feed-forward.