| // PERMUTE_ARGS: -release -g |
| |
| version(Windows) {} |
| else version(X86_64) |
| { |
| /* uncomment to enable tests! */ |
| //version = Run_X86_64_Tests; |
| } |
| |
| extern (C) int printf(const char*, ...); |
| |
| template tuple(A...) { alias A tuple; } |
| |
| alias byte B; |
| alias short S; |
| alias int I; |
| alias long L; |
| alias float F; |
| alias double D; |
| alias real R; |
| |
| // Single Type |
| |
| struct b { B a; } |
| struct bb { B a,b; } |
| struct bbb { B a,b,c; } |
| struct bbbb { B a,b,c,d; } |
| struct bbbbb { B a,b,c,d, e; } |
| struct b6 { B a,b,c,d, e,f; } |
| struct b7 { B a,b,c,d, e,f,g; } |
| struct b8 { B a,b,c,d, e,f,g,h; } |
| struct b9 { B a,b,c,d, e,f,g,h, i; } |
| struct b10 { B a,b,c,d, e,f,g,h, i,j; } |
| struct b11 { B a,b,c,d, e,f,g,h, i,j,k; } |
| struct b12 { B a,b,c,d, e,f,g,h, i,j,k,l; } |
| struct b13 { B a,b,c,d, e,f,g,h, i,j,k,l, m; } |
| struct b14 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n; } |
| struct b15 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o; } |
| struct b16 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p; } |
| struct b17 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q; } |
| struct b18 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r; } |
| struct b19 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s; } |
| struct b20 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s,t;} |
| |
| struct s { S a; } |
| struct ss { S a,b; } |
| struct sss { S a,b,c; } |
| struct ssss { S a,b,c,d; } |
| struct sssss { S a,b,c,d, e; } |
| struct s6 { S a,b,c,d, e,f; } |
| struct s7 { S a,b,c,d, e,f,g; } |
| struct s8 { S a,b,c,d, e,f,g,h; } |
| struct s9 { S a,b,c,d, e,f,g,h, i; } |
| struct s10 { S a,b,c,d, e,f,g,h, i,j;} |
| |
| struct i { I a; } struct l { L a; } |
| struct ii { I a,b; } struct ll { L a,b; } |
| struct iii { I a,b,c; } struct lll { L a,b,c; } |
| struct iiii { I a,b,c,d; } struct llll { L a,b,c,d; } |
| struct iiiii { I a,b,c,d,e; } struct lllll { L a,b,c,d,e; } |
| |
| struct f { F a; } struct d { D a; } |
| struct ff { F a,b; } struct dd { D a,b; } |
| struct fff { F a,b,c; } struct ddd { D a,b,c; } |
| struct ffff { F a,b,c,d; } struct dddd { D a,b,c,d; } |
| struct fffff { F a,b,c,d,e; } struct ddddd { D a,b,c,d,e; } |
| |
| // Mixed Size |
| |
| struct js { I a; S b; } |
| struct iss { I a; S b,c; } |
| struct si { S a; I b; } |
| struct ssi { S a,b; I c; } |
| struct sis { S a; I b; S c; } |
| |
| struct ls { L a; S b; } |
| struct lss { L a; S b,c; } |
| struct sl { S a; L b; } |
| struct ssl { S a,b; L c; } |
| struct sls { S a; L b; S c; } |
| |
| struct li { L a; I b; } |
| struct lii { L a; I b,c; } |
| struct il { I a; L b; } |
| struct iil { I a,b; L c; } |
| struct ili { I a; L b; I c; } |
| |
| struct df { D a; F b; } |
| struct dff { D a; F b,c; } |
| struct fd { F a; D b; } |
| struct ffd { F a,b; D c; } |
| struct fdf { F a; D b; F c; } |
| |
| // Mixed Types |
| |
| struct fi { F a; I b; } |
| struct fii { F a; I b,c; } |
| struct jf { I a; F b; } |
| struct iif { I a,b; F c; } |
| struct ifi { I a; F b; I c; } |
| |
| struct ffi { F a,b; I c; } |
| struct ffii { F a,b; I c,d; } |
| struct iff { I a; F b,c; } |
| struct iiff { I a,b; F c,d; } |
| struct ifif { I a; F b; I c; F d;} |
| |
| struct di { D a; I b; } |
| struct dii { D a; I b,c; } |
| struct id { I a; D b; } |
| struct iid { I a,b; D c; } |
| struct idi { I a; D b; I c; } |
| |
| // Real ( long double ) |
| |
| struct r { R a; } |
| struct rr { R a,b; } |
| struct rb { R a; B b; } |
| struct rf { R a; F b; } |
| struct fr { F a; R b; } |
| |
| // Int Registers only |
| alias tuple!( b,bb,bbb,bbbb,bbbbb, |
| b6, b7, b8, b9, b10, |
| b11,b12,b13,b14,b15, |
| b16,b17,b18,b19,b20, |
| s,ss,sss,ssss,sssss, |
| s6, s7, s8, s9, s10, |
| i,ii,iii,iiii,iiiii, |
| l,ll,lll,llll,lllll, |
| // |
| js,iss,si,ssi, sis, |
| ls,lss,sl,ssl, sls, |
| li,lii,il,iil, ili, |
| fi,fii,jf,iif, ifi, |
| ffi,ffii,iff,iiff,ifif, // INT_END |
| |
| // SSE registers only |
| f,ff,fff,ffff,fffff, |
| d,dd,ddd,dddd,ddddd, |
| // |
| df,dff,fd,ffd, fdf, // SSE_END |
| |
| // Int and SSE |
| di, dii,id, iid, idi, // MIX_END |
| // --- |
| ) ALL_T; |
| |
| enum INT_END = 65; |
| enum SSE_END = 80; |
| enum MIX_END = ALL_T.length; |
| |
| // x87 |
| alias tuple!( r,rr,rb,rf,fr, |
| // --- |
| ) R_T; |
| //"r","rr","rb","rf","fr", |
| |
| |
| string[] ALL_S=[ |
| "b","bb","bbb","bbbb","bbbbb", |
| "b6", "b7", "b8", "b9", "b10", |
| "b11","b12","b13","b14","b15", |
| "b16","b17","b18","b19","b20", |
| "s","ss","sss","ssss","sssss", |
| "s6","s7","s8","s9" , "s10", |
| "i","ii","iii","iiii","iiiii", |
| "l","ll","lll","llll","lllll", |
| // --- |
| "js","iss","si","ssi", "sis", |
| "ls","lss","sl","ssl", "sls", |
| "li","lii","il","iil", "ili", |
| "fi","fii","jf","iif", "ifi", |
| "ffi","ffii","iff","iiff","ifif", |
| // --- |
| "f","ff","fff","ffff","fffff", |
| "d","dd","ddd","dddd","ddddd", |
| "df","dff","fd","ffd", "dfd", |
| // --- |
| "di","dii","id","iid","idi", |
| ]; |
| |
| /* *********************************************************************** |
| All |
| ************************************************************************/ |
| // test1 Struct passing and return |
| |
| int[MIX_END] results_1; |
| |
| T test1_out(T)( ) |
| { |
| T t; |
| foreach( i, ref e; t.tupleof ) e = i+1; |
| return t; |
| } |
| T test1_inout(T)( T t) |
| { |
| foreach( i, ref e; t.tupleof ) e += 10; |
| return t; |
| } |
| |
| void test1_call_out(T)( int n ) |
| { |
| T t1; |
| foreach( i, ref e; t1.tupleof ) e = i+1; |
| T t2 = test1_out!(T)(); |
| |
| if( t1 == t2 ) results_1[n] |= 1; |
| } |
| void test1_call_inout(T)( int n ) |
| { |
| T t1; |
| foreach( i, ref e; t1.tupleof ) e = i+1; |
| T t2 = test1_inout!(T)( t1 ); |
| foreach( i, ref e; t1.tupleof ) e += 10; |
| |
| if( t1 == t2 ) results_1[n] |= 2; |
| } |
| |
| void D_test1( ) |
| { |
| // Run Tests |
| foreach( n, T; ALL_T ) |
| { |
| test1_call_out!(T)(n); |
| test1_call_inout!(T)(n); |
| } |
| |
| bool pass = true; |
| foreach( i, r; results_1 ) |
| { |
| if( ~r & 1 ) |
| { |
| pass = false; |
| printf( "Test1 out %s \tFail\n", ALL_S[i].ptr ); |
| } |
| if( ~r & 2 ) |
| { |
| pass = false; |
| printf( "Test1 inout %s \tFail\n", ALL_S[i].ptr ); |
| } |
| } |
| assert( pass ); |
| |
| results_1[0..5] = 0; |
| foreach( n, T; R_T ) |
| { |
| test1_call_out!(T)(n); |
| test1_call_inout!(T)(n); |
| } |
| } |
| |
| /************************************************************************/ |
| // based on runnable/test23.d : test44() |
| // Return Struct into an Array |
| |
| struct S1 |
| { int i,j; |
| |
| static S1 foo(int x) |
| { S1 s; |
| s.i = x; |
| return s; |
| } } |
| struct S2 |
| { int i,j,k; |
| |
| static S2 foo(int x) |
| { S2 s; |
| s.i = x; |
| return s; |
| } } |
| struct S3 |
| { float i,j; |
| |
| static S3 foo(int x) |
| { S3 s; |
| s.i = x; |
| return s; |
| } } |
| struct S4 |
| { float i,j,k; |
| |
| static S4 foo(int x) |
| { S4 s; |
| s.i = x; |
| return s; |
| } } |
| struct S5 |
| { float i,j; |
| int k; |
| |
| static S5 foo(float x) |
| { S5 s; |
| s.i = x; |
| return s; |
| } } |
| |
| void D_test2() |
| { |
| S1[] s1; |
| S2[] s2; |
| S3[] s3; |
| S4[] s4; |
| S5[] s5; |
| |
| s1 = s1 ~ S1.foo(6); s1 = s1 ~ S1.foo(1); |
| s2 = s2 ~ S2.foo(6); s2 = s2 ~ S2.foo(1); |
| s3 = s3 ~ S3.foo(6); s3 = s3 ~ S3.foo(1); |
| s4 = s4 ~ S4.foo(6); s4 = s4 ~ S4.foo(1); |
| s5 = s5 ~ S5.foo(6); s5 = s5 ~ S5.foo(1); |
| |
| assert( s1.length == 2 ); |
| assert( s1[0].i == 6 ); |
| assert( s1[1].i == 1 ); |
| |
| assert( s2.length == 2 ); |
| assert( s2[0].i == 6 ); |
| assert( s2[1].i == 1 ); |
| |
| /+ // These Fail on Mainline DMD64 ( Should pass! ) |
| assert( s3.length == 2 ); |
| assert( s3[0].i == 6 ); |
| assert( s3[1].i == 1 ); |
| |
| assert( s4.length == 2 ); |
| assert( s4[0].i == 6 ); |
| assert( s4[1].i == 1 ); |
| +/ |
| assert( s5.length == 2 ); |
| assert( s5[0].i == 6 ); |
| assert( s5[1].i == 1 ); |
| |
| } |
| |
| /* *********************************************************************** |
| X86_64 |
| ************************************************************************/ |
| |
| version(Run_X86_64_Tests) |
| { |
| |
| |
| struct TEST |
| { |
| immutable int num; |
| immutable string desc; |
| bool[MIX_END] result; |
| } |
| |
| /** |
| * 0 = Should Fail |
| * 1 = Should Pass |
| */ |
| immutable int[MIX_END] expected = |
| [ |
| 1,1,1,1,1, // b |
| 1,1,1,1,1, // b6 |
| 1,1,1,1,1, // b11 |
| 1,0,0,0,0, // b16 |
| |
| 1,1,1,1,1, // s |
| 1,1,1,0,0, // s6 |
| 1,1,1,1,0, // i |
| 1,1,0,0,0, // l |
| 1,1,1,1,1, // si mix |
| 1,1,1,1,0, // sl |
| 1,1,1,1,0, // il |
| 1,1,1,1,1, // int and float |
| 1,1,1,1,1, // int and float |
| |
| // SSE regs only |
| 1,1,1,1,0, // f |
| 1,1,0,0,0, // d |
| 1,1,1,1,0, // float and double |
| |
| // SSE + INT regs |
| 1,1,1,1,0, // int and double |
| ]; |
| |
| |
| /** |
| * Describes value expected in registers |
| * |
| * null means do not test |
| * ( because value is passed on the stack ). |
| */ |
| |
| immutable long[][] RegValue = |
| [ |
| /* 0 b */ [ 0x0000000000000001, ], |
| /* 1 bb */ [ 0x0000000000000201, ], |
| /* 2 bbb */ [ 0x0000000000030201, ], |
| /* 3 bbbb */ [ 0x0000000004030201, ], |
| /* 4 bbbbb */ [ 0x0000000504030201, ], |
| /* 5 b6 */ [ 0x0000060504030201, ], |
| /* 6 b7 */ [ 0x0007060504030201, ], |
| /* 7 b8 */ [ 0x0807060504030201, ], |
| /* 8 b9 */ [ 0x0807060504030201, 0x0000000000000009 ], |
| /* 9 b10 */ [ 0x0807060504030201, 0x0000000000000a09 ], |
| /* 10 b11 */ [ 0x0807060504030201, 0x00000000000b0a09 ], |
| /* 11 b12 */ [ 0x0807060504030201, 0x000000000c0b0a09 ], |
| /* 12 b13 */ [ 0x0807060504030201, 0x0000000d0c0b0a09 ], |
| /* 13 b14 */ [ 0x0807060504030201, 0x00000e0d0c0b0a09 ], |
| /* 14 b15 */ [ 0x0807060504030201, 0x000f0e0d0c0b0a09 ], |
| /* 15 b16 */ [ 0x0807060504030201, 0x100f0e0d0c0b0a09 ], |
| /* 16 b17 */ null, |
| /* 17 b18 */ null, |
| /* 18 b19 */ null, |
| /* 19 b20 */ null, |
| /* 20 s */ [ 0x0000000000000001, ], |
| /* 21 ss */ [ 0x0000000000020001, ], |
| /* 22 sss */ [ 0x0000000300020001, ], |
| /* 23 ssss */ [ 0x0004000300020001, ], |
| /* 24 sssss */ [ 0x0004000300020001, 0x0000000000000005 ], |
| /* 25 s6 */ [ 0x0004000300020001, 0x0000000000060005 ], |
| /* 26 s7 */ [ 0x0004000300020001, 0x0000000700060005 ], |
| /* 27 s8 */ [ 0x0004000300020001, 0x0008000700060005 ], |
| /* 28 s9 */ null, |
| /* 29 s10 */ null, |
| /* 30 i */ [ 0x0000000000000001, ], |
| /* 31 ii */ [ 0x0000000200000001, ], |
| /* 32 iii */ [ 0x0000000200000001, 0x0000000000000003 ], |
| /* 33 iiii */ [ 0x0000000200000001, 0x0000000400000003 ], |
| /* 34 iiiii */ null, |
| /* 35 l */ [ 0x0000000000000001, ], |
| /* 36 ll */ [ 0x0000000000000001, 0x0000000000000002 ], |
| /* 37 lll */ null, |
| /* 38 llll */ null, |
| /* 39 lllll */ null, |
| |
| /* 40 js */ [ 0x0000000200000001, ], |
| /* 41 iss */ [ 0x0003000200000001, ], |
| /* 42 si */ [ 0x0000000200000001, ], |
| /* 43 ssi */ [ 0x0000000300020001, ], |
| /* 44 sis */ [ 0x0000000200000001, 0x0000000000000003 ], |
| /* 45 ls */ [ 0x0000000000000001, 0x0000000000000002 ], |
| /* 46 lss */ [ 0x0000000000000001, 0x0000000000030002 ], |
| /* 47 sl */ [ 0x0000000000000001, 0x0000000000000002 ], |
| /* 48 ssl */ [ 0x0000000000020001, 0x0000000000000003 ], |
| /* 49 sls */ null, |
| /* 50 li */ [ 0x0000000000000001, 0x0000000000000002 ], |
| /* 51 lii */ [ 0x0000000000000001, 0x0000000300000002 ], |
| /* 52 il */ [ 0x0000000000000001, 0x0000000000000002 ], |
| /* 53 iil */ [ 0x0000000200000001, 0x0000000000000003 ], |
| /* 54 ili */ null, |
| |
| /* 55 fi */ [ 0x000000023f800000, ], |
| /* 56 fii */ [ 0x000000023f800000, 0x0000000000000003 ], |
| /* 57 jf */ [ 0x4000000000000001, ], |
| /* 58 iif */ [ 0x0000000200000001, 0x0000000040400000 ], |
| /* 59 ifi */ [ 0x4000000000000001, 0x0000000000000003 ], |
| |
| /* 60 ffi */ [ 0x0000000000000003, 0x400000003f800000 ], |
| /* 61 ffii */ [ 0x0000000400000003, 0x400000003f800000 ], |
| /* 62 iff */ [ 0x4000000000000001, 0x0000000040400000 ], |
| /* 63 iiff */ [ 0x0000000200000001, 0x4080000040400000 ], |
| /* 64 ifif */ [ 0x4000000000000001, 0x4080000000000003 ], |
| |
| /* 65 f */ [ 0x000000003f800000, ], |
| /* 66 ff */ [ 0x400000003f800000, ], |
| /* 67 fff */ [ 0x400000003f800000, 0x0000000040400000 ], |
| /* 68 ffff */ [ 0x400000003f800000, 0x4080000040400000 ], |
| /* 69 fffff */ null, |
| /* 70 d */ [ 0x3ff0000000000000, ], |
| /* 71 dd */ [ 0x3ff0000000000000, 0x4000000000000000 ], |
| /* 72 ddd */ null, |
| /* 73 dddd */ null, |
| /* 74 ddddd */ null, |
| |
| /* 75 df */ [ 0x3ff0000000000000, 0x0000000040000000 ], |
| /* 76 dff */ [ 0x3ff0000000000000, 0x4040000040000000 ], |
| /* 77 fd */ [ 0x000000003f800000, 0x4000000000000000 ], |
| /* 78 ffd */ [ 0x400000003f800000, 0x4008000000000000 ], |
| /* 79 fdf */ null, |
| |
| /* 80 di */ [ 0x3ff0000000000000, 0x0000000000000002 ], |
| /* 81 dii */ [ 0x3ff0000000000000, 0x0000000300000002 ], |
| /* 82 id */ [ 0x4000000000000000, 0x0000000000000001 ], |
| /* 83 iid */ [ 0x4008000000000000, 0x0000000200000001 ], |
| /* 84 idi */ null, |
| ]; |
| |
| /* Have to do it this way for OSX: Issue 7354 */ |
| __gshared long[2] dump; |
| |
| /** |
| * Generate Register capture |
| */ |
| string gen_reg_capture( int n, string registers )( ) |
| { |
| if( RegValue[n] == null ) return "return;"; |
| |
| string[] REG = mixin(registers); // ["RDI","RSI"]; |
| |
| // Which type of compare |
| static if(n < INT_END) |
| enum MODE = 1; // Int |
| else static if(n < SSE_END) |
| enum MODE = 2; // Float |
| else enum MODE = 3; // Mix |
| |
| /* Begin */ |
| |
| string code = "asm {\n"; |
| |
| final switch( MODE ) |
| { |
| case 1: code ~= "mov [dump], "~REG[0]~";\n"; |
| REG = REG[1..$]; |
| break; |
| case 2: |
| case 3: code ~= "movq [dump], XMM0;\n"; |
| } |
| |
| if( RegValue[n].length == 2 ) |
| final switch( MODE ) |
| { |
| case 1: |
| case 3: code ~= "mov [dump+8], "~REG[0]~";\n"; |
| break; |
| case 2: code ~= "movq [dump+8], XMM1;\n"; |
| } else { |
| code ~= "xor R8, R8;\n"; |
| code ~= "mov [dump+8], R8;\n"; |
| } |
| |
| return code ~ "}\n"; |
| } |
| |
| /** |
| * Check the results |
| */ |
| bool check( TEST data ) |
| { |
| bool pass = true; |
| foreach( i, e; expected ) |
| { |
| if( data.result[i] != (e & 1) ) |
| { |
| printf( "Test%d %s \tFail\n", data.num, ALL_S[i].ptr); |
| pass = false; |
| } |
| } |
| return pass; |
| } |
| |
| /************************************************************************/ |
| |
| // test1 Return Struct in Registers |
| // ( if RDI == 12 we have no hidden pointer ) |
| |
| TEST data1 = { 1, "RDI hidden pointer" }; |
| |
| T test1_asm( T, int n )( int i ) |
| { |
| asm { |
| |
| cmp EDI, 12; |
| je L1; |
| |
| leave; ret; |
| } |
| L1: |
| data1.result[n] = true; |
| } |
| |
| void test1() |
| { |
| printf("\nRunning iasm Test 1 ( %s )\n", data1.desc.ptr); |
| |
| foreach( int n, T; ALL_T ) |
| test1_asm!(T,n)(12); |
| |
| check( data1 ); |
| } |
| |
| /************************************************************************/ |
| // test2 Pass Struct in Registers |
| // ( if RDI == 0 we have no stack pointer ) |
| |
| TEST data2 = { 2, "RDI struct pointer" }; |
| |
| T test2_asm( T, int n )( T t ) |
| { |
| asm { |
| |
| mov [dump], RDI; |
| mov [dump+8], RSP; |
| cmp EDI, 0; // TODO test RDI is a ptr to stack ? ? |
| je L1; |
| |
| leave; ret; |
| } |
| L1: |
| data2.result[n] = true; |
| } |
| T test2f_asm( T, int n )( T t, int x ) |
| { |
| asm { |
| |
| cmp EDI, 12; |
| je L1; |
| |
| leave; ret; |
| } |
| L1: |
| data2.result[n] = true; |
| } |
| |
| void test2() |
| { |
| printf("\nRunning iasm Test 2 ( %s )\n", data2.desc.ptr); |
| |
| // Integer |
| foreach( int n, T; ALL_T ) { |
| T t = { 0 }; |
| test2_asm!(T,n)( t ); |
| } |
| |
| // float alternative test |
| foreach( int n, T; ALL_T[INT_END..SSE_END] ) |
| { |
| enum n2 = n + INT_END; |
| data2.result[n2] = false; |
| test2f_asm!(T,n2)( T.init, 12 ); |
| } |
| |
| check( data2 ); |
| } |
| |
| /************************************************************************/ |
| // test3 |
| |
| TEST data3 = { 3, "Check Return Register value" }; |
| |
| void test3_run( T, int n )( ) |
| { |
| test3_ret!T(); |
| mixin( gen_reg_capture!(n,`["RAX","RDX"]`)() ); |
| |
| //dbg!(T,n)( ); |
| |
| enum len = RegValue[n].length; |
| if( dump[0..len] == RegValue[n] ) |
| data3.result[n] = true; |
| } |
| |
| T test3_ret( T )( ) |
| { |
| T t; |
| foreach( i, ref e; t.tupleof ) e = i+1; |
| return t; |
| } |
| |
| void test3() |
| { |
| printf("\nRunning iasm Test 3 ( %s )\n", data3.desc.ptr); |
| |
| foreach( int n, T; ALL_T ) |
| test3_run!(T,n)( ); |
| |
| check( data3 ); |
| } |
| |
| /************************************************************************/ |
| // test4 |
| |
| TEST data4 = { 4, "Check Input Register value" }; |
| |
| void test4_run( T, int n )( T t ) |
| { |
| mixin( gen_reg_capture!(n,`["RDI","RSI"]`)() ); |
| |
| //dbg!(T,n)( ); |
| |
| enum len = RegValue[n].length; |
| if( dump[0..len] == RegValue[n] ) |
| data4.result[n] = true; |
| } |
| |
| void dbg( T, int n )( ) |
| { |
| import std.stdio; |
| writefln( "D %s\t[ %16x, %16x ]", T.stringof, dump[0], dump[1], ); |
| writef( "C %s\t[ %16x", T.stringof, RegValue[n][0] ); |
| if( RegValue[n].length == 2 ) |
| writef( ", %16x", RegValue[n][1] ); |
| writefln( " ]" ); |
| } |
| void test4() |
| { |
| printf("\nRunning iasm Test 4 ( %s )\n", data4.desc.ptr); |
| |
| foreach( int n, T; ALL_T ) |
| { |
| T t; |
| foreach( i, ref e; t.tupleof ) e = i+1; |
| test4_run!(T,n)( t ); |
| } |
| check( data4 ); |
| } |
| |
| |
| } // end version(Run_X86_64_Tests) |
| |
| /************************************************************************/ |
| |
| |
| void main() |
| { |
| D_test1(); |
| D_test2(); |
| |
| version(Run_X86_64_Tests) |
| { |
| test1(); |
| test2(); |
| test3(); |
| test4(); |
| } |
| } |
| |
| /+ |
| /** |
| * C code to generate the table RegValue |
| */ |
| string c_generate_returns() |
| { |
| string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10," |
| "11,12,13,14,15,16,17,18,19,20,"; |
| |
| string code = "#include \"cgen.h\"\n"; |
| |
| // Generate return functions |
| foreach( int n, T; ALL_T ) |
| { |
| auto Ts = T.stringof; |
| auto len = T.tupleof.length; |
| |
| code ~= "struct "~Ts~" func_ret_"~Ts~"(void) { \n"; |
| code ~= "struct "~Ts~" x = { "; |
| code ~= value[0..len*3] ~ " };\n"; |
| code ~= "return x;\n}\n"; |
| } |
| return code; |
| } |
| string c_generate_pass() |
| { |
| string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10," |
| "11,12,13,14,15,16,17,18,19,20,"; |
| |
| string code; |
| |
| // Generate return functions |
| foreach( int n, T; ALL_T ) |
| { |
| auto Ts = T.stringof; |
| auto len = T.tupleof.length; |
| |
| code ~= "void func_pass_"~Ts~"( struct "~Ts~" x ) {\n"; |
| //////////////// |
| // Which type of compare |
| static if(n < INT_END) |
| enum MODE = 1; // Int |
| else static if(n < SSE_END) |
| enum MODE = 2; // Float |
| else enum MODE = 3; // Mix |
| |
| auto nn = n.stringof; |
| |
| /* Begin */ |
| |
| code ~= "asm(\n"; |
| final switch( MODE ) |
| { |
| case 1: |
| code ~= `"movq %rdi, reg\n" "movq %rsi, reg+8\n"`; |
| break; |
| case 2: |
| code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`; |
| break; |
| case 3: |
| code ~= `"movq %xmm0, reg\n" "movq %rdi, reg+8\n"`; |
| } |
| code ~= "\n);\n"; |
| code ~= "}\n"; |
| |
| //////////////// |
| code ~= "void func_call_"~Ts~"( void ) {\n"; |
| code ~= "struct "~Ts~" x = { "; |
| code ~= value[0..len*3] ~ " };\n"; |
| code ~= "func_pass_"~Ts~"( x );\n}\n"; |
| } |
| return code; |
| } |
| string c_generate_main() |
| { |
| string code = "void main() {\n"; |
| |
| foreach( int n, T; ALL_T ) |
| { |
| // Which type of compare |
| static if(n < INT_END) |
| enum MODE = 1; // Int |
| else static if(n < SSE_END) |
| enum MODE = 2; // Float |
| else enum MODE = 3; // Mix |
| |
| auto nn = n.stringof; |
| auto Ts = T.stringof; |
| |
| /* Begin */ |
| |
| code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n"; |
| if( !(expected[n] & 1) ) |
| { |
| code ~= `printf("null,\n");`"\n"; |
| continue; |
| } |
| code ~= "asm(\n"; |
| code ~= `"call func_ret_`~Ts~`\n"`"\n"; |
| final switch( MODE ) |
| { |
| case 1: |
| code ~= `"movq %rax, reg\n" "movq %rdx, reg+8\n"`; |
| break; |
| case 2: |
| code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`; |
| break; |
| case 3: |
| code ~= `"movq %xmm0, reg\n" "movq %rax, reg+8\n"`; |
| } |
| code ~= "\n);\n"; |
| |
| code ~= `printf("[ 0x%016lx", reg.r1 );`"\n"; |
| |
| if( T.sizeof > 8 || MODE == 3 ) |
| code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n"; |
| else code ~= `printf(", %015c ],\n", ' ' );`"\n"; |
| } |
| |
| foreach( int n, T; ALL_T ) |
| { |
| // Which type of compare |
| static if(n < INT_END) |
| enum MODE = 1; // Int |
| else static if(n < SSE_END) |
| enum MODE = 2; // Float |
| else enum MODE = 3; // Mix |
| |
| auto nn = n.stringof; |
| auto Ts = T.stringof; |
| |
| /* Begin */ |
| |
| code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n"; |
| if( !(expected[n] & 1) ) |
| { |
| code ~= `printf("null,\n");`"\n"; |
| continue; |
| } |
| code ~= "func_call_"~Ts~"();\n"; |
| |
| code ~= `printf("[ 0x%016lx", reg.r1 );`"\n"; |
| |
| if( T.sizeof > 8 || MODE == 3 ) |
| code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n"; |
| else code ~= `printf(", %015c ],\n", ' ' );`"\n"; |
| } |
| |
| |
| return code ~ "}"; |
| } |
| pragma(msg, c_generate_returns() ); |
| pragma(msg, c_generate_pass() ); |
| pragma(msg, c_generate_main() ); |
| // +/ |
| |
| /+ |
| /** |
| * Generate Functions that pass/return each Struct type |
| * |
| * ( Easier to look at objdump this way ) |
| */ |
| string d_generate_functions( ) |
| { |
| string code = "extern(C) {"; |
| |
| // pass |
| foreach( s; ALL_T ) |
| { |
| string ss = s.stringof; |
| |
| code ~= "void func_in_"~ss~"( "~ss~" t ) { t.a = 12; }\n"; |
| } |
| // return |
| foreach( s; ALL_T[0..10] ) |
| { |
| string ss = s.stringof; |
| |
| code ~= ` |
| auto func_out_`~ss~`() |
| { |
| `~ss~` t; |
| foreach( i, ref e; t.tupleof ) e = i+1; |
| return t; |
| }`; |
| } |
| // pass & return |
| foreach( s; ALL_T[0..10] ) |
| { |
| string ss = s.stringof; |
| |
| code ~= ` |
| auto func_inout_`~ss~`( `~ss~` t ) |
| { |
| foreach( i, ref e; t.tupleof ) e += 10; |
| return t; |
| }`; |
| } |
| return code ~ "\n} // extern(C)\n"; |
| } |
| //pragma( msg, d_generate_functions() ); |
| mixin( d_generate_functions() ); |
| // +/ |