1 /*
2 * Copyright (C) 2024 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_BINDINGS_H_
18 #define BERBERIS_INTRINSICS_COMMON_INTRINSICS_BINDINGS_H_
19
20 #include <cstdint>
21
22 #include "berberis/base/dependent_false.h"
23 #include "berberis/intrinsics/intrinsics_args.h"
24 #include "berberis/intrinsics/type_traits.h"
25
26 namespace berberis::intrinsics::bindings {
27
28 class FLAGS {
29 public:
30 static constexpr bool kIsImmediate = false;
31 static constexpr bool kIsImplicitReg = true;
32 static constexpr char kAsRegister = 0;
33 template <typename MachineInsnArch>
34 static constexpr auto kRegClass = MachineInsnArch::kFLAGS;
35 };
36
37 class Mem8 {
38 public:
39 using Type = uint8_t;
40 static constexpr bool kIsImmediate = false;
41 static constexpr char kAsRegister = 'm';
42 };
43
44 class Mem16 {
45 public:
46 using Type = uint16_t;
47 static constexpr bool kIsImmediate = false;
48 static constexpr char kAsRegister = 'm';
49 };
50
51 class Mem32 {
52 public:
53 using Type = uint32_t;
54 static constexpr bool kIsImmediate = false;
55 static constexpr char kAsRegister = 'm';
56 };
57
58 class Mem64 {
59 public:
60 using Type = uint64_t;
61 static constexpr bool kIsImmediate = false;
62 static constexpr char kAsRegister = 'm';
63 };
64
65 // Tag classes. They are never instantioned, only used as tags to pass information about
66 // bindings.
67 class Def;
68 class DefEarlyClobber;
69 class Use;
70 class UseDef;
71
72 template <typename Tag, typename MachineRegKind>
ToRegKind()73 constexpr auto ToRegKind() {
74 if constexpr (std::is_same_v<Tag, Def>) {
75 return MachineRegKind::kDef;
76 } else if constexpr (std::is_same_v<Tag, DefEarlyClobber>) {
77 return MachineRegKind::kDefEarlyClobber;
78 } else if constexpr (std::is_same_v<Tag, Use>) {
79 return MachineRegKind::kUse;
80 } else if constexpr (std::is_same_v<Tag, UseDef>) {
81 return MachineRegKind::kUseDef;
82 } else {
83 static_assert(kDependentTypeFalse<Tag>);
84 }
85 }
86
87 template <typename Tag, typename MachineRegKind>
88 inline constexpr auto kRegKind = ToRegKind<Tag, MachineRegKind>();
89
90 // Tag classes. They are never instantioned, only used as tags to pass information about
91 // bindings.
92 class NoCPUIDRestriction; // All CPUs have at least “no CPUID restriction” mode.
93
94 // Tag classes. They are never instantioned, only used as tags to pass information about
95 // bindings.
96 class NoNansOperation;
97 class PreciseNanOperationsHandling;
98 class ImpreciseNanOperationsHandling;
99
100 template <auto kIntrinsicTemplateName,
101 auto kMacroInstructionTemplateName,
102 auto kMnemo,
103 typename GetOpcode,
104 typename CPUIDRestrictionTemplateValue,
105 typename PreciseNanOperationsHandlingTemplateValue,
106 bool kSideEffectsTemplateValue,
107 typename... Types>
108 class AsmCallInfo;
109
110 template <auto kIntrinsicTemplateName,
111 auto kMacroInstructionTemplateName,
112 auto kMnemo,
113 typename GetOpcode,
114 typename CPUIDRestrictionTemplateValue,
115 typename PreciseNanOperationsHandlingTemplateValue,
116 bool kSideEffectsTemplateValue,
117 typename... InputArgumentsTypes,
118 typename... OutputArgumentsTypes,
119 typename... BindingsTypes>
120 class AsmCallInfo<kIntrinsicTemplateName,
121 kMacroInstructionTemplateName,
122 kMnemo,
123 GetOpcode,
124 CPUIDRestrictionTemplateValue,
125 PreciseNanOperationsHandlingTemplateValue,
126 kSideEffectsTemplateValue,
127 std::tuple<InputArgumentsTypes...>,
128 std::tuple<OutputArgumentsTypes...>,
129 BindingsTypes...>
130 final {
131 public:
132 static constexpr auto kIntrinsic = kIntrinsicTemplateName;
133 static constexpr auto kMacroInstruction = kMacroInstructionTemplateName;
134 // TODO(b/260725458): Use lambda template argument after C++20 becomes available.
135 template <typename Opcode>
136 static constexpr auto kOpcode = GetOpcode{}.template operator()<Opcode>();
137 using CPUIDRestriction = CPUIDRestrictionTemplateValue;
138 using PreciseNanOperationsHandling = PreciseNanOperationsHandlingTemplateValue;
139 static constexpr bool kSideEffects = kSideEffectsTemplateValue;
140 static constexpr const char* InputArgumentsTypeNames[] = {
141 TypeTraits<InputArgumentsTypes>::kName...};
142 static constexpr const char* OutputArgumentsTypeNames[] = {
143 TypeTraits<OutputArgumentsTypes>::kName...};
144 template <typename Callback, typename... Args>
ProcessBindings(Callback && callback,Args &&...args)145 constexpr static void ProcessBindings(Callback&& callback, Args&&... args) {
146 (callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...), ...);
147 }
148 template <typename Callback, typename... Args>
VerifyBindings(Callback && callback,Args &&...args)149 constexpr static bool VerifyBindings(Callback&& callback, Args&&... args) {
150 return (callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...) && ...);
151 }
152 template <typename Callback, typename... Args>
MakeTuplefromBindings(Callback && callback,Args &&...args)153 constexpr static auto MakeTuplefromBindings(Callback&& callback, Args&&... args) {
154 return std::tuple_cat(callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...)...);
155 }
156 using InputArguments = std::tuple<InputArgumentsTypes...>;
157 using OutputArguments = std::tuple<OutputArgumentsTypes...>;
158 using Bindings = std::tuple<BindingsTypes...>;
159 using IntrinsicType = std::conditional_t<std::tuple_size_v<OutputArguments> == 0,
160 void (*)(InputArgumentsTypes...),
161 OutputArguments (*)(InputArgumentsTypes...)>;
162 template <template <typename, auto, auto, typename...> typename MachineInsnType,
163 template <typename...>
164 typename ConstructorArgs,
165 typename Opcode>
166 using MachineInsn = MachineInsnType<AsmCallInfo,
167 kMnemo,
168 kOpcode<Opcode>,
169 ConstructorArgs<BindingsTypes...>,
170 BindingsTypes...>;
171 };
172
173 } // namespace berberis::intrinsics::bindings
174
175 #endif // BERBERIS_INTRINSICS_COMMON_INTRINSICS_BINDINGS_H_
176