Rust: أعد تمكين التعليقات التوضيحية noalias افتراضيًا بمجرد أن لا يخطئ LLVM في تجميعها

تم إنشاؤها على ٦ أكتوبر ٢٠١٨  ·  33تعليقات  ·  مصدر: rust-lang/rust

تتعقب هذه المشكلة التراجع عن القيمة الافتراضية -Zmutable-alias=no المقدمة في https://github.com/rust-lang/rust/pull/54639 بسبب خطأ في LLVM. cc نجيزا

( ديجا فو؟ )

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

التعليق الأكثر فائدة

لقد اختزلته إلى حالة اختبار C بسيطة (تجميعها في -O3 و -O0 ومقارنة الإخراج):

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

لاحظ أنه إذا قمت بإزالة restrict ، أي ما يعادل C noalias ، فإن السلوك يكون صحيحًا. ومع ذلك ، فإن assert(a != b) يمر ، مما يثبت أنه لا يمكن أن يحدث UB بسبب استدعائه بـ restrict .

ما يحدث هو:

  1. نسخة () مضمنة ، مما يؤدي إلى شيء مثل:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. يفتح LLVM الحلقة:
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 أن mat[0] لا يمكن أن يكون الاسم المستعار مع mat[idxs[1]] أو mat[1] ، لذا لا يمكن تغييره بين mat[0] = 7; و mat[idxs[2]] = mat[0]; ، لذا فهو آمن لـ ترقيم القيمة العالمية لتحسين هذا الأخير إلى mat[idxs[2]] = 7; .

ولكن mat[0] لا اسم مستعار مع mat[idxs[1]] ، لأن idxs[1] == 0 . ولم نعد بذلك ، لأنه في التكرار الثاني عندما يتم تمرير &mat[idxs[1]] إلى copy ، تكون الوسيطة الأخرى هي &mat[1] . فلماذا تعتقد LLVM أنها لا تستطيع ذلك؟

حسنًا ، يتعلق الأمر بالطريقة التي يتم بها تضمين copy . تم تحويل سمة الوظيفة noalias إلى بيانات وصفية !alias.scope و !noalias في إرشادات التحميل والتخزين ، مثل:

  %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

عادةً ، إذا تم تضمين دالة عدة مرات ، تحصل كل نسخة على معرفاتها الفريدة الخاصة بها لـ alias.scope و noalias ، مما يشير إلى أن كل استدعاء يمثل علاقة "عدم المساواة" الخاصة بها * بين زوج الوسيطات المميزة بعلامة noalias ( restrict عند المستوى C) ، والتي قد تحتوي على قيم مختلفة لكل مكالمة.

ومع ذلك ، في هذه الحالة ، يتم أولاً تضمين الوظيفة في الحلقة ، ثم يتم تكرار الشفرة المضمنة عندما تكون الحلقة غير منضبطة - وهذا التكرار لا يغير المعرفات. لهذا السبب ، لا تعتقد LLVM أن a يمكن استخدامها مع أي من b 's ، وهذا خطأ ، لأن a من الأسماء المستعارة الأولى والثالثة مع b من المكالمة الثانية (تشير جميعها إلى &mat[0] ).

والمثير للدهشة أن مجلس التعاون الخليجي يخطئ أيضًا في تجميع هذا ، بإنتاج مختلف. (clang and GCC at -O0 كلاهما ناتج 7 10 ؛ clang at -O3 الناتج 7 7 ؛ GCC at -O3 الناتج 10 7 .) آه ، آمل حقًا أنني لم أفعل أفسد شيئًا ما وأضف UB بعد كل شيء ، لكنني لا أرى كيف ...

* الأمر أكثر تعقيدًا قليلاً من ذلك ، ولكن في هذه الحالة ، نظرًا لأن copy لا يستخدم أي مؤشر حسابي ويكتب إلى كلا المؤشرين ، فإن عدم المساواة a != b ضرورية وكافية لاستدعاء عدم كن UB.

ال 33 كومينتر

ما زلت أعمل على اكتشاف المشكلة الأساسية. التذكرة الممتعة هي https://github.com/rust-lang/rust/issues/54462.

باستخدام الحد الأدنى من استنساخ nagisa :


حالة الاختبار المصغرة مع عدم وجود رمز غير آمن (تأكد من التجميع باستخدام وحدة كود واحدة!):

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

لقد تمكنت من تقسيم ممرات التحسين الخاصة بـ LLVM للعثور على الشخص الذي يسبب الخطأ.

يؤدي تشغيل هذا الأمر إلى عمل قابل للتنفيذ (استبدل bug.rs باسم الملف الذي حفظت النسخ فيه).

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

أثناء تشغيل هذا الأمر ينتج عنه ملف تنفيذي معطل (يفشل `` assert_eq ''):

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

إخراج LLVM منصف

بالنسبة لهذا الملف ، يتوافق التحسين 2261 مع Global Value Numbering on function (_ZN3bug6swappy17hdcc51d0e284ea38bE)

يؤدي تشريح مراجعات LLVM (باستخدام llvmlab bisect) إلى تضييقه إلى r305936-r305938 ، ويفترض r305938:

[BasicAA] استخدم MayAlias ​​بدلاً من PartialAlias ​​كبديل.

لاحظ أن هذا تغيير قديم جدًا ، بدءًا من يونيو 2017.

تحرير: بالنظر إلى وصف الالتزام ، يبدو من المحتمل أن الخطأ كان موجودًا قبل ذلك ، ولكن تم حجبه بواسطة BasicAA مما منع تشغيل الأسماء المستعارة اللاحقة ، وهو ما تم إصلاحه في الالتزام. تتضمن الحالة التحقق من الاسم المستعار بين زوج من التعليمات getelementptr حيث يعلم المترجم أن لديهم نفس العنوان الأساسي ولكن لا يعرف الإزاحات.

تحرير 2: أيضًا ، يؤدي تمرير -enable-scoped-noalias=false كخيار LLVM إلى منع الخطأ في الجمع. (هذا ليس مفاجئًا لأن ذلك يعطل معالجة noalias تمامًا ، ولكن فقط في حالة ما إذا كان ذلك مفيدًا…)

من خلال إلقاء نظرة على ما قبل GVN IR ، أشعر أن السبب الأساسي هنا قد يكون في حلقة متدرجة ، اعتمادًا على ما إذا كان فهمي لكيفية عمل التعليقات التوضيحية لتسمية LLVM صحيحًا.

النظر في رمز مثل

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

حيث لا يكون a[i & 1] و b[i & 1] اسمًا مستعارًا ضمن تكرار واحد ، ولكن a و b بشكل عام قد يكونان اسمًا مستعارًا.

في LLVM IR ، سيحدث هذا شيئًا مثل:

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}

إذا قمنا بتشغيل هذا من خلال -loop-unroll فسنحصل على:

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}

لاحظ كيف تستخدم جميع النسخ الأربع للحلقة بيانات وصفية للتسمية المستعارة على نفس النطاق المستعار. بدلاً من أن تكون noalias في تكرار واحد ، فهي noalias عبر الوظيفة بأكملها.

أخيرًا ، يمنحنا -scoped-noalias -gvn :

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}

وهذا سينتج عنه نتائج غير صحيحة إذا كان a = b + 1 .

من الممكن إعادة إظهار هذه المشكلة من C بالرمز التالي:

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

باستخدام Clang 6.0 ، يطبع هذا 2 2 2 بسعر -O0 و 1 2 2 بسعر -O3 . أنا لست متأكدا مما اذا كان هذا الرمز هو قانوني بموجب restrict دلالات في C، ولكن أعتقد أنه يجب أن يكون قانونيا تحت صرامة noalias دلالات LLVM.

لقد اختزلته إلى حالة اختبار C بسيطة (تجميعها في -O3 و -O0 ومقارنة الإخراج):

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

لاحظ أنه إذا قمت بإزالة restrict ، أي ما يعادل C noalias ، فإن السلوك يكون صحيحًا. ومع ذلك ، فإن assert(a != b) يمر ، مما يثبت أنه لا يمكن أن يحدث UB بسبب استدعائه بـ restrict .

ما يحدث هو:

  1. نسخة () مضمنة ، مما يؤدي إلى شيء مثل:
for (int i = 0; i < 3; i++) {
    mat[idxs[i]] = mat[i%2]; mat[i%2] = 7;
}
  1. يفتح LLVM الحلقة:
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 أن mat[0] لا يمكن أن يكون الاسم المستعار مع mat[idxs[1]] أو mat[1] ، لذا لا يمكن تغييره بين mat[0] = 7; و mat[idxs[2]] = mat[0]; ، لذا فهو آمن لـ ترقيم القيمة العالمية لتحسين هذا الأخير إلى mat[idxs[2]] = 7; .

ولكن mat[0] لا اسم مستعار مع mat[idxs[1]] ، لأن idxs[1] == 0 . ولم نعد بذلك ، لأنه في التكرار الثاني عندما يتم تمرير &mat[idxs[1]] إلى copy ، تكون الوسيطة الأخرى هي &mat[1] . فلماذا تعتقد LLVM أنها لا تستطيع ذلك؟

حسنًا ، يتعلق الأمر بالطريقة التي يتم بها تضمين copy . تم تحويل سمة الوظيفة noalias إلى بيانات وصفية !alias.scope و !noalias في إرشادات التحميل والتخزين ، مثل:

  %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

عادةً ، إذا تم تضمين دالة عدة مرات ، تحصل كل نسخة على معرفاتها الفريدة الخاصة بها لـ alias.scope و noalias ، مما يشير إلى أن كل استدعاء يمثل علاقة "عدم المساواة" الخاصة بها * بين زوج الوسيطات المميزة بعلامة noalias ( restrict عند المستوى C) ، والتي قد تحتوي على قيم مختلفة لكل مكالمة.

ومع ذلك ، في هذه الحالة ، يتم أولاً تضمين الوظيفة في الحلقة ، ثم يتم تكرار الشفرة المضمنة عندما تكون الحلقة غير منضبطة - وهذا التكرار لا يغير المعرفات. لهذا السبب ، لا تعتقد LLVM أن a يمكن استخدامها مع أي من b 's ، وهذا خطأ ، لأن a من الأسماء المستعارة الأولى والثالثة مع b من المكالمة الثانية (تشير جميعها إلى &mat[0] ).

والمثير للدهشة أن مجلس التعاون الخليجي يخطئ أيضًا في تجميع هذا ، بإنتاج مختلف. (clang and GCC at -O0 كلاهما ناتج 7 10 ؛ clang at -O3 الناتج 7 7 ؛ GCC at -O3 الناتج 10 7 .) آه ، آمل حقًا أنني لم أفعل أفسد شيئًا ما وأضف UB بعد كل شيء ، لكنني لا أرى كيف ...

* الأمر أكثر تعقيدًا قليلاً من ذلك ، ولكن في هذه الحالة ، نظرًا لأن copy لا يستخدم أي مؤشر حسابي ويكتب إلى كلا المؤشرين ، فإن عدم المساواة a != b ضرورية وكافية لاستدعاء عدم كن UB.

هيه ، يبدو أنني تسابقت مع nikic للعثور على نفس التفسير. حالة الاختبار الخاصة بهم أجمل قليلاً :)

هذا وقت رائع حقًا ^^ لقد توصلنا إلى نفس النتيجة تقريبًا مع نفس حالة الاختبار المصغرة في نفس الوقت :)

لإصلاح ذلك ، ربما يلزم إجراء شيء ما على غرار https://github.com/llvm-mirror/llvm/blob/54d4881c352796b18bfe7314662a294754e3a752/lib/Transforms/Utils/InlineFunction.cpp#L801 في LoopUnrollPass.

لقد أرسلت تقرير خطأ LLVM لهذه المشكلة على https://bugs.llvm.org/show_bug.cgi؟id=39282.

و- فقط أذكر هذا للتأكد من اكتماله - قدمت تقريرًا بالخطأ إلى دول مجلس التعاون الخليجي نظرًا لأنه أخطأ أيضًا في تكوين حالة اختبار C الخاصة بي: https://gcc.gnu.org/bugzilla/show_bug.cgi؟id=87609

الفرز: إذا قرأت هذا بشكل صحيح ، فسيتم قبول إصلاح LLVM (https://reviews.llvm.org/D9375). لست متأكدًا مما يعنيه ذلك للاندماج فعليًا في LLVM ، أو متى حدث ذلك ؛ يجب على شخص أكثر دراية بعملية مراجعة LLVM التحقق مما إذا كانت المشكلة قد تم إصلاحها الآن (ولأي إصدارات).

لم يتم دمجها ، وكانت عملية المراجعة غريبة بعض الشيء والشخص الذي وافق عليها لم يعد يراجع التصحيحات بعد الآن.

كانت هناك دعوة للاختبار مع مجموعة التصحيح "التقييد الكامل". قد يكون من المفيد إذا حاول شخص ما إعادة تمكين noalias في Rust فوق مستوى تم تطبيق مجموعة التصحيح هذه.

أنا على استعداد لمحاولة القيام بذلك.
لدي وصول إلى خوادم قوية بشكل معتدل (48 مركزًا لـ HT ، و 128 جيجا من ذاكرة الوصول العشوائي) وأعتقد أنه يمكنني إدارة كل شيء بشكل صحيح باستخدام التصحيح.
بمجرد أن أحصل على سلسلة أدوات عاملة ، ما الصناديق التي توصي بتجربتها؟

لقد انتهيت من دمج جميع الالتزامات الخاصة بالصدأ في مدير المنبع في llvm ثم التصحيح .
هنا هو الفرع الناتج: https://github.com/PaulGrandperrin/llvm-project/tree/llvm-master-with-rustlang-patches-and-D69542
سأحاول الآن تجميع سلسلة الأدوات وتجربتها

تأكد أولاً من العودة إلى: https://github.com/rust-lang/rust/pull/54639 بحيث يقوم Rust بالفعل بإصدار noalias.

أول شيء جيد يجب تجربته هو شيء مثل:

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

وتأكيد أنه يتم تجميعه إلى شيء مثل:

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

و لا

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

بعد ذلك ، تأكد من أن الكود من https://github.com/rust-lang/rust/issues/54462#issue -362850708 لم يعد يخطئ.

jrmuizel ملاحظة أن # 54639 لا تشملnagisa الصورة الحد الأدنى من الناسخ ل# 54462 كاختبار مترجم جديد. ربما العودة الكاملة ليست بالترتيب؟

لا أعتقد أنه من المهم إدراجه أم لا لأن AFAIK يتعلق فقط بتغيير بعض العلامات الافتراضية (والتي يمكن تجاوزها بـ -Zmutable-noalias=yes ) ويمكنني يدويًا تجميع ملف الاختبار المذكور.

فقط لكي تعلم ، ما زلت أحاول إنشاء LLVM ولكن حتى الآن أحصل على خطأ تجميع مع أو بدون تصحيحات الصدأ المطبقة (على سبيل المثال: فقط upstream's llvm master + فشل التصحيح أيضًا):

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

ربما خرج LLVM الرئيسي بالفعل عن المزامنة مع التصحيح (وهو ما يمكن أن يحدث بالنظر إلى حجم التصحيح ومدى سرعة تحرك LLVM الرئيسي) وتحتاج إلى البناء ضد نسخة أقدم من LLVM الرئيسي؟ سيكون من المفيد بالتأكيد إجراء اختبار اتصال مع مؤلف التصحيح حول هذا الأمر.

هذا بالضبط ما أفعله ، محاولًا العثور على نسخة سابقة يتم إنشاؤها باستخدام التصحيح :-)

أنا الآن متأكد من أن المشكلة ليست مع llvm / master ولكنها من التصحيح.
أقدم التزام من llvm / master لا يزال متوافقًا مع التصحيح هو https://github.com/llvm/llvm-project/commit/5b99c189b3bfc0faa157f7ca39652c0bb8c315a7 ولكن حتى ذلك الحين فشل التصحيح في التجميع.
أنا متعب للغاية وكسول لمحاولة فهم C ++ الآن ، سأحاول مرة أخرى غدًا.
في غضون ذلك ، هل يمكن لشخص ما الاتصال بمؤلف التصحيح لطلب المساعدة؟

لا أعتقد أنك ستكون قادرًا على استخدام LLVM الرئيسي بسهولة مع Rust (بعد أن تقوم ببنائه بالفعل) دون تصحيح rustllvm . AFAIK يدعم الإصدارات 6-9 فقط في الوقت الحالي.

@ mati865 حاولت أولاً تطبيق التصحيح على شوكة llvm-9 الخاصة بالصدأ لكنها لم تكن تافهة جدًا ...

يبدو أن التصحيح أعيد تأسيسه أعلى llvm / llvm-project @ 82d3ba87d06f9e2abc6e27d8799587d433c56630. هل يبني لك إذا تقدمت فوق ذلك؟

jrmuizel شكرا سأحاول ذلك!
في غضون ذلك ، تمكنت بنجاح من تكييف rustllvm للبناء مع llvm master.

PingPaulGrandperrin ، أي تحديثات؟

https://reviews.llvm.org/D68484

من الناحية الواقعية ، ما هو الجدول الزمني المقدر والفرص الإجمالية لهذا التصحيح من أي وقت مضى ، مع الأخذ في الاعتبار حجمه؟

MSxDOS تريد أن تسأل مطوري LLVM. بشكل عام ، أتوقع أن يكون حجم التصحيح أقل أهمية من رغبة المالكين في رؤيته مدمجة ، لذا فإن السؤال الذي يجب طرحه هو كم تريد LLVM رؤيتها تهبط.

إليك أحدث حالة رأيتها: https://reviews.llvm.org/D69542#1836439

أفترض في وقت ما أنه سيتوقف عن أن يكون ذا صلة إذا نجح https://github.com/bytecodealliance/cranelift~~ https://github.com/bjorn3/rustc_codegen_cranelift ؟

leeoniya ، لا توجد خطة قصيرة المدى لاستخدام

لقد فوجئت بمعرفة مدى تحفظ المترجم فيما يتعلق بافتراض إمكانية وجود تسمية مستعارة بدون هذا الخيار. فمثلا:

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

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

نظرًا لأنه يصل إلى أعضاء الهيكل من خلال &mut ، فإنه يفترض أن الاسم المستعار s.x و s.y يمكن أن يكون اسمًا مستعارًا ، لذلك يتطلب وصولين إلى الذاكرة بدلاً من واحد مقابل s.y . هذا أمر مؤسف حقًا ، عندما تفكر في عدد المرات التي يقرأ فيها الأعضاء / يكتبوا عبر &mut يجب أن يكون متشابكًا في برنامج نموذجي.

تحرير: بناءً على بعض الاختبارات ، لا يبدو أن هذا يؤثر على كل هذه القراءة / الكتابة ، وهذا ليس مفاجئًا ، لأنه من المحتمل أن يقتل الأداء إذا حدث. ومع ذلك ، فإن استخدام -Z mutable-noalias يصلح الوصول إلى الذاكرة المزدوجة في المثال أعلاه ، لذلك قد يتم ضبط بعض الحالات.

PaulGrandperrin هناك نسخة جديدة من هذا التصحيح على https://reviews.llvm.org/D69542 استنادًا إلى llvm @ 9fb46a452d4e5666828c95610ceac8dcd9e4ce16. هل أنت على استعداد لمحاولة تشغيله مرة أخرى؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات