simd 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f0bff704f3580fee55205c32ada6a1844dde4ae
4
- data.tar.gz: 9e4f9d097fa20a349b77279535d39ea695a881a4
3
+ metadata.gz: 3acc0dcd98951246c84b35036f47dedd69d798cb
4
+ data.tar.gz: 323dbca8597e5993d0bd48ebb8805febdf064c47
5
5
  SHA512:
6
- metadata.gz: ccaa110b5ff7708c5e14dd5355f4361544832b412c2d150e9849f8106c55e1183252cbe540163941b65968037369b8618b5e66c9267e75807553aa2e7e8ccda5
7
- data.tar.gz: e107fe3e242f6baa6d93ab6edf2886f58499d70fd690f6f1c72d7bff165932ce953026d480b0ac3a41c5e35d1ec4dc8b96c19d38d19857f0fdc8c7e759c3fa44
6
+ metadata.gz: e05f61501a47ad89bf55a6a25fcda70add8aa004701336e0543c4421ca0b4a9628aab30281e0aa9c30bb79a994fad2152c7da853dc6989adea400a79c9ada05c
7
+ data.tar.gz: 45f06b3ead4a140d992f34c2135724f649143e58035945e9e8f8de9e0595b8fda54538cab233a494ddcb0eb1e6e1a6d0f5948084b6e29e91d461c34d901eb8ef
@@ -5,4 +5,5 @@ void Init_simd()
5
5
  {
6
6
  SIMD = rb_define_module("SIMD");
7
7
  Init_SIMD_FloatArray(SIMD);
8
+ Init_SIMD_SmallFloatArray(SIMD);
8
9
  }
@@ -2,3 +2,4 @@
2
2
 
3
3
  void Init_simd();
4
4
  void Init_SIMD_FloatArray(VALUE parent);
5
+ void Init_SIMD_SmallFloatArray(VALUE parent);
@@ -0,0 +1,76 @@
1
+ #include "simd_common.h"
2
+
3
+ /* Internal: Allocate memory for the vector container. */
4
+ VALUE allocate(VALUE klass)
5
+ {
6
+ vector_t *vector = malloc(sizeof(vector_t));
7
+ if(vector == NULL)
8
+ {
9
+ rb_raise(rb_eNoMemError, "Unable to allocate memory");
10
+ }
11
+
12
+ vector->data = NULL; /* Avoid potentially freeing unitialized memory. */
13
+ return(Data_Wrap_Struct(klass, NULL, deallocate, vector));
14
+ }
15
+
16
+ /* Internal: Free memory from the vector container and the data array. */
17
+ void deallocate(vector_t *vector)
18
+ {
19
+ if(vector)
20
+ {
21
+ if(vector->data)
22
+ {
23
+ free(vector->data);
24
+ }
25
+ free(vector);
26
+ }
27
+ }
28
+
29
+ /* Public: Return the number of elements in the Array. */
30
+ VALUE method_length(VALUE self)
31
+ {
32
+ vector_t *vector;
33
+ Data_Get_Struct(self, vector_t, vector);
34
+
35
+ return(INT2NUM(vector->len));
36
+ }
37
+
38
+ /* Internal: Allocate memory for the data array. */
39
+ void *internal_allocate_vector_array(unsigned long count, size_t size)
40
+ {
41
+ unsigned int modulo = 16 / size;
42
+ void *vector = malloc(((count + (count % modulo)) / modulo + 1) * size);
43
+ if(vector == NULL)
44
+ {
45
+ rb_raise(rb_eNoMemError, "Unable to allocate memory");
46
+ }
47
+
48
+ return(vector);
49
+ }
50
+
51
+ /* Internal: Determine if two arrays can be acted upon, by being of equal
52
+ * lengths or with the operand's length being a multiple of the data array's. */
53
+ int internal_align_vectors(unsigned long v1, unsigned long v2, unsigned int modulo)
54
+ {
55
+ if((v1 % modulo) != (v2 % modulo))
56
+ {
57
+ rb_raise(rb_eArgError, "Both Vectors must be of even or odd length.");
58
+ }
59
+
60
+ if(v1 == v2)
61
+ {
62
+ return(0);
63
+ }
64
+ if(v2 == modulo)
65
+ {
66
+ return(1);
67
+ }
68
+ if(v1 % v2 == 0 && v2 % modulo == 0)
69
+ {
70
+ return(2);
71
+ }
72
+
73
+ rb_raise(rb_eArgError, "Vector lengths misaligned.");
74
+ /* Never reached */
75
+ return(-1);
76
+ }
@@ -0,0 +1,12 @@
1
+ #pragma once
2
+
3
+ #include "ruby.h"
4
+ #include "simd_types.h"
5
+
6
+ VALUE allocate(VALUE klass);
7
+ void deallocate(vector_t *vector);
8
+
9
+ VALUE method_length(VALUE self);
10
+
11
+ void *internal_allocate_vector_array(unsigned long count, size_t size);
12
+ int internal_align_vectors(unsigned long v1, unsigned long v2, unsigned int modulo);
@@ -16,59 +16,37 @@ void Init_SIMD_FloatArray(VALUE parent)
16
16
  rb_define_method(SIMD_FloatArray, "to_a", method_to_a, 0);
17
17
  }
18
18
 
19
- /* Internal: Allocate memory for the vector container. */
20
- static VALUE allocate(VALUE klass)
21
- {
22
- d2v_container *vector = malloc(sizeof(d2v_container));
23
- if(vector == NULL)
24
- {
25
- rb_raise(rb_eNoMemError, "Unable to allocate memory");
26
- }
27
-
28
- vector->data = NULL; /* Avoid potentially freeing unitialized memory. */
29
- return(Data_Wrap_Struct(klass, NULL, deallocate, vector));
30
- }
31
-
32
- /* Internal: Free memory from the vector container and the data array. */
33
- static void deallocate(d2v_container *vector)
34
- {
35
- if(vector)
36
- {
37
- if(vector->data)
38
- {
39
- free(vector->data);
40
- }
41
- free(vector);
42
- }
43
- }
44
-
45
19
  /* Public: Initialize the FloatArray object given a Ruby Array of values
46
20
  * which can be cast to a double. */
47
21
  static VALUE method_initialize(VALUE self, VALUE rb_array)
48
22
  {
49
- d2v_container *vector;
23
+ vector_t *vector;
24
+ d2v_t *data;
50
25
  unsigned long n,m,i;
51
26
 
52
27
  Check_Type(rb_array, T_ARRAY);
53
- Data_Get_Struct(self, d2v_container, vector);
28
+ Data_Get_Struct(self, vector_t, vector);
54
29
 
55
30
  vector->len = n = RARRAY_LEN(rb_array);
56
31
 
57
32
  if(vector->len < 2)
58
33
  {
59
- rb_raise(rb_eArgError, "Vectors must be at least 2 long");
34
+ rb_raise(rb_eArgError, "Vectors must be at least 4 long");
60
35
  }
61
36
 
62
- vector->data = internal_allocate_vector_array(vector->len);
37
+ vector->data = internal_allocate_vector_array(vector->len, sizeof(d2v_t));
63
38
 
64
- for(i = 0; i < n; i++)
65
- vector->data[i/2].f[i%2] = NUM2DBL(rb_ary_entry(rb_array, i));
39
+ data = (d2v_t *)vector->data;
40
+ for(i = 0; i < vector->len; i++)
41
+ {
42
+ data[i/2].f[i%2] = NUM2DBL(rb_ary_entry(rb_array, i));
43
+ }
66
44
 
67
45
  /* If the array is an odd number of elements, set the final element to 1 */
68
46
  m = n + (n % 2);
69
- if(n < m)
47
+ for(i = n % 4; i > 0; i--)
70
48
  {
71
- vector->data[m/2].f[1] = 1.0;
49
+ data[m/2].f[1] = 1.0;
72
50
  }
73
51
 
74
52
  return(self);
@@ -102,26 +80,19 @@ static VALUE method_subtract(VALUE self, VALUE obj)
102
80
  return(internal_apply_operation(self, obj, func_subtract));
103
81
  }
104
82
 
105
- /* Public: Return the number of elements in the Array. */
106
- static VALUE method_length(VALUE self)
107
- {
108
- d2v_container *vector;
109
- Data_Get_Struct(self, d2v_container, vector);
110
-
111
- return(INT2NUM(vector->len));
112
- }
113
-
114
83
  /* Public: Return a Ruby Array containing the doubles within the data array. */
115
84
  static VALUE method_to_a(VALUE self)
116
85
  {
117
86
  unsigned long i;
118
- d2v_container *vector;
87
+ vector_t *vector;
88
+ d2v_t *data;
119
89
  VALUE rb_array = rb_ary_new();
120
90
 
121
- Data_Get_Struct(self, d2v_container, vector);
91
+ Data_Get_Struct(self, vector_t, vector);
92
+ data = (d2v_t *)vector->data;
122
93
  for(i = 0; i < vector->len; i++)
123
94
  {
124
- rb_ary_store(rb_array, i, DBL2NUM(vector->data[i/2].f[i%2]));
95
+ rb_ary_store(rb_array, i, DBL2NUM(data[i/2].f[i%2]));
125
96
  }
126
97
 
127
98
  return(rb_array);
@@ -133,83 +104,50 @@ static VALUE internal_apply_operation(VALUE self, VALUE obj, b_operation func)
133
104
  {
134
105
  unsigned long size, i;
135
106
  int align;
136
- d2v_container *v1, *v2, *r;
107
+ vector_t *v1, *v2, *rv;
108
+ d2v_t *d1, *d2, *r;
137
109
  VALUE result_obj = allocate(SIMD_FloatArray);
138
110
 
139
- Data_Get_Struct(self, d2v_container, v1);
140
- Data_Get_Struct(obj, d2v_container, v2);
141
- Data_Get_Struct(result_obj, d2v_container, r);
111
+ Data_Get_Struct(self, vector_t, v1);
112
+ Data_Get_Struct(obj, vector_t, v2);
113
+ Data_Get_Struct(result_obj, vector_t, rv);
114
+ rv->data = internal_allocate_vector_array(v1->len, sizeof(d2v_t));
142
115
 
143
- align = internal_align_vectors(v1->len, v2->len);
116
+ align = internal_align_vectors(v1->len, v2->len, 2);
144
117
 
145
- /* Ensure that size will be the result of ceil(len / 2.0) */
118
+ /* Ensure that size will be the result of ceil(len / 4.0) */
146
119
  size = (v1->len + 1) / 2;
147
- r->data = internal_allocate_vector_array(v1->len);
148
- r->len = v1->len;
120
+
121
+ d1 = (d2v_t *)v1->data;
122
+ d2 = (d2v_t *)v2->data;
123
+ r = (d2v_t *)rv->data;
124
+
125
+ rv->len = v1->len;
149
126
 
150
127
  switch(align)
151
128
  {
152
129
  case 0: /* Same size arrays */
153
130
  for(i = 0; i < size; i++)
154
131
  {
155
- r->data[i].v = func(v1->data[i].v, v2->data[i].v);
132
+ r[i].v = func(d1[i].v, d2[i].v);
156
133
  }
157
134
  break;
158
135
  case 1: /* Operand is exactly 2 long (size of 1 sse register) */
159
136
  for(i = 0; i < size; i++)
160
137
  {
161
- r->data[i].v = func(v1->data[i].v, v2->data[0].v);
138
+ r[i].v = func(d1[i].v, d2[0].v);
162
139
  }
163
140
  break;
164
141
  default: /* Self is a multiple of operand's length long */
165
142
  for(i = 0; i < size; i++)
166
143
  {
167
- r->data[i].v = func(v1->data[i].v, v2->data[i % v2->len].v);
144
+ r[i].v = func(d1[i].v, d2[i % v2->len].v);
168
145
  }
169
146
  }
170
147
 
171
148
  return(result_obj);
172
149
  }
173
150
 
174
- /* Internal: Allocate memory for the data array. */
175
- static d2v_t *internal_allocate_vector_array(unsigned long size)
176
- {
177
- d2v_t *vector = malloc(((size + (size % 2)) / 2 + 1) * sizeof(d2v_t));
178
- if(vector == NULL)
179
- {
180
- rb_raise(rb_eNoMemError, "Unable to allocate memory");
181
- }
182
-
183
- return(vector);
184
- }
185
-
186
- /* Internal: Determine if two arrays can be acted upon, by being of equal
187
- * lengths or with the operand's length being a multiple of the data array's. */
188
- static int internal_align_vectors(unsigned long v1, unsigned long v2)
189
- {
190
- if((v1 % 2) != (v2 % 2))
191
- {
192
- rb_raise(rb_eArgError, "Both Vectors must be of even or odd length.");
193
- }
194
-
195
- if(v1 == v2)
196
- {
197
- return(0);
198
- }
199
- if(v2 == 2)
200
- {
201
- return(1);
202
- }
203
- if(v1 % v2 == 0)
204
- {
205
- return(2);
206
- }
207
-
208
- rb_raise(rb_eArgError, "Vector length must be evenly divisible by operand.");
209
- /* Never reached */
210
- return(-1);
211
- }
212
-
213
151
  /* Function: Multiply two vectors. */
214
152
  static d2v func_multiply(d2v v1, d2v v2)
215
153
  {
@@ -1,19 +1,22 @@
1
1
  #include "ruby.h"
2
- #include "simd_types.h"
2
+ #include "simd_common.h"
3
3
 
4
+ /*
4
5
  static VALUE allocate(VALUE klass);
5
6
  static void deallocate(d2v_container *floatarray);
7
+ */
6
8
 
7
9
  static VALUE method_initialize(VALUE self, VALUE rb_array);
8
10
  static VALUE method_multiply(VALUE self, VALUE obj);
9
11
  static VALUE method_divide(VALUE self, VALUE obj);
10
12
  static VALUE method_add(VALUE self, VALUE obj);
11
13
  static VALUE method_subtract(VALUE self, VALUE obj);
12
- static VALUE method_length(VALUE self);
13
14
  static VALUE method_to_a(VALUE self);
14
15
 
16
+ /*
15
17
  static d2v_t *internal_allocate_vector_array(unsigned long size);
16
18
  static int internal_align_vectors(unsigned long v1, unsigned long v2);
19
+ */
17
20
  static VALUE internal_apply_operation(VALUE self, VALUE obj, b_operation func);
18
21
 
19
22
  static d2v func_multiply(d2v v1, d2v v2);
@@ -0,0 +1,173 @@
1
+ #include "simd_smallfloatarray.h"
2
+
3
+ VALUE SIMD_SmallFloatArray = Qnil;
4
+
5
+ /* Internal: Create the SIMD::FloatArray class. */
6
+ void Init_SIMD_SmallFloatArray(VALUE parent)
7
+ {
8
+ SIMD_SmallFloatArray = rb_define_class_under(parent, "SmallFloatArray", rb_cObject);
9
+ rb_define_alloc_func(SIMD_SmallFloatArray, allocate);
10
+ rb_define_method(SIMD_SmallFloatArray, "initialize", method_initialize, 1);
11
+ rb_define_method(SIMD_SmallFloatArray, "*", method_multiply, 1);
12
+ rb_define_method(SIMD_SmallFloatArray, "/", method_divide, 1);
13
+ rb_define_method(SIMD_SmallFloatArray, "+", method_add, 1);
14
+ rb_define_method(SIMD_SmallFloatArray, "-", method_subtract, 1);
15
+ rb_define_method(SIMD_SmallFloatArray, "length", method_length, 0);
16
+ rb_define_method(SIMD_SmallFloatArray, "to_a", method_to_a, 0);
17
+ }
18
+
19
+ /* Public: Initialize the FloatArray object given a Ruby Array of values
20
+ * which can be cast to a double. */
21
+ static VALUE method_initialize(VALUE self, VALUE rb_array)
22
+ {
23
+ vector_t *vector;
24
+ f4v_t *data;
25
+ unsigned long n,m,i;
26
+
27
+ Check_Type(rb_array, T_ARRAY);
28
+ Data_Get_Struct(self, vector_t, vector);
29
+
30
+ vector->len = n = RARRAY_LEN(rb_array);
31
+
32
+ if(vector->len < 4)
33
+ {
34
+ rb_raise(rb_eArgError, "Vectors must be at least 4 long");
35
+ }
36
+
37
+ vector->data = internal_allocate_vector_array(vector->len, sizeof(f4v_t));
38
+
39
+ data = (f4v_t *)vector->data;
40
+ for(i = 0; i < vector->len; i++)
41
+ {
42
+ data[i/4].f[i%4] = (float)NUM2DBL(rb_ary_entry(rb_array, i));
43
+ }
44
+
45
+ /* If the array is an odd number of elements, set the final element to 1 */
46
+ m = n + (n % 4);
47
+ for(i = n % 4; i > 0; i--)
48
+ {
49
+ data[m/4].f[i] = 1.0;
50
+ }
51
+
52
+ return(self);
53
+ }
54
+
55
+ /* Public: Multiply values contained in the data array with those contained in
56
+ * another FloatArray object, returning a new FloatArray. */
57
+ static VALUE method_multiply(VALUE self, VALUE obj)
58
+ {
59
+ return(internal_apply_operation(self, obj, func_multiply));
60
+ }
61
+
62
+ /* Public: Divide values contained in the data array by those contained in
63
+ * another FloatArray object, returning a new FloatArray. */
64
+ static VALUE method_divide(VALUE self, VALUE obj)
65
+ {
66
+ return(internal_apply_operation(self, obj, func_divide));
67
+ }
68
+
69
+ /* Public: add values contained in the data array with those contained in
70
+ * another FloatArray object, returning a new FloatArray. */
71
+ static VALUE method_add(VALUE self, VALUE obj)
72
+ {
73
+ return(internal_apply_operation(self, obj, func_add));
74
+ }
75
+
76
+ /* Public: Subtract values contained in another FloatArray object from those
77
+ * contained in the current data array object, returning a new FloatArray. */
78
+ static VALUE method_subtract(VALUE self, VALUE obj)
79
+ {
80
+ return(internal_apply_operation(self, obj, func_subtract));
81
+ }
82
+
83
+ /* Public: Return a Ruby Array containing the doubles within the data array. */
84
+ static VALUE method_to_a(VALUE self)
85
+ {
86
+ unsigned long i;
87
+ vector_t *vector;
88
+ f4v_t *data;
89
+ VALUE rb_array = rb_ary_new();
90
+
91
+ Data_Get_Struct(self, vector_t, vector);
92
+ data = (f4v_t *)vector->data;
93
+ for(i = 0; i < vector->len; i++)
94
+ {
95
+ rb_ary_store(rb_array, i, DBL2NUM(data[i/4].f[i%4]));
96
+ }
97
+
98
+ return(rb_array);
99
+ }
100
+
101
+ /* Internal: Given another FloatArray object, perform an action specified via a
102
+ * function pointer against both. */
103
+ static VALUE internal_apply_operation(VALUE self, VALUE obj, bf_operation func)
104
+ {
105
+ unsigned long size, i;
106
+ int align;
107
+ vector_t *v1, *v2, *rv;
108
+ f4v_t *d1, *d2, *r;
109
+ VALUE result_obj = allocate(SIMD_SmallFloatArray);
110
+
111
+ Data_Get_Struct(self, vector_t, v1);
112
+ Data_Get_Struct(obj, vector_t, v2);
113
+ Data_Get_Struct(result_obj, vector_t, rv);
114
+ rv->data = internal_allocate_vector_array(v1->len, sizeof(f4v_t));
115
+
116
+ align = internal_align_vectors(v1->len, v2->len, 4);
117
+
118
+ /* Ensure that size will be the result of ceil(len / 4.0) */
119
+ size = (v1->len + 3) / 4;
120
+
121
+ d1 = (f4v_t *)v1->data;
122
+ d2 = (f4v_t *)v2->data;
123
+ r = (f4v_t *)rv->data;
124
+
125
+ rv->len = v1->len;
126
+
127
+ switch(align)
128
+ {
129
+ case 0: /* Same size arrays */
130
+ for(i = 0; i < size; i++)
131
+ {
132
+ r[i].v = func(d1[i].v, d2[i].v);
133
+ }
134
+ break;
135
+ case 1: /* Operand is exactly 4 long (size of 1 sse register) */
136
+ for(i = 0; i < size; i++)
137
+ {
138
+ r[i].v = func(d1[i].v, d2[0].v);
139
+ }
140
+ break;
141
+ default: /* Self is a multiple of operand's length long */
142
+ for(i = 0; i < size; i++)
143
+ {
144
+ r[i].v = func(d1[i].v, d2[i % v2->len].v);
145
+ }
146
+ }
147
+
148
+ return(result_obj);
149
+ }
150
+
151
+ /* Function: Multiply two vectors. */
152
+ static f4v func_multiply(f4v v1, f4v v2)
153
+ {
154
+ return(v1 * v2);
155
+ }
156
+
157
+ /* Function: Divide two vectors. */
158
+ static f4v func_divide(f4v v1, f4v v2)
159
+ {
160
+ return(v1 / v2);
161
+ }
162
+
163
+ /* Function: Add two vectors. */
164
+ static f4v func_add(f4v v1, f4v v2)
165
+ {
166
+ return(v1 + v2);
167
+ }
168
+
169
+ /* Function: Subtract two vectors. */
170
+ static f4v func_subtract(f4v v1, f4v v2)
171
+ {
172
+ return(v1 - v2);
173
+ }
@@ -0,0 +1,25 @@
1
+ #include "ruby.h"
2
+ #include "simd_common.h"
3
+
4
+ /*
5
+ static VALUE allocate(VALUE klass);
6
+ static void deallocate(vector_t *vector);
7
+ */
8
+
9
+ static VALUE method_initialize(VALUE self, VALUE rb_array);
10
+ static VALUE method_multiply(VALUE self, VALUE obj);
11
+ static VALUE method_divide(VALUE self, VALUE obj);
12
+ static VALUE method_add(VALUE self, VALUE obj);
13
+ static VALUE method_subtract(VALUE self, VALUE obj);
14
+ static VALUE method_to_a(VALUE self);
15
+
16
+ /*
17
+ static f4v_t *internal_allocate_vector_array(unsigned long size);
18
+ static int internal_align_vectors(unsigned long v1, unsigned long v2);
19
+ */
20
+ static VALUE internal_apply_operation(VALUE self, VALUE obj, bf_operation func);
21
+
22
+ static f4v func_multiply(f4v v1, f4v v2);
23
+ static f4v func_divide(f4v v1, f4v v2);
24
+ static f4v func_add(f4v v1, f4v v2);
25
+ static f4v func_subtract(f4v v1, f4v v2);
@@ -1,3 +1,5 @@
1
+ #pragma once
2
+
1
3
  /*
2
4
  * Types for FloatArray
3
5
  *
@@ -11,10 +13,25 @@ typedef union d2v_t
11
13
  double f[2];
12
14
  } d2v_t;
13
15
 
14
- typedef struct d2v_container
16
+ /*
17
+ * Types for SmallFloatArray
18
+ *
19
+ * Since ruby internally uses doubles for the Float type, SIMD::SmallFloatArray
20
+ * provides reduced-size floats for faster operation when it's known that the
21
+ * lack of precision and range will not be a detriment.
22
+ */
23
+ typedef float __attribute__ ((vector_size (16))) f4v;
24
+ typedef union f4v_t
25
+ {
26
+ f4v v;
27
+ float f[4];
28
+ } f4v_t;
29
+
30
+ typedef struct vector_t
15
31
  {
16
- d2v_t *data;
32
+ void *data;
17
33
  unsigned long len;
18
- } d2v_container;
34
+ } vector_t;
19
35
 
20
36
  typedef d2v (*b_operation)(d2v v1, d2v v2);
37
+ typedef f4v (*bf_operation)(f4v v1, f4v v2);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina Wuest
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-11 00:00:00.000000000 Z
11
+ date: 2014-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -34,8 +34,12 @@ files:
34
34
  - ext/simd/extconf.rb
35
35
  - ext/simd/simd.c
36
36
  - ext/simd/simd.h
37
+ - ext/simd/simd_common.c
38
+ - ext/simd/simd_common.h
37
39
  - ext/simd/simd_floatarray.c
38
40
  - ext/simd/simd_floatarray.h
41
+ - ext/simd/simd_smallfloatarray.c
42
+ - ext/simd/simd_smallfloatarray.h
39
43
  - ext/simd/simd_types.h
40
44
  homepage: https://gitlab.com/wuest/simd-ruby
41
45
  licenses: []