On Fri, Mar 15, 2013 at 2:55 PM, Sriraman Tallam <tmsri...@google.com> wrote: > Hi, > > This patch is meant for google/gcc-4_7 but I want this to be > considered for trunk when it opens again. This patch makes it easy to > test for code coverage of multiversioned functions. Here is a > motivating example: > > __attribute__((target ("default"))) int foo () { ... return 0; } > __attribute__((target ("sse"))) int foo () { ... return 1; } > __attribute__((target ("popcnt"))) int foo () { ... return 2; } > > int main () > { > return foo(); > } > > Lets say your test CPU supports popcnt. A run of this program will > invoke the popcnt version of foo (). Then, how do we test the sse > version of foo()? To do that for the above example, we need to run > this code on a CPU that has sse support but no popcnt support. > Otherwise, we need to comment out the popcnt version and run this > example. This can get painful when there are many versions. The same > argument applies to testing the default version of foo. > > So, I am introducing the ability to mock a CPU. If the CPU you are > testing on supports sse, you should be able to test the sse version. > > First, I have introduced a new flag called -fmv-debug. This patch > invokes the function version dispatcher every time a call to a foo () > is made. Without that flag, the version dispatch happens once at > startup time via the IFUNC mechanism. > > Also, with -fmv-debug, the version dispatcher uses the two new > builtins "__builtin_mock_cpu_is" and "__builtin_mock_cpu_supports" to > check the cpu type and cpu isa.
With this option, compiler probably can also define some macros so that if user can use to write overriding hooks. > > Then, I plan to add the following hooks to libgcc (in a different patch) : > > int set_mock_cpu_is (const char *cpu); > int set_mock_cpu_supports (const char *isa); > int init_mock_cpu (); // Clear the values of the mock cpu. > > With this support, here is how you can test for code coverage of the > "sse" version and "default version of foo in the above example: > > int main () > { > // Test SSE version. > if (__builtin_cpu_supports ("sse")) > { > init_mock_cpu(); > set_mock_cpu_supports ("sse"); > assert (foo () == 1); > } > // Test default version. > init_mock_cpu(); > assert (foo () == 0); > } > > Invoking a multiversioned binary several times with appropriate mock > cpu values for the various ISAs and CPUs will give the complete code > coverage desired. Ofcourse, the underlying platform should be able to > support the various features. > It is the other way around -- it simplifies unit test writing and running -- one unit test just need to be run on the same hardware (with the most hw features) *ONCE* and all the versions can be covered. > Note that the above test will work only with -fmv-debug as the > dispatcher must be invoked on every multiversioned call to be able to > dynamically change the version. > > Multiple ISA features can be set in the mock cpu by calling > "set_mock_cpu_supports" several times with different ISA names. > Calling "init_mock_cpu" will clear all the values. "set_mock_cpu_is" > will set the CPU type. > Just through about another idea. Is it possible for compiler to create some alias for each version so that they can be accessed explicitly, just like the use of :: ? if (__buitin_cpu_supports ("sse")) CHECK_RESULT (foo_sse (...)); CHECK_RESULT (foo_default(...)); ... David > This patch only includes the gcc changes. I will separately prepare a > patch for the libgcc changes. Right now, since the libgcc changes are > not available the two new mock cpu builtins check the real CPU like > "__builtin_cpu_is" and "__builtin_cpu_supports". > > Patch attached. Please look at mv14_debug_code_coverage.C for an > exhaustive example of testing for code coverage in the presence of > multiple versions. > > Comments please. > > Thanks > Sri