Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
for(int i = 0; i < N; i++) *a++ = *b++ + *c++;
Первый код запутывает компилятор.
for(int i = 0; i < N; i++)
00161049 mov edx,dword ptr [esp+10h]
0016104D lea esi,[eax+10h]
00161050 add edx,8
00161053 sub eax,dword ptr [esp+10h]
00161057 lea ecx,[argc]
0016105A mov dword ptr [esp+10h],14h
{
a[i] = b[i] + c[i];
00161062 mov ebp,dword ptr [ecx-4]
00161065 add ebp,dword ptr [esi-10h]
00161068 add ecx,14h
0016106B mov dword ptr [edx-8],ebp
0016106E mov ebp,dword ptr [ecx+ebx-14h]
00161072 add ebp,dword ptr [ecx-14h]
00161075 add edx,14h
00161078 mov dword ptr [ecx+edi-14h],ebp
0016107C mov ebp,dword ptr [eax+edx-14h]
00161080 add ebp,dword ptr [ecx-10h]
00161083 add esi,14h
00161086 mov dword ptr [edx-14h],ebp
00161089 mov ebp,dword ptr [ecx-0Ch]
0016108C add ebp,dword ptr [esi-18h]
0016108F mov dword ptr [edx-10h],ebp
00161092 mov ebp,dword ptr [ecx-8]
00161095 add ebp,dword ptr [esi-14h]
00161098 sub dword ptr [esp+10h],1
0016109D mov dword ptr [edx-0Ch],ebp
001610A0 jne main+62h (161062h)
001610A2 pop edi
001610A3 pop esi
001610A4 pop ebp
}
a += N;
b += N;
c += N;for (int i = 0; i < N; i++)
00191046 mov ecx,14h
0019104B jmp main+50h (191050h)
0019104D lea ecx,[ecx]
{
*a++ = *b++ + *c++;
00191050 mov edx,dword ptr [esi]
00191052 add edx,dword ptr [eax]
00191054 add edi,14h
00191057 mov dword ptr [edi-14h],edx
0019105A mov edx,dword ptr [eax+4]
0019105D add edx,dword ptr [esi+4]
00191060 add esi,14h
00191063 mov dword ptr [edi-10h],edx
00191066 mov edx,dword ptr [eax+8]
00191069 add edx,dword ptr [esi-0Ch]
0019106C add eax,14h
0019106F mov dword ptr [edi-0Ch],edx
00191072 mov edx,dword ptr [eax-8]
00191075 add edx,dword ptr [esi-8]
00191078 mov dword ptr [edi-8],edx
0019107B mov edx,dword ptr [eax-4]
0019107E add edx,dword ptr [esi-4]
00191081 sub ecx,1
00191084 mov dword ptr [edi-4],edx
00191087 jne main+50h (191050h)
00191089 pop edi
0019108A pop esi
0019108B pop ebp
}Первый код запутывает компилятор. Даже если итерации цикла независимы, компилятор не считает их таковыми; по этой причине он не может векторизовать данный кусок кода. А вот второй — может.
10: create runtime check for data references *b_27 and *a_26
10: create runtime check for data references *c_28 and *a_26
void f(int * __restrict__ a, int * __restrict__ b, int * __restrict__ c, int N) {
for(int i = 0; i < N; i++)
*a++ = *b++ + *c++;
}g++ -O2 -ftree-vectorize -march=native -ftree-vectorizer-verbose=544 for (int i=0; i<N; i++)
0x0000000000400828 <+536>: cmp %rsi,%rdx
0x000000000040082b <+539>: jne 0x400818 <main()+520>
0x000000000040082d <+541>: lea 0x28(%r12),%rbx
45 {
46 *a++ = *b++ + *c++;
0x00000000004007c9 <+441>: movdqu 0x0(%rbp),%xmm1
0x00000000004007ce <+446>: lea 0x20(%r12),%rax
0x00000000004007d3 <+451>: mov $0x2,%edx
0x00000000004007d8 <+456>: movdqu 0x0(%r13),%xmm0
0x00000000004007de <+462>: paddd %xmm1,%xmm0
0x00000000004007e2 <+466>: movdqu %xmm0,(%r12)
0x00000000004007e8 <+472>: movdqu 0x10(%rbp),%xmm1
0x00000000004007ed <+477>: add $0x20,%rbp
0x00000000004007f1 <+481>: movdqu 0x10(%r13),%xmm0
0x00000000004007f7 <+487>: add $0x20,%r13
0x00000000004007fb <+491>: paddd %xmm1,%xmm0
0x00000000004007ff <+495>: movdqu %xmm0,0x10(%r12)
0x0000000000400818 <+520>: mov 0x0(%rbp,%rdx,1),%ecx
0x000000000040081c <+524>: add 0x0(%r13,%rdx,1),%ecx
0x0000000000400821 <+529>: mov %ecx,(%rax,%rdx,1)
0x0000000000400824 <+532>: add $0x4,%rdx
47 }
20 for (int i=0; i<N; i++)
0x00000000004006bc <+172>: mov $0x8,%eax
0x0000000000400710 <+256>: cmp %rsi,%rdx
0x0000000000400713 <+259>: jne 0x400700 <main()+240>
21 {
22 a[i] = b[i]+c[i];
0x00000000004006b1 <+161>: movdqu 0x0(%r13),%xmm1
0x00000000004006b7 <+167>: mov $0x2,%edx
0x00000000004006c1 <+177>: movdqu (%r12),%xmm0
0x00000000004006c7 <+183>: paddd %xmm1,%xmm0
0x00000000004006cb <+187>: movdqu %xmm0,0x0(%rbp)
0x00000000004006d0 <+192>: movdqu 0x10(%r13),%xmm1
0x00000000004006d6 <+198>: movdqu 0x10(%r12),%xmm0
0x00000000004006dd <+205>: paddd %xmm1,%xmm0
0x00000000004006e1 <+209>: movdqu %xmm0,0x10(%rbp)
0x0000000000400700 <+240>: mov 0x0(%r13,%rdx,1),%ecx
0x0000000000400705 <+245>: add (%r12,%rdx,1),%ecx
0x0000000000400709 <+249>: mov %ecx,(%rax,%rdx,1)
0x000000000040070c <+252>: add $0x4,%rdx
23 }
-fdump-tree-optimized выводит оптимизированную версию с внутреннего представления, -g -Wa,-ahl=test.s ссылается не на все строки, а -S -fverbose-asm ссылается не на реальные строки, а опять же на внутреннее представление.jne, и вопpос «где цикл?» отпадает сам собой./m: 0x0000000000400a7a <+426>: add $0x4,%rbx
0x0000000000400a7e <+430>: cmp $0x28,%rbx
0x0000000000400a82 <+434>: jne 0x400a50 <main()+384>
0x0000000000400a84 <+436>: lea 0x10(%r12),%rax
0x0000000000400a89 <+441>: lea 0x10(%r13),%rdx
0x0000000000400a8d <+445>: cmp %rax,%r13
0x0000000000400a90 <+448>: setae %cl
0x0000000000400a93 <+451>: cmp %rdx,%r12
0x0000000000400a96 <+454>: setae %dl
0x0000000000400a99 <+457>: or %dl,%cl
0x0000000000400a9b <+459>: je 0x400b60 <main()+656>
0x0000000000400aa1 <+465>: cmp %rax,%rbp
0x0000000000400aa4 <+468>: lea 0x10(%rbp),%rax
0x0000000000400aa8 <+472>: setae %dl
0x0000000000400aab <+475>: cmp %rax,%r12
0x0000000000400aae <+478>: setae %al
0x0000000000400ab1 <+481>: or %al,%dl
0x0000000000400ab3 <+483>: je 0x400b60 <main()+656>
0x0000000000400ab9 <+489>: movdqu 0x0(%rbp),%xmm1
0x0000000000400abe <+494>: lea 0x20(%r12),%rax
0x0000000000400ac3 <+499>: mov $0x2,%edx
0x0000000000400ac8 <+504>: movdqu 0x0(%r13),%xmm0
0x0000000000400ace <+510>: paddd %xmm1,%xmm0
0x0000000000400ad2 <+514>: movdqu %xmm0,(%r12)
0x0000000000400ad8 <+520>: movdqu 0x10(%rbp),%xmm1
0x0000000000400add <+525>: add $0x20,%rbp
0x0000000000400ae1 <+529>: movdqu 0x10(%r13),%xmm0
0x0000000000400ae7 <+535>: add $0x20,%r13
0x0000000000400aeb <+539>: paddd %xmm1,%xmm0
0x0000000000400aef <+543>: movdqu %xmm0,0x10(%r12)
0x0000000000400af6 <+550>: sub $0x1,%edx
0x0000000000400af9 <+553>: lea 0x4(,%rdx,4),%rsi
0x0000000000400b01 <+561>: xor %edx,%edx
0x0000000000400b03 <+563>: nopl 0x0(%rax,%rax,1)
0x0000000000400b08 <+568>: mov 0x0(%rbp,%rdx,1),%ecx
0x0000000000400b0c <+572>: add 0x0(%r13,%rdx,1),%ecx
0x0000000000400b11 <+577>: mov %ecx,(%rax,%rdx,1)
0x0000000000400b14 <+580>: add $0x4,%rdx
0x0000000000400962 <+146>: add $0x4,%rbx
0x0000000000400966 <+150>: cmp $0x28,%rbx
0x000000000040096a <+154>: jne 0x400938 <main()+104>
0x000000000040096c <+156>: lea 0x10(%rbp),%rax
0x0000000000400970 <+160>: lea 0x10(%r12),%rdx
0x0000000000400975 <+165>: cmp %rax,%r12
0x0000000000400978 <+168>: setae %cl
0x000000000040097b <+171>: cmp %rdx,%rbp
0x000000000040097e <+174>: setae %dl
0x0000000000400981 <+177>: or %dl,%cl
0x0000000000400983 <+179>: je 0x400b54 <main()+644>
0x0000000000400989 <+185>: cmp %rax,%r13
0x000000000040098c <+188>: lea 0x10(%r13),%rax
0x0000000000400990 <+192>: setae %dl
0x0000000000400993 <+195>: cmp %rax,%rbp
0x0000000000400996 <+198>: setae %al
0x0000000000400999 <+201>: or %al,%dl
0x000000000040099b <+203>: je 0x400b54 <main()+644>
0x00000000004009a1 <+209>: movdqu 0x0(%r13),%xmm1
0x00000000004009a7 <+215>: mov $0x2,%edx
0x00000000004009ac <+220>: mov $0x8,%eax
0x00000000004009b1 <+225>: movdqu (%r12),%xmm0
0x00000000004009b7 <+231>: paddd %xmm1,%xmm0
0x00000000004009bb <+235>: movdqu %xmm0,0x0(%rbp)
0x00000000004009c0 <+240>: movdqu 0x10(%r13),%xmm1
0x00000000004009c6 <+246>: movdqu 0x10(%r12),%xmm0
0x00000000004009cd <+253>: paddd %xmm1,%xmm0
0x00000000004009d1 <+257>: movdqu %xmm0,0x10(%rbp)
0x00000000004009d6 <+262>: shl $0x2,%rax
0x00000000004009da <+266>: sub $0x1,%edx
0x00000000004009dd <+269>: lea 0x4(,%rdx,4),%rsi
0x00000000004009e5 <+277>: add %rax,%r13
0x00000000004009e8 <+280>: add %rax,%r12
0x00000000004009eb <+283>: xor %edx,%edx
0x00000000004009ed <+285>: add %rbp,%rax
0x00000000004009f0 <+288>: mov 0x0(%r13,%rdx,1),%ecx
0x00000000004009f5 <+293>: add (%r12,%rdx,1),%ecx
0x00000000004009f9 <+297>: mov %ecx,(%rax,%rdx,1)
0x00000000004009fc <+300>: add $0x4,%rdx
При выполнении DCE компилятор исключает из программы код, который никогда не выполняется.Тут вы не правы. DCE – удаление мертвого кода; кода, который никак не влияет на исполнение кода (например, неиспользуемое сложение двух чисел, или вызов процедуры без побочных эффектов, или ваш пример со сложением в цикле). UCE – удаление недостижимого кода; кода, который может иметь побочные эффекты, но не существует пути исполнения выполняющего этот код (например, код после return или ветка if-а с константым условием).
0x00000000004008d6 <+6>: mov $0xa,%ebx
0x00000000004008db <+11>: sub $0x8,%rsp
0x00000000004008df <+15>: nop
16 {
17 int N = 10;
18 for (int i=0; i<N; i++)
0x00000000004008e5 <+21>: sub $0x1,%ebx
0x00000000004008e8 <+24>: jne 0x4008e0 <main()+16>
19 {
20 doSomething();
0x00000000004008e0 <+16>: callq 0x400b90 <doSomething()>
21 }
24 for (int i=0; i<globalN; i++)
0x00000000004008ea <+26>: mov 0x2009d0(%rip),%eax # 0x6012c0 <globalN>
0x00000000004008f0 <+32>: xor %ebx,%ebx
0x00000000004008f2 <+34>: test %eax,%eax
0x00000000004008f4 <+36>: jle 0x400910 <main()+64>
0x00000000004008f6 <+38>: nopw %cs:0x0(%rax,%rax,1)
0x0000000000400905 <+53>: add $0x1,%ebx
0x0000000000400908 <+56>: cmp %ebx,0x2009b2(%rip) # 0x6012c0 <globalN>
0x000000000040090e <+62>: jg 0x400900 <main()+48>
25 {
26 doSomething();
0x0000000000400900 <+48>: callq 0x400b90 <doSomething()>
27 }
private и к ней обращается только один метод — случай аналогичен локальной (не уверен, что любой компилятор это поймёт, но вышеупомянутый gcc понял).static, то компилятор с лёгкостью определит оптимальное количество чтений. Это важно. На практике, если уж без глобальных переменных не обойтись, всё равно почти всегда переменную удаётся сделать статической и обращаться к ней извне через специальные функции.a[i] тоже может изменить значение N. Поэтому «в общем случае» её надо перечитывать каждую итерацию цикла.a[i] может изменить значение N?#include <iostream>
int main()
{
int lsize = 2;
int array[2];
int k = -1;
std::cout<<array+k<<" "<<&lsize<<" "<<lsize<<std::endl;
array[k] = 100500;
std::cout<<array+k<<" "<<&lsize<<" "<<lsize<<std::endl;
return 0;
}
The execution of a program contains a data race if it contains two conflicting actions in
different threads, at least one of which is not atomic, and neither happens before the
other. Any such data race results in undefined behavior.
int v;
void set(int a)
{
static_assert(PLALTFORM_HAS_ATOMIC_INT_STORE);
v = a;
}
int get()
{
static_assert(PLALTFORM_HAS_ATOMIC_INT_STORE);
return v;
}
int N;
void f(int *a, int *b) {
a[0] = b[0];
}void bar(int i){
return i;
}
Как заставить компилятор C/C++ генерировать плохой код