(root)/
gcc-13.2.0/
libgomp/
testsuite/
libgomp.oacc-c-c++-common/
subset-subarray-mappings-1-r-p.c
       1  /* Test "subset" subarray mappings
       2     { dg-additional-options "-DOPENACC_RUNTIME" } using OpenACC Runtime Library routines,
       3     { dg-additional-options "-DPOINTERS" } using pointers.  */
       4  
       5  /* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
       6  
       7  #if OPENACC_RUNTIME
       8  #elif OPENACC_DIRECTIVES
       9  #else
      10  # error
      11  #endif
      12  
      13  #if POINTERS
      14  #elif ARRAYS
      15  #else
      16  # error
      17  #endif
      18  
      19  
      20  #include <openacc.h>
      21  #include <acc_prof.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <assert.h>
      25  #include <stdint.h>
      26  #include <stdbool.h>
      27  
      28  
      29  static bool cb_ev_alloc_expected;
      30  static size_t cb_ev_alloc_bytes;
      31  static const void *cb_ev_alloc_device_ptr;
      32  static void
      33  cb_ev_alloc (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
      34  {
      35    assert (cb_ev_alloc_expected);
      36    cb_ev_alloc_expected = false;
      37  
      38    cb_ev_alloc_bytes = event_info->data_event.bytes;
      39    cb_ev_alloc_device_ptr = event_info->data_event.device_ptr;
      40  }
      41  
      42  static bool cb_ev_free_expected;
      43  static const void *cb_ev_free_device_ptr;
      44  static void
      45  cb_ev_free (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
      46  {
      47    assert (cb_ev_free_expected);
      48    cb_ev_free_expected = false;
      49  
      50    cb_ev_free_device_ptr = event_info->data_event.device_ptr;
      51  }
      52  
      53  
      54  /* Match the alignment processing that
      55     'libgomp/target.c:gomp_map_vars_internal' is doing; simplified, not
      56     considering special alignment requirements of certain data types.  */
      57  
      58  static size_t
      59  aligned_size (size_t tgt_size)
      60  {
      61    size_t tgt_align = sizeof (void *);
      62    return tgt_size + tgt_align - 1;
      63  }
      64  
      65  static const void *
      66  aligned_address (const void *tgt_start)
      67  {
      68    size_t tgt_align = sizeof (void *);
      69    return (void *) (((uintptr_t) tgt_start + tgt_align - 1) & ~(tgt_align - 1));
      70  }
      71  
      72  
      73  #define SIZE 1024
      74  #define SUBSET 32
      75  
      76  
      77  static void
      78  f1 (void)
      79  {
      80    cb_ev_alloc_expected = false;
      81    cb_ev_free_expected = false;
      82    acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
      83    acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
      84  
      85  #if POINTERS
      86    char* myblock = (char *) malloc (SIZE);
      87  #else
      88    char myblock[SIZE];
      89  #endif
      90    int i;
      91    void *dst;
      92    for (i = 0; i < SIZE; i++)
      93      myblock[i] = i;
      94  
      95    cb_ev_alloc_expected = true;
      96  #if OPENACC_RUNTIME
      97    dst = acc_copyin (myblock, SIZE);
      98  #else
      99  # if POINTERS
     100  #  pragma acc enter data copyin (myblock[0:SIZE])
     101  # else
     102  #  pragma acc enter data copyin (myblock)
     103  # endif
     104    dst = acc_deviceptr (myblock);
     105  #endif
     106    assert (dst);
     107    assert (!cb_ev_alloc_expected);
     108    assert (cb_ev_alloc_bytes == aligned_size (SIZE));
     109    assert (aligned_address (cb_ev_alloc_device_ptr) == dst);
     110    for (i = 0; i < SIZE; i += SUBSET)
     111      {
     112        void *partdst = acc_deviceptr (&myblock[i]);
     113        assert ((uintptr_t) partdst == (uintptr_t) dst + i);
     114        assert (acc_hostptr (partdst) == &myblock[i]);
     115      }
     116    for (i = 0; i < SIZE; i += SUBSET)
     117      {
     118        void *partdst;
     119  #if OPENACC_RUNTIME
     120        partdst = acc_pcopyin (&myblock[i], SUBSET);
     121  #else
     122  # pragma acc enter data pcopyin (myblock[i:SUBSET])
     123        partdst = acc_deviceptr (&myblock[i]);
     124  #endif
     125        assert ((uintptr_t) partdst == (uintptr_t) dst + i);
     126      }
     127    /* Dereference first half.  */
     128    for (i = 0; i < 512; i += SUBSET)
     129      {
     130        assert (acc_is_present (&myblock[i], SUBSET));
     131        assert (acc_is_present (myblock, SIZE));
     132  #if OPENACC_RUNTIME
     133        acc_delete (&myblock[i], SUBSET);
     134  #else
     135  # pragma acc exit data delete (myblock[i:SUBSET])
     136  #endif
     137        assert (acc_is_present (&myblock[i], SUBSET));
     138        assert (acc_is_present (myblock, SIZE));
     139      }
     140    /* Dereference all.  */
     141  #if OPENACC_RUNTIME
     142    acc_delete (myblock, SIZE);
     143  #else
     144  # if POINTERS
     145  #  pragma acc exit data delete (myblock[0:SIZE])
     146  # else
     147  #  pragma acc exit data delete (myblock)
     148  # endif
     149  #endif
     150    /* Expect it's still present.  */
     151    assert (acc_is_present (myblock, SIZE));
     152    /* Dereference second half.  */
     153    for (i = 512; i < SIZE; i += SUBSET)
     154      {
     155        bool last = i >= SIZE - SUBSET;
     156  
     157        assert (acc_is_present (&myblock[i], SUBSET));
     158        assert (acc_is_present (myblock, SIZE));
     159        if (last)
     160  	cb_ev_free_expected = true;
     161  #if OPENACC_RUNTIME
     162        acc_delete (&myblock[i], SUBSET);
     163  #else
     164  # pragma acc exit data delete (myblock[i:SUBSET])
     165  #endif
     166        assert (!cb_ev_free_expected);
     167        if (last)
     168  	assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
     169        assert (acc_is_present (&myblock[i], SUBSET) != last);
     170        assert (acc_is_present (myblock, SIZE) != last);
     171      }
     172    /* Expect it's all gone now.  */
     173    for (i = 512; i < SIZE; i += SUBSET)
     174      assert (!acc_is_present (&myblock[i], SUBSET));
     175    assert (!acc_is_present (myblock, SIZE));
     176    assert (!acc_is_present (myblock, 1));
     177  
     178  #if POINTERS
     179    free (myblock);
     180  #endif
     181  
     182    acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
     183    acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
     184  }
     185  
     186  
     187  static void
     188  f2 (void)
     189  {
     190    cb_ev_alloc_expected = false;
     191    cb_ev_free_expected = false;
     192    acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
     193    acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
     194  
     195  #if POINTERS
     196    char *block1 = (char *) malloc (SIZE);
     197    char *block2 = (char *) malloc (SIZE);
     198    char *block3 = (char *) malloc (SIZE);
     199  #else
     200    char block1[SIZE];
     201    char block2[SIZE];
     202    char block3[SIZE];
     203  #endif
     204    int i;
     205    for (i = 0; i < SIZE; i++)
     206      block1[i] = block2[i] = block3[i] = i;
     207  
     208    cb_ev_alloc_expected = true;
     209  #if POINTERS
     210  # pragma acc data copyin(block1[0:SIZE], block2[0:SIZE], block3[0:SIZE])
     211  #else
     212  # pragma acc data copyin(block1, block2, block3)
     213  #endif
     214    {
     215      void *block1_d = acc_deviceptr (block1);
     216      void *block2_d = acc_deviceptr (block2);
     217      void *block3_d = acc_deviceptr (block3);
     218      assert (!cb_ev_alloc_expected);
     219      /* 'block1', 'block2', 'block3' get mapped in one device memory object, in
     220         reverse order.  */
     221      assert (cb_ev_alloc_bytes == aligned_size (3 * SIZE));
     222      assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 2 * SIZE) == block1_d);
     223      assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 1 * SIZE) == block2_d);
     224      assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 0 * SIZE) == block3_d);
     225  
     226      for (i = 0; i < SIZE; i += SUBSET)
     227        {
     228  	void *block2_part_d;
     229  #if OPENACC_RUNTIME
     230  	block2_part_d = acc_pcopyin (&block2[i], SUBSET);
     231  #else
     232  # pragma acc enter data pcopyin (block2[i:SUBSET])
     233  	block2_part_d = acc_deviceptr (&block2[i]);
     234  #endif
     235  	assert ((uintptr_t) block2_part_d == (uintptr_t) block2_d + i);
     236        }
     237    }
     238    /* The mappings have been removed, but the device memory object has not yet
     239       been 'free'd.  */
     240    assert (!acc_is_present (block1, SIZE));
     241    assert (acc_is_present (block2, SIZE));
     242    assert (!acc_is_present (block3, SIZE));
     243    for (i = 0; i < SIZE; i += SUBSET)
     244      {
     245        bool last = i >= SIZE - SUBSET;
     246  
     247        assert (acc_is_present (block2, SIZE));
     248        if (last)
     249  	cb_ev_free_expected = true;
     250  #if OPENACC_RUNTIME
     251        acc_delete (&block2[i], SUBSET);
     252  #else
     253  # pragma acc exit data delete (block2[i:SUBSET])
     254  #endif
     255        assert (!cb_ev_free_expected);
     256        if (last)
     257  	assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
     258      }
     259    assert (!acc_is_present (block1, SIZE));
     260    assert (!acc_is_present (block2, SIZE));
     261    assert (!acc_is_present (block3, SIZE));
     262  
     263  #if POINTERS
     264    free (block1);
     265    free (block2);
     266    free (block3);
     267  #endif
     268  
     269    acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
     270    acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
     271  }
     272  
     273  
     274  static void
     275  f3 ()
     276  {
     277    cb_ev_alloc_expected = false;
     278    cb_ev_free_expected = false;
     279    acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
     280    acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
     281  
     282  #if POINTERS
     283    char *h = (char *) malloc (SIZE);
     284  #else
     285    char h[SIZE];
     286  #endif
     287  
     288    char *d1;
     289    cb_ev_alloc_expected = true;
     290  #if OPENACC_RUNTIME
     291    d1 = (char *) acc_present_or_create (h, SIZE);
     292  #else
     293  # if POINTERS
     294  #  pragma acc enter data present_or_create (h[0:SIZE])
     295  # else
     296  #  pragma acc enter data present_or_create (h)
     297  # endif
     298    d1 = (char *) acc_deviceptr (h);
     299  #endif
     300    assert (d1);
     301    assert (!cb_ev_alloc_expected);
     302    assert (cb_ev_alloc_bytes == aligned_size (SIZE));
     303    assert (aligned_address (cb_ev_alloc_device_ptr) == d1);
     304    assert (acc_is_present (h, SIZE));
     305    assert (acc_is_present (&h[2], SIZE - 2));
     306  
     307    char *d2;
     308  #if OPENACC_RUNTIME
     309    d2 = (char *) acc_present_or_create (&h[2], SIZE - 2);
     310  #else
     311  # pragma acc enter data present_or_create (h[2:SIZE - 2])
     312    d2 = (char *) acc_deviceptr (&h[2]);
     313  #endif
     314    assert (d2);
     315    assert (d1 == d2 - 2);
     316    assert (acc_is_present (h, SIZE));
     317    assert (acc_is_present (&h[2], SIZE - 2));
     318  
     319    d2 = (char *) acc_deviceptr (&h[2]);
     320    assert (d1 == d2 - 2);
     321  
     322  #if OPENACC_RUNTIME
     323    acc_delete (&h[2], SIZE - 2);
     324  #else
     325  # pragma acc exit data delete (h[2:SIZE - 2])
     326  #endif
     327    assert (acc_is_present (h, SIZE));
     328    assert (acc_is_present (&h[2], SIZE - 2));
     329  
     330    cb_ev_free_expected = true;
     331  #if OPENACC_RUNTIME
     332    acc_delete (h, SIZE);
     333  #else
     334  # if POINTERS
     335  #  pragma acc exit data delete (h[0:SIZE])
     336  # else
     337  #  pragma acc exit data delete (h)
     338  # endif
     339  #endif
     340    assert (!cb_ev_free_expected);
     341    assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
     342  
     343    assert (!acc_is_present (h, SIZE));
     344    assert (!acc_is_present (&h[2], SIZE - 2));
     345    assert (!acc_is_present (h, 1));
     346  
     347  # if POINTERS
     348    free (h);
     349  #endif
     350  
     351    acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
     352    acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
     353  }
     354  
     355  
     356  /* Based on what used to be 'libgomp.oacc-c-c++-common/lib-22.c'.  */
     357  
     358  static void
     359  f_lib_22 (void)
     360  {
     361    cb_ev_alloc_expected = false;
     362    cb_ev_free_expected = false;
     363    acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
     364    acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
     365  
     366    const int c0 = 0;
     367    const int c1 = 1;
     368  
     369  #if POINTERS
     370    char *h = (char *) malloc (SIZE);
     371  #else
     372    char h[SIZE];
     373  #endif
     374  
     375    memset (h, c0, SIZE);
     376    void *d;
     377    cb_ev_alloc_expected = true;
     378  #if OPENACC_RUNTIME
     379    d = acc_copyin (h, SIZE);
     380  #else
     381  # if POINTERS
     382  #  pragma acc enter data copyin (h[0:SIZE])
     383  # else
     384  #  pragma acc enter data copyin (h)
     385  # endif
     386    d = acc_deviceptr (h);
     387  #endif
     388    assert (d);
     389    assert (!cb_ev_alloc_expected);
     390    assert (cb_ev_alloc_bytes == aligned_size (SIZE));
     391    assert (aligned_address (cb_ev_alloc_device_ptr) == d);
     392    /* Overwrite the local memory.  */
     393    memset (h, c1, SIZE);
     394    /* Now 'copyout' not the whole but only a "subset" subarray, missing one
     395       SUBSET at the beginning, and half a SUBSET at the end...  */
     396    cb_ev_free_expected = true;
     397  #if OPENACC_RUNTIME
     398    acc_copyout (h + SUBSET, SIZE - SUBSET - SUBSET / 2);
     399  #else
     400  # pragma acc exit data copyout (h[SUBSET:SIZE - SUBSET - SUBSET / 2])
     401  #endif
     402    /* ..., yet, expect the device memory object to be 'free'd...  */
     403    assert (!cb_ev_free_expected);
     404    assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
     405    /* ..., and the mapping to be removed...  */
     406    assert (!acc_is_present (h, SIZE));
     407    assert (!acc_is_present (&h[SUBSET], SIZE - SUBSET - SUBSET / 2));
     408    assert (!acc_is_present (h, 1));
     409    /* ..., but the 'copyout'ed device memory to correspond to just the "subset"
     410       subarray.  */
     411    for (size_t i = 0; i < SIZE; ++i)
     412      {
     413        if (i < SUBSET)
     414  	assert (h[i] == c1);
     415        else if (i < SIZE - SUBSET / 2)
     416  	assert (h[i] == c0);
     417        else if (i < SIZE)
     418  	assert (h[i] == c1);
     419      }
     420  
     421  #if POINTERS
     422    free (h);
     423  #endif
     424  
     425    acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
     426    acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
     427  }
     428  
     429  
     430  /* Based on what used to be 'libgomp.oacc-c-c++-common/lib-30.c'.  */
     431  
     432  static void
     433  f_lib_30 (void)
     434  {
     435    cb_ev_alloc_expected = false;
     436    cb_ev_free_expected = false;
     437    acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
     438    acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
     439  
     440  #if POINTERS
     441    char *h = (char *) malloc (SIZE);
     442  #else
     443    char h[SIZE];
     444  #endif
     445    memset (h, 0, SIZE);
     446  
     447    void *d;
     448    cb_ev_alloc_expected = true;
     449  #if OPENACC_RUNTIME
     450    d = acc_create (h, SIZE);
     451  #else
     452  # if POINTERS
     453  #  pragma acc enter data create (h[0:SIZE])
     454  # else
     455  #  pragma acc enter data create (h)
     456  # endif
     457    d = acc_deviceptr (h);
     458  #endif
     459    assert (d);
     460    assert (!cb_ev_alloc_expected);
     461    assert (cb_ev_alloc_bytes == aligned_size (SIZE));
     462    assert (aligned_address (cb_ev_alloc_device_ptr) == d);
     463  
     464    /* We 'delete' not the whole but only a "subset" subarray...  */
     465    cb_ev_free_expected = true;
     466  #if OPENACC_RUNTIME
     467    acc_delete (h, SIZE - SUBSET);
     468  #else
     469  # pragma acc exit data delete (h[0:SIZE - SUBSET])
     470  #endif
     471    /* ..., yet, expect the device memory object to be 'free'd...  */
     472    assert (!cb_ev_free_expected);
     473    assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
     474    /* ..., and the mapping to be removed.  */
     475    assert (!acc_is_present (h, SIZE));
     476    assert (!acc_is_present (h, SIZE - SUBSET));
     477    assert (!acc_is_present (h, 1));
     478  
     479  #if POINTERS
     480    free (h);
     481  #endif
     482  
     483    acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
     484    acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
     485  }
     486  
     487  
     488  int
     489  main ()
     490  {
     491    f1 ();
     492    f2 ();
     493    f3 ();
     494    f_lib_22 ();
     495    f_lib_30 ();
     496  
     497    return 0;
     498  }