Merge tag 'regmap-fix-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux/fpc-iii.git] / fs / erofs / tagptr.h
bloba72897c86744c057240a2ee6fc6461c5cbe19924
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * A tagged pointer implementation
5 * Copyright (C) 2018 Gao Xiang <gaoxiang25@huawei.com>
6 */
7 #ifndef __EROFS_FS_TAGPTR_H
8 #define __EROFS_FS_TAGPTR_H
10 #include <linux/types.h>
11 #include <linux/build_bug.h>
14 * the name of tagged pointer types are tagptr{1, 2, 3...}_t
15 * avoid directly using the internal structs __tagptr{1, 2, 3...}
17 #define __MAKE_TAGPTR(n) \
18 typedef struct __tagptr##n { \
19 uintptr_t v; \
20 } tagptr##n##_t;
22 __MAKE_TAGPTR(1)
23 __MAKE_TAGPTR(2)
24 __MAKE_TAGPTR(3)
25 __MAKE_TAGPTR(4)
27 #undef __MAKE_TAGPTR
29 extern void __compiletime_error("bad tagptr tags")
30 __bad_tagptr_tags(void);
32 extern void __compiletime_error("bad tagptr type")
33 __bad_tagptr_type(void);
35 /* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
36 #define __tagptr_mask_1(ptr, n) \
37 __builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
38 (1UL << (n)) - 1 :
40 #define __tagptr_mask(ptr) (\
41 __tagptr_mask_1(ptr, 1) ( \
42 __tagptr_mask_1(ptr, 2) ( \
43 __tagptr_mask_1(ptr, 3) ( \
44 __tagptr_mask_1(ptr, 4) ( \
45 __bad_tagptr_type(), 0)))))
47 /* generate a tagged pointer from a raw value */
48 #define tagptr_init(type, val) \
49 ((typeof(type)){ .v = (uintptr_t)(val) })
52 * directly cast a tagged pointer to the native pointer type, which
53 * could be used for backward compatibility of existing code.
55 #define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
57 /* encode tagged pointers */
58 #define tagptr_fold(type, ptr, _tags) ({ \
59 const typeof(_tags) tags = (_tags); \
60 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
61 __bad_tagptr_tags(); \
62 tagptr_init(type, (uintptr_t)(ptr) | tags); })
64 /* decode tagged pointers */
65 #define tagptr_unfold_ptr(tptr) \
66 ((void *)((tptr).v & ~__tagptr_mask(tptr)))
68 #define tagptr_unfold_tags(tptr) \
69 ((tptr).v & __tagptr_mask(tptr))
71 /* operations for the tagger pointer */
72 #define tagptr_eq(_tptr1, _tptr2) ({ \
73 typeof(_tptr1) tptr1 = (_tptr1); \
74 typeof(_tptr2) tptr2 = (_tptr2); \
75 (void)(&tptr1 == &tptr2); \
76 (tptr1).v == (tptr2).v; })
78 /* lock-free CAS operation */
79 #define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
80 typeof(_ptptr) ptptr = (_ptptr); \
81 typeof(_o) o = (_o); \
82 typeof(_n) n = (_n); \
83 (void)(&o == &n); \
84 (void)(&o == ptptr); \
85 tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
87 /* wrap WRITE_ONCE if atomic update is needed */
88 #define tagptr_replace_tags(_ptptr, tags) ({ \
89 typeof(_ptptr) ptptr = (_ptptr); \
90 *ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
91 *ptptr; })
93 #define tagptr_set_tags(_ptptr, _tags) ({ \
94 typeof(_ptptr) ptptr = (_ptptr); \
95 const typeof(_tags) tags = (_tags); \
96 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
97 __bad_tagptr_tags(); \
98 ptptr->v |= tags; \
99 *ptptr; })
101 #define tagptr_clear_tags(_ptptr, _tags) ({ \
102 typeof(_ptptr) ptptr = (_ptptr); \
103 const typeof(_tags) tags = (_tags); \
104 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
105 __bad_tagptr_tags(); \
106 ptptr->v &= ~tags; \
107 *ptptr; })
109 #endif /* __EROFS_FS_TAGPTR_H */