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 }