blob: 11c45c7726ce1492d3b0c2928fd30f1945e1e7f7 [file] [edit]
// RUN: %libomptarget-compile-generic
// RUN: env LIBOMPTARGET_INFO=16 \
// RUN: %libomptarget-run-generic 2>&1 | %fcheck-generic
// RUN: %libomptarget-compileopt-generic
// RUN: env LIBOMPTARGET_INFO=16 \
// RUN: %libomptarget-run-generic 2>&1 | %fcheck-generic
// REQUIRES: amdgpu
// Regression test for a cross-team reduction bug where the final xteam
// reduction used a full-wave reduction path even though the kernel was launched
// with fewer threads than the device wave size. On wave64 AMDGPU targets,
// thread_limit(32) creates a partial wave. The 63-team case uses the
// single-thread final reduction path; the 64-team case crosses the wave-size
// boundary and must still ignore inactive lanes.
#include <limits.h>
#include <stdio.h>
#define THREAD_LIMIT 32
#define TEAMS_BELOW_WAVE_SIZE_BOUNDARY 63
#define TEAMS_AT_WAVE_SIZE_BOUNDARY 64
#define NUM_ITERS (THREAD_LIMIT * TEAMS_BELOW_WAVE_SIZE_BOUNDARY + 1)
#define EXPECTED_MIN UINT_MAX
static unsigned reduce_min(int teams) {
unsigned min_val = UINT_MAX;
#pragma omp target teams distribute parallel for num_teams(teams) \
thread_limit(THREAD_LIMIT) reduction(min : min_val)
for (int i = 0; i < NUM_ITERS; ++i) {
unsigned val = EXPECTED_MIN;
if (val < min_val)
min_val = val;
}
return min_val;
}
int main(void) {
unsigned min63 = reduce_min(TEAMS_BELOW_WAVE_SIZE_BOUNDARY);
unsigned min64 = reduce_min(TEAMS_AT_WAVE_SIZE_BOUNDARY);
// CHECK: Launching kernel {{.*}} with [63,1,1] blocks and [32,1,1] threads
// CHECK-SAME: in SPMD mode
// CHECK: Launching kernel {{.*}} with [64,1,1] blocks and [32,1,1] threads
// CHECK-SAME: in SPMD mode
// CHECK: min63 = 0xffffffff
// CHECK: min64 = 0xffffffff
printf("min63 = %#x\n", min63);
printf("min64 = %#x\n", min64);
return min63 == EXPECTED_MIN && min64 == EXPECTED_MIN ? 0 : 1;
}