ifunction-s2.m4 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. dnl Support macro file for intrinsic functions.
  2. dnl Contains the generic sections of the array functions.
  3. dnl This file is part of the GNU Fortran Runtime Library (libgfortran)
  4. dnl Distributed under the GNU GPL with exception. See COPYING for details.
  5. dnl
  6. dnl Pass the implementation for a single section as the parameter to
  7. dnl {MASK_}ARRAY_FUNCTION.
  8. dnl The variables base, delta, and len describe the input section.
  9. dnl For masked section the mask is described by mbase and mdelta.
  10. dnl These should not be modified. The result should be stored in *dest.
  11. dnl The names count, extent, sstride, dstride, base, dest, rank, dim
  12. dnl retarray, array, pdim and mstride should not be used.
  13. dnl The variable n is declared as index_type and may be used.
  14. dnl Other variable declarations may be placed at the start of the code,
  15. dnl The types of the array parameter and the return value are
  16. dnl atype_name and rtype_name respectively.
  17. dnl Execution should be allowed to continue to the end of the block.
  18. dnl You should not return or break from the inner loop of the implementation.
  19. dnl Care should also be taken to avoid using the names defined in iparm.m4
  20. define(START_ARRAY_FUNCTION,
  21. `#include <string.h>
  22. #include <assert.h>
  23. static inline int
  24. compare_fcn (const atype_name *a, const atype_name *b, gfc_charlen_type n)
  25. {
  26. if (sizeof ('atype_name`) == 1)
  27. return memcmp (a, b, n);
  28. else
  29. return memcmp_char4 (a, b, n);
  30. }
  31. extern void name`'rtype_qual`_'atype_code (rtype * const restrict,
  32. gfc_charlen_type, atype * const restrict,
  33. const index_type * const restrict, gfc_charlen_type);
  34. export_proto(name`'rtype_qual`_'atype_code);
  35. void
  36. name`'rtype_qual`_'atype_code (rtype * const restrict retarray,
  37. gfc_charlen_type xlen, atype * const restrict array,
  38. const index_type * const restrict pdim, gfc_charlen_type string_len)
  39. {
  40. index_type count[GFC_MAX_DIMENSIONS];
  41. index_type extent[GFC_MAX_DIMENSIONS];
  42. index_type sstride[GFC_MAX_DIMENSIONS];
  43. index_type dstride[GFC_MAX_DIMENSIONS];
  44. const atype_name * restrict base;
  45. rtype_name * restrict dest;
  46. index_type rank;
  47. index_type n;
  48. index_type len;
  49. index_type delta;
  50. index_type dim;
  51. int continue_loop;
  52. assert (xlen == string_len);
  53. /* Make dim zero based to avoid confusion. */
  54. rank = GFC_DESCRIPTOR_RANK (array) - 1;
  55. dim = (*pdim) - 1;
  56. if (unlikely (dim < 0 || dim > rank))
  57. {
  58. runtime_error ("Dim argument incorrect in u_name intrinsic: "
  59. "is %ld, should be between 1 and %ld",
  60. (long int) dim + 1, (long int) rank + 1);
  61. }
  62. len = GFC_DESCRIPTOR_EXTENT(array,dim);
  63. if (len < 0)
  64. len = 0;
  65. delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
  66. for (n = 0; n < dim; n++)
  67. {
  68. sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
  69. extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
  70. if (extent[n] < 0)
  71. extent[n] = 0;
  72. }
  73. for (n = dim; n < rank; n++)
  74. {
  75. sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1) * string_len;
  76. extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
  77. if (extent[n] < 0)
  78. extent[n] = 0;
  79. }
  80. if (retarray->base_addr == NULL)
  81. {
  82. size_t alloc_size, str;
  83. for (n = 0; n < rank; n++)
  84. {
  85. if (n == 0)
  86. str = 1;
  87. else
  88. str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
  89. GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
  90. }
  91. retarray->offset = 0;
  92. retarray->dtype.rank = rank;
  93. alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]
  94. * string_len;
  95. retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
  96. if (alloc_size == 0)
  97. {
  98. /* Make sure we have a zero-sized array. */
  99. GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
  100. return;
  101. }
  102. }
  103. else
  104. {
  105. if (rank != GFC_DESCRIPTOR_RANK (retarray))
  106. runtime_error ("rank of return array incorrect in"
  107. " u_name intrinsic: is %ld, should be %ld",
  108. (long int) (GFC_DESCRIPTOR_RANK (retarray)),
  109. (long int) rank);
  110. if (unlikely (compile_options.bounds_check))
  111. bounds_ifunction_return ((array_t *) retarray, extent,
  112. "return value", "u_name");
  113. }
  114. for (n = 0; n < rank; n++)
  115. {
  116. count[n] = 0;
  117. dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len;
  118. if (extent[n] <= 0)
  119. return;
  120. }
  121. base = array->base_addr;
  122. dest = retarray->base_addr;
  123. continue_loop = 1;
  124. while (continue_loop)
  125. {
  126. const atype_name * restrict src;
  127. src = base;
  128. {
  129. ')dnl
  130. define(START_ARRAY_BLOCK,
  131. ` if (len <= 0)
  132. memset (dest, '$1`, sizeof (*dest) * string_len);
  133. else
  134. {
  135. for (n = 0; n < len; n++, src += delta)
  136. {
  137. ')dnl
  138. define(FINISH_ARRAY_FUNCTION,
  139. ` }
  140. '$1`
  141. memcpy (dest, retval, sizeof (*dest) * string_len);
  142. }
  143. }
  144. /* Advance to the next element. */
  145. count[0]++;
  146. base += sstride[0];
  147. dest += dstride[0];
  148. n = 0;
  149. while (count[n] == extent[n])
  150. {
  151. /* When we get to the end of a dimension, reset it and increment
  152. the next dimension. */
  153. count[n] = 0;
  154. /* We could precalculate these products, but this is a less
  155. frequently used path so probably not worth it. */
  156. base -= sstride[n] * extent[n];
  157. dest -= dstride[n] * extent[n];
  158. n++;
  159. if (n >= rank)
  160. {
  161. /* Break out of the loop. */
  162. continue_loop = 0;
  163. break;
  164. }
  165. else
  166. {
  167. count[n]++;
  168. base += sstride[n];
  169. dest += dstride[n];
  170. }
  171. }
  172. }
  173. }')dnl
  174. define(START_MASKED_ARRAY_FUNCTION,
  175. `
  176. extern void `m'name`'rtype_qual`_'atype_code (rtype * const restrict,
  177. gfc_charlen_type, atype * const restrict,
  178. const index_type * const restrict,
  179. gfc_array_l1 * const restrict, gfc_charlen_type);
  180. export_proto(`m'name`'rtype_qual`_'atype_code);
  181. void
  182. `m'name`'rtype_qual`_'atype_code (rtype * const restrict retarray,
  183. gfc_charlen_type xlen, atype * const restrict array,
  184. const index_type * const restrict pdim,
  185. gfc_array_l1 * const restrict mask,
  186. gfc_charlen_type string_len)
  187. {
  188. index_type count[GFC_MAX_DIMENSIONS];
  189. index_type extent[GFC_MAX_DIMENSIONS];
  190. index_type sstride[GFC_MAX_DIMENSIONS];
  191. index_type dstride[GFC_MAX_DIMENSIONS];
  192. index_type mstride[GFC_MAX_DIMENSIONS];
  193. rtype_name * restrict dest;
  194. const atype_name * restrict base;
  195. const GFC_LOGICAL_1 * restrict mbase;
  196. index_type rank;
  197. index_type dim;
  198. index_type n;
  199. index_type len;
  200. index_type delta;
  201. index_type mdelta;
  202. int mask_kind;
  203. if (mask == NULL)
  204. {
  205. name`'rtype_qual`_'atype_code (retarray, xlen, array, pdim, string_len);
  206. return;
  207. }
  208. assert (xlen == string_len);
  209. dim = (*pdim) - 1;
  210. rank = GFC_DESCRIPTOR_RANK (array) - 1;
  211. if (unlikely (dim < 0 || dim > rank))
  212. {
  213. runtime_error ("Dim argument incorrect in u_name intrinsic: "
  214. "is %ld, should be between 1 and %ld",
  215. (long int) dim + 1, (long int) rank + 1);
  216. }
  217. len = GFC_DESCRIPTOR_EXTENT(array,dim);
  218. if (len <= 0)
  219. return;
  220. mbase = mask->base_addr;
  221. mask_kind = GFC_DESCRIPTOR_SIZE (mask);
  222. if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
  223. #ifdef HAVE_GFC_LOGICAL_16
  224. || mask_kind == 16
  225. #endif
  226. )
  227. mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
  228. else
  229. runtime_error ("Funny sized logical array");
  230. delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
  231. mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
  232. for (n = 0; n < dim; n++)
  233. {
  234. sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
  235. mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
  236. extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
  237. if (extent[n] < 0)
  238. extent[n] = 0;
  239. }
  240. for (n = dim; n < rank; n++)
  241. {
  242. sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len;
  243. mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
  244. extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
  245. if (extent[n] < 0)
  246. extent[n] = 0;
  247. }
  248. if (retarray->base_addr == NULL)
  249. {
  250. size_t alloc_size, str;
  251. for (n = 0; n < rank; n++)
  252. {
  253. if (n == 0)
  254. str = 1;
  255. else
  256. str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
  257. GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
  258. }
  259. alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]
  260. * string_len;
  261. retarray->offset = 0;
  262. retarray->dtype.rank = rank;
  263. if (alloc_size == 0)
  264. {
  265. /* Make sure we have a zero-sized array. */
  266. GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
  267. return;
  268. }
  269. else
  270. retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
  271. }
  272. else
  273. {
  274. if (rank != GFC_DESCRIPTOR_RANK (retarray))
  275. runtime_error ("rank of return array incorrect in u_name intrinsic");
  276. if (unlikely (compile_options.bounds_check))
  277. {
  278. bounds_ifunction_return ((array_t *) retarray, extent,
  279. "return value", "u_name");
  280. bounds_equal_extents ((array_t *) mask, (array_t *) array,
  281. "MASK argument", "u_name");
  282. }
  283. }
  284. for (n = 0; n < rank; n++)
  285. {
  286. count[n] = 0;
  287. dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len;
  288. if (extent[n] <= 0)
  289. return;
  290. }
  291. dest = retarray->base_addr;
  292. base = array->base_addr;
  293. while (base)
  294. {
  295. const atype_name * restrict src;
  296. const GFC_LOGICAL_1 * restrict msrc;
  297. src = base;
  298. msrc = mbase;
  299. {
  300. ')dnl
  301. define(START_MASKED_ARRAY_BLOCK,
  302. ` for (n = 0; n < len; n++, src += delta, msrc += mdelta)
  303. {
  304. ')dnl
  305. define(FINISH_MASKED_ARRAY_FUNCTION,
  306. ` }
  307. memcpy (dest, retval, sizeof (*dest) * string_len);
  308. }
  309. /* Advance to the next element. */
  310. count[0]++;
  311. base += sstride[0];
  312. mbase += mstride[0];
  313. dest += dstride[0];
  314. n = 0;
  315. while (count[n] == extent[n])
  316. {
  317. /* When we get to the end of a dimension, reset it and increment
  318. the next dimension. */
  319. count[n] = 0;
  320. /* We could precalculate these products, but this is a less
  321. frequently used path so probably not worth it. */
  322. base -= sstride[n] * extent[n];
  323. mbase -= mstride[n] * extent[n];
  324. dest -= dstride[n] * extent[n];
  325. n++;
  326. if (n >= rank)
  327. {
  328. /* Break out of the loop. */
  329. base = NULL;
  330. break;
  331. }
  332. else
  333. {
  334. count[n]++;
  335. base += sstride[n];
  336. mbase += mstride[n];
  337. dest += dstride[n];
  338. }
  339. }
  340. }
  341. }')dnl
  342. define(SCALAR_ARRAY_FUNCTION,
  343. `
  344. void `s'name`'rtype_qual`_'atype_code (rtype * const restrict,
  345. gfc_charlen_type, atype * const restrict,
  346. const index_type * const restrict,
  347. GFC_LOGICAL_4 *, gfc_charlen_type);
  348. export_proto(`s'name`'rtype_qual`_'atype_code);
  349. void
  350. `s'name`'rtype_qual`_'atype_code (rtype * const restrict retarray,
  351. gfc_charlen_type xlen, atype * const restrict array,
  352. const index_type * const restrict pdim,
  353. GFC_LOGICAL_4 *mask, gfc_charlen_type string_len)
  354. {
  355. index_type count[GFC_MAX_DIMENSIONS];
  356. index_type extent[GFC_MAX_DIMENSIONS];
  357. index_type dstride[GFC_MAX_DIMENSIONS];
  358. rtype_name * restrict dest;
  359. index_type rank;
  360. index_type n;
  361. index_type dim;
  362. if (mask == NULL || *mask)
  363. {
  364. name`'rtype_qual`_'atype_code (retarray, xlen, array, pdim, string_len);
  365. return;
  366. }
  367. /* Make dim zero based to avoid confusion. */
  368. dim = (*pdim) - 1;
  369. rank = GFC_DESCRIPTOR_RANK (array) - 1;
  370. if (unlikely (dim < 0 || dim > rank))
  371. {
  372. runtime_error ("Dim argument incorrect in u_name intrinsic: "
  373. "is %ld, should be between 1 and %ld",
  374. (long int) dim + 1, (long int) rank + 1);
  375. }
  376. for (n = 0; n < dim; n++)
  377. {
  378. extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
  379. if (extent[n] <= 0)
  380. extent[n] = 0;
  381. }
  382. for (n = dim; n < rank; n++)
  383. {
  384. extent[n] =
  385. GFC_DESCRIPTOR_EXTENT(array,n + 1);
  386. if (extent[n] <= 0)
  387. extent[n] = 0;
  388. }
  389. if (retarray->base_addr == NULL)
  390. {
  391. size_t alloc_size, str;
  392. for (n = 0; n < rank; n++)
  393. {
  394. if (n == 0)
  395. str = 1;
  396. else
  397. str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
  398. GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
  399. }
  400. retarray->offset = 0;
  401. retarray->dtype.rank = rank;
  402. alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]
  403. * string_len;
  404. if (alloc_size == 0)
  405. {
  406. /* Make sure we have a zero-sized array. */
  407. GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
  408. return;
  409. }
  410. else
  411. retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
  412. }
  413. else
  414. {
  415. if (rank != GFC_DESCRIPTOR_RANK (retarray))
  416. runtime_error ("rank of return array incorrect in"
  417. " u_name intrinsic: is %ld, should be %ld",
  418. (long int) (GFC_DESCRIPTOR_RANK (retarray)),
  419. (long int) rank);
  420. if (unlikely (compile_options.bounds_check))
  421. {
  422. for (n=0; n < rank; n++)
  423. {
  424. index_type ret_extent;
  425. ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
  426. if (extent[n] != ret_extent)
  427. runtime_error ("Incorrect extent in return value of"
  428. " u_name intrinsic in dimension %ld:"
  429. " is %ld, should be %ld", (long int) n + 1,
  430. (long int) ret_extent, (long int) extent[n]);
  431. }
  432. }
  433. }
  434. for (n = 0; n < rank; n++)
  435. {
  436. count[n] = 0;
  437. dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len;
  438. }
  439. dest = retarray->base_addr;
  440. while(1)
  441. {
  442. memset (dest, '$1`, sizeof (*dest) * string_len);
  443. count[0]++;
  444. dest += dstride[0];
  445. n = 0;
  446. while (count[n] == extent[n])
  447. {
  448. /* When we get to the end of a dimension, reset it and increment
  449. the next dimension. */
  450. count[n] = 0;
  451. /* We could precalculate these products, but this is a less
  452. frequently used path so probably not worth it. */
  453. dest -= dstride[n] * extent[n];
  454. n++;
  455. if (n >= rank)
  456. return;
  457. else
  458. {
  459. count[n]++;
  460. dest += dstride[n];
  461. }
  462. }
  463. }
  464. }')dnl
  465. define(ARRAY_FUNCTION,
  466. `START_ARRAY_FUNCTION($1)
  467. $2
  468. START_ARRAY_BLOCK($1)
  469. $3
  470. FINISH_ARRAY_FUNCTION($4)')dnl
  471. define(MASKED_ARRAY_FUNCTION,
  472. `START_MASKED_ARRAY_FUNCTION
  473. $2
  474. START_MASKED_ARRAY_BLOCK
  475. $3
  476. FINISH_MASKED_ARRAY_FUNCTION')dnl