| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef _BCACHEFS_BKEY_CMP_H | |
| #define _BCACHEFS_BKEY_CMP_H | |
| #include "bkey.h" | |
| #ifdef CONFIG_X86_64 | |
| static inline int __bkey_cmp_bits(const u64 *l, const u64 *r, | |
| unsigned nr_key_bits) | |
| { | |
| long d0, d1, d2, d3; | |
| int cmp; | |
| /* we shouldn't need asm for this, but gcc is being retarded: */ | |
| asm(".intel_syntax noprefix;" | |
| "xor eax, eax;" | |
| "xor edx, edx;" | |
| "1:;" | |
| "mov r8, [rdi];" | |
| "mov r9, [rsi];" | |
| "sub ecx, 64;" | |
| "jl 2f;" | |
| "cmp r8, r9;" | |
| "jnz 3f;" | |
| "lea rdi, [rdi - 8];" | |
| "lea rsi, [rsi - 8];" | |
| "jmp 1b;" | |
| "2:;" | |
| "not ecx;" | |
| "shr r8, 1;" | |
| "shr r9, 1;" | |
| "shr r8, cl;" | |
| "shr r9, cl;" | |
| "cmp r8, r9;" | |
| "3:\n" | |
| "seta al;" | |
| "setb dl;" | |
| "sub eax, edx;" | |
| ".att_syntax prefix;" | |
| : "=&D" (d0), "=&S" (d1), "=&d" (d2), "=&c" (d3), "=&a" (cmp) | |
| : "0" (l), "1" (r), "3" (nr_key_bits) | |
| : "r8", "r9", "cc", "memory"); | |
| return cmp; | |
| } | |
| #else | |
| static inline int __bkey_cmp_bits(const u64 *l, const u64 *r, | |
| unsigned nr_key_bits) | |
| { | |
| u64 l_v, r_v; | |
| if (!nr_key_bits) | |
| return 0; | |
| /* for big endian, skip past header */ | |
| nr_key_bits += high_bit_offset; | |
| l_v = *l & (~0ULL >> high_bit_offset); | |
| r_v = *r & (~0ULL >> high_bit_offset); | |
| while (1) { | |
| if (nr_key_bits < 64) { | |
| l_v >>= 64 - nr_key_bits; | |
| r_v >>= 64 - nr_key_bits; | |
| nr_key_bits = 0; | |
| } else { | |
| nr_key_bits -= 64; | |
| } | |
| if (!nr_key_bits || l_v != r_v) | |
| break; | |
| l = next_word(l); | |
| r = next_word(r); | |
| l_v = *l; | |
| r_v = *r; | |
| } | |
| return cmp_int(l_v, r_v); | |
| } | |
| #endif | |
| static inline __pure __flatten | |
| int __bch2_bkey_cmp_packed_format_checked_inlined(const struct bkey_packed *l, | |
| const struct bkey_packed *r, | |
| const struct btree *b) | |
| { | |
| const struct bkey_format *f = &b->format; | |
| int ret; | |
| EBUG_ON(!bkey_packed(l) || !bkey_packed(r)); | |
| EBUG_ON(b->nr_key_bits != bkey_format_key_bits(f)); | |
| ret = __bkey_cmp_bits(high_word(f, l), | |
| high_word(f, r), | |
| b->nr_key_bits); | |
| EBUG_ON(ret != bpos_cmp(bkey_unpack_pos(b, l), | |
| bkey_unpack_pos(b, r))); | |
| return ret; | |
| } | |
| static inline __pure __flatten | |
| int bch2_bkey_cmp_packed_inlined(const struct btree *b, | |
| const struct bkey_packed *l, | |
| const struct bkey_packed *r) | |
| { | |
| struct bkey unpacked; | |
| if (likely(bkey_packed(l) && bkey_packed(r))) | |
| return __bch2_bkey_cmp_packed_format_checked_inlined(l, r, b); | |
| if (bkey_packed(l)) { | |
| __bkey_unpack_key_format_checked(b, &unpacked, l); | |
| l = (void *) &unpacked; | |
| } else if (bkey_packed(r)) { | |
| __bkey_unpack_key_format_checked(b, &unpacked, r); | |
| r = (void *) &unpacked; | |
| } | |
| return bpos_cmp(((struct bkey *) l)->p, ((struct bkey *) r)->p); | |
| } | |
| #endif /* _BCACHEFS_BKEY_CMP_H */ |