ffi.scm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. ; -*- mode: scheme; coding: utf-8 -*-
  2. ; (c) Daniel Llorens - 2021
  3. ; This library is free software; you can redistribute it and/or modify it under
  4. ; the terms of the GNU General Public License as published by the Free
  5. ; Software Foundation; either version 3 of the License, or (at your option) any
  6. ; later version.
  7. ;;; Commentary:
  8. ;; Fortran FFI featuring newra types
  9. ;;; Code:
  10. (define-module (newra ffi)
  11. #:export (ra->fortran fortran-library-function))
  12. (import (srfi srfi-8) (srfi srfi-26) (srfi srfi-71) (srfi srfi-1) (srfi srfi-4 gnu)
  13. (ice-9 match) (ice-9 format) (rnrs bytevectors)
  14. (system foreign) (system foreign-library)
  15. (newra) (newra base))
  16. ; https://gcc.gnu.org/onlinedocs/gfortran/Further-Interoperability-of-Fortran-with-C.html
  17. ; https://github.com/gcc-mirror/gcc/blob/master/libgfortran/ISO_Fortran_binding.h
  18. #|
  19. /* CFI type definitions. */
  20. typedef ptrdiff_t CFI_index_t;
  21. typedef int8_t CFI_rank_t;
  22. typedef int8_t CFI_attribute_t;
  23. typedef int16_t CFI_type_t;
  24. /* CFI_dim_t. */
  25. typedef struct CFI_dim_t
  26. {
  27. CFI_index_t lower_bound;
  28. CFI_index_t extent;
  29. CFI_index_t sm; // step between start of successive elements, in bytes
  30. }
  31. CFI_dim_t;
  32. /* CFI_cdesc_t, C descriptors are cast to this structure as follows:
  33. CFI_CDESC_T(CFI_MAX_RANK) foo;
  34. CFI_cdesc_t * bar = (CFI_cdesc_t *) &foo;
  35. */
  36. typedef struct CFI_cdesc_t
  37. {
  38. void *base_addr;
  39. size_t elem_len; // size of one element, in bytes
  40. int version;
  41. CFI_rank_t rank;
  42. CFI_attribute_t attribute;
  43. CFI_type_t type;
  44. CFI_dim_t dim[];
  45. }
  46. CFI_cdesc
  47. #define CFI_type_Integer 1
  48. #define CFI_type_Logical 2
  49. #define CFI_type_Real 3
  50. #define CFI_type_Complex 4
  51. #define CFI_type_Character 5
  52. |#
  53. (define CFI_VERSION 1)
  54. (define CFI_MAX_RANK 15)
  55. (define CFI_attribute_pointer 0)
  56. (define CFI_attribute_allocatable 1)
  57. (define CFI_attribute_other 2)
  58. (define CFI_type_Integer 1)
  59. (define CFI_type_Logical 2)
  60. (define CFI_type_Real 3)
  61. (define CFI_type_Complex 4)
  62. (define CFI_type_Character 5)
  63. (define CFI_type_kind_shift 8)
  64. (define CFI_type_int8_t (+ CFI_type_Integer (ash (sizeof int8) CFI_type_kind_shift)))
  65. (define CFI_type_int16_t (+ CFI_type_Integer (ash (sizeof int16) CFI_type_kind_shift)))
  66. (define CFI_type_int32_t (+ CFI_type_Integer (ash (sizeof int32) CFI_type_kind_shift)))
  67. (define CFI_type_int64_t (+ CFI_type_Integer (ash (sizeof int64) CFI_type_kind_shift)))
  68. (define CFI_type_float (+ CFI_type_Real (ash (sizeof float) CFI_type_kind_shift)))
  69. (define CFI_type_double (+ CFI_type_Real (ash (sizeof double) CFI_type_kind_shift)))
  70. (define CFI_type_float_Complex (+ CFI_type_Complex (ash (sizeof float) CFI_type_kind_shift)))
  71. (define CFI_type_double_Complex (+ CFI_type_Complex (ash (sizeof double) CFI_type_kind_shift)))
  72. (define (CFI-type t)
  73. (case t
  74. ((vu8 u8 s8) CFI_type_int8_t)
  75. ((u16 s16) CFI_type_int16_t)
  76. ((u32 s32) CFI_type_int32_t)
  77. ((u64 s64) CFI_type_int64_t)
  78. ((f32) CFI_type_float)
  79. ((f64) CFI_type_double)
  80. ((c32) CFI_type_float_Complex)
  81. ((c64) CFI_type_double_Complex)
  82. (else (throw 'no-CFI-type-for t))))
  83. (define CFI_index_t ptrdiff_t)
  84. (define CFI_rank_t int8)
  85. (define CFI_attribute_t int8)
  86. (define CFI_type_t int16)
  87. (define (ra->fortran a)
  88. (define theversion 1)
  89. (define theattribute CFI_attribute_pointer)
  90. (let ((rank (ra-rank a))
  91. (elemsize (srfi-4-vector-type-size (ra-root a))))
  92. (unless (<= 0 rank CFI_MAX_RANK)
  93. (throw 'bad-rank rank))
  94. (make-c-struct
  95. (append (list '* ; 0
  96. size_t ; 8
  97. int ; 16
  98. CFI_rank_t ; 20
  99. CFI_attribute_t ; 21
  100. CFI_type_t) ; 22
  101. (make-list (* 3 rank) CFI_index_t)) ; 24
  102. (append (list (bytevector->pointer (ra-root a) (* elemsize (ra-offset a))) ; 0
  103. elemsize ; 8
  104. theversion ; 16
  105. rank ; 20
  106. theattribute ; 21
  107. (CFI-type (ra-type a))) ; 22
  108. (append-map ; 24
  109. (match-lambda
  110. (($ <dim> len lo step)
  111. ; lbound is always 1 fortranside. FIXME warn?
  112. (list lo len (* elemsize step))))
  113. (vector->list (ra-dims a)))))))
  114. (define (ra->ffi-type t)
  115. (case t
  116. ((vu8 u8) uint8)
  117. ((u16) uint16)
  118. ((u32) uint32)
  119. ((u64) uint64)
  120. ((s8) int8)
  121. ((s16) int16)
  122. ((s32) int32)
  123. ((s64) int64)
  124. ((f32) float)
  125. ((f64) double)
  126. ((c32) complex-float)
  127. ((c64) complex-double)
  128. (else (throw 'no-ffi-type-for t))))
  129. (define (symbol->ffi-type t)
  130. (case t
  131. ((uint8) uint8)
  132. ((uint16) uint16)
  133. ((uint32) uint32)
  134. ((uint64) uint64)
  135. ((int8) int8)
  136. ((int16) int16)
  137. ((int32) int32)
  138. ((int64) int64)
  139. ((float) float)
  140. ((double) double)
  141. ((complex-float) complex-float)
  142. ((complex-double) complex-double)
  143. (else (throw 'no-ffi-type-for t))))
  144. (define* (fortran-library-function lib name return-type arg-types)
  145. (let ((f (foreign-library-function
  146. lib name #:return-type return-type
  147. #:arg-types (make-list (length arg-types) '*))))
  148. (lambda args
  149. (let ((fargs
  150. (map (match-lambda*
  151. ((arg (type-symbol dims ...))
  152. (unless (eqv? (symbol->ffi-type type-symbol) (ra->ffi-type (ra-type arg)))
  153. (throw 'bad-type type-symbol (ra-type arg)))
  154. (ra->fortran
  155. (let ((ndims (length dims)))
  156. (if (and (= ndims 1) (eq? '.. (car dims)))
  157. arg
  158. (if (and (= ndims (ra-rank arg))
  159. (every (lambda (lohi dim)
  160. (or (eq? ': dim) (equal? lohi dim)))
  161. (ra-dimensions arg) dims))
  162. arg
  163. (throw 'bad-sizes (ra-dimensions arg) dims))))))
  164. ((arg '*)
  165. arg)
  166. ((arg type-symbol)
  167. (make-c-struct (list (symbol->ffi-type type-symbol)) (list arg))))
  168. args
  169. arg-types)))
  170. (apply f fargs)))))