I have an application that is intended to target a wide family of Intel processors, from archaic (Pentium, Pentium II) to modern (Haswell, Skylake). It features specific code paths tailored for the various extensions to the x86 instruction set (SSE, AVX, etc.). However, I only have access to computers dating back to Sandy Bridge and can not verify that the application will actually run on the oldest architectures supported. While it is true that CPUs that old are unlikely to be useful for any purpose, it would be good from a code quality point of view to know that a function named my_routine_sse2
does not accidentally use instructions from SSE3 or such.
What approaches do people usually take when facing this kind of problem? Are there automated tools that will scan functions and ensure illegal instructions are not present? Are there services (web or otherwise) that provide access to legacy computer architectures for testing and debugging?
Make unit tests that can run under bochs, to test all your my_routine_sse2
and so on functions.
You'll still need to test the whole app occasionally, to make sure you didn't screw up the CPU dispatcher, or include some non-baseline instructions outside of functions controlled by your dispatcher.
BTW, function pointers are very good for CPU dispatching. At start-up, check CPUID and set some function pointers. Later functions call through the function pointers to get whatever version of the function the dispatcher chose for this host. Then you don't have a tree of conditional branches everywhere you want to use a function with optimized versions available. x264 (the open source h.264 video encoder) uses this technique for its extensive collection of asm routines.
You're right that your sse2 functions shouldn't go beyond sse2, but if you set your baseline at SSE2, you can use it everywhere without checking. Auto-vectorization can do nice things sometimes. If you use floating point, you can get gcc to use a different ABI where float / double are passed/returned in SSE registers, instead of x87. (Or maybe still passed on the stack, like other things in the outdated 32bit x86 ABI.)
All CPUs for the past ~10 years can run 64bit code, although some people have 32bit Windows on CPUs on newer CPUs. Unfortunately it's still generally required to provide 32bit builds for people with legacy systems.
SSE2 might be a reasonable choice for a baseline, though. The newest CPUs you'd exclude that way are AMD AthlonXP CPUs from just before the first AMD64 k8 cores.