Merge pull request #811 from wernsaar/develop
[platform/upstream/openblas.git] / common_x86.h
1 /*********************************************************************/
2 /* Copyright 2009, 2010 The University of Texas at Austin.           */
3 /* All rights reserved.                                              */
4 /*                                                                   */
5 /* Redistribution and use in source and binary forms, with or        */
6 /* without modification, are permitted provided that the following   */
7 /* conditions are met:                                               */
8 /*                                                                   */
9 /*   1. Redistributions of source code must retain the above         */
10 /*      copyright notice, this list of conditions and the following  */
11 /*      disclaimer.                                                  */
12 /*                                                                   */
13 /*   2. Redistributions in binary form must reproduce the above      */
14 /*      copyright notice, this list of conditions and the following  */
15 /*      disclaimer in the documentation and/or other materials       */
16 /*      provided with the distribution.                              */
17 /*                                                                   */
18 /*    THIS  SOFTWARE IS PROVIDED  BY THE  UNIVERSITY OF  TEXAS AT    */
19 /*    AUSTIN  ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,    */
20 /*    INCLUDING, BUT  NOT LIMITED  TO, THE IMPLIED  WARRANTIES OF    */
21 /*    MERCHANTABILITY  AND FITNESS FOR  A PARTICULAR  PURPOSE ARE    */
22 /*    DISCLAIMED.  IN  NO EVENT SHALL THE UNIVERSITY  OF TEXAS AT    */
23 /*    AUSTIN OR CONTRIBUTORS BE  LIABLE FOR ANY DIRECT, INDIRECT,    */
24 /*    INCIDENTAL,  SPECIAL, EXEMPLARY,  OR  CONSEQUENTIAL DAMAGES    */
25 /*    (INCLUDING, BUT  NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE    */
26 /*    GOODS  OR  SERVICES; LOSS  OF  USE,  DATA,  OR PROFITS;  OR    */
27 /*    BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON ANY THEORY OF    */
28 /*    LIABILITY, WHETHER  IN CONTRACT, STRICT  LIABILITY, OR TORT    */
29 /*    (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY OUT    */
30 /*    OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF ADVISED  OF  THE    */
31 /*    POSSIBILITY OF SUCH DAMAGE.                                    */
32 /*                                                                   */
33 /* The views and conclusions contained in the software and           */
34 /* documentation are those of the authors and should not be          */
35 /* interpreted as representing official policies, either expressed   */
36 /* or implied, of The University of Texas at Austin.                 */
37 /*********************************************************************/
38
39 #ifndef COMMON_X86
40 #define COMMON_X86
41
42 #ifndef ASSEMBLER
43
44 #ifdef C_MSVC
45 #include <intrin.h>
46 #endif
47
48 #define MB
49 #define WMB
50
51 #ifdef C_SUN
52 #define __asm__ __asm
53 #define __volatile__
54 #endif
55
56 static void __inline blas_lock(volatile BLASULONG *address){
57
58   int ret;
59
60   do {
61     while (*address) {YIELDING;};
62
63 #if defined(_MSC_VER) && !defined(__clang__)
64         // use intrinsic instead of inline assembly
65         ret = _InterlockedExchange((volatile LONG *)address, 1);
66         // inline assembly
67         /*__asm {
68                 mov eax, address
69                 mov ebx, 1
70                 xchg [eax], ebx
71                 mov ret, ebx
72         }*/
73 #else
74     __asm__ __volatile__(
75                          "xchgl %0, %1\n"
76                          : "=r"(ret), "=m"(*address)
77                          : "0"(1), "m"(*address)
78                          : "memory");
79 #endif
80
81   } while (ret);
82
83 }
84 #define BLAS_LOCK_DEFINED
85
86 static __inline unsigned long long rpcc(void){
87 #if defined(_MSC_VER) && !defined(__clang__)
88   return __rdtsc(); // use MSVC intrinsic
89 #else
90   unsigned int a, d;
91
92   __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
93
94   return ((unsigned long long)a + ((unsigned long long)d << 32));
95 #endif
96 };
97 #define RPCC_DEFINED
98
99 static __inline unsigned long getstackaddr(void){
100 #if defined(_MSC_VER) && !defined(__clang__)
101   return (unsigned long)_ReturnAddress(); // use MSVC intrinsic
102 #else
103   unsigned long addr;
104
105   __asm__ __volatile__ ("mov %%esp, %0"
106                          : "=r"(addr) : : "memory");
107
108   return addr;
109 #endif
110 };
111
112
113 static __inline long double sqrt_long(long double val) {
114 #if defined(_MSC_VER) && !defined(__clang__)
115   return sqrt(val); // not sure if this will use fsqrt
116 #else
117   long double result;
118
119   __asm__ __volatile__ ("fldt %1\n"
120                     "fsqrt\n"
121                     "fstpt %0\n" : "=m" (result) : "m"(val));
122   return result;
123 #endif
124 }
125
126 #define SQRT(a)  sqrt_long(a)
127
128 /* This is due to gcc's bug */
129 void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx);
130
131 #define WHEREAMI
132
133 static __inline int WhereAmI(void){
134   int eax, ebx, ecx, edx;
135   int apicid;
136
137   cpuid(1, &eax, &ebx, &ecx, &edx);
138   apicid  = BITMASK(ebx, 24, 0xff);
139
140   return apicid;
141 }
142
143 #ifdef ENABLE_SSE_EXCEPTION
144
145 #define IDEBUG_START \
146 { \
147   unsigned int fp_sse_mode, new_fp_mode; \
148   __asm__ __volatile__ ("stmxcsr %0" : "=m" (fp_sse_mode) : ); \
149   new_fp_mode = fp_sse_mode & ~0xd00; \
150   __asm__ __volatile__ ("ldmxcsr %0" : : "m" (new_fp_mode) );
151
152 #define IDEBUG_END \
153   __asm__ __volatile__ ("ldmxcsr %0" : : "m" (fp_sse_mode) ); \
154 }
155
156 #endif
157
158 #ifdef XDOUBLE
159 #define GET_IMAGE(res)  __asm__ __volatile__("fstpt %0" : "=m"(res) : : "memory")
160 #elif defined(DOUBLE)
161 #define GET_IMAGE(res)  __asm__ __volatile__("fstpl %0" : "=m"(res) : : "memory")
162 #else
163 #define GET_IMAGE(res)  __asm__ __volatile__("fstps %0" : "=m"(res) : : "memory");
164 #endif
165
166 #define GET_IMAGE_CANCEL        __asm__ __volatile__ ("ffree %st")
167
168 #ifdef SMP
169 extern unsigned int blas_quick_divide_table[];
170
171 static __inline int blas_quickdivide(unsigned int x, unsigned int y){
172
173   unsigned int result;
174
175   if (y <= 1) return x;
176
177 #if defined(_MSC_VER) && !defined(__clang__)
178   result = x/y;
179   return result;
180 #else
181
182   y = blas_quick_divide_table[y];
183
184   __asm__ __volatile__  ("mull %0" :"=d" (result) :"a"(x), "0" (y));
185
186   return result;
187 #endif
188 }
189 #endif
190
191 #endif
192
193 #ifndef PAGESIZE
194 #define PAGESIZE        ( 4 << 10)
195 #endif
196 #define HUGE_PAGESIZE   ( 4 << 20)
197
198 #define BUFFER_SIZE     (16 << 20)
199
200 #define SEEK_ADDRESS
201
202 #if defined(DOUBLE) || defined(XDOUBLE)
203 #define MMXLOAD         movq
204 #define MMXSTORE        movq
205 #else
206 #define MMXLOAD         movd
207 #define MMXSTORE        movd
208 #endif
209
210 #if defined(PILEDRIVER) || defined(BULLDOZER) || defined(STEAMROLLER) || defined(EXCAVATOR)
211 //Enable some optimazation for barcelona.
212 #define BARCELONA_OPTIMIZATION
213 #endif
214
215 #if defined(HAVE_3DNOW)
216 #define EMMS    femms
217 #elif defined(HAVE_MMX)
218 #define EMMS    emms
219 #endif
220
221 #ifndef EMMS
222 #define EMMS
223 #endif
224
225 #if defined(CORE2) || defined(PENTIUM4)
226 #define movapd  movaps
227 #endif
228
229 #define BRANCH          .byte 0x3e
230 #define NOBRANCH        .byte 0x2e
231 #define PADDING         .byte 0x66;
232 #define HALT            hlt
233
234 #ifndef COMPLEX
235 #ifdef XDOUBLE
236 #define LOCAL_BUFFER_SIZE  QLOCAL_BUFFER_SIZE
237 #elif defined DOUBLE
238 #define LOCAL_BUFFER_SIZE  DLOCAL_BUFFER_SIZE
239 #else
240 #define LOCAL_BUFFER_SIZE  SLOCAL_BUFFER_SIZE
241 #endif
242 #else
243 #ifdef XDOUBLE
244 #define LOCAL_BUFFER_SIZE  XLOCAL_BUFFER_SIZE
245 #elif defined DOUBLE
246 #define LOCAL_BUFFER_SIZE  ZLOCAL_BUFFER_SIZE
247 #else
248 #define LOCAL_BUFFER_SIZE  CLOCAL_BUFFER_SIZE
249 #endif
250 #endif
251
252 #if defined(OS_WINDOWS)
253 #if   LOCAL_BUFFER_SIZE > 16384
254 #define STACK_TOUCHING \
255         movl    $0,  4096 * 4(%esp);\
256         movl    $0,  4096 * 3(%esp);\
257         movl    $0,  4096 * 2(%esp);\
258         movl    $0,  4096 * 1(%esp);
259 #elif LOCAL_BUFFER_SIZE > 12288
260 #define STACK_TOUCHING \
261         movl    $0,  4096 * 3(%esp);\
262         movl    $0,  4096 * 2(%esp);\
263         movl    $0,  4096 * 1(%esp);
264 #elif LOCAL_BUFFER_SIZE > 8192
265 #define STACK_TOUCHING \
266         movl    $0,  4096 * 2(%esp);\
267         movl    $0,  4096 * 1(%esp);
268 #elif LOCAL_BUFFER_SIZE > 4096
269 #define STACK_TOUCHING \
270         movl    $0,  4096 * 1(%esp);
271 #else
272 #define STACK_TOUCHING
273 #endif
274 #else
275 #define STACK_TOUCHING
276 #endif
277
278 #ifndef F_INTERFACE
279 #define REALNAME ASMNAME
280 #else
281 #define REALNAME ASMFNAME
282 #endif
283
284 #if defined(F_INTERFACE_PATHSCALE) || defined(F_INTERFACE_OPEN64)
285 #define RETURN_BY_STRUCT
286 #elif defined(F_INTERFACE_GFORT) || defined(F_INTERFACE_G95)
287 #define RETURN_BY_COMPLEX
288 #else
289 #define RETURN_BY_STACK
290 #endif
291
292 #ifdef OS_DARWIN
293 #define PROLOGUE .text;.align 5; .globl REALNAME; REALNAME:
294 #define EPILOGUE        .subsections_via_symbols
295 #define PROFCODE
296 #endif
297
298 #if defined(OS_WINNT) || defined(OS_CYGWIN_NT) || defined(OS_INTERIX)
299 #define SAVEREGISTERS \
300         subl    $32, %esp;\
301         movups  %xmm6,    0(%esp);\
302         movups  %xmm7,   16(%esp)
303
304 #define RESTOREREGISTERS \
305         movups     0(%esp), %xmm6;\
306         movups    16(%esp), %xmm7;\
307         addl    $32, %esp
308 #else
309 #define SAVEREGISTERS
310 #define RESTOREREGISTERS
311 #endif
312
313 #if defined(OS_WINNT) || defined(OS_CYGWIN_NT) || defined(OS_INTERIX)
314 #define PROLOGUE \
315         .text; \
316         .align 16; \
317         .globl REALNAME ;\
318         .def REALNAME;.scl      2;.type 32;.endef; \
319 REALNAME:
320
321 #define PROFCODE
322
323 #ifdef __clang__
324 #define EPILOGUE .end
325 #else
326 #define EPILOGUE .end    REALNAME
327 #endif
328 #endif
329
330 #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(__ELF__)
331 #define PROLOGUE \
332         .text; \
333         .align 16; \
334         .globl REALNAME ;\
335        .type REALNAME, @function; \
336 REALNAME:
337
338 #ifdef PROFILE
339 #define PROFCODE call mcount
340 #else
341 #define PROFCODE
342 #endif
343
344 #define EPILOGUE \
345         .size    REALNAME, .-REALNAME; \
346         .section .note.GNU-stack,"",@progbits
347
348 #endif
349
350 #ifdef XDOUBLE
351 #define FLD     fldt
352 #define FST     fstpt
353 #define FSTU    fstt
354 #define FMUL    fmult
355 #define FADD    faddt
356 #define FSUB    fsubt
357 #define FSUBR   fsubrt
358 #elif defined(DOUBLE)
359 #define FLD     fldl
360 #define FST     fstpl
361 #define FSTU    fstl
362 #define FMUL    fmull
363 #define FADD    faddl
364 #define FSUB    fsubl
365 #define FSUBR   fsubrl
366 #else
367 #define FLD     flds
368 #define FST     fstps
369 #define FSTU    fsts
370 #define FMUL    fmuls
371 #define FADD    fadds
372 #define FSUB    fsubs
373 #define FSUBR   fsubrs
374 #endif
375 #endif
376
377 #ifdef C_SUN
378 #define ffreep  fstp
379 #endif
380
381 #ifdef __APPLE__
382 #define ALIGN_2 .align 2
383 #define ALIGN_3 .align 3
384 #define ALIGN_4 .align 4
385 #define ALIGN_5 .align 5
386 #define ffreep  fstp
387 #endif
388
389 #ifndef ALIGN_2
390 #define ALIGN_2 .align 4
391 #endif
392
393 #ifndef ALIGN_3
394 #define ALIGN_3 .align 8
395 #endif
396
397 #ifndef ALIGN_4
398 #define ALIGN_4 .align 16
399 #endif
400
401 #ifndef ALIGN_5
402 #define ALIGN_5 .align 32
403 #endif
404
405 #ifndef ALIGN_6
406 #define ALIGN_6 .align 64
407 #endif
408 // ffreep %st(0).
409 // Because Clang didn't support ffreep, we directly use the opcode.
410 // Please check out http://www.sandpile.org/x86/opc_fpu.htm
411 #ifndef ffreep
412 #define ffreep .byte 0xdf, 0xc0 #
413 #endif