-
-
Save dnadlinger/afcb826282f45ba76f92 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.stdio; | |
import std.process; | |
import std.random; | |
import std.exception; | |
import std.uuid; | |
import std.range; | |
import std.string; | |
// x86_32 - bug with empty struct - fixed | |
// x86_64 posix - bug with empty struct (https://issues.dlang.org/show_bug.cgi?id=13956) | |
// x86_64 posix - bug with float+double struct (https://issues.dlang.org/show_bug.cgi?id=13955) | |
// x86_64 posix - bug with double+char struct (not reduced, probably similar) | |
// x86_64 posix - more? | |
abstract | |
class Value | |
{ | |
// void writeCheckCpp(ref File f, string prefix, size_t i); | |
// void writeCheckD(ref File f, string prefix, size_t i); | |
void writeStructCpp(ref File f); | |
void writeStructD(ref File f); | |
void writeMemberCpp(ref File f, size_t i); | |
void writeMemberD(ref File f, size_t i); | |
void writeParamD(ref File f, size_t i); | |
void writeParamPromotedD(ref File f, size_t i); | |
void writeVarD(ref File f, size_t i, bool value); | |
void writeVarPromotedD(ref File f, size_t i, bool value); | |
void writeTypeD(ref File f, size_t i); | |
void writeTypePromotedD(ref File f, size_t i); | |
void writeInitD(ref File f); | |
void writeParamCpp(ref File f, size_t i); | |
void writeParamPromotedCpp(ref File f, size_t i); | |
void writeVarPromotedCpp(ref File f, size_t i); | |
void writeTypePromotedCpp(ref File f, size_t i); | |
} | |
class Struct : Value | |
{ | |
string name; | |
Value[] members; | |
this(string name) | |
{ | |
this.name = name; | |
} | |
// override void writeCheckCpp(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix); | |
// } | |
// override void writeCheckD(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix); | |
// } | |
override void writeStructCpp(ref File f) | |
{ | |
foreach(i, m; members) | |
m.writeStructCpp(f); | |
f.writefln("struct %s {", name); | |
foreach(i, m; members) | |
m.writeMemberCpp(f, i); | |
f.writefln("};"); | |
f.writefln(""); | |
} | |
override void writeStructD(ref File f) | |
{ | |
foreach(i, m; members) | |
m.writeStructD(f); | |
f.writefln("struct %s {", name); | |
foreach(i, m; members) | |
m.writeMemberD(f, i); | |
f.writefln("}"); | |
f.writefln(""); | |
} | |
override void writeMemberCpp(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", name, mname); | |
} | |
override void writeMemberD(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", name, mname); | |
} | |
override void writeParamD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamPromotedD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeParamPromotedCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", name, i); | |
} | |
override void writeTypeD(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeTypePromotedD(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeTypePromotedCpp(ref File f, size_t i) | |
{ | |
f.writef("%s", name); | |
} | |
override void writeVarD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
{ | |
f.writef(" %s arg%d = ", name, i); | |
writeInitD(f); | |
f.writeln(";"); | |
} | |
else | |
f.writefln(" %s arg%d;", name, i); | |
} | |
override void writeVarPromotedD(ref File f, size_t i, bool value) | |
{ | |
writeVarD(f, i, value); | |
} | |
override void writeVarPromotedCpp(ref File f, size_t i) | |
{ | |
f.writefln(" %s arg%d;", name, i); | |
} | |
override void writeInitD(ref File f) | |
{ | |
f.writef("%s(", name); | |
foreach(i, m; members) | |
{ | |
if (i) | |
f.write(", "); | |
m.writeInitD(f); | |
} | |
f.writef(")"); | |
} | |
} | |
class Basic : Value | |
{ | |
string dname; | |
string cname; | |
string ival; | |
string dprom; | |
string cprom; | |
this(string dname, string cname, string ival, string dprom, string cprom) | |
{ | |
this.dname = dname; | |
this.cname = cname; | |
this.ival = ival; | |
this.dprom = dprom; | |
this.cprom = cprom; | |
} | |
// override void writeCheckCpp(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix); | |
// } | |
// override void writeCheckD(ref File f, string prefix, size_t i) | |
// { | |
// auto m = "val_%d".format(i); | |
// f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix); | |
// } | |
override void writeStructCpp(ref File f) | |
{ | |
} | |
override void writeStructD(ref File f) | |
{ | |
} | |
override void writeMemberCpp(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", cname, mname); | |
} | |
override void writeMemberD(ref File f, size_t i) | |
{ | |
auto mname = "val_%d".format(i); | |
f.writefln("\t%s %s;", dname, mname); | |
} | |
override void writeParamD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", dname, i); | |
} | |
override void writeParamPromotedD(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", dprom, i); | |
} | |
override void writeParamCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", cname, i); | |
} | |
override void writeParamPromotedCpp(ref File f, size_t i) | |
{ | |
if (i) | |
f.write(", "); | |
f.writef("%s arg%d", cprom, i); | |
} | |
override void writeTypeD(ref File f, size_t i) | |
{ | |
f.writef("%s", dname); | |
} | |
override void writeTypePromotedD(ref File f, size_t i) | |
{ | |
f.writef("%s", dprom); | |
} | |
override void writeTypePromotedCpp(ref File f, size_t i) | |
{ | |
f.writef("%s", cprom); | |
} | |
override void writeVarD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
f.writefln(" %s arg%d = %s;", dname, i, ival); | |
else | |
f.writefln(" %s arg%d;", dname, i); | |
} | |
override void writeVarPromotedD(ref File f, size_t i, bool value) | |
{ | |
if (value) | |
f.writefln(" %s arg%d = %s;", dprom, i, ival); | |
else | |
f.writefln(" %s arg%d;", dprom, i); | |
} | |
override void writeVarPromotedCpp(ref File f, size_t i) | |
{ | |
f.writefln(" %s arg%d;", cprom, i); | |
} | |
override void writeInitD(ref File f) | |
{ | |
f.writef("%s", ival); | |
} | |
} | |
version(D_LP64) | |
{ | |
static immutable string[5][] basics = | |
[ | |
["byte", "signed char", "99", "int", "int"], | |
["ubyte", "unsigned char", "100", "int", "int"], | |
["char", "char", "101", "int", "int"], | |
["int", "int", "102", "int", "int"], | |
["uint", "unsigned", "103", "uint", "unsigned"], | |
["long", "long", "104", "long", "long"], | |
["ulong", "unsigned long", "105", "ulong", "unsigned long"], | |
["float", "float", "0", "double", "double"], | |
["double", "double", "0", "double", "double"], | |
["real", "long double", "0", "real", "long double"], | |
["bool", "bool", "false", "int", "int"], | |
["void*", "void*", "null", "void*", "void*"], | |
]; | |
} | |
else version(X86) | |
{ | |
static immutable string[5][] basics = | |
[ | |
["byte", "signed char", "99", "int", "int"], | |
["ubyte", "unsigned char", "100", "int", "int"], | |
["char", "char", "101", "int", "int"], | |
["int", "int", "102", "int", "int"], | |
["uint", "unsigned", "103", "uint", "unsigned"], | |
["long", "long long", "104", "long", "long long"], | |
["ulong", "unsigned long long", "105", "ulong", "unsigned long long"], | |
["float", "float", "0", "double", "double"], | |
["double", "double", "0", "double", "double"], | |
["real", "long double", "0", "real", "long double"], | |
["bool", "bool", "false", "int", "int"], | |
["void*", "void*", "null", "void*", "void*"], | |
]; | |
} | |
Value genValue(bool allowstruct) | |
{ | |
auto p = uniform(0, basics.length+allowstruct); | |
if (p == basics.length) | |
{ | |
static int id; | |
return genStruct("S%d".format(id++)); | |
} | |
else | |
{ | |
return new Basic(basics[p][0], basics[p][1], basics[p][2], basics[p][3], basics[p][4]); | |
} | |
} | |
Struct genStruct(string name) | |
{ | |
auto s = new Struct(name); | |
// modify here to change the number of struct members | |
foreach(i; 0..uniform(0, 3)) | |
{ | |
s.members ~= genValue(false); | |
} | |
return s; | |
} | |
void main() | |
{ | |
while(true) | |
{ | |
auto testname = "test_vararg_" ~ randomUUID().toString().replace("-", "_"); | |
Value[] values; | |
// modify here to change the number of parameters | |
values.length = uniform(2, 20); | |
foreach(ref v; values) | |
v = genValue(true); | |
// modify here to change the number of named parameters | |
auto namedArgs = values.length; //uniform(1, values.length); | |
auto df = File(testname ~ "_d.d", "wb"); | |
auto cf = File(testname ~ "_cpp.cpp", "wb"); | |
df.writeln("import core.stdc.stdarg;"); | |
df.writeln(); | |
cf.writeln("#include <stdarg.h>"); | |
cf.writeln(); | |
foreach(v; values) | |
{ | |
v.writeStructCpp(cf); | |
v.writeStructD(df); | |
} | |
cf.write("void checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
v.writeParamCpp(cf, i); | |
else | |
v.writeParamPromotedCpp(cf, i); | |
} | |
cf.writeln(");"); | |
// cf.writeln("int main(void) {"); | |
// cf.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckCpp(cf, "s", i); | |
// cf.writefln("printf(\"size: %%d\\n\", sizeof(s));"); | |
// cf.writeln("\treturn 0;"); | |
// cf.writeln("}"); | |
cf.write("void cppvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamCpp(cf, i); | |
if (values.length != namedArgs) | |
cf.writeln(", ...)"); | |
else | |
cf.writeln(")"); | |
cf.writeln("{"); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
v.writeVarPromotedCpp(cf, i); | |
} | |
if (values.length != namedArgs) | |
{ | |
cf.writeln(" va_list va;"); | |
cf.writefln(" va_start(va, arg%d);", namedArgs-1); | |
} | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
cf.writef(" arg%d = va_arg(va, ", i); | |
v.writeTypePromotedCpp(cf, i); | |
cf.writefln(");"); | |
} | |
if (values.length != namedArgs) | |
{ | |
cf.writeln(" va_end(va);"); | |
} | |
cf.write(" checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
cf.write(", "); | |
cf.writef("arg%d", i); | |
} | |
cf.writeln(");"); | |
cf.writeln("}"); | |
cf.writeln(); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void cppvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamD(df, i); | |
if (values.length > namedArgs) | |
df.writeln(", ...);"); | |
else | |
df.writeln(");"); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void dvararg("); | |
foreach(i, v; values[0..namedArgs]) | |
v.writeParamD(df, i); | |
if (values.length != namedArgs) | |
df.writeln(", ...)"); | |
else | |
df.writeln(")"); | |
df.writeln("{"); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
v.writeVarPromotedD(df, i, false); | |
} | |
if (values.length != namedArgs) | |
{ | |
df.writeln(" va_list va;"); | |
version(X86) | |
{ | |
df.writefln(" va_start(va, arg%d);", namedArgs-1); | |
} | |
else version (Windows) | |
{ | |
static assert(0); | |
} | |
else version(X86_64) | |
{ | |
df.writefln(" va_start(va, __va_argsave);", namedArgs-1); | |
} | |
else | |
static assert(0); | |
} | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
continue; | |
df.write(" va_arg!("); | |
v.writeTypePromotedD(df, i); | |
df.writefln(")(va, arg%d);", i); | |
} | |
if (values.length != namedArgs) | |
{ | |
df.writeln(" va_end(va);"); | |
} | |
df.write(" checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
df.write("extern(C++) void checkValues("); | |
foreach(i, v; values) | |
{ | |
if (i < namedArgs) | |
v.writeParamD(df, i); | |
else | |
v.writeParamPromotedD(df, i); | |
} | |
df.writeln(")"); | |
df.writeln("{"); | |
foreach(i, v; values) | |
{ | |
df.writef(" assert(arg%d == ", i); | |
v.writeInitD(df); | |
df.writeln(");"); | |
} | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
df.writeln("void main()"); | |
df.writeln("{"); | |
foreach(i, v; values) | |
{ | |
v.writeVarD(df, i, true); | |
} | |
df.write(" dvararg("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.write(" cppvararg("); | |
foreach(i, v; values) | |
{ | |
if (i) | |
df.write(", "); | |
df.writef("arg%d", i); | |
} | |
df.writeln(");"); | |
df.writeln("}"); | |
df.writeln(); | |
///////////////////////////////////////////// | |
// df.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckD(df, "s", i); | |
// df.writefln("printf(\"size: %%d\\n\", s.sizeof);"); | |
// df.writeln("}"); | |
// df.writeln("void main() {"); | |
// df.writeln("\tTest s;"); | |
// foreach(i, m; s.members) | |
// m.writeCheckD(df, "s", i); | |
// df.writefln("printf(\"size: %%d\\n\", s.sizeof);"); | |
// df.writeln("}"); | |
cf.close(); | |
df.close(); | |
version(Windows) | |
{ | |
writeln("%s_d.d".format(testname)); | |
auto dmcres = executeShell("dmc -g -c %s_cpp.cpp".format(testname)); | |
writeln(dmcres.output); | |
enforce(dmcres.status == 0); | |
auto dmdres = executeShell("dmd -g %s_d.d %s_cpp.obj".format(testname, testname)); | |
writeln(dmdres.output); | |
enforce(dmdres.status == 0); | |
auto dout = executeShell("%s_d".format(testname)); | |
} | |
else | |
{ | |
writeln("%s_d.d".format(testname)); | |
auto gppres = executeShell("g++ -g %s_cpp.cpp -c -o %s_cpp.o".format(testname, testname)); | |
writeln(gppres.output); | |
enforce(gppres.status == 0); | |
auto dmdres = executeShell("CC=g++ ./dmd -gc %s_d.d %s_cpp.o".format(testname, testname)); | |
writeln(dmdres.output); | |
enforce(dmdres.status == 0); | |
auto dout = executeShell("./%s_d".format(testname)); | |
} | |
writeln(dout.output); | |
enforce(dout.status == 0); | |
import std.file; | |
remove("%s_cpp.cpp".format(testname)); | |
remove("%s_cpp.o".format(testname)); | |
remove("%s_d.d".format(testname)); | |
remove("%s_d.o".format(testname)); | |
remove("%s_d".format(testname)); | |
} | |
} | |
// extern(C++) void dvarArg(int arg0, ...) | |
// { | |
// long arg1; | |
// bool arg2; | |
// va_list va; | |
// va_start(va, arg0); | |
// va_arg!long(va, arg1); | |
// va_arg!bool(va, arg2); | |
// va_end(va); | |
// checkValues(arg0, arg1, arg2); | |
// } | |
// extern(C++) void checkValues(int arg0, long arg1, bool arg2) | |
// { | |
// assert(arg0 == 3); | |
// assert(arg1 == 7); | |
// assert(arg2 == false); | |
// } | |
// void main() | |
// { | |
// int arg0 = 3; | |
// long arg1 = 7; | |
// bool arg2 = false; | |
// dvarArg(arg0, arg1, arg2); | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment