diff --git a/Tests/acc_integral_constant_expression.F90 b/Tests/acc_integral_constant_expression.F90 new file mode 100644 index 0000000..d9fd0b5 --- /dev/null +++ b/Tests/acc_integral_constant_expression.F90 @@ -0,0 +1,290 @@ +! acc_integral_constant_expression.F90 +! +! Feature under test (OpenACC 3.4, Section 1.6, Feb 2026): +! - Clause arguments that require an integral-constant-expression accept +! Fortran integer constant expressions declared with PARAMETER. +! +! Notes: +! - T1: collapse() uses a PARAMETER ICE. +! - T2: tile() uses a PARAMETER ICE. +! - T3: tile() uses PARAMETER ICE values in tile( , ). +! - T4: cache() slice bounds use PARAMETER ICE values. +! - T5: cache() slice bounds use PARAMETER ICE values. +! - T6: gang(dim:) uses a PARAMETER ICE (must be 1..3). +! Some compilers may not support gang(dim:) yet; keep for spec coverage. +! + +#ifndef T1 +!T1:syntax,collapse-clause,runtime,loop,V:3.4- + LOGICAL FUNCTION test1() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: COLL_T2 = 1 + 1 + INTEGER, PARAMETER :: M_T2 = 48, N_T2 = 12 + INTEGER :: i, j, idx, errors + REAL(8), DIMENSION(M_T2*N_T2) :: a, b, c + errors = 0 + DO idx = 1, M_T2*N_T2 + a(idx) = DBLE(idx+2) + b(idx) = DBLE(idx-1) + c(idx) = 0.0D0 + END DO + !$acc data copyin(a(1:M_T2*N_T2), b(1:M_T2*N_T2)) copy(c(1:M_T2*N_T2)) + !$acc parallel loop collapse(COLL_T2) + DO i = 1, M_T2 + DO j = 1, N_T2 + idx = (i-1)*N_T2 + j + c(idx) = a(idx) + b(idx) + END DO + END DO + !$acc end parallel loop + !$acc end data + DO idx = 1, M_T2*N_T2 + IF (ABS(c(idx)-(a(idx)+b(idx))) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test1 = (errors .NE. 0) + END FUNCTION +#endif +#ifndef T2 +!T2:syntax,tile-clause,runtime,loop,V:3.4- + LOGICAL FUNCTION test2() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: TILE_T2 = 1 + 1 + INTEGER, PARAMETER :: M_T3 = 256 + INTEGER :: i, errors + REAL(8), DIMENSION(M_T3) :: a, c + errors = 0 + DO i = 1, M_T3 + a(i) = DBLE(i) + c(i) = 0.0D0 + END DO + !$acc data copyin(a(1:M_T3)) copy(c(1:M_T3)) + !$acc parallel loop tile(TILE_T2) + DO i = 1, M_T3 + c(i) = 2.0D0 * a(i) + END DO + !$acc end parallel loop + !$acc end data + DO i = 1, M_T3 + IF (ABS(c(i) - 2.0D0*a(i)) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test2 = (errors .NE. 0) + END FUNCTION +#endif +#ifndef T3 +!T3:syntax,tile-clause,runtime,loop,V:3.4- + LOGICAL FUNCTION test3() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: TILE2_T4 = 1 + 1 + INTEGER, PARAMETER :: M_T4 = 64, N_T4 = 40 + INTEGER :: i, j, idx, errors + REAL(8), DIMENSION(M_T4*N_T4) :: a, b, c + errors = 0 + DO idx = 1, M_T4*N_T4 + a(idx) = DBLE(idx+1) + b(idx) = DBLE(3*idx) + c(idx) = 0.0D0 + END DO + !$acc data copyin(a(1:M_T4*N_T4), b(1:M_T4*N_T4)) copy(c(1:M_T4*N_T4)) + !$acc parallel loop tile(TILE2_T4, TILE2_T4) + DO i = 1, M_T4 + DO j = 1, N_T4 + idx = (i-1)*N_T4 + j + c(idx) = a(idx) + b(idx) + END DO + END DO + !$acc end parallel loop + !$acc end data + DO idx = 1, M_T4*N_T4 + IF (ABS(c(idx)-(a(idx)+b(idx))) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test3 = (errors .NE. 0) + END FUNCTION +#endif +#ifndef T4 +!T4:syntax,cache-directive,runtime,compute,V:3.4- + LOGICAL FUNCTION test4() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: M_T5 = 1024 + INTEGER, PARAMETER :: L_T5 = 16 + INTEGER, PARAMETER :: LO_T5 = 32 + INTEGER :: i, errors + REAL(8), DIMENSION(M_T5) :: p, cp + errors = 0 + DO i = 1, M_T5 + p(i) = DBLE(i) + cp(i) = 0.0D0 + END DO + !$acc data copyin(p(1:M_T5)) copy(cp(1:M_T5)) + + !$acc parallel loop + DO i = 1, M_T5 + !$acc cache(p(LO_T5:LO_T5+L_T5-1)) + cp(i) = p(i) + 1.0D0 + END DO + !$acc end parallel loop + + + !$acc end data + DO i = 1, M_T5 + IF (ABS(cp(i) - (p(i)+1.0D0)) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test4 = (errors .NE. 0) + END FUNCTION +#endif +#ifndef T5 +!T5:syntax,cache-directive,runtime,compute,V:3.4- + LOGICAL FUNCTION test5() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: M_T6 = 1024 + INTEGER, PARAMETER :: LO_T6 = 40 + INTEGER, PARAMETER :: LEN_T6 = 8 + INTEGER, PARAMETER :: HI_T6 = LO_T6 + LEN_T6 - 1 + INTEGER :: i, errors + REAL(8), DIMENSION(M_T6) :: q, cq + errors = 0 + DO i = 1, M_T6 + q(i) = DBLE(i) + cq(i) = 0.0D0 + END DO + !$acc data copyin(q(1:M_T6)) copy(cq(1:M_T6)) + + !$acc parallel loop + DO i = 1, M_T6 + !$acc cache(q(LO_T6:HI_T6)) + cq(i) = q(i) * 2.0D0 + END DO + !$acc end parallel loop + + !$acc end data + DO i = 1, M_T6 + IF (ABS(cq(i) - 2.0D0*q(i)) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test5 = (errors .NE. 0) + END FUNCTION +#endif +#ifndef T6 +!T6:syntax,gang-clause,runtime,loop,V:3.4- +! gang(dim:DIM_T7) where dim is an integral constant expression (PARAMETER), must evaluate to 1..3 +! NOTE: Some compilers may not support the 'dim:' keyword form yet; keep this as spec conformance coverage. + LOGICAL FUNCTION test6() + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER, PARAMETER :: M_T7 = 512 + INTEGER, PARAMETER :: DIM_T7 = 2 + INTEGER :: i, errors + REAL(8), DIMENSION(M_T7) :: a, c + errors = 0 + DO i = 1, M_T7 + a(i) = DBLE(i) + c(i) = 0.0D0 + END DO + !$acc data copyin(a(1:M_T7)) copy(c(1:M_T7)) + !$acc parallel loop gang(dim:DIM_T7) + DO i = 1, M_T7 + c(i) = 2.0D0 * a(i) + END DO + !$acc end parallel loop + !$acc end data + DO i = 1, M_T7 + IF (ABS(c(i) - 2.0D0*a(i)) .GT. PRECISION) THEN + errors = errors + 1 + END IF + END DO + test6 = (errors .NE. 0) + END FUNCTION +#endif + PROGRAM main + IMPLICIT NONE + INCLUDE "acc_testsuite.Fh" + INTEGER :: failcode, testrun + LOGICAL :: failed +#ifndef T1 + LOGICAL :: test1 +#endif +#ifndef T2 + LOGICAL :: test2 +#endif +#ifndef T3 + LOGICAL :: test3 +#endif +#ifndef T4 + LOGICAL :: test4 +#endif +#ifndef T5 + LOGICAL :: test5 +#endif +#ifndef T6 + LOGICAL :: test6 +#endif + failcode = 0 +#ifndef T1 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test1() + END DO + IF (failed) THEN + failcode = failcode + 2**0 + END IF +#endif +#ifndef T2 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test2() + END DO + IF (failed) THEN + failcode = failcode + 2**1 + END IF +#endif +#ifndef T3 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test3() + END DO + IF (failed) THEN + failcode = failcode + 2**2 + END IF +#endif +#ifndef T4 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test4() + END DO + IF (failed) THEN + failcode = failcode + 2**3 + END IF +#endif +#ifndef T5 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test5() + END DO + IF (failed) THEN + failcode = failcode + 2**4 + END IF +#endif +#ifndef T6 + failed = .FALSE. + DO testrun = 1, NUM_TEST_CALLS + failed = failed .OR. test6() + END DO + IF (failed) THEN + failcode = failcode + 2**5 + END IF +#endif + CALL EXIT(failcode) + END PROGRAM diff --git a/Tests/acc_integral_constant_expression.c b/Tests/acc_integral_constant_expression.c new file mode 100644 index 0000000..3cf4d19 --- /dev/null +++ b/Tests/acc_integral_constant_expression.c @@ -0,0 +1,310 @@ +// acc_integral_constant_expression.c +// +//Feature under test (OpenACC 3.4, Section 1.6, Feb 2026): +// - Clause arguments that require an integral-constant-expression accept +// C integral constant expressions (macros and enum values). +// +// Notes: +// - T1: collapse() uses a macro ICE. +// - T2: tile() uses a macro ICE. +// - T3: tile() mixes enum + macro ICE. +// - T4: cache() element index uses an enum ICE. +// - T5: cache() lower:length slice uses ICE values. +// - T6: gang(dim:) uses an enum ICE (must be 1..3). +// Some compilers may not support gang(dim:) yet; keep for spec coverage. + +#include "acc_testsuite.h" +#include +#include +#include +#include +// C integer constant expressions: enums + macros +enum { ICE_ENUM2 = 2, ICE_ENUM4 = 4, ICE_ENUM_LOWER = 3 }; +#define ICE_MACRO2 (1 + 1) +#define ICE_TILE1 (2) +#define ICE_TILE2 (ICE_MACRO2) // still ICE +#define ICE_LEN4 (4) + +#ifndef T1 +int test1(void){ + int err = 0; + const int M = 48, N = 12; + const int MN = M*N; + real_t *a=(real_t*)malloc((size_t)MN*sizeof(real_t)); + real_t *b=(real_t*)malloc((size_t)MN*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)MN*sizeof(real_t)); + if(!a||!b||!c){ + free(a); + free(b); + free(c); + return 1; + } + for(int i=0;i PRECISION){ + err++; + } + } + + free(a); + free(b); + free(c); + return err; +} +#endif +#ifndef T2 +int test2(void){ + int err = 0; + const int M = 256; + real_t *a=(real_t*)malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + free(a); + free(c); + return 1; + } + for(int i=0;i PRECISION){ + err++; + } + } + free(a); + free(c); + return err; +} +#endif +#ifndef T3 +int test3(void){ + int err = 0; + const int M = 64, N = 40; + const int MN = M*N; + real_t *a=(real_t*)malloc((size_t)MN*sizeof(real_t)); + real_t *b=(real_t*)malloc((size_t)MN*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)MN*sizeof(real_t)); + if(!a||!b||!c){ + free(a); + free(b); + free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + free(a); + free(b); + free(c); + return err; +} +#endif +#ifndef T4 +int test4(void){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + free(a); + free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + free(a); + free(c); + return err; +} +#endif +#ifndef T5 +int test5(void){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + free(a); + free(c); + return 1; + } + for(int i=0;i PRECISION){ + err++; + } + } + + free(a); + free(c); + return err; +} +#endif +#ifndef T6 +int test6(void){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + free(a); + free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + free(a); + free(c); + return err; +} +#endif +int main(void){ + int failcode=0, failed; +#ifndef T1 + failed=0; + for(int i=0;i +#include +#include +#include +// C++ integral constant expressions: constexpr + enum +static constexpr int ICE_CONST2 = 2; +static constexpr int ICE_CONST4 = 4; +enum class E2 : int { V = 2 }; +static constexpr int ICE_LOWER = 3; + +#ifndef T1 +int test1(){ + int err = 0; + const int M = 48, N = 12, MN = M*N; + real_t *a=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + real_t *b=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + if(!a||!b||!c){ + std::free(a); + std::free(b); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + std::free(a); + std::free(b); + std::free(c); + return err; +} +#endif +#ifndef T2 +int test2(){ + int err = 0; + const int M = 256; + real_t *a=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + std::free(a); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + std::free(a); + std::free(c); + return err; +} +#endif +#ifndef T3 +int test3(){ + int err = 0; + const int M = 64, N = 40, MN = M*N; + real_t *a=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + real_t *b=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)MN*sizeof(real_t)); + if(!a||!b||!c){ + std::free(a); + std::free(b); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + std::free(a); + std::free(b); + std::free(c); + return err; +} +#endif +#ifndef T4 +int test4(){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + std::free(a); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + std::free(a); + std::free(c); + return err; +} +#endif +#ifndef T5 +int test5(){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + std::free(a); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + std::free(a); + std::free(c); + return err; +} +#endif +#ifndef T6 +int test6(){ + int err = 0; + const int M = 512; + real_t *a=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + real_t *c=(real_t*)std::malloc((size_t)M*sizeof(real_t)); + if(!a||!c){ + std::free(a); + std::free(c); + return 1; + } + + for(int i=0;i PRECISION){ + err++; + } + } + + std::free(a); + std::free(c); + return err; +} +#endif +int main(){ + int failcode=0, failed; +#ifndef T1 + failed=0; + for(int i=0;i