diff --git a/module.cpp b/module.cpp index 4f23f907..a4e75588 100644 --- a/module.cpp +++ b/module.cpp @@ -1486,22 +1486,49 @@ lEmitStructDecl(const StructType *st, std::vector *emittedSt fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str()); fprintf(file, "#define __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str()); - fprintf(file, "struct %s", st->GetCStructName().c_str()); + char sSOA[48]; + bool pack, needsAlign = false; + llvm::Type *stype = st->LLVMType(g->ctx); + llvm::DataLayout *DL = g->target->getDataLayout(); + + if (!(pack = llvm::dyn_cast(stype)->isPacked())) + for (int i = 0; !needsAlign && (i < st->GetElementCount()); ++i) { + const Type *ftype = st->GetElementType(i)->GetAsNonConstType(); + needsAlign |= ftype->IsVaryingType() + && (CastType(ftype) == NULL); + } if (st->GetSOAWidth() > 0) // This has to match the naming scheme in // StructType::GetCDeclaration(). - fprintf(file, "_SOA%d", st->GetSOAWidth()); - fprintf(file, " {\n"); - + sprintf(sSOA, "_SOA%d", st->GetSOAWidth()); + else + *sSOA = '\0'; + if (!needsAlign) + fprintf(file, "%sstruct %s%s {\n", (pack)? "packed " : "", + st->GetCStructName().c_str(), sSOA); + else { + unsigned uABI = DL->getABITypeAlignment(stype); + fprintf(file, "__ISPC_ALIGNED_STRUCT__(%u) %s%s {\n", uABI, + st->GetCStructName().c_str(), sSOA); + } for (int i = 0; i < st->GetElementCount(); ++i) { - const Type *type = st->GetElementType(i)->GetAsNonConstType(); - std::string d = type->GetCDeclaration(st->GetElementName(i)); - // Don't expand struct members as their insides will be expanded. - if (type->IsVaryingType() && (CastType(type) == NULL)) { - fprintf(file, " %s[%d];\n", d.c_str(), g->target->getVectorWidth()); + const Type *ftype = st->GetElementType(i)->GetAsNonConstType(); + std::string d = ftype->GetCDeclaration(st->GetElementName(i)); + + fprintf(file, " "); + if (needsAlign && ftype->IsVaryingType() && + (CastType(ftype) == NULL)) { + unsigned uABI = DL->getABITypeAlignment(ftype->LLVMType(g->ctx)); + fprintf(file, "__ISPC_ALIGN__(%u) ", uABI); + } + // Don't expand arrays, pointers and structures: + // their insides will be expanded automatically. + if (!ftype->IsArrayType() && !ftype->IsPointerType() && + ftype->IsVaryingType() && (CastType(ftype) == NULL)) { + fprintf(file, "%s[%d];\n", d.c_str(), g->target->getVectorWidth()); } else { - fprintf(file, " %s;\n", d.c_str()); + fprintf(file, "%s;\n", d.c_str()); } } fprintf(file, "};\n"); @@ -1515,8 +1542,22 @@ lEmitStructDecl(const StructType *st, std::vector *emittedSt static void lEmitStructDecls(std::vector &structTypes, FILE *file, bool emitUnifs=true) { std::vector emittedStructs; + + fprintf(file, + "\n#ifndef __ISPC_ALIGN__\n" + "#if defined(__clang__) || !defined(_MSC_VER)\n" + "// Clang, GCC, ICC\n" + "#define __ISPC_ALIGN__(s) __attribute__((aligned(s)))\n" + "#define __ISPC_ALIGNED_STRUCT__(s) struct __ISPC_ALIGN__(s)\n" + "#else\n" + "// Visual Studio\n" + "#define __ISPC_ALIGN__(s) __declspec(align(s))\n" + "#define __ISPC_ALIGNED_STRUCT__(s) __ISPC_ALIGN__(s) struct\n" + "#endif\n" + "#endif\n\n"); + for (unsigned int i = 0; i < structTypes.size(); ++i) - lEmitStructDecl(structTypes[i], &emittedStructs, file, emitUnifs); + lEmitStructDecl(structTypes[i], &emittedStructs, file, emitUnifs); } diff --git a/run_tests.py b/run_tests.py index d9b753c1..ec756cf8 100755 --- a/run_tests.py +++ b/run_tests.py @@ -194,8 +194,8 @@ def run_test(testname): # We need to figure out the signature of the test # function that this test has. - sig2def = { "f_v(" : 0, "f_f(" : 1, "f_fu(" : 2, "f_fi(" : 3, - "f_du(" : 4, "f_duf(" : 5, "f_di(" : 6 } + sig2def = { "f_v(" : 0, "f_f(" : 1, "f_fu(" : 2, "f_fi(" : 3, + "f_du(" : 4, "f_duf(" : 5, "f_di(" : 6, "f_sz" : 7 } file = open(filename, 'r') match = -1 for line in file: @@ -310,16 +310,16 @@ def run_test(testname): ispc_cmd = ispc_exe_rel + " --woff %s -o %s -O3 --emit-asm --target=%s" % \ (filename4ptx, obj_name, options.target) - - - # compile the ispc code, make the executable, and run it... + ispc_cmd += " -h " + filename + ".h" + cc_cmd += " -DTEST_HEADER=<" + filename + ".h>" (compile_error, run_error) = run_cmds([ispc_cmd, cc_cmd], options.wrapexe + " " + exe_name, \ testname, should_fail) # clean up after running the test try: + os.unlink(filename + ".h") if not options.save_bin: if not run_error: os.unlink(exe_name) diff --git a/test_static.cpp b/test_static.cpp index 412115d0..03ffdac8 100644 --- a/test_static.cpp +++ b/test_static.cpp @@ -51,6 +51,16 @@ #include #endif +#if (TEST_SIG == 7) + #define varying_f_sz f_sz + #define v1_varying_f_sz f_sz + #define v2_varying_f_sz f_sz + #define v4_varying_f_sz f_sz + #define v8_varying_f_sz f_sz + #define v16_varying_f_sz f_sz + #include TEST_HEADER +#endif + extern "C" { extern int width(); extern void f_v(float *result); @@ -103,7 +113,7 @@ void *ISPCAlloc(void **handle, int64_t size, int32_t alignment) { #if defined(_WIN32) || defined(_WIN64) -#define ALIGN +#define ALIGN __declspec(align(64)) #else #define ALIGN __attribute__((aligned(64))) #endif @@ -112,11 +122,11 @@ int main(int argc, char *argv[]) { int w = width(); assert(w <= 64); - float returned_result[64] ALIGN; - float vfloat[64] ALIGN; - double vdouble[64] ALIGN; - int vint[64] ALIGN; - int vint2[64] ALIGN; + ALIGN float returned_result[64]; + ALIGN float vfloat[64]; + ALIGN double vdouble[64]; + ALIGN int vint[64]; + ALIGN int vint2[64]; for (int i = 0; i < 64; ++i) { returned_result[i] = -1e20; @@ -142,6 +152,8 @@ int main(int argc, char *argv[]) { f_duf(returned_result, vdouble, 5.f); #elif (TEST_SIG == 6) f_di(returned_result, vdouble, vint2); +#elif (TEST_SIG == 7) + *returned_result = sizeof(ispc::f_sz); #else #error "Unknown or unset TEST_SIG value" #endif diff --git a/tests/align1.ispc b/tests/align1.ispc new file mode 100644 index 00000000..dd56e502 --- /dev/null +++ b/tests/align1.ispc @@ -0,0 +1,22 @@ +struct InnerUniform { + uniform int i; +}; + +struct f_sz { + uniform int type, temp[5]; + int k[3]; + InnerUniform u; +}; + + + +export void keep_struct_declared(varying f_sz * uniform s) { +} + +export uniform int width() { + return 1; +} + +export void result(uniform float RET[]) { + RET[0] = sizeof(f_sz); +} diff --git a/tests/align2.ispc b/tests/align2.ispc new file mode 100644 index 00000000..344c85f8 --- /dev/null +++ b/tests/align2.ispc @@ -0,0 +1,21 @@ +struct InnerVec { + int i; +}; + +struct f_sz { + InnerVec u; + uniform int tail; +}; + + + +export void keep_struct_declared(varying f_sz * uniform s) { +} + +export uniform int width() { + return 1; +} + +export void result(uniform float RET[]) { + RET[0] = sizeof(f_sz); +}