diff --git a/examples/aobench/ao.cpp b/examples/aobench/ao.cpp index 48cfca42..25ad30e4 100644 --- a/examples/aobench/ao.cpp +++ b/examples/aobench/ao.cpp @@ -55,6 +55,7 @@ using namespace ispc; #include "../timing.h" +#include "../cpuid.h" #define NSUBSAMPLES 2 @@ -103,6 +104,38 @@ savePPM(const char *fname, int w, int h) } +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main(int argc, char **argv) { if (argc != 4) { @@ -117,6 +150,8 @@ int main(int argc, char **argv) height = atoi (argv[3]); } + ensureTargetISAIsSupported(); + // Allocate space for output images img = new unsigned char[width * height * 3]; fimg = new float[width * height * 3]; diff --git a/examples/aobench_instrumented/ao.cpp b/examples/aobench_instrumented/ao.cpp index 5037bdc4..addd947e 100644 --- a/examples/aobench_instrumented/ao.cpp +++ b/examples/aobench_instrumented/ao.cpp @@ -56,6 +56,7 @@ using namespace ispc; #include "instrument.h" #include "../timing.h" +#include "../cpuid.h" #define NSUBSAMPLES 2 @@ -102,6 +103,38 @@ savePPM(const char *fname, int w, int h) } +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main(int argc, char **argv) { if (argc != 4) { @@ -116,6 +149,8 @@ int main(int argc, char **argv) height = atoi (argv[3]); } + ensureTargetISAIsSupported(); + // Allocate space for output images img = new unsigned char[width * height * 3]; fimg = new float[width * height * 3]; diff --git a/examples/cpuid.h b/examples/cpuid.h new file mode 100644 index 00000000..f7ab70a8 --- /dev/null +++ b/examples/cpuid.h @@ -0,0 +1,66 @@ +/* + Copyright (c) 2010-2011, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ISPC_CPUID_H +#define ISPC_CPUID_H 1 + +#ifdef _MSC_VER +// Provides a __cpuid() function with same signature as below +#include +#else +static void __cpuid(int info[4], int infoType) { + __asm__ __volatile__ ("cpuid" + : "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3]) + : "0" (infoType)); +} +#endif + +inline bool CPUSupportsSSE2() { + int info[4]; + __cpuid(info, 1); + return (info[3] & (1 << 26)); +} + +inline bool CPUSupportsSSE4() { + int info[4]; + __cpuid(info, 1); + return (info[2] & (1 << 19)); +} + +inline bool CPUSupportsAVX() { + int info[4]; + __cpuid(info, 1); + return (info[2] & (1 << 28)); +} + +#endif // ISPC_CPUID_H diff --git a/examples/mandelbrot/mandelbrot.cpp b/examples/mandelbrot/mandelbrot.cpp index 2105a335..eb32f77e 100644 --- a/examples/mandelbrot/mandelbrot.cpp +++ b/examples/mandelbrot/mandelbrot.cpp @@ -41,6 +41,7 @@ #include #include #include "../timing.h" +#include "../cpuid.h" #include "mandelbrot_ispc.h" using namespace ispc; @@ -66,6 +67,38 @@ writePPM(int *buf, int width, int height, const char *fn) { } +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main() { unsigned int width = 768; unsigned int height = 512; @@ -77,6 +110,8 @@ int main() { int maxIterations = 256; int *buf = new int[width*height]; + ensureTargetISAIsSupported(); + // // Compute the image using the ispc implementation; report the minimum // time of three runs. diff --git a/examples/mandelbrot_tasks/mandelbrot.cpp b/examples/mandelbrot_tasks/mandelbrot.cpp index 50ad4cf8..44b57b76 100644 --- a/examples/mandelbrot_tasks/mandelbrot.cpp +++ b/examples/mandelbrot_tasks/mandelbrot.cpp @@ -41,6 +41,7 @@ #include #include #include "../timing.h" +#include "../cpuid.h" #include "mandelbrot_ispc.h" using namespace ispc; @@ -66,6 +67,38 @@ writePPM(int *buf, int width, int height, const char *fn) { } +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main() { unsigned int width = 1536; unsigned int height = 1024; @@ -74,6 +107,8 @@ int main() { float y0 = -1; float y1 = 1; + ensureTargetISAIsSupported(); + extern void TasksInit(); TasksInit(); diff --git a/examples/options/options.cpp b/examples/options/options.cpp index 5fe48f86..1f58e8eb 100644 --- a/examples/options/options.cpp +++ b/examples/options/options.cpp @@ -41,6 +41,7 @@ using std::max; #include "options_defs.h" #include "../timing.h" +#include "../cpuid.h" #include "options_ispc.h" using namespace ispc; @@ -53,7 +54,41 @@ extern void binomial_put_serial(float Sa[], float Xa[], float Ta[], float ra[], float va[], float result[], int count); +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main() { + ensureTargetISAIsSupported(); + float *S = new float[N_OPTIONS]; float *X = new float[N_OPTIONS]; float *T = new float[N_OPTIONS]; diff --git a/examples/rt/rt.cpp b/examples/rt/rt.cpp index d7a19285..fc798bfb 100644 --- a/examples/rt/rt.cpp +++ b/examples/rt/rt.cpp @@ -44,6 +44,7 @@ #include #include #include "../timing.h" +#include "../cpuid.h" #include "rt_ispc.h" using namespace ispc; @@ -92,12 +93,46 @@ static void writeImage(int *idImage, float *depthImage, int width, int height, } +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: rt \n"); exit(1); } + ensureTargetISAIsSupported(); + #define READ(var, n) \ if (fread(&(var), sizeof(var), n, f) != (unsigned int)n) { \ fprintf(stderr, "Unexpected EOF reading scene file\n"); \ diff --git a/examples/simple/simple.cpp b/examples/simple/simple.cpp index 9542532f..4a760341 100644 --- a/examples/simple/simple.cpp +++ b/examples/simple/simple.cpp @@ -32,12 +32,48 @@ */ #include +#include +#include "../cpuid.h" // Include the header file that the ispc compiler generates #include "simple_ispc.h" using namespace ispc; +// Make sure that the vector ISA used during compilation is supported by +// the processor. The ISPC_TARGET_* macro is set in the ispc-generated +// header file that we include above. +static void +ensureTargetISAIsSupported() { +#if defined(ISPC_TARGET_SSE2) + bool isaSupported = CPUSupportsSSE2(); + const char *target = "SSE2"; +#elif defined(ISPC_TARGET_SSE4) + bool isaSupported = CPUSupportsSSE4(); + const char *target = "SSE4"; +#elif defined(ISPC_TARGET_AVX) + bool isaSupported = CPUSupportsAVX(); + const char *target = "AVX"; +#else +#error "Unknown ISPC_TARGET_* value" +#endif + if (!isaSupported) { + fprintf(stderr, "***\n*** Error: the ispc-compiled code uses the %s instruction " + "set, which isn't\n*** supported by this computer's CPU!\n", target); + fprintf(stderr, "***\n*** Please modify the " +#ifdef _MSC_VER + "MSVC project file " +#else + "Makefile " +#endif + "to select another target (e.g. sse2)\n***\n"); + exit(1); + } +} + + int main() { + ensureTargetISAIsSupported(); + float vin[16], vout[16]; // Initialize input buffer diff --git a/module.cpp b/module.cpp index b09429d8..9daf77cd 100644 --- a/module.cpp +++ b/module.cpp @@ -1316,6 +1316,21 @@ Module::writeHeader(const char *fn) { fprintf(f, "#ifndef %s\n#define %s\n\n", guard.c_str(), guard.c_str()); fprintf(f, "#include \n\n"); + + switch (g->target.isa) { + case Target::SSE2: + fprintf(f, "#define ISPC_TARGET_SSE2\n\n"); + break; + case Target::SSE4: + fprintf(f, "#define ISPC_TARGET_SSE4\n\n"); + break; + case Target::AVX: + fprintf(f, "#define ISPC_TARGET_AVX\n\n"); + break; + default: + FATAL("Unhandled target in header emission"); + } + fprintf(f, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n"); if (g->emitInstrumentation) {