Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
73 changes: 73 additions & 0 deletions arch/riscv/include/asm/alternative-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,77 @@
_ALTERNATIVE_CFG_2(old_content, new_content_1, vendor_id_1, patch_id_1, CONFIG_k_1, \
new_content_2, vendor_id_2, patch_id_2, CONFIG_k_2)

/*
* use_alternative_{likely,unlikely}() returns true if the alternative is
* applied and false otherwise, but in a way where the compiler can optimize
* this check down to a nop instruction that's patched into a jump, or vice
* versa.
*
* Always returns false if the alternatives mechanism is not available.
*
* Usage example:
* if (use_alternative_likely(0, RISCV_ISA_ZBB))
*
* Similar to static keys, "likely" means use a nop if the alternative is
* selected, and jump if unselected; "unlikely" is the other way around.
*/

#ifndef __ASSEMBLER__

#include <linux/types.h>

#ifdef CONFIG_RISCV_ALTERNATIVE

static __always_inline bool use_alternative_likely(u16 vendor_id, u32 patch_id)
{
BUILD_BUG_ON(!__builtin_constant_p(vendor_id));
BUILD_BUG_ON(!__builtin_constant_p(patch_id));

asm goto(ALTERNATIVE("j %l[no_alt]", "nop", %[vendor_id], %[patch_id], 1)
:
: [vendor_id] "i"(vendor_id),
[patch_id] "i"(patch_id)
:
: no_alt);

return true;

no_alt:
return false;
}

static __always_inline bool use_alternative_unlikely(u16 vendor_id, u32 patch_id)
{
BUILD_BUG_ON(!__builtin_constant_p(vendor_id));
BUILD_BUG_ON(!__builtin_constant_p(patch_id));

asm goto(ALTERNATIVE("nop", "j %l[alt]", %[vendor_id], %[patch_id], 1)
:
: [vendor_id] "i"(vendor_id),
[patch_id] "i"(patch_id)
:
: alt);

return false;

alt:
return true;
}

#else

static inline bool use_alternative_likely(u16 vendor_id, u32 patch_id)
{
return false;
}

static inline bool use_alternative_unlikely(u16 vendor_id, u32 patch_id)
{
return false;
}

#endif /* CONFIG_RISCV_ALTERNATIVE */

#endif /* __ASSEMBLER__ */

#endif
42 changes: 18 additions & 24 deletions arch/riscv/include/asm/arch_hweight.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,17 @@
static __always_inline unsigned int __arch_hweight32(unsigned int w)
{
#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
asm (".option push\n"
".option arch,+zbb\n"
CPOPW "%0, %1\n"
".option pop\n"
: "=r" (w) : "r" (w) :);

asm (".option push\n"
".option arch,+zbb\n"
CPOPW "%0, %1\n"
".option pop\n"
: "=r" (w) : "r" (w) :);

return w;

legacy:
return w;
}
#endif

return __sw_hweight32(w);
}

Expand All @@ -51,20 +48,17 @@ static inline unsigned int __arch_hweight8(unsigned int w)
static __always_inline unsigned long __arch_hweight64(__u64 w)
{
#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
asm (".option push\n"
".option arch,+zbb\n"
"cpop %0, %1\n"
".option pop\n"
: "=r" (w) : "r" (w) :);

asm (".option push\n"
".option arch,+zbb\n"
"cpop %0, %1\n"
".option pop\n"
: "=r" (w) : "r" (w) :);

return w;

legacy:
return w;
}
#endif

return __sw_hweight64(w);
}
#else /* BITS_PER_LONG == 64 */
Expand Down
112 changes: 50 additions & 62 deletions arch/riscv/include/asm/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,17 @@

static __always_inline unsigned long variable__ffs(unsigned long word)
{
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);

asm volatile (".option push\n"
".option arch,+zbb\n"
"ctz %0, %1\n"
".option pop\n"
: "=r" (word) : "r" (word) :);

return word;

legacy:
return generic___ffs(word);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
asm volatile (".option push\n"
".option arch,+zbb\n"
"ctz %0, %1\n"
".option pop\n"
: "=r" (word) : "r" (word) :);

return word;
} else {
return generic___ffs(word);
}
}

/**
Expand All @@ -76,20 +73,17 @@ static __always_inline unsigned long variable__ffs(unsigned long word)

static __always_inline unsigned long variable__fls(unsigned long word)
{
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);

asm volatile (".option push\n"
".option arch,+zbb\n"
"clz %0, %1\n"
".option pop\n"
: "=r" (word) : "r" (word) :);

return BITS_PER_LONG - 1 - word;

legacy:
return generic___fls(word);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
asm volatile (".option push\n"
".option arch,+zbb\n"
"clz %0, %1\n"
".option pop\n"
: "=r" (word) : "r" (word) :);

return BITS_PER_LONG - 1 - word;
} else {
return generic___fls(word);
}
}

/**
Expand All @@ -105,23 +99,20 @@ static __always_inline unsigned long variable__fls(unsigned long word)

static __always_inline int variable_ffs(int x)
{
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);

if (!x)
return 0;

asm volatile (".option push\n"
".option arch,+zbb\n"
CTZW "%0, %1\n"
".option pop\n"
: "=r" (x) : "r" (x) :);

return x + 1;

legacy:
return generic_ffs(x);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
if (!x)
return 0;

asm volatile (".option push\n"
".option arch,+zbb\n"
CTZW "%0, %1\n"
".option pop\n"
: "=r" (x) : "r" (x) :);

return x + 1;
} else {
return generic_ffs(x);
}
}

/**
Expand All @@ -137,23 +128,20 @@ static __always_inline int variable_ffs(int x)

static __always_inline int variable_fls(unsigned int x)
{
asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
: : : : legacy);

if (!x)
return 0;

asm volatile (".option push\n"
".option arch,+zbb\n"
CLZW "%0, %1\n"
".option pop\n"
: "=r" (x) : "r" (x) :);

return 32 - x;

legacy:
return generic_fls(x);
if (use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
if (!x)
return 0;

asm volatile (".option push\n"
".option arch,+zbb\n"
CLZW "%0, %1\n"
".option pop\n"
: "=r" (x) : "r" (x) :);

return 32 - x;
} else {
return generic_fls(x);
}
}

/**
Expand Down
13 changes: 4 additions & 9 deletions arch/riscv/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,11 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
* ZBB only saves three instructions on 32-bit and five on 64-bit so not
* worth checking if supported without Alternatives.
*/
if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB)) {
if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) &&
IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB) &&
use_alternative_likely(0, RISCV_ISA_EXT_ZBB)) {
unsigned long fold_temp;

asm goto(ALTERNATIVE("j %l[no_zbb]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
:
:
:
: no_zbb);

if (IS_ENABLED(CONFIG_32BIT)) {
asm(".option push \n\
.option arch,+zbb \n\
Expand All @@ -81,7 +76,7 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
}
return (__force __sum16)(csum >> 16);
}
no_zbb:

#ifndef CONFIG_32BIT
csum += ror64(csum, 32);
csum >>= 32;
Expand Down
Loading
Loading