xref: /illumos-gate/usr/src/lib/libc/i386/fp/_base_il.S (revision 12fb9219923f41528f673d4f31667db2c3f103ff)
1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
14 */
15
16	.file	"_base_il.s"
17
18/*
19 * These files are in assembly because some compilers will mistakenly reorder
20 * multiplications or divisions wrapped in _putsw() and _getsw().  They are
21 * proper subroutines for now, but should be considered candidates for
22 * inlining eventually.
23 *
24 * The original C sources are included for readability in the pre-function
25 * comment blocks.
26 */
27
28#include <SYS.h>
29
30/*
31 * Multiplies two normal or subnormal doubles, returns result and exceptions.
32 *
33
34double
35__mul_set(double x, double y, int *pe) {
36	extern void _putsw(), _getsw();
37	int sw;
38	double z;
39
40	_putsw(0);
41	z = x * y;
42	_getsw(&sw);
43	if ((sw & 0x3f) == 0) {
44		*pe = 0;
45	} else {
46		*pe = 1;
47	}
48	return (z);
49}
50
51 */
52	ENTRY(__mul_set)
53	subl	$0x8, %esp	/* Give us an extra 8 bytes to play with. */
54	/* Clear the floating point exception register. */
55	fnclex			/* Equivalent of _putsw(0); */
56
57	fldl	0xc(%esp)	/* Load up x */
58	fmull	0x14(%esp)	/* And multiply! */
59
60	/* Check to see if the multiply caused any exceptions. */
61	fstsw	(%esp)		/* Equivalent of... */
62	xorl	%edx, %edx
63	andl	$0x3f, (%esp)	/* If the status word (low bits) are zero... */
64	setne	%dl		/* ... set *pe (aka. (%eax)) accordingly. */
65	movl	0x1c(%esp), %eax/* Get pe. */
66	movl	%edx, (%eax)	/* And set it.  (True == FP exception). */
67	addl	$0x8, %esp	/* Release the 8 play bytes. */
68	ret
69	SET_SIZE(__mul_set)
70
71/*
72 * Divides two normal or subnormal doubles x/y, returns result and exceptions.
73 *
74
75double
76__div_set(double x, double y, int *pe) {
77	extern void _putsw(), _getsw();
78	int sw;
79	double z;
80
81	_putsw(0);
82	z = x / y;
83	_getsw(&sw);
84	if ((sw & 0x3f) == 0) {
85		*pe = 0;
86	} else {
87		*pe = 1;
88	}
89	return (z);
90}
91
92 */
93
94	ENTRY(__div_set)
95	subl	$0x8, %esp	/* Give us an extra 8 bytes to play with. */
96	/* Clear the floating point exception register. */
97	fnclex			/* Equivalent of _putsw(0); */
98
99	fldl	0xc(%esp)	/* Load up x */
100	fdivl	0x14(%esp)	/* And divide! */
101
102	/* Check to see if the divide caused any exceptions. */
103	fstsw	(%esp)		/* Equivalent of... */
104	xorl	%edx, %edx
105	andl	$0x3f, (%esp)	/* If the status word (low bits) are zero... */
106	setne	%dl		/* ... set *pe (aka. (%eax)) accordingly. */
107	movl	0x1c(%esp), %eax/* Get pe. */
108	movl	%edx, (%eax)	/* And set it.  (True == FP exception). */
109	addl	$0x8, %esp	/* Release the 8 play bytes. */
110	ret
111	SET_SIZE(__div_set)
112
113/* double __dabs(double *d) - Get the abs. value of *d.  Straightforward. */
114
115	ENTRY(__dabs)
116	movl	0x4(%esp), %eax
117	fldl	(%eax)
118	fabs			/* Just let the FPU do its thing. */
119	ret
120	SET_SIZE(__dabs)
121