您能否給我一個循環如何實現向量化的例子?例如,我有以下循環:循環如何被矢量化?可以通過循環實現什麼向量操作
for (i=1; i < N; i++) {
a[i] = b[i]*c[i];
d[i] = a[i-1] + 7;
}
我知道不應該有矢量化循環之前的任何依賴,但是你展示之後,有沒有什麼相關性。它究竟如何被矢量化,哪些步驟?
您能否給我一個循環如何實現向量化的例子?例如,我有以下循環:循環如何被矢量化?可以通過循環實現什麼向量操作
for (i=1; i < N; i++) {
a[i] = b[i]*c[i];
d[i] = a[i-1] + 7;
}
我知道不應該有矢量化循環之前的任何依賴,但是你展示之後,有沒有什麼相關性。它究竟如何被矢量化,哪些步驟?
從你的問題來看,我不太清楚你是否在問如何手動向量化矢量化,或者如果你問矢量化編譯器如何做到這一點。因此,我將僅解釋編譯器如何執行,並且如果需要,您可以始終手動重複相同的步驟。讓我們用作爲一個例子向量化到寬度4
原始代碼:
for (i=1; i < N; i++) {
a[i] = b[i]*c[i];
d[i] = a[i-1] + 7;
}
首先,編譯器需要確定的是,雖然第n次迭代取決於迭代n-1,這是一個虛假的依賴,因爲有沒有數據流依賴性 - a[n]
不取決於a[n-1]
。一旦這被確定,編譯器可以執行loop fission :
for (i=1; i < N; i++) {
a[i] = b[i]*c[i];
}
for (i=1; i < N; i++) {
d[i] = a[i-1] + 7;
}
這兩種現在可以向量化;讓我們把重點放在第一個,但對另一個來說也是一樣的。因此,我們的代碼是:
for (i=1; i < N; i++) {
a[i] = b[i]*c[i];
}
對於我們的例子,讓我們假設量化寬度爲4。矢量化的關鍵是loop unrolling。因此,編譯器解開大小4:
int i = 1;
// Unrolled loop:
for (; i < N-3; i+=4) {
a[i] = b[i] *c[i];
a[i+1] = b[i+1]*c[i+1];
a[i+2] = b[i+2]*c[i+2];
a[i+3] = b[i+3]*c[i+3];
}
// Remainder loop:
for (; i < N; i++) {
a[i] = b[i]*c[i];
}
它現在明顯的是如何向量化 - 編譯器改變在展開循環指令相同的序列到一個單一的向量指令:
int i = 1;
// Unrolled loop:
for (; i < N-3; i+=4) {
a[i:i+3] = b[i:i+3]*c[i:i+3];
}
// Remainder loop:
for (; i < N; i++) {
a[i] = b[i]*c[i];
}
之後,在編譯器的後期「降低」階段,它將爲該操作分配一個實際指令 - 例如,如果這些是啓用SSE的體系結構上的單精度浮點數組,則它可能會使用mulps
。
1以簡化的方式,當然。
2記住這種情況下的環路分裂實際上會傷害數據的局部性。
3編譯器實際上並不需要展開,只需要查找重複項 - 這些步驟通常會一起使用。
這是什麼語言?這可能很明顯,但你仍然在你的問題中指定它。 – Jubobs 2014-09-28 17:48:32
這是錯誤的。假設i = 0,那麼你設置了一個[11] = b [0] * c [0],但是下一個語句你想把d [0]設置爲[4 * N] + 7,顯然, 4 * N]可能還沒有被初始化/分配。所以這個數據依賴性必須先解決。 – 2014-09-28 17:55:45
@Jubobs和DebasishJana,即使沒有指定語言並給出示例不是最好的,但我仍想嘗試理解進一步的矢量化步驟。或者你可以舉一個你自己的例子,並說明如何在假設沒有依賴的情況下完成它。 謝謝 – Mikon 2014-09-28 18:03:16