Added structure alignment in headers; extended the test system to support alignment tests
This commit is contained in:
63
module.cpp
63
module.cpp
@@ -1486,22 +1486,49 @@ lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedSt
|
|||||||
fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str());
|
fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetCStructName().c_str());
|
||||||
fprintf(file, "#define __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<llvm::StructType>(stype)->isPacked()))
|
||||||
|
for (int i = 0; !needsAlign && (i < st->GetElementCount()); ++i) {
|
||||||
|
const Type *ftype = st->GetElementType(i)->GetAsNonConstType();
|
||||||
|
needsAlign |= ftype->IsVaryingType()
|
||||||
|
&& (CastType<StructType>(ftype) == NULL);
|
||||||
|
}
|
||||||
if (st->GetSOAWidth() > 0)
|
if (st->GetSOAWidth() > 0)
|
||||||
// This has to match the naming scheme in
|
// This has to match the naming scheme in
|
||||||
// StructType::GetCDeclaration().
|
// StructType::GetCDeclaration().
|
||||||
fprintf(file, "_SOA%d", st->GetSOAWidth());
|
sprintf(sSOA, "_SOA%d", st->GetSOAWidth());
|
||||||
fprintf(file, " {\n");
|
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) {
|
for (int i = 0; i < st->GetElementCount(); ++i) {
|
||||||
const Type *type = st->GetElementType(i)->GetAsNonConstType();
|
const Type *ftype = st->GetElementType(i)->GetAsNonConstType();
|
||||||
std::string d = type->GetCDeclaration(st->GetElementName(i));
|
std::string d = ftype->GetCDeclaration(st->GetElementName(i));
|
||||||
// Don't expand struct members as their insides will be expanded.
|
|
||||||
if (type->IsVaryingType() && (CastType<StructType>(type) == NULL)) {
|
fprintf(file, " ");
|
||||||
fprintf(file, " %s[%d];\n", d.c_str(), g->target->getVectorWidth());
|
if (needsAlign && ftype->IsVaryingType() &&
|
||||||
|
(CastType<StructType>(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<StructType>(ftype) == NULL)) {
|
||||||
|
fprintf(file, "%s[%d];\n", d.c_str(), g->target->getVectorWidth());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(file, " %s;\n", d.c_str());
|
fprintf(file, "%s;\n", d.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(file, "};\n");
|
fprintf(file, "};\n");
|
||||||
@@ -1515,8 +1542,22 @@ lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedSt
|
|||||||
static void
|
static void
|
||||||
lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file, bool emitUnifs=true) {
|
lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file, bool emitUnifs=true) {
|
||||||
std::vector<const StructType *> emittedStructs;
|
std::vector<const StructType *> 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)
|
for (unsigned int i = 0; i < structTypes.size(); ++i)
|
||||||
lEmitStructDecl(structTypes[i], &emittedStructs, file, emitUnifs);
|
lEmitStructDecl(structTypes[i], &emittedStructs, file, emitUnifs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
run_tests.py
10
run_tests.py
@@ -194,8 +194,8 @@ def run_test(testname):
|
|||||||
|
|
||||||
# We need to figure out the signature of the test
|
# We need to figure out the signature of the test
|
||||||
# function that this test has.
|
# function that this test has.
|
||||||
sig2def = { "f_v(" : 0, "f_f(" : 1, "f_fu(" : 2, "f_fi(" : 3,
|
sig2def = { "f_v(" : 0, "f_f(" : 1, "f_fu(" : 2, "f_fi(" : 3,
|
||||||
"f_du(" : 4, "f_duf(" : 5, "f_di(" : 6 }
|
"f_du(" : 4, "f_duf(" : 5, "f_di(" : 6, "f_sz" : 7 }
|
||||||
file = open(filename, 'r')
|
file = open(filename, 'r')
|
||||||
match = -1
|
match = -1
|
||||||
for line in file:
|
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" % \
|
ispc_cmd = ispc_exe_rel + " --woff %s -o %s -O3 --emit-asm --target=%s" % \
|
||||||
(filename4ptx, obj_name, options.target)
|
(filename4ptx, obj_name, options.target)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# compile the ispc code, make the executable, and run it...
|
# 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],
|
(compile_error, run_error) = run_cmds([ispc_cmd, cc_cmd],
|
||||||
options.wrapexe + " " + exe_name, \
|
options.wrapexe + " " + exe_name, \
|
||||||
testname, should_fail)
|
testname, should_fail)
|
||||||
|
|
||||||
# clean up after running the test
|
# clean up after running the test
|
||||||
try:
|
try:
|
||||||
|
os.unlink(filename + ".h")
|
||||||
if not options.save_bin:
|
if not options.save_bin:
|
||||||
if not run_error:
|
if not run_error:
|
||||||
os.unlink(exe_name)
|
os.unlink(exe_name)
|
||||||
|
|||||||
@@ -51,6 +51,16 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#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 "C" {
|
||||||
extern int width();
|
extern int width();
|
||||||
extern void f_v(float *result);
|
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)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
#define ALIGN
|
#define ALIGN __declspec(align(64))
|
||||||
#else
|
#else
|
||||||
#define ALIGN __attribute__((aligned(64)))
|
#define ALIGN __attribute__((aligned(64)))
|
||||||
#endif
|
#endif
|
||||||
@@ -112,11 +122,11 @@ int main(int argc, char *argv[]) {
|
|||||||
int w = width();
|
int w = width();
|
||||||
assert(w <= 64);
|
assert(w <= 64);
|
||||||
|
|
||||||
float returned_result[64] ALIGN;
|
ALIGN float returned_result[64];
|
||||||
float vfloat[64] ALIGN;
|
ALIGN float vfloat[64];
|
||||||
double vdouble[64] ALIGN;
|
ALIGN double vdouble[64];
|
||||||
int vint[64] ALIGN;
|
ALIGN int vint[64];
|
||||||
int vint2[64] ALIGN;
|
ALIGN int vint2[64];
|
||||||
|
|
||||||
for (int i = 0; i < 64; ++i) {
|
for (int i = 0; i < 64; ++i) {
|
||||||
returned_result[i] = -1e20;
|
returned_result[i] = -1e20;
|
||||||
@@ -142,6 +152,8 @@ int main(int argc, char *argv[]) {
|
|||||||
f_duf(returned_result, vdouble, 5.f);
|
f_duf(returned_result, vdouble, 5.f);
|
||||||
#elif (TEST_SIG == 6)
|
#elif (TEST_SIG == 6)
|
||||||
f_di(returned_result, vdouble, vint2);
|
f_di(returned_result, vdouble, vint2);
|
||||||
|
#elif (TEST_SIG == 7)
|
||||||
|
*returned_result = sizeof(ispc::f_sz);
|
||||||
#else
|
#else
|
||||||
#error "Unknown or unset TEST_SIG value"
|
#error "Unknown or unset TEST_SIG value"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
22
tests/align1.ispc
Normal file
22
tests/align1.ispc
Normal file
@@ -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);
|
||||||
|
}
|
||||||
21
tests/align2.ispc
Normal file
21
tests/align2.ispc
Normal file
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user