What is the return value of test_bit() in <asm/bitops.h> on x86_64?
Hi, I was shocked when I found that `test_bit()` will return -1 or 0 to denote whether a bit is set or not in a bitmap. Looking at its implementation here: ``` static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) { return ((1UL << (nr & (BITS_PER_LONG-1))) & (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; } static inline int variable_test_bit(long nr, volatile const unsigned long *addr) { int oldbit; asm volatile("bt %2,%1\n\t" "sbb %0,%0" : "=r" (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); return oldbit; } ``` The sbb instruction will let `det = dst - (src + CF)`. So it seems that test_bit() will return -1 if a bit is set? And it seems to work that way in my project. However, when I wrote another toy function to test it, I saw that it will return 1 for those bits set. ``` #define TEST_MAX_BITS 512 static void rr_unit_test(struct kvm_vcpu *vcpu) { static u64 counter = 0; int ret; DECLARE_BITMAP(test_map, TEST_MAX_BITS); u64 nr; if (vcpu->vcpu_id != 0) return; if (counter == 0) { ++counter; bitmap_zero(test_map, TEST_MAX_BITS); ret = test_bit(5, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(5, test_map); ret = test_bit(5, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); ret = test_bit(6, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); ret = test_bit(512, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(512, test_map); ret = test_bit(512, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); nr = 448; ret = test_bit(nr, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(nr, test_map); ret = test_bit(nr, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); } } ``` So why will test_bit() behave differently? Thanks very much! Regards, Le Tan
Hi, 2015-12-10 10:20 GMT+08:00 Le Tan <tamlokveer@gmail.com>:
Hi, I was shocked when I found that `test_bit()` will return -1 or 0 to denote whether a bit is set or not in a bitmap. Looking at its implementation here: ``` static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) { return ((1UL << (nr & (BITS_PER_LONG-1))) & (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
static inline int variable_test_bit(long nr, volatile const unsigned long *addr) { int oldbit;
asm volatile("bt %2,%1\n\t" "sbb %0,%0" : "=r" (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr));
return oldbit; } ``` The sbb instruction will let `det = dst - (src + CF)`. So it seems that test_bit() will return -1 if a bit is set? And it seems to work that way in my project.
However, when I wrote another toy function to test it, I saw that it will return 1 for those bits set. ``` #define TEST_MAX_BITS 512
static void rr_unit_test(struct kvm_vcpu *vcpu) { static u64 counter = 0; int ret; DECLARE_BITMAP(test_map, TEST_MAX_BITS); u64 nr;
if (vcpu->vcpu_id != 0) return; if (counter == 0) { ++counter; bitmap_zero(test_map, TEST_MAX_BITS); ret = test_bit(5, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(5, test_map); ret = test_bit(5, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); ret = test_bit(6, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); ret = test_bit(512, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(512, test_map); ret = test_bit(512, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); nr = 448; ret = test_bit(nr, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); set_bit(nr, test_map); ret = test_bit(nr, test_map); printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret); } } ``` So why will test_bit() behave differently? Thanks very much!
Regards, Le Tan
Sorry for my being careless. Though I declared nr variable here, but it is still __builtin_constant_p. So test_bit() will return -1 for those nr which are not builtin constant, and return 1 on the other case. Sorry for my disturbance! :) Regards, Le
participants (1)
-
Le Tan