[ifunc] Use c implementation to compare cpu variant names
Did this for fun but turns out it generates better assembly code.
With a C implementation, compiler can expand both the comparison
loop and cpu_variant_names array. Results in a decision tree like
structure. For example the "cortex-a" prefix common in many variants
will only be compared once.
Test: run bionic unit tests.
Test: use debugger to check which variant is used.
Change-Id: Id70e5536f968161f20b18f35d46430457c338f0f
diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp
index 90eff56..822581c 100644
--- a/libc/arch-arm/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm/dynamic_function_dispatch.cpp
@@ -45,7 +45,7 @@
static constexpr int MAX_CPU_NAME_LEN = 12;
struct CpuVariantNames {
- char name[MAX_CPU_NAME_LEN];
+ alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
CpuVariant variant;
};
@@ -104,11 +104,23 @@
return name; \
}
+static bool is_same_name(const char* a, const char* b) {
+ static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
+ const int* ia = reinterpret_cast<const int*>(a);
+ const int* ib = reinterpret_cast<const int*>(b);
+ for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
+ if (ia[i] != ib[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
static CpuVariant init_cpu_variant() {
int fd = ifunc_open("/dev/cpu_variant:arm");
if (fd < 0) return kGeneric;
- char name[MAX_CPU_NAME_LEN];
+ alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
int bytes_read, total_read = 0;
while (total_read < MAX_CPU_NAME_LEN - 1 &&
@@ -125,12 +137,9 @@
}
name[total_read] = 0;
- typedef int strcmp_func(const char* __lhs, const char* __rhs);
- DECLARE_FUNC(strcmp_func, strcmp_a15);
-
const CpuVariantNames* cpu_variant = cpu_variant_names;
while (cpu_variant->variant != kUnknown) {
- if (strcmp_a15(cpu_variant->name, name) == 0) {
+ if (is_same_name(cpu_variant->name, name)) {
return cpu_variant->variant;
}
cpu_variant++;