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/common/intrinsics_float.h" // Float16/Float32/Float64
24
25 namespace berberis {
26
27 class SIMD128Register;
28
29 namespace intrinsics {
30 #if !defined(__aarch64__)
31 enum EnumFromTemplateType {
32 kInt8T,
33 kUInt8T,
34 kInt16T,
35 kUInt16T,
36 kInt32T,
37 kUInt32T,
38 kInt64T,
39 kUInt64T,
40 kFloat16,
41 kFloat32,
42 kFloat64,
43 kSIMD128Register,
44 };
45
46 template <typename Type>
TypeToEnumFromTemplateType()47 constexpr EnumFromTemplateType TypeToEnumFromTemplateType() {
48 if constexpr (std::is_same_v<int8_t, std::decay_t<Type>>) {
49 return EnumFromTemplateType::kInt8T;
50 } else if constexpr (std::is_same_v<uint8_t, std::decay_t<Type>>) {
51 return EnumFromTemplateType::kUInt8T;
52 } else if constexpr (std::is_same_v<int16_t, std::decay_t<Type>>) {
53 return EnumFromTemplateType::kUInt16T;
54 } else if constexpr (std::is_same_v<uint16_t, std::decay_t<Type>>) {
55 return EnumFromTemplateType::kUInt16T;
56 } else if constexpr (std::is_same_v<int32_t, std::decay_t<Type>>) {
57 return EnumFromTemplateType::kUInt32T;
58 } else if constexpr (std::is_same_v<uint32_t, std::decay_t<Type>>) {
59 return EnumFromTemplateType::kUInt32T;
60 } else if constexpr (std::is_same_v<int64_t, std::decay_t<Type>>) {
61 return EnumFromTemplateType::kUInt64T;
62 } else if constexpr (std::is_same_v<uint64_t, std::decay_t<Type>>) {
63 return EnumFromTemplateType::kUInt64T;
64 } else if constexpr (std::is_same_v<Float16, std::decay_t<Type>>) {
65 return EnumFromTemplateType::kFloat16;
66 } else if constexpr (std::is_same_v<Float32, std::decay_t<Type>>) {
67 return EnumFromTemplateType::kFloat32;
68 } else if constexpr (std::is_same_v<Float64, std::decay_t<Type>>) {
69 return EnumFromTemplateType::kFloat64;
70 } else if constexpr (std::is_same_v<Float64, std::decay_t<Type>>) {
71 return EnumFromTemplateType::kSIMD128Register;
72 } else {
73 static_assert(kDependentTypeFalse<Type>);
74 }
75 }
76
77 template <typename Type>
78 constexpr EnumFromTemplateType kEnumFromTemplateType = TypeToEnumFromTemplateType<Type>();
79 #endif
80 // A solution for the inability to call generic implementation from specialization.
81 // Declaration:
82 // template <typename Type,
83 // int size,
84 // enum PreferredIntrinsicsImplementation = kUseAssemblerImplementationIfPossible>
85 // inline std::tuple<SIMD128Register> VectorMultiplyByScalarInt(SIMD128Register op1,
86 // SIMD128Register op2);
87 // Normal use only specifies two arguments, e.g. VectorMultiplyByScalarInt<uint32_t, 2>,
88 // but assembler implementation can (if SSE 4.1 is not available) do the following call:
89 // return VectorMultiplyByScalarInt<uint32_t, 2, kUseCppImplementation>(in0, in1);
90 //
91 // Because PreferredIntrinsicsImplementation argument has non-default value we have call to the
92 // generic C-based implementation here.
93
94 enum PreferredIntrinsicsImplementation {
95 kUseAssemblerImplementationIfPossible,
96 kUseCppImplementation
97 };
98
99 } // namespace intrinsics
100
101 } // namespace berberis
102
103 #endif // BERBERIS_INTRINSICS_COMMON_INTRINSICS_H_
104