Pergunta

Se eu tenho o C99 restrict direito palavra-chave, qualificando um ponteiro com ele é uma promessa feita de que os dados que as referências não serão modificadas pelas costas do compilador por meio de aliasing.

Por outro lado, a forma como eu entendo a const qualificador é como documentação aplicadas pelo compilador que um determinado objeto não será modificado por trás das costas de um código escrito ser humano. O compilador pode obter uma dica como um efeito colateral, mas como programador eu realmente não me importo.

De maneira semelhante, seria apropriado considerar um qualificador restrict em um protótipo de função como um requisito que o usuário garante acesso exclusivo ( "aliasing evitar", ou talvez algo mais forte) para a duração da chamada? Ela deve ser usada como "documentação"?

Além disso, há algo para entender no fato de que restrict qualifica um ponteiro em vez dos dados aponta para (como const faz)?

EDIT:. Eu acreditava inicialmente que restrict poderia ter implicações com código de rosca, mas isso parece errado assim que eu remover referências a tópicos da questão para evitar confundir os leitores

Foi útil?

Solução

O melhor 'intuição' para ter sobre a restringir palavra-chave é que a sua garantia (pelo programador para o compilador) que, para a vida do ponteiro, memória acessada via esse ponteiro só serão acessados ??via esse ponteiro e não através de outro ponteiro ou referência ou endereço global. Portanto, é importante que a sua em um ponteiro como uma propriedade de ambos o ponteiro ea memória, amarrando os dois juntos até que o ponteiro sai do escopo.

Outras dicas

Chris Dodd tem a descrição correta da palavra-chave. Em algumas plataformas, pode ser muito importante por razões de desempenho, porque permite que o compilador saber que uma vez que ele tem dados carregados através desse ponteiro para um registro, ele não precisa fazê-lo novamente. Sem essa garantia, o compilador deve recarregar os dados através de um ponteiro de cada vez qualquer outro ponteiro possivelmente-aliasing é escrito através, o que pode causar uma barraca gasoduto sério chamado de load-hit-store .

const e restrict são conceitos diferentes, e não é o caso que const implica restrict. Todos const diz é que você não vai escrever através desse ponteiro dentro do escopo dessa função . Um ponteiro const pode ainda ser alias. Por exemplo, considere:

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
}

Enquanto você não pode escrever diretamente para a nesta função, seria perfeitamente legal para você chamar foo como:

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

restrict é uma garantia diferente:. Uma promessa que a != b em todas as chamadas para foo()

Eu href="http://assemblyrequired.crashworks.org/2008/07/08/load-hit-stores-and-the-__restrict-keyword/" escrito sobre a palavra-chave restrict e suas implicações de desempenho no comprimento , e isso tem Mike Acton . Embora falamos de um PowerPC específico em ordem, o problema de carga-hit-store existe no x86, bem como, mas o x86 é fora-de-ordem de execução faz com que a tenda mais difícil de isolar em um perfil.

E apenas para enfatizar: este é não um arcano ou otimização prematura, se você se preocupa com o desempenho em tudo. restrict pode levar a speedups realmente significativas, se usado corretamente.

A maioria do que você sabe que é! Errado

const não não garantia de que algo não vai mudar atrás das costas do compilador. Tudo que faz é parar você de escrever a esse ponto. Outra coisa ainda pode ser capaz de escrever para esse local, porém, assim o compilador não pode assumir que é constante.

Como já foi dito, a restringir o qualificador é sobre aliasing. De fato, durante a primeira rodada de C padronização, houve uma proposta de palavra-chave "noalias". Infelizmente, a proposta foi bastante mal escrito - que levou a uma e única vez que o Dennis Ritchie se envolveu durante esse processo, quando ele escreveu uma carta que disse algo no sentido de que "noalias deve ir Isso não está aberto a negociação.. "

É desnecessário dizer que 'noalias' não se tornou parte de C. Quando chegou a hora de tentar novamente, a proposta foi escrito bastante melhor que restringem foi incluído no padrão - e mesmo que noalias provavelmente teria sido um nome mais significativo para ele, que o nome estava tão contaminado que eu duvido que alguém mesmo considerado tentar usá-lo.

Em qualquer caso, a intenção primária de restringir é para dizer ao compilador que não haverá um apelido para este item. Uma razão para isso é permitir que as coisas sejam armazenados nos registos temporariamente. Por exemplo, considere algo como:

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

O compilador realmente quer colocar i num registo e de carga * a em um registrador, então quando chega a hora de decidir se vai executar outra iteração do loop, ele apenas compara os valores naqueles aos registos entre si . Infelizmente, ele não pode fazer isso - se alguém que usou essa função era completamente louco, e chamou-lhe com a == b, cada vez que escreve a * b dentro do loop, esse novo valor é também o valor de * a - por isso tem que ler * a partir da memória em cada iteração do loop, apenas no caso quem chamou era completamente insano. Usando restringir informa o compilador pode gerar código assumindo que a e b será sempre diferente, assim que escrever para * a nunca vai mudar * b (ou vice-versa).

Seu entendimento é em grande parte correta. O qualificador restrict simplesmente afirma que os dados acessados ??por um ponteiro de modo qualificado é única acessado por esse ponteiro exato. Aplica-se a lê como poços como escreve.

O compilador não se importa com threads simultâneos, que não estava indo para gerar o código de forma diferente, e você pode espancar seus próprios dados como você gosta. Mas ele precisa saber o que operações do ponteiro pode mudar o que a memória global.

Restrict também traz consigo um aviso API para os seres humanos que uma determinada função é implementada com a suposição de parâmetros unaliased.

No bloqueio, o usuário é necessária, tanto quanto o compilador está em causa. Ele só quer ter certeza de que ele lê corretamente dados que estavam deveria para ser derrotado, por código de o compilador deveria gerar , caso haja nenhum qualificador restrict. Adicionando liberta restrict-lo de que a preocupação.

Finalmente, note que o compilador é provável que já esteja analisando possível aliasing baseado em tipos de dados, nos níveis de otimização mais elevados, de modo restrict é importante principalmente para funções com vários ponteiros para o mesmo tipo de dados. Você pode tirar uma lição de este assunto e certifique-se de que qualquer aliasing deliberada que você faz é feito através de um union.

Podemos ver restrict em ação:

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)

Na coluna da direita, com restrict, o compilador não precisa b[0] releitura da memória. Era capaz de ler b[0] e mantê-lo em %edx registo, e em seguida, basta armazenar o registo duas vezes para a memória. Na coluna da esquerda, ele não sabia se a loja para a pode ter mudado b.

Alguém mais familiarizados com o padrão provavelmente poderia dar uma resposta melhor, mas vou dar-lhe um tiro.

"Os dados não será modificado por trás do compilador de volta" sons mais como o oposto de "volátil" para mim.

"const" significa que os dados não serão modificados na frente do programador; isto é, ela não pode modificar os dados através do significante marcado como "const" (eu escrevo "significante" porque em int const *pi, o nome pi não é const, mas *pi é). Os dados podem ser modificáveis ??via um outro significante (dados não-const pode ser passado para uma função como dados const, depois de tudo).

Que "restringir" qualifica ponteiros é a chave. Os ponteiros são a única maneira de dados de alias em C, por isso eles são a única maneira que você pode acessar algum pedaço de dados através de dois nomes diferentes. "Restringir" é tudo sobre como limitar o acesso aos dados para um caminho de acesso.

Este pode ser um exemplo de um extremamente domínio estreito, mas plataforma Nios II da Altera é um microcontrolador soft-core que você pode personalizar dentro de um FPGA. Então, dentro do código fonte C para que micro, você pode usar uma ferramenta C-to-hardware para acelerar laços internos usando hardware personalizado, em vez de software.

lá, o uso da palavra-chave __restrict__ (que é o mesmo que restrict de C99) permite que a ferramenta C2H para optimizar correctamente a aceleração da operação de ponteiro em paralelo em vez de sequencialmente hardware. Pelo menos neste caso, o restrict é simplesmente não destinado ao consumo humano. Veja também página do Sun on restrict, onde a primeira linha diz

Usando o qualificador restrict apropriadamente em C programas pode permitir que o compilador para produzir executáveis ??significativamente mais rápido.

Se alguém está interessado em ler mais sobre C2H, este PDF discute optimizando resultados C2H. A seção sobre __restrict__ está na página 20.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top