18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#include <linux/kernel.h>
38c2ecf20Sopenharmony_ci#include <linux/gcd.h>
48c2ecf20Sopenharmony_ci#include <linux/export.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/*
78c2ecf20Sopenharmony_ci * This implements the binary GCD algorithm. (Often attributed to Stein,
88c2ecf20Sopenharmony_ci * but as Knuth has noted, appears in a first-century Chinese math text.)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This is faster than the division-based algorithm even on x86, which
118c2ecf20Sopenharmony_ci * has decent hardware division.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* If __ffs is available, the even/odd algorithm benchmarks slower. */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/**
198c2ecf20Sopenharmony_ci * gcd - calculate and return the greatest common divisor of 2 unsigned longs
208c2ecf20Sopenharmony_ci * @a: first value
218c2ecf20Sopenharmony_ci * @b: second value
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ciunsigned long gcd(unsigned long a, unsigned long b)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	unsigned long r = a | b;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (!a || !b)
288c2ecf20Sopenharmony_ci		return r;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	b >>= __ffs(b);
318c2ecf20Sopenharmony_ci	if (b == 1)
328c2ecf20Sopenharmony_ci		return r & -r;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	for (;;) {
358c2ecf20Sopenharmony_ci		a >>= __ffs(a);
368c2ecf20Sopenharmony_ci		if (a == 1)
378c2ecf20Sopenharmony_ci			return r & -r;
388c2ecf20Sopenharmony_ci		if (a == b)
398c2ecf20Sopenharmony_ci			return a << __ffs(r);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci		if (a < b)
428c2ecf20Sopenharmony_ci			swap(a, b);
438c2ecf20Sopenharmony_ci		a -= b;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#else
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* If normalization is done by loops, the even/odd algorithm is a win. */
508c2ecf20Sopenharmony_ciunsigned long gcd(unsigned long a, unsigned long b)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned long r = a | b;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (!a || !b)
558c2ecf20Sopenharmony_ci		return r;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* Isolate lsbit of r */
588c2ecf20Sopenharmony_ci	r &= -r;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	while (!(b & r))
618c2ecf20Sopenharmony_ci		b >>= 1;
628c2ecf20Sopenharmony_ci	if (b == r)
638c2ecf20Sopenharmony_ci		return r;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for (;;) {
668c2ecf20Sopenharmony_ci		while (!(a & r))
678c2ecf20Sopenharmony_ci			a >>= 1;
688c2ecf20Sopenharmony_ci		if (a == r)
698c2ecf20Sopenharmony_ci			return r;
708c2ecf20Sopenharmony_ci		if (a == b)
718c2ecf20Sopenharmony_ci			return a;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci		if (a < b)
748c2ecf20Sopenharmony_ci			swap(a, b);
758c2ecf20Sopenharmony_ci		a -= b;
768c2ecf20Sopenharmony_ci		a >>= 1;
778c2ecf20Sopenharmony_ci		if (a & r)
788c2ecf20Sopenharmony_ci			a += b;
798c2ecf20Sopenharmony_ci		a >>= 1;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gcd);
86