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