Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 10d34b9569c7
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0a368e3f103a
Choose a head ref
  • 9 commits
  • 6 files changed
  • 1 contributor

Commits on May 20, 2021

  1. CPUID

    eggrobin committed May 20, 2021
    Copy the full SHA
    4b4dbe3 View commit details
  2. EOL@EOF

    eggrobin committed May 20, 2021
    Copy the full SHA
    9b60202 View commit details
  3. keep 333

    eggrobin committed May 20, 2021
    Copy the full SHA
    1981bc9 View commit details

Commits on May 25, 2021

  1. PSN and lint

    eggrobin committed May 25, 2021
    Copy the full SHA
    570a7ea View commit details

Commits on May 26, 2021

  1. Copy the full SHA
    72d59a8 View commit details
  2. review comments

    eggrobin committed May 26, 2021
    Copy the full SHA
    0ec8c56 View commit details
  3. merge

    eggrobin committed May 26, 2021
    Copy the full SHA
    d86671e View commit details
  4. remove macro

    eggrobin committed May 26, 2021
    Copy the full SHA
    8e725e5 View commit details

Commits on May 27, 2021

  1. Merge pull request #2990 from eggrobin/fma

    CPUID
    eggrobin authored May 27, 2021
    Copy the full SHA
    0a368e3 View commit details
Showing with 160 additions and 0 deletions.
  1. +3 −0 base/base.vcxproj
  2. +9 −0 base/base.vcxproj.filters
  3. +62 −0 base/cpuid.cpp
  4. +47 −0 base/cpuid.hpp
  5. +38 −0 base/cpuid_test.cpp
  6. +1 −0 base/not_null_test.cpp
3 changes: 3 additions & 0 deletions base/base.vcxproj
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
<ClInclude Include="bits_body.hpp" />
<ClInclude Include="bundle.hpp" />
<ClInclude Include="constant_function.hpp" />
<ClInclude Include="cpuid.hpp" />
<ClInclude Include="disjoint_sets.hpp" />
<ClInclude Include="disjoint_sets_body.hpp" />
<ClInclude Include="encoder.hpp" />
@@ -87,6 +88,8 @@
<ClCompile Include="bits_test.cpp" />
<ClCompile Include="bundle.cpp" />
<ClCompile Include="bundle_test.cpp" />
<ClCompile Include="cpuid.cpp" />
<ClCompile Include="cpuid_test.cpp" />
<ClCompile Include="disjoint_sets_test.cpp" />
<ClCompile Include="flags.cpp" />
<ClCompile Include="flags_test.cpp" />
9 changes: 9 additions & 0 deletions base/base.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -206,6 +206,9 @@
<ClInclude Include="macos_allocator_replacement.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cpuid.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="not_null_test.cpp">
@@ -277,5 +280,11 @@
<ClCompile Include="malloc_allocator_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="cpuid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cpuid_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
62 changes: 62 additions & 0 deletions base/cpuid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "base/cpuid.hpp"

#include <string>

#include "base/macros.hpp"
#if PRINCIPIA_COMPILER_MSVC
#include <intrin.h>
#else
#include <cpuid.h>
#endif

namespace principia {
namespace base {
namespace internal_cpuid {

struct CPUIDResult {
std::uint32_t eax;
std::uint32_t ebx;
std::uint32_t ecx;
std::uint32_t edx;
};

CPUIDResult CPUID(std::uint32_t const eax, std::uint32_t const ecx) {
#if PRINCIPIA_COMPILER_MSVC
int result[4];
__cpuidex(result, eax, ecx);
return {.eax = static_cast<std::uint32_t>(result[0]),
.ebx = static_cast<std::uint32_t>(result[1]),
.ecx = static_cast<std::uint32_t>(result[2]),
.edx = static_cast<std::uint32_t>(result[3])};
#else
CPUIDResult result;
__cpuid_count(eax, ecx, result.eax, result.ebx, result.ecx, result.edx);
return result;
#endif
}

std::string CPUVendorIdentificationString() {
auto const leaf_0 = CPUID(0, 0);
std::string result(12, '\0');
std::memcpy(&result[0], &leaf_0.ebx, 4);
std::memcpy(&result[4], &leaf_0.edx, 4);
std::memcpy(&result[8], &leaf_0.ecx, 4);
return result;
}

CPUFeatureFlags operator|(CPUFeatureFlags const left,
CPUFeatureFlags const right) {
return static_cast<CPUFeatureFlags>(static_cast<std::uint64_t>(left) |
static_cast<std::uint64_t>(right));
}

bool HasCPUFeatures(CPUFeatureFlags const flags) {
auto const leaf_1 = CPUID(1, 0);
return static_cast<CPUFeatureFlags>(
(ecx_bit * leaf_1.ecx | edx_bit * leaf_1.edx) &
static_cast<std::uint64_t>(flags)) == flags;
}

} // namespace internal_cpuid
} // namespace base
} // namespace principia
47 changes: 47 additions & 0 deletions base/cpuid.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <cstdint>
#include <string>

namespace principia {
namespace base {
namespace internal_cpuid {

// See the Intel® 64 and IA-32 Architectures Software Developer’s Manual,
// Volume 2A, CPUID—CPU Identification.

// Leaf 0.
std::string CPUVendorIdentificationString();

// Leaf 1.
// We represent feature flags as EDX + 2³² ECX.
constexpr std::uint64_t edx_bit = 1;
constexpr std::uint64_t ecx_bit = edx_bit << 32;
enum class CPUFeatureFlags : std::uint64_t {
// Table 3-11.
FPU = edx_bit << 0, // x87 Floating Point Unit on chip.
PSN = edx_bit << 18, // Processor Serial Number.
SSE = edx_bit << 25, // Streaming SIMD Extensions.
SSE2 = edx_bit << 26, // Streaming SIMD Extensions 2.
// Table 3-10.
SSE3 = ecx_bit << 0, // Streaming SIMD Extensions 3.
FMA = ecx_bit << 12, // Fused Multiply Add.
SSE4_1 = ecx_bit << 19, // Streaming SIMD Extensions 4.1.
AVX = ecx_bit << 28, // Advanced Vector eXtensions.
};

// Bitwise or of feature flags; the result represents the union of all features
// in |left| and |right|.
CPUFeatureFlags operator|(CPUFeatureFlags left, CPUFeatureFlags right);

// Whether the CPU has all features listed in |flags|.
bool HasCPUFeatures(CPUFeatureFlags flags);

} // namespace internal_cpuid

using internal_cpuid::CPUFeatureFlags;
using internal_cpuid::CPUVendorIdentificationString;
using internal_cpuid::HasCPUFeatures;

} // namespace base
} // namespace principia
38 changes: 38 additions & 0 deletions base/cpuid_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

#include "base/cpuid.hpp"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace principia {
namespace base {

using ::testing::Eq;
using ::testing::Test;

class CPUIDTest : public Test {};

TEST_F(CPUIDTest, Vendor) {
// This mostly checks that we are getting something from CPUID, since it is
// hard to expect things from the feature flags. This could be expanded to an
// AnyOf as needed if the tests are run on non-Intel processors.
EXPECT_THAT(CPUVendorIdentificationString(), Eq("GenuineIntel"));
}

TEST_F(CPUIDTest, CPUFeatureFlags) {
// We require Prescott or later.
EXPECT_TRUE(HasCPUFeatures(CPUFeatureFlags::FPU | CPUFeatureFlags::SSE |
CPUFeatureFlags::SSE2 | CPUFeatureFlags::SSE3));
// We develop on Sandy Bridge or later.
EXPECT_TRUE(HasCPUFeatures(CPUFeatureFlags::AVX));
// Check that we don’t always return true.
// We are not running these tests on a Pentium III, so we do not have the
// Processor Serial Number feature.
EXPECT_FALSE(HasCPUFeatures(CPUFeatureFlags::PSN));
EXPECT_FALSE(HasCPUFeatures(CPUFeatureFlags::FPU | CPUFeatureFlags::SSE |
CPUFeatureFlags::SSE2 | CPUFeatureFlags::SSE3 |
CPUFeatureFlags::PSN));
}

} // namespace base
} // namespace principia
1 change: 1 addition & 0 deletions base/not_null_test.cpp
Original file line number Diff line number Diff line change
@@ -71,6 +71,7 @@ TEST_F(NotNullTest, Move) {
_MSC_FULL_VER == 192'628'806 || \
_MSC_FULL_VER == 192'729'111 || \
_MSC_FULL_VER == 192'829'333 || \
_MSC_FULL_VER == 192'829'337 || \
_MSC_FULL_VER == 192'930'036)
EXPECT_THAT(*(std::unique_ptr<int> const&)int_ptr1, Eq(3));
#endif