| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  | require "os/mac/pathname" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Hardware | 
					
						
							|  |  |  |   class CPU | 
					
						
							|  |  |  |     class << self | 
					
						
							| 
									
										
										
										
											2016-07-06 10:43:54 +01:00
										 |  |  |       PPC_OPTIMIZATION_FLAGS = { | 
					
						
							| 
									
										
										
										
											2016-09-17 15:32:44 +01:00
										 |  |  |         g3: "-mcpu=750", | 
					
						
							|  |  |  |         g4: "-mcpu=7400", | 
					
						
							|  |  |  |         g4e: "-mcpu=7450", | 
					
						
							|  |  |  |         g5: "-mcpu=970", | 
					
						
							|  |  |  |         g5_64: "-mcpu=970 -arch ppc64", | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |       }.freeze | 
					
						
							|  |  |  |       def optimization_flags | 
					
						
							| 
									
										
										
										
											2016-07-06 10:43:54 +01:00
										 |  |  |         OPTIMIZATION_FLAGS.merge(PPC_OPTIMIZATION_FLAGS) | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # These methods use info spewed out by sysctl. | 
					
						
							|  |  |  |       # Look in <mach/machine.h> for decoding info. | 
					
						
							|  |  |  |       def type | 
					
						
							|  |  |  |         case sysctl_int("hw.cputype") | 
					
						
							|  |  |  |         when 7
 | 
					
						
							|  |  |  |           :intel | 
					
						
							|  |  |  |         when 18
 | 
					
						
							|  |  |  |           :ppc | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           :dunno | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def family | 
					
						
							|  |  |  |         if intel? | 
					
						
							|  |  |  |           case sysctl_int("hw.cpufamily") | 
					
						
							|  |  |  |           when 0x73d67300 # Yonah: Core Solo/Duo | 
					
						
							|  |  |  |             :core | 
					
						
							|  |  |  |           when 0x426f69ef # Merom: Core 2 Duo | 
					
						
							|  |  |  |             :core2 | 
					
						
							|  |  |  |           when 0x78ea4fbc # Penryn | 
					
						
							|  |  |  |             :penryn | 
					
						
							|  |  |  |           when 0x6b5a4cd2 # Nehalem | 
					
						
							|  |  |  |             :nehalem | 
					
						
							|  |  |  |           when 0x573B5EEC # Arrandale | 
					
						
							|  |  |  |             :arrandale | 
					
						
							|  |  |  |           when 0x5490B78C # Sandy Bridge | 
					
						
							|  |  |  |             :sandybridge | 
					
						
							|  |  |  |           when 0x1F65E835 # Ivy Bridge | 
					
						
							|  |  |  |             :ivybridge | 
					
						
							|  |  |  |           when 0x10B282DC # Haswell | 
					
						
							|  |  |  |             :haswell | 
					
						
							|  |  |  |           when 0x582ed09c # Broadwell | 
					
						
							|  |  |  |             :broadwell | 
					
						
							|  |  |  |           when 0x37fc219f # Skylake | 
					
						
							|  |  |  |             :skylake | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             :dunno | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         elsif ppc? | 
					
						
							|  |  |  |           case sysctl_int("hw.cpusubtype") | 
					
						
							|  |  |  |           when 9
 | 
					
						
							|  |  |  |             :g3  # PowerPC 750 | 
					
						
							|  |  |  |           when 10
 | 
					
						
							|  |  |  |             :g4  # PowerPC 7400 | 
					
						
							|  |  |  |           when 11
 | 
					
						
							|  |  |  |             :g4e # PowerPC 7450 | 
					
						
							|  |  |  |           when 100
 | 
					
						
							|  |  |  |             # This is the only 64-bit PPC CPU type, so it's useful | 
					
						
							|  |  |  |             # to distinguish in `brew config` output and in bottle tags | 
					
						
							|  |  |  |             MacOS.prefer_64_bit? ? :g5_64 : :g5 # PowerPC 970 | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             :dunno | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def extmodel | 
					
						
							|  |  |  |         sysctl_int("machdep.cpu.extmodel") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def cores | 
					
						
							|  |  |  |         sysctl_int("hw.ncpu") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def bits | 
					
						
							|  |  |  |         sysctl_bool("hw.cpu64bit_capable") ? 64 : 32
 | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def arch_32_bit | 
					
						
							|  |  |  |         intel? ? :i386 : :ppc | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def arch_64_bit | 
					
						
							|  |  |  |         intel? ? :x86_64 : :ppc64 | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Returns an array that's been extended with ArchitectureListExtension, | 
					
						
							|  |  |  |       # which provides helpers like #as_arch_flags and #as_cmake_arch_flags. | 
					
						
							|  |  |  |       def universal_archs | 
					
						
							|  |  |  |         # Building 64-bit is a no-go on Tiger, and pretty hit or miss on Leopard. | 
					
						
							|  |  |  |         # Don't even try unless Tigerbrew's experimental 64-bit Leopard support is enabled. | 
					
						
							|  |  |  |         if MacOS.version <= :leopard && !MacOS.prefer_64_bit? | 
					
						
							|  |  |  |           [arch_32_bit].extend ArchitectureListExtension | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           # Amazingly, this order (64, then 32) matters. It shouldn't, but it | 
					
						
							|  |  |  |           # does. GCC (some versions? some systems?) can blow up if the other | 
					
						
							|  |  |  |           # order is used. | 
					
						
							| 
									
										
										
										
											2017-03-12 19:44:01 +00:00
										 |  |  |           # https://superuser.com/questions/740563/gcc-4-8-on-macos-fails-depending-on-arch-order | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |           [arch_64_bit, arch_32_bit].extend ArchitectureListExtension | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-15 22:05:56 +08:00
										 |  |  |       # Determines whether the current CPU and macOS combination | 
					
						
							|  |  |  |       # can run an executable of the specified architecture. | 
					
						
							|  |  |  |       # `arch` is a symbol in the same format returned by | 
					
						
							|  |  |  |       # Hardware::CPU.family | 
					
						
							|  |  |  |       def can_run?(arch) | 
					
						
							|  |  |  |         if Hardware::CPU.intel? | 
					
						
							|  |  |  |           intel_can_run? arch | 
					
						
							|  |  |  |         elsif Hardware::CPU.ppc? | 
					
						
							|  |  |  |           ppc_can_run? arch | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |       def features | 
					
						
							|  |  |  |         @features ||= sysctl_n( | 
					
						
							|  |  |  |           "machdep.cpu.features", | 
					
						
							|  |  |  |           "machdep.cpu.extfeatures", | 
					
						
							| 
									
										
										
										
											2017-02-12 15:06:54 +00:00
										 |  |  |           "machdep.cpu.leaf7_features", | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |         ).split(" ").map { |s| s.downcase.to_sym } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def aes? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.aes") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def altivec? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.altivec") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def avx? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.avx1_0") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def avx2? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.avx2_0") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sse3? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.sse3") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def ssse3? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.supplementalsse3") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sse4? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.sse4_1") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sse4_2? | 
					
						
							|  |  |  |         sysctl_bool("hw.optional.sse4_2") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sysctl_bool(key) | 
					
						
							|  |  |  |         sysctl_int(key) == 1
 | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sysctl_int(key) | 
					
						
							|  |  |  |         sysctl_n(key).to_i | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def sysctl_n(*keys) | 
					
						
							|  |  |  |         (@properties ||= {}).fetch(keys) do | 
					
						
							|  |  |  |           @properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2017-04-15 22:05:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       def intel_can_run?(arch) | 
					
						
							|  |  |  |         case arch | 
					
						
							|  |  |  |         when :ppc | 
					
						
							|  |  |  |           # Rosetta is still available | 
					
						
							|  |  |  |           MacOS.version < :lion | 
					
						
							|  |  |  |         when :ppc64 | 
					
						
							|  |  |  |           # Rosetta never supported PPC64 | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         when :x86_64 | 
					
						
							|  |  |  |           Hardware::CPU.is_64_bit? | 
					
						
							|  |  |  |         when :i386 | 
					
						
							|  |  |  |           true | 
					
						
							|  |  |  |         else # dunno | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def ppc_can_run?(arch) | 
					
						
							|  |  |  |         case arch | 
					
						
							|  |  |  |         when :ppc | 
					
						
							|  |  |  |           true | 
					
						
							|  |  |  |         when :ppc64 | 
					
						
							|  |  |  |           Hardware::CPU.is_64_bit? | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           # Intel is never supported | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-04-25 18:00:01 +01:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |