Pregunta

Si me dieron el C99 restrict palabra clave correcta, calificando con un puntero que es una promesa hizo que los datos de TI referencias no serán modificados a espaldas del compilador a través de alias.

Por el contrario, la forma en que entiendo el calificador const es como documentación del compilador-forzada que un objeto dado no será modificado a espaldas de un código escrito ser humano. El compilador puede obtener una pista como un efecto secundario, sino como un programador que no les importa.

De forma similar, sería apropiado considerar un calificador restrict en un prototipo de función como un requisito de que el usuario se asegura de acceso exclusivo ( "evitar el aliasing", o tal vez algo más fuerte) para la duración de la llamada? Debe ser usada como "documentación"?

Además, ¿hay algo que entender en el hecho de que restrict califica un puntero en lugar de los datos que lo han generado (como const hace)?

EDIT:. Originalmente creía que restrict podría tener implicaciones con código de roscado, pero esto parece mal, así que eliminar las referencias a las discusiones de la cuestión para evitar confundir a los lectores

¿Fue útil?

Solución

La mejor 'intuición' a tener sobre el restringir la palabra clave es que su garantía (por el programador para el compilador) que, durante la vida útil del puntero, la memoria accede a través de ese puntero será accesible únicamente a través de ese puntero y no a través de otro puntero o una referencia o dirección global. Por lo tanto es importante que la de un puntero como una propiedad tanto el puntero y la memoria, atar los dos juntos hasta que el puntero sale del ámbito.

Otros consejos

Chris Dodd tiene la descripción correcta de la palabra clave. En algunas plataformas, puede ser muy importante por razones de rendimiento, ya que permite que el compilador sabe que una vez que se haya cargado los datos a través de ese puntero sobre un registro, no es necesario que lo haga de nuevo. Sin esta garantía, el compilador debe volver a cargar los datos a través de un puntero cada vez que cualquier otro puntero posiblemente-aliasing se escribe a través, lo que puede provocar una parada del gasoducto seria llamado carga-hit-tienda .

const y restrict son conceptos diferentes, y no es el caso que implica const restrict. Todo dice const es que no se va a escribir a través de ese puntero dentro del ámbito de esa función . Un puntero const todavía puede tener un alias. Por ejemplo considerar:

int foo( const int *a, int * b )
{
   *b *= 2;
   return *a + *b; // induces LHS: *a must be read back immediately
                   // after write has cleared the store queue
}

Si bien no se puede escribir directamente a a en esta función, sería perfectamente legal para que usted pueda llamar foo como:

int x = 3;
foo( &x, &x );  // returns 12

restrict es una garantía diferente:. a != b la promesa de que en todas las llamadas a foo()

la palabra clave restrict y sus implicaciones en el rendimiento en longitud , y también lo ha hecho Mike Acton . Aunque hablamos de un PowerPC específica en orden, existe el problema de carga-hit-tienda en el 86 también, pero los de x86 ejecución fuera de orden hace que la parada más difíciles de aislar en un perfil.

Y sólo para destacar: esto es no una optimización arcano o prematuro, si se preocupan por el rendimiento en absoluto. restrict puede conducir a aceleraciones muy importantes si se usa correctamente.

La mayor parte de lo que sabemos que está mal!

const hace no garantía de que algo no va a cambiar a espaldas del compilador. Todo lo que hace es dejar de de la escritura a ese lugar. Otra cosa que todavía podría ser capaz de escribir en ese lugar, sin embargo, por lo que el compilador no puede asumir que es constante.

Como han dicho otros, el calificador se trata de restringir el aliasing. De hecho, durante la primera ronda de C de normalización, hubo una propuesta para una palabra clave "noalias". Por desgracia, la propuesta fue bastante mal escrito - que llevó a la primera y única vez el Dennis Ritchie se involucró durante ese proceso, cuando escribió una carta que dijo algo en el sentido de que "deben ir noalias Esto no está abierto a la negociación.. "

No es necesario decir, '' noalias no se convirtieron en parte de C. Cuando llegó el momento de volver a intentarlo, la propuesta fue escrito bastante mejor que restringen fue incluido en el estándar - y aunque noalias probablemente han sido una nombre más significativo para él, por lo que el nombre fue contaminada que dudo que nadie consideró incluso intentar utilizarlo.

En cualquier caso, la intención primaria de restringir es decirle al compilador que no habrá un alias de este artículo. Una razón de esto es permitir que las cosas que se almacenan en los registros de forma temporal. Por ejemplo, considere algo como:

void f(int *a, int *b, int *c) { 
    for (int i=0; i<*a; i++)
        *b += c[i];
}

El compilador realmente quiere poner i en un registro, y cargar * a en un registro, por lo que cuando llega el momento de decidir si se debe ejecutar otra iteración del bucle, sólo se comparan los valores en los que a los registros entre sí . Por desgracia, no se puede hacer eso - si alguien que utiliza esta función estaba completamente loco, y lo llamó con un == b, cada vez que se escribe a * b dentro del bucle, que el nuevo valor es también el valor de un * - por lo que tiene que leer * a partir de la memoria en cada iteración del bucle, si acaso a quien llama que estaba completamente loco. El uso de restringir le dice al compilador puede generar código suponiendo que A y B será siempre distinta, por lo que escribir a * a * nunca cambiará B (o viceversa).

Su comprensión es en gran medida correcta. El calificador restrict se limita a establecer que los datos consultados por un puntero de modo cualificado es solamente se accede por ese puntero exacta. Se aplica a los pozos dice lo que escribe.

El compilador no se preocupa por hilos concurrentes, no se va a generar código de forma diferente, y puede darle una paliza a sus propios datos como desee. Pero es necesario saber qué operaciones puntero puede cambiar lo que la memoria global.

Restrict también lleva consigo una advertencia API para los seres humanos que una determinada función se implementa con la asunción de parámetros unaliased.

No se bloqueo por parte del usuario es necesaria en lo que se refiere al compilador. Que sólo quiere asegurarse de que lee correctamente los datos que fue supone a pedradas, por código el compilador se suponía para generar , en caso de que haya ningún calificador restrict. Añadiendo restrict lo libera de esa preocupación.

Por último, cabe destacar que el compilador es probable que sea ya posible analizar aliasing en base a los tipos de datos, en los niveles más altos de optimización, por lo restrict es importante sobre todo para funciones con múltiples punteros al mismo tipo de datos. Usted puede tomar una lección de este tema y asegurarse de que cualquier solapamiento deliberado que haces se realiza a través de un union.

Podemos ver restrict en acción:

void move(int *a, int *b) {     void move(int *__restrict a, int *__restrict b) {
    a[0] = b[0];                    a[0] = b[0];
    a[1] = b[0];                    a[1] = b[0];
}                               }
    movl    (%edx), %eax            movl    (%edx), %edx
    movl    %eax, (%ecx)            movl    %edx, (%eax)
    movl    (%edx), %eax            movl    %edx, 4(%eax)
    movl    %eax, 4(%ecx)

En la columna de la derecha, con restrict, el compilador no necesitaba volver a leer b[0] de la memoria. Fue capaz de leer b[0] y mantenerlo en %edx registro, y luego simplemente almacenar el registro de dos veces a la memoria. En la columna de la izquierda, que no sabía si la tienda a a puede haber cambiado b.

Alguien más familiarizados con el estándar probablemente podría dar una respuesta mejor, pero voy a darle un tiro.

"Los datos no se modificarán a espaldas del compilador" suena más como lo opuesto a la "volátil" para mí.

"const" significa que los datos no serán modificadas en frente del programador; es decir, que no puede modificar los datos a través del significante marcado como "const" (escribo "significante" porque en int const *pi, el nombre pi no es constante, sino que es *pi). Los datos pueden ser modificables a través de otro significante (datos no const se pueden pasar a una función como datos const, después de todo).

Eso "restringir" califica punteros es la clave. Los punteros son la única forma de datos de alias en C, por lo que son la única manera de que pueda acceder a alguna pieza de datos a través de dos nombres diferentes. "Restringir" tiene que ver con la limitación del acceso a los datos de trayectoria de un acceso.

Esto podría ser un ejemplo de un muy de dominios restringidos, pero la plataforma Nios II de Altera es un microcontrolador de núcleo blando que se puede personalizar dentro de una FPGA. Entonces, dentro del código fuente C para que las micro, se puede utilizar una herramienta de C-al hardware para acelerar bucles internos utilizando hardware personalizado, en lugar de en el software.

En allí, el uso de la palabra clave __restrict__ (que es la misma que restrict de C99) permite que la herramienta C2H para optimizar adecuadamente la aceleración de hardware de la operación del puntero en paralelo en lugar de secuencialmente. Por lo menos en este caso, el restrict es simplemente no significaba para el consumo humano. Ver también la página de Sun en restrict, donde la primera línea dice

  

Uso del calificador restrict adecuadamente en los programas de C puede permitir que el compilador para producir ejecutables significativamente más rápidas.

Si alguien está interesado en leer más sobre C2H, este PDF discute la optimización de los resultados C2H. La sección sobre __restrict__ está en la página 20.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top