Rust: Aktifkan kembali anotasi noalias secara default setelah LLVM tidak lagi salah mengkompilasinya

Dibuat pada 6 Okt 2018  ·  33Komentar  ·  Sumber: rust-lang/rust

Masalah ini melacak pembatalan default -Zmutable-alias=no diperkenalkan di https://github.com/rust-lang/rust/pull/54639 karena bug di LLVM. cc @nagisa

( Dejavu? )

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

Komentar yang paling membantu

Saya menguranginya menjadi kasus uji C sederhana (kompilasi di -O3 dan -O0 dan bandingkan output):

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

Perhatikan bahwa jika Anda menghapus restrict , C setara dengan noalias , perilakunya benar. Namun meskipun demikian, assert(a != b) lolos, membuktikan bahwa tidak ada UB yang dapat terjadi karena memanggilnya dengan restrict .

Apa yang terjadi adalah:

  1. copy() menjadi sebaris, menghasilkan sesuatu seperti:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. LLVM membuka gulungan 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. LLVM berpikir mat[0] tidak dapat alias dengan mat[idxs[1]] atau mat[1] , ergo itu tidak dapat diubah antara mat[0] = 7; dan mat[idxs[2]] = mat[0]; , ergo aman untuk penomoran nilai global untuk mengoptimalkan yang terakhir menjadi mat[idxs[2]] = 7; .

Tapi mat[0] melakukan alias dengan mat[idxs[1]] , karena idxs[1] == 0 . Dan kami tidak berjanji tidak akan melakukannya, karena pada iterasi kedua ketika &mat[idxs[1]] diteruskan ke copy , argumen lainnya adalah &mat[1] . Jadi mengapa LLVM berpikir itu tidak bisa?

Nah, itu ada hubungannya dengan cara copy digarisbawahi. Atribut fungsi noalias diubah menjadi metadata !alias.scope dan !noalias pada instruksi pemuatan dan penyimpanan, seperti:

  %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

Biasanya, jika suatu fungsi digarisbawahi beberapa kali, setiap salinan mendapatkan ID uniknya sendiri untuk alias.scope dan noalias, yang menunjukkan bahwa setiap panggilan mewakili hubungan 'ketidaksetaraan' sendiri* antara pasangan argumen yang ditandai noalias ( restrict pada level C), yang mungkin memiliki nilai berbeda untuk setiap panggilan.

Namun, dalam kasus ini, pertama-tama fungsi tersebut dimasukkan ke dalam loop, kemudian kode inline diduplikasi saat loop dibuka – dan duplikasi ini tidak mengubah ID. Karena itu, LLVM tidak ada berpikir a 's kaleng alias dengan salah satu b ' s, yang palsu, karena a dari alias panggilan pertama dan ketiga dengan b dari panggilan kedua (semua menunjuk ke &mat[0] ).

Hebatnya, GCC juga salah mengkompilasi ini, dengan output yang berbeda. (dentang dan GCC pada -O0 keduanya menghasilkan 7 10 ; dentang pada -O3 menghasilkan 7 7 ; GCC pada -O3 menghasilkan 10 7 .) Uh, saya sangat berharap tidak melakukannya mengacaukan sesuatu dan menambahkan UB, tapi saya tidak mengerti caranya ...

* Ini sedikit lebih rumit dari itu, tetapi dalam kasus ini, karena copy tidak menggunakan aritmatika pointer dan menulis ke kedua pointer, ketidaksetaraan a != b diperlukan dan cukup untuk panggilan tidak ke menjadi UB.

Semua 33 komentar

Saya masih berusaha mencari tahu masalah mendasarnya. Tiket menariknya adalah https://github.com/rust-lang/rust/issues/54462.

Menggunakan reproduksi minimal @nagisa :


Kasus uji yang diperkecil tanpa kode yang tidak aman (pastikan untuk mengompilasi dengan 1 unit 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);
}

Saya dapat membagi dua pass pengoptimalan LLVM untuk menemukan yang menyebabkan kesalahan.

Menjalankan perintah ini menghasilkan eksekusi yang berfungsi (ganti bug.rs dengan nama file tempat Anda menyimpan reproduksi).

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

Saat menjalankan perintah ini menghasilkan executable yang rusak (`assert_eq`` gagal):

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

Output membagi dua LLVM

Untuk file ini, optimasi 2261 sesuai dengan Global Value Numbering on function (_ZN3bug6swappy17hdcc51d0e284ea38bE)

Membagi dua revisi LLVM (menggunakan llvmlab membagi dua) mempersempitnya menjadi r305936-r305938, mungkin r305938:

[BasicAA] Gunakan MayAlias ​​alih-alih PartialAlias ​​untuk fallback.

Perhatikan bahwa ini adalah perubahan yang cukup lama, dari Juni 2017.

Sunting: Melihat deskripsi komit, sepertinya bug sudah ada sebelumnya, tetapi ditutupi oleh BasicAA yang mencegah alias lewat dari berjalan, yang diperbaiki oleh komit. Kasus ini melibatkan pemeriksaan aliasing antara sepasang instruksi getelementptr mana kompiler mengetahui bahwa mereka memiliki alamat dasar yang sama tetapi tidak mengetahui offsetnya.

Sunting2: Juga, meneruskan -enable-scoped-noalias=false sebagai opsi LLVM mencegah kesalahan kompilasi. (Ini tidak mengherankan karena itu menonaktifkan penanganan noalias sama sekali, tetapi untuk berjaga-jaga jika itu membantu ...)

Dari melihat IR pra-GVN, saya merasa seperti akar penyebab di sini mungkin dalam lingkaran terbuka, tergantung pada apakah pemahaman saya tentang cara kerja anotasi aliasing LLVM sudah benar.

Pertimbangkan kode seperti

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

di mana a[i & 1] dan b[i & 1] tidak alias dalam satu iterasi , tetapi a dan b secara umum mungkin alias.

Di LLVM IR ini akan menjadi seperti:

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}

Jika kita menjalankan ini melalui -loop-unroll kita mendapatkan:

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}

Perhatikan bagaimana keempat salinan loop menggunakan metadata aliasing pada domain aliasing yang sama. Alih-alih menjadi noalia dalam satu iterasi, ini adalah noalia di seluruh fungsi.

Akhirnya, -scoped-noalias -gvn memberi kita:

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}

Dan ini akan menghasilkan hasil yang salah jika a = b + 1 .

Dimungkinkan untuk mereproduksi masalah ini dari C dengan kode berikut:

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

Dengan Dentang 6.0 ini mencetak 2 2 2 pada -O0 dan 1 2 2 pada -O3 . Saya tidak yakin apakah kode ini legal di bawah semantik restrict di C, tapi saya pikir itu harus legal di bawah semantik noalias lebih ketat dari LLVM.

Saya menguranginya menjadi kasus uji C sederhana (kompilasi di -O3 dan -O0 dan bandingkan output):

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

Perhatikan bahwa jika Anda menghapus restrict , C setara dengan noalias , perilakunya benar. Namun meskipun demikian, assert(a != b) lolos, membuktikan bahwa tidak ada UB yang dapat terjadi karena memanggilnya dengan restrict .

Apa yang terjadi adalah:

  1. copy() menjadi sebaris, menghasilkan sesuatu seperti:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. LLVM membuka gulungan 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. LLVM berpikir mat[0] tidak dapat alias dengan mat[idxs[1]] atau mat[1] , ergo itu tidak dapat diubah antara mat[0] = 7; dan mat[idxs[2]] = mat[0]; , ergo aman untuk penomoran nilai global untuk mengoptimalkan yang terakhir menjadi mat[idxs[2]] = 7; .

Tapi mat[0] melakukan alias dengan mat[idxs[1]] , karena idxs[1] == 0 . Dan kami tidak berjanji tidak akan melakukannya, karena pada iterasi kedua ketika &mat[idxs[1]] diteruskan ke copy , argumen lainnya adalah &mat[1] . Jadi mengapa LLVM berpikir itu tidak bisa?

Nah, itu ada hubungannya dengan cara copy digarisbawahi. Atribut fungsi noalias diubah menjadi metadata !alias.scope dan !noalias pada instruksi pemuatan dan penyimpanan, seperti:

  %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

Biasanya, jika suatu fungsi digarisbawahi beberapa kali, setiap salinan mendapatkan ID uniknya sendiri untuk alias.scope dan noalias, yang menunjukkan bahwa setiap panggilan mewakili hubungan 'ketidaksetaraan' sendiri* antara pasangan argumen yang ditandai noalias ( restrict pada level C), yang mungkin memiliki nilai berbeda untuk setiap panggilan.

Namun, dalam kasus ini, pertama-tama fungsi tersebut dimasukkan ke dalam loop, kemudian kode inline diduplikasi saat loop dibuka – dan duplikasi ini tidak mengubah ID. Karena itu, LLVM tidak ada berpikir a 's kaleng alias dengan salah satu b ' s, yang palsu, karena a dari alias panggilan pertama dan ketiga dengan b dari panggilan kedua (semua menunjuk ke &mat[0] ).

Hebatnya, GCC juga salah mengkompilasi ini, dengan output yang berbeda. (dentang dan GCC pada -O0 keduanya menghasilkan 7 10 ; dentang pada -O3 menghasilkan 7 7 ; GCC pada -O3 menghasilkan 10 7 .) Uh, saya sangat berharap tidak melakukannya mengacaukan sesuatu dan menambahkan UB, tapi saya tidak mengerti caranya ...

* Ini sedikit lebih rumit dari itu, tetapi dalam kasus ini, karena copy tidak menggunakan aritmatika pointer dan menulis ke kedua pointer, ketidaksetaraan a != b diperlukan dan cukup untuk panggilan tidak ke menjadi UB.

Heh, sepertinya saya berpacu dengan @nikic untuk menemukan penjelasan yang sama. Test case mereka sedikit lebih bagus :)

Itu waktu yang sangat tepat ^^ Kami mencapai kesimpulan yang sama dengan kasus uji tereduksi yang hampir sama pada saat yang bersamaan :)

Untuk memperbaikinya, mungkin sesuatu di sepanjang baris https://github.com/llvm-mirror/llvm/blob/54d4881c352796b18bfe7314662a294754e3a752/lib/Transforms/Utils/InlineFunction.cpp#L801 perlu juga dilakukan di LoopUnrollPass.

Saya telah mengirimkan laporan bug LLVM untuk masalah ini di https://bugs.llvm.org/show_bug.cgi?id=39282.

Dan – hanya menyebutkan ini untuk kelengkapan – saya mengirimkan laporan bug ke GCC karena itu juga salah mengkompilasi kasus uji C saya: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87609

Triase: Jika saya membaca ini dengan benar, perbaikan LLVM diterima (https://reviews.llvm.org/D9375). Saya tidak yakin apa artinya benar-benar bergabung ke LLVM, atau kapan itu terjadi; seseorang yang lebih berpengetahuan tentang proses revisi LLVM harus memeriksa apakah masalah telah diperbaiki sekarang (dan untuk versi apa).

Itu tidak digabungkan, proses peninjauannya agak aneh dan orang yang menyetujuinya tidak meninjau tambalan lagi.

Ada panggilan untuk pengujian dengan set tambalan "batas penuh". Mungkin akan bermanfaat jika seseorang mencoba mengaktifkan kembali noalia di Rust di atas llvm yang menerapkan set tambalan ini.

Saya bersedia untuk mencoba melakukan itu.
Saya memiliki akses ke server yang cukup kuat (48 HT core, 128G ram) dan saya pikir saya dapat mengatur untuk membangun semuanya dengan benar dengan patch.
Setelah saya memiliki rantai alat yang berfungsi, peti mana yang akan Anda rekomendasikan untuk dicoba?

Saya selesai menggabungkan semua komit khusus karat pada master hulu llvm dan kemudian menerapkan patch .
Inilah cabang yang dihasilkan: https://github.com/PaulGrandperrin/llvm-project/tree/llvm-master-with-rustlang-patches-and-D69542
Sekarang saya akan mencoba mengkompilasi rantai alat dan mencobanya

Pertama, pastikan Anda mengembalikan: https://github.com/rust-lang/rust/pull/54639 sehingga Rust benar-benar memancarkan noalias.

Hal pertama yang baik untuk dicoba adalah sesuatu seperti:

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

dan konfirmasikan bahwa itu dikompilasi menjadi sesuatu seperti:

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

dan tidak

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

Selanjutnya, pastikan kode dari https://github.com/rust-lang/rust/issues/54462#issue -36280708 tidak lagi salah kompilasi.

@jrmuizel Perhatikan bahwa # 54639 tidak termasuk @nagisa 's reproducer minimal untuk # 54.462 sebagai tes compiler baru. Mungkin pengembalian penuh tidak berurutan?

Saya tidak berpikir penting untuk memasukkannya atau tidak karena AFAIK ini hanya tentang mengubah beberapa flag default (yang dapat diganti dengan -Zmutable-noalias=yes ) dan saya dapat secara manual mengkompilasi file tes yang disebutkan.

Asal tahu saja, saya masih mencoba membangun LLVM tetapi sampai sekarang saya mendapatkan kesalahan kompilasi dengan atau tanpa tambalan khusus karat yang diterapkan (yaitu: hanya master llvm hulu + tambalan juga gagal):

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

Mungkin master LLVM sudah tidak sinkron dengan tambalan (yang bisa terjadi mengingat seberapa besar tambalan dan seberapa cepat master LLVM bergerak) dan Anda perlu membangun terhadap revisi master LLVM yang lebih lama? Pasti akan bermanfaat untuk melakukan ping ke penulis tambalan tentang ini.

Itulah tepatnya yang saya lakukan, mencoba menemukan revisi lama yang dibuat dengan tambalan :-)

Saya sekarang yakin masalahnya bukan dengan llvm/master tetapi dari tambalan.
Komit tertua dari llvm/master yang masih kompatibel dengan tambalan adalah https://github.com/llvm/llvm-project/commit/5b99c189b3bfc0faa157f7ca39652c0bb8c315a7 tetapi bahkan sejauh itu tambalan gagal dikompilasi.
Saya terlalu lelah dan malas untuk mencoba memahami C++ sekarang, saya akan mencoba lagi besok.
Sementara itu, dapatkah seseorang menghubungi pembuat tambalan untuk meminta bantuan?

Saya tidak berpikir Anda akan dapat dengan mudah menggunakan master LLVM dengan Rust (setelah Anda benar-benar membuatnya) tanpa menambal rustllvm . AFAIK hanya mendukung rilis 6-9 sekarang.

@mati865 Saya mencoba terlebih dahulu untuk menerapkan tambalan pada garpu llvm-9 karat tetapi itu juga tidak sepele ...

Tambalan ini tampaknya dibuat ulang di atas llvm/

@jrmuizel terima kasih saya akan mencobanya!
Sementara itu, saya berhasil mengadaptasi rustllvm ke build dengan llvm master.

Ping @PaulGrandperrin , ada pembaruan?

https://reviews.llvm.org/D68484

Secara realistis, berapa perkiraan waktu dan peluang keseluruhan patch ini untuk digabungkan, mengingat ukurannya?

@MSxDOS Anda ingin bertanya kepada pengembang LLVM. Secara umum saya berharap bahwa ukuran tambalan kurang penting daripada keinginan pemilik untuk melihatnya bergabung, jadi pertanyaan untuk diajukan adalah seberapa besar LLVM ingin melihatnya mendarat.

Berikut status terbaru yang saya lihat: https://reviews.llvm.org/D69542#1836439

saya berasumsi di beberapa titik itu akan berhenti relevan jika https://github.com/bytecodealliance/cranelift~~ https://github.com/bjorn3/rustc_codegen_cranelift berhasil?

@leeoniya , tidak ada rencana jangka pendek untuk menggunakan cranelift untuk opt build. cranelift tidak memiliki banyak pekerjaan pengoptimalan yang diperlukan untuk mewujudkannya.

Saya terkejut mengetahui betapa konservatifnya kompiler sehubungan dengan asumsi mungkin ada aliasing tanpa opsi ini. Sebagai contoh:

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

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

Karena mengakses anggota struct melalui &mut , ia mengasumsikan bahwa s.x dan s.y can alias, jadi memerlukan dua akses memori alih-alih satu untuk s.y . Sangat disayangkan, ketika Anda mempertimbangkan berapa kali anggota membaca/menulis melalui &mut harus disisipkan dalam program biasa.

Sunting: berdasarkan beberapa pengujian, ini tampaknya tidak memengaruhi semua pembacaan/penulisan seperti itu, yang tidak mengejutkan, karena mungkin akan mematikan kinerja jika itu terjadi. Namun, menggunakan -Z mutable-noalias memperbaiki akses memori ganda dalam contoh di atas, jadi beberapa kasus mungkin rusak.

@PaulGrandperrin ada versi baru dari patch ini di https://reviews.llvm.org/D69542 berdasarkan llvm@9fb46a452d4e5666828c95610ceac8dcd9e4ce16. Apakah Anda bersedia untuk mencoba menjalankannya lagi?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat