-
Notifications
You must be signed in to change notification settings - Fork 48
Description
When generating the resolver function for function multiversioning, a mechanism is needed to retrieve the environment information.
To achieve this goal, several steps need to be taken:
- Collect the required extensions for a particular function.
- Transform these required extensions into a platform-dependent form.
- Query whether the environment fulfills these requirements during runtime.
Step 1 is handled by the compiler, while step 3 must follow the necessary steps from the platform during runtime.
This RFC aims to propose how the compiler and runtime function can tackle problem 2.
Here is a example
__attribute__((target_clones("default", "arch=rv64gcv"))) int bar() {
return 1;
}
In this example, there are two versions of function bar
. One for default, another for "rv64gcv".
If environment fullfills the requirement, then bar
could use the version arch=rv64gcv
. Otherwise, It invokes with default
version.
This process be controlled by the ifunc
resolver function.
ptr bar.resolver() {
if (isFullFill(...))
return "bar.arch=rv64gcv";
return bar.default;
}
The
isFullFill
should available during the program runtime.
The version arch=rv64gcv
require
i, m, a, f, d, c, v, zicsr, zifencei, zve32f, zve32x, zve64d, zve64f, zve64x, zvl128b, zvl32b, zvl64b,
The problem 2 is about where to maintain the relationship between extension names and platform-dependent probe forms.
Here are three possible approach to achieve goal.
- Encode all required extensions into a string format, then let the platform implement its own probe approach based on the string inside the runtime function. This approach maintains the relationship between extension names and platform-dependent probe forms inside the runtime function.
ptr bar.resolver() {
if (isFullFill("i;m;a;f;d;c;v;zicsr;zifencei;zve32f;zve32x;zve64d;zve64f;zve64x;zvl128b;zvl32b;zvl64b"))
return bar.arch=rv64gcv;
return bar.default;
}
bool isFullFill(char *ReqExts) {
if (isLinux())
return doLinuxRISCVExtensionProbe(ReqExts);
if (isFreeBSD())
return doFreeBSDRISCVExtensionProbe(ReqExts);
// Other platform
....
return false;
}
- Pros
- Human readable
- Relatively high portability
- Provides a uniform interface for all platforms
- Cons
- Requires extra effort for string processing in the runtime function.
- Encode all required extensions into a compiler-defined key, then let the platform implement its own probe approach inside the runtime. This approach maintains the relationship between the compiler-defined key for extensions and the platform-dependent probe form inside the runtime function.
// Assume compiler define
// i -> 1
// m -> 2
...
ptr bar.resolver() {
if (isFullFill([1, 2, 3, 8, ...], length))
return bar.arch=rv64gcv;
return bar.default;
}
bool isFullFill(int *ReqExts, length) {
if (isLinux())
return doLinuxRISCVExtensionProbe(ReqExts, length);
if (isFreeBSD())
return doFreeBSDRISCVExtensionProbe(ReqExts, length);
// Other platform
....
return false;
}
- Pros
- Doesn't require string processing during runtime
- Provides a uniform interface for all platforms
- Cons
- Requires maintaining the relationship between the compiler-defined key for extensions and the concrete extension names inside runtime function.
- Define a different runtime function for each platform and construct any necessary information during compilation time if necessary for the platform. This approach maintains the relationship between extension names and platform-dependent probe forms inside the compiler.
// If compiler compile for linux, then use bar.resolver.linux
ptr bar.resolver.linux() {
if (isFullFillLinux(LinuxProbeObject))
return bar.arch=rv64gcv;
return bar.default;
}
ptr bar.resolver.freebsd() {
if (isFullFillFreeBSD(FreeBSDProbeObject))
return bar.arch=rv64gcv;
return bar.default;
}
// Other platform bar.resolver
...
bool isFullFillLinux(LinuxProbeObject Obj) {
return doLinuxProbe(Obj);
}
bool isFullFillFreeBSD(FreeBSDProbeObject Obj) {
return doFreeBSDProbe(Obj);
}
// Other platform isFullFill
...
- Pros
- Relatively simple implementation for the runtime function
- Cons
- Does not provide a uniform interface for all platforms