Switch atmosphere's build target to C++20. (#952)

* ams: update to build with gcc10/c++20

* remove mno-outline-atomics

* ams: take care of most TODO C++20s

* fusee/sept: update for gcc10

* whoosh, your code now uses pre-compiled headers

* make: dependency fixes
This commit is contained in:
SciresM
2020-05-11 15:02:10 -07:00
committed by GitHub
parent 17b6bcfd37
commit 3a1ccdd919
258 changed files with 723 additions and 804 deletions

View File

@@ -23,7 +23,7 @@
namespace ams::crypto {
template<size_t ModulusSize, typename Hash> /* requires HashFunction<Hash> */
template<size_t ModulusSize, typename Hash> requires impl::HashFunction<Hash>
class RsaOaepDecryptor {
NON_COPYABLE(RsaOaepDecryptor);
NON_MOVEABLE(RsaOaepDecryptor);

View File

@@ -23,7 +23,7 @@
namespace ams::crypto {
template<size_t ModulusSize, typename Hash> /* requires HashFunction<Hash> */
template<size_t ModulusSize, typename Hash> requires impl::HashFunction<Hash>
class RsaOaepEncryptor {
NON_COPYABLE(RsaOaepEncryptor);
NON_MOVEABLE(RsaOaepEncryptor);

View File

@@ -23,7 +23,7 @@
namespace ams::crypto {
template<size_t _ModulusSize, typename Hash> /* requires HashFunction<Hash> */
template<size_t _ModulusSize, typename Hash> requires impl::HashFunction<Hash>
class RsaPssVerifier {
NON_COPYABLE(RsaPssVerifier);
NON_MOVEABLE(RsaPssVerifier);

View File

@@ -23,15 +23,13 @@
namespace ams::crypto::impl {
/* TODO: C++20
template<typename T>
concept HashFunction = requires(T &t, const void *cv, void *v, size_t sz) {
{ T::HashSize } -> std::same_as<size_t>;
{ T::BlockSize } -> std::same_as<size_t>;
{ t.Initialize() } -> std::same_as<void>;
{ t.Update(cv, sz) } -> std::same_as<void>;
{ t.GetHash(v, sz) } -> std::same_as<void>;
};
*/
template<typename T>
concept HashFunction = requires(T &t, const void *cv, void *v, size_t sz) {
{ T::HashSize } -> std::convertible_to<size_t>;
{ T::BlockSize } -> std::convertible_to<size_t>;
{ t.Initialize() } -> std::same_as<void>;
{ t.Update(cv, sz) } -> std::same_as<void>;
{ t.GetHash(v, sz) } -> std::same_as<void>;
};
}

View File

@@ -22,7 +22,7 @@
namespace ams::crypto::impl {
template<typename Hash> /* requires HashFunction<Hash> */
template<typename Hash> requires HashFunction<Hash>
class RsaOaepImpl {
NON_COPYABLE(RsaOaepImpl);
NON_MOVEABLE(RsaOaepImpl);

View File

@@ -22,7 +22,7 @@
namespace ams::crypto::impl {
template<typename Hash> /* requires HashFunction<Hash> */
template<typename Hash> requires HashFunction<Hash>
class RsaPssImpl {
NON_COPYABLE(RsaPssImpl);
NON_MOVEABLE(RsaPssImpl);

View File

@@ -66,6 +66,6 @@ namespace ams::crypto::impl {
}
};
/* static_assert(HashFunction<Sha256Impl>); */
static_assert(HashFunction<Sha256Impl>);
}

View File

@@ -35,9 +35,6 @@
#define CONST_FOLD(x) (__builtin_constant_p(x) ? (x) : (x))
#define WRAP_TEMPLATE_CONSTANT(...) ([] { using U = union { static constexpr auto GetValue() { return __VA_ARGS__; } }; return U{}; }())
#define UNWRAP_TEMPLATE_CONSTANT(tpnm) (tpnm::GetValue())
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)

View File

@@ -28,6 +28,7 @@
/* C++ headers. */
#include <type_traits>
#include <concepts>
#include <algorithm>
#include <iterator>
#include <limits>
@@ -38,6 +39,8 @@
#include <functional>
#include <tuple>
#include <array>
#include <bit>
#include <span>
/* Stratosphere wants additional libstdc++ headers, others do not. */
#ifdef ATMOSPHERE_IS_STRATOSPHERE

View File

@@ -19,207 +19,7 @@
namespace ams {
/* TODO C++20 switch to template<typename T> using Span = std::span<T> */
namespace impl {
template<typename Span>
class SpanConstIterator;
template<typename Span, typename Derived, typename Reference>
class SpanIteratorImpl {
public:
friend class SpanConstIterator<Span>;
using index_type = typename Span::index_type;
using difference_type = typename Span::difference_type;
using value_type = typename std::remove_cv<typename Span::element_type>::type;
using pointer = typename std::add_pointer<Reference>::type;
using reference = Reference;
using iterator_category = std::random_access_iterator_tag;
private:
const Span *span = nullptr;
index_type index = 0;
public:
constexpr ALWAYS_INLINE SpanIteratorImpl() = default;
constexpr ALWAYS_INLINE SpanIteratorImpl(const Span *s, index_type idx) : span(s), index(idx) { /* ... */ }
constexpr ALWAYS_INLINE pointer operator->() const {
return this->span->data() + this->index;
}
constexpr ALWAYS_INLINE reference operator*() const {
return *this->operator->();
}
constexpr ALWAYS_INLINE Derived operator++(int) {
auto prev = static_cast<Derived &>(*this);
++(*this);
return prev;
}
constexpr ALWAYS_INLINE Derived operator--(int) {
auto prev = static_cast<Derived &>(*this);
--(*this);
return prev;
}
constexpr ALWAYS_INLINE Derived &operator++() { ++this->index; return static_cast<Derived &>(*this); }
constexpr ALWAYS_INLINE Derived &operator--() { --this->index; return static_cast<Derived &>(*this); }
constexpr ALWAYS_INLINE Derived &operator+=(difference_type n) { this->index += n; return static_cast<Derived &>(*this); }
constexpr ALWAYS_INLINE Derived &operator-=(difference_type n) { this->index -= n; return static_cast<Derived &>(*this); }
constexpr ALWAYS_INLINE Derived operator+(difference_type n) const { auto r = static_cast<const Derived &>(*this); return r += n; }
constexpr ALWAYS_INLINE Derived operator-(difference_type n) const { auto r = static_cast<const Derived &>(*this); return r -= n; }
constexpr ALWAYS_INLINE friend Derived operator+(difference_type n, Derived it) { return it + n; }
constexpr ALWAYS_INLINE difference_type operator-(Derived rhs) const { AMS_ASSERT(this->span == rhs.span); return this->index - rhs.index; }
constexpr ALWAYS_INLINE reference operator[](difference_type n) const { return *(*this + n); }
constexpr ALWAYS_INLINE friend bool operator==(Derived lhs, Derived rhs) {
return lhs.span == rhs.span && lhs.index == rhs.index;
}
constexpr ALWAYS_INLINE friend bool operator<(Derived lhs, Derived rhs) {
AMS_ASSERT(lhs.span == rhs.span);
return lhs.index < rhs.index;
}
constexpr ALWAYS_INLINE friend bool operator!=(Derived lhs, Derived rhs) { return !(lhs == rhs); }
constexpr ALWAYS_INLINE friend bool operator>(Derived lhs, Derived rhs) { return rhs < lhs; }
constexpr ALWAYS_INLINE friend bool operator<=(Derived lhs, Derived rhs) { return !(lhs > rhs); }
constexpr ALWAYS_INLINE friend bool operator>=(Derived lhs, Derived rhs) { return !(lhs < rhs); }
};
template<typename Span>
class SpanIterator : public SpanIteratorImpl<Span, SpanIterator<Span>, typename Span::element_type&> {
public:
using SpanIteratorImpl<Span, SpanIterator<Span>, typename Span::element_type&>::SpanIteratorImpl;
};
template<typename Span>
class SpanConstIterator : public SpanIteratorImpl<Span, SpanConstIterator<Span>, const typename Span::element_type&> {
public:
using SpanIteratorImpl<Span, SpanConstIterator<Span>, const typename Span::element_type&>::SpanIteratorImpl;
constexpr ALWAYS_INLINE SpanConstIterator() = default;
constexpr ALWAYS_INLINE SpanConstIterator(const SpanIterator<Span> &rhs) : SpanConstIterator(rhs.span, rhs.index) { /* ... */ }
};
}
template<typename T>
class Span {
public:
using element_type = T;
using value_type = typename std::remove_cv<element_type>::type;
using index_type = std::ptrdiff_t;
using difference_type = std::ptrdiff_t;
using pointer = element_type *;
using reference = element_type &;
using iterator = ::ams::impl::SpanIterator<Span>;
using const_iterator = ::ams::impl::SpanConstIterator<Span>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
T *ptr;
index_type num_elements;
public:
constexpr ALWAYS_INLINE Span() : ptr(), num_elements() { /* ... */ }
constexpr ALWAYS_INLINE Span(T *p, index_type size) : ptr(p), num_elements(size) {
AMS_ASSERT(this->num_elements > 0 || this->ptr == nullptr);
}
constexpr ALWAYS_INLINE Span(T *start, T *end) : Span(start, end - start) { /* ... */ }
template<size_t Size>
constexpr ALWAYS_INLINE Span(T (&arr)[Size]) : Span(static_cast<T *>(arr), static_cast<index_type>(Size)) { /* ... */ }
template<size_t Size>
constexpr ALWAYS_INLINE Span(std::array<value_type, Size> &arr) : Span(arr.data(), static_cast<index_type>(Size)) { /* ... */ }
template<size_t Size>
constexpr ALWAYS_INLINE Span(const std::array<value_type, Size> &arr) : Span(arr.data(), static_cast<index_type>(Size)) { /* ... */ }
template<typename U, typename = typename std::enable_if<std::is_convertible<U(*)[], T(*)[]>::value>::type>
constexpr ALWAYS_INLINE Span(const Span<U> &rhs) : Span(rhs.data(), rhs.size()) { /* ... */ }
public:
constexpr ALWAYS_INLINE iterator begin() const { return { this, 0 }; }
constexpr ALWAYS_INLINE iterator end() const { return { this, this->num_elements }; }
constexpr ALWAYS_INLINE const_iterator cbegin() const { return { this, 0 }; }
constexpr ALWAYS_INLINE const_iterator cend() const { return { this, this->num_elements }; }
constexpr ALWAYS_INLINE reverse_iterator rbegin() const { return reverse_iterator(this->end()); }
constexpr ALWAYS_INLINE reverse_iterator rend() const { return reverse_iterator(this->begin()); }
constexpr ALWAYS_INLINE const_reverse_iterator crbegin() const { return reverse_iterator(this->cend()); }
constexpr ALWAYS_INLINE const_reverse_iterator crend() const { return reverse_iterator(this->cbegin()); }
constexpr ALWAYS_INLINE pointer data() const { return this->ptr; }
constexpr ALWAYS_INLINE index_type size() const { return this->num_elements; }
constexpr ALWAYS_INLINE index_type size_bytes() const { return this->size() * sizeof(T); }
constexpr ALWAYS_INLINE bool empty() const { return this->size() == 0; }
constexpr ALWAYS_INLINE T &operator[](index_type idx) const {
AMS_ASSERT(idx < this->size());
return this->ptr[idx];
}
constexpr ALWAYS_INLINE T &operator()(index_type idx) const { return (*this)[idx]; }
constexpr ALWAYS_INLINE Span first(index_type size) const {
AMS_ASSERT(size <= this->size());
return { this->ptr, size };
}
constexpr ALWAYS_INLINE Span last(index_type size) const {
AMS_ASSERT(size <= this->size());
return { this->ptr + (this->size() - size), size };
}
constexpr ALWAYS_INLINE Span subspan(index_type idx, index_type size) const {
AMS_ASSERT(size <= this->size());
AMS_ASSERT(this->size() - size >= idx);
return { this->ptr + idx, size };
}
constexpr ALWAYS_INLINE Span subspan(index_type idx) const {
AMS_ASSERT(idx <= this->size());
return { this->ptr + idx, this->size() - idx };
}
};
template<typename T>
constexpr ALWAYS_INLINE Span<T> MakeSpan(T *start, T *end) {
return { start, end };
}
template<typename T>
constexpr ALWAYS_INLINE Span<T> MakeSpan(T *p, typename Span<T>::index_type size) {
return { p, size };
}
template<typename T, size_t Size>
constexpr ALWAYS_INLINE Span<T> MakeSpan(T (&arr)[Size]) {
return Span<T>(arr);
}
template<typename T, size_t Size>
constexpr ALWAYS_INLINE Span<T> MakeSpan(std::array<T, Size> &arr) {
return Span<T>(arr);
}
template<typename T, size_t Size>
constexpr ALWAYS_INLINE Span<const T> MakeSpan(const std::array<T, Size> &arr) {
return Span<const T>(arr);
}
using Span = std::span<T>;
}

View File

@@ -261,12 +261,11 @@ namespace ams::svc::codegen::impl {
/* TODO */
};
template<typename CodeGenerator, typename MetaCodeHolder>
static ALWAYS_INLINE void GenerateCodeForMetaCode(MetaCodeHolder) {
constexpr auto MetaCode = UNWRAP_TEMPLATE_CONSTANT(MetaCodeHolder);
template<typename CodeGenerator, auto MetaCode>
static ALWAYS_INLINE void GenerateCodeForMetaCode() {
constexpr size_t NumOperations = MetaCode.GetNumOperations();
static_assert(NumOperations <= 64);
#define SVC_CODEGEN_HANDLER(n) do { if constexpr (n < NumOperations) { constexpr auto Operation = MetaCode.GetOperation(n); GenerateCodeForOperation<CodeGenerator>(WRAP_TEMPLATE_CONSTANT(Operation)); } } while (0)
#define SVC_CODEGEN_HANDLER(n) do { if constexpr (n < NumOperations) { constexpr auto Operation = MetaCode.GetOperation(n); GenerateCodeForOperation<CodeGenerator, Operation>(); } } while (0)
SVC_CODEGEN_FOR_I_FROM_0_TO_64(SVC_CODEGEN_HANDLER)
#undef SVC_CODEGEN_HANDLER
}

View File

@@ -143,7 +143,7 @@ namespace ams::svc::codegen::impl {
template<size_t N>
class RegisterAllocator {
private:
public:
std::array<bool, N> map;
public:
constexpr explicit RegisterAllocator() : map() { /* ... */ }

View File

@@ -319,38 +319,43 @@ namespace ams::svc::codegen::impl {
template<typename... T>
struct TypeIndexFilter {
template<typename UseArrayHolder, typename HeadType, typename... TailType, size_t HeadIndex, size_t... TailIndex>
static constexpr auto GetFilteredTupleImpl(UseArrayHolder, std::tuple<HeadType, TailType...>, std::index_sequence<HeadIndex, TailIndex...>) {
constexpr auto UseArray = UNWRAP_TEMPLATE_CONSTANT(UseArrayHolder);
static_assert(sizeof...(TailType) == sizeof...(TailIndex));
static_assert(HeadIndex <= UseArray.size());
if constexpr (sizeof...(TailType) == 0) {
if constexpr (!UseArray[HeadIndex]) {
return std::tuple<HeadType>{};
} else {
return std::tuple<>{};
}
} else {
auto tail_tuple = GetFilteredTupleImpl(UseArrayHolder{}, std::tuple<TailType...>{}, std::index_sequence<TailIndex...>{});
if constexpr (!UseArray[HeadIndex]) {
return std::tuple_cat(std::tuple<HeadType>{}, tail_tuple);
} else {
return std::tuple_cat(std::tuple<>{}, tail_tuple);
}
}
}
template<auto UseArray, typename X, typename Y>
struct Helper;
template<typename UseArrayHolder>
static constexpr auto GetFilteredTuple(UseArrayHolder) {
return GetFilteredTupleImpl(UseArrayHolder{}, std::tuple<T...>{}, std::make_index_sequence<sizeof...(T)>());
}
template<auto UseArray, size_t...Index>
struct Helper<UseArray, std::tuple<>, std::index_sequence<Index...>> {
using Type = std::tuple<>;
};
template<auto UseArray, typename HeadType, typename... TailType, size_t HeadIndex, size_t... TailIndex>
struct Helper<UseArray, std::tuple<HeadType, TailType...>, std::index_sequence<HeadIndex, TailIndex...>> {
using LastHeadType = std::tuple<HeadType>;
using LastNullType = std::tuple<>;
using LastType = typename std::conditional<!UseArray[HeadIndex], LastHeadType, LastNullType>::type;
using NextTailType = std::tuple<TailType...>;
using NextTailSequence = std::index_sequence<TailIndex...>;
using NextType = typename std::conditional<!UseArray[HeadIndex],
decltype(std::tuple_cat(std::declval<LastHeadType>(), std::declval<typename Helper<UseArray, NextTailType, NextTailSequence>::Type>())),
decltype(std::tuple_cat(std::declval<LastNullType>(), std::declval<typename Helper<UseArray, NextTailType, NextTailSequence>::Type>()))
>::type;
using Type = typename std::conditional<sizeof...(TailType) == 0, LastType, NextType>::type;
};
template<auto UseArray>
using FilteredTupleType = typename Helper<UseArray, std::tuple<T...>, decltype(std::make_index_sequence<sizeof...(T)>())>::Type;
};
template<typename AllocatorHolder, typename FirstOperation, typename...OtherOperations>
static constexpr auto GetModifiedOperations(AllocatorHolder, std::tuple<FirstOperation, OtherOperations...> ops) {
template<auto Allocator, typename FirstOperation, typename...OtherOperations>
static constexpr auto GetModifiedOperations(std::tuple<FirstOperation, OtherOperations...> ops) {
constexpr size_t ModifyRegister = [] {
auto allocator = UNWRAP_TEMPLATE_CONSTANT(AllocatorHolder);
auto allocator = Allocator;
return allocator.AllocateFirstFree();
}();
@@ -359,13 +364,13 @@ namespace ams::svc::codegen::impl {
return std::tuple<ModifiedFirstOperation, OtherOperations..., NewMoveOperation>{};
}
template<typename Conversion, typename AllocatorHolder, typename FirstOperation, typename... OtherOperations>
static constexpr auto GenerateBeforeOperations(MetaCodeGenerator &mcg, AllocatorHolder, std::tuple<FirstOperation, OtherOperations...> ops) -> RegisterAllocator<UNWRAP_TEMPLATE_CONSTANT(AllocatorHolder).GetRegisterCount()> {
template<typename Conversion, auto Allocator, typename FirstOperation, typename... OtherOperations>
static constexpr auto GenerateBeforeOperations(MetaCodeGenerator &mcg, std::tuple<FirstOperation, OtherOperations...> ops) -> RegisterAllocator<Allocator.GetRegisterCount()> {
constexpr size_t NumOperations = 1 + sizeof...(OtherOperations);
using OperationsTuple = decltype(ops);
using FilterHelper = TypeIndexFilter<FirstOperation, OtherOperations...>;
constexpr auto ProcessOperation = []<typename Operation>(MetaCodeGenerator &pr_mcg, auto &allocator, Operation) {
constexpr auto ProcessOperation = []<typename Operation>(MetaCodeGenerator &pr_mcg, auto &allocator) {
if (Conversion::template CanGenerateCode<Operation, CodeGenerationKind::SvcInvocationToKernelProcedure>(allocator)) {
Conversion::template GenerateCode<Operation, CodeGenerationKind::SvcInvocationToKernelProcedure>(pr_mcg, allocator);
return true;
@@ -373,12 +378,12 @@ namespace ams::svc::codegen::impl {
return false;
};
constexpr auto ProcessResults = [ProcessOperation]<typename... Operations>(std::tuple<Operations...>) {
auto allocator = UNWRAP_TEMPLATE_CONSTANT(AllocatorHolder);
constexpr auto ProcessResults = []<auto AllocatorVal, auto ProcessOp, typename... Operations>(std::tuple<Operations...>) {
auto allocator = AllocatorVal;
MetaCodeGenerator pr_mcg;
auto use_array = std::array<bool, NumOperations>{ ProcessOperation(pr_mcg, allocator, Operations{})... };
auto use_array = std::array<bool, NumOperations>{ ProcessOp.template operator()<Operations>(pr_mcg, allocator)... };
return std::make_tuple(use_array, allocator, pr_mcg);
}(OperationsTuple{});
}.template operator()<Allocator, ProcessOperation>(OperationsTuple{});
constexpr auto CanGenerate = std::get<0>(ProcessResults);
constexpr auto AfterAllocator = std::get<1>(ProcessResults);
@@ -388,15 +393,15 @@ namespace ams::svc::codegen::impl {
mcg.AddOperationDirectly(GeneratedCode.GetOperation(i));
}
constexpr auto FilteredOperations = FilterHelper::template GetFilteredTuple(WRAP_TEMPLATE_CONSTANT(CanGenerate));
static_assert(std::tuple_size<decltype(FilteredOperations)>::value <= NumOperations);
if constexpr (std::tuple_size<decltype(FilteredOperations)>::value > 0) {
if constexpr (std::tuple_size<decltype(FilteredOperations)>::value != NumOperations) {
return GenerateBeforeOperations<Conversion>(mcg, WRAP_TEMPLATE_CONSTANT(AfterAllocator), FilteredOperations);
using FilteredOperations = typename FilterHelper::FilteredTupleType<CanGenerate>;
static_assert(std::tuple_size<FilteredOperations>::value <= NumOperations);
if constexpr (std::tuple_size<FilteredOperations>::value > 0) {
if constexpr (std::tuple_size<FilteredOperations>::value != NumOperations) {
return GenerateBeforeOperations<Conversion, AfterAllocator>(mcg, FilteredOperations{});
} else {
/* No progress was made, so we need to make a change. */
constexpr auto ModifiedOperations = GetModifiedOperations(WRAP_TEMPLATE_CONSTANT(AfterAllocator), FilteredOperations);
return GenerateBeforeOperations<Conversion>(mcg, WRAP_TEMPLATE_CONSTANT(AfterAllocator), ModifiedOperations);
constexpr auto ModifiedOperations = GetModifiedOperations<AfterAllocator>(FilteredOperations{});
return GenerateBeforeOperations<Conversion, AfterAllocator>(mcg, ModifiedOperations);
}
} else {
return AfterAllocator;
@@ -433,7 +438,7 @@ namespace ams::svc::codegen::impl {
/* Generate code for before operations. */
if constexpr (Conversion::NumBeforeOperations > 0) {
allocator = GenerateBeforeOperations<Conversion>(mcg, WRAP_TEMPLATE_CONSTANT(InitialAllocator), typename Conversion::BeforeOperations{});
allocator = GenerateBeforeOperations<Conversion, InitialAllocator>(mcg, typename Conversion::BeforeOperations{});
} else {
allocator = InitialAllocator;
}
@@ -527,8 +532,8 @@ namespace ams::svc::codegen::impl {
static ALWAYS_INLINE void WrapSvcFunction() {
/* Generate appropriate assembly. */
GenerateCodeForMetaCode<CodeGenerator>(WRAP_TEMPLATE_CONSTANT(BeforeMetaCode));
ON_SCOPE_EXIT { GenerateCodeForMetaCode<CodeGenerator>(WRAP_TEMPLATE_CONSTANT(AfterMetaCode)); };
GenerateCodeForMetaCode<CodeGenerator, BeforeMetaCode>();
ON_SCOPE_EXIT { GenerateCodeForMetaCode<CodeGenerator, AfterMetaCode>(); };
return reinterpret_cast<void (*)()>(Function)();
}

View File

@@ -24,7 +24,7 @@ namespace ams::svc::codegen::impl {
static constexpr size_t MaxParameters = 8;
private:
static constexpr size_t InvalidIndex = std::numeric_limits<size_t>::max();
private:
public:
/* ABI parameters. */
Abi abi;
@@ -102,7 +102,7 @@ namespace ams::svc::codegen::impl {
};
class ProcedureLayout {
private:
public:
Abi abi;
ParameterLayout input;
ParameterLayout output;
@@ -205,7 +205,7 @@ namespace ams::svc::codegen::impl {
};
class SvcInvocationLayout {
private:
public:
Abi abi;
ParameterLayout input;
ParameterLayout output;
@@ -220,11 +220,7 @@ namespace ams::svc::codegen::impl {
}
for (size_t i = 1; i < num_parameters; i++) {
for (size_t j = i; j > 0 && param_layout.GetParameter(map[j-1]).GetLocation(0) > param_layout.GetParameter(map[j]).GetLocation(0); j--) {
/* std::swap is not constexpr until c++20 :( */
/* TODO: std::swap(map[j], map[j-1]); */
const size_t tmp = map[j];
map[j] = map[j-1];
map[j-1] = tmp;
std::swap(map[j], map[j-1]);
}
}

View File

@@ -304,9 +304,8 @@ namespace ams::svc::codegen::impl {
static constexpr auto DetermineConversionOperations() {
[[maybe_unused]] constexpr auto Procedure = LayoutForKernel;
[[maybe_unused]] constexpr ParameterLayout Svc = Input ? LayoutForSvc.GetInputLayout() : LayoutForSvc.GetOutputLayout();
[[maybe_unused]] constexpr std::array<size_t, Svc.GetNumParameters()> ParameterMap = []<typename SvcHolder>(SvcHolder){
[[maybe_unused]] constexpr std::array<size_t, Svc.GetNumParameters()> ParameterMap = []<auto CapturedSvc>(){
/* We want to iterate over the parameters in sorted order. */
constexpr ParameterLayout CapturedSvc = UNWRAP_TEMPLATE_CONSTANT(SvcHolder);
std::array<size_t, CapturedSvc.GetNumParameters()> map{};
const size_t num_parameters = CapturedSvc.GetNumParameters();
for (size_t i = 0; i < num_parameters; i++) {
@@ -314,15 +313,11 @@ namespace ams::svc::codegen::impl {
}
for (size_t i = 1; i < num_parameters; i++) {
for (size_t j = i; j > 0 && CapturedSvc.GetParameter(map[j-1]).GetLocation(0) > CapturedSvc.GetParameter(map[j]).GetLocation(0); j--) {
/* std::swap is not constexpr until c++20 :( */
/* TODO: std::swap(map[j], map[j-1]); */
const size_t tmp = map[j];
map[j] = map[j-1];
map[j-1] = tmp;
std::swap(map[j], map[j-1]);
}
}
return map;
}(WRAP_TEMPLATE_CONSTANT(Svc));
}.template operator()<Svc>();
if constexpr (ParameterIndex >= Svc.GetNumParameters()) {
/* Base case: we're done. */
@@ -377,16 +372,13 @@ namespace ams::svc::codegen::impl {
constexpr size_t RegisterSize = SvcAbiType::RegisterSize;
constexpr size_t PassedSize = ProcedureParam.GetTypeSize();
/* TODO: C++20 templated lambdas. For now, use GCC extension syntax. */
constexpr auto SvcIndexSequence = []<typename SvcParamWrapper, size_t... Is>(SvcParamWrapper, std::index_sequence<Is...>) {
constexpr Parameter CapturedSvcParam = UNWRAP_TEMPLATE_CONSTANT(SvcParamWrapper);
constexpr auto SvcIndexSequence = []<auto CapturedSvcParam, size_t... Is>(std::index_sequence<Is...>) {
return std::index_sequence<CapturedSvcParam.GetLocation(Is).GetIndex()...>{};
}(WRAP_TEMPLATE_CONSTANT(SvcParam), std::make_index_sequence<SvcParam.GetNumLocations()>());
}.template operator()<SvcParam>(std::make_index_sequence<SvcParam.GetNumLocations()>());
constexpr auto OperationValue = []<typename ProcedureLocWrapper, size_t... Is>(ProcedureLocWrapper, std::index_sequence<Is...>) {
constexpr Location CapturedProcedureLoc = UNWRAP_TEMPLATE_CONSTANT(ProcedureLocWrapper);
constexpr auto OperationValue = []<auto CapturedProcedureLoc, size_t... Is>(std::index_sequence<Is...>) {
return LayoutConversionBase::OperationScatter<RegisterSize, PassedSize, StackIndex * KernelAbiType::RegisterSize, CapturedProcedureLoc.GetIndex(), Is...>{};
}(WRAP_TEMPLATE_CONSTANT(ProcedureLoc), SvcIndexSequence);
}.template operator()<ProcedureLoc>(SvcIndexSequence);
constexpr auto cur_op = std::make_tuple(OperationValue);

View File

@@ -79,7 +79,7 @@ namespace ams::svc::codegen::impl {
return op;
}
private:
public:
size_t num_operations;
std::array<Operation, MaxOperations> operations;
public:
@@ -98,15 +98,13 @@ namespace ams::svc::codegen::impl {
}
};
template<typename _OperationHolder>
template<auto Operation>
static constexpr auto GetOperationParameterSequence() {
constexpr auto _Operation = UNWRAP_TEMPLATE_CONSTANT(_OperationHolder);
constexpr size_t NumParameters = _Operation.num_parameters;
constexpr size_t NumParameters = Operation.num_parameters;
return []<typename OperationHolder, size_t... Is>(OperationHolder, std::index_sequence<Is...>) {
constexpr auto Operation = UNWRAP_TEMPLATE_CONSTANT(OperationHolder);
return []<size_t... Is>(std::index_sequence<Is...>) {
return std::index_sequence<Operation.parameters[Is]...>{};
}(_OperationHolder{}, std::make_index_sequence<NumParameters>());
}(std::make_index_sequence<NumParameters>());
}
template<typename CodeGenerator, MetaCode::OperationKind Kind, size_t... Parameters>
@@ -130,10 +128,9 @@ namespace ams::svc::codegen::impl {
#undef META_CODE_OPERATION_KIND_GENERATE_CODE
}
template<typename CodeGenerator, typename OperationHolder>
static ALWAYS_INLINE void GenerateCodeForOperation(OperationHolder) {
constexpr auto Operation = UNWRAP_TEMPLATE_CONSTANT(OperationHolder);
GenerateCodeForOperationImpl<CodeGenerator, Operation.kind>(GetOperationParameterSequence<OperationHolder>());
template<typename CodeGenerator, auto Operation>
static ALWAYS_INLINE void GenerateCodeForOperation() {
GenerateCodeForOperationImpl<CodeGenerator, Operation.kind>(GetOperationParameterSequence<Operation>());
}
class MetaCodeGenerator {

View File

@@ -27,7 +27,7 @@ namespace ams::svc::codegen::impl {
class Location {
private:
static constexpr size_t InvalidIndex = std::numeric_limits<size_t>::max();
private:
public:
Storage storage;
size_t index;
public:
@@ -75,7 +75,7 @@ namespace ams::svc::codegen::impl {
static constexpr size_t MaxLocations = 8;
static constexpr size_t IdentifierLengthMax = 0x40;
class Identifier {
private:
public:
char name[IdentifierLengthMax];
size_t index;
public:
@@ -99,7 +99,7 @@ namespace ams::svc::codegen::impl {
return !(*this == rhs);
}
};
private:
public:
Identifier identifier;
ArgumentType type;
size_t type_size;

View File

@@ -58,11 +58,11 @@ namespace ams::svc::ipc {
private:
util::BitPack32 header[2];
public:
constexpr ALWAYS_INLINE MessageHeader() : header({util::BitPack32{0}, util::BitPack32{0}}) {
constexpr ALWAYS_INLINE MessageHeader() : header{util::BitPack32{0}, util::BitPack32{0}} {
this->header[0].Set<Tag>(NullTag);
}
constexpr ALWAYS_INLINE MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch, s32 raw, s32 recv_list) : header({util::BitPack32{0}, util::BitPack32{0}}) {
constexpr ALWAYS_INLINE MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch, s32 raw, s32 recv_list) : header{util::BitPack32{0}, util::BitPack32{0}} {
this->header[0].Set<Tag>(tag);
this->header[0].Set<PointerCount>(ptr);
this->header[0].Set<SendCount>(send);
@@ -74,11 +74,11 @@ namespace ams::svc::ipc {
this->header[1].Set<HasSpecialHeader>(special);
}
ALWAYS_INLINE explicit MessageHeader(const MessageBuffer &buf) : header({util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE explicit MessageHeader(const MessageBuffer &buf) : header{util::BitPack32{0}, util::BitPack32{0}} {
buf.Get(0, this->header, util::size(this->header));
}
ALWAYS_INLINE explicit MessageHeader(const u32 *msg) : header({util::BitPack32{msg[0]}, util::BitPack32{msg[1]}}) { /* ... */ }
ALWAYS_INLINE explicit MessageHeader(const u32 *msg) : header{util::BitPack32{msg[0]}, util::BitPack32{msg[1]}} { /* ... */ }
constexpr ALWAYS_INLINE u16 GetTag() const {
return this->header[0].Get<Tag>();
@@ -219,9 +219,9 @@ namespace ams::svc::ipc {
private:
util::BitPack32 data[3];
public:
constexpr ALWAYS_INLINE MapAliasDescriptor() : data({util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}) { /* ... */ }
constexpr ALWAYS_INLINE MapAliasDescriptor() : data{util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}} { /* ... */ }
ALWAYS_INLINE MapAliasDescriptor(const void *buffer, size_t _size, Attribute attr = Attribute_Ipc) : data({util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE MapAliasDescriptor(const void *buffer, size_t _size, Attribute attr = Attribute_Ipc) : data{util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}} {
const u64 address = reinterpret_cast<u64>(buffer);
const u64 size = static_cast<u64>(_size);
this->data[0] = { static_cast<u32>(size) };
@@ -233,7 +233,7 @@ namespace ams::svc::ipc {
this->data[2].Set<AddressHigh>(GetAddressHigh(address));
}
ALWAYS_INLINE MapAliasDescriptor(const MessageBuffer &buf, s32 index) : data({util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE MapAliasDescriptor(const MessageBuffer &buf, s32 index) : data{util::BitPack32{0}, util::BitPack32{0}, util::BitPack32{0}} {
buf.Get(index, this->data, util::size(this->data));
}
@@ -283,9 +283,9 @@ namespace ams::svc::ipc {
private:
util::BitPack32 data[2];
public:
constexpr ALWAYS_INLINE PointerDescriptor() : data({util::BitPack32{0}, util::BitPack32{0}}) { /* ... */ }
constexpr ALWAYS_INLINE PointerDescriptor() : data{util::BitPack32{0}, util::BitPack32{0}} { /* ... */ }
ALWAYS_INLINE PointerDescriptor(const void *buffer, size_t size, s32 index) : data({util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE PointerDescriptor(const void *buffer, size_t size, s32 index) : data{util::BitPack32{0}, util::BitPack32{0}} {
const u64 address = reinterpret_cast<u64>(buffer);
this->data[0].Set<Index>(index);
@@ -296,7 +296,7 @@ namespace ams::svc::ipc {
this->data[1] = { static_cast<u32>(address) };
}
ALWAYS_INLINE PointerDescriptor(const MessageBuffer &buf, s32 index) : data({util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE PointerDescriptor(const MessageBuffer &buf, s32 index) : data{util::BitPack32{0}, util::BitPack32{0}} {
buf.Get(index, this->data, util::size(this->data));
}
@@ -338,9 +338,9 @@ namespace ams::svc::ipc {
private:
util::BitPack32 data[2];
public:
constexpr ALWAYS_INLINE ReceiveListEntry() : data({util::BitPack32{0}, util::BitPack32{0}}) { /* ... */ }
constexpr ALWAYS_INLINE ReceiveListEntry() : data{util::BitPack32{0}, util::BitPack32{0}} { /* ... */ }
ALWAYS_INLINE ReceiveListEntry(const void *buffer, size_t size) : data({util::BitPack32{0}, util::BitPack32{0}}) {
ALWAYS_INLINE ReceiveListEntry(const void *buffer, size_t size) : data{util::BitPack32{0}, util::BitPack32{0}} {
const u64 address = reinterpret_cast<u64>(buffer);
this->data[0] = { static_cast<u32>(address) };
@@ -349,7 +349,7 @@ namespace ams::svc::ipc {
this->data[1].Set<Size>(size);
}
ALWAYS_INLINE ReceiveListEntry(u32 a, u32 b) : data({util::BitPack32{a}, util::BitPack32{b}}) { /* ... */ }
ALWAYS_INLINE ReceiveListEntry(u32 a, u32 b) : data{util::BitPack32{a}, util::BitPack32{b}} { /* ... */ }
constexpr ALWAYS_INLINE uintptr_t GetAddress() {
const u64 address = (static_cast<u64>(this->data[1].Get<AddressHigh>()) << AddressLow::Count) | this->data[0].Get<AddressLow>();

View File

@@ -18,6 +18,7 @@
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/util/util_type_traits.hpp>
#include <vapours/util/util_alignment.hpp>
#include <vapours/util/util_size.hpp>
#include <vapours/util/util_endian.hpp>

View File

@@ -50,7 +50,7 @@ namespace ams::util {
static constexpr size_t Next = Index + Count;
using BitPackType = BitPack<IntegralStorageType>;
static_assert(std::is_pod<BitPackType>::value);
static_assert(util::is_pod<BitPackType>::value);
static_assert(Mask<Index, Count> != 0);
static_assert(std::is_integral<T>::value || std::is_enum<T>::value);
@@ -84,10 +84,10 @@ namespace ams::util {
using BitPack32 = impl::BitPack<u32>;
using BitPack64 = impl::BitPack<u64>;
static_assert(std::is_pod<BitPack8>::value);
static_assert(std::is_pod<BitPack16>::value);
static_assert(std::is_pod<BitPack32>::value);
static_assert(std::is_pod<BitPack64>::value);
static_assert(util::is_pod<BitPack8>::value);
static_assert(util::is_pod<BitPack16>::value);
static_assert(util::is_pod<BitPack32>::value);
static_assert(util::is_pod<BitPack64>::value);
static_assert(std::is_trivially_destructible<BitPack8 >::value);
static_assert(std::is_trivially_destructible<BitPack16>::value);
static_assert(std::is_trivially_destructible<BitPack32>::value);

View File

@@ -30,11 +30,9 @@ namespace ams::util {
}
template <typename T>
template <typename T> requires std::integral<T>
class BitsOf {
private:
static_assert(std::is_integral<T>::value);
static constexpr ALWAYS_INLINE int GetLsbPos(T v) {
return __builtin_ctzll(static_cast<u64>(v));
}
@@ -78,69 +76,68 @@ namespace ams::util {
}
};
template<typename T = u64, typename ...Args>
template<typename T = u64, typename ...Args> requires std::integral<T>
constexpr ALWAYS_INLINE T CombineBits(Args... args) {
return (... | (T(1u) << args));
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ResetLeastSignificantOneBit(T x) {
return x & (x - 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T SetLeastSignificantZeroBit(T x) {
return x | (x + 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T LeastSignificantOneBit(T x) {
return x & ~(x - 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T LeastSignificantZeroBit(T x) {
return ~x & (x + 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ResetTrailingOnes(T x) {
return x & (x + 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T SetTrailingZeros(T x) {
return x | (x - 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T MaskTrailingZeros(T x) {
return (~x) & (x - 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T MaskTrailingOnes(T x) {
return ~((~x) | (x + 1));
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T MaskTrailingZerosAndLeastSignificantOneBit(T x) {
return x ^ (x - 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T MaskTrailingOnesAndLeastSignificantZeroBit(T x) {
return x ^ (x + 1);
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE int PopCount(T x) {
/* TODO: C++20 std::bit_cast */
using U = typename std::make_unsigned<T>::type;
U u = static_cast<U>(x);
/* TODO: C++20 std::is_constant_evaluated */
if (false) {
if (std::is_constant_evaluated()) {
/* https://en.wikipedia.org/wiki/Hamming_weight */
constexpr U m1 = U(-1) / 0x03;
constexpr U m2 = U(-1) / 0x05;
@@ -168,10 +165,9 @@ namespace ams::util {
}
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE int CountLeadingZeros(T x) {
/* TODO: C++20 std::is_constant_evaluated */
if (false) {
if (std::is_constant_evaluated()) {
for (size_t i = 0; i < impl::Log2<BITSIZEOF(T)>; ++i) {
const size_t shift = (0x1 << i);
x |= x >> shift;
@@ -195,18 +191,18 @@ namespace ams::util {
}
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE bool IsPowerOfTwo(T x) {
return x > 0 && ResetLeastSignificantOneBit(x) == 0;
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T CeilingPowerOfTwo(T x) {
AMS_ASSERT(x > 0);
return T(1) << (BITSIZEOF(T) - CountLeadingZeros(T(x - 1)));
}
template<typename T>
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T FloorPowerOfTwo(T x) {
AMS_ASSERT(x > 0);
return T(1) << (BITSIZEOF(T) - CountLeadingZeros(x) - 1);

View File

@@ -20,27 +20,17 @@
namespace ams::util {
/* TODO: C++20 std::endian */
constexpr bool IsLittleEndian() {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return true;
#else
return false;
#endif
return std::endian::native == std::endian::little;
}
constexpr bool IsBigEndian() {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return true;
#else
return false;
#endif
return std::endian::native == std::endian::big;
}
static_assert(IsLittleEndian() ^ IsBigEndian());
template<typename U> /* requires unsigned_integral<U> */
template<typename U> requires std::unsigned_integral<U>
constexpr ALWAYS_INLINE U SwapBytes(const U u) {
static_assert(BITSIZEOF(u8) == 8);
constexpr U ByteMask = 0xFFu;
@@ -85,14 +75,14 @@ namespace ams::util {
((u & (ByteMask << 0)) << 40);
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE void SwapBytes(T *ptr) {
using U = typename std::make_unsigned<T>::type;
*ptr = static_cast<T>(SwapBytes(static_cast<U>(*ptr)));
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ConvertToBigEndian(const T val) {
using U = typename std::make_unsigned<T>::type;
@@ -104,7 +94,7 @@ namespace ams::util {
}
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ConvertToLittleEndian(const T val) {
using U = typename std::make_unsigned<T>::type;
@@ -116,7 +106,7 @@ namespace ams::util {
}
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ConvertToBigEndian48(const T val) {
using U = typename std::make_unsigned<T>::type;
static_assert(sizeof(T) == sizeof(u64));
@@ -130,7 +120,7 @@ namespace ams::util {
}
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T ConvertToLittleEndian48(const T val) {
using U = typename std::make_unsigned<T>::type;
static_assert(sizeof(T) == sizeof(u64));
@@ -144,12 +134,12 @@ namespace ams::util {
}
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T LoadBigEndian(T *ptr) {
return ConvertToBigEndian(*ptr);
}
template<typename T> /* requires integral<T> */
template<typename T> requires std::integral<T>
constexpr ALWAYS_INLINE T LoadLittleEndian(T *ptr) {
return ConvertToLittleEndian(*ptr);
}

View File

@@ -17,16 +17,14 @@
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/util/util_endian.hpp>
namespace ams::util {
template<char A, char B, char C, char D>
struct FourCC {
/* TODO: C++20 std::endian */
static constexpr u32 Code = (static_cast<u32>(A) << 0x00) |
(static_cast<u32>(B) << 0x08) |
(static_cast<u32>(C) << 0x10) |
(static_cast<u32>(D) << 0x18);
static constexpr u32 Code = IsLittleEndian() ? ((static_cast<u32>(A) << 0x00) | (static_cast<u32>(B) << 0x08) | (static_cast<u32>(C) << 0x10) | (static_cast<u32>(D) << 0x18))
: ((static_cast<u32>(A) << 0x18) | (static_cast<u32>(B) << 0x10) | (static_cast<u32>(C) << 0x08) | (static_cast<u32>(D) << 0x00));
static constexpr const char String[] = {A, B, C, D};
@@ -36,11 +34,8 @@ namespace ams::util {
template<char A, char B, char C, char D>
struct ReverseFourCC {
/* TODO: C++20 std::endian */
static constexpr u32 Code = (static_cast<u32>(A) << 0x18) |
(static_cast<u32>(B) << 0x10) |
(static_cast<u32>(C) << 0x08) |
(static_cast<u32>(D) << 0x00);
static constexpr u32 Code = IsLittleEndian() ? ((static_cast<u32>(A) << 0x18) | (static_cast<u32>(B) << 0x10) | (static_cast<u32>(C) << 0x08) | (static_cast<u32>(D) << 0x00))
: ((static_cast<u32>(A) << 0x00) | (static_cast<u32>(B) << 0x08) | (static_cast<u32>(C) << 0x10) | (static_cast<u32>(D) << 0x18));
static constexpr const char String[] = {D, C, B, A};

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
namespace ams::util {
template<typename T>
using is_pod = std::bool_constant<std::is_standard_layout<T>::value && std::is_trivial<T>::value>;
}