Skip to content

[compiler-rt][RISCV] Implement __init_riscv_feature_bits #85790

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

Merged
merged 33 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
628f3e8
[compiler-rt][RISCV] Implement __riscv_feature_bits/__riscv_vendor_fe…
BeMg Jun 11, 2024
0979c37
Update bitmask
BeMg Jun 13, 2024
e0a712c
Rename ifunc_select with feature_bits
BeMg Jun 13, 2024
bbc63d6
Update comment
BeMg Jun 14, 2024
e43b30c
Extract Implied extension into new help function
BeMg Jun 14, 2024
06309cc
Rename syscall number name
BeMg Jun 26, 2024
f491305
Add static
BeMg Jun 26, 2024
f7231df
Improve format
BeMg Jun 26, 2024
c00722c
Guard by linux marco
BeMg Jun 26, 2024
a378f83
inline sys_riscv_hwprobe
BeMg Jun 26, 2024
3e8d57f
Refine struct riscv_hwprobe Hwprobes init
BeMg Jun 26, 2024
2589b56
Check initHwProbe return value
BeMg Jun 26, 2024
c63a0f6
Align with RISCVFeatures.td
BeMg Jun 26, 2024
2cd7f07
Align bitmask
BeMg Jul 11, 2024
e6058a0
Drop updateImpliedFeatures
BeMg Jul 11, 2024
f090e58
Update RISCV_FEATURE_BITS_LENGTH to 1
BeMg Jul 11, 2024
6abf7dd
Reduce with marco
BeMg Jul 12, 2024
de6f128
Update format
BeMg Jul 12, 2024
425edcb
Remove useless hwprobe length
BeMg Jul 12, 2024
3d0c131
Replace length with RISCV_FEATURE_BITS_LENGTH
BeMg Jul 12, 2024
95e4f54
__init_riscv_features_bit -> __init_riscv_features_bits
BeMg Jul 16, 2024
4d6c0aa
Use 0 instead cpu_set_t* and drop cpu_set_t
BeMg Jul 16, 2024
9d2be8d
Drop RISCV_HWPROBE_WHICH_CPUS
BeMg Jul 16, 2024
35e5d61
Update __init_riscv_feature_bits naming
BeMg Jul 17, 2024
1c2fdab
Make __riscv_feature_bits/__riscv_vendor_feature_bits out of defined(…
BeMg Jul 17, 2024
b6d436d
Move groupid/bitmask out of defined(__linux__)
BeMg Jul 17, 2024
d48e852
fixup format
BeMg Jul 17, 2024
406db36
Move FeaturesBitCached = 1 after __riscv_feature_bits be inited.
BeMg Jul 17, 2024
25b29be
Only store the global object
BeMg Jul 17, 2024
e159608
Init local features
BeMg Jul 17, 2024
31c7b0d
Fixup format
BeMg Jul 17, 2024
c3b5d15
Add comment when hwprobe key is unknown
BeMg Jul 20, 2024
a809208
fixup format
BeMg Jul 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler-rt/lib/builtins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ endif()
set(powerpc64le_SOURCES ${powerpc64_SOURCES})

set(riscv_SOURCES
riscv/feature_bits.c
riscv/fp_mode.c
riscv/save.S
riscv/restore.S
Expand Down
298 changes: 298 additions & 0 deletions compiler-rt/lib/builtins/riscv/feature_bits.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
//=== feature_bits.c - Update RISC-V Feature Bits Structure -*- C -*-=========//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#define RISCV_FEATURE_BITS_LENGTH 1
struct {
unsigned length;
unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
} __riscv_feature_bits __attribute__((visibility("hidden"), nocommon));

#define RISCV_VENDOR_FEATURE_BITS_LENGTH 1
struct {
unsigned vendorID;
unsigned length;
unsigned long long features[RISCV_VENDOR_FEATURE_BITS_LENGTH];
} __riscv_vendor_feature_bits __attribute__((visibility("hidden"), nocommon));

// NOTE: Should sync-up with RISCVFeatures.td
// TODO: Maybe generate a header from tablegen then include it.
#define A_GROUPID 0
#define A_BITMASK (1ULL << 0)
#define C_GROUPID 0
#define C_BITMASK (1ULL << 2)
#define D_GROUPID 0
#define D_BITMASK (1ULL << 3)
#define F_GROUPID 0
#define F_BITMASK (1ULL << 5)
#define I_GROUPID 0
#define I_BITMASK (1ULL << 8)
#define M_GROUPID 0
#define M_BITMASK (1ULL << 12)
#define V_GROUPID 0
#define V_BITMASK (1ULL << 21)
#define ZACAS_GROUPID 0
#define ZACAS_BITMASK (1ULL << 26)
#define ZBA_GROUPID 0
#define ZBA_BITMASK (1ULL << 27)
#define ZBB_GROUPID 0
#define ZBB_BITMASK (1ULL << 28)
#define ZBC_GROUPID 0
#define ZBC_BITMASK (1ULL << 29)
#define ZBKB_GROUPID 0
#define ZBKB_BITMASK (1ULL << 30)
#define ZBKC_GROUPID 0
#define ZBKC_BITMASK (1ULL << 31)
#define ZBKX_GROUPID 0
#define ZBKX_BITMASK (1ULL << 32)
#define ZBS_GROUPID 0
#define ZBS_BITMASK (1ULL << 33)
#define ZFA_GROUPID 0
#define ZFA_BITMASK (1ULL << 34)
#define ZFH_GROUPID 0
#define ZFH_BITMASK (1ULL << 35)
#define ZFHMIN_GROUPID 0
#define ZFHMIN_BITMASK (1ULL << 36)
#define ZICBOZ_GROUPID 0
#define ZICBOZ_BITMASK (1ULL << 37)
#define ZICOND_GROUPID 0
#define ZICOND_BITMASK (1ULL << 38)
#define ZIHINTNTL_GROUPID 0
#define ZIHINTNTL_BITMASK (1ULL << 39)
#define ZIHINTPAUSE_GROUPID 0
#define ZIHINTPAUSE_BITMASK (1ULL << 40)
#define ZKND_GROUPID 0
#define ZKND_BITMASK (1ULL << 41)
#define ZKNE_GROUPID 0
#define ZKNE_BITMASK (1ULL << 42)
#define ZKNH_GROUPID 0
#define ZKNH_BITMASK (1ULL << 43)
#define ZKSED_GROUPID 0
#define ZKSED_BITMASK (1ULL << 44)
#define ZKSH_GROUPID 0
#define ZKSH_BITMASK (1ULL << 45)
#define ZKT_GROUPID 0
#define ZKT_BITMASK (1ULL << 46)
#define ZTSO_GROUPID 0
#define ZTSO_BITMASK (1ULL << 47)
#define ZVBB_GROUPID 0
#define ZVBB_BITMASK (1ULL << 48)
#define ZVBC_GROUPID 0
#define ZVBC_BITMASK (1ULL << 49)
#define ZVFH_GROUPID 0
#define ZVFH_BITMASK (1ULL << 50)
#define ZVFHMIN_GROUPID 0
#define ZVFHMIN_BITMASK (1ULL << 51)
#define ZVKB_GROUPID 0
#define ZVKB_BITMASK (1ULL << 52)
#define ZVKG_GROUPID 0
#define ZVKG_BITMASK (1ULL << 53)
#define ZVKNED_GROUPID 0
#define ZVKNED_BITMASK (1ULL << 54)
#define ZVKNHA_GROUPID 0
#define ZVKNHA_BITMASK (1ULL << 55)
#define ZVKNHB_GROUPID 0
#define ZVKNHB_BITMASK (1ULL << 56)
#define ZVKSED_GROUPID 0
#define ZVKSED_BITMASK (1ULL << 57)
#define ZVKSH_GROUPID 0
#define ZVKSH_BITMASK (1ULL << 58)
#define ZVKT_GROUPID 0
#define ZVKT_BITMASK (1ULL << 59)

#if defined(__linux__)

static long syscall_impl_5_args(long number, long arg1, long arg2, long arg3,
long arg4, long arg5) {
register long a7 __asm__("a7") = number;
register long a0 __asm__("a0") = arg1;
register long a1 __asm__("a1") = arg2;
register long a2 __asm__("a2") = arg3;
register long a3 __asm__("a3") = arg4;
register long a4 __asm__("a4") = arg5;
__asm__ __volatile__("ecall\n\t"
: "=r"(a0)
: "r"(a7), "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
: "memory");
return a0;
}

#define RISCV_HWPROBE_KEY_MVENDORID 0
#define RISCV_HWPROBE_KEY_MARCHID 1
#define RISCV_HWPROBE_KEY_MIMPID 2
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1ULL << 0)
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#define RISCV_HWPROBE_IMA_FD (1ULL << 0)
#define RISCV_HWPROBE_IMA_C (1ULL << 1)
#define RISCV_HWPROBE_IMA_V (1ULL << 2)
#define RISCV_HWPROBE_EXT_ZBA (1ULL << 3)
#define RISCV_HWPROBE_EXT_ZBB (1ULL << 4)
#define RISCV_HWPROBE_EXT_ZBS (1ULL << 5)
#define RISCV_HWPROBE_EXT_ZICBOZ (1ULL << 6)
#define RISCV_HWPROBE_EXT_ZBC (1ULL << 7)
#define RISCV_HWPROBE_EXT_ZBKB (1ULL << 8)
#define RISCV_HWPROBE_EXT_ZBKC (1ULL << 9)
#define RISCV_HWPROBE_EXT_ZBKX (1ULL << 10)
#define RISCV_HWPROBE_EXT_ZKND (1ULL << 11)
#define RISCV_HWPROBE_EXT_ZKNE (1ULL << 12)
#define RISCV_HWPROBE_EXT_ZKNH (1ULL << 13)
#define RISCV_HWPROBE_EXT_ZKSED (1ULL << 14)
#define RISCV_HWPROBE_EXT_ZKSH (1ULL << 15)
#define RISCV_HWPROBE_EXT_ZKT (1ULL << 16)
#define RISCV_HWPROBE_EXT_ZVBB (1ULL << 17)
#define RISCV_HWPROBE_EXT_ZVBC (1ULL << 18)
#define RISCV_HWPROBE_EXT_ZVKB (1ULL << 19)
#define RISCV_HWPROBE_EXT_ZVKG (1ULL << 20)
#define RISCV_HWPROBE_EXT_ZVKNED (1ULL << 21)
#define RISCV_HWPROBE_EXT_ZVKNHA (1ULL << 22)
#define RISCV_HWPROBE_EXT_ZVKNHB (1ULL << 23)
#define RISCV_HWPROBE_EXT_ZVKSED (1ULL << 24)
#define RISCV_HWPROBE_EXT_ZVKSH (1ULL << 25)
#define RISCV_HWPROBE_EXT_ZVKT (1ULL << 26)
#define RISCV_HWPROBE_EXT_ZFH (1ULL << 27)
#define RISCV_HWPROBE_EXT_ZFHMIN (1ULL << 28)
#define RISCV_HWPROBE_EXT_ZIHINTNTL (1ULL << 29)
#define RISCV_HWPROBE_EXT_ZVFH (1ULL << 30)
#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31)
#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1ULL << 0)
#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */

struct riscv_hwprobe {
long long key;
unsigned long long value;
};

#define __NR_riscv_hwprobe 258
static long initHwProbe(struct riscv_hwprobe *Hwprobes, int len) {
return syscall_impl_5_args(__NR_riscv_hwprobe, (long)Hwprobes, len, 0, 0, 0);
}

#define SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(EXTNAME) \
SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_EXT_##EXTNAME, EXTNAME)

#define SET_SINGLE_IMAEXT_RISCV_FEATURE(HWPROBE_BITMASK, EXT) \
SET_SINGLE_RISCV_FEATURE(IMAEXT0Value &HWPROBE_BITMASK, EXT)

#define SET_SINGLE_RISCV_FEATURE(COND, EXT) \
if (COND) { \
SET_RISCV_FEATURE(EXT); \
}

#define SET_RISCV_FEATURE(EXT) features[EXT##_GROUPID] |= EXT##_BITMASK

static void initRISCVFeature(struct riscv_hwprobe Hwprobes[]) {

// Note: If a hwprobe key is unknown to the kernel, its key field
// will be cleared to -1, and its value set to 0.
// This unsets all extension bitmask bits.

// Init vendor extension
__riscv_vendor_feature_bits.length = 0;
__riscv_vendor_feature_bits.vendorID = Hwprobes[2].value;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth a note in the code...

On first glance it looks like there's missing error handling here. The code is actually okay, but that's slightly non-obvious.

You may be on a kernel version which supports hwprobe, but doesn't recognize a given key. In that situation, the documentation says that the syscall will return success, but the key field will be set to -1. This code is relying on the fact that the value field will also be 0 in this case. This happens to work out to having all the bits unset.


// Init standard extension
// TODO: Maybe Extension implied generate from tablegen?
__riscv_feature_bits.length = RISCV_FEATURE_BITS_LENGTH;

unsigned long long features[RISCV_FEATURE_BITS_LENGTH];
int i;

for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; i++)
features[i] = 0;

// Check RISCV_HWPROBE_KEY_BASE_BEHAVIOR
unsigned long long BaseValue = Hwprobes[0].value;
if (BaseValue & RISCV_HWPROBE_BASE_BEHAVIOR_IMA) {
SET_RISCV_FEATURE(I);
SET_RISCV_FEATURE(M);
SET_RISCV_FEATURE(A);
}

// Check RISCV_HWPROBE_KEY_IMA_EXT_0
unsigned long long IMAEXT0Value = Hwprobes[1].value;
if (IMAEXT0Value & RISCV_HWPROBE_IMA_FD) {
SET_RISCV_FEATURE(F);
SET_RISCV_FEATURE(D);
}

SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_IMA_C, C);
SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_IMA_V, V);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBA);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBB);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBS);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZICBOZ);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBC);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKB);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKC);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKX);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKND);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKNE);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKNH);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKSED);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKSH);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKT);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVBB);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVBC);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKB);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKG);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNED);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNHA);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNHB);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKSED);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKSH);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKT);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFH);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFHMIN);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZIHINTNTL);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZIHINTPAUSE);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVFH);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVFHMIN);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFA);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZTSO);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZACAS);
SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZICOND);

for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; i++)
__riscv_feature_bits.features[i] = features[i];
}

#endif // defined(__linux__)

static int FeaturesBitCached = 0;

void __init_riscv_feature_bits() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a missing piece here. The corresponding bit of X86 code (in compiler-rt/lib/builtins/cpu_model/x86.c), uses CONSTRUCTOR_ATTRIBUTE to ensure that the initialization is called early in process lifetime even if an ifunc which explicitly depends invokes the initialization isn't called. I believe we need to do the same thing here. The slightly confusing bit is that aarch64 appears not to do this.


if (FeaturesBitCached)
return;

#if defined(__linux__)
struct riscv_hwprobe Hwprobes[] = {
{RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
{RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
{RISCV_HWPROBE_KEY_MVENDORID, 0},
};
if (initHwProbe(Hwprobes, sizeof(Hwprobes) / sizeof(Hwprobes[0])))
return;

initRISCVFeature(Hwprobes);
#endif // defined(__linux__)

FeaturesBitCached = 1;
}