لماذا لا يوجد تأثير لمؤشر التقييد
-
12-12-2019 - |
سؤال
لا أستطيع رؤية أي اختلاف في الكود بواسطة gcc لتقييد المؤشرات.
file1
void test (int *a, int *b, int *c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
file2
void test (int *restrict a, int *restrict b, int *restrict c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
جمع مع
gcc -S -std=c99 -masm=intel file1.c
gcc -S -std=c99 -masm=intel file2.c
file1.s و file2.s كلاهما نفس الشيء، باستثناء .file
السطر الذي يخبرنا باسم الملف:
.file "file1.c"
.text
.globl test
.type test, @function
test:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
jmp .L2
.L3:
movq -8(%rbp), %rax
movl (%rax), %edx
movq -16(%rbp), %rax
movl (%rax), %eax
addl %eax, %edx
movq -24(%rbp), %rax
movl %edx, (%rax)
addq $4, -24(%rbp)
addq $4, -8(%rbp)
addq $4, -16(%rbp)
.L2:
movq -8(%rbp), %rax
movl (%rax), %eax
testl %eax, %eax
jne .L3
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size test, .-test
.ident "GCC: (GNU) 4.6.3 20120306 (Red Hat 4.6.3-2)"
.section .note.GNU-stack,"",@progbits
تتم قراءة كل من هذه التعليمات البرمجية من الذاكرة ثم قم بتعيين موقع الذاكرة المشار إليه a
ل b
.حيث توقعت restrict
لن يقوم الإصدار بإعادة قراءة عناوين a
و b
, ، وعناوين a
و b
سيتم زيادتها في التسجيل وفي النهاية كتابتها إلى الذاكرة.
هل هناك أي خطأ أفعله؟أم أن اختيار المثال جيد؟
لقد حاولت مع مفاتيح مختلفة -O0
, -O1
, -O2
, -O3
, -Ofast
, ، و -fstrict-aliasing
مع نفس النتائج المتطابقة لكلا الملفين.
ملحوظة: دول مجلس التعاون الخليجي --الإصدار = دول مجلس التعاون الخليجي (دول مجلس التعاون الخليجي) 4.6.3 20120306 (ريد هات 4.6.3-2)
يحرر تم تغيير الرمز.
المحلول
الشيء هو أن التعبير التالي:
*c++ = *a++ + *b++;
يحتاج إلى حد كبير إلى إلغاء الإشارة إلى جميع المؤشرات في كل تكرار للحلقة على أي حال، حيث تتغير المؤشرات في كل تكرار.ليس هناك فائدة من الاستخدام restrict
.
حاول تغيير الخط داخل الحلقة إلى:
*c++ = *a++ + *b;
(قد تحتاج أيضًا إلى تمكين التحسينات مثل -O2
).
سترى ذلك في restrict
حالة تحميله *b
في السجل مرة واحدة، بينما في الحالة بدون قيود فإنه يحتاج إلى التحميل من خلال المؤشر في كل تكرار حلقة لأنه لا يعرف ما إذا كان أم لا c
الأسماء المستعارة من أي وقت مضى b
.
نصائح أخرى
أنت تقرأ فقط من خلال أحد المؤشرات، لذلك restrict
لا يهم.
يرى هذا المثال حيث يكون الأمر مهمًا لأن المؤشرات قد تستخدم نفس البيانات، وتتم كتابة البيانات وقراءتها من خلال كلا المؤشرين.