static __always_inline unsigned long _compound_head(const struct page *page)
{
unsigned long info = READ_ONCE(page->compound_info);
+ unsigned long mask;
- /* Bit 0 encodes PageTail() */
- if (!(info & 1))
- return (unsigned long)page;
+ if (!compound_info_has_mask()) {
+ /* Bit 0 encodes PageTail() */
+ if (info & 1)
+ return info - 1;
- /*
- * If compound_info_has_mask() is false, the rest of compound_info is
- * the pointer to the head page.
- */
- if (!compound_info_has_mask())
- return info - 1;
+ return (unsigned long)page;
+ }
/*
* If compound_info_has_mask() is true the rest of the info encodes
* the mask that converts the address of the tail page to the head page.
*
* No need to clear bit 0 in the mask as 'page' always has it clear.
+ *
+ * Let's do it in a branchless manner.
*/
- return (unsigned long)page & info;
+
+ /* Non-tail: -1UL, Tail: 0 */
+ mask = (info & 1) - 1;
+
+ /* Non-tail: -1UL, Tail: info */
+ mask |= info;
+
+ return (unsigned long)page & mask;
}
#define compound_head(page) ((typeof(page))_compound_head(page))