blob: e7cafae75bdb22bee1344430c52f1814688273af [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 DEFINE_MACRO_ASSEMBLER_GENERIC_FUNCTIONS
#error This file is supposed to be included from berberis/intrinsics/macro_assembler-inl.h
#else
#undef DEFINE_MACRO_ASSEMBLER_GENERIC_FUNCTIONS
#endif
using Condition = typename Assembler::Condition;
using Label = typename Assembler::Label;
using Operand = typename Assembler::Operand;
using Register = typename Assembler::Register;
using ScaleFactor = typename Assembler::ScaleFactor;
using XMMRegister = typename Assembler::XMMRegister;
using Float32 = intrinsics::Float32;
using Float64 = intrinsics::Float64;
template <typename IntType>
using ImmFormat =
std::conditional_t<sizeof(IntType) <= sizeof(int32_t), std::make_signed_t<IntType>, int32_t>;
template <typename format, typename... allowed_formats>
static constexpr bool kFormatIs = (std::is_same_v<format, allowed_formats> || ...);
template <typename IntType>
static constexpr bool kIntType =
kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
template <typename IntType>
static constexpr bool kIntTypeBW = kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t>;
template <typename IntType>
static constexpr bool kIntTypeBWL =
kFormatIs<IntType, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t>;
template <typename IntType>
static constexpr bool kIntTypeWL = kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t>;
template <typename IntType>
static constexpr bool kIntTypeWLQ =
kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
template <typename IntType>
static constexpr bool kIntTypeLQ = kFormatIs<IntType, int32_t, uint32_t, int64_t, uint64_t>;
// Psr is the only asymmetric instruction where unsigned 64bit variant was supported in MMX in CPUs
// released last century while signed 64bit variant is only added in AVX10 which is not yet even
// available for purchase!
template <typename IntType>
static constexpr bool kIntTypePsr =
kFormatIs<IntType, int16_t, uint16_t, int32_t, uint32_t, uint64_t>;
template <typename IntType>
static constexpr bool kSignedIntType = kFormatIs<IntType, int8_t, int16_t, int32_t, int64_t>;
template <typename IntType>
static constexpr bool kUnsignedIntType = kFormatIs<IntType, uint8_t, uint16_t, uint32_t, uint64_t>;
template <typename FloatType>
static constexpr bool kFloatType = kFormatIs<FloatType, Float32, Float64>;
#define DEFINE_EXPAND_INSTRUCTION(Declare_dest, Declare_src) \
template <typename format_out, typename format_in> \
std::enable_if_t<kIntType<format_out> && kIntType<format_in> && \
sizeof(format_in) <= sizeof(format_out)> \
Expand(Declare_dest, Declare_src) { \
if constexpr (std::is_same_v<decltype(dest), decltype(src)> && \
sizeof(format_out) == sizeof(format_in)) { \
if (dest == src) { \
return; \
} \
} \
if constexpr (kFormatIs<format_out, int8_t, uint8_t> && \
kFormatIs<format_in, int8_t, uint8_t>) { \
Assembler::Movb(dest, src); \
} else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
kFormatIs<format_in, int8_t>) { \
Assembler::Movsxbw(dest, src); \
} else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
kFormatIs<format_in, uint8_t>) { \
Assembler::Movzxbw(dest, src); \
} else if constexpr (kFormatIs<format_out, int16_t, uint16_t> && \
kFormatIs<format_in, int16_t, uint16_t>) { \
Assembler::Movw(dest, src); \
} else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
kFormatIs<format_in, int8_t>) { \
Assembler::Movsxbl(dest, src); \
} else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
kFormatIs<format_in, uint8_t>) { \
Assembler::Movzxbl(dest, src); \
} else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
kFormatIs<format_in, int16_t>) { \
Assembler::Movsxwl(dest, src); \
} else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
kFormatIs<format_in, uint16_t>) { \
Assembler::Movzxwl(dest, src); \
} else if constexpr (kFormatIs<format_out, int32_t, uint32_t> && \
kFormatIs<format_in, int32_t, uint32_t>) { \
Assembler::Movl(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, int8_t>) { \
Assembler::Movsxbq(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, uint8_t>) { \
Assembler::Movzxbl(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, int16_t>) { \
Assembler::Movsxwq(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, uint16_t>) { \
Assembler::Movzxwl(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, int32_t>) { \
Assembler::Movsxlq(dest, src); \
} else if constexpr (kFormatIs<format_out, int64_t, uint64_t> && \
kFormatIs<format_in, uint32_t>) { \
Assembler::Movl(dest, src); \
} else { \
Assembler::Movq(dest, src); \
} \
}
DEFINE_EXPAND_INSTRUCTION(Register dest, Operand src)
DEFINE_EXPAND_INSTRUCTION(Register dest, Register src)
#undef DEFINE_EXPAND_INSTRUCTION
#define DEFINE_INT_INSTRUCTION( \
insn_name, asm_name, insn_siffix, type_check, parameters, arguments) \
template <typename format> \
std::enable_if_t<type_check<format>> insn_name##insn_siffix parameters { \
if constexpr (kFormatIs<format, int8_t, uint8_t>) { \
Assembler::asm_name##b##insn_siffix arguments; \
} else if constexpr (kFormatIs<format, int16_t, uint16_t>) { \
Assembler::asm_name##w##insn_siffix arguments; \
} else if constexpr (kFormatIs<format, int32_t, uint32_t>) { \
Assembler::asm_name##l##insn_siffix arguments; \
} else { \
Assembler::asm_name##q##insn_siffix arguments; \
} \
}
DEFINE_INT_INSTRUCTION(CmpXchg, CmpXchg, , kIntType, (Operand dest, Register src), (dest, src))
DEFINE_INT_INSTRUCTION(CmpXchg, CmpXchg, , kIntType, (Register dest, Register src), (dest, src))
DEFINE_INT_INSTRUCTION(LockCmpXchg,
LockCmpXchg,
,
kIntType,
(Operand dest, Register src),
(dest, src))
DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm))
DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Operand dest, Register src), (dest, src))
DEFINE_INT_INSTRUCTION(Mov,
Mov,
,
kIntType,
(Register dest, std::make_signed_t<format> imm),
(dest, imm))
DEFINE_INT_INSTRUCTION(Mov, Mov, , kIntType, (Register dest, Operand src), (dest, src))
DEFINE_INT_INSTRUCTION(Mul, Imul, , kIntTypeWLQ, (Operand dest, Register src), (dest, src))
DEFINE_INT_INSTRUCTION(Mul, Imul, , kIntTypeWLQ, (Operand dest, Operand src), (dest, src))
DEFINE_INT_INSTRUCTION(Mul,
Imul,
,
kIntTypeWLQ,
(Operand dest, Register src, ImmFormat<format> imm),
(dest, src, imm))
DEFINE_INT_INSTRUCTION(Mul,
Imul,
,
kIntTypeWLQ,
(Operand dest, Operand src, ImmFormat<format> imm),
(dest, src, imm))
DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm))
DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Operand dest, Register src), (dest, src))
DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Register dest, ImmFormat<format> imm), (dest, imm))
DEFINE_INT_INSTRUCTION(Test, Test, , kIntType, (Register dest, Register src), (dest, src))
#define DEFINE_ARITH_INSTRUCTION(insn_name, asm_name, type_check) \
DEFINE_INT_INSTRUCTION(insn_name, asm_name, , type_check, (Operand arg), (arg)) \
DEFINE_INT_INSTRUCTION(insn_name, asm_name, , type_check, (Register arg), (arg))
DEFINE_ARITH_INSTRUCTION(Dec, Dec, kIntType)
DEFINE_ARITH_INSTRUCTION(Div, Div, kUnsignedIntType)
DEFINE_ARITH_INSTRUCTION(Div, Idiv, kSignedIntType)
DEFINE_ARITH_INSTRUCTION(Inc, Inc, kIntType)
DEFINE_ARITH_INSTRUCTION(Mul, Imul, kSignedIntType)
DEFINE_ARITH_INSTRUCTION(Mul, Mul, kUnsignedIntType)
DEFINE_ARITH_INSTRUCTION(Neg, Neg, kIntType)
DEFINE_ARITH_INSTRUCTION(Not, Not, kIntType)
#undef DEFINE_ARITH_INSTRUCTION
#define DEFINE_ARITH_INSTRUCTION(insn_name) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Operand dest, ImmFormat<format> imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Operand dest, Register src), (dest, src)) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Register dest, ImmFormat<format> imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Register dest, Operand src), (dest, src)) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Register dest, Register src), (dest, src))
DEFINE_ARITH_INSTRUCTION(Adc)
DEFINE_ARITH_INSTRUCTION(Add)
DEFINE_ARITH_INSTRUCTION(And)
DEFINE_ARITH_INSTRUCTION(Cmp)
DEFINE_ARITH_INSTRUCTION(Or)
DEFINE_ARITH_INSTRUCTION(Sbb)
DEFINE_ARITH_INSTRUCTION(Sub)
DEFINE_ARITH_INSTRUCTION(Xor)
#undef DEFINE_ARITH_INSTRUCTION
#define DEFINE_SHIFT_INSTRUCTION(insn_name) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Operand dest, int8_t imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION(insn_name, insn_name, ByCl, kIntType, (Operand dest), (dest)) \
DEFINE_INT_INSTRUCTION( \
insn_name, insn_name, , kIntType, (Register dest, int8_t imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION(insn_name, insn_name, ByCl, kIntType, (Register dest), (dest))
DEFINE_SHIFT_INSTRUCTION(Rcl)
DEFINE_SHIFT_INSTRUCTION(Rcr)
DEFINE_SHIFT_INSTRUCTION(Rol)
DEFINE_SHIFT_INSTRUCTION(Ror)
DEFINE_SHIFT_INSTRUCTION(Sar)
DEFINE_SHIFT_INSTRUCTION(Shl)
DEFINE_SHIFT_INSTRUCTION(Shr)
#undef DEFINE_INT_INSTRUCTION
#undef DEFINE_SHIFT_INSTRUCTION
#define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename format> \
std::enable_if_t<kIntTypeWLQ<format>> insn_name parameters { \
if constexpr (kFormatIs<format, int16_t, uint16_t>) { \
Assembler::insn_name##w arguments; \
} else if constexpr (kFormatIs<format, int32_t, uint32_t>) { \
Assembler::insn_name##l arguments; \
} else { \
Assembler::insn_name##q arguments; \
} \
}
DEFINE_INT_INSTRUCTION(Cmov, (Condition cond, Register dest, Operand src), (cond, dest, src))
DEFINE_INT_INSTRUCTION(Cmov, (Condition cond, Register dest, Register src), (cond, dest, src))
#define DEFINE_BIT_INSTRUCTION(insn_name) \
DEFINE_INT_INSTRUCTION(insn_name, (Operand dest, ImmFormat<format> imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION(insn_name, (Operand dest, Register src), (dest, src)) \
DEFINE_INT_INSTRUCTION(insn_name, (Register dest, ImmFormat<format> imm), (dest, imm)) \
DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Register src), (dest, src))
DEFINE_BIT_INSTRUCTION(Bt)
DEFINE_BIT_INSTRUCTION(Btc)
DEFINE_BIT_INSTRUCTION(Btr)
DEFINE_BIT_INSTRUCTION(Bts)
#undef DEFINE_BIT_INSTRUCTION
#define DEFINE_BIT_INSTRUCTION(insn_name) \
DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Operand src), (dest, src)) \
DEFINE_INT_INSTRUCTION(insn_name, (Register dest, Register src), (dest, src))
DEFINE_BIT_INSTRUCTION(Bsf)
DEFINE_BIT_INSTRUCTION(Bsr)
DEFINE_BIT_INSTRUCTION(Lzcnt)
DEFINE_BIT_INSTRUCTION(Tzcnt)
#undef DEFINE_BIT_INSTRUCTION
#undef DEFINE_INT_INSTRUCTION
// Note: Mov<int32_t> from one register to that same register doesn't zero-out top 32bits,
// like real Movq would! If you want that effect then use Expand<tnt32_t, int32_t> instead!
template <typename format>
std::enable_if_t<kIntType<format>> Mov(Register dest, Register src) {
if (dest == src) {
return;
}
if constexpr (kFormatIs<format, int8_t, uint8_t>) {
Assembler::Movb(dest, src);
} else if constexpr (kFormatIs<format, int16_t, uint16_t>) {
Assembler::Movw(dest, src);
} else if constexpr (kFormatIs<format, int32_t, uint32_t>) {
Assembler::Movl(dest, src);
} else {
Assembler::Movq(dest, src);
}
}
#define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename target_format> \
std::enable_if_t<kIntTypeBW<target_format>> insn_name parameters { \
if constexpr (kFormatIs<target_format, int8_t>) { \
Assembler::insn_name##sswb arguments; \
} else if constexpr (kFormatIs<target_format, uint8_t>) { \
Assembler::insn_name##uswb arguments; \
} else if constexpr (kFormatIs<target_format, int16_t>) { \
Assembler::insn_name##ssdw arguments; \
} else { \
Assembler::insn_name##usdw arguments; \
} \
}
#define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name) \
DEFINE_INT_INSTRUCTION(P##insn_name, (XMMRegister dest, XMMRegister src), (dest, src)) \
DEFINE_INT_INSTRUCTION(P##insn_name, (XMMRegister dest, Operand src), (dest, src)) \
DEFINE_INT_INSTRUCTION( \
Vp##insn_name, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2)) \
DEFINE_INT_INSTRUCTION( \
Vp##insn_name, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2))
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(ack)
#undef DEFINE_INT_INSTRUCTION
#define DEFINE_INT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename format> \
std::enable_if_t<kUnsignedIntType<format>> insn_name parameters { \
if constexpr (kFormatIs<format, uint8_t>) { \
Assembler::insn_name##bw arguments; \
} else if constexpr (kFormatIs<format, uint16_t>) { \
Assembler::insn_name##wd arguments; \
} else if constexpr (kFormatIs<format, uint32_t>) { \
Assembler::insn_name##dq arguments; \
} else { \
Assembler::insn_name##qdq arguments; \
} \
}
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(unpckh)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(unpckl)
#undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
#undef DEFINE_INT_INSTRUCTION
#define DEFINE_XMM_INT_INSTRUCTION( \
insn_name, asm_name, type_check, parameters, arguments, signed, unsigned) \
template <typename format> \
std::enable_if_t<type_check<format>> insn_name parameters { \
if constexpr (kFormatIs<format, int8_t>) { \
Assembler::asm_name##signed##b arguments; \
} else if constexpr (kFormatIs<format, uint8_t>) { \
Assembler::asm_name##unsigned##b arguments; \
} else if constexpr (kFormatIs<format, int16_t>) { \
Assembler::asm_name##signed##w arguments; \
} else if constexpr (kFormatIs<format, uint16_t>) { \
Assembler::asm_name##unsigned##w arguments; \
} else if constexpr (kFormatIs<format, int32_t>) { \
Assembler::asm_name##signed##d arguments; \
} else if constexpr (kFormatIs<format, uint32_t>) { \
Assembler::asm_name##unsigned##d arguments; \
} else if constexpr (kFormatIs<format, int64_t>) { \
Assembler::asm_name##signed##q arguments; \
} else { \
Assembler::asm_name##unsigned##q arguments; \
} \
}
#define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name, asm_name, type_check, signed, unsigned) \
DEFINE_XMM_INT_INSTRUCTION(P##insn_name, \
P##asm_name, \
type_check, \
(XMMRegister dest, Operand src), \
(dest, src), \
signed, \
unsigned) \
DEFINE_XMM_INT_INSTRUCTION(P##insn_name, \
P##asm_name, \
type_check, \
(XMMRegister dest, XMMRegister src), \
(dest, src), \
signed, \
unsigned) \
DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name, \
Vp##asm_name, \
type_check, \
(XMMRegister dest, XMMRegister src1, Operand src2), \
(dest, src1, src2), \
signed, \
unsigned) \
DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name, \
Vp##asm_name, \
type_check, \
(XMMRegister dest, XMMRegister src1, XMMRegister src2), \
(dest, src1, src2), \
signed, \
unsigned)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(add, add, kIntType, , )
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(adds, add, kIntTypeBW, s, us)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(cmpeq, cmpeq, kIntType, , )
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(cmpgt, cmpgt, kSignedIntType, , )
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(max, max, kIntTypeBWL, s, u)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(min, min, kIntTypeBWL, s, u)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(mull, mull, kIntTypeWL, , )
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sl, sl, kIntTypeWLQ, l, l)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sr, sr, kIntTypePsr, a, l)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(subs, sub, kIntTypeBW, s, us)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sub, sub, kIntType, , )
#undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
// Shifts have immediate form in addition to register-to-register form.
#define DEFINE_XMM_INT_INSTRUCTIONS_GROUP(insn_name, asm_name, type_check, signed, unsigned) \
DEFINE_XMM_INT_INSTRUCTION(P##insn_name, \
P##asm_name, \
type_check, \
(XMMRegister dest, int8_t imm), \
(dest, imm), \
signed, \
unsigned) \
DEFINE_XMM_INT_INSTRUCTION(Vp##insn_name, \
Vp##asm_name, \
type_check, \
(XMMRegister dest, XMMRegister src, int8_t imm), \
(dest, src, imm), \
signed, \
unsigned)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sl, sl, kIntTypeWLQ, l, l)
DEFINE_XMM_INT_INSTRUCTIONS_GROUP(sr, sr, kIntTypePsr, a, l)
#undef DEFINE_XMM_INT_INSTRUCTIONS_GROUP
#undef DEFINE_XMM_INT_INSTRUCTION
#define DEFINE_MOVS_INSTRUCTION(insn_name, opt_check, parameters, arguments) \
template <typename format> \
std::enable_if_t<kFloatType<format>> insn_name parameters { \
if constexpr (kFormatIs<format, Float32>) { \
opt_check; \
Assembler::insn_name##s arguments; \
} else { \
opt_check; \
Assembler::insn_name##d arguments; \
} \
}
DEFINE_MOVS_INSTRUCTION(Movs, , (XMMRegister dest, Operand src), (dest, src))
DEFINE_MOVS_INSTRUCTION(Movs, , (Operand dest, XMMRegister src), (dest, src))
DEFINE_MOVS_INSTRUCTION(Movs,
if (dest == src) return,
(XMMRegister dest, XMMRegister src),
(dest, src))
DEFINE_MOVS_INSTRUCTION(Vmovs, , (XMMRegister dest, Operand src), (dest, src))
DEFINE_MOVS_INSTRUCTION(Vmovs, , (Operand dest, XMMRegister src), (dest, src))
DEFINE_MOVS_INSTRUCTION(Vmovs,
if ((dest == src1) && (dest == src2)) return,
(XMMRegister dest, XMMRegister src1, XMMRegister src2),
(dest, src1, src2))
#undef DEFINE_MOVS_INSTRUCTION
#define DEFINE_XMM_MOV_INSTRUCTION(insn_name, parameters, arguments) \
template <typename format> \
std::enable_if_t<kFloatType<format>> insn_name parameters { \
if constexpr (kFormatIs<format, Float32>) { \
Assembler::insn_name##d arguments; \
} else { \
Assembler::insn_name##q arguments; \
} \
}
DEFINE_XMM_MOV_INSTRUCTION(Mov, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Mov, (Operand dest, XMMRegister src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Mov, (XMMRegister dest, Register src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Mov, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Vmov, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Vmov, (Operand dest, XMMRegister src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Vmov, (XMMRegister dest, Register src), (dest, src))
DEFINE_XMM_MOV_INSTRUCTION(Vmov, (Register dest, XMMRegister src), (dest, src))
#undef DEFINE_XMM_MOV_INSTRUCTION
#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename FormatFrom, typename FormatTo> \
std::enable_if_t<kFloatType<FormatFrom> && kSignedIntType<FormatTo> && kIntTypeLQ<FormatTo>> \
insn_name parameters { \
if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) { \
Assembler::insn_name##ss2sil arguments; \
} else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) { \
Assembler::insn_name##ss2siq(dest, src); \
} else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) { \
Assembler::insn_name##sd2sil(dest, src); \
} else { \
Assembler::insn_name##sd2siq(dest, src); \
} \
}
DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvt, (Register dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvtt, (Register dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (Register dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvtt, (Register dest, Operand src), (dest, src))
#undef DEFINE_XMM_CVT_INSTRUCTION
#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename FormatFrom, typename FormatTo> \
std::enable_if_t<kSignedIntType<FormatFrom> && kIntTypeWL<FormatFrom> && kFloatType<FormatTo>> \
insn_name parameters { \
if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int32_t>) { \
Assembler::insn_name##sil2ss arguments; \
} else if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, int64_t>) { \
Assembler::insn_name##siq2ss(dest, src); \
} else if constexpr (kFormatIs<FormatFrom, Float64> && kFormatIs<FormatTo, int32_t>) { \
Assembler::insn_name##sil2sd(dest, src); \
} else { \
Assembler::insn_name##siq2sd(dest, src); \
} \
}
DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Register src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvt, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Register src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, (XMMRegister dest, Operand src), (dest, src))
#undef DEFINE_XMM_CVT_INSTRUCTION
#define DEFINE_XMM_CVT_INSTRUCTION(insn_name, insn_suffix, parameters, arguments) \
template <typename FormatFrom, typename FormatTo> \
std::enable_if_t<kFloatType<FormatFrom> && kFloatType<FormatTo> && \
sizeof(FormatFrom) != sizeof(FormatTo)> \
insn_name##insn_suffix parameters { \
if constexpr (kFormatIs<FormatFrom, Float32> && kFormatIs<FormatTo, Float64>) { \
Assembler::insn_name##insn_suffix##s2##insn_suffix##d arguments; \
} else { \
Assembler::insn_name##insn_suffix##d2##insn_suffix##s arguments; \
} \
}
DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvt, p, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Cvt, s, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt, p, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
s,
(XMMRegister dest, XMMRegister src1, XMMRegister src2),
(dest, src1, src2))
DEFINE_XMM_CVT_INSTRUCTION(Vcvt,
s,
(XMMRegister dest, XMMRegister src1, Operand src2),
(dest, src1, src2))
#undef DEFINE_XMM_CVT_INSTRUCTION
#define DEFINE_XMM_FLOAT_INSTRUCTION(insn_name, parameters, arguments) \
template <typename format> \
std::enable_if_t<kFloatType<format>> insn_name parameters { \
if constexpr (kFormatIs<format, Float32>) { \
Assembler::insn_name##s arguments; \
} else { \
Assembler::insn_name##d arguments; \
} \
}
DEFINE_XMM_FLOAT_INSTRUCTION(Comis, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Comis, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Ucomis, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Ucomis, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Vcomis, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Vcomis, (XMMRegister dest, XMMRegister src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Vucomis, (XMMRegister dest, Operand src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Vucomis, (XMMRegister dest, XMMRegister src), (dest, src))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name, vinsn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##s, (XMMRegister dest, Operand src), (dest, src)) \
DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##s, (XMMRegister dest, XMMRegister src), (dest, src)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
vinsn_name##s, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
vinsn_name##s, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name, vinsn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##p, (XMMRegister dest, Operand src), (dest, src)) \
DEFINE_XMM_FLOAT_INSTRUCTION(insn_name##p, (XMMRegister dest, XMMRegister src), (dest, src)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
vinsn_name##p, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
vinsn_name##p, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(insn_name, vinsn_name) \
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name, vinsn_name) \
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name, vinsn_name)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Add, Vadd)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpeq, Vcmpeq)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmple, Vcmple)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmplt, Vcmplt)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpord, Vcmpord)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpneq, Vcmpneq)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpnle, Vcmpnle)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpnlt, Vcmpnlt)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Cmpunord, Vcmpunord)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Hadd, Vhadd)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Max, Vmax)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Min, Vmin)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Mul, Vmul)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Sub, Vsub)
// Note: logical operations 𝐫𝐞𝐚𝐥𝐥𝐲 don't have scalar versions!
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(And, Vand)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(Or, Vor)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(Xor, Vxor)
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##s, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##s, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##p, (XMMRegister dest, XMMRegister src1, Operand src2), (dest, src1, src2)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##p, (XMMRegister dest, XMMRegister src1, XMMRegister src2), (dest, src1, src2))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd231)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub231)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub231)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd231)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd231)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub132)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub213)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub231)
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##s, \
(XMMRegister dest, XMMRegister src1, XMMRegister src2, Operand src3), \
(dest, src1, src2, src3)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##s, \
(XMMRegister dest, XMMRegister src1, Operand src2, XMMRegister src3), \
(dest, src1, src2, src3)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##s, \
(XMMRegister dest, XMMRegister src1, XMMRegister src2, XMMRegister src3), \
(dest, src1, src2, src3))
#define DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED(insn_name) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##p, \
(XMMRegister dest, XMMRegister src1, XMMRegister src2, Operand src3), \
(dest, src1, src2, src3)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##p, \
(XMMRegister dest, XMMRegister src1, Operand src2, XMMRegister src3), \
(dest, src1, src2, src3)) \
DEFINE_XMM_FLOAT_INSTRUCTION( \
insn_name##p, \
(XMMRegister dest, XMMRegister src1, XMMRegister src2, XMMRegister src3), \
(dest, src1, src2, src3))
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmadd)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmaddsub)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsubadd)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfmsub)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmadd)
DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP(Vfnmsub)
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_PACKED
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP_SCALAR
#undef DEFINE_XMM_FLOAT_INSTRUCTIONS_GROUP
// Special, unique, instructions
// Movmskps/Movmskpd doesn't support memoru operand, Round[sp][sd] two arguments and immediate.
DEFINE_XMM_FLOAT_INSTRUCTION(Movmskp, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Vmovmskp, (Register dest, XMMRegister src), (dest, src))
DEFINE_XMM_FLOAT_INSTRUCTION(Roundp,
(XMMRegister dest, XMMRegister src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Rounds,
(XMMRegister dest, XMMRegister src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Roundp,
(XMMRegister dest, Operand src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Rounds,
(XMMRegister dest, Operand src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Vroundp,
(XMMRegister dest, XMMRegister src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Vrounds,
(XMMRegister dest, XMMRegister src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Vroundp,
(XMMRegister dest, Operand src, uint8_t imm8),
(dest, src, imm8))
DEFINE_XMM_FLOAT_INSTRUCTION(Vrounds,
(XMMRegister dest, Operand src, uint8_t imm8),
(dest, src, imm8))
#undef DEFINE_XMM_FLOAT_INSTRUCTION