1 /// Copyright: Copyright (c) 2017-2020 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module tests.aggregates;
5 
6 import std.stdio;
7 import tester;
8 
9 Test[] aggregatesTests() { return collectTests!(tests.aggregates)(); }
10 
11 
12 @TestInfo(&tester64)
13 immutable aggr64 = q{--- aggr64
14 	// Test structs
15 	struct Big {
16 		i64 a;
17 		i64 b;
18 	}
19 	struct Big2
20 	{
21 		u8 r;
22 		u8 g;
23 		u8 b;
24 		u8 a;
25 		u8 r2;
26 		u8 g2;
27 		u8 b2;
28 		u8 a2;
29 	}
30 	struct Small {
31 		i32 a;
32 		i32 b;
33 	}
34 	struct Small3 {
35 		i32 a;
36 		i16 b;
37 		i16 c;
38 	}
39 	struct Micro {
40 		u8 a;
41 		u8 b;
42 	}
43 	struct Mini {
44 		Micro a;
45 		Micro b;
46 	}
47 	struct Single_u8  { u8  a; }
48 	struct Single_u16 { u16 a; }
49 	struct Single_u32 { u32 a; }
50 	struct Single_u64 { u64 a; }
51 	// constructor is a function (expression) that returns struct type
52 	// can compile it into create_aggregate instruction
53 	// - default initialization of members
54 	// + return result (by ptr)
55 	Small returnSmallStruct() {
56 		return Small(10, 42);
57 	}
58 	Single_u8  return_Single_u8_const () { return Single_u8 (42); }
59 	Single_u16 return_Single_u16_const() { return Single_u16(42); }
60 	Single_u32 return_Single_u32_const() { return Single_u32(42); }
61 	Single_u64 return_Single_u64_const() { return Single_u64(42); }
62 
63 	Single_u8  return_Single_u8 (u8  val) { return Single_u8 (val); }
64 	Single_u16 return_Single_u16(u16 val) { return Single_u16(val); }
65 	Single_u32 return_Single_u32(u32 val) { return Single_u32(val); }
66 	Single_u64 return_Single_u64(u64 val) { return Single_u64(val); }
67 	// return aggregate by storing into hidden first parameter
68 	Big returnBigStruct() {
69 		return Big(10, 42);
70 	}
71 	Big returnBigStruct2() {
72 		Big res = Big(10, 42);
73 		return res;
74 	}
75 	Small buildSmallStruct(i32 a, i32 b) {
76 		return Small(a, b);
77 	}
78 	Small3 buildSmall3Struct(i32 a, i16 b, i16 c) {
79 		return Small3(a, b, c);
80 	}
81 	Mini buildMiniStruct(u8 a, u8 b, u8 c, u8 d) {
82 		return Mini(Micro(a, b), Micro(c, d));
83 	}
84 	Big2 buildBig2Struct(u8 r, u8 g, u8 b, u8 a) {
85 		return Big2(r, 42, b, 42, 42, g, 42, a);
86 	}
87 	Mini returnMiniStruct() {
88 		return Mini(Micro(10, 42), Micro(120, 3));
89 	}
90 	// - pass as arg (fits in register)
91 	Small passArgSmallStruct() {
92 		return receiveArgSmallStruct(Small(10, 42));
93 	}
94 	Small passArgSmallStructVar(i32 x, i32 y) {
95 		return receiveArgSmallStruct(Small(x+1, y+1));
96 	}
97 	// - pass as arg (fits in register, pushed)
98 	Small passArgSmallStructPush() {
99 		return receiveArgSmallStructPush(1,2,3,4,Small(10, 42));
100 	}
101 	// - pass as arg (by ptr)
102 	Big passArgBigStruct() {
103 		return receiveArgBigStruct(Big(10, 42));
104 	}
105 	// - pass as arg (by ptr, pushed)
106 	Big passArgBigStructPush() {
107 		return receiveArgBigStructPush(1,2,3,4,Big(10, 42));
108 	}
109 	// - receive parameter (fits in register)
110 	Small receiveArgSmallStruct(Small arg) { return arg; }
111 	Small receiveArgSmallStructPush(i32,i32,i32,i32,Small arg) { return arg; }
112 	// - receive parameter (by ptr)
113 	Big receiveArgBigStruct(Big arg) { return arg; }
114 	Big receiveArgBigStructPush(i32,i32,i32,i32,Big arg) { return arg; }
115 	// - pass member as arg (by ptr)
116 	// - pass member as arg (fits in register)
117 	// - receive result (fits in register)
118 	// - receive result (by ptr)
119 	// - return result (fits in register)
120 	// - store in memory
121 	// - load from memory
122 	// - set member
123 	// - get member
124 	// - get member ptr
125 	// - get ptr
126 };
127 void tester64(ref TestContext ctx) {
128 	static struct Big {
129 		long a;
130 		long b;
131 	}
132 	static struct Big2
133 	{
134 		ubyte r;
135 		ubyte g;
136 		ubyte b;
137 		ubyte a;
138 		ubyte r2;
139 		ubyte g2;
140 		ubyte b2;
141 		ubyte a2;
142 	}
143 	static struct Small {
144 		int a;
145 		int b;
146 	}
147 	static struct Small3 {
148 		int a;
149 		short b;
150 		short c;
151 	}
152 	static struct Micro {
153 		ubyte a;
154 		ubyte b;
155 	}
156 	static struct Mini {
157 		Micro a;
158 		Micro b;
159 	}
160 	static struct Single_u8  { ubyte  a; }
161 	static struct Single_u16 { ushort a; }
162 	static struct Single_u32 { uint   a; }
163 	static struct Single_u64 { ulong  a; }
164 
165 	auto returnSmallStruct = ctx.getFunctionPtr!(Small)("returnSmallStruct");
166 	assert(returnSmallStruct() == Small(10, 42));
167 
168 	auto return_Single_u8_const = ctx.getFunctionPtr!(Single_u8)("return_Single_u8_const");
169 	assert(return_Single_u8_const() == Single_u8(42));
170 	auto return_Single_u16_const = ctx.getFunctionPtr!(Single_u16)("return_Single_u16_const");
171 	assert(return_Single_u16_const() == Single_u16(42));
172 	auto return_Single_u32_const = ctx.getFunctionPtr!(Single_u32)("return_Single_u32_const");
173 	assert(return_Single_u32_const() == Single_u32(42));
174 	auto return_Single_u64_const = ctx.getFunctionPtr!(Single_u64)("return_Single_u64_const");
175 	assert(return_Single_u64_const() == Single_u64(42));
176 
177 	auto return_Single_u8 = ctx.getFunctionPtr!(Single_u8, ubyte)("return_Single_u8");
178 	assert(return_Single_u8(42) == Single_u8(42));
179 	auto return_Single_u16 = ctx.getFunctionPtr!(Single_u16, ushort)("return_Single_u16");
180 	assert(return_Single_u16(42) == Single_u16(42));
181 	auto return_Single_u32 = ctx.getFunctionPtr!(Single_u32, uint)("return_Single_u32");
182 	assert(return_Single_u32(42) == Single_u32(42));
183 	auto return_Single_u64 = ctx.getFunctionPtr!(Single_u64, ulong)("return_Single_u64");
184 	assert(return_Single_u64(42) == Single_u64(42));
185 
186 	auto returnBigStruct = ctx.getFunctionPtr!(Big)("returnBigStruct");
187 	assert(returnBigStruct() == Big(10, 42));
188 
189 	auto returnBigStruct2 = ctx.getFunctionPtr!(Big)("returnBigStruct2");
190 	assert(returnBigStruct2() == Big(10, 42));
191 
192 	auto passArgBigStruct = ctx.getFunctionPtr!(Big)("passArgBigStruct");
193 	assert(passArgBigStruct() == Big(10, 42));
194 
195 	auto passArgBigStructPush = ctx.getFunctionPtr!(Big)("passArgBigStructPush");
196 	assert(passArgBigStructPush() == Big(10, 42));
197 
198 	auto passArgSmallStruct = ctx.getFunctionPtr!(Small)("passArgSmallStruct");
199 	assert(passArgSmallStruct() == Small(10, 42));
200 
201 	auto passArgSmallStructVar = ctx.getFunctionPtr!(Small, int, int)("passArgSmallStructVar");
202 	assert(passArgSmallStructVar(10, 42) == Small(11, 43));
203 
204 	auto passArgSmallStructPush = ctx.getFunctionPtr!(Small)("passArgSmallStructPush");
205 	assert(passArgSmallStructPush() == Small(10, 42));
206 
207 	auto buildSmallStruct = ctx.getFunctionPtr!(Small, int, int)("buildSmallStruct");
208 	assert(buildSmallStruct(10, 42) == Small(10, 42));
209 
210 	auto buildSmall3Struct = ctx.getFunctionPtr!(Small3, int, short, short)("buildSmall3Struct");
211 	assert(buildSmall3Struct(10, 42, 120) == Small3(10, 42, 120));
212 
213 	auto buildMiniStruct = ctx.getFunctionPtr!(Mini, ubyte, ubyte, ubyte, ubyte)("buildMiniStruct");
214 	assert(buildMiniStruct(10, 42, 120, 3) == Mini(Micro(10, 42), Micro(120, 3)));
215 
216 	auto buildBig2Struct = ctx.getFunctionPtr!(Big2, ubyte, ubyte, ubyte, ubyte)("buildBig2Struct");
217 	assert(buildBig2Struct(10, 42, 120, 3) == Big2(10, 42, 120, 42, 42, 42, 42, 3));
218 
219 	auto returnMiniStruct = ctx.getFunctionPtr!(Mini)("returnMiniStruct");
220 	assert(returnMiniStruct() == Mini(Micro(10, 42), Micro(120, 3)));
221 }
222 
223 
224 @TestInfo(&tester129)
225 immutable aggr129 = q{--- aggr129
226 	// Extract member from small struct (0 offset)
227 	struct Point { i32 x; i32 y; }
228 	void run(Point* points, Point neighbor)
229 	{
230 		Point* t = &points[neighbor.x]; // neighbor.x is 0th member
231 		t.x = 42;
232 	}
233 };
234 void tester129(ref TestContext ctx) {
235 	static struct Point { int x; int y; }
236 	auto run = ctx.getFunctionPtr!(void, Point*, Point)("run");
237 	Point point;
238 	run(&point, Point(0, 0));
239 	assert(point == Point(42, 0));
240 }
241 
242 
243 @TestInfo(&tester130)
244 immutable aggr130 = q{--- aggr130
245 	// Extract member from small struct (1 offset)
246 	struct Point { i32 x; i32 y; }
247 	void run(Point* points, Point neighbor)
248 	{
249 		Point* t = &points[neighbor.y]; // neighbor.y is 1st member
250 		t.y = 42;
251 	}
252 };
253 void tester130(ref TestContext ctx) {
254 	static struct Point { int x; int y; }
255 	auto run = ctx.getFunctionPtr!(void, Point*, Point)("run");
256 	Point point;
257 	run(&point, Point(0, 0));
258 	assert(point == Point(0, 42));
259 }
260 
261 
262 @TestInfo(&tester131)
263 immutable aggr131 = q{--- aggr131
264 	// Construct and store into ptr
265 	struct Point { i32 x; i32 y; }
266 	void run(Point* point, i32 x, i32 y)
267 	{
268 		*point = Point(x, y);
269 	}
270 };
271 void tester131(ref TestContext ctx) {
272 	static struct Point { int x; int y; }
273 	auto run = ctx.getFunctionPtr!(void, Point*, int, int)("run");
274 	Point point;
275 	run(&point, 42, 90);
276 	assert(point == Point(42, 90));
277 }
278 
279 
280 @TestInfo(&tester132, [HostSymbol("consume", cast(void*)&aggr132_external_consume)])
281 immutable aggr132 = q{--- aggr132
282 	// Bug. Wrong size of shl used when building small aggregate
283 	struct Point { i32 x; i32 y; }
284 	@extern(module, "host")
285 	void consume(i32, i32);
286 	void run(Point* player)
287 	{
288 		Point point;
289 		Point* ptr = &point;
290 		*ptr = Point(player.x, player.y);
291 		consume(point.x, point.y);
292 	}
293 };
294 extern(C) void aggr132_external_consume(int x, int y) {
295 	assert(x == 42);
296 	assert(y == 90);
297 }
298 void tester132(ref TestContext ctx) {
299 	static struct Point { int x; int y; }
300 	auto run = ctx.getFunctionPtr!(void, Point*)("run");
301 	Point p = Point(42, 90);
302 	run(&p);
303 }
304 
305 
306 @TestInfo(&tester133, [HostSymbol("consume", cast(void*)&aggr133_external_consume)])
307 immutable aggr133 = q{--- aggr133
308 	// Bug. Wrong size of shr used when deconstructing small aggregate
309 	struct Point { i32 x; i32 y; }
310 	@extern(module, "host")
311 	void consume(i32, i32);
312 	void run(Point point)
313 	{
314 		consume(point.x, point.y);
315 	}
316 };
317 extern(C) void aggr133_external_consume(int x, int y) {
318 	assert(x == 42);
319 	assert(y == 90);
320 }
321 void tester133(ref TestContext ctx) {
322 	static struct Point { int x; int y; }
323 	auto run = ctx.getFunctionPtr!(void, Point)("run");
324 	Point p = Point(42, 90);
325 	run(p);
326 }
327 
328 
329 @TestInfo(&tester134)
330 immutable aggr134 = q{--- aggr134
331 	// SysV ABI
332 	struct Struct { i64 x; i64 y; }
333 	Struct run(Struct s) { return s; }
334 };
335 void tester134(ref TestContext ctx) {
336 	static struct Point { long x; long y; }
337 	auto run = ctx.getFunctionPtr!(Point, Point)("run");
338 	assert(run(Point(1, 2)) == Point(1, 2));
339 }
340 
341 
342 @TestInfo(&tester135)
343 immutable aggr135 = q{--- aggr135
344 	// SysV ABI
345 	struct vec1 { f32 x; }
346 	struct vec2 { f32 x; f32 y; }
347 	struct vec3 { f32 x; f32 y; f32 z; }
348 	struct vec4 { f32 x; f32 y; f32 z; f32 w; }
349 	struct vec5 { f32 x; f32 y; f32 z; f32 w; f32 q; }
350 	vec1 pass_vec1(vec1 v) { return v; }
351 	vec2 pass_vec2(vec2 v) { return v; }
352 	vec3 pass_vec3(vec3 v) { return v; }
353 	void pass_vec3_ptr(vec3* res, vec3 v) {
354 		*res = pass_vec3(v);
355 	}
356 	vec4 pass_vec4(vec4 v) { return v; }
357 	vec5 pass_vec5(vec5 v) { return v; }
358 };
359 void tester135(ref TestContext ctx) {
360 	static struct vec1 { float x; }
361 	static struct vec2 { float x; float y; }
362 	static struct vec3 { float x; float y; float z; }
363 	static struct vec4 { float x; float y; float z; float w; }
364 	static struct vec5 { float x; float y; float z; float w; float q; }
365 
366 	auto pass_vec1 = ctx.getFunctionPtr!(vec1, vec1)("pass_vec1");
367 	assert(pass_vec1(vec1(1)) == vec1(1));
368 
369 	auto pass_vec2 = ctx.getFunctionPtr!(vec2, vec2)("pass_vec2");
370 	assert(pass_vec2(vec2(1, 2)) == vec2(1, 2));
371 
372 	auto pass_vec3_ptr = ctx.getFunctionPtr!(void, vec3*, vec3)("pass_vec3_ptr");
373 	vec3 r1;
374 	pass_vec3_ptr(&r1, vec3(1, 2, 3));
375 	assert(r1 == vec3(1, 2, 3));
376 
377 	auto pass_vec3 = ctx.getFunctionPtr!(vec3, vec3)("pass_vec3");
378 	assert(pass_vec3(vec3(1, 2, 3)) == vec3(1, 2, 3));
379 
380 	auto pass_vec4 = ctx.getFunctionPtr!(vec4, vec4)("pass_vec4");
381 	assert(pass_vec4(vec4(1, 2, 3, 4)) == vec4(1, 2, 3, 4));
382 
383 	auto pass_vec5 = ctx.getFunctionPtr!(vec5, vec5)("pass_vec5");
384 	assert(pass_vec5(vec5(1, 2, 3, 4, 5)) == vec5(1, 2, 3, 4, 5));
385 }
386 
387 
388 @TestInfo(&tester136)
389 immutable aggr136 = q{--- aggr136
390 	// SysV ABI
391 	struct vec1 { f32[1] x; }
392 	struct vec2 { f32[2] x; }
393 	struct vec3 { f32[3] x; }
394 	struct vec4 { f32[4] x; }
395 	struct vec5 { f32[5] x; }
396 	vec1 pass_vec1(vec1 v) { return v; }
397 	vec2 pass_vec2(vec2 v) { return v; }
398 	vec3 pass_vec3(vec3 v) { return v; }
399 	vec4 pass_vec4(vec4 v) { return v; }
400 	vec5 pass_vec5(vec5 v) { return v; }
401 };
402 void tester136(ref TestContext ctx) {
403 	static struct vec1 { float[1] x; }
404 	static struct vec2 { float[2] x; }
405 	static struct vec3 { float[3] x; }
406 	static struct vec4 { float[4] x; }
407 	static struct vec5 { float[5] x; }
408 
409 	auto pass_vec1 = ctx.getFunctionPtr!(vec1, vec1)("pass_vec1");
410 	assert(pass_vec1(vec1([1])) == vec1([1]));
411 
412 	auto pass_vec2 = ctx.getFunctionPtr!(vec2, vec2)("pass_vec2");
413 	assert(pass_vec2(vec2([1, 2])) == vec2([1, 2]));
414 
415 	auto pass_vec3 = ctx.getFunctionPtr!(vec3, vec3)("pass_vec3");
416 	assert(pass_vec3(vec3([1, 2, 3])) == vec3([1, 2, 3]));
417 
418 	auto pass_vec4 = ctx.getFunctionPtr!(vec4, vec4)("pass_vec4");
419 	assert(pass_vec4(vec4([1, 2, 3, 4])) == vec4([1, 2, 3, 4]));
420 
421 	auto pass_vec5 = ctx.getFunctionPtr!(vec5, vec5)("pass_vec5");
422 	assert(pass_vec5(vec5([1, 2, 3, 4, 5])) == vec5([1, 2, 3, 4, 5]));
423 }
424 
425 
426 @TestInfo(&tester137)
427 immutable aggr137 = q{--- aggr137
428 	// SysV ABI
429 	struct vec1 { f32 x; i32 y; }
430 	struct vec2 { i32 x; f32 y; }
431 	struct vec3 { i32 x; f32 y; f32 z; i32 w; }
432 	struct vec4 { f32 x; i32 y; i32 z; f32 w; }
433 	struct vec5 { i32 x; i32 y; f32 z; f32 w; }
434 	struct vec6 { f32 x; f32 y; i32 z; i32 w; }
435 	vec1 pass_vec1(vec1 v) { return v; }
436 	vec2 pass_vec2(vec2 v) { return v; }
437 	vec3 pass_vec3(vec3 v) { return v; }
438 	vec4 pass_vec4(vec4 v) { return v; }
439 	vec5 pass_vec5(vec5 v) { return v; }
440 	vec6 pass_vec6(vec6 v) { return v; }
441 };
442 void tester137(ref TestContext ctx) {
443 	static struct vec1 { float x; int y; }
444 	static struct vec2 { int x; float y; }
445 	static struct vec3 { int x; float y; float z; int w; }
446 	static struct vec4 { float x; int y; int z; float w; }
447 	static struct vec5 { int x; int y; float z; float w; }
448 	static struct vec6 { float x; float y; int z; int w; }
449 
450 	auto pass_vec1 = ctx.getFunctionPtr!(vec1, vec1)("pass_vec1");
451 	assert(pass_vec1(vec1(1, 2)) == vec1(1, 2));
452 
453 	auto pass_vec2 = ctx.getFunctionPtr!(vec2, vec2)("pass_vec2");
454 	assert(pass_vec2(vec2(1, 2)) == vec2(1, 2));
455 
456 	auto pass_vec3 = ctx.getFunctionPtr!(vec3, vec3)("pass_vec3");
457 	assert(pass_vec3(vec3(1, 2, 3, 4)) == vec3(1, 2, 3, 4));
458 
459 	auto pass_vec4 = ctx.getFunctionPtr!(vec4, vec4)("pass_vec4");
460 	assert(pass_vec4(vec4(1, 2, 3, 4)) == vec4(1, 2, 3, 4));
461 
462 	auto pass_vec5 = ctx.getFunctionPtr!(vec5, vec5)("pass_vec5");
463 	assert(pass_vec5(vec5(1, 2, 3, 4)) == vec5(1, 2, 3, 4));
464 
465 	auto pass_vec6 = ctx.getFunctionPtr!(vec6, vec6)("pass_vec6");
466 	assert(pass_vec6(vec6(1, 2, 3, 4)) == vec6(1, 2, 3, 4));
467 }
468 
469 
470 @TestInfo(&tester138)
471 immutable aggr138 = q{--- aggr138
472 	// lowering
473 	struct Point { i32 x; i32 y; }
474 	i32 getX(Point neighbor) {
475 		return neighbor.x; // neighbor.x is member 0
476 	}
477 	i32 getY(Point neighbor) {
478 		return neighbor.y; // neighbor.y is member 1
479 	}
480 };
481 void tester138(ref TestContext ctx) {
482 	static struct Point { int x; int y; }
483 	auto getX = ctx.getFunctionPtr!(int, Point)("getX");
484 	auto getY = ctx.getFunctionPtr!(int, Point)("getY");
485 	assert(getX(Point(1, 2)) == 1);
486 	assert(getY(Point(1, 2)) == 2);
487 }
488 
489 
490 @TestInfo(&tester139, [HostSymbol("external", cast(void*)&aggr139_external)])
491 immutable aggr139 = q{--- aggr139
492 	// passing address of member var
493 	struct Struct {
494 		u64 var2;
495 		u64 var;
496 		u64 fun() {
497 			external(&var);
498 			return var;
499 		}
500 	}
501 	u64 run() {
502 		Struct s;
503 		return s.fun();
504 	}
505 	@extern(module, "host")
506 	void external(u64*);
507 };
508 extern(C) void aggr139_external(ulong* ptr) {
509 	*ptr = 42;
510 }
511 void tester139(ref TestContext ctx) {
512 	assert(ctx.getFunctionPtr!(ulong)("run")() == 42);
513 }