1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* This file is copied from the coreboot repository as part of
* the libpayload project:
*
* Copyright 2014 Google Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common.h>
union overlay64 {
u64 longw;
struct {
u32 lower;
u32 higher;
} words;
};
u64 __ashldi3(u64 num, unsigned int shift)
{
union overlay64 output;
output.longw = num;
if (shift >= 32) {
output.words.higher = output.words.lower << (shift - 32);
output.words.lower = 0;
} else {
if (!shift)
return num;
output.words.higher = (output.words.higher << shift) |
(output.words.lower >> (32 - shift));
output.words.lower = output.words.lower << shift;
}
return output.longw;
}
u64 __lshrdi3(u64 num, unsigned int shift)
{
union overlay64 output;
output.longw = num;
if (shift >= 32) {
output.words.lower = output.words.higher >> (shift - 32);
output.words.higher = 0;
} else {
if (!shift)
return num;
output.words.lower = output.words.lower >> shift |
(output.words.higher << (32 - shift));
output.words.higher = output.words.higher >> shift;
}
return output.longw;
}
#define MAX_32BIT_UINT ((((u64)1) << 32) - 1)
static u64 _64bit_divide(u64 dividend, u64 divider, u64 *rem_p)
{
u64 result = 0;
/*
* If divider is zero - let the rest of the system care about the
* exception.
*/
if (!divider)
return 1 / (u32)divider;
/* As an optimization, let's not use 64 bit division unless we must. */
if (dividend <= MAX_32BIT_UINT) {
if (divider > MAX_32BIT_UINT) {
result = 0;
if (rem_p)
*rem_p = divider;
} else {
result = (u32)dividend / (u32)divider;
if (rem_p)
*rem_p = (u32)dividend % (u32)divider;
}
return result;
}
while (divider <= dividend) {
u64 locald = divider;
u64 limit = __lshrdi3(dividend, 1);
int shifts = 0;
while (locald <= limit) {
shifts++;
locald = locald + locald;
}
result |= __ashldi3(1, shifts);
dividend -= locald;
}
if (rem_p)
*rem_p = dividend;
return result;
}
u64 __udivdi3(u64 num, u64 den)
{
return _64bit_divide(num, den, NULL);
}
u64 __umoddi3(u64 num, u64 den)
{
u64 v = 0;
_64bit_divide(num, den, &v);
return v;
}
|