summaryrefslogtreecommitdiff
path: root/src/fenv/i386/fenv.s
blob: f6036d678499a05b7f504b7509f54cf2f7f1b2b8 (plain) (blame)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
.hidden __hwcap

.global feclearexcept
.type feclearexcept,@function
feclearexcept:	
	mov 4(%esp),%ecx
	and $0x3f,%ecx
	fnstsw %ax
		# consider sse fenv as well if the cpu has XMM capability
	call 1f
1:	addl $__hwcap-1b,(%esp)
	pop %edx
	testl $0x02000000,(%edx)
	jz 2f
		# maintain exceptions in the sse mxcsr, clear x87 exceptions
	test %eax,%ecx
	jz 1f
	fnclex
1:	push %edx
	stmxcsr (%esp)
	pop %edx
	and $0x3f,%eax
	or %eax,%edx
	test %edx,%ecx
	jz 1f
	not %ecx
	and %ecx,%edx
	push %edx
	ldmxcsr (%esp)
	pop %edx
1:	xor %eax,%eax
	ret
		# only do the expensive x87 fenv load/store when needed
2:	test %eax,%ecx
	jz 1b
	not %ecx
	and %ecx,%eax
	test $0x3f,%eax
	jz 1f
	fnclex
	jmp 1b
1:	sub $32,%esp
	fnstenv (%esp)
	mov %al,4(%esp)
	fldenv (%esp)
	add $32,%esp
	xor %eax,%eax
	ret

.global feraiseexcept
.type feraiseexcept,@function
feraiseexcept:	
	mov 4(%esp),%eax
	and $0x3f,%eax
	sub $32,%esp
	fnstenv (%esp)
	or %al,4(%esp)
	fldenv (%esp)
	add $32,%esp
	xor %eax,%eax
	ret

.global __fesetround
.type __fesetround,@function
__fesetround:
	mov 4(%esp),%ecx
	push %eax
	xor %eax,%eax
	fnstcw (%esp)
	andb $0xf3,1(%esp)
	or %ch,1(%esp)
	fldcw (%esp)
		# consider sse fenv as well if the cpu has XMM capability
	call 1f
1:	addl $__hwcap-1b,(%esp)
	pop %edx
	testl $0x02000000,(%edx)
	jz 1f
	stmxcsr (%esp)
	shl $3,%ch
	andb $0x9f,1(%esp)
	or %ch,1(%esp)
	ldmxcsr (%esp)
1:	pop %ecx
	ret

.global fegetround
.type fegetround,@function
fegetround:
	push %eax
	fnstcw (%esp)
	pop %eax
	and $0xc00,%eax
	ret

.global fegetenv
.type fegetenv,@function
fegetenv:
	mov 4(%esp),%ecx
	xor %eax,%eax
	fnstenv (%ecx)
		# consider sse fenv as well if the cpu has XMM capability
	call 1f
1:	addl $__hwcap-1b,(%esp)
	pop %edx
	testl $0x02000000,(%edx)
	jz 1f
	push %eax
	stmxcsr (%esp)
	pop %edx
	and $0x3f,%edx
	or %edx,4(%ecx)
1:	ret

.global fesetenv
.type fesetenv,@function
fesetenv:
	mov 4(%esp),%ecx
	xor %eax,%eax
	inc %ecx
	jz 1f
	fldenv -1(%ecx)
	movl -1(%ecx),%ecx
	jmp 2f
1:	push %eax
	push %eax
	push %eax
	push %eax
	push %eax
	push %eax
	pushl $0x37f
	fldenv (%esp)
	add $28,%esp
		# consider sse fenv as well if the cpu has XMM capability
2:	call 1f
1:	addl $__hwcap-1b,(%esp)
	pop %edx
	testl $0x02000000,(%edx)
	jz 1f
		# mxcsr := same rounding mode, cleared exceptions, default mask
	and $0xc00,%ecx
	shl $3,%ecx
	or $0x1f80,%ecx
	mov %ecx,4(%esp)
	ldmxcsr 4(%esp)
1:	ret

.global fetestexcept
.type fetestexcept,@function
fetestexcept:
	mov 4(%esp),%ecx
	and $0x3f,%ecx
	fnstsw %ax
		# consider sse fenv as well if the cpu has XMM capability
	call 1f
1:	addl $__hwcap-1b,(%esp)
	pop %edx
	testl $0x02000000,(%edx)
	jz 1f
	stmxcsr 4(%esp)
	or 4(%esp),%eax
1:	and %ecx,%eax
	ret