Странное поведение при копировании массива Intel Cilk Plus
Я использую нотацию Intel Cilk Plus для обучения векторному программированию. Тем не менее, я встретил странное поведение копирования массивов.
Задача, которую нужно решить - это параллельный префикс. D - это вход, а P - это выход.
// Неверный код результата. Протестировано на Intel ICC 14.0.2.
void vec_prefix(int n, int D[n], int P[n]) {
P[0:n] = D[0:n]; //initial copy
int bound=1;
int * Buf1 = _mm_malloc(n*sizeof(int), 16);
int * Buf2 = _mm_malloc(n*sizeof(int), 16);
while(bound<n){
Buf1[0:n-bound] = P[0:n-bound];
Buf2[0:n-bound] = P[bound:n-bound];
//printf("WHY??\n"); //Add this fence, the result will be correct.
P[bound:n-bound] = Buf1[0:n-bound] + Buf2[0:n-bound];
bound<<=1;
}
_mm_free(Buf1); _mm_free(Buf2);
}
Если я удалю комментарий строки "printf", результат будет правильным. В противном случае, неправильно. Но если все копии соответствуют описаниям в документе Intel, код должен быть правильным.
Кажется, что если нет такого ограничения памяти, первые две строки ' Buf1/Buf2 copy не завершены, и операция add позже использует некоторое нестабильное значение. Или, оптимизатор компилятора просто использует копирование-распространение для удаления копии и создает "P[bound:n-bound] = P[0:n-bound] + P[bound:n-bound]". Это не определено в документе Intel.
// Исправить код результата
void vec_prefix(int n, int D[n], int P[n]) {
P[0:n] = D[0:n]; //initial copy
int bound=1;
int * Buf1 = _mm_malloc(n*sizeof(int), 16);
while(bound<n){
//direct copy part
Buf1[0:bound] = P[0:bound];
//add part
Buf1[bound:n-bound] = P[bound:n-bound] + P[0:n-bound];
//copy back
P[0:n] = Buf1[0:n];
bound<<=1;
}
_mm_free(Buf1);
}
Ссылка: документ Intel
1 ответ
Ваш код выглядит правильно для меня. Никакого "забора" не требуется. Я отправил внутренний отчет об ошибке в группу компиляторов Intel с примером всех из них в качестве входных данных. Спасибо за пример.
Если компилятор работает правильно, вы можете даже сократить цикл while до:
while(bound<n){
Buf1[0:n-bound] = P[0:n-bound];
P[bound:n-bound] = Buf1[0:n-bound] + P[bound:n-bound];
bound<<=1;
}
Второе назначение секции массива в порядке, так как перекрытие для P точно. Увы, в этом примере icc также показывает свою ошибку.