GCC Code Coverage Report


Directory: src/athena/
File: src/athena/athena_onnx_utils.f90
Date: 2026-04-15 16:08:59
Exec Total Coverage
Lines: 367 417 88.0%
Functions: 0 0 -%
Branches: 849 1733 49.0%

Line Branch Exec Source
1 module athena__onnx_utils
2 !! Shared utility routines for ONNX JSON export
3 !!
4 !! Contains base64 encoding, node emission helpers, col→row transpose,
5 !! and activation/attribute-building utilities used by both the main
6 !! write_onnx procedure and layer-specific emit_onnx_nodes overrides.
7 use coreutils, only: real32, to_lower
8 use athena__misc_types, only: onnx_node_type, onnx_initialiser_type, &
9 onnx_tensor_type, onnx_attribute_type
10 use athena__base_layer, only: base_layer_type, learnable_layer_type
11 implicit none
12
13 private
14
15 public :: emit_node
16 public :: emit_squeeze_node
17 public :: emit_constant_int64
18 public :: emit_constant_float
19 public :: emit_constant_of_shape_float
20 public :: emit_activation_node
21 public :: emit_initialisers
22 public :: build_attributes_json
23 public :: col_to_row_major_2d
24 public :: write_json_nodes
25 public :: write_json_initialisers
26 public :: write_json_tensors
27 public :: encode_float32_base64
28 public :: encode_float32_base64_alloc
29 public :: encode_int64_base64
30 public :: encode_int64_base64_alloc
31 public :: decode_base64_to_float32
32 public :: decode_base64_to_int64
33 public :: row_to_col_major_2d
34 public :: encode_string_base64
35 public :: base64_encode_bytes
36 public :: base64_encode_bytes_fixed
37 public :: parse_space_separated_ints
38 public :: onnx_to_athena_activation
39
40 contains
41
42
43 !###############################################################################
44 165 subroutine emit_node(op_type, name, out1, attr_json, nodes, num_nodes, &
45 in1, in2, in3)
46 !! Emit a simple ONNX node (individual string interface)
47 !! Avoids gfortran array constructor issues
48 implicit none
49
50 ! Arguments
51 character(*), intent(in) :: op_type, name, out1, attr_json
52 !! ONNX operation type, node name, output name, and attribute JSON
53 type(onnx_node_type), intent(inout), dimension(:) :: nodes
54 !! Node accumulator array
55 integer, intent(inout) :: num_nodes
56 !! Current number of populated nodes
57 character(*), intent(in), optional :: in1, in2, in3
58 !! Optional input tensor names
59
60 ! Local variables
61 integer :: n_in
62 !! Number of connected inputs for the emitted node
63
64 165 n_in = 0
65
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if(present(in1)) n_in = 1
66
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 64 times.
165 if(present(in2)) n_in = 2
67
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 158 times.
165 if(present(in3)) n_in = 3
68
69 165 num_nodes = num_nodes + 1
70
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 165 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 165 times.
✓ Branch 7 taken 165 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 165 times.
✗ Branch 10 not taken.
165 nodes(num_nodes)%name = trim(name)
71
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 165 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 165 times.
✓ Branch 7 taken 165 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 165 times.
✗ Branch 10 not taken.
165 nodes(num_nodes)%op_type = trim(op_type)
72
9/18
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✓ Branch 6 taken 165 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 165 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 165 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 165 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 165 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 165 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 165 times.
165 allocate(nodes(num_nodes)%inputs(n_in))
73
7/14
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 165 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 165 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 165 times.
✓ Branch 15 taken 165 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 165 times.
✗ Branch 18 not taken.
165 if(present(in1)) nodes(num_nodes)%inputs(1) = trim(in1)
74
8/14
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 101 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 101 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 101 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 101 times.
✓ Branch 15 taken 101 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 101 times.
✗ Branch 18 not taken.
165 if(present(in2)) nodes(num_nodes)%inputs(2) = trim(in2)
75
8/14
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 158 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✓ Branch 15 taken 7 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 7 times.
✗ Branch 18 not taken.
165 if(present(in3)) nodes(num_nodes)%inputs(3) = trim(in3)
76
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 165 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 165 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 165 times.
165 allocate(nodes(num_nodes)%outputs(1))
77
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 165 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 165 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 165 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 165 times.
✓ Branch 13 taken 165 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 165 times.
✗ Branch 16 not taken.
165 nodes(num_nodes)%outputs(1) = trim(out1)
78
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✓ Branch 6 taken 165 times.
✗ Branch 7 not taken.
165 nodes(num_nodes)%attributes_json = attr_json
79
80
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 end subroutine emit_node
81 !###############################################################################
82
83
84 !###############################################################################
85 14 subroutine emit_squeeze_node(name, input, axes_input, output, &
86 14 nodes, num_nodes)
87 !! Emit a Squeeze node (ONNX opset 13+: axes as input)
88 implicit none
89
90 ! Arguments
91 character(*), intent(in) :: name, input, axes_input, output
92 !! Node name, data input, axes input, and output tensor name
93 type(onnx_node_type), intent(inout), dimension(:) :: nodes
94 !! Node accumulator array
95 integer, intent(inout) :: num_nodes
96 !! Current number of populated nodes
97
98 call emit_node('Squeeze', name, output, '', nodes, num_nodes, &
99
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
14 in1=input, in2=axes_input)
100
101
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 end subroutine emit_squeeze_node
102 !###############################################################################
103
104
105 !###############################################################################
106
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 subroutine emit_constant_int64(name, values, dims, &
107
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 nodes, num_nodes, inits, num_inits)
108 !! Emit a Constant node producing an int64 tensor
109 implicit none
110
111 ! Arguments
112 character(*), intent(in) :: name
113 !! Constant node and output tensor name
114 integer, intent(in) :: values(:), dims(:)
115 !! Constant values and tensor dimensions
116 type(onnx_node_type), intent(inout), dimension(:) :: nodes
117 !! Node accumulator array
118 integer, intent(inout) :: num_nodes
119 !! Current number of populated nodes
120 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
121 !! Initialiser accumulator array (unused, kept for interface symmetry)
122 integer, intent(inout) :: num_inits
123 !! Current number of populated initialisers (unused)
124
125 ! Local variables
126 character(4096) :: attr_str
127 !! Serialized ONNX attribute JSON for the constant payload
128 character(256) :: raw_b64
129 !! Base64-encoded raw tensor data
130 integer :: i
131 !! Dimension loop index
132
133 ! Encode int64 values as base64
134
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
37 call encode_int64_base64(values, raw_b64)
135
136 ! Build dims string
137 37 attr_str = ' "attribute": [{"name": "value", "t": {'
138
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✓ Branch 9 taken 37 times.
✗ Branch 10 not taken.
37 if(size(dims) .gt. 0)then
139
2/4
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 attr_str = trim(attr_str) // '"dims": ['
140
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✓ Branch 9 taken 37 times.
✓ Branch 10 taken 37 times.
74 do i = 1, size(dims)
141
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 if(i .gt. 1) attr_str = trim(attr_str) // ', '
142
3/6
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 37 times.
74 write(attr_str, '(A,"""",I0,"""")') trim(attr_str), dims(i)
143 end do
144
2/4
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 attr_str = trim(attr_str) // '], '
145 end if
146 attr_str = trim(attr_str) // '"dataType": 7, "rawData": "' // &
147
3/6
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 37 times.
✗ Branch 10 not taken.
37 trim(raw_b64) // '"}, "type": "TENSOR"}]'
148
149 37 num_nodes = num_nodes + 1
150
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✓ Branch 7 taken 37 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 37 times.
✗ Branch 10 not taken.
37 nodes(num_nodes)%name = trim(name)
151
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
37 nodes(num_nodes)%op_type = 'Constant'
152
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 37 times.
37 allocate(nodes(num_nodes)%inputs(0))
153
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 37 times.
37 allocate(nodes(num_nodes)%outputs(1))
154
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 37 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 37 times.
✓ Branch 13 taken 37 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 37 times.
✗ Branch 16 not taken.
37 nodes(num_nodes)%outputs(1) = trim(name)
155
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✓ Branch 7 taken 37 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 37 times.
✗ Branch 10 not taken.
37 nodes(num_nodes)%attributes_json = trim(attr_str)
156
157
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 end subroutine emit_constant_int64
158 !###############################################################################
159
160
161 !###############################################################################
162
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 subroutine emit_constant_float(name, values, dims, &
163
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 nodes, num_nodes, inits, num_inits)
164 !! Emit a Constant node producing a float32 tensor
165 implicit none
166
167 ! Arguments
168 character(*), intent(in) :: name
169 !! Constant node and output tensor name
170 real(real32), intent(in) :: values(:)
171 !! Float32 constant values to embed in the node
172 integer, intent(in) :: dims(:)
173 !! Tensor dimensions for the constant value
174 type(onnx_node_type), intent(inout), dimension(:) :: nodes
175 !! Node accumulator array
176 integer, intent(inout) :: num_nodes
177 !! Current number of populated nodes
178 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
179 !! Initialiser accumulator array (unused, kept for interface symmetry)
180 integer, intent(inout) :: num_inits
181 !! Current number of populated initialisers (unused)
182
183 ! Local variables
184 character(4096) :: attr_str
185 !! Serialized ONNX attribute JSON for the constant payload
186 character(256) :: raw_b64
187 !! Base64-encoded raw tensor data
188 integer :: i
189 !! Dimension loop index
190
191
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
7 call encode_float32_base64(values, size(values), raw_b64)
192
193 7 attr_str = ' "attribute": [{"name": "value", "t": {'
194
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
7 if(size(dims) .gt. 0)then
195
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 attr_str = trim(attr_str) // '"dims": ['
196
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 7 times.
14 do i = 1, size(dims)
197
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7 if(i .gt. 1) attr_str = trim(attr_str) // ', '
198
3/6
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 7 times.
14 write(attr_str, '(A,"""",I0,"""")') trim(attr_str), dims(i)
199 end do
200
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 attr_str = trim(attr_str) // '], '
201 end if
202 attr_str = trim(attr_str) // '"dataType": 1, "rawData": "' // &
203
3/6
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
7 trim(raw_b64) // '"}, "type": "TENSOR"}]'
204
205 7 num_nodes = num_nodes + 1
206
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
7 nodes(num_nodes)%name = trim(name)
207
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 nodes(num_nodes)%op_type = 'Constant'
208
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
7 allocate(nodes(num_nodes)%inputs(0))
209
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
7 allocate(nodes(num_nodes)%outputs(1))
210
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 7 times.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 7 times.
✗ Branch 16 not taken.
7 nodes(num_nodes)%outputs(1) = trim(name)
211
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
7 nodes(num_nodes)%attributes_json = trim(attr_str)
212
213
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 end subroutine emit_constant_float
214 !###############################################################################
215
216
217 !###############################################################################
218 5 subroutine emit_constant_of_shape_float(name, shape_input, value, output, &
219 5 nodes, num_nodes, inits, num_inits)
220 !! Emit a ConstantOfShape node
221 implicit none
222
223 ! Arguments
224 character(*), intent(in) :: name, shape_input, output
225 !! Node name, shape tensor input, and output tensor name
226 real(real32), intent(in) :: value
227 !! Fill value to use for the generated tensor
228 type(onnx_node_type), intent(inout), dimension(:) :: nodes
229 !! Node accumulator array
230 integer, intent(inout) :: num_nodes
231 !! Current number of populated nodes
232 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
233 !! Initialiser accumulator array (unused, kept for interface symmetry)
234 integer, intent(inout) :: num_inits
235 !! Current number of populated initialisers (unused)
236
237 ! Local variables
238 character(4096) :: attr_str
239 !! Serialized ONNX attribute JSON for the fill tensor
240 character(256) :: raw_b64
241 !! Base64-encoded fill value
242
243
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 call encode_float32_base64([value], 1, raw_b64)
244
245 attr_str = ' "attribute": [{"name": "value", "t": {' // &
246 '"dims": ["1"], "dataType": 1, "rawData": "' // &
247
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
5 trim(raw_b64) // '"}, "type": "TENSOR"}]'
248
249 call emit_node('ConstantOfShape', name, output, &
250 trim(attr_str), nodes, num_nodes, &
251
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
5 in1=shape_input)
252
253
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 end subroutine emit_constant_of_shape_float
254 !###############################################################################
255
256
257 !###############################################################################
258 12 subroutine emit_activation_node(name, prefix, input_override, &
259 12 nodes, num_nodes, max_nodes)
260 !! Emit an activation function node
261 use coreutils, only: to_camel_case
262 implicit none
263
264 ! Arguments
265 character(*), intent(in) :: name, prefix, input_override
266 !! Activation name, node prefix, and optional override for the input name
267 type(onnx_node_type), intent(inout), dimension(:) :: nodes
268 !! Node accumulator array
269 integer, intent(inout) :: num_nodes
270 !! Current number of populated nodes
271 integer, intent(in) :: max_nodes
272 !! Maximum number of nodes available in the accumulator
273
274 ! Local variables
275 character(128) :: actv_name, input_n, output_n
276 !! Normalised ONNX op name, input tensor name, and output tensor name
277 character(4096) :: attr_str
278 !! Serialized ONNX attribute JSON for activation-specific options
279
280 actv_name = to_camel_case( &
281 trim(adjustl(name)), &
282
2/4
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
12 capitalise_first_letter = .true.)
283
284
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if(len_trim(input_override) .gt. 0)then
285
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 input_n = trim(input_override)
286 else
287
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 input_n = trim(prefix) // '_output'
288 end if
289
3/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
12 output_n = trim(prefix) // '_' // trim(adjustl(name)) // '_output'
290
291 12 attr_str = ''
292 ! LeakyRelu needs alpha attribute
293
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 if(trim(name) .eq. 'leaky_relu')then
294 actv_name = 'LeakyRelu'
295 attr_str = ' "attribute": [{"name": "alpha", ' // &
296 '"f": 0.01, "type": "FLOAT"}]'
297 end if
298
299 call emit_node(trim(actv_name), &
300 trim(prefix)//'_'//trim(adjustl(name)), &
301 trim(output_n), trim(attr_str), nodes, num_nodes, &
302
9/18
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✓ Branch 20 taken 12 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 12 times.
✓ Branch 26 taken 12 times.
✗ Branch 27 not taken.
12 in1=trim(input_n))
303
304
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 end subroutine emit_activation_node
305 !###############################################################################
306
307
308 !###############################################################################
309 10 subroutine emit_initialisers(layer, prefix, inits, num_inits, max_inits)
310 !! Emit initialisers for a learnable layer
311 implicit none
312
313 ! Arguments
314 class(learnable_layer_type), intent(in) :: layer
315 !! Learnable layer containing parameter tensors and shape metadata
316 character(*), intent(in) :: prefix
317 !! Name prefix used to generate exported initialiser names
318 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
319 !! Initialiser accumulator array
320 integer, intent(inout) :: num_inits
321 !! Current number of populated initialisers
322 integer, intent(in) :: max_inits
323 !! Maximum number of initialisers available in the accumulator
324
325 ! Local variables
326 integer :: i, j, n
327 !! Parameter index, shape index, and flattened tensor size
328 character(128) :: name
329 !! Generated ONNX initialiser name for the current parameter tensor
330
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(.not.allocated(layer%params)) return
332
333
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
36 do i = 1, size(layer%params)
334
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 n = size(layer%params(i)%val, 1)
335 26 num_inits = num_inits + 1
336
1/2
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
26 write(name, '(A,"_param",I0)') trim(prefix), i
337
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 26 times.
✓ Branch 7 taken 26 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
26 inits(num_inits)%name = trim(name)
338
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 inits(num_inits)%data_type = 1
339
340 ! Set dims from weight_shape
341
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if(allocated(layer%weight_shape))then
342
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 11 times.
26 if(i .le. size(layer%weight_shape, 2))then
343 15 j = 0
344
9/18
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 15 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 15 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 15 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 15 times.
15 allocate(inits(num_inits)%dims(size(layer%weight_shape, 1)))
345
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 15 times.
49 inits(num_inits)%dims = 0
346
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 15 times.
49 do j = 1, size(layer%weight_shape, 1)
347
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 34 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 34 times.
✓ Branch 12 taken 34 times.
✗ Branch 13 not taken.
49 if(layer%weight_shape(j,i) .gt. 0)then
348
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 34 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 34 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 34 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 34 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 34 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 34 times.
34 inits(num_inits)%dims(j) = layer%weight_shape(j,i)
349 end if
350 end do
351 ! Remove zero dims
352
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
30 inits(num_inits)%dims = pack(inits(num_inits)%dims, &
353
18/32
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 15 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 15 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 15 times.
✓ Branch 24 taken 34 times.
✓ Branch 25 taken 15 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 15 times.
✓ Branch 29 taken 34 times.
✓ Branch 30 taken 15 times.
✓ Branch 31 taken 15 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 15 times.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✓ Branch 37 taken 34 times.
✓ Branch 38 taken 15 times.
147 inits(num_inits)%dims .gt. 0)
354 else
355
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 11 times.
11 allocate(inits(num_inits)%dims(1))
356
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
✓ Branch 13 taken 11 times.
22 inits(num_inits)%dims = [n]
357 end if
358 else
359 allocate(inits(num_inits)%dims(1))
360 inits(num_inits)%dims = [n]
361 end if
362
363
9/18
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 26 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 26 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 26 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 26 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 26 times.
26 allocate(inits(num_inits)%data(n))
364 ! Convert column-major to row-major for 2D weight matrices
365
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
36 if(allocated(layer%weight_shape))then
366
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 11 times.
26 if(i .le. size(layer%weight_shape, 2))then
367
11/18
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 15 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 15 times.
✓ Branch 18 taken 34 times.
✓ Branch 19 taken 15 times.
✓ Branch 20 taken 34 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 13 times.
✓ Branch 23 taken 2 times.
49 if(count(layer%weight_shape(:,i) .gt. 0) .eq. 2)then
368 call col_to_row_major_2d( &
369 130 layer%params(i)%val(:,1), &
370
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 inits(num_inits)%data, &
371 52 layer%weight_shape(1,i), &
372
19/38
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 13 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 13 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 13 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 13 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 13 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 13 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 13 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 13 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 13 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 13 times.
✗ Branch 41 not taken.
✓ Branch 42 taken 13 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 13 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 13 times.
✗ Branch 50 not taken.
✓ Branch 51 taken 13 times.
✗ Branch 53 not taken.
✓ Branch 54 taken 13 times.
26 layer%weight_shape(2,i))
373 else
374
14/28
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 2 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 36 taken 72 times.
✓ Branch 37 taken 2 times.
74 inits(num_inits)%data = layer%params(i)%val(:,1)
375 end if
376 else
377
14/28
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 11 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 11 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 11 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 11 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 11 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 11 times.
✓ Branch 30 taken 11 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 11 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 36 taken 82 times.
✓ Branch 37 taken 11 times.
93 inits(num_inits)%data = layer%params(i)%val(:,1)
378 end if
379 else
380 inits(num_inits)%data = layer%params(i)%val(:,1)
381 end if
382 end do
383
384
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 end subroutine emit_initialisers
385 !###############################################################################
386
387
388 !###############################################################################
389 subroutine build_attributes_json(layer, op_type, attr_json)
390 !! Build JSON string for layer attributes
391 implicit none
392
393 ! Arguments
394 class(base_layer_type), intent(in) :: layer
395 !! Layer supplying ONNX attribute metadata
396 character(*), intent(in) :: op_type
397 !! ONNX operation type used to handle special cases
398 character(4096), intent(out) :: attr_json
399 !! Serialized JSON fragment containing the emitted attributes
400
401 ! Local variables
402 17 type(onnx_attribute_type), allocatable, dimension(:) :: attributes
403 !! Attribute list returned by the layer
404 integer :: i, j, itmp1
405 !! Attribute index, value index, and temporary integer count
406 character(256) :: buffer
407 !! Temporary string buffer for serialised scalar values
408 17 integer, allocatable :: ivar_list(:)
409 !! Parsed integer attribute payload for INTS-valued attributes
410 real(real32), allocatable :: rvar_list(:)
411 !! Placeholder for future real-valued list attributes
412 character(10) :: type_lw
413 !! Lower-case attribute type string used in the select case
414
415 17 attr_json = ''
416
417 ! For Gemm, add transB attribute
418
3/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 13 times.
17 if(trim(op_type) .eq. 'Gemm')then
419 attr_json = ' "attribute": [' // &
420 '{"name": "alpha", "f": 1.0, "type": "FLOAT"}, ' // &
421 '{"name": "beta", "f": 1.0, "type": "FLOAT"}, ' // &
422 4 '{"name": "transB", "i": "1", "type": "INT"}]'
423 4 return
424 end if
425
426
11/34
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 29 times.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 29 times.
✓ Branch 28 taken 13 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 29 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 29 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 29 times.
84 attributes = layer%get_attributes()
427
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
13 if(.not.allocated(attributes) .or. size(attributes) .eq. 0) return
428
429 8 attr_json = ' "attribute": ['
430
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 8 times.
37 do i = 1, size(attributes)
431
4/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
29 if(i .gt. 1) attr_json = trim(attr_json) // ', '
432 attr_json = trim(attr_json) // '{"name": "' // &
433
5/10
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 29 times.
✓ Branch 12 taken 29 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 29 times.
✗ Branch 16 not taken.
29 trim(attributes(i)%name) // '"'
434
435
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 8 taken 29 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 29 times.
✗ Branch 11 not taken.
29 type_lw = trim(adjustl(attributes(i)%type))
436 8 select case(type_lw)
437 case('int')
438 attr_json = trim(attr_json) // ', "i": "' // &
439
5/10
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✓ Branch 13 taken 15 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 15 times.
✗ Branch 17 not taken.
15 trim(adjustl(attributes(i)%val)) // '", "type": "INT"}'
440 case('ints')
441 ! Parse multiple ints
442 10 itmp1 = 1
443
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 10 times.
40 do j = 1, len_trim(attributes(i)%val)
444
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 30 times.
✓ Branch 11 taken 30 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 30 times.
✓ Branch 16 taken 10 times.
✓ Branch 17 taken 20 times.
40 if(attributes(i)%val(j:j) .eq. ' ') itmp1 = itmp1 + 1
445 end do
446
7/14
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 10 times.
10 allocate(ivar_list(itmp1))
447
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 read(attributes(i)%val, *) ivar_list
448
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 attr_json = trim(attr_json) // ', "ints": ['
449
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 do j = 1, itmp1
450
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
20 if(j .gt. 1) attr_json = trim(attr_json) // ', '
451
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
20 write(buffer, '("""",I0,"""")') ivar_list(j)
452
3/6
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
30 attr_json = trim(attr_json) // trim(adjustl(buffer))
453 end do
454
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 attr_json = trim(attr_json) // '], "type": "INTS"}'
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 deallocate(ivar_list)
456 case('float')
457 attr_json = trim(attr_json) // ', "f": ' // &
458 trim(adjustl(attributes(i)%val)) // ', "type": "FLOAT"}'
459 case('string')
460 ! Base64 encode the string value
461 call encode_string_base64( &
462
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
4 trim(adjustl(attributes(i)%val)), buffer)
463 attr_json = trim(attr_json) // ', "s": "' // &
464
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
4 trim(buffer) // '", "type": "STRING"}'
465 case default
466
3/9
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
29 attr_json = trim(attr_json) // '}'
467 end select
468 end do
469
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 attr_json = trim(attr_json) // ']'
470
471
10/16
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 29 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 29 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 29 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 29 times.
✗ Branch 15 not taken.
76 end subroutine build_attributes_json
472 !###############################################################################
473
474
475 ! =============================================================================
476 ! JSON serialisation utilities
477 ! =============================================================================
478
479 !###############################################################################
480
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 subroutine write_json_nodes(unit, nodes, num_nodes)
481 !! Write nodes array to JSON
482 implicit none
483
484 ! Arguments
485 integer, intent(in) :: unit
486 !! Output unit receiving the JSON text
487 type(onnx_node_type), intent(in), dimension(:) :: nodes
488 !! Node collection to serialise
489 integer, intent(in) :: num_nodes
490 !! Number of populated nodes in the collection
491
492 ! Local variables
493 integer :: i, j
494 !! Node and tensor index counters
495
496 11 write(unit, '(A)') ' "node": ['
497
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 11 times.
256 do i = 1, num_nodes
498 245 write(unit, '(A)') ' {'
499 ! Write inputs
500
6/10
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 245 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 245 times.
✓ Branch 12 taken 201 times.
✓ Branch 13 taken 44 times.
245 if(allocated(nodes(i)%inputs) .and. size(nodes(i)%inputs) .gt. 0)then
501 201 write(unit, '(A)', advance='no') ' "input": ['
502
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 201 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✓ Branch 6 taken 351 times.
✓ Branch 7 taken 201 times.
552 do j = 1, size(nodes(i)%inputs)
503
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 201 times.
351 if(j .gt. 1) write(unit, '(A)', advance='no') ', '
504 351 write(unit, '(A,A,A)', advance='no') '"', &
505
5/10
✗ Branch 1 not taken.
✓ Branch 2 taken 351 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 351 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 351 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 351 times.
✓ Branch 16 taken 351 times.
✗ Branch 17 not taken.
903 trim(adjustl(nodes(i)%inputs(j))), '"'
506 end do
507 201 write(unit, '(A)') '],'
508 end if
509 ! Write outputs
510
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
✓ Branch 6 taken 245 times.
✗ Branch 7 not taken.
245 if(allocated(nodes(i)%outputs))then
511 245 write(unit, '(A)', advance='no') ' "output": ['
512
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
✓ Branch 6 taken 245 times.
✓ Branch 7 taken 245 times.
490 do j = 1, size(nodes(i)%outputs)
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 if(j .gt. 1) write(unit, '(A)', advance='no') ', '
514 245 write(unit, '(A,A,A)', advance='no') '"', &
515
5/10
✗ Branch 1 not taken.
✓ Branch 2 taken 245 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 245 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 245 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 245 times.
✓ Branch 16 taken 245 times.
✗ Branch 17 not taken.
735 trim(adjustl(nodes(i)%outputs(j))), '"'
516 end do
517 245 write(unit, '(A)') '],'
518 end if
519 ! Name
520 245 write(unit, '(A,A,A)', advance='no') ' "name": "', &
521
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 245 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 245 times.
✓ Branch 10 taken 245 times.
✗ Branch 11 not taken.
490 trim(adjustl(nodes(i)%name)), '"'
522 ! OpType
523 245 write(unit, '(A)') ','
524 245 write(unit, '(A,A,A)', advance='no') ' "opType": "', &
525
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 245 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 245 times.
✓ Branch 10 taken 245 times.
✗ Branch 11 not taken.
490 trim(adjustl(nodes(i)%op_type)), '"'
526 ! Attributes
527
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
✓ Branch 6 taken 128 times.
✓ Branch 7 taken 117 times.
245 if(len_trim(nodes(i)%attributes_json) .gt. 0)then
528 128 write(unit, '(A)') ','
529
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 128 times.
✓ Branch 9 taken 128 times.
✗ Branch 10 not taken.
128 write(unit, '(A)') trim(nodes(i)%attributes_json)
530 else
531 117 write(unit, '(A)') ''
532 end if
533
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 11 times.
256 if(i .lt. num_nodes)then
534 234 write(unit, '(A)') ' },'
535 else
536 11 write(unit, '(A)') ' }'
537 end if
538 end do
539 11 write(unit, '(A)') ' ]'
540
541 11 end subroutine write_json_nodes
542 !###############################################################################
543
544
545 !###############################################################################
546
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 subroutine write_json_initialisers(unit, inits, num_inits)
547 !! Write initialisers array to JSON with base64-encoded rawData
548 implicit none
549
550 ! Arguments
551 integer, intent(in) :: unit
552 !! Output unit receiving the JSON text
553 type(onnx_initialiser_type), intent(in), dimension(:) :: inits
554 !! Initialiser collection to serialise
555 integer, intent(in) :: num_inits
556 !! Number of populated initialisers in the collection
557
558 ! Local variables
559 integer :: i, j, n
560 !! Initialiser index, dimension index, and raw element count
561 11 character(:), allocatable :: raw_b64
562 !! Base64-encoded raw tensor payload
563
564 11 write(unit, '(A)') ' "initializer": ['
565
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 11 times.
57 do i = 1, num_inits
566 46 write(unit, '(A)') ' {'
567 ! Dims
568
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
46 if(allocated(inits(i)%dims))then
569 46 write(unit, '(A)', advance='no') ' "dims": ['
570
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 6 taken 87 times.
✓ Branch 7 taken 46 times.
133 do j = 1, size(inits(i)%dims)
571
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 46 times.
87 if(j .gt. 1) write(unit, '(A)', advance='no') ', '
572
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 87 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 87 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 87 times.
133 write(unit, '("""",I0,"""")' , advance='no') inits(i)%dims(j)
573 end do
574 46 write(unit, '(A)') '],'
575 end if
576 ! Data type
577
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 46 times.
46 write(unit, '(A,I0,A)') ' "dataType": ', inits(i)%data_type, ','
578 ! Name
579 46 write(unit, '(A,A,A)') ' "name": "', &
580
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
✓ Branch 10 taken 46 times.
✗ Branch 11 not taken.
92 trim(adjustl(inits(i)%name)), '",'
581 ! Raw data (base64 encoded)
582
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
46 if(allocated(inits(i)%data))then
583
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
46 n = size(inits(i)%data)
584
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 6 taken 35 times.
✓ Branch 7 taken 11 times.
46 call encode_float32_base64_alloc(inits(i)%data, n, raw_b64)
585 46 write(unit, '(A,A,A)') ' "rawData": "', raw_b64, '"'
586 else if(allocated(inits(i)%int_data))then
587 n = size(inits(i)%int_data)
588 call encode_int64_base64_alloc(inits(i)%int_data, n, raw_b64)
589 write(unit, '(A,A,A)') ' "rawData": "', raw_b64, '"'
590 else
591 write(unit, '(A)') ' "rawData": ""'
592 end if
593
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 11 times.
57 if(i .lt. num_inits)then
594 35 write(unit, '(A)') ' },'
595 else
596 11 write(unit, '(A)') ' }'
597 end if
598 end do
599 11 write(unit, '(A)') ' ]'
600
601
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 end subroutine write_json_initialisers
602 !###############################################################################
603
604
605 !###############################################################################
606 22 subroutine write_json_tensors(unit, section_name, tensors, num_tensors)
607 !! Write input/output tensor specifications to JSON
608 implicit none
609
610 ! Arguments
611 integer, intent(in) :: unit
612 !! Output unit receiving the JSON text
613 character(*), intent(in) :: section_name
614 !! JSON section name, e.g. input or output
615 type(onnx_tensor_type), intent(in), dimension(:) :: tensors
616 !! Tensor collection to serialise
617 integer, intent(in) :: num_tensors
618 !! Number of populated tensors in the collection
619
620 ! Local variables
621 integer :: i, j
622 !! Tensor and dimension index counters
623
624
1/2
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
22 write(unit, '(A,A,A)') ' "', trim(section_name), '": ['
625
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 22 times.
49 do i = 1, num_tensors
626 27 write(unit, '(A)') ' {'
627 27 write(unit, '(A,A,A)') ' "name": "', &
628
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 27 times.
✓ Branch 10 taken 27 times.
✗ Branch 11 not taken.
54 trim(adjustl(tensors(i)%name)), '",'
629 27 write(unit, '(A)') ' "type": {'
630 27 write(unit, '(A)') ' "tensorType": {'
631
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 write(unit, '(A,I0,A)') ' "elemType": ', &
632
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
81 tensors(i)%elem_type, ','
633 27 write(unit, '(A)') ' "shape": {'
634 27 write(unit, '(A)') ' "dim": ['
635
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
27 if(allocated(tensors(i)%dims))then
636
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 6 taken 57 times.
✓ Branch 7 taken 27 times.
84 do j = 1, size(tensors(i)%dims)
637 57 write(unit, '(A)') ' {'
638
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57 times.
✓ Branch 6 taken 51 times.
✓ Branch 7 taken 6 times.
57 if(allocated(tensors(i)%dim_params))then
639
6/10
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 51 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 51 times.
✓ Branch 12 taken 24 times.
✓ Branch 13 taken 27 times.
51 if(len_trim(tensors(i)%dim_params(j)) .gt. 0)then
640 24 write(unit, '(A,A,A)') ' "dimParam": "', &
641
5/10
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
✓ Branch 16 taken 24 times.
✗ Branch 17 not taken.
48 trim(adjustl(tensors(i)%dim_params(j))), '"'
642 else
643 write(unit, '(A,"""",I0,"""")') &
644
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 ' "dimValue": ', &
645
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 27 times.
81 tensors(i)%dims(j)
646 end if
647 else
648 write(unit, '(A,"""",I0,"""")') &
649
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 ' "dimValue": ', &
650
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
18 tensors(i)%dims(j)
651 end if
652
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 27 times.
84 if(j .lt. size(tensors(i)%dims))then
653 30 write(unit, '(A)') ' },'
654 else
655 27 write(unit, '(A)') ' }'
656 end if
657 end do
658 end if
659 27 write(unit, '(A)') ' ]'
660 27 write(unit, '(A)') ' }'
661 27 write(unit, '(A)') ' }'
662 27 write(unit, '(A)') ' }'
663
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 22 times.
49 if(i .lt. num_tensors)then
664 5 write(unit, '(A)') ' },'
665 else
666 22 write(unit, '(A)') ' }'
667 end if
668 end do
669 22 write(unit, '(A,A,A)') ' ]'
670
671
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 end subroutine write_json_tensors
672 !###############################################################################
673
674
675 ! =============================================================================
676 ! Data layout utilities
677 ! =============================================================================
678
679 !###############################################################################
680 30 subroutine col_to_row_major_2d(data_in, data_out, m, n)
681 !! Convert flat column-major [m,n] to flat row-major [m,n]
682 !! Fortran stores arrays column-major; ONNX rawData expects row-major.
683 implicit none
684 integer, intent(in) :: m, n
685 real(real32), intent(in) :: data_in(m * n)
686 real(real32), intent(out) :: data_out(m * n)
687 integer :: i, j
688
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 30 times.
214 do i = 1, m
689
2/2
✓ Branch 0 taken 2807 times.
✓ Branch 1 taken 184 times.
3021 do j = 1, n
690
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2807 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2807 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2807 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2807 times.
2991 data_out((i-1)*n + j) = data_in((j-1)*m + i)
691 end do
692 end do
693 30 end subroutine col_to_row_major_2d
694 !###############################################################################
695
696
697 ! =============================================================================
698 ! Base64 encoding utilities
699 ! =============================================================================
700
701 !###############################################################################
702
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 subroutine encode_float32_base64(values, n, output)
703 !! Encode float32 array as base64 string (fixed-length output)
704 use iso_fortran_env, only: int8
705 implicit none
706 real(real32), intent(in) :: values(:)
707 integer, intent(in) :: n
708 character(256), intent(out) :: output
709
710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 character(:), allocatable :: result
711
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
12 call encode_float32_base64_alloc(values, n, result)
712
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 output = result
713
714
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 end subroutine encode_float32_base64
715 !###############################################################################
716
717
718 !###############################################################################
719
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 subroutine encode_float32_base64_alloc(values, n, output)
720 !! Encode float32 array as base64 string (allocatable output)
721 use iso_fortran_env, only: int8, int32
722 implicit none
723 real(real32), intent(in) :: values(:)
724 integer, intent(in) :: n
725 character(:), allocatable, intent(out) :: output
726
727 58 integer(int8), allocatable :: bytes(:)
728 integer(int32) :: ival
729 integer :: i, j, nbytes
730
731 58 nbytes = n * 4
732
6/12
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 58 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 58 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 58 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 58 times.
58 allocate(bytes(nbytes))
733
734
2/2
✓ Branch 0 taken 3421 times.
✓ Branch 1 taken 58 times.
3479 do i = 1, n
735
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3421 times.
3421 ival = transfer(values(i), ival)
736
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3421 times.
3421 bytes((i-1)*4 + 1) = int(iand(ival, 255), int8)
737
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3421 times.
3421 bytes((i-1)*4 + 2) = int(iand(ishft(ival, -8), 255), int8)
738
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3421 times.
3421 bytes((i-1)*4 + 3) = int(iand(ishft(ival, -16), 255), int8)
739
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3421 times.
3479 bytes((i-1)*4 + 4) = int(iand(ishft(ival, -24), 255), int8)
740 end do
741
742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 call base64_encode_bytes(bytes, nbytes, output)
743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 deallocate(bytes)
744
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 end subroutine encode_float32_base64_alloc
746 !###############################################################################
747
748
749 !###############################################################################
750
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 subroutine encode_int64_base64(values, output)
751 !! Encode integer array as base64 int64 string (fixed-length output)
752 use iso_fortran_env, only: int8, int64
753 implicit none
754 integer, intent(in) :: values(:)
755 character(256), intent(out) :: output
756
757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 integer(int8), allocatable :: bytes(:)
758 integer(int64) :: ival64
759 integer :: i, j, n, nbytes
760
761
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
37 n = size(values)
762 37 nbytes = n * 8
763
6/12
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 37 times.
37 allocate(bytes(nbytes))
764
765
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 37 times.
74 do i = 1, n
766
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
37 ival64 = int(values(i), int64)
767
2/2
✓ Branch 0 taken 296 times.
✓ Branch 1 taken 37 times.
370 do j = 0, 7
768 bytes((i-1)*8 + j + 1) = &
769
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 296 times.
✓ Branch 4 taken 296 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✓ Branch 7 taken 259 times.
333 int(iand(ishft(ival64, -j*8), int(255, int64)), int8)
770 end do
771 end do
772
773 37 call base64_encode_bytes_fixed(bytes, nbytes, output)
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 deallocate(bytes)
775
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 end subroutine encode_int64_base64
777 !###############################################################################
778
779
780 !###############################################################################
781 subroutine encode_int64_base64_alloc(values, n, output)
782 !! Encode integer array as base64 int64 string (allocatable output)
783 use iso_fortran_env, only: int8, int64
784 implicit none
785 integer, intent(in) :: values(:)
786 integer, intent(in) :: n
787 character(:), allocatable, intent(out) :: output
788
789 integer(int8), allocatable :: bytes(:)
790 integer(int64) :: ival64
791 integer :: i, j, nbytes
792
793 nbytes = n * 8
794 allocate(bytes(nbytes))
795
796 do i = 1, n
797 ival64 = int(values(i), int64)
798 do j = 0, 7
799 bytes((i-1)*8 + j + 1) = &
800 int(iand(ishft(ival64, -j*8), int(255, int64)), int8)
801 end do
802 end do
803
804 call base64_encode_bytes(bytes, nbytes, output)
805 deallocate(bytes)
806
807 end subroutine encode_int64_base64_alloc
808 !###############################################################################
809
810
811 !###############################################################################
812 subroutine encode_string_base64(str, output)
813 !! Encode a string as base64
814 use iso_fortran_env, only: int8
815 implicit none
816 character(*), intent(in) :: str
817 character(256), intent(out) :: output
818
819 4 integer(int8), allocatable :: bytes(:)
820 integer :: i, n
821
822 4 n = len_trim(str)
823
6/12
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4 times.
4 allocate(bytes(n))
824
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 do i = 1, n
825
6/12
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 17 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 17 times.
21 bytes(i) = int(ichar(str(i:i)), int8)
826 end do
827
828 4 call base64_encode_bytes_fixed(bytes, n, output)
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 deallocate(bytes)
830
831
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 end subroutine encode_string_base64
832 !###############################################################################
833
834
835 !###############################################################################
836
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 subroutine base64_encode_bytes(bytes, nbytes, output)
837 !! Core base64 encoder (allocatable output)
838 use iso_fortran_env, only: int8
839 implicit none
840 integer(int8), intent(in) :: bytes(:)
841 integer, intent(in) :: nbytes
842 character(:), allocatable, intent(out) :: output
843
844 character(64), parameter :: b64 = &
845 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
846 integer :: i, j, ngroups, out_len
847 integer :: b0, b1, b2, idx
848
849 99 ngroups = (nbytes + 2) / 3
850 99 out_len = ngroups * 4
851
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
99 allocate(character(out_len) :: output)
852
853 99 j = 1
854
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 do i = 1, nbytes, 3
855
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4694 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4694 times.
4694 b0 = iand(int(bytes(i)), 255)
856
2/2
✓ Branch 0 taken 4673 times.
✓ Branch 1 taken 21 times.
4694 if(i + 1 .le. nbytes)then
857
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4673 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4673 times.
4673 b1 = iand(int(bytes(i+1)), 255)
858 else
859 21 b1 = 0
860 end if
861
2/2
✓ Branch 0 taken 4630 times.
✓ Branch 1 taken 64 times.
4694 if(i + 2 .le. nbytes)then
862
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4630 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4630 times.
4630 b2 = iand(int(bytes(i+2)), 255)
863 else
864 64 b2 = 0
865 end if
866
867 4694 idx = ishft(b0, -2) + 1
868
8/16
✓ Branch 0 taken 4694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4694 times.
✓ Branch 5 taken 4694 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4694 times.
✓ Branch 10 taken 4694 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 4694 times.
✓ Branch 15 taken 4694 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4694 times.
4694 output(j:j) = b64(idx:idx)
869
870 4694 idx = ior(ishft(iand(b0, 3), 4), ishft(b1, -4)) + 1
871
8/16
✓ Branch 0 taken 4694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4694 times.
✓ Branch 5 taken 4694 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4694 times.
✓ Branch 10 taken 4694 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 4694 times.
✓ Branch 15 taken 4694 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4694 times.
4694 output(j+1:j+1) = b64(idx:idx)
872
873
2/2
✓ Branch 0 taken 4673 times.
✓ Branch 1 taken 21 times.
4694 if(i + 1 .le. nbytes)then
874 4673 idx = ior(ishft(iand(b1, 15), 2), ishft(b2, -6)) + 1
875
8/16
✓ Branch 0 taken 4673 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4673 times.
✓ Branch 5 taken 4673 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4673 times.
✓ Branch 10 taken 4673 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 4673 times.
✓ Branch 15 taken 4673 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4673 times.
4673 output(j+2:j+2) = b64(idx:idx)
876 else
877
4/8
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 21 times.
21 output(j+2:j+2) = '='
878 end if
879
880
2/2
✓ Branch 0 taken 4630 times.
✓ Branch 1 taken 64 times.
4694 if(i + 2 .le. nbytes)then
881 4630 idx = iand(b2, 63) + 1
882
8/16
✓ Branch 0 taken 4630 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4630 times.
✓ Branch 5 taken 4630 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4630 times.
✓ Branch 10 taken 4630 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 4630 times.
✓ Branch 15 taken 4630 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4630 times.
4630 output(j+3:j+3) = b64(idx:idx)
883 else
884
4/8
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 5 taken 64 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 64 times.
64 output(j+3:j+3) = '='
885 end if
886
887
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 4595 times.
4694 j = j + 4
888 end do
889
890 99 end subroutine base64_encode_bytes
891 !###############################################################################
892
893
894 !###############################################################################
895
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 subroutine base64_encode_bytes_fixed(bytes, nbytes, output)
896 !! Core base64 encoder (fixed-length output)
897 use iso_fortran_env, only: int8
898 implicit none
899 integer(int8), intent(in) :: bytes(:)
900 integer, intent(in) :: nbytes
901 character(256), intent(out) :: output
902
903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 character(:), allocatable :: tmp
904
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 41 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 41 times.
41 call base64_encode_bytes(bytes, nbytes, tmp)
905
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 output = tmp
906
907
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 end subroutine base64_encode_bytes_fixed
908 !###############################################################################
909
910
911 ! =============================================================================
912 ! Base64 decoding utilities
913 ! =============================================================================
914
915 !###############################################################################
916 47 subroutine base64_decode_bytes(input, bytes, nbytes)
917 !! Core base64 decoder
918 use iso_fortran_env, only: int8
919 implicit none
920 character(*), intent(in) :: input
921 integer(int8), allocatable, intent(out) :: bytes(:)
922 integer, intent(out) :: nbytes
923
924 character(64), parameter :: b64 = &
925 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
926 integer :: i, j, in_len, ngroups, pad
927 integer :: v0, v1, v2, v3
928
929 47 in_len = len_trim(input)
930 47 if(in_len .eq. 0)then
931 allocate(bytes(0))
932 nbytes = 0
933 return
934 end if
935
936 ! Count padding
937 47 pad = 0
938
6/10
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 47 times.
✓ Branch 10 taken 11 times.
✓ Branch 11 taken 36 times.
47 if(input(in_len:in_len) .eq. '=') pad = pad + 1
939
6/10
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 47 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 42 times.
47 if(in_len .ge. 2 .and. input(in_len-1:in_len-1) .eq. '=') pad = pad + 1
940
941 47 ngroups = in_len / 4
942 47 nbytes = ngroups * 3 - pad
943
6/12
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 47 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 47 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 47 times.
47 allocate(bytes(nbytes))
944
945 47 j = 1
946
1/2
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
47 do i = 1, in_len, 4
947
4/8
✓ Branch 0 taken 4288 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4288 times.
✓ Branch 5 taken 4288 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4288 times.
4288 v0 = index(b64, input(i:i)) - 1
948
4/8
✓ Branch 0 taken 4288 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4288 times.
✓ Branch 5 taken 4288 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4288 times.
4288 v1 = index(b64, input(i+1:i+1)) - 1
949
6/10
✓ Branch 0 taken 4288 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4288 times.
✓ Branch 5 taken 4288 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4288 times.
✓ Branch 10 taken 4283 times.
✓ Branch 11 taken 5 times.
4288 if(input(i+2:i+2) .ne. '=')then
950
4/8
✓ Branch 0 taken 4283 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4283 times.
✓ Branch 5 taken 4283 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4283 times.
4283 v2 = index(b64, input(i+2:i+2)) - 1
951 else
952 5 v2 = 0
953 end if
954
6/10
✓ Branch 0 taken 4288 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4288 times.
✓ Branch 5 taken 4288 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4288 times.
✓ Branch 10 taken 4277 times.
✓ Branch 11 taken 11 times.
4288 if(input(i+3:i+3) .ne. '=')then
955
4/8
✓ Branch 0 taken 4277 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4277 times.
✓ Branch 5 taken 4277 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4277 times.
4277 v3 = index(b64, input(i+3:i+3)) - 1
956 else
957 11 v3 = 0
958 end if
959
960
1/2
✓ Branch 0 taken 4288 times.
✗ Branch 1 not taken.
4288 if(j .le. nbytes) &
961
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4288 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4288 times.
4288 bytes(j) = int(ior(ishft(v0, 2), ishft(v1, -4)), int8)
962
2/2
✓ Branch 0 taken 4283 times.
✓ Branch 1 taken 5 times.
4288 if(j + 1 .le. nbytes) &
963
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4283 times.
4283 bytes(j+1) = int(ior(ishft(iand(v1, 15), 4), ishft(v2, -2)), int8)
964
2/2
✓ Branch 0 taken 4277 times.
✓ Branch 1 taken 11 times.
4288 if(j + 2 .le. nbytes) &
965
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4277 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4277 times.
4277 bytes(j+2) = int(ior(ishft(iand(v2, 3), 6), v3), int8)
966
2/2
✓ Branch 0 taken 4241 times.
✓ Branch 1 taken 47 times.
4288 j = j + 3
967 end do
968
969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 end subroutine base64_decode_bytes
970 !###############################################################################
971
972
973 !###############################################################################
974 47 subroutine decode_base64_to_float32(input, values, n)
975 !! Decode base64 string to float32 array
976 use iso_fortran_env, only: int8, int32
977 implicit none
978 character(*), intent(in) :: input
979 real(real32), allocatable, intent(out) :: values(:)
980 integer, intent(out) :: n
981
982 47 integer(int8), allocatable :: bytes(:)
983 integer :: nbytes, i
984 integer(int32) :: ival
985
986 47 call base64_decode_bytes(input, bytes, nbytes)
987 47 n = nbytes / 4
988
7/14
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 47 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 47 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 47 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 47 times.
47 allocate(values(n))
989
990
2/2
✓ Branch 0 taken 3212 times.
✓ Branch 1 taken 47 times.
3259 do i = 1, n
991 ival = ior(ior(ior( &
992 iand(int(bytes((i-1)*4 + 1), int32), 255), &
993 ishft(iand(int(bytes((i-1)*4 + 2), int32), 255), 8)), &
994 ishft(iand(int(bytes((i-1)*4 + 3), int32), 255), 16)), &
995
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 3212 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3212 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3212 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3212 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3212 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3212 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3212 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3212 times.
3212 ishft(iand(int(bytes((i-1)*4 + 4), int32), 255), 24))
996
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3212 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3212 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3212 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3212 times.
3259 values(i) = transfer(ival, values(i))
997 end do
998
999
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 deallocate(bytes)
1000
1001
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
94 end subroutine decode_base64_to_float32
1002 !###############################################################################
1003
1004
1005 !###############################################################################
1006 subroutine decode_base64_to_int64(input, values, n)
1007 !! Decode base64 string to integer array (from 8-byte int64 encoding)
1008 use iso_fortran_env, only: int8, int64
1009 implicit none
1010 character(*), intent(in) :: input
1011 integer, allocatable, intent(out) :: values(:)
1012 integer, intent(out) :: n
1013
1014 integer(int8), allocatable :: bytes(:)
1015 integer :: nbytes, i, j
1016 integer(int64) :: ival64
1017
1018 call base64_decode_bytes(input, bytes, nbytes)
1019 n = nbytes / 8
1020 allocate(values(n))
1021
1022 do i = 1, n
1023 ival64 = 0
1024 do j = 0, 7
1025 ival64 = ior(ival64, &
1026 ishft(iand(int(bytes((i-1)*8 + j + 1), int64), &
1027 int(255, int64)), j*8))
1028 end do
1029 values(i) = int(ival64)
1030 end do
1031
1032 deallocate(bytes)
1033
1034 end subroutine decode_base64_to_int64
1035 !###############################################################################
1036
1037
1038 ! =============================================================================
1039 ! Reverse data layout utility
1040 ! =============================================================================
1041
1042 !###############################################################################
1043 37 subroutine row_to_col_major_2d(data_in, data_out, m, n)
1044 !! Convert flat row-major [m,n] to flat column-major [m,n]
1045 !! Inverse of col_to_row_major_2d.
1046 implicit none
1047 integer, intent(in) :: m, n
1048 real(real32), intent(in) :: data_in(m * n)
1049 real(real32), intent(out) :: data_out(m * n)
1050 integer :: i, j
1051
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 37 times.
222 do i = 1, m
1052
2/2
✓ Branch 0 taken 2413 times.
✓ Branch 1 taken 185 times.
2635 do j = 1, n
1053
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2413 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2413 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2413 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2413 times.
2598 data_out((j-1)*m + i) = data_in((i-1)*n + j)
1054 end do
1055 end do
1056 37 end subroutine row_to_col_major_2d
1057 !###############################################################################
1058
1059
1060 !###############################################################################
1061 5 subroutine parse_space_separated_ints(str, values)
1062 !! Parse space-separated integers from a string into an allocatable array
1063 implicit none
1064 character(*), intent(in) :: str
1065 integer, allocatable, intent(out) :: values(:)
1066
1067 integer :: i, stat, ival
1068 character(256) :: work
1069 character(32) :: token
1070
1071
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 work = trim(adjustl(str))
1072
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
5 allocate(values(0))
1073
1074
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 do while(len_trim(work) .gt. 0)
1075
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 i = index(trim(work), ' ')
1076
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if(i .eq. 0)then
1077
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 token = trim(work)
1078 5 work = ''
1079 else
1080
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
7 token = work(1:i-1)
1081
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
7 work = adjustl(work(i+1:))
1082 end if
1083 12 read(token, *, iostat=stat) ival
1084
16/26
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✓ Branch 17 taken 9 times.
✓ Branch 18 taken 12 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 12 times.
✓ Branch 21 taken 21 times.
✓ Branch 22 taken 12 times.
✓ Branch 23 taken 12 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 12 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 12 times.
✓ Branch 29 taken 21 times.
✓ Branch 30 taken 12 times.
63 if(stat .eq. 0) values = [values, ival]
1085 end do
1086
1087 5 end subroutine parse_space_separated_ints
1088 !###############################################################################
1089
1090
1091 !###############################################################################
1092 11 function onnx_to_athena_activation(optype) result(name)
1093 !! Convert an ONNX activation op_type string to the Athena activation name
1094 implicit none
1095 character(*), intent(in) :: optype
1096 character(64) :: name
1097
1098 11 select case(trim(optype))
1099 case('LeakyRelu')
1100 name = 'leaky_relu'
1101 case('Relu')
1102 5 name = 'relu'
1103 case('Sigmoid')
1104 2 name = 'sigmoid'
1105 case('Softmax')
1106 1 name = 'softmax'
1107 case('Tanh')
1108 2 name = 'tanh'
1109 case('Selu')
1110 name = 'selu'
1111 case('Swish')
1112 1 name = 'swish'
1113 case default
1114
6/14
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
22 name = to_lower(trim(optype))
1115 end select
1116
1117 11 end function onnx_to_athena_activation
1118 !###############################################################################
1119
1120
1121 end module athena__onnx_utils
1122