Странное поведение при копировании массива 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 также показывает свою ошибку.

Другие вопросы по тегам