-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[compiler-rt][RISCV] Implement __riscv_ifunc_select #85790
base: main
Are you sure you want to change the base?
Conversation
This patch implement the `__riscv_ifunc_select` base on `Hwprobe/cpuinfo`. ``` unsigned __riscv_ifunc_select(char *FeatStrs); ``` The __riscv_ifunc_select function checks if the features specified in FeatStrs are supported. If all features are available in the current runtime environment, it returns 1. Otherwise, it returns 0.
This patch make #85786 could run some real test. |
#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) | ||
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) | ||
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we align to the newest interface: https://docs.kernel.org/arch/riscv/hwprobe.html?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Are there any processes for GNU/GCC implementation? If we want to port glibc, I think it should be required. |
|
|
||
#endif // defined(__linux__) | ||
|
||
unsigned __riscv_ifunc_select(struct riscv_hwprobe *ReqireKeys, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reqire -> Require
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
|
||
// hwprobe not success | ||
if (initHwProbe(HwprobePairs, 2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the 2 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be replaced with Length from the argument. Fixed.
unsigned Length) { | ||
#if defined(__linux__) | ||
// Init Hwprobe | ||
struct riscv_hwprobe HwprobePairs[64]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does 64 come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It need a big enough buffer to place the key from __riscv_ifunc_select
argument, and pass it into sys_hwprobe
.
For now, the RISCV_HWPROBE_MAX_KEY
is 6.
unsigned Length) { | ||
#if defined(__linux__) | ||
// Init Hwprobe | ||
struct riscv_hwprobe HwprobePairs[Length]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a question: are we allowed to use VLA here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use malloc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if this is the convention of compiler-rt development, I think we should avoid using standard libraries here.
VLA is OK here, I just don't know if we can use this feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect use VLA here may introduce vulnerabilities since we don't have any length check and this could trigger stack overflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or could we define a MAX_PAIR_LENGTH constant here and discard content exceeding that limit before invoking the system call, or simply return false in this situation?
For example:
Something like
#define MAX_PAIR_LENGTH 6
struct riscv_hwprobe HwprobePairs[MAX_PAIR_LENGTH];
if (Length > MAX_PAIR_LENGTH)
Length = MAX_PAIR_LENGTH;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that we limit the number of features in target_clones
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. That limit come from hwprobe system call's key. I expect the compiler will transform the feature inside target_clones
into minimum hwprobe system call pair.
The pair from the arguments of __riscv_ifunc_select could be mapped into a struct riscv_hwprobe
.
For example:
; query for version "arch=rv64im"
// CHECK: @__riscv_hwprobe_args = internal global [2 x %riscv_hwprobe_pair] [%riscv_hwprobe_pair { i64 3, i64 1 }, %riscv_hwprobe_pair { i64 4, i64 0 }]
; query for version "arch=+zbb,+zba,+zbc,+zbkb,+zknd,+zknh,+zksed,+zvksh,+zfh,+zfa,+v"
// CHECK: @__riscv_hwprobe_args.1 = internal global [2 x %riscv_hwprobe_pair.0] [%riscv_hwprobe_pair.0 { i64 3, i64 1 }, %riscv_hwprobe_pair.0 { i64 4, i64 4462766492 }]
// CHECK-LABEL: define weak_odr ptr @foo1.resolver() comdat {
// CHECK-NEXT: resolver_entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @__riscv_hwprobe_args, i32 2)
...
// CHECK-LABEL: define weak_odr ptr @foo2.resolver() comdat {
// CHECK-NEXT: resolver_entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @__riscv_hwprobe_args.1, i32 2)
// CHECK-NEXT: br i1 [[TMP0]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
...
The "arch=+zbb,+zba,+zbc,+zbkb,+zknd,+zknh,+zksed,+zvksh,+zfh,+zfa,+v" version has more features than the "arch=rv64im" version, but only the pair value is updated during __riscv_ifunc_select invocation.
But we need to increase limit when hwprobe support more key for new feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I think the MAX_PAIR_LENGTH
way is OK to me.
Since this resolver function is expected to be available and interchangeable for both I've create one for this PR riscv-non-isa/riscv-c-api-doc#74 and provide the three different candidate approach to achieve the same purpose. |
This patch implement the
__riscv_ifunc_select
base onHwprobe
.The __riscv_ifunc_select function checks if all required keys and their corresponding values from the caller match the hwprobe result. If all features are available in the current runtime environment, it returns 1. Otherwise, it returns 0.