Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp467414imm; Wed, 26 Sep 2018 01:33:54 -0700 (PDT) X-Google-Smtp-Source: ACcGV62WYexwnMXFoMCrJRu7BIk1d1YmzdJJscMyDqb/f99uUVlFvWMPdaG9Jfs0M/Tv0Va8AfWd X-Received: by 2002:a62:8c8c:: with SMTP id m134-v6mr5167782pfd.130.1537950834278; Wed, 26 Sep 2018 01:33:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1537950834; cv=none; d=google.com; s=arc-20160816; b=irDjbM80fLSyCnx+H5kPboR2woMztKVS1Tw+WehePRz37qfAQdm0HP+bjLYB+TWbjx UB6iiSX8hAZRFHkHZxSVcwrg6c30wuwIqK0ZXip+q2/I7WUNDBDHw9NljnKxWLyZO8QS shU5Hfnf7ZRQhwmvbmzBX4sYq3Z3w0v7dsgriJBs9LwbyFLvtJOYsV7MSpga31MwtAKX xZzOcJXDxwZTqMexsO3UsSetffyVka6tALH4uMieD90qqpjacGwcGsXO0vfBlyg4QhLA jQzbiQDUJjJQIYJdZ2xea8b374YTO2tdiGt89MJCpuQleE7oSRKxd8TVka2nckMUpgpR YvPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=Ki1eRqJFQzl2hXEoAfjNvJt7p0QtHAb9T8LBqlbaiDA=; b=NzB3upp2YQPZxN0ZUJldZEY+l+7JOydw/RcaJbgUHuroHMUKuE53gRLlNNW4yRyBZm vXuJiO9d1vMuk9zRQYSDeE9zCR/EeAW4z6PxGq0rN/zkrxcmubVlJyC3ujZc50lUrdmv f9JJvddoutIsjAv7Y5YhwAZbGajpAsEecOClMehHf+5TyJE1w55ZsKrEiqjiiFslhSPA GRS10UjzQaWnod1hZWTEn4SzyENI03ysE2AbICmeQF8WRsO7Er0Sty4VM7N0XazHCoh3 e6m/D4TPCdyfJhvQdPSxKCq5r5kR/LKuthyp7R/RdMlMFTw349wUXLprDpqpS/RClRH3 JJGw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=cG9lbJlq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s13-v6si4668459pgi.73.2018.09.26.01.33.39; Wed, 26 Sep 2018 01:33:54 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=cG9lbJlq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727222AbeIZOow (ORCPT + 99 others); Wed, 26 Sep 2018 10:44:52 -0400 Received: from mail-pl1-f193.google.com ([209.85.214.193]:44987 "EHLO mail-pl1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726841AbeIZOov (ORCPT ); Wed, 26 Sep 2018 10:44:51 -0400 Received: by mail-pl1-f193.google.com with SMTP id p25-v6so2482104pli.11 for ; Wed, 26 Sep 2018 01:33:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Ki1eRqJFQzl2hXEoAfjNvJt7p0QtHAb9T8LBqlbaiDA=; b=cG9lbJlq6LEKZpsN8oj8DCDROGxS99Ao4ZTFkCkt/kBNmGiSb+K6SPLZcn/MwLYVfL kVeNfczz756XZ+cEpWbMzrPfJX2TxM6g/PXoXtPPHC++2EU6wQYkIuZDK7dR01a2GxC/ 0C/ixfGA6KA0UeLxACLWny2mCLN9e8sxRExL+RlFT56JeXO/xrjIO7GL5Fm41SOVRZ/K w7ufRIy8erPrdYaCjr//TFy7BAqoIeYSZsT2Lnfk0AgKOnwhKvFx7QGKfPeO/2/OoL03 Yt9rBQDdRBt5eiXOmaL3ifDeg+pfk7kco7Daf/dLNhyOAiAl8EPbfXVnjk31vXMCPHvZ kZSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Ki1eRqJFQzl2hXEoAfjNvJt7p0QtHAb9T8LBqlbaiDA=; b=a3AF2DCfsxommAFGeipaJ84CXSK6H3KPBEPTkG8XXdss7+Oj7RhpuU7YZIvDKp0TGo gSYJp8n2T0Se++ZPTpVZFFluIusXRhuQBH+r+duApmyeloK8s8/B3QJxSwKQcK1fCg8j +Nl0B4kVwuuJuYfUekWwkUJpgaR/XbGvka5kbXP6NOtjlcgAF+G+pfwiZmlXFTz5nu1a CjlEecQr7D+OwEKQNyWcesraCZ8sDmDA4K9uF68EzpVxybgQ3KxB+X4PefUoYKdtZmhx nMX5rECxrar8tP1+4VsZ2vu9FS4cw9PR+f5ppQfYl+NLlZpCYZFdMu/hJPVFv2Jyt7al 6QYA== X-Gm-Message-State: ABuFfojeIy5wKt5R1FjHB16XbPQPcIY70HNC4PeYilV4ZKclGRpx1WDq 7OrS/tVc5D4Y2iCAYx036K8= X-Received: by 2002:a17:902:d216:: with SMTP id t22-v6mr4991728ply.338.1537950783246; Wed, 26 Sep 2018 01:33:03 -0700 (PDT) Received: from app09.andestech.com ([118.163.51.199]) by smtp.gmail.com with ESMTPSA id f15-v6sm5530764pgv.66.2018.09.26.01.33.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 26 Sep 2018 01:33:02 -0700 (PDT) From: Zong Li To: palmer@sifive.com, aou@eecs.berkeley.edu Cc: hch@infradead.org, zong@andestech.com, vincentc@andestech.com, linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Zong Li Subject: [PATCH v2 3/5] lib: Add umoddi3 and udivmoddi4 of GCC library routines Date: Wed, 26 Sep 2018 16:31:12 +0800 Message-Id: <7a24493868f29559a1628eed44af15dc10a9940a.1537949825.git.zongbox@gmail.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add umoddi3 and udivmoddi4 support for 32-bit. The RV32 need the umoddi3 to do modulo when the operands are long long type, like other libraries implementation such as ucmpdi2, lshrdi3 and so on. I encounter the undefined reference 'umoddi3' when I use the in house dma driver, although it is in house driver, but I think that umoddi3 is a common function for RV32. The udivmoddi4 and umoddi3 are copies from libgcc in gcc. There are other functions use the udivmoddi4 in libgcc, so I separate the umoddi3 and udivmoddi4 for flexible extension in the future. Signed-off-by: Zong Li --- lib/Kconfig | 3 + lib/Makefile | 1 + lib/udivmoddi4.c | 309 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/umoddi3.c | 34 ++++++ 4 files changed, 347 insertions(+) create mode 100644 lib/udivmoddi4.c create mode 100644 lib/umoddi3.c diff --git a/lib/Kconfig b/lib/Kconfig index a3928d4..d82f206 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -621,3 +621,6 @@ config GENERIC_LIB_CMPDI2 config GENERIC_LIB_UCMPDI2 bool + +config GENERIC_LIB_UMODDI3 + bool diff --git a/lib/Makefile b/lib/Makefile index ca3f7eb..51bf24d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -271,3 +271,4 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o +obj-$(CONFIG_GENERIC_LIB_UMODDI3) += umoddi3.o udivmoddi4.o diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c new file mode 100644 index 0000000..6518b3a --- /dev/null +++ b/lib/udivmoddi4.c @@ -0,0 +1,309 @@ +/* + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Under Section 7 of GPL version 3, you are granted additional + * permissions described in the GCC Runtime Library Exception, version + * 3.1, as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License and + * a copy of the GCC Runtime Library Exception along with this program; + * see the files COPYING3 and COPYING.RUNTIME respectively. + */ + +#include + +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz(X)) + +#define W_TYPE_SIZE 32 + +#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) + +/* If we still don't have umul_ppmm, define it using plain C. */ +#if !defined(umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + unsigned long __x0, __x1, __x2, __x3; \ + unsigned short __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart(u); \ + __uh = __ll_highpart(u); \ + __vl = __ll_lowpart(v); \ + __vh = __ll_highpart(v); \ + \ + __x0 = (unsigned long) __ul * __vl; \ + __x1 = (unsigned long) __ul * __vh; \ + __x2 = (unsigned long) __uh * __vl; \ + __x3 = (unsigned long) __uh * __vh; \ + \ + __x1 += __ll_highpart(__x0); \ + __x1 += __x2; \ + if (__x1 < __x2) \ + __x3 += __ll_B; \ + \ + (w1) = __x3 + __ll_highpart(__x1); \ + (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ + } while (0) +#endif + +#if !defined(sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + unsigned long __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + unsigned long __d1, __d0, __q1, __q0; \ + unsigned long __r1, __r0, __m; \ + __d1 = __ll_highpart(d); \ + __d0 = __ll_lowpart(d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (unsigned long) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart(n0); \ + if (__r1 < __m) { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) \ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (unsigned long) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart(n0); \ + if (__r0 < __m) { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (unsigned long) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined(udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +unsigned long long __udivmoddi4(unsigned long long u, unsigned long long v, + unsigned long long *rp) +{ + const DWunion nn = {.ll = u }; + const DWunion dd = {.ll = v }; + DWunion rr, ww; + unsigned long d0, d1, n0, n1, n2; + unsigned long q0 = 0, q1 = 0; + unsigned long b, bm; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + + if (d1 == 0) { + if (d0 > n1) { + /* 0q = nn / 0D */ + + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } else { + /* qq = NN / 0d */ + + if (d0 == 0) + /* Divide intentionally by zero. */ + d0 = 1 / d0; + + udiv_qrnnd(q1, n1, 0, n1, d0); + udiv_qrnnd(q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) { + if (d0 > n1) { + /* 0q = nn / 0D */ + + count_leading_zeros(bm, d0); + + if (bm != 0) { + /* + * Normalize, i.e. make the most significant bit + * of the denominator set. + */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } else { + /* qq = NN / 0d */ + + if (d0 == 0) + /* Divide intentionally by zero. */ + d0 = 1 / d0; + + count_leading_zeros(bm, d0); + + if (bm == 0) { + /* + * From (n1 >= d0) /\ (the most significant bit + * of d0 is set), conclude (the most significant + * bit of n1 is set) /\ (theleading quotient + * digit q1 = 1). + * + * This special case is necessary, not an + * optimization. (Shifts counts of W_TYPE_SIZE + * are undefined.) + */ + + n1 -= d0; + q1 = 1; + } else { + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd(q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + } else { + if (d1 > n1) { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + /* 0q = NN / dd */ + + count_leading_zeros(bm, d1); + if (bm == 0) { + /* + * From (n1 >= d1) /\ (the most significant bit + * of d1 is set), conclude (the most significant + * bit of n1 is set) /\ (the quotient digit q0 = + * 0 or 1). + * + * This special case is necessary, not an + * optimization. + */ + + /* + * The condition on the next line takes + * advantage of that n1 >= d1 (true due to + * program flow). + */ + if (n1 > d1 || n0 >= d0) { + q0 = 1; + sub_ddmmss(n1, n0, n1, n0, d1, d0); + } else { + q0 = 0; + } + + q1 = 0; + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + unsigned long m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q0, n1, n2, n1, d1); + umul_ppmm(m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) { + q0--; + sub_ddmmss(m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) { + sub_ddmmss(n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} diff --git a/lib/umoddi3.c b/lib/umoddi3.c new file mode 100644 index 0000000..0134696 --- /dev/null +++ b/lib/umoddi3.c @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Under Section 7 of GPL version 3, you are granted additional + * permissions described in the GCC Runtime Library Exception, version + * 3.1, as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License and + * a copy of the GCC Runtime Library Exception along with this program; + * see the files COPYING3 and COPYING.RUNTIME respectively. + */ + +#include +#include + +extern unsigned long long __udivmoddi4(unsigned long long u, + unsigned long long v, + unsigned long long *rp); + +unsigned long long __umoddi3(unsigned long long u, unsigned long long v) +{ + unsigned long long w; + (void)__udivmoddi4(u, v, &w); + return w; +} +EXPORT_SYMBOL(__umoddi3); -- 2.7.4