blob: 6659930e65e5fa035ad4947e4f2270f8a3686818 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_
#define BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_
#include <xmmintrin.h>
#include <cstdint>
#include "berberis/base/dependent_false.h"
#include "berberis/intrinsics/intrinsics_args.h"
#include "berberis/intrinsics/type_traits.h"
namespace berberis::intrinsics::bindings {
class Imm2 {
public:
using Type = int8_t;
static constexpr bool kIsImmediate = true;
};
class Imm8 {
public:
using Type = int8_t;
static constexpr bool kIsImmediate = true;
};
class Imm16 {
public:
using Type = int16_t;
static constexpr bool kIsImmediate = true;
};
class Imm32 {
public:
using Type = int32_t;
static constexpr bool kIsImmediate = true;
};
class Imm64 {
public:
using Type = int64_t;
static constexpr bool kIsImmediate = true;
};
class AL {
public:
using Type = uint8_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'a';
};
class AX {
public:
using Type = uint16_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'a';
};
class EAX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'a';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kEAX;
};
class RAX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'a';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kRAX;
};
class CL {
public:
using Type = uint8_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'c';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kCL;
};
class CX {
public:
using Type = uint16_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'c';
};
class ECX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'c';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kECX;
};
class RCX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'c';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kRCX;
};
class DL {
public:
using Type = uint8_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'd';
};
class DX {
public:
using Type = uint16_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'd';
};
class EDX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'd';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kEDX;
};
class RDX {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 'd';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kRDX;
};
class GeneralReg8 {
public:
using Type = uint8_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'q';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kGeneralReg8;
};
class GeneralReg16 {
public:
using Type = uint16_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'r';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kGeneralReg16;
};
class GeneralReg32 {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'r';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kGeneralReg32;
};
class GeneralReg64 {
public:
using Type = uint64_t;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'r';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kGeneralReg64;
};
class FLAGS {
public:
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = true;
static constexpr char kAsRegister = 0;
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kFLAGS;
};
class FpReg32 {
public:
using Type = __m128;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'x';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kFpReg32;
};
class FpReg64 {
public:
using Type = __m128;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'x';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kFpReg64;
};
class VecReg128 {
public:
using Type = __m128;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'x';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kVecReg128;
};
class XmmReg {
public:
using Type = __m128;
static constexpr bool kIsImmediate = false;
static constexpr bool kIsImplicitReg = false;
static constexpr char kAsRegister = 'x';
template <typename MachineInsnArch>
static constexpr auto kRegClass = MachineInsnArch::kXmmReg;
};
class Mem8 {
public:
using Type = uint8_t;
static constexpr bool kIsImmediate = false;
static constexpr char kAsRegister = 'm';
};
class Mem16 {
public:
using Type = uint16_t;
static constexpr bool kIsImmediate = false;
static constexpr char kAsRegister = 'm';
};
class Mem32 {
public:
using Type = uint32_t;
static constexpr bool kIsImmediate = false;
static constexpr char kAsRegister = 'm';
};
class Mem64 {
public:
using Type = uint64_t;
static constexpr bool kIsImmediate = false;
static constexpr char kAsRegister = 'm';
};
// // Tag classes. They are never instantioned, only used as tags to pass information about
// bindings.
class Def;
class DefEarlyClobber;
class Use;
class UseDef;
template <typename Tag, typename MachineRegKind>
constexpr auto ToRegKind() {
if constexpr (std::is_same_v<Tag, Def>) {
return MachineRegKind::kDef;
} else if constexpr (std::is_same_v<Tag, DefEarlyClobber>) {
return MachineRegKind::kDefEarlyClobber;
} else if constexpr (std::is_same_v<Tag, Use>) {
return MachineRegKind::kUse;
} else if constexpr (std::is_same_v<Tag, UseDef>) {
return MachineRegKind::kUseDef;
} else {
static_assert(kDependentTypeFalse<Tag>);
}
}
template <typename Tag, typename MachineRegKind>
inline constexpr auto kRegKind = ToRegKind<Tag, MachineRegKind>();
enum CPUIDRestriction : int {
kNoCPUIDRestriction = 0,
kHas3DNOW,
kHas3DNOWP,
kHasADX,
kHasAES,
kHasAESAVX,
kHasAMXBF16,
kHasAMXFP16,
kHasAMXINT8,
kHasAMXTILE,
kHasAVX,
kHasAVX2,
kHasAVX5124FMAPS,
kHasAVX5124VNNIW,
kHasAVX512BF16,
kHasAVX512BITALG,
kHasAVX512BW,
kHasAVX512CD,
kHasAVX512DQ,
kHasAVX512ER,
kHasAVX512F,
kHasAVX512FP16,
kHasAVX512IFMA,
kHasAVX512PF,
kHasAVX512VBMI,
kHasAVX512VBMI2,
kHasAVX512VL,
kHasAVX512VNNI,
kHasAVX512VPOPCNTDQ,
kHasBMI,
kHasBMI2,
kHasCLMUL,
kHasCMOV,
kHasCMPXCHG16B,
kHasCMPXCHG8B,
kHasF16C,
kHasFMA,
kHasFMA4,
kHasFXSAVE,
kHasLZCNT,
kHasPOPCNT,
kHasRDSEED,
kHasSERIALIZE,
kHasSHA,
kHasSSE,
kHasSSE2,
kHasSSE3,
kHasSSE4_1,
kHasSSE4_2,
kHasSSE4a,
kHasSSSE3,
kHasTBM,
kHasVAES,
kHasX87,
kIsAuthenticAMD
};
enum PreciseNanOperationsHandling : int {
kNoNansOperation = 0,
kPreciseNanOperationsHandling,
kImpreciseNanOperationsHandling
};
template <auto kIntrinsicTemplateName,
auto kMacroInstructionTemplateName,
CPUIDRestriction kCPUIDRestrictionTemplateValue,
PreciseNanOperationsHandling kPreciseNanOperationsHandlingTemplateValue,
bool kSideEffectsTemplateValue,
typename... Types>
class AsmCallInfo;
template <auto kIntrinsicTemplateName,
auto kMacroInstructionTemplateName,
CPUIDRestriction kCPUIDRestrictionTemplateValue,
PreciseNanOperationsHandling kPreciseNanOperationsHandlingTemplateValue,
bool kSideEffectsTemplateValue,
typename... InputArgumentsTypes,
typename... OutputArgumentsTypes,
typename... BindingsTypes>
class AsmCallInfo<kIntrinsicTemplateName,
kMacroInstructionTemplateName,
kCPUIDRestrictionTemplateValue,
kPreciseNanOperationsHandlingTemplateValue,
kSideEffectsTemplateValue,
std::tuple<InputArgumentsTypes...>,
std::tuple<OutputArgumentsTypes...>,
BindingsTypes...>
final {
public:
static constexpr auto kIntrinsic = kIntrinsicTemplateName;
static constexpr auto kMacroInstruction = kMacroInstructionTemplateName;
static constexpr CPUIDRestriction kCPUIDRestriction = kCPUIDRestrictionTemplateValue;
static constexpr PreciseNanOperationsHandling kPreciseNanOperationsHandling =
kPreciseNanOperationsHandlingTemplateValue;
static constexpr bool kSideEffects = kSideEffectsTemplateValue;
static constexpr const char* InputArgumentsTypeNames[] = {
TypeTraits<InputArgumentsTypes>::kName...};
static constexpr const char* OutputArgumentsTypeNames[] = {
TypeTraits<OutputArgumentsTypes>::kName...};
template <typename Callback, typename... Args>
constexpr static void ProcessBindings(Callback&& callback, Args&&... args) {
(callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...), ...);
}
template <typename Callback, typename... Args>
constexpr static auto MakeTuplefromBindings(Callback&& callback, Args&&... args) {
return std::tuple_cat(callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...)...);
}
using InputArguments = std::tuple<InputArgumentsTypes...>;
using OutputArguments = std::tuple<OutputArgumentsTypes...>;
using Bindings = std::tuple<BindingsTypes...>;
using IntrinsicType = std::conditional_t<std::tuple_size_v<OutputArguments> == 0,
void (*)(InputArgumentsTypes...),
OutputArguments (*)(InputArgumentsTypes...)>;
};
} // namespace berberis::intrinsics::bindings
#endif // BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_