1.1 --- a/src/cpu/x86/vm/vm_version_x86_32.cpp Thu Feb 19 17:38:53 2009 -0800 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,472 +0,0 @@ 1.4 -/* 1.5 - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. 1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 - * 1.8 - * This code is free software; you can redistribute it and/or modify it 1.9 - * under the terms of the GNU General Public License version 2 only, as 1.10 - * published by the Free Software Foundation. 1.11 - * 1.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 - * version 2 for more details (a copy is included in the LICENSE file that 1.16 - * accompanied this code). 1.17 - * 1.18 - * You should have received a copy of the GNU General Public License version 1.19 - * 2 along with this work; if not, write to the Free Software Foundation, 1.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 - * 1.22 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 - * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 - * have any questions. 1.25 - * 1.26 - */ 1.27 - 1.28 -# include "incls/_precompiled.incl" 1.29 -# include "incls/_vm_version_x86_32.cpp.incl" 1.30 - 1.31 - 1.32 -int VM_Version::_cpu; 1.33 -int VM_Version::_model; 1.34 -int VM_Version::_stepping; 1.35 -int VM_Version::_cpuFeatures; 1.36 -const char* VM_Version::_features_str = ""; 1.37 -VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; 1.38 - 1.39 -static BufferBlob* stub_blob; 1.40 -static const int stub_size = 300; 1.41 - 1.42 -extern "C" { 1.43 - typedef void (*getPsrInfo_stub_t)(void*); 1.44 -} 1.45 -static getPsrInfo_stub_t getPsrInfo_stub = NULL; 1.46 - 1.47 - 1.48 -class VM_Version_StubGenerator: public StubCodeGenerator { 1.49 - public: 1.50 - 1.51 - VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} 1.52 - 1.53 - address generate_getPsrInfo() { 1.54 - // Flags to test CPU type. 1.55 - const uint32_t EFL_AC = 0x40000; 1.56 - const uint32_t EFL_ID = 0x200000; 1.57 - // Values for when we don't have a CPUID instruction. 1.58 - const int CPU_FAMILY_SHIFT = 8; 1.59 - const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); 1.60 - const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); 1.61 - 1.62 - Label detect_486, cpu486, detect_586, std_cpuid1; 1.63 - Label ext_cpuid1, ext_cpuid5, done; 1.64 - 1.65 - StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); 1.66 -# define __ _masm-> 1.67 - 1.68 - address start = __ pc(); 1.69 - 1.70 - // 1.71 - // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info); 1.72 - // 1.73 - __ push(rbp); 1.74 - __ movptr(rbp, Address(rsp, 8)); // cpuid_info address 1.75 - __ push(rbx); 1.76 - __ push(rsi); 1.77 - __ pushf(); // preserve rbx, and flags 1.78 - __ pop(rax); 1.79 - __ push(rax); 1.80 - __ mov(rcx, rax); 1.81 - // 1.82 - // if we are unable to change the AC flag, we have a 386 1.83 - // 1.84 - __ xorl(rax, EFL_AC); 1.85 - __ push(rax); 1.86 - __ popf(); 1.87 - __ pushf(); 1.88 - __ pop(rax); 1.89 - __ cmpptr(rax, rcx); 1.90 - __ jccb(Assembler::notEqual, detect_486); 1.91 - 1.92 - __ movl(rax, CPU_FAMILY_386); 1.93 - __ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax); 1.94 - __ jmp(done); 1.95 - 1.96 - // 1.97 - // If we are unable to change the ID flag, we have a 486 which does 1.98 - // not support the "cpuid" instruction. 1.99 - // 1.100 - __ bind(detect_486); 1.101 - __ mov(rax, rcx); 1.102 - __ xorl(rax, EFL_ID); 1.103 - __ push(rax); 1.104 - __ popf(); 1.105 - __ pushf(); 1.106 - __ pop(rax); 1.107 - __ cmpptr(rcx, rax); 1.108 - __ jccb(Assembler::notEqual, detect_586); 1.109 - 1.110 - __ bind(cpu486); 1.111 - __ movl(rax, CPU_FAMILY_486); 1.112 - __ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax); 1.113 - __ jmp(done); 1.114 - 1.115 - // 1.116 - // at this point, we have a chip which supports the "cpuid" instruction 1.117 - // 1.118 - __ bind(detect_586); 1.119 - __ xorptr(rax, rax); 1.120 - __ cpuid(); 1.121 - __ orptr(rax, rax); 1.122 - __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input 1.123 - // value of at least 1, we give up and 1.124 - // assume a 486 1.125 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); 1.126 - __ movl(Address(rsi, 0), rax); 1.127 - __ movl(Address(rsi, 4), rbx); 1.128 - __ movl(Address(rsi, 8), rcx); 1.129 - __ movl(Address(rsi,12), rdx); 1.130 - 1.131 - __ cmpl(rax, 3); // Is cpuid(0x4) supported? 1.132 - __ jccb(Assembler::belowEqual, std_cpuid1); 1.133 - 1.134 - // 1.135 - // cpuid(0x4) Deterministic cache params 1.136 - // 1.137 - __ movl(rax, 4); // and rcx already set to 0x0 1.138 - __ xorl(rcx, rcx); 1.139 - __ cpuid(); 1.140 - __ push(rax); 1.141 - __ andl(rax, 0x1f); // Determine if valid cache parameters used 1.142 - __ orl(rax, rax); // rax,[4:0] == 0 indicates invalid cache 1.143 - __ pop(rax); 1.144 - __ jccb(Assembler::equal, std_cpuid1); 1.145 - 1.146 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::dcp_cpuid4_offset()))); 1.147 - __ movl(Address(rsi, 0), rax); 1.148 - __ movl(Address(rsi, 4), rbx); 1.149 - __ movl(Address(rsi, 8), rcx); 1.150 - __ movl(Address(rsi,12), rdx); 1.151 - 1.152 - // 1.153 - // Standard cpuid(0x1) 1.154 - // 1.155 - __ bind(std_cpuid1); 1.156 - __ movl(rax, 1); 1.157 - __ cpuid(); 1.158 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); 1.159 - __ movl(Address(rsi, 0), rax); 1.160 - __ movl(Address(rsi, 4), rbx); 1.161 - __ movl(Address(rsi, 8), rcx); 1.162 - __ movl(Address(rsi,12), rdx); 1.163 - 1.164 - __ movl(rax, 0x80000000); 1.165 - __ cpuid(); 1.166 - __ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported? 1.167 - __ jcc(Assembler::belowEqual, done); 1.168 - __ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported? 1.169 - __ jccb(Assembler::belowEqual, ext_cpuid1); 1.170 - __ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported? 1.171 - __ jccb(Assembler::belowEqual, ext_cpuid5); 1.172 - // 1.173 - // Extended cpuid(0x80000008) 1.174 - // 1.175 - __ movl(rax, 0x80000008); 1.176 - __ cpuid(); 1.177 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset()))); 1.178 - __ movl(Address(rsi, 0), rax); 1.179 - __ movl(Address(rsi, 4), rbx); 1.180 - __ movl(Address(rsi, 8), rcx); 1.181 - __ movl(Address(rsi,12), rdx); 1.182 - 1.183 - // 1.184 - // Extended cpuid(0x80000005) 1.185 - // 1.186 - __ bind(ext_cpuid5); 1.187 - __ movl(rax, 0x80000005); 1.188 - __ cpuid(); 1.189 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid5_offset()))); 1.190 - __ movl(Address(rsi, 0), rax); 1.191 - __ movl(Address(rsi, 4), rbx); 1.192 - __ movl(Address(rsi, 8), rcx); 1.193 - __ movl(Address(rsi,12), rdx); 1.194 - 1.195 - // 1.196 - // Extended cpuid(0x80000001) 1.197 - // 1.198 - __ bind(ext_cpuid1); 1.199 - __ movl(rax, 0x80000001); 1.200 - __ cpuid(); 1.201 - __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1_offset()))); 1.202 - __ movl(Address(rsi, 0), rax); 1.203 - __ movl(Address(rsi, 4), rbx); 1.204 - __ movl(Address(rsi, 8), rcx); 1.205 - __ movl(Address(rsi,12), rdx); 1.206 - 1.207 - // 1.208 - // return 1.209 - // 1.210 - __ bind(done); 1.211 - __ popf(); 1.212 - __ pop(rsi); 1.213 - __ pop(rbx); 1.214 - __ pop(rbp); 1.215 - __ ret(0); 1.216 - 1.217 -# undef __ 1.218 - 1.219 - return start; 1.220 - }; 1.221 -}; 1.222 - 1.223 - 1.224 -void VM_Version::get_processor_features() { 1.225 - 1.226 - _cpu = 4; // 486 by default 1.227 - _model = 0; 1.228 - _stepping = 0; 1.229 - _cpuFeatures = 0; 1.230 - _logical_processors_per_package = 1; 1.231 - if (!Use486InstrsOnly) { 1.232 - // Get raw processor info 1.233 - getPsrInfo_stub(&_cpuid_info); 1.234 - assert_is_initialized(); 1.235 - _cpu = extended_cpu_family(); 1.236 - _model = extended_cpu_model(); 1.237 - _stepping = cpu_stepping(); 1.238 - if (cpu_family() > 4) { // it supports CPUID 1.239 - _cpuFeatures = feature_flags(); 1.240 - // Logical processors are only available on P4s and above, 1.241 - // and only if hyperthreading is available. 1.242 - _logical_processors_per_package = logical_processor_count(); 1.243 - } 1.244 - } 1.245 - _supports_cx8 = supports_cmpxchg8(); 1.246 - // if the OS doesn't support SSE, we can't use this feature even if the HW does 1.247 - if( !os::supports_sse()) 1.248 - _cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2); 1.249 - if (UseSSE < 4) { 1.250 - _cpuFeatures &= ~CPU_SSE4_1; 1.251 - _cpuFeatures &= ~CPU_SSE4_2; 1.252 - } 1.253 - if (UseSSE < 3) { 1.254 - _cpuFeatures &= ~CPU_SSE3; 1.255 - _cpuFeatures &= ~CPU_SSSE3; 1.256 - _cpuFeatures &= ~CPU_SSE4A; 1.257 - } 1.258 - if (UseSSE < 2) 1.259 - _cpuFeatures &= ~CPU_SSE2; 1.260 - if (UseSSE < 1) 1.261 - _cpuFeatures &= ~CPU_SSE; 1.262 - 1.263 - if (logical_processors_per_package() == 1) { 1.264 - // HT processor could be installed on a system which doesn't support HT. 1.265 - _cpuFeatures &= ~CPU_HT; 1.266 - } 1.267 - 1.268 - char buf[256]; 1.269 - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 1.270 - cores_per_cpu(), threads_per_core(), 1.271 - cpu_family(), _model, _stepping, 1.272 - (supports_cmov() ? ", cmov" : ""), 1.273 - (supports_cmpxchg8() ? ", cx8" : ""), 1.274 - (supports_fxsr() ? ", fxsr" : ""), 1.275 - (supports_mmx() ? ", mmx" : ""), 1.276 - (supports_sse() ? ", sse" : ""), 1.277 - (supports_sse2() ? ", sse2" : ""), 1.278 - (supports_sse3() ? ", sse3" : ""), 1.279 - (supports_ssse3()? ", ssse3": ""), 1.280 - (supports_sse4_1() ? ", sse4.1" : ""), 1.281 - (supports_sse4_2() ? ", sse4.2" : ""), 1.282 - (supports_mmx_ext() ? ", mmxext" : ""), 1.283 - (supports_3dnow() ? ", 3dnow" : ""), 1.284 - (supports_3dnow2() ? ", 3dnowext" : ""), 1.285 - (supports_sse4a() ? ", sse4a": ""), 1.286 - (supports_ht() ? ", ht": "")); 1.287 - _features_str = strdup(buf); 1.288 - 1.289 - // UseSSE is set to the smaller of what hardware supports and what 1.290 - // the command line requires. I.e., you cannot set UseSSE to 2 on 1.291 - // older Pentiums which do not support it. 1.292 - if( UseSSE > 4 ) UseSSE=4; 1.293 - if( UseSSE < 0 ) UseSSE=0; 1.294 - if( !supports_sse4_1() ) // Drop to 3 if no SSE4 support 1.295 - UseSSE = MIN2((intx)3,UseSSE); 1.296 - if( !supports_sse3() ) // Drop to 2 if no SSE3 support 1.297 - UseSSE = MIN2((intx)2,UseSSE); 1.298 - if( !supports_sse2() ) // Drop to 1 if no SSE2 support 1.299 - UseSSE = MIN2((intx)1,UseSSE); 1.300 - if( !supports_sse () ) // Drop to 0 if no SSE support 1.301 - UseSSE = 0; 1.302 - 1.303 - // On new cpus instructions which update whole XMM register should be used 1.304 - // to prevent partial register stall due to dependencies on high half. 1.305 - // 1.306 - // UseXmmLoadAndClearUpper == true --> movsd(xmm, mem) 1.307 - // UseXmmLoadAndClearUpper == false --> movlpd(xmm, mem) 1.308 - // UseXmmRegToRegMoveAll == true --> movaps(xmm, xmm), movapd(xmm, xmm). 1.309 - // UseXmmRegToRegMoveAll == false --> movss(xmm, xmm), movsd(xmm, xmm). 1.310 - 1.311 - if( is_amd() ) { // AMD cpus specific settings 1.312 - if( supports_sse2() && FLAG_IS_DEFAULT(UseAddressNop) ) { 1.313 - // Use it on new AMD cpus starting from Opteron. 1.314 - UseAddressNop = true; 1.315 - } 1.316 - if( supports_sse2() && FLAG_IS_DEFAULT(UseNewLongLShift) ) { 1.317 - // Use it on new AMD cpus starting from Opteron. 1.318 - UseNewLongLShift = true; 1.319 - } 1.320 - if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { 1.321 - if( supports_sse4a() ) { 1.322 - UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron 1.323 - } else { 1.324 - UseXmmLoadAndClearUpper = false; 1.325 - } 1.326 - } 1.327 - if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { 1.328 - if( supports_sse4a() ) { 1.329 - UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h' 1.330 - } else { 1.331 - UseXmmRegToRegMoveAll = false; 1.332 - } 1.333 - } 1.334 - if( FLAG_IS_DEFAULT(UseXmmI2F) ) { 1.335 - if( supports_sse4a() ) { 1.336 - UseXmmI2F = true; 1.337 - } else { 1.338 - UseXmmI2F = false; 1.339 - } 1.340 - } 1.341 - if( FLAG_IS_DEFAULT(UseXmmI2D) ) { 1.342 - if( supports_sse4a() ) { 1.343 - UseXmmI2D = true; 1.344 - } else { 1.345 - UseXmmI2D = false; 1.346 - } 1.347 - } 1.348 - } 1.349 - 1.350 - if( is_intel() ) { // Intel cpus specific settings 1.351 - if( FLAG_IS_DEFAULT(UseStoreImmI16) ) { 1.352 - UseStoreImmI16 = false; // don't use it on Intel cpus 1.353 - } 1.354 - if( cpu_family() == 6 || cpu_family() == 15 ) { 1.355 - if( FLAG_IS_DEFAULT(UseAddressNop) ) { 1.356 - // Use it on all Intel cpus starting from PentiumPro 1.357 - UseAddressNop = true; 1.358 - } 1.359 - } 1.360 - if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { 1.361 - UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus 1.362 - } 1.363 - if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { 1.364 - if( supports_sse3() ) { 1.365 - UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus 1.366 - } else { 1.367 - UseXmmRegToRegMoveAll = false; 1.368 - } 1.369 - } 1.370 - if( cpu_family() == 6 && supports_sse3() ) { // New Intel cpus 1.371 -#ifdef COMPILER2 1.372 - if( FLAG_IS_DEFAULT(MaxLoopPad) ) { 1.373 - // For new Intel cpus do the next optimization: 1.374 - // don't align the beginning of a loop if there are enough instructions 1.375 - // left (NumberOfLoopInstrToAlign defined in c2_globals.hpp) 1.376 - // in current fetch line (OptoLoopAlignment) or the padding 1.377 - // is big (> MaxLoopPad). 1.378 - // Set MaxLoopPad to 11 for new Intel cpus to reduce number of 1.379 - // generated NOP instructions. 11 is the largest size of one 1.380 - // address NOP instruction '0F 1F' (see Assembler::nop(i)). 1.381 - MaxLoopPad = 11; 1.382 - } 1.383 -#endif // COMPILER2 1.384 - if( FLAG_IS_DEFAULT(UseXMMForArrayCopy) ) { 1.385 - UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus 1.386 - } 1.387 - if( supports_sse4_2() && supports_ht() ) { // Newest Intel cpus 1.388 - if( FLAG_IS_DEFAULT(UseUnalignedLoadStores) && UseXMMForArrayCopy ) { 1.389 - UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus 1.390 - } 1.391 - } 1.392 - } 1.393 - } 1.394 - 1.395 - assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value"); 1.396 - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); 1.397 - 1.398 - // set valid Prefetch instruction 1.399 - if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0; 1.400 - if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3; 1.401 - if( ReadPrefetchInstr == 3 && !supports_3dnow() ) ReadPrefetchInstr = 0; 1.402 - if( !supports_sse() && supports_3dnow() ) ReadPrefetchInstr = 3; 1.403 - 1.404 - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; 1.405 - if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3; 1.406 - if( AllocatePrefetchInstr == 3 && !supports_3dnow() ) AllocatePrefetchInstr=0; 1.407 - if( !supports_sse() && supports_3dnow() ) AllocatePrefetchInstr = 3; 1.408 - 1.409 - // Allocation prefetch settings 1.410 - intx cache_line_size = L1_data_cache_line_size(); 1.411 - if( cache_line_size > AllocatePrefetchStepSize ) 1.412 - AllocatePrefetchStepSize = cache_line_size; 1.413 - if( FLAG_IS_DEFAULT(AllocatePrefetchLines) ) 1.414 - AllocatePrefetchLines = 3; // Optimistic value 1.415 - assert(AllocatePrefetchLines > 0, "invalid value"); 1.416 - if( AllocatePrefetchLines < 1 ) // set valid value in product VM 1.417 - AllocatePrefetchLines = 1; // Conservative value 1.418 - 1.419 - AllocatePrefetchDistance = allocate_prefetch_distance(); 1.420 - AllocatePrefetchStyle = allocate_prefetch_style(); 1.421 - 1.422 - if( AllocatePrefetchStyle == 2 && is_intel() && 1.423 - cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core 1.424 - AllocatePrefetchDistance = 320; 1.425 - } 1.426 - assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); 1.427 - 1.428 -#ifndef PRODUCT 1.429 - if (PrintMiscellaneous && Verbose) { 1.430 - tty->print_cr("Logical CPUs per core: %u", 1.431 - logical_processors_per_package()); 1.432 - tty->print_cr("UseSSE=%d",UseSSE); 1.433 - tty->print("Allocation: "); 1.434 - if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow()) { 1.435 - tty->print_cr("no prefetching"); 1.436 - } else { 1.437 - if (UseSSE == 0 && supports_3dnow()) { 1.438 - tty->print("PREFETCHW"); 1.439 - } else if (UseSSE >= 1) { 1.440 - if (AllocatePrefetchInstr == 0) { 1.441 - tty->print("PREFETCHNTA"); 1.442 - } else if (AllocatePrefetchInstr == 1) { 1.443 - tty->print("PREFETCHT0"); 1.444 - } else if (AllocatePrefetchInstr == 2) { 1.445 - tty->print("PREFETCHT2"); 1.446 - } else if (AllocatePrefetchInstr == 3) { 1.447 - tty->print("PREFETCHW"); 1.448 - } 1.449 - } 1.450 - if (AllocatePrefetchLines > 1) { 1.451 - tty->print_cr(" %d, %d lines with step %d bytes", AllocatePrefetchDistance, AllocatePrefetchLines, AllocatePrefetchStepSize); 1.452 - } else { 1.453 - tty->print_cr(" %d, one line", AllocatePrefetchDistance); 1.454 - } 1.455 - } 1.456 - } 1.457 -#endif // !PRODUCT 1.458 -} 1.459 - 1.460 -void VM_Version::initialize() { 1.461 - ResourceMark rm; 1.462 - // Making this stub must be FIRST use of assembler 1.463 - 1.464 - stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size); 1.465 - if (stub_blob == NULL) { 1.466 - vm_exit_during_initialization("Unable to allocate getPsrInfo_stub"); 1.467 - } 1.468 - CodeBuffer c(stub_blob->instructions_begin(), 1.469 - stub_blob->instructions_size()); 1.470 - VM_Version_StubGenerator g(&c); 1.471 - getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t, 1.472 - g.generate_getPsrInfo()); 1.473 - 1.474 - get_processor_features(); 1.475 -}