Rust: Reative as anotações noalias por padrão, uma vez que o LLVM não as compila mais

Criado em 6 out. 2018  ·  33Comentários  ·  Fonte: rust-lang/rust

Este problema rastreia o desfazer do padrão -Zmutable-alias=no introduzido em https://github.com/rust-lang/rust/pull/54639 por conta de um bug no LLVM. cc @nagisa

( Deja vu? )

A-LLVM A-codegen C-tracking-issue I-slow T-compiler

Comentários muito úteis

Eu o reduzi a um caso de teste C simples (compilar em -O3 e -O0 e comparar a saída):

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

__attribute__((always_inline))
static inline void copy(int *restrict a, int *restrict b) {
    assert(a != b);
    *b = *a;
    *a = 7;
}

__attribute__((noinline))
void floppy(int mat[static 2], size_t idxs[static 3]) {
    for (int i = 0; i < 3; i++) {
        copy(&mat[i%2], &mat[idxs[i]]);
    }
}

int main() {
    int mat[3] = {10, 20};
    size_t idxs[3] = {1, 0, 1};
    floppy(mat, idxs);
    printf("%d %d\n", mat[0], mat[1]);
}

Observe que se você remover restrict , o equivalente em C de noalias , o comportamento está correto. Ainda assim, o assert(a != b) passa, provando que nenhum UB pode ocorrer devido a chamá-lo com restrict .

O que está acontecendo é:

  1. copy () fica embutido, resultando em algo como:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. O LLVM desenrola o loop:
mat[idxs[0]] = mat[0]; mat[0] = 7; /* from copy(&mat[0%2], &mat[idxs[0]]) */
mat[idxs[1]] = mat[1]; mat[1] = 7; /* from copy(&mat[1%2], &mat[idxs[1]]) */
mat[idxs[2]] = mat[0]; mat[0] = 7; /* from copy(&mat[2%2], &mat[idxs[2]]) */
  1. O LLVM pensa que mat[0] não pode ser alternado com mat[idxs[1]] ou mat[1] , logo não pode ter sido alterado entre mat[0] = 7; e mat[idxs[2]] = mat[0]; , logo é seguro para numeração de valor global para otimizar o último para mat[idxs[2]] = 7; .

Mas mat[0] faz alias com mat[idxs[1]] , porque idxs[1] == 0 . E não prometemos que não faria isso, porque na segunda iteração, quando &mat[idxs[1]] é passado para copy , o outro argumento é &mat[1] . Então, por que o LLVM acha que não pode?

Bem, tem a ver com a maneira copy é embutido. O atributo de função noalias é transformado em metadados !alias.scope e !noalias nas instruções de carregamento e armazenamento, como:

  %8 = load i32, i32* %0, align 4, !tbaa !8, !alias.scope !10, !noalias !13
  store i32 %8, i32* %7, align 4, !tbaa !8, !alias.scope !13, !noalias !10
  store i32 7, i32* %0, align 4, !tbaa !8, !alias.scope !10, !noalias !13

Normalmente, se uma função é alinhada várias vezes, cada cópia obtém seus próprios IDs exclusivos para alias.scope e noalias, indicando que cada chamada representa sua própria relação de 'desigualdade' * entre o par de argumentos marcado noalias ( restrict no nível C), que pode ter valores diferentes para cada chamada.

No entanto, neste caso, primeiro a função é embutida no loop, então o código embutido é duplicado quando o loop é desenrolado - e essa duplicação não altera os IDs. Por causa disso, o LLVM pensa que nenhum dos a pode criar um alias com b , que é falso, porque a do primeiro e do terceiro chama aliases com b da segunda chamada (todos apontando para &mat[0] ).

Surpreendentemente, o GCC também compila isso, com saída diferente. (clang e GCC em -O0 geram 7 10 ; clang em -O3 geram 7 7 ; GCC em -O3 geram 10 7 .) Uh, eu realmente espero que não afinal bagunçar alguma coisa e adicionar UB, mas não vejo como ...

* É um pouco mais complicado do que isso, mas neste caso, uma vez que copy não usa nenhum ponteiro aritmético e escreve para ambos os ponteiros, a desigualdade a != b é necessária e suficiente para uma chamada não para seja UB.

Todos 33 comentários

Ainda estou tentando descobrir o problema subjacente. O ingresso interessante é https://github.com/rust-lang/rust/issues/54462.

Usando a reprodução mínima de @nagisa :


Caso de teste minimizado sem código inseguro (certifique-se de compilar com 1 unidade codegen!):

fn linidx(row: usize, col: usize) -> usize {
    row * 1 + col * 3
}

fn swappy() -> [f32; 12] {
    let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0];

    for i in 0..2 {
        for j in i+1..3 {
            if mat[linidx(j, 3)] > mat[linidx(i, 3)] {
                    for k in 0..4 {
                            let (x, rest) = mat.split_at_mut(linidx(i, k) + 1);
                            let a = x.last_mut().unwrap();
                            let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
                            ::std::mem::swap(a, b);
                    }
            }
        }
    }

    mat
}

fn main() {
    let mat = swappy();
    assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat);
}

Consegui dividir os passos de otimização do LLVM para encontrar o que estava causando o erro.

A execução deste comando resulta em um executável funcional (substitua bug.rs pelo nome do arquivo em que você salvou a reprodução).

rustc -Z no-parallel-llvm -C codegen-units=1 -O -Z mutable-noalias=yes -C llvm-args=-opt-bisect-limit=2260 bug.rs

Ao executar este comando resulta em um executável quebrado (o `assert_eq`` falha):

rustc -Z no-parallel-llvm -C codegen-units=1 -O -Z mutable-noalias=yes -C llvm-args=-opt-bisect-limit=2261 bug.rs

Saída LLVM bissect

Para este arquivo, a otimização 2261 corresponde a Global Value Numbering on function (_ZN3bug6swappy17hdcc51d0e284ea38bE)

A divisão das revisões do LLVM (usando a divisão do llvmlab) reduz para r305936-r305938, presumivelmente r305938:

[BasicAA] Use MayAlias ​​em vez de PartialAlias ​​para fallback.

Observe que esta é uma mudança bastante antiga, de junho de 2017.

Edit: Olhando para a descrição do commit, parece provável que o bug existia antes disso, mas foi mascarado pelo BasicAA impedindo que passagens de alias posteriores rodassem, que é o que o commit corrigiu. O caso envolve a verificação de aliasing entre um par de instruções getelementptr onde o compilador sabe que eles têm o mesmo endereço de base, mas não conhece os deslocamentos.

Edit2: Além disso, passar -enable-scoped-noalias=false como uma opção LLVM evita a compilação incorreta. (Isso não é surpreendente, uma vez que desativa totalmente o manuseio de noálias, mas apenas no caso de ajudar ...)

De uma olhada no IR pré-GVN, eu sinto que a causa raiz aqui pode estar no desenrolar do loop, dependendo se meu entendimento de como as anotações de aliasing do LLVM funcionam está correto.

Considere um código como

int *a, *b;
for (int i = 0; i < 4; i++) {
    a[i & 1] = b[i & 1];
}

onde a[i & 1] e b[i & 1] não fazem alias dentro de uma única iteração , mas a e b em geral podem ser alias.

No LLVM IR isso seria algo como:

define void @test(i32* %addr1, i32* %addr2) {
start:
    br label %body

body:
    %i = phi i32 [ 0, %start ], [ %i2, %body ]
    %j = and i32 %i, 1
    %addr1i = getelementptr inbounds i32, i32* %addr1, i32 %j
    %addr2i = getelementptr inbounds i32, i32* %addr2, i32 %j

    %x = load i32, i32* %addr1i, !alias.scope !2
    store i32 %x, i32* %addr2i, !noalias !2

    %i2 = add i32 %i, 1
    %cmp = icmp slt i32 %i2, 4
    br i1 %cmp, label %body, label %end

end:
    ret void
}

!0 = !{!0}
!1 = !{!1, !0}
!2 = !{!1}

Se executarmos isso em -loop-unroll , obteremos:

define void @test(i32* %addr1, i32* %addr2) {
start:
  br label %body

body:                                             ; preds = %start
  %x = load i32, i32* %addr1, !alias.scope !0
  store i32 %x, i32* %addr2, !noalias !0
  %addr1i.1 = getelementptr inbounds i32, i32* %addr1, i32 1
  %addr2i.1 = getelementptr inbounds i32, i32* %addr2, i32 1
  %x.1 = load i32, i32* %addr1i.1, !alias.scope !0
  store i32 %x.1, i32* %addr2i.1, !noalias !0
  %x.2 = load i32, i32* %addr1, !alias.scope !0
  store i32 %x.2, i32* %addr2, !noalias !0
  %addr1i.3 = getelementptr inbounds i32, i32* %addr1, i32 1
  %addr2i.3 = getelementptr inbounds i32, i32* %addr2, i32 1
  %x.3 = load i32, i32* %addr1i.3, !alias.scope !0
  store i32 %x.3, i32* %addr2i.3, !noalias !0
  ret void
}

!0 = !{!1}
!1 = distinct !{!1, !2}
!2 = distinct !{!2}

Observe como todas as quatro cópias do loop usam metadados de aliasing no mesmo domínio de aliasing. Em vez de ser noalias em uma única iteração, é noalias em toda a função.

Finalmente, -scoped-noalias -gvn nos dá:

define void @test(i32* %addr1, i32* %addr2) {
start:
  %x = load i32, i32* %addr1, !alias.scope !0
  store i32 %x, i32* %addr2, !noalias !0
  %addr1i.1 = getelementptr inbounds i32, i32* %addr1, i32 1
  %addr2i.1 = getelementptr inbounds i32, i32* %addr2, i32 1
  %x.1 = load i32, i32* %addr1i.1, !alias.scope !0
  store i32 %x.1, i32* %addr2i.1, !noalias !0
  store i32 %x, i32* %addr2, !noalias !0
  store i32 %x.1, i32* %addr2i.1, !noalias !0
  ret void
}

!0 = !{!1}
!1 = distinct !{!1, !2}
!2 = distinct !{!2}

E isso resultará em resultados incorretos se a = b + 1 .

É possível reproduzir esse problema de C com o seguinte código:

#include "stdio.h"

void copy(int * restrict to, int * restrict from) {
    *to = *from;
}

void test(int *a, int *b) {
    for (int i = 0; i < 4; i++) {
        copy(&b[i & 1], &a[i & 1]);
    }
}

int main() {
    int ary[] = {0, 1, 2};
    test(&ary[1], &ary[0]);
    printf("%d %d %d\n", ary[0], ary[1], ary[2]);
    return 1;
}

Com o Clang 6.0, isso imprime 2 2 2 em -O0 e 1 2 2 em -O3 . Não tenho certeza se este código é legal sob a semântica restrict em C, mas acho que deveria ser legal sob a semântica noalias mais estrita do LLVM.

Eu o reduzi a um caso de teste C simples (compilar em -O3 e -O0 e comparar a saída):

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

__attribute__((always_inline))
static inline void copy(int *restrict a, int *restrict b) {
    assert(a != b);
    *b = *a;
    *a = 7;
}

__attribute__((noinline))
void floppy(int mat[static 2], size_t idxs[static 3]) {
    for (int i = 0; i < 3; i++) {
        copy(&mat[i%2], &mat[idxs[i]]);
    }
}

int main() {
    int mat[3] = {10, 20};
    size_t idxs[3] = {1, 0, 1};
    floppy(mat, idxs);
    printf("%d %d\n", mat[0], mat[1]);
}

Observe que se você remover restrict , o equivalente em C de noalias , o comportamento está correto. Ainda assim, o assert(a != b) passa, provando que nenhum UB pode ocorrer devido a chamá-lo com restrict .

O que está acontecendo é:

  1. copy () fica embutido, resultando em algo como:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. O LLVM desenrola o loop:
mat[idxs[0]] = mat[0]; mat[0] = 7; /* from copy(&mat[0%2], &mat[idxs[0]]) */
mat[idxs[1]] = mat[1]; mat[1] = 7; /* from copy(&mat[1%2], &mat[idxs[1]]) */
mat[idxs[2]] = mat[0]; mat[0] = 7; /* from copy(&mat[2%2], &mat[idxs[2]]) */
  1. O LLVM pensa que mat[0] não pode ser alternado com mat[idxs[1]] ou mat[1] , logo não pode ter sido alterado entre mat[0] = 7; e mat[idxs[2]] = mat[0]; , logo é seguro para numeração de valor global para otimizar o último para mat[idxs[2]] = 7; .

Mas mat[0] faz alias com mat[idxs[1]] , porque idxs[1] == 0 . E não prometemos que não faria isso, porque na segunda iteração, quando &mat[idxs[1]] é passado para copy , o outro argumento é &mat[1] . Então, por que o LLVM acha que não pode?

Bem, tem a ver com a maneira copy é embutido. O atributo de função noalias é transformado em metadados !alias.scope e !noalias nas instruções de carregamento e armazenamento, como:

  %8 = load i32, i32* %0, align 4, !tbaa !8, !alias.scope !10, !noalias !13
  store i32 %8, i32* %7, align 4, !tbaa !8, !alias.scope !13, !noalias !10
  store i32 7, i32* %0, align 4, !tbaa !8, !alias.scope !10, !noalias !13

Normalmente, se uma função é alinhada várias vezes, cada cópia obtém seus próprios IDs exclusivos para alias.scope e noalias, indicando que cada chamada representa sua própria relação de 'desigualdade' * entre o par de argumentos marcado noalias ( restrict no nível C), que pode ter valores diferentes para cada chamada.

No entanto, neste caso, primeiro a função é embutida no loop, então o código embutido é duplicado quando o loop é desenrolado - e essa duplicação não altera os IDs. Por causa disso, o LLVM pensa que nenhum dos a pode criar um alias com b , que é falso, porque a do primeiro e do terceiro chama aliases com b da segunda chamada (todos apontando para &mat[0] ).

Surpreendentemente, o GCC também compila isso, com saída diferente. (clang e GCC em -O0 geram 7 10 ; clang em -O3 geram 7 7 ; GCC em -O3 geram 10 7 .) Uh, eu realmente espero que não afinal bagunçar alguma coisa e adicionar UB, mas não vejo como ...

* É um pouco mais complicado do que isso, mas neste caso, uma vez que copy não usa nenhum ponteiro aritmético e escreve para ambos os ponteiros, a desigualdade a != b é necessária e suficiente para uma chamada não para seja UB.

Heh, parece que corri com @nikic para encontrar a mesma explicação. O caso de teste deles é um pouco melhor :)

Esse é um momento muito bom ^^ Chegamos à mesma conclusão com quase o mesmo caso de teste reduzido ao mesmo tempo :)

Para corrigir isso, provavelmente algo na linha de https://github.com/llvm-mirror/llvm/blob/54d4881c352796b18bfe7314662a294754e3a752/lib/Transforms/Utils/InlineFunction.cpp#L801 também precisa ser feito em LoopUnrollPass.

Enviei um relatório de bug do LLVM para esse problema em https://bugs.llvm.org/show_bug.cgi?id=39282.

E - apenas mencionando isso para integridade - enviei um relatório de bug ao GCC, pois ele também compilou incorretamente meu caso de teste C: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87609

Triagem: Se estou lendo corretamente, a correção LLVM foi aceita (https://reviews.llvm.org/D9375). Não tenho certeza do que isso significa para realmente mesclar ao LLVM, ou quando isso aconteceu; alguém com mais conhecimento sobre o processo de revisão do LLVM deve verificar se o problema foi corrigido agora (e para quais versões).

Não está mesclado, o processo de revisão foi um pouco estranho e a pessoa que deu o OK não revisou mais os patches.

Houve uma chamada para testes com o conjunto de patches "restrição total". Provavelmente seria valioso se alguém tentasse reativar o noalias no Rust em cima de um llvm que tenha esse conjunto de patch aplicado.

Estou disposto a tentar fazer isso.
Tenho acesso a servidores moderadamente poderosos (48 núcleos HT, 128G de ram) e acho que consigo construir tudo corretamente com o patch.
Assim que tiver um conjunto de ferramentas em funcionamento, quais caixas você recomendaria experimentar?

Terminei de mesclar todos os commits específicos de ferrugem no master upstream do llvm e apliquei o patch .
Aqui está o branch resultante: https://github.com/PaulGrandperrin/llvm-project/tree/llvm-master-with-rustlang-patches-and-D69542
Vou agora tentar compilar o conjunto de ferramentas e testá-lo

Primeiro, certifique-se de reverter: https://github.com/rust-lang/rust/pull/54639 para que Rust esteja realmente emitindo noalias.

Uma boa primeira coisa a tentar é algo como:

pub fn adds(a: &mut i32, b: &mut i32) {
    *a += *b;
    *a += *b;
}

e confirme se ele compila para algo como:

example::adds:
        mov     eax, dword ptr [rsi]
        add     eax, eax
        add     dword ptr [rdi], eax
        ret

e não

example::adds:
        mov     eax, dword ptr [rdi]
        add     eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        add     eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        ret

Em seguida, certifique-se de que o código de https://github.com/rust-lang/rust/issues/54462#issue -362850708 não seja mais compilado incorretamente.

@jrmuizel Observe que # 54639 inclui o reprodutor mínimo de @nagisa para # 54462 como um novo teste de compilador. Talvez uma reversão total não esteja em ordem?

Eu não acho que seja importante incluí-lo ou não porque AFAIK se trata apenas de alterar algum sinalizador padrão (que pode ser substituído por -Zmutable-noalias=yes ) e posso compilar manualmente o arquivo de teste mencionado.

Só para você saber, ainda estou tentando construir o LLVM, mas agora recebo um erro de compilação com ou sem os patches específicos de ferrugem aplicados (ou seja: apenas o mestre llvm do upstream + o patch também falha):

In file included from /usr/include/c++/8/cmath:45,
                 from /opt/rust/src/llvm-project/llvm/include/llvm-c/DataTypes.h:28,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/Support/DataTypes.h:16,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/ADT/Hashing.h:47,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/ADT/ArrayRef.h:12,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/Transforms/Utils/NoAliasUtils.h:16,
                 from /opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp:13:
/opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp: In function ‘void llvm::cloneNoAliasScopes(llvm::ArrayRef<llvm::MetadataAsValue*>, llvm::DenseMap<llvm::MDN
ode*, llvm::MDNode*>&, llvm::DenseMap<llvm::MetadataAsValue*, llvm::MetadataAsValue*>&, llvm::StringRef, llvm::LLVMContext&)’:
/opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp:174:30: error: no matching function for call to ‘llvm::AliasScopeNode::AliasScopeNode(double)’
         llvm::AliasScopeNode SNAN(MD);
                              ^~~~
In file included from /opt/rust/src/llvm-project/llvm/include/llvm/IR/TrackingMDRef.h:16,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/IR/DebugLoc.h:17,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/IR/Instruction.h:21,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/IR/BasicBlock.h:22,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/IR/Instructions.h:27,
                 from /opt/rust/src/llvm-project/llvm/include/llvm/Transforms/Utils/NoAliasUtils.h:22,
                 from /opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp:13:
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1446:12: note: candidate: ‘llvm::AliasScopeNode::AliasScopeNode(const llvm::MDNode*)’
   explicit AliasScopeNode(const MDNode *N) : Node(N) {}
            ^~~~~~~~~~~~~~
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1446:12: note:   no known conversion for argument 1 from ‘double’ to ‘const llvm::MDNode*’
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1445:3: note: candidate: ‘constexpr llvm::AliasScopeNode::AliasScopeNode()’
   AliasScopeNode() = default;
   ^~~~~~~~~~~~~~
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1445:3: note:   candidate expects 0 arguments, 1 provided
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1441:7: note: candidate: ‘constexpr llvm::AliasScopeNode::AliasScopeNode(const llvm::AliasScopeNode&)’
 class AliasScopeNode {
       ^~~~~~~~~~~~~~
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1441:7: note:   no known conversion for argument 1 from ‘double’ to ‘const llvm::AliasScopeNode&’
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1441:7: note: candidate: ‘constexpr llvm::AliasScopeNode::AliasScopeNode(llvm::AliasScopeNode&&)’
/opt/rust/src/llvm-project/llvm/include/llvm/IR/Metadata.h:1441:7: note:   no known conversion for argument 1 from ‘double’ to ‘llvm::AliasScopeNode&&’
/opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp:177:31: error: request for member ‘getName’ in ‘__builtin_nans(((const char*)""))’, which is of non-class ty
pe ‘double’
         auto ScopeName = SNAN.getName();
                               ^~~~~~~
/opt/rust/src/llvm-project/llvm/lib/Transforms/Utils/NoAliasUtils.cpp:187:39: error: request for member ‘getDomain’ in ‘__builtin_nans(((const char*)""))’, which is of non-class
type ‘double’
             const_cast<MDNode *>(SNAN.getDomain()), Name);
                                       ^~~~~~~~~
[ 75%] Building CXX object lib/Target/Hexagon/CMakeFiles/LLVMHexagonCodeGen.dir/RDFCopy.cpp.o
make[2]: *** [lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/build.make:635: lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/NoAliasUtils.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....

Talvez o mestre LLVM já tenha saído de sincronia com o patch (o que pode acontecer considerando o tamanho do patch e a velocidade com que o mestre LLVM está se movendo) e você precisa compilar com uma revisão anterior do mestre LLVM? Definitivamente valeria a pena pingar o autor do patch sobre isso.

É exatamente o que estou fazendo, tentando encontrar uma revisão mais antiga que seja compilada com o patch :-)

Agora tenho certeza de que o problema não é com llvm / master, mas sim com o patch.
O commit mais antigo de llvm / master que ainda é compatível com o patch é https://github.com/llvm/llvm-project/commit/5b99c189b3bfc0faa157f7ca39652c0bb8c315a7, mas mesmo naquele período o patch falha ao compilar.
Estou muito cansado e com preguiça de tentar entender o C ++ agora, tentarei novamente amanhã.
Enquanto isso, alguém pode entrar em contato com o autor do patch para pedir ajuda?

Eu não acho que você será capaz de usar facilmente o LLVM master com Rust (depois de realmente compilá-lo) sem corrigir o rustllvm . AFAIK suporta apenas versões 6-9 no momento.

@ mati865 Tentei primeiro aplicar o patch na bifurcação llvm-9 do Rust, mas também não foi nada trivial ...

O patch aparentemente foi realocado em llvm / llvm-project @ 82d3ba87d06f9e2abc6e27d8799587d433c56630. Será que funciona para você se você se inscrever além disso?

@jrmuizel obrigado, vou tentar isso!
Nesse ínterim, consegui adaptar com sucesso o rustllvm para compilar com o mestre do llvm.

Ping @PaulGrandperrin , alguma atualização?

https://reviews.llvm.org/D68484

Falando realisticamente, qual é o cronograma estimado e as chances gerais desse patch ser mesclado, considerando seu tamanho?

@MSxDOS Você gostaria de perguntar aos desenvolvedores LLVM. Em geral, eu esperaria que o tamanho de um patch importasse menos do que o desejo dos proprietários de vê-lo mesclado, então a pergunta a fazer é quanto o LLVM deseja vê-lo cair.

Aqui está o status mais recente que vi: https://reviews.llvm.org/D69542#1836439

Presumo que em algum momento deixará de ser relevante se https://github.com/bytecodealliance/cranelift~~ https://github.com/bjorn3/rustc_codegen_cranelift funcionar?

@leeoniya , não há um plano de curto prazo para usar cranelift para compilações opt. O cranelift não tem muito trabalho de otimização que seria necessário para tornar isso possível.

Fiquei surpreso ao descobrir o quão conservador o compilador é em relação a assumir que poderia haver aliasing sem essa opção. Por exemplo:

fn baz(s: &mut S) {
    if s.y < 10 {
        s.x = foo();
    }

    if s.y < 5 {
        s.x = foo();
    }
}

Como ele acessa os membros da estrutura por meio de &mut , ele assume que s.x e s.y podem alias, portanto, requer dois acessos à memória em vez de um para s.y . Isso é realmente lamentável, quando você considera quantas vezes o membro lê / escreve via &mut deve ser intercalado em um programa típico.

Editar: com base em alguns testes, isso não parece afetar todas as leituras / gravações, o que não é surpreendente, porque provavelmente mataria o desempenho se isso acontecesse. Ainda assim, usar -Z mutable-noalias corrige o duplo acesso à memória no exemplo acima, portanto, alguns casos podem ser interrompidos.

@PaulGrandperrin há uma nova versão deste patch em https://reviews.llvm.org/D69542 baseado em llvm @ 9fb46a452d4e5666828c95610ceac8dcd9e4ce16. Você está disposto a tentar colocá-lo em execução novamente?

Esta página foi útil?
0 / 5 - 0 avaliações