Move macro instruction related info into machine_insn_info.h
Without separate machine_insn_info namespace
Bug: 399130034
Test: m berberis_all
Change-Id: I68a13fa53d8ff91f352f1a307eb605cd3369f87b
diff --git a/backend/include/berberis/backend/x86_64/machine_insn_intrinsics.h b/backend/include/berberis/backend/x86_64/machine_insn_intrinsics.h
index e5a48ef..b2cfe0d 100644
--- a/backend/include/berberis/backend/x86_64/machine_insn_intrinsics.h
+++ b/backend/include/berberis/backend/x86_64/machine_insn_intrinsics.h
@@ -58,33 +58,34 @@
struct ConstructorArg;
// Immediates expand into their class type.
-template <typename T>
-struct ConstructorArg<ArgTraits<T>, std::enable_if_t<ArgTraits<T>::Class::kIsImmediate, void>> {
- using type = std::tuple<typename ArgTraits<T>::Class::Type>;
+template <typename T, typename O>
+struct ConstructorArg<ArgTraits<T, O>,
+ std::enable_if_t<ArgTraits<T, O>::Class::kIsImmediate, void>> {
+ using type = std::tuple<typename ArgTraits<T, O>::Class::Type>;
};
// Mem ops expand into base register and disp.
-template <typename T>
-struct ConstructorArg<ArgTraits<T>,
- std::enable_if_t<!ArgTraits<T>::Class::kIsImmediate &&
- ArgTraits<T>::RegisterClass::kAsRegister == 'm',
+template <typename T, typename O>
+struct ConstructorArg<ArgTraits<T, O>,
+ std::enable_if_t<!ArgTraits<T, O>::Class::kIsImmediate &&
+ ArgTraits<T, O>::RegisterClass::kAsRegister == 'm',
void>> {
- static_assert(ArgTraits<T>::kUsage == intrinsics::bindings::kDefEarlyClobber);
+ static_assert(ArgTraits<T, O>::kUsage == intrinsics::bindings::kDefEarlyClobber);
// Need to emit base register AND disp.
using type = std::tuple<MachineReg, int32_t>;
};
// Everything else expands into a MachineReg.
-template <typename T>
-struct ConstructorArg<ArgTraits<T>,
- std::enable_if_t<!ArgTraits<T>::Class::kIsImmediate &&
- ArgTraits<T>::RegisterClass::kAsRegister != 'm',
+template <typename T, typename O>
+struct ConstructorArg<ArgTraits<T, O>,
+ std::enable_if_t<!ArgTraits<T, O>::Class::kIsImmediate &&
+ ArgTraits<T, O>::RegisterClass::kAsRegister != 'm',
void>> {
using type = std::tuple<MachineReg>;
};
template <typename T>
-using constructor_one_arg_t = typename ConstructorArg<ArgTraits<T>>::type;
+using constructor_one_arg_t = typename ConstructorArg<T>::type;
// Use this alias to generate constructor Args from bindings.
template <typename... T>
@@ -102,7 +103,7 @@
using is_mem_t = is_mem_impl<T>;
template <typename... Bindings>
-constexpr size_t mem_count_v = std::tuple_size_v<filter_t<is_mem_t, ArgTraits<Bindings>...>>;
+constexpr size_t mem_count_v = std::tuple_size_v<filter_t<is_mem_t, Bindings...>>;
template <size_t N, typename... Bindings>
constexpr bool has_n_mem_v = mem_count_v<Bindings...> > (N - 1);
@@ -136,7 +137,7 @@
template <typename>
struct GenMachineInsnInfoT;
// We want to filter out any bindings that are not used for Register args.
- using RegBindings = filter_t<has_reg_class_t, ArgTraits<Bindings>...>;
+ using RegBindings = filter_t<has_reg_class_t, Bindings...>;
public:
// This static simplifies constructing this MachineInsn in intrinsic implementations.
@@ -160,8 +161,8 @@
std::string s(kMnemo);
// Code below assumes that we have at most two memory operands.
static_assert(([]<typename Binding> {
- if constexpr (!ArgTraits<Binding>::Class::kIsImmediate) {
- return ArgTraits<Binding>::Class::kAsRegister == 'm';
+ if constexpr (!Binding::Class::kIsImmediate) {
+ return Binding::Class::kAsRegister == 'm';
}
return false;
}.template operator()<Bindings>() +
@@ -173,7 +174,7 @@
if (arg_idx > 0) {
s += ", ";
}
- if constexpr (ArgTraits<Binding>::Class::kIsImmediate) {
+ if constexpr (Binding::Class::kIsImmediate) {
// Without static_cast here compilation fails with extemely criptic error message:
// error: implicit instantiation of undefined template 'berberis::InOutArg<0, 0, …>'
// …
@@ -184,7 +185,7 @@
// Same below.
s += GetImmOperandDebugString(static_cast<const MachineInsnX86_64*>(this));
arg_idx++;
- } else if constexpr (ArgTraits<Binding>::Class::kAsRegister == 'm') {
+ } else if constexpr (Binding::Class::kAsRegister == 'm') {
if (disp_idx == 0) {
s += GetBaseDispMemOperandDebugString(static_cast<const MachineInsnX86_64*>(this),
reg_idx);
@@ -196,7 +197,7 @@
disp2());
}
arg_idx++, reg_idx++, disp_idx++;
- } else if constexpr (ArgTraits<Binding>::RegisterClass::kIsImplicitReg) {
+ } else if constexpr (Binding::RegisterClass::kIsImplicitReg) {
s += GetImplicitRegOperandDebugString(static_cast<const MachineInsnX86_64*>(this),
reg_idx);
arg_idx++, reg_idx++;
@@ -216,8 +217,8 @@
void Emit(CodeEmitter* as) const override {
// Code below assumes that we have at most two memory operands.
static_assert(([]<typename Binding> {
- if constexpr (!ArgTraits<Binding>::Class::kIsImmediate) {
- return ArgTraits<Binding>::Class::kAsRegister == 'm';
+ if constexpr (!Binding::Class::kIsImmediate) {
+ return Binding::Class::kAsRegister == 'm';
}
return false;
}.template operator()<Bindings>() +
@@ -227,17 +228,16 @@
kMacroInstruction,
std::tuple_cat(
std::tuple<CodeEmitter&>{*as}, [®_idx, &disp_idx, this]<typename Binding> {
- if constexpr (ArgTraits<Binding>::Class::kIsImmediate) {
+ if constexpr (Binding::Class::kIsImmediate) {
return std::tuple{
static_cast<constructor_one_arg_t<Binding>>(MachineInsnX86_64::imm())};
- } else if constexpr (ArgTraits<Binding>::RegisterClass::kAsRegister == 'x') {
+ } else if constexpr (Binding::RegisterClass::kAsRegister == 'x') {
return std::tuple{GetXReg(this->RegAt(reg_idx++))};
- } else if constexpr (ArgTraits<Binding>::RegisterClass::kAsRegister == 'r' ||
- ArgTraits<Binding>::RegisterClass::kAsRegister == 'q') {
+ } else if constexpr (Binding::RegisterClass::kAsRegister == 'r' ||
+ Binding::RegisterClass::kAsRegister == 'q') {
return std::tuple{GetGReg(this->RegAt(reg_idx++))};
- } else if constexpr (ArgTraits<Binding>::RegisterClass::kAsRegister == 'm' &&
- ArgTraits<Binding>::kUsage ==
- intrinsics::bindings::kDefEarlyClobber) {
+ } else if constexpr (Binding::RegisterClass::kAsRegister == 'm' &&
+ Binding::kUsage == intrinsics::bindings::kDefEarlyClobber) {
disp_idx++;
if (disp_idx == 1) {
return std::tuple{Assembler::Operand{.base = GetGReg(this->RegAt(reg_idx++)),
@@ -246,7 +246,7 @@
return std::tuple{Assembler::Operand{.base = GetGReg(this->RegAt(reg_idx++)),
.disp = static_cast<int32_t>(disp2())}};
}
- } else if constexpr (ArgTraits<Binding>::RegisterClass::kIsImplicitReg) {
+ } else if constexpr (Binding::RegisterClass::kIsImplicitReg) {
return std::tuple{};
} else {
static_assert(kDependentTypeFalse<Binding>);
@@ -264,7 +264,7 @@
typename... BindingsRest,
typename T,
typename... Args>
- auto ProcessArgs(T arg, Args... args) -> std::enable_if_t<ArgTraits<B>::Class::kIsImmediate> {
+ auto ProcessArgs(T arg, Args... args) -> std::enable_if_t<B::Class::kIsImmediate> {
this->set_imm(arg);
ProcessArgs<reg_idx, disp_idx, BindingsRest...>(args...);
}
@@ -275,8 +275,7 @@
typename... BindingsRest,
typename T,
typename... Args>
- auto ProcessArgs(T arg, Args... args)
- -> std::enable_if_t<ArgTraits<B>::RegisterClass::kAsRegister != 'm'> {
+ auto ProcessArgs(T arg, Args... args) -> std::enable_if_t<B::RegisterClass::kAsRegister != 'm'> {
static_assert(std::is_same_v<MachineReg, T>);
this->SetRegAt(reg_idx, arg);
ProcessArgs<reg_idx + 1, disp_idx, BindingsRest...>(args...);
@@ -289,10 +288,11 @@
typename T1,
typename T2,
typename... Args>
- auto ProcessArgs(T1 base, T2 disp, Args... args)
- -> std::enable_if_t<ArgTraits<B>::RegisterClass::kAsRegister == 'm'> {
+ auto ProcessArgs(T1 base,
+ T2 disp,
+ Args... args) -> std::enable_if_t<B::RegisterClass::kAsRegister == 'm'> {
// Only tmp memory args are supported.
- static_assert(ArgTraits<B>::arg_info.arg_type == ArgInfo::TMP_ARG);
+ static_assert(B::arg_info.arg_type == ArgInfo::TMP_ARG);
this->SetRegAt(reg_idx, base);
if constexpr (disp_idx == 0) {
this->set_disp(disp);
diff --git a/backend/x86_64/machine_insn_intrinsics_tests.cc b/backend/x86_64/machine_insn_intrinsics_tests.cc
index 958968f..afafb9d 100644
--- a/backend/x86_64/machine_insn_intrinsics_tests.cc
+++ b/backend/x86_64/machine_insn_intrinsics_tests.cc
@@ -17,46 +17,73 @@
#include "gtest/gtest.h"
#include "berberis/backend/x86_64/machine_insn_intrinsics.h"
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
#include "berberis/intrinsics/intrinsics_args.h"
+#include "berberis/intrinsics/intrinsics_bindings.h"
namespace berberis {
namespace {
// TEST(MachineInsnIntrinsicsTest, HasNMem)
-static_assert(x86_64::has_n_mem_v<
- 1,
- TmpArg<intrinsics::bindings::Mem32, intrinsics::bindings::kDefEarlyClobber>>);
+static_assert(
+ x86_64::has_n_mem_v<
+ 1,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem32,
+ intrinsics::bindings::kDefEarlyClobber>>>);
static_assert(!x86_64::has_n_mem_v<1>);
-static_assert(!x86_64::has_n_mem_v<
- 1,
- TmpArg<intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDefEarlyClobber>>);
-static_assert(x86_64::has_n_mem_v<2,
- TmpArg<intrinsics::bindings::Mem32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::Mem32, intrinsics::bindings::kDef>>);
-static_assert(!x86_64::has_n_mem_v<
- 2,
- TmpArg<intrinsics::bindings::Mem32, intrinsics::bindings::kDefEarlyClobber>>);
+static_assert(
+ !x86_64::has_n_mem_v<
+ 1,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDefEarlyClobber>>>);
+static_assert(
+ x86_64::has_n_mem_v<2,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem32,
+ intrinsics::bindings::kDef>>>);
+static_assert(
+ !x86_64::has_n_mem_v<
+ 2,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem32,
+ intrinsics::bindings::kDefEarlyClobber>>>);
// TEST(MachineInsnIntrinsicsTest, ConstructorArgs)
static_assert(
- std::is_same_v<x86_64::constructor_args_t<
- TmpArg<intrinsics::bindings::Mem64, intrinsics::bindings::kDefEarlyClobber>>,
+ std::is_same_v<x86_64::constructor_args_t<ArgTraits<
+ TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem64,
+ intrinsics::bindings::kDefEarlyClobber>>>,
std::tuple<MachineReg, int32_t>>);
static_assert(
- std::is_same_v<x86_64::constructor_args_t<TmpArg<intrinsics::bindings::GeneralReg64,
- intrinsics::bindings::kDefEarlyClobber>>,
+ std::is_same_v<x86_64::constructor_args_t<ArgTraits<
+ TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg64,
+ intrinsics::bindings::kDefEarlyClobber>>>,
std::tuple<MachineReg>>);
-static_assert(std::is_same_v<x86_64::constructor_args_t<
- InArg<0, intrinsics::bindings::Imm32, intrinsics::bindings::kUse>>,
- std::tuple<int32_t>>);
+static_assert(
+ std::is_same_v<x86_64::constructor_args_t<
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Imm32,
+ intrinsics::bindings::kUse>>>,
+ std::tuple<int32_t>>);
static_assert(
std::is_same_v<
x86_64::constructor_args_t<
- InArg<0, intrinsics::bindings::Imm16, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::Mem64, intrinsics::bindings::kDefEarlyClobber>,
- TmpArg<intrinsics::bindings::GeneralReg64, intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Imm16,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::Mem64,
+ intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg64,
+ intrinsics::bindings::kDefEarlyClobber>>>,
std::tuple<int16_t, MachineReg, int32_t, MachineReg>>);
} // namespace
diff --git a/heavy_optimizer/riscv64/inline_intrinsic.h b/heavy_optimizer/riscv64/inline_intrinsic.h
index c293500..92f173b 100644
--- a/heavy_optimizer/riscv64/inline_intrinsic.h
+++ b/heavy_optimizer/riscv64/inline_intrinsic.h
@@ -32,9 +32,9 @@
#include "berberis/base/checks.h"
#include "berberis/base/config.h"
#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
#include "berberis/intrinsics/intrinsics.h"
#include "berberis/intrinsics/intrinsics_args.h"
+#include "berberis/intrinsics/intrinsics_bindings.h"
#include "berberis/intrinsics/intrinsics_process_bindings.h"
#include "berberis/intrinsics/macro_assembler.h"
#include "berberis/runtime_primitives/platform.h"
@@ -363,22 +363,23 @@
return true;
}
- template <typename ArgBinding, typename IntrinsicBindingInfo>
- auto /*MakeTuplefromBindingsClient*/ operator()(ArgTraits<ArgBinding>, IntrinsicBindingInfo) {
- static constexpr const auto& arg_info = ArgTraits<ArgBinding>::arg_info;
+ template <typename ArgBinding, typename OperandInfo, typename IntrinsicBindingInfo>
+ auto /*MakeTuplefromBindingsClient*/ operator()(ArgTraits<ArgBinding, OperandInfo>,
+ IntrinsicBindingInfo) {
+ static constexpr const auto& arg_info = ArgTraits<ArgBinding, OperandInfo>::arg_info;
if constexpr (arg_info.arg_type == ArgInfo::IMM_ARG) {
auto imm = std::get<arg_info.from>(input_args_);
return std::tuple{imm};
} else {
- return ProcessArgInput<ArgBinding, IntrinsicBindingInfo>();
+ return ProcessArgInput<ArgBinding, OperandInfo, IntrinsicBindingInfo>();
}
}
- template <typename ArgBinding, typename IntrinsicBindingInfo>
+ template <typename ArgBinding, typename OperandInfo, typename IntrinsicBindingInfo>
auto ProcessArgInput() {
- static constexpr const auto& arg_info = ArgTraits<ArgBinding>::arg_info;
- using RegisterClass = typename ArgTraits<ArgBinding>::RegisterClass;
- static constexpr auto kUsage = ArgTraits<ArgBinding>::kUsage;
+ static constexpr const auto& arg_info = ArgTraits<ArgBinding, OperandInfo>::arg_info;
+ using RegisterClass = typename ArgTraits<ArgBinding, OperandInfo>::RegisterClass;
+ static constexpr auto kUsage = ArgTraits<ArgBinding, OperandInfo>::kUsage;
static constexpr auto kNumOut =
std::tuple_size_v<typename IntrinsicBindingInfo::OutputArguments>;
@@ -400,7 +401,7 @@
static_assert(!RegisterClass::kIsImplicitReg);
if constexpr (RegisterClass::kAsRegister == 'x') {
if constexpr (kNumOut > 1) {
- static_assert(kDependentTypeFalse<ArgTraits<ArgBinding>>);
+ static_assert(kDependentTypeFalse<ArgTraits<ArgBinding, OperandInfo>>);
} else {
CHECK(xmm_result_reg_.IsInvalidReg());
xmm_result_reg_ = AllocVReg();
@@ -421,7 +422,7 @@
static_assert(kUsage == intrinsics::bindings::kUseDef);
static_assert(RegisterClass::kIsImplicitReg);
if constexpr (kNumOut > 1) {
- static_assert(kDependentTypeFalse<ArgTraits<ArgBinding>>);
+ static_assert(kDependentTypeFalse<ArgTraits<ArgBinding, OperandInfo>>);
} else {
CHECK(implicit_result_reg_.IsInvalidReg());
implicit_result_reg_ = AllocVReg();
@@ -440,7 +441,7 @@
}
} else if constexpr (arg_info.arg_type == ArgInfo::OUT_TMP_ARG) {
if constexpr (kNumOut > 1) {
- static_assert(kDependentTypeFalse<ArgTraits<ArgBinding>>);
+ static_assert(kDependentTypeFalse<ArgTraits<ArgBinding, OperandInfo>>);
} else {
CHECK(implicit_result_reg_.IsInvalidReg());
implicit_result_reg_ = AllocVReg();
@@ -499,9 +500,9 @@
using type = T;
};
- template <typename IntrinsicBindingInfo, typename... ArgBinding>
- void ProcessBindingsResults(type_wrapper<std::tuple<ArgBinding...>>) {
- (ProcessBindingResult<ArgBinding, IntrinsicBindingInfo>(), ...);
+ template <typename IntrinsicBindingInfo, typename... ArgBinding, typename... OperandInfo>
+ void ProcessBindingsResults(type_wrapper<std::tuple<ArgTraits<ArgBinding, OperandInfo>...>>) {
+ (ProcessBindingResult<ArgBinding, OperandInfo, IntrinsicBindingInfo>(), ...);
if constexpr (std::tuple_size_v<typename IntrinsicBindingInfo::OutputArguments> == 0) {
// No return value. Do nothing.
} else if constexpr (std::tuple_size_v<typename IntrinsicBindingInfo::OutputArguments> == 1) {
@@ -529,13 +530,13 @@
}
}
- template <typename ArgBinding, typename IntrinsicBindingInfo>
+ template <typename ArgBinding, typename OperandInfo, typename IntrinsicBindingInfo>
void ProcessBindingResult() {
- if constexpr (ArgTraits<ArgBinding>::Class::kIsImmediate) {
+ if constexpr (ArgTraits<ArgBinding, OperandInfo>::Class::kIsImmediate) {
return;
} else {
- using RegisterClass = typename ArgTraits<ArgBinding>::RegisterClass;
- static constexpr const auto& arg_info = ArgTraits<ArgBinding>::arg_info;
+ using RegisterClass = typename ArgTraits<ArgBinding, OperandInfo>::RegisterClass;
+ static constexpr const auto& arg_info = ArgTraits<ArgBinding, OperandInfo>::arg_info;
if constexpr (RegisterClass::kAsRegister == 'm' || RegisterClass::kAsRegister == 0) {
return;
} else if constexpr ((arg_info.arg_type == ArgInfo::IN_OUT_ARG ||
diff --git a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/intrinsics_bindings.h b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/machine_insn_info.h
similarity index 82%
rename from intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/intrinsics_bindings.h
rename to intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/machine_insn_info.h
index d6e9fc7..06f2358 100644
--- a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/intrinsics_bindings.h
+++ b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/machine_insn_info.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-#ifndef BERBERIS_INTRINSICS_COMMON_TO_RISCV_INTRINSICS_BINDINGS_H_
-#define BERBERIS_INTRINSICS_COMMON_TO_RISCV_INTRINSICS_BINDINGS_H_
+#ifndef BERBERIS_INTRINSICS_COMMON_TO_RISCV_MACHINE_INSN_INFO_H_
+#define BERBERIS_INTRINSICS_COMMON_TO_RISCV_MACHINE_INSN_INFO_H_
#include <cstdint>
#include "berberis/assembler/riscv.h"
-#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/common/intrinsics_bindings.h"
-#include "berberis/intrinsics/intrinsics_args.h"
-#include "berberis/intrinsics/type_traits.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
namespace berberis::intrinsics::bindings {
@@ -97,4 +94,4 @@
} // namespace berberis::intrinsics::bindings
-#endif // BERBERIS_INTRINSICS_COMMON_TO_RISCV_INTRINSICS_BINDINGS_H_
+#endif // BERBERIS_INTRINSICS_COMMON_TO_RISCV_MACHINE_INSN_INFO_H_
diff --git a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/text_assembler_riscv.h b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/text_assembler_riscv.h
index 3fc0ae2..b87b031 100644
--- a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/text_assembler_riscv.h
+++ b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/text_assembler_riscv.h
@@ -27,7 +27,8 @@
#include "berberis/base/checks.h"
#include "berberis/base/config.h"
#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/all_to_riscv64/intrinsics_bindings.h"
+#include "berberis/intrinsics/all_to_riscv64/machine_insn_info.h"
+#include "berberis/intrinsics/common/intrinsics_bindings.h"
namespace berberis {
diff --git a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/verifier_assembler_riscv.h b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/verifier_assembler_riscv.h
index 9b5248c..fa78b0a 100644
--- a/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/verifier_assembler_riscv.h
+++ b/intrinsics/all_to_riscv64/include/berberis/intrinsics/all_to_riscv64/verifier_assembler_riscv.h
@@ -26,7 +26,7 @@
#include "berberis/base/checks.h"
#include "berberis/base/config.h"
#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/all_to_riscv64/intrinsics_bindings.h"
+#include "berberis/intrinsics/all_to_riscv64/machine_insn_info.h"
#include "berberis/intrinsics/common/intrinsics_bindings.h"
namespace berberis {
diff --git a/intrinsics/all_to_riscv64/include/berberis/intrinsics/intrinsics_bindings.h b/intrinsics/all_to_riscv64/include/berberis/intrinsics/intrinsics_bindings.h
new file mode 100644
index 0000000..9d67f35
--- /dev/null
+++ b/intrinsics/all_to_riscv64/include/berberis/intrinsics/intrinsics_bindings.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2025 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_INTRINSICS_BINDINGS_H_
+#define BERBERIS_INTRINSICS_INTRINSICS_BINDINGS_H_
+
+#include "berberis/intrinsics/common/intrinsics_bindings.h"
+#include "berberis/intrinsics/machine_insn_info.h"
+
+#endif // BERBERIS_INTRINSICS_INTRINSICS_BINDINGS_H_
diff --git a/intrinsics/all_to_riscv64/include/berberis/intrinsics/machine_insn_info.h b/intrinsics/all_to_riscv64/include/berberis/intrinsics/machine_insn_info.h
new file mode 100644
index 0000000..09cd47c
--- /dev/null
+++ b/intrinsics/all_to_riscv64/include/berberis/intrinsics/machine_insn_info.h
@@ -0,0 +1,23 @@
+/*
+ * 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_MACHINE_INSN_INFO_H_
+#define BERBERIS_INTRINSICS_MACHINE_INSN_INFO_H_
+
+#include "berberis/intrinsics/all_to_riscv64/machine_insn_info.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
+
+#endif // BERBERIS_INTRINSICS_MACHINE_INSN_INFO_H_
diff --git a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h
similarity index 94%
rename from intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h
rename to intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h
index 51cd64e..62eeb04 100644
--- a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h
+++ b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-#ifndef BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_INTRINSICS_BINDINGS_H_
-#define BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_INTRINSICS_BINDINGS_H_
+#ifndef BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_MACHINE_INSN_INFO_H_
+#define BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_MACHINE_INSN_INFO_H_
#include <xmmintrin.h>
#include <cstdint>
-#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/common/intrinsics_bindings.h"
-#include "berberis/intrinsics/intrinsics_args.h"
-#include "berberis/intrinsics/type_traits.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
namespace berberis::intrinsics::bindings {
@@ -344,4 +341,4 @@
} // namespace berberis::intrinsics::bindings
-#endif // BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_INTRINSICS_BINDINGS_H_
+#endif // BERBERIS_INTRINSICS_ALL_TO_X86_32_OR_x86_64_MACHINE_INSN_INFO_H_
diff --git a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/text_assembler_x86_32_and_x86_64.h b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/text_assembler_x86_32_and_x86_64.h
index 15ea057..193e429 100644
--- a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/text_assembler_x86_32_and_x86_64.h
+++ b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/text_assembler_x86_32_and_x86_64.h
@@ -26,7 +26,7 @@
#include "berberis/base/checks.h"
#include "berberis/base/config.h"
#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
+#include "berberis/intrinsics/common/intrinsics_bindings.h"
namespace berberis {
diff --git a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_x86_32_and_x86_64.h b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_x86_32_and_x86_64.h
index 35600bd..5a3ab3c 100644
--- a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_x86_32_and_x86_64.h
+++ b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_x86_32_and_x86_64.h
@@ -26,7 +26,7 @@
#include "berberis/base/checks.h"
#include "berberis/base/config.h"
#include "berberis/base/dependent_false.h"
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
+#include "berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h"
#include "berberis/intrinsics/common/intrinsics_bindings.h"
namespace berberis {
diff --git a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/intrinsics_bindings.h b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/intrinsics_bindings.h
index fe32c39..1f13a3f 100644
--- a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/intrinsics_bindings.h
+++ b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/intrinsics_bindings.h
@@ -17,6 +17,7 @@
#ifndef BERBERIS_INTRINSICS_INTRINSICS_BINDINGS_H_
#define BERBERIS_INTRINSICS_INTRINSICS_BINDINGS_H_
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
+#include "berberis/intrinsics/common/intrinsics_bindings.h"
+#include "berberis/intrinsics/machine_insn_info.h"
#endif // BERBERIS_INTRINSICS_INTRINSICS_BINDINGS_H_
diff --git a/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/machine_insn_info.h b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/machine_insn_info.h
new file mode 100644
index 0000000..41c7b2a
--- /dev/null
+++ b/intrinsics/all_to_x86_32_or_x86_64/include/berberis/intrinsics/machine_insn_info.h
@@ -0,0 +1,23 @@
+/*
+ * 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_MACHINE_INSN_INFO_H_
+#define BERBERIS_INTRINSICS_MACHINE_INSN_INFO_H_
+
+#include "berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
+
+#endif // BERBERIS_INTRINSICS_MACHINE_INSN_INFO_H_
diff --git a/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_test.cc b/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_test.cc
index cfb80b5..49038f6 100644
--- a/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_test.cc
+++ b/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_test.cc
@@ -16,9 +16,10 @@
#include "gtest/gtest.h"
-#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_bindings.h"
#include "berberis/intrinsics/all_to_x86_32_or_x86_64/intrinsics_float.h"
+#include "berberis/intrinsics/all_to_x86_32_or_x86_64/machine_insn_info.h"
#include "berberis/intrinsics/all_to_x86_32_or_x86_64/verifier_assembler_x86_32_and_x86_64.h"
+#include "berberis/intrinsics/common/intrinsics_bindings.h"
namespace berberis {
@@ -194,8 +195,12 @@
false,
std::tuple<SIMD128Register, SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<InOutArg<0, 0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDef>,
- InArg<1, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>>>;
+ std::tuple<ArgTraits<InOutArg<0, 0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>>>;
VerifyIntrinsic<IntrinsicBindingInfo>();
}
@@ -211,8 +216,12 @@
false,
std::tuple<SIMD128Register, SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<InOutArg<0, 0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDef>,
- InArg<1, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>>>;
+ std::tuple<ArgTraits<InOutArg<0, 0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>>>;
ASSERT_DEATH(VerifyIntrinsic<IntrinsicBindingInfo>(), "error: expect_sse3 != need_sse3");
}
@@ -229,9 +238,15 @@
std::tuple<uint32_t, uint32_t>,
std::tuple<uint32_t>,
std::tuple<
- OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDefEarlyClobber>,
- InOutArg<1, 1, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUseDef>,
- InArg<2, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>>>;
+ ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<InOutArg<1, 1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUseDef>>,
+ ArgTraits<InArg<2>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>>>;
ASSERT_DEATH(VerifyIntrinsic<IntrinsicBindingInfo>(), "error: expect_flags != defines_flags");
}
@@ -247,10 +262,19 @@
false,
std::tuple<SIMD128Register, SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<OutArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDefEarlyClobber>,
- InArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>,
- InArg<1, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ std::tuple<
+ ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<InArg<1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
ASSERT_DEATH(VerifyIntrinsic<IntrinsicBindingInfo>(), "error: expect_flags != defines_flags");
}
@@ -267,10 +291,18 @@
std::tuple<uint32_t, uint32_t>,
std::tuple<uint32_t>,
std::tuple<
- OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDefEarlyClobber>,
- InOutArg<1, 1, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUseDef>,
- InArg<2, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<InOutArg<1, 1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUseDef>>,
+ ArgTraits<InArg<2>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
VerifyIntrinsic<IntrinsicBindingInfo>();
}
@@ -286,10 +318,18 @@
false,
std::tuple<uint32_t, uint32_t>,
std::tuple<uint32_t>,
- std::tuple<OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDef>,
- InOutArg<1, 1, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUseDef>,
- InArg<2, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InOutArg<1, 1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUseDef>>,
+ ArgTraits<InArg<2>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
ASSERT_DEATH(
VerifyIntrinsic<IntrinsicBindingInfo>(),
@@ -307,9 +347,16 @@
false,
std::tuple<SIMD128Register, SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<OutArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDefEarlyClobber>,
- InArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>,
- InArg<1, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>>>;
+ std::tuple<
+ ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDefEarlyClobber>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<InArg<1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>>>;
VerifyIntrinsic<IntrinsicBindingInfo>();
}
@@ -325,9 +372,15 @@
false,
std::tuple<SIMD128Register, SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<OutArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>,
- InArg<1, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<InArg<1>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>>>;
ASSERT_DEATH(VerifyIntrinsic<IntrinsicBindingInfo>(),
"error: intrinsic used a 'use' xmm register after writing to a 'def' xmm register");
@@ -344,8 +397,12 @@
false,
std::tuple<uint32_t>,
std::tuple<uint32_t>,
- std::tuple<OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>>>;
VerifyIntrinsic<IntrinsicBindingInfo>();
}
@@ -361,9 +418,15 @@
false,
std::tuple<uint32_t>,
std::tuple<uint32_t>,
- std::tuple<OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
ASSERT_DEATH(
VerifyIntrinsic<IntrinsicBindingInfo>(),
@@ -381,9 +444,15 @@
false,
std::tuple<uint32_t>,
std::tuple<uint32_t>,
- std::tuple<OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
VerifyIntrinsic<IntrinsicBindingInfo>();
}
@@ -399,9 +468,15 @@
false,
std::tuple<uint32_t>,
std::tuple<uint32_t>,
- std::tuple<OutArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::GeneralReg32, intrinsics::bindings::kUse>,
- TmpArg<intrinsics::bindings::FLAGS, intrinsics::bindings::kDef>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::GeneralReg32,
+ intrinsics::bindings::kUse>>,
+ ArgTraits<TmpArg,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::FLAGS,
+ intrinsics::bindings::kDef>>>>;
ASSERT_DEATH(
VerifyIntrinsic<IntrinsicBindingInfo>(),
@@ -419,8 +494,12 @@
false,
std::tuple<SIMD128Register>,
std::tuple<SIMD128Register>,
- std::tuple<OutArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kDef>,
- InArg<0, intrinsics::bindings::XmmReg, intrinsics::bindings::kUse>>>;
+ std::tuple<ArgTraits<OutArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kDef>>,
+ ArgTraits<InArg<0>,
+ intrinsics::bindings::OperandInfo<intrinsics::bindings::XmmReg,
+ intrinsics::bindings::kUse>>>>;
ASSERT_DEATH(VerifyIntrinsic<IntrinsicBindingInfo>(),
"error: intrinsic used a 'use' xmm register after writing to a 'def' xmm register");
diff --git a/intrinsics/gen_intrinsics.py b/intrinsics/gen_intrinsics.py
index b7ad0fe..d3d95ca 100755
--- a/intrinsics/gen_intrinsics.py
+++ b/intrinsics/gen_intrinsics.py
@@ -886,12 +886,13 @@
if info_prefix is None:
class_info = ''
else:
- class_info = ', %s::%s' % (info_prefix, arg['class'])
+ class_info = '%s::%s' % (info_prefix, arg['class'])
if arg['class'] == 'Imm8':
if info_prefix is None:
return 'ImmArg<%d, int8_t>' % (arg['ir_arg'])
else:
- return 'ImmArg<%d, int8_t%s>' % (arg['ir_arg'], class_info)
+ return 'ImmArg<%d>, intrinsics::bindings::OperandInfo<%s, %s::kUse>' % (
+ arg['ir_arg'], class_info, info_prefix)
if info_prefix is None:
using_info = ''
else:
@@ -901,34 +902,37 @@
'use': 'kUse',
'use_def': 'kUseDef'
}[arg['usage']])
+ if info_prefix is None:
+ operand_info = ''
+ else:
+ operand_info = ', intrinsics::bindings::OperandInfo<%s%s>' % (
+ class_info, using_info)
if arg['usage'] == 'use':
if need_tmp:
- return 'InTmpArg<%d%s%s>' % (arg['ir_arg'], class_info, using_info)
- return 'InArg<%d%s%s>' % (arg['ir_arg'], class_info, using_info)
+ return 'InTmpArg<%d>%s' % (arg['ir_arg'], operand_info)
+ return 'InArg<%d>%s' % (arg['ir_arg'], operand_info)
if arg['usage'] in ('def', 'def_early_clobber'):
assert 'ir_arg' not in arg
if 'ir_res' in arg:
if need_tmp:
- return 'OutTmpArg<%d%s%s>' % (arg['ir_res'], class_info, using_info)
- return 'OutArg<%d%s%s>' % (arg['ir_res'], class_info, using_info)
- if info_prefix is None:
- return 'TmpArg'
- else:
- return 'TmpArg<%s%s>' % (class_info[2:], using_info)
+ return 'OutTmpArg<%d>%s' % (arg['ir_res'], operand_info)
+ return 'OutArg<%d>%s' % (arg['ir_res'], operand_info)
+ return 'TmpArg%s' % operand_info
if arg['usage'] == 'use_def':
if 'ir_res' in arg:
if need_tmp:
- return 'InOutTmpArg<%s, %s%s%s>' % (arg['ir_arg'], arg['ir_res'],
- class_info, using_info)
- return 'InOutArg<%s, %s%s%s>' % (arg['ir_arg'], arg['ir_res'],
- class_info, using_info)
- return 'InTmpArg<%s%s%s>' % (arg['ir_arg'], class_info, using_info)
+ return 'InOutTmpArg<%s, %s>%s' % (
+ arg['ir_arg'], arg['ir_res'], operand_info)
+ return 'InOutArg<%s, %s>%s' % (
+ arg['ir_arg'], arg['ir_res'], operand_info)
+ return 'InTmpArg<%s>%s' % (
+ arg['ir_arg'], operand_info)
assert False, 'unknown operand usage %s' % (arg['usage'])
def _get_reg_operands_info(args, info_prefix=None):
return 'std::tuple<%s>' % ', '.join(
- _get_reg_operand_info(arg, info_prefix)
+ 'ArgTraits<%s>' % _get_reg_operand_info(arg, info_prefix)
for arg in args)
diff --git a/intrinsics/include/berberis/intrinsics/common/intrinsics_bindings.h b/intrinsics/include/berberis/intrinsics/common/intrinsics_bindings.h
index 55f0a69..bb67b8c 100644
--- a/intrinsics/include/berberis/intrinsics/common/intrinsics_bindings.h
+++ b/intrinsics/include/berberis/intrinsics/common/intrinsics_bindings.h
@@ -20,6 +20,7 @@
#include <cstdint>
#include "berberis/base/dependent_false.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
#include "berberis/intrinsics/intrinsics_args.h"
#include "berberis/intrinsics/type_traits.h"
@@ -27,49 +28,6 @@
namespace intrinsics::bindings {
-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 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';
-};
-
-enum RegBindingKind { kDef = 2, kDefEarlyClobber = 3, kUse = 5, kUseDef = 7 };
-
-// Tag classes. They are never instantioned, only used as tags to pass information about
-// bindings.
-class NoCPUIDRestriction; // All CPUs have at least “no CPUID restriction” mode.
-
// Tag classes. They are never instantioned, only used as tags to pass information about
// bindings.
class NoNansOperation;
@@ -121,15 +79,15 @@
TypeTraits<OutputArgumentsTypes>::kName...};
template <typename Callback, typename... Args>
constexpr static void ProcessBindings(Callback&& callback, Args&&... args) {
- (callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...), ...);
+ (callback(BindingsTypes(), std::forward<Args>(args)...), ...);
}
template <typename Callback, typename... Args>
constexpr static bool VerifyBindings(Callback&& callback, Args&&... args) {
- return (callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...) && ...);
+ return (callback(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)...)...);
+ return std::tuple_cat(callback(BindingsTypes(), std::forward<Args>(args)...)...);
}
using InputArguments = std::tuple<InputArgumentsTypes...>;
using OutputArguments = std::tuple<OutputArgumentsTypes...>;
diff --git a/intrinsics/include/berberis/intrinsics/common/machine_insn_info.h b/intrinsics/include/berberis/intrinsics/common/machine_insn_info.h
new file mode 100644
index 0000000..c62fb64
--- /dev/null
+++ b/intrinsics/include/berberis/intrinsics/common/machine_insn_info.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 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_MACHINE_INSN_INFO_H_
+#define BERBERIS_INTRINSICS_COMMON_MACHINE_INSN_INFO_H_
+
+#include <cstdint>
+
+namespace berberis::intrinsics::bindings {
+
+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 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';
+};
+
+// Note: value of RegBindingKind and MachineRegKind have to be the same since we convert one to
+// another with a static_cast in berberis/backend/x86_64/machine_insn_intrinsics.h. We don't care
+// about these values in intrinsics module, but for optimizations it's important to have LSB set
+// when an instruction uses the value (which is true for kDefEarlyClobber: in that case the
+// instruction sets the value and then uses it), the next bit is set when register is output and MSB
+// bit is set when register is input. We have static_assert in the aforemetioned header that ensures
+// that an attempt to change these two enums and make them different would lead to a compile-time
+// error.
+enum RegBindingKind { kDef = 2, kDefEarlyClobber = 3, kUse = 5, kUseDef = 7 };
+
+template <typename RegisterClassTemplateName, RegBindingKind kUsageTemplateName>
+class OperandInfo {
+ public:
+ using RegisterClass = RegisterClassTemplateName;
+ static constexpr RegBindingKind kUsage = kUsageTemplateName;
+ static_assert(!RegisterClass::kIsImmediate || kUsage == kUse);
+};
+
+// Tag classes. They are never instantioned, only used as tags to pass information about
+// bindings.
+class NoCPUIDRestriction; // All CPUs have at least “no CPUID restriction” mode.
+
+} // namespace berberis::intrinsics::bindings
+
+#endif // BERBERIS_INTRINSICS_COMMON_MACHINE_INSN_INFO_H_
diff --git a/intrinsics/include/berberis/intrinsics/intrinsics_args.h b/intrinsics/include/berberis/intrinsics/intrinsics_args.h
index 758556b..76f46c1 100644
--- a/intrinsics/include/berberis/intrinsics/intrinsics_args.h
+++ b/intrinsics/include/berberis/intrinsics/intrinsics_args.h
@@ -21,6 +21,7 @@
#include <cstdio>
#include "berberis/base/checks.h"
+#include "berberis/intrinsics/common/machine_insn_info.h"
namespace berberis {
@@ -118,35 +119,34 @@
const int to = 0;
};
-template <int N, typename RegisterClass, auto kUsage>
+template <int N>
class InArg;
-template <int N, typename RegisterClass, auto kUsage>
+template <int N>
class OutArg;
-template <int N, typename RegisterClass, auto kUsage>
+template <int N>
class OutTmpArg;
-template <int N, int M, typename RegisterClass, auto kUsage>
+template <int N, int M>
class InOutArg;
-template <int N, int M, typename RegisterClass, auto kUsage>
+template <int N, int M>
class InOutTmpArg;
-template <int N, typename RegisterClass, auto kUsage>
+template <int N>
class InTmpArg;
-template <int N, typename ImmType, typename ImmediateClass>
+template <int N, typename ImmType = void>
class ImmArg;
-template <typename RegisterClass, auto kUsage>
class TmpArg;
-template <typename ArgInfo>
+template <typename ArgInfo, typename OperandInfo>
class ArgTraits;
template <int N, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<InArg<N, RegisterClassType, kUsageParam>> {
+class ArgTraits<InArg<N>, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -155,7 +155,7 @@
};
template <int N, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<OutArg<N, RegisterClassType, kUsageParam>> {
+class ArgTraits<OutArg<N>, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -164,7 +164,7 @@
};
template <int N, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<OutTmpArg<N, RegisterClassType, kUsageParam>> {
+class ArgTraits<OutTmpArg<N>, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -173,7 +173,7 @@
};
template <int N, int M, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<InOutArg<N, M, RegisterClassType, kUsageParam>> {
+class ArgTraits<InOutArg<N, M>, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -182,7 +182,8 @@
};
template <int N, int M, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<InOutTmpArg<N, M, RegisterClassType, kUsageParam>> {
+class ArgTraits<InOutTmpArg<N, M>,
+ intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -191,7 +192,7 @@
};
template <int N, typename RegisterClassType, auto kUsageParam>
-class ArgTraits<InTmpArg<N, RegisterClassType, kUsageParam>> {
+class ArgTraits<InTmpArg<N>, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -199,8 +200,9 @@
static constexpr ArgInfo arg_info{.arg_type = ArgInfo::IN_TMP_ARG, .from = N};
};
-template <int N, typename ImmType, typename ImmediateClassType>
-class ArgTraits<ImmArg<N, ImmType, ImmediateClassType>> {
+template <int N, typename ImmediateClassType>
+class ArgTraits<ImmArg<N>,
+ intrinsics::bindings::OperandInfo<ImmediateClassType, intrinsics::bindings::kUse>> {
public:
using Class = ImmediateClassType;
using ImmediateClass = ImmediateClassType;
@@ -208,7 +210,7 @@
};
template <typename RegisterClassType, auto kUsageParam>
-class ArgTraits<TmpArg<RegisterClassType, kUsageParam>> {
+class ArgTraits<TmpArg, intrinsics::bindings::OperandInfo<RegisterClassType, kUsageParam>> {
public:
using Class = RegisterClassType;
using RegisterClass = RegisterClassType;
@@ -274,9 +276,9 @@
return true;
}
-template <typename MachineInsn, typename... Args>
+template <typename MachineInsn, typename... Args, typename... Operands>
constexpr bool IsCompatible() {
- const ArgInfo arguments[] = {ArgTraits<Args>::arg_info...};
+ const ArgInfo arguments[] = {ArgTraits<Args, Operands>::arg_info...};
// Note: we couldn't pass arguments as an array into IsCompatible by reference
// because this would cause compilation error in case where we have no arguments.
//
diff --git a/lite_translator/riscv64_to_x86_64/inline_intrinsic.h b/lite_translator/riscv64_to_x86_64/inline_intrinsic.h
index deccaa8..e0c6df2 100644
--- a/lite_translator/riscv64_to_x86_64/inline_intrinsic.h
+++ b/lite_translator/riscv64_to_x86_64/inline_intrinsic.h
@@ -319,29 +319,33 @@
return {true};
}
- template <typename ArgBinding, typename IntrinsicBindingInfo>
- auto /*MakeTuplefromBindingsClient*/ operator()(ArgTraits<ArgBinding>, IntrinsicBindingInfo) {
- static constexpr const auto& arg_info = ArgTraits<ArgBinding>::arg_info;
+ template <typename ArgBinding, typename OperandInfo, typename IntrinsicBindingInfo>
+ auto /*MakeTuplefromBindingsClient*/ operator()(ArgTraits<ArgBinding, OperandInfo>,
+ IntrinsicBindingInfo) {
+ static constexpr const auto& arg_info = ArgTraits<ArgBinding, OperandInfo>::arg_info;
if constexpr (arg_info.arg_type == ArgInfo::IMM_ARG) {
- return ProcessArgInput<ArgBinding, IntrinsicBindingInfo>(reg_alloc_);
+ return ProcessArgInput<ArgBinding, OperandInfo, IntrinsicBindingInfo>(reg_alloc_);
} else {
- using RegisterClass = typename ArgTraits<ArgBinding>::RegisterClass;
+ using RegisterClass = typename ArgTraits<ArgBinding, OperandInfo>::RegisterClass;
if constexpr (RegisterClass::kAsRegister == 'x') {
- return ProcessArgInput<ArgBinding, IntrinsicBindingInfo>(simd_reg_alloc_);
+ return ProcessArgInput<ArgBinding, OperandInfo, IntrinsicBindingInfo>(simd_reg_alloc_);
} else {
- return ProcessArgInput<ArgBinding, IntrinsicBindingInfo>(reg_alloc_);
+ return ProcessArgInput<ArgBinding, OperandInfo, IntrinsicBindingInfo>(reg_alloc_);
}
}
}
- template <typename ArgBinding, typename IntrinsicBindingInfo, typename RegAllocForArg>
+ template <typename ArgBinding,
+ typename OperandInfo,
+ typename IntrinsicBindingInfo,
+ typename RegAllocForArg>
auto ProcessArgInput(RegAllocForArg&& reg_alloc) {
- static constexpr const auto& arg_info = ArgTraits<ArgBinding>::arg_info;
+ static constexpr const auto& arg_info = ArgTraits<ArgBinding, OperandInfo>::arg_info;
if constexpr (arg_info.arg_type == ArgInfo::IMM_ARG) {
return std::tuple{std::get<arg_info.from>(input_args_)};
} else {
- using RegisterClass = typename ArgTraits<ArgBinding>::RegisterClass;
- static constexpr auto kUsage = ArgTraits<ArgBinding>::kUsage;
+ using RegisterClass = typename ArgTraits<ArgBinding, OperandInfo>::RegisterClass;
+ static constexpr auto kUsage = ArgTraits<ArgBinding, OperandInfo>::kUsage;
if constexpr (arg_info.arg_type == ArgInfo::IN_ARG) {
using Type =
std::tuple_element_t<arg_info.from, typename IntrinsicBindingInfo::InputArguments>;