llvm-project
200 строк · 5.4 Кб
1//===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements __udivmoddi4 for the compiler_rt library.
10//
11//===----------------------------------------------------------------------===//
12
13#include "int_lib.h"14
15// Effects: if rem != 0, *rem = a % b
16// Returns: a / b
17
18// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
19
20#if defined(_MSC_VER) && !defined(__clang__)21// MSVC throws a warning about mod 0 here, disable it for builds that
22// warn-as-error
23#pragma warning(push)24#pragma warning(disable : 4723 4724)25#endif26
27COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {28const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;29const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;30udwords n;31n.all = a;32udwords d;33d.all = b;34udwords q;35udwords r;36unsigned sr;37// special cases, X is unknown, K != 038if (n.s.high == 0) {39if (d.s.high == 0) {40// 0 X41// ---42// 0 X43if (rem)44*rem = n.s.low % d.s.low;45return n.s.low / d.s.low;46}47// 0 X48// ---49// K X50if (rem)51*rem = n.s.low;52return 0;53}54// n.s.high != 055if (d.s.low == 0) {56if (d.s.high == 0) {57// K X58// ---59// 0 060if (rem)61*rem = n.s.high % d.s.low;62return n.s.high / d.s.low;63}64// d.s.high != 065if (n.s.low == 0) {66// K 067// ---68// K 069if (rem) {70r.s.high = n.s.high % d.s.high;71r.s.low = 0;72*rem = r.all;73}74return n.s.high / d.s.high;75}76// K K77// ---78// K 079if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ {80if (rem) {81r.s.low = n.s.low;82r.s.high = n.s.high & (d.s.high - 1);83*rem = r.all;84}85return n.s.high >> ctzsi(d.s.high);86}87// K K88// ---89// K 090sr = clzsi(d.s.high) - clzsi(n.s.high);91// 0 <= sr <= n_uword_bits - 2 or sr large92if (sr > n_uword_bits - 2) {93if (rem)94*rem = n.all;95return 0;96}97++sr;98// 1 <= sr <= n_uword_bits - 199// q.all = n.all << (n_udword_bits - sr);100q.s.low = 0;101q.s.high = n.s.low << (n_uword_bits - sr);102// r.all = n.all >> sr;103r.s.high = n.s.high >> sr;104r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);105} else /* d.s.low != 0 */ {106if (d.s.high == 0) {107// K X108// ---109// 0 K110if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ {111if (rem)112*rem = n.s.low & (d.s.low - 1);113if (d.s.low == 1)114return n.all;115sr = ctzsi(d.s.low);116q.s.high = n.s.high >> sr;117q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);118return q.all;119}120// K X121// ---122// 0 K123sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high);124// 2 <= sr <= n_udword_bits - 1125// q.all = n.all << (n_udword_bits - sr);126// r.all = n.all >> sr;127if (sr == n_uword_bits) {128q.s.low = 0;129q.s.high = n.s.low;130r.s.high = 0;131r.s.low = n.s.high;132} else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */ {133q.s.low = 0;134q.s.high = n.s.low << (n_uword_bits - sr);135r.s.high = n.s.high >> sr;136r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);137} else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */ {138q.s.low = n.s.low << (n_udword_bits - sr);139q.s.high = (n.s.high << (n_udword_bits - sr)) |140(n.s.low >> (sr - n_uword_bits));141r.s.high = 0;142r.s.low = n.s.high >> (sr - n_uword_bits);143}144} else {145// K X146// ---147// K K148sr = clzsi(d.s.high) - clzsi(n.s.high);149// 0 <= sr <= n_uword_bits - 1 or sr large150if (sr > n_uword_bits - 1) {151if (rem)152*rem = n.all;153return 0;154}155++sr;156// 1 <= sr <= n_uword_bits157// q.all = n.all << (n_udword_bits - sr);158q.s.low = 0;159if (sr == n_uword_bits) {160q.s.high = n.s.low;161r.s.high = 0;162r.s.low = n.s.high;163} else {164q.s.high = n.s.low << (n_uword_bits - sr);165r.s.high = n.s.high >> sr;166r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);167}168}169}170// Not a special case171// q and r are initialized with:172// q.all = n.all << (n_udword_bits - sr);173// r.all = n.all >> sr;174// 1 <= sr <= n_udword_bits - 1175su_int carry = 0;176for (; sr > 0; --sr) {177// r:q = ((r:q) << 1) | carry178r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));179r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));180q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));181q.s.low = (q.s.low << 1) | carry;182// carry = 0;183// if (r.all >= d.all)184// {185// r.all -= d.all;186// carry = 1;187// }188const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);189carry = s & 1;190r.all -= d.all & s;191}192q.all = (q.all << 1) | carry;193if (rem)194*rem = r.all;195return q.all;196}
197
198#if defined(_MSC_VER) && !defined(__clang__)199#pragma warning(pop)200#endif201