927 lines
26 KiB
D
927 lines
26 KiB
D
// 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() );
|
|
// +/
|