aboutsummaryrefslogtreecommitdiff
path: root/core/runtime/internal_linux.odin
blob: 19b52a42a369059134f48291760899a8b3495672 (plain)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package runtime

import "intrinsics"

@(link_name="__umodti3")
umodti3 :: proc "c" (a, b: u128) -> u128 {
	r: u128 = ---;
	_ = udivmod128(a, b, &r);
	return r;
}


@(link_name="__udivmodti4")
udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
	return udivmod128(a, b, rem);
}

@(link_name="__udivti3")
udivti3 :: proc "c" (a, b: u128) -> u128 {
	return udivmodti4(a, b, nil);
}


@(link_name="__modti3")
modti3 :: proc "c" (a, b: i128) -> i128 {
	s_a := a >> (128 - 1);
	s_b := b >> (128 - 1);
	an := (a ~ s_a) - s_a;
	bn := (b ~ s_b) - s_b;

	r: u128 = ---;
	_ = udivmod128(transmute(u128)an, transmute(u128)bn, &r);
	return (transmute(i128)r ~ s_a) - s_a;
}


@(link_name="__divmodti4")
divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 {
	u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem);
	return transmute(i128)u;
}

@(link_name="__divti3")
divti3 :: proc "c" (a, b: i128) -> i128 {
	u := udivmodti4(transmute(u128)a, transmute(u128)b, nil);
	return transmute(i128)u;
}


@(link_name="__fixdfti")
fixdfti :: proc(a: u64) -> i128 {
	significandBits :: 52;
	typeWidth       :: (size_of(u64)*8);
	exponentBits    :: (typeWidth - significandBits - 1);
	maxExponent     :: ((1 << exponentBits) - 1);
	exponentBias    :: (maxExponent >> 1);

	implicitBit     :: (u64(1) << significandBits);
	significandMask :: (implicitBit - 1);
	signBit         :: (u64(1) << (significandBits + exponentBits));
	absMask         :: (signBit - 1);
	exponentMask    :: (absMask ~ significandMask);

	// Break a into sign, exponent, significand
	aRep := a;
	aAbs := aRep & absMask;
	sign := i128(-1 if aRep & signBit != 0 else 1);
	exponent := u64((aAbs >> significandBits) - exponentBias);
	significand := u64((aAbs & significandMask) | implicitBit);

	// If exponent is negative, the result is zero.
	if exponent < 0 {
		return 0;
	}

	// If the value is too large for the integer type, saturate.
	if exponent >= size_of(i128) * 8 {
		return max(i128) if sign == 1 else min(i128);
	}

	// If 0 <= exponent < significandBits, right shift to get the result.
	// Otherwise, shift left.
	if exponent < significandBits {
		return sign * i128(significand >> (significandBits - exponent));
	} else {
		return sign * (i128(significand) << (exponent - significandBits));
	}

}

@(link_name="__floattidf")
floattidf :: proc(a: i128) -> f64 {
	DBL_MANT_DIG :: 53;
	if a == 0 {
		return 0.0;
	}
	a := a;
	N :: size_of(i128) * 8;
	s := a >> (N-1);
	a = (a ~ s) - s;
	sd: = N - intrinsics.count_leading_zeros(a);  // number of significant digits
	e := u32(sd - 1);        // exponent
	if sd > DBL_MANT_DIG {
		switch sd {
		case DBL_MANT_DIG + 1:
			a <<= 1;
		case DBL_MANT_DIG + 2:
			// okay
		case:
			a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) |
				i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0);
		};

		a |= i128((a & 4) != 0);
		a += 1;
		a >>= 2;

		if a & (1 << DBL_MANT_DIG) != 0 {
			a >>= 1;
			e += 1;
		}
	} else {
		a <<= u128(DBL_MANT_DIG - sd);
	}
	fb: [2]u32;
	fb[1] = (u32(s) & 0x80000000) |           // sign
	        ((e + 1023) << 20)    |           // exponent
	        u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high
	fb[1] = u32(a);                           // mantissa-low
	return transmute(f64)fb;
}