1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "lint.h"
30 #include "base_conversion.h"
31
32 /* The following should be coded as inline expansion templates. */
33
34 /*
35 * Multiplies two normal or subnormal doubles, returns result and exceptions.
36 */
37 double
38 __mul_set(double x, double y, int *pe) {
39 extern void _putsw(), _getsw();
40 int sw;
41 volatile double z;
42
43 _putsw(0);
44 /*
45 * NOTE: By declaring 'z' volatile above, we intend for the
46 * compiler to not move this after the _getmxcsr() call, whose results
47 * are only useful if they immediately follow the multiply.
48 *
49 * From the C11 spec:
50 *
51 * 134 - A volatile declaration may be used to describe an
52 * object corresponding to a memory-mapped input/output port
53 * or an object accessed by an asynchronously interrupting
54 * function. Actions on objects so declared shall by an
55 * implementation or reordered except as permitted by the
56 * rules for evaluating expressions."
57 */
58 z = x * y;
59 _getsw(&sw);
60 if ((sw & 0x3f) == 0) {
61 *pe = 0;
62 } else {
63 /* Result may not be exact. */
64 *pe = 1;
65 }
66 return (z);
67 }
68
69 /*
70 * Divides two normal or subnormal doubles x/y, returns result and exceptions.
71 */
72 double
73 __div_set(double x, double y, int *pe) {
74 extern void _putsw(), _getsw();
75 int sw;
76 volatile double z;
77
78 _putsw(0);
79 /* NOTE: See __mul_set() above, same principle applies here. */
80 z = x / y;
81 _getsw(&sw);
82 if ((sw & 0x3f) == 0) {
83 *pe = 0;
84 } else {
85 *pe = 1;
86 }
87 return (z);
88 }
89
90 double
91 __dabs(double *d)
92 {
93 /* should use hardware fabs instruction */
94 return ((*d < 0.0) ? -*d : *d);
95 }
96
97 /*
98 * Returns IEEE mode/status and
99 * sets up standard environment for base conversion.
100 */
101 void
102 __get_ieee_flags(__ieee_flags_type *b) {
103 extern void _getcw(), _getsw(), _putcw();
104 int cw;
105
106 _getcw(&cw);
107 b->mode = cw;
108 _getsw(&b->status);
109 /*
110 * set CW to...
111 * RC (bits 10:11) 0 == round to nearest even
112 * PC (bits 8:9) 2 == round to double
113 * EM (bits 0:5) 0x3f == all exception trapping masked off
114 */
115 cw = (cw & ~0xf3f) | 0x23f;
116 _putcw(cw);
117 }
118
119 /*
120 * Restores previous IEEE mode/status
121 */
122 void
123 __set_ieee_flags(__ieee_flags_type *b) {
124 extern void _putcw(), _putsw();
125
126 _putcw(b->mode);
127 _putsw(b->status);
128 }