// Copyright 2018, VIXL authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// VIXL aims to handle and detect all architectural features that are likely to // influence code-generation decisions at EL0 (user-space). // // - There may be multiple VIXL feature flags for a given architectural // extension. This occurs where the extension allow components to be // implemented independently, or where kernel support is needed, and is likely // to be fragmented. // // For example, Pointer Authentication (kPAuth*) has a separate feature flag // for access to PACGA, and to indicate that the QARMA algorithm is // implemented. // // - Conversely, some extensions have configuration options that do not affect // EL0, so these are presented as a single VIXL feature. // // For example, the RAS extension (kRAS) has several variants, but the only // feature relevant to VIXL is the addition of the ESB instruction so we only // need a single flag. // // - VIXL offers separate flags for separate features even if they're // architecturally linked. // // For example, the architecture requires kFPHalf and kNEONHalf to be equal, // but they have separate hardware ID register fields so VIXL presents them as // separate features. // // - VIXL can detect every feature for which it can generate code. // // - VIXL can detect some features for which it cannot generate code. // // The CPUFeatures::Feature enum — derived from the macro list below — is // frequently extended. New features may be added to the list at any point, and // no assumptions should be made about the numerical values assigned to each // enum constant. The symbolic names can be considered to be stable. // // The debug descriptions are used only for debug output. The 'cpuinfo' strings // are informative; VIXL does not use /proc/cpuinfo for feature detection.
// A representation of the set of features known to be supported by the target // device. Each feature is represented by a simple boolean flag. // // - When the Assembler is asked to assemble an instruction, it asserts (in // debug mode) that the necessary features are available. // // - TODO: The MacroAssembler relies on the Assembler's assertions, but in // some cases it may be useful for macros to generate a fall-back sequence // in case features are not available. // // - The Simulator assumes by default that all features are available, but it // is possible to configure it to fail if the simulated code uses features // that are not enabled. // // The Simulator also offers pseudo-instructions to allow features to be // enabled and disabled dynamically. This is useful when you want to ensure // that some features are constrained to certain areas of code. // // - The base Disassembler knows nothing about CPU features, but the // PrintDisassembler can be configured to annotate its output with warnings // about unavailable features. The Simulator uses this feature when // instruction trace is enabled. // // - The Decoder-based components -- the Simulator and PrintDisassembler -- // rely on a CPUFeaturesAuditor visitor. This visitor keeps a list of // features actually encountered so that a large block of code can be // examined (either directly or through simulation), and the required // features analysed later. // // Expected usage: // // // By default, VIXL uses CPUFeatures::AArch64LegacyBaseline(), for // // compatibility with older version of VIXL. // MacroAssembler masm; // // // Generate code only for the current CPU. // masm.SetCPUFeatures(CPUFeatures::InferFromOS()); // // // Turn off feature checking entirely. // masm.SetCPUFeatures(CPUFeatures::All()); // // Feature set manipulation: // // CPUFeatures f; // The default constructor gives an empty set. // // Individual features can be added (or removed). // f.Combine(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::AES); // f.Remove(CPUFeatures::kNEON); // // // Some helpers exist for extensions that provide several features. // f.Remove(CPUFeatures::All()); // f.Combine(CPUFeatures::AArch64LegacyBaseline()); // // // Chained construction is also possible. // CPUFeatures g = // f.With(CPUFeatures::kPmull1Q).Without(CPUFeatures::kCRC32); // // // Features can be queried. Where multiple features are given, they are // // combined with logical AND. // if (h.Has(CPUFeatures::kNEON)) { ... } // if (h.Has(CPUFeatures::kFP, CPUFeatures::kNEON)) { ... } // if (h.Has(g)) { ... } // // If the empty set is requested, the result is always 'true'. // VIXL_ASSERT(h.Has(CPUFeatures())); // // // For debug and reporting purposes, features can be enumerated (or // // printed directly): // std::cout << CPUFeatures::kNEON; // Prints something like "NEON". // std::cout << f; // Prints something like "FP, NEON, CRC32". class CPUFeatures {
public: // clang-format off // Individual features. // These should be treated as opaque tokens. User code should not rely on // specific numeric values or ordering. enum Feature { // Refer to VIXL_CPU_FEATURE_LIST (above) for the list of feature names that // this class supports.
// By default, construct with no features enabled.
constexpr CPUFeatures() : features_{} {}
// Construct with some features already enabled. template <typename T, typename... U>
CPUFeatures(T first, U... others) : features_{} {
Combine(first, others...);
}
// Construct with all features enabled. This can be used to disable feature // checking: `Has(...)` returns true regardless of the argument. static CPUFeatures All();
// Construct an empty CPUFeatures. This is equivalent to the default // constructor, but is provided for symmetry and convenience. static CPUFeatures None() { return CPUFeatures(); }
// The presence of these features was assumed by version of VIXL before this // API was added, so using this set by default ensures API compatibility. static CPUFeatures AArch64LegacyBaseline() { return CPUFeatures(kFP, kNEON, kCRC32);
}
// Construct a new CPUFeatures object using ID registers. This assumes that // kIDRegisterEmulation is present. static CPUFeatures InferFromIDRegisters();
// Construct a new CPUFeatures object based on what the OS reports. static CPUFeatures InferFromOS(
QueryIDRegistersOption option = kQueryIDRegistersIfAvailable);
// Combine another CPUFeatures object into this one. Features that already // exist in this set are left unchanged. void Combine(const CPUFeatures& other);
// Combine a specific feature into this set. If it already exists in the set, // the set is left unchanged. void Combine(Feature feature);
// Combine multiple features (or feature sets) into this set. template <typename T, typename... U> void Combine(T first, U... others) {
Combine(first);
Combine(others...);
}
// Remove features in another CPUFeatures object from this one. void Remove(const CPUFeatures& other);
// Remove a specific feature from this set. This has no effect if the feature // doesn't exist in the set. void Remove(Feature feature0);
// Remove multiple features (or feature sets) from this set. template <typename T, typename... U> void Remove(T first, U... others) {
Remove(first);
Remove(others...);
}
// Chaining helpers for convenient construction by combining other CPUFeatures // or individual Features. template <typename... T>
CPUFeatures With(T... others) const {
CPUFeatures f(*this);
f.Combine(others...); return f;
}
// Test whether the `other` feature set is equal to or a subset of this one. bool Has(const CPUFeatures& other) const;
// Test whether a single feature exists in this set. // Note that `Has(kNone)` always returns true. bool Has(Feature feature) const;
// Test whether all of the specified features exist in this set. template <typename T, typename... U> bool Has(T first, U... others) const { return Has(first) && Has(others...);
}
// Return the number of enabled features.
size_t Count() const; bool HasNoFeatures() const { return Count() == 0; }
// This is not a proper C++ iterator type, but it simulates enough of // ForwardIterator that simple loops can be written. class CPUFeaturesConstIterator {
public:
CPUFeaturesConstIterator(const CPUFeatures* cpu_features = NULL,
CPUFeatures::Feature start = CPUFeatures::kNone)
: cpu_features_(cpu_features), feature_(start) {
VIXL_ASSERT(IsValid());
}
// For proper support of C++'s simplest "Iterator" concept, this class would // have to define member types (such as CPUFeaturesIterator::pointer) to make // it appear as if it iterates over Feature objects in memory. That is, we'd // need CPUFeatures::iterator to behave like std::vector<Feature>::iterator. // This is at least partially possible -- the std::vector<bool> specialisation // does something similar -- but it doesn't seem worthwhile for a // special-purpose debug helper, so they are omitted here. private: const CPUFeatures* cpu_features_;
CPUFeatures::Feature feature_;
// A convenience scope for temporarily modifying a CPU features object. This // allows features to be enabled for short sequences. // // Expected usage: // // { // CPUFeaturesScope cpu(&masm, CPUFeatures::kCRC32); // // This scope can now use CRC32, as well as anything else that was enabled // // before the scope. // // ... // // // At the end of the scope, the original CPU features are restored. // } class CPUFeaturesScope {
public: // Start a CPUFeaturesScope on any object that implements // `CPUFeatures* GetCPUFeatures()`. template <typename T> explicit CPUFeaturesScope(T* cpu_features_wrapper)
: cpu_features_(cpu_features_wrapper->GetCPUFeatures()),
old_features_(*cpu_features_) {}
// Start a CPUFeaturesScope on any object that implements // `CPUFeatures* GetCPUFeatures()`, with the specified features enabled. template <typename T, typename U, typename... V>
CPUFeaturesScope(T* cpu_features_wrapper, U first, V... features)
: cpu_features_(cpu_features_wrapper->GetCPUFeatures()),
old_features_(*cpu_features_) {
cpu_features_->Combine(first, features...);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.