1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef BERBERIS_INTRINSICS_COMMON_INTRINSICS_H_
18 #define BERBERIS_INTRINSICS_COMMON_INTRINSICS_H_
19
20 #include <cstdint>
21
22 #include "berberis/base/dependent_false.h"
23 #include "berberis/intrinsics/intrinsics_float.h" // Float32/Float64/ProcessNans
24
25 namespace berberis {
26
27 class SIMD128Register;
28
29 namespace intrinsics {
30
31 enum EnumFromTemplateType {
32 kInt8T,
33 kUInt8T,
34 kInt16T,
35 kUInt16T,
36 kInt32T,
37 kUInt32T,
38 kInt64T,
39 kUInt64T,
40 kFloat32,
41 kFloat64,
42 kSIMD128Register,
43 };
44
45 template <typename Type>
TypeToEnumFromTemplateType()46 constexpr EnumFromTemplateType TypeToEnumFromTemplateType() {
47 if constexpr (std::is_same_v<int8_t, std::decay_t<Type>>) {
48 return EnumFromTemplateType::kInt8T;
49 } else if constexpr (std::is_same_v<uint8_t, std::decay_t<Type>>) {
50 return EnumFromTemplateType::kUInt8T;
51 } else if constexpr (std::is_same_v<int16_t, std::decay_t<Type>>) {
52 return EnumFromTemplateType::kUInt16T;
53 } else if constexpr (std::is_same_v<uint16_t, std::decay_t<Type>>) {
54 return EnumFromTemplateType::kUInt16T;
55 } else if constexpr (std::is_same_v<int32_t, std::decay_t<Type>>) {
56 return EnumFromTemplateType::kUInt32T;
57 } else if constexpr (std::is_same_v<uint32_t, std::decay_t<Type>>) {
58 return EnumFromTemplateType::kUInt32T;
59 } else if constexpr (std::is_same_v<int64_t, std::decay_t<Type>>) {
60 return EnumFromTemplateType::kUInt64T;
61 } else if constexpr (std::is_same_v<uint64_t, std::decay_t<Type>>) {
62 return EnumFromTemplateType::kUInt64T;
63 } else if constexpr (std::is_same_v<Float32, std::decay_t<Type>>) {
64 return EnumFromTemplateType::kFloat32;
65 } else if constexpr (std::is_same_v<Float64, std::decay_t<Type>>) {
66 return EnumFromTemplateType::kFloat64;
67 } else if constexpr (std::is_same_v<Float64, std::decay_t<Type>>) {
68 return EnumFromTemplateType::kSIMD128Register;
69 } else {
70 static_assert(kDependentTypeFalse<Type>);
71 }
72 }
73
74 template <typename Type>
75 constexpr EnumFromTemplateType kEnumFromTemplateType = TypeToEnumFromTemplateType<Type>();
76
77 // A solution for the inability to call generic implementation from specialization.
78 // Declaration:
79 // template <typename Type,
80 // int size,
81 // enum PreferredIntrinsicsImplementation = kUseAssemblerImplementationIfPossible>
82 // inline std::tuple<SIMD128Register> VectorMultiplyByScalarInt(SIMD128Register op1,
83 // SIMD128Register op2);
84 // Normal use only specifies two arguments, e.g. VectorMultiplyByScalarInt<uint32_t, 2>,
85 // but assembler implementation can (if SSE 4.1 is not available) do the following call:
86 // return VectorMultiplyByScalarInt<uint32_t, 2, kUseCppImplementation>(in0, in1);
87 //
88 // Because PreferredIntrinsicsImplementation argument has non-default value we have call to the
89 // generic C-based implementation here.
90
91 enum PreferredIntrinsicsImplementation {
92 kUseAssemblerImplementationIfPossible,
93 kUseCppImplementation
94 };
95
96 } // namespace intrinsics
97
98 } // namespace berberis
99
100 #endif // BERBERIS_INTRINSICS_COMMON_INTRINSICS_H_
101