Rust: Réactivez les annotations noalias par défaut une fois que LLVM ne les compile plus mal

Créé le 6 oct. 2018  ·  33Commentaires  ·  Source: rust-lang/rust

Ce problème suit l'annulation du -Zmutable-alias=no par défaut introduit dans https://github.com/rust-lang/rust/pull/54639 en raison d'un bogue dans LLVM. cc @nagisa

( Déjà vu ? )

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

Commentaire le plus utile

Je l'ai réduit à un simple cas de test C (compiler à -O3 et -O0 et comparer la sortie):

#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]);
}

Notez que si vous supprimez restrict , l'équivalent en C de noalias , le comportement est correct. Pourtant, même alors, le assert(a != b) passe, prouvant qu'aucun UB ne peut se produire en raison de l'appel avec restrict .

Ce qui se passe c'est :

  1. copy() est intégré, ce qui donne quelque chose comme :
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. LLVM déroule la boucle :
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. LLVM pense que mat[0] ne peut pas créer d'alias avec mat[idxs[1]] ou mat[1] , ergo il ne peut pas avoir été changé entre mat[0] = 7; et mat[idxs[2]] = mat[0]; , ergo c'est sans danger pour numérotation des valeurs globales pour optimiser cette dernière à mat[idxs[2]] = 7; .

Mais mat[0] fait un alias avec mat[idxs[1]] , car idxs[1] == 0 . Et nous n'avons pas promis que ce ne serait pas le cas, car à la deuxième itération, lorsque &mat[idxs[1]] est passé à copy , l'autre argument est &mat[1] . Alors pourquoi LLVM pense-t-il qu'il ne le peut pas ?

Eh bien, cela a à voir avec la façon dont copy est inline. L'attribut de fonction noalias est transformé en métadonnées !alias.scope et !noalias sur les instructions de chargement et de stockage, comme :

  %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

Normalement, si une fonction est insérée plusieurs fois, chaque copie obtient ses propres identifiants uniques pour alias.scope et noalias, indiquant que chaque appel représente sa propre relation "d'inégalité"* entre la paire d'arguments marqués noalias ( restrict au niveau C), qui peuvent avoir des valeurs différentes pour chaque appel.

Cependant, dans ce cas, la fonction est d'abord inline dans la boucle, puis le code inline est dupliqué lorsque la boucle est déroulée - et cette duplication ne change pas les ID. Pour cette raison, LLVM pense qu'aucun des a ne peut créer d'alias avec l' un des b , ce qui est faux, car a du premier et du troisième appelle des alias avec b du deuxième appel (tous pointant vers &mat[0] ).

Étonnamment, GCC le compile également mal, avec une sortie différente. (clang et GCC à -O0 génèrent tous les deux 7 10 ; clang à -O3 génère 7 7 ; GCC à -O3 génère 10 7 .) Euh, j'espère vraiment que je ne l'ai pas fait bousiller quelque chose et ajouter UB après tout, mais je ne vois pas comment...

* C'est un peu plus compliqué que ça, mais dans ce cas, puisque copy n'utilise aucune arithmétique de pointeur et écrit sur les deux pointeurs, l'inégalité a != b est nécessaire et suffisante pour qu'un appel ne être UB.

Tous les 33 commentaires

Je travaille toujours à trouver le problème sous-jacent. Le billet intéressant est https://github.com/rust-lang/rust/issues/54462.

Utilisation de la reproduction minimale de @nagisa :


Cas de test minimisé sans code dangereux (assurez-vous de compiler avec 1 unité de 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);
}

J'ai pu diviser les passes d'optimisation de LLVM pour trouver celle qui cause l'erreur.

L'exécution de cette commande génère un exécutable fonctionnel (remplacez bug.rs par le nom du fichier dans lequel vous avez enregistré la reproduction).

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

Lors de l'exécution de cette commande, l'exécutable est cassé (le `assert_eq`` échoue) :

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

Sortie bissectrice LLVM

Pour ce fichier, l'optimisation 2261 correspond à Global Value Numbering on function (_ZN3bug6swappy17hdcc51d0e284ea38bE)

La bissectrice des révisions LLVM (à l'aide de llvmlab bisect) la réduit à r305936-r305938, vraisemblablement r305938 :

[BasicAA] Utilisez MayAlias ​​au lieu de PartialAlias ​​pour le repli.

Notez qu'il s'agit d'un changement assez ancien, de juin 2017.

Edit: En regardant la description du commit, il semble probable que le bogue existait avant cela, mais a été masqué par BasicAA empêchant l'exécution des passes d'alias ultérieures, ce que le commit a corrigé. Le cas consiste à vérifier l'aliasing entre une paire d'instructions getelementptr où le compilateur sait qu'elles ont la même adresse de base mais ne connaît pas les décalages.

Edit2 : De plus, passer -enable-scoped-noalias=false tant qu'option LLVM empêche les erreurs de compilation. (Ce n'est pas surprenant puisque cela désactive complètement la gestion des noalias, mais juste au cas où cela aiderait…)

En regardant l'IR pré-GVN, j'ai l'impression que la cause première ici pourrait être en boucle, selon que ma compréhension du fonctionnement des annotations d'alias LLVM est correcte.

Considérez un code comme

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

a[i & 1] et b[i & 1] ne créent pas d'alias au sein d'une seule itération , mais a et b en général peuvent créer des alias.

Dans LLVM IR, cela donnerait quelque chose comme :

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}

Si nous exécutons cela à travers -loop-unroll nous obtenons :

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}

Notez comment les quatre copies de la boucle utilisent des métadonnées d'alias sur le même domaine d'alias. Au lieu d'être des noalias au sein d'une seule itération, c'est des noalias sur l'ensemble de la fonction.

Finalement, -scoped-noalias -gvn nous donne :

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}

Et cela entraînera des résultats incorrects si a = b + 1 .

Il est possible de reproduire ce problème à partir de C avec le code suivant :

#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;
}

Avec Clang 6.0, cela imprime 2 2 2 à -O0 et 1 2 2 à -O3 . Je ne sais pas si ce code est légal sous la sémantique restrict en C, mais je pense qu'il devrait être légal sous la sémantique noalias plus stricte de LLVM.

Je l'ai réduit à un simple cas de test C (compiler à -O3 et -O0 et comparer la sortie):

#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]);
}

Notez que si vous supprimez restrict , l'équivalent en C de noalias , le comportement est correct. Pourtant, même alors, le assert(a != b) passe, prouvant qu'aucun UB ne peut se produire en raison de l'appel avec restrict .

Ce qui se passe c'est :

  1. copy() est intégré, ce qui donne quelque chose comme :
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. LLVM déroule la boucle :
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. LLVM pense que mat[0] ne peut pas créer d'alias avec mat[idxs[1]] ou mat[1] , ergo il ne peut pas avoir été changé entre mat[0] = 7; et mat[idxs[2]] = mat[0]; , ergo c'est sans danger pour numérotation des valeurs globales pour optimiser cette dernière à mat[idxs[2]] = 7; .

Mais mat[0] fait un alias avec mat[idxs[1]] , car idxs[1] == 0 . Et nous n'avons pas promis que ce ne serait pas le cas, car à la deuxième itération, lorsque &mat[idxs[1]] est passé à copy , l'autre argument est &mat[1] . Alors pourquoi LLVM pense-t-il qu'il ne le peut pas ?

Eh bien, cela a à voir avec la façon dont copy est inline. L'attribut de fonction noalias est transformé en métadonnées !alias.scope et !noalias sur les instructions de chargement et de stockage, comme :

  %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

Normalement, si une fonction est insérée plusieurs fois, chaque copie obtient ses propres identifiants uniques pour alias.scope et noalias, indiquant que chaque appel représente sa propre relation "d'inégalité"* entre la paire d'arguments marqués noalias ( restrict au niveau C), qui peuvent avoir des valeurs différentes pour chaque appel.

Cependant, dans ce cas, la fonction est d'abord inline dans la boucle, puis le code inline est dupliqué lorsque la boucle est déroulée - et cette duplication ne change pas les ID. Pour cette raison, LLVM pense qu'aucun des a ne peut créer d'alias avec l' un des b , ce qui est faux, car a du premier et du troisième appelle des alias avec b du deuxième appel (tous pointant vers &mat[0] ).

Étonnamment, GCC le compile également mal, avec une sortie différente. (clang et GCC à -O0 génèrent tous les deux 7 10 ; clang à -O3 génère 7 7 ; GCC à -O3 génère 10 7 .) Euh, j'espère vraiment que je ne l'ai pas fait bousiller quelque chose et ajouter UB après tout, mais je ne vois pas comment...

* C'est un peu plus compliqué que ça, mais dans ce cas, puisque copy n'utilise aucune arithmétique de pointeur et écrit sur les deux pointeurs, l'inégalité a != b est nécessaire et suffisante pour qu'un appel ne être UB.

Heh, on dirait que j'ai couru avec @nikic pour trouver la même explication. Leur cas de test est légèrement plus sympa :)

C'est un très bon timing ^^ Nous sommes arrivés à la même conclusion avec presque le même cas de test réduit en même temps :)

Pour résoudre ce problème, quelque chose du genre https://github.com/llvm-mirror/llvm/blob/54d4881c352796b18bfe7314662a294754e3a752/lib/Transforms/Utils/InlineFunction.cpp#L801 doit également être fait dans LoopUnrollPass.

J'ai soumis un rapport de bogue LLVM pour ce problème à l' adresse https://bugs.llvm.org/show_bug.cgi?id=39282.

Et – en mentionnant simplement cela pour être complet – j'ai soumis un rapport de bogue à GCC car il a également mal compilé mon cas de test C : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87609

Triage : Si je lis ceci correctement, le correctif LLVM a été accepté (https://reviews.llvm.org/D9375). Je ne sais pas ce que cela signifie pour la fusion dans LLVM, ou quand cela s'est produit ; quelqu'un de mieux informé sur le processus de révision de LLVM devrait vérifier si le problème est résolu maintenant (et pour quelles versions).

Il n'est pas fusionné, le processus de révision était un peu étrange et la personne qui l'a approuvé ne révise plus les correctifs.

Il y a eu un appel à tester avec l'ensemble de correctifs "full restrict". Il serait probablement utile que quelqu'un essaie de réactiver noalias dans Rust en plus d'un llvm auquel cet ensemble de correctifs est appliqué.

Je suis prêt à essayer de le faire.
J'ai accès à des serveurs moyennement puissants (48 cores HT, 128G de ram) et je pense arriver à tout construire correctement avec le patch.
Une fois que j'ai une chaîne d'outils fonctionnelle, quelles caisses recommanderiez-vous d'essayer ?

J'ai fini de fusionner tous les commits spécifiques à la rouille sur le maître en amont de llvm, puis patch .
Voici la branche résultante : https://github.com/PaulGrandperrin/llvm-project/tree/llvm-master-with-rustlang-patches-and-D69542
Je vais maintenant essayer de compiler la chaîne d'outils et l'essayer

Assurez-vous d'abord de revenir: https://github.com/rust-lang/rust/pull/54639 afin que Rust émette réellement des noalias.

Une bonne première chose à essayer est quelque chose comme :

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

et confirmez qu'il compile vers quelque chose comme :

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

et pas

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

Ensuite, assurez-vous que le code de https://github.com/rust-lang/rust/issues/54462#issue -362850708 n'est plus mal compilé.

@jrmuizel Notez que # 54639 ne comprend @nagisa « s reproducer minimale pour # 54462 comme un nouveau test du compilateur. Peut-être qu'un retour complet n'est pas en ordre ?

Je ne pense pas qu'il soit important de l'inclure ou non car, autant que je sache, il s'agit uniquement de changer un indicateur par défaut (qui peut être remplacé par -Zmutable-noalias=yes ) et je peux compiler manuellement le fichier de test mentionné.

Juste pour que vous le sachiez, j'essaie toujours de compiler LLVM mais pour l'instant, j'obtiens une erreur de compilation avec ou sans les correctifs spécifiques à la rouille appliqués (c'est-à-dire : juste le maître llvm en amont + le correctif échoue aussi) :

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....

Peut-être que le maître LLVM s'est déjà désynchronisé avec le correctif (ce qui pourrait arriver compte tenu de la taille du correctif et de la vitesse à laquelle le maître LLVM se déplace) et vous devez vous baser sur une ancienne révision du maître LLVM ? Cela vaudrait certainement la peine d'envoyer un ping à l'auteur du patch à ce sujet.

C'est exactement ce que je fais, en essayant de trouver une révision plus ancienne qui se construit avec le correctif :-)

Je suis maintenant sûr que le problème ne vient pas de llvm/master mais du patch.
Le plus ancien commit de llvm/master qui est toujours compatible avec le correctif est https://github.com/llvm/llvm-project/commit/5b99c189b3bfc0faa157f7ca39652c0bb8c315a7 mais même si loin, le correctif ne parvient pas à se compiler.
Je suis trop fatigué et paresseux pour essayer de comprendre le C++ maintenant, je réessayerai demain.
En attendant, quelqu'un peut-il contacter l'auteur du patch pour lui demander de l'aide ?

Je ne pense pas que vous puissiez utiliser facilement le LLVM maître avec Rust (après l'avoir construit) sans patcher rustllvm . AFAIK, il ne prend en charge que les versions 6-9 pour le moment.

@ mati865 J'ai d'abord essayé d'appliquer le patch sur la fourche llvm-9 de rouille mais ce n'était pas non plus anodin...

Le correctif est apparemment rebasé sur llvm/ llvm-project@82d3ba87d06f9e2abc6e27d8799587d433c56630. Est-ce que cela se construit pour vous si vous postulez en plus de cela?

@jrmuizel merci je vais essayer ça !
En attendant, j'ai réussi à adapter rustllvm pour construire avec llvm master.

Ping @PaulGrandperrin , des nouvelles ?

https://reviews.llvm.org/D68484

De manière réaliste, quelle est la chronologie estimée et les chances globales de fusion de ce patch, compte tenu de sa taille ?

@MSxDOS Vous voudriez demander aux développeurs LLVM. En général, je m'attendrais à ce que la taille d'un patch importe moins que le désir des propriétaires de le voir fusionné, donc la question à se poser est de savoir à quel point LLVM veut le voir atterrir.

Voici le dernier statut que j'ai vu : https://reviews.llvm.org/D69542#1836439

Je suppose qu'à un moment donné, cela cessera d'être pertinent si https://github.com/bytecodealliance/cranelift~~ https://github.com/bjorn3/rustc_codegen_cranelift fonctionne ?

@leeoniya , il n'y a pas de plan à court terme pour utiliser un pont roulant pour des constructions opt. Cranelift n'a pas beaucoup de travail d'optimisation qui serait nécessaire pour rendre cela possible.

J'ai été surpris de découvrir à quel point le compilateur est prudent en supposant qu'il pourrait y avoir un alias sans cette option. Par example:

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

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

Parce qu'il accède aux membres de la structure via un &mut , il suppose que s.x et s.y peuvent créer un alias, il nécessite donc deux accès mémoire au lieu d'un pour s.y . C'est vraiment malheureux, quand on considère combien de fois les lectures/écritures de membres via &mut doivent être entrelacées dans un programme typique.

Edit : sur la base de certains tests, cela ne semble pas affecter toutes ces lectures/écritures, ce qui n'est pas surprenant, car cela tuerait probablement les performances si c'était le cas. Néanmoins, l'utilisation de -Z mutable-noalias corrige le double accès à la mémoire dans l'exemple ci-dessus, de sorte que certains cas peuvent être bloqués.

@PaulGrandperrin, il existe une nouvelle version de ce correctif sur https://reviews.llvm.org/D69542 basée sur llvm@9fb46a452d4e5666828c95610ceac8dcd9e4ce16. Êtes-vous prêt à essayer de le faire fonctionner à nouveau ?

Cette page vous a été utile?
0 / 5 - 0 notes