summaryrefslogtreecommitdiff
path: root/libs/pbd/fpu.cc
blob: ae69b62e8d5447ae3d6927e2bc072984f467e71c (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
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <stdint.h>

#include <pbd/fpu.h>
#include <pbd/error.h>

#include "i18n.h"

using namespace PBD;
using namespace std;

FPU::FPU ()
{
	unsigned long cpuflags = 0;

	_flags = Flags (0);

#ifndef ARCH_X86
	return;
#endif
	
#ifndef USE_X86_64_ASM
	asm volatile (
		"mov $1, %%eax\n"
		"pushl %%ebx\n"
		"cpuid\n"
		"movl %%edx, %0\n"
		"popl %%ebx\n"
		: "=r" (cpuflags)
		: 
		: "%eax", "%ecx", "%edx", "memory"
		);
	
#else
	
	asm volatile (
		"pushq %%rbx\n"
		"movq $1, %%rax\n"
		"cpuid\n"
		"movq %%rdx, %0\n"
		"popq %%rbx\n"
		: "=r" (cpuflags)
		: 
		: "%rax", "%rcx", "%rdx", "memory"
		);

#endif /* USE_X86_64_ASM */
	
	if (cpuflags & (1<<25)) {
		_flags = Flags (_flags | (HasSSE|HasFlushToZero));
	}

	if (cpuflags & (1<<26)) {
		_flags = Flags (_flags | HasSSE2);
	}

	if (cpuflags & (1 << 24)) {
		
		char* fxbuf = 0;
		
		if (posix_memalign ((void**)&fxbuf, 16, 512)) {
			error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg;
		} else {
			
			asm volatile (
				"fxsave (%0)"
				:
				: "r" (fxbuf)
				: "memory"
				);
			
			uint32_t mxcsr_mask = *((uint32_t*) &fxbuf[28]);
			
			/* if the mask is zero, set its default value (from intel specs) */
			
			if (mxcsr_mask == 0) {
				mxcsr_mask = 0xffbf;
			}
			
			if (mxcsr_mask & (1<<6)) {
				_flags = Flags (_flags | HasDenormalsAreZero);
			} 

			free (fxbuf);
		}
	}
}			

FPU::~FPU ()
{
}