/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2008-2017, Petr Kobalicek

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
#ifndef __PLUMED_asmjit_x86globals_h
#define __PLUMED_asmjit_x86globals_h
#ifdef __PLUMED_HAS_ASMJIT
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Guard]
#ifndef _ASMJIT_X86_X86GLOBALS_H
#define _ASMJIT_X86_X86GLOBALS_H

// [Dependencies]
#include "./globals.h"

// [Api-Begin]
#include "./asmjit_apibegin.h"

namespace PLMD {
namespace asmjit {

//! \addtogroup asmjit_x86
//! \{

// ============================================================================
// [asmjit::x86regs::]
// ============================================================================

//! X86 registers.
namespace x86regs {}

// ============================================================================
// [asmjit::x86defs::]
// ============================================================================

//! X86 definitions.
namespace x86defs {

// ============================================================================
// [asmjit::x86defs::SpecialRegs]
// ============================================================================

//! Flags describing special registers and/or their parts.
ASMJIT_ENUM(SpecialRegs) {
  kSpecialReg_FLAGS_CF    = 0x00000001U, //!< [R|E]FLAGS - Carry flag.
  kSpecialReg_FLAGS_PF    = 0x00000002U, //!< [R|E]FLAGS - Parity flag.
  kSpecialReg_FLAGS_AF    = 0x00000004U, //!< [R|E]FLAGS - Adjust flag.
  kSpecialReg_FLAGS_ZF    = 0x00000008U, //!< [R|E]FLAGS - Zero flag.
  kSpecialReg_FLAGS_SF    = 0x00000010U, //!< [R|E]FLAGS - Sign flag.
  kSpecialReg_FLAGS_TF    = 0x00000020U, //!< [R|E]FLAGS - Trap flag.
  kSpecialReg_FLAGS_IF    = 0x00000040U, //!< [R|E]FLAGS - Interrupt enable flag.
  kSpecialReg_FLAGS_DF    = 0x00000080U, //!< [R|E]FLAGS - Direction flag.
  kSpecialReg_FLAGS_OF    = 0x00000100U, //!< [R|E]FLAGS - Overflow flag.
  kSpecialReg_FLAGS_AC    = 0x00000200U, //!< [R|E]FLAGS - Alignment check.
  kSpecialReg_FLAGS_SYS   = 0x00000400U, //!< [R|E]FLAGS - System flags.

  kSpecialReg_X87CW_EXC   = 0x00000800U, //!< X87 Control Word - Exception control.
  kSpecialReg_X87CW_PC    = 0x00001000U, //!< X87 Control Word - Precision control.
  kSpecialReg_X87CW_RC    = 0x00002000U, //!< X87 Control Word - Rounding control.

  kSpecialReg_X87SW_EXC   = 0x00004000U, //!< X87 Status Word - Exception flags.
  kSpecialReg_X87SW_C0    = 0x00008000U, //!< X87 Status Word - C0 flag.
  kSpecialReg_X87SW_C1    = 0x00010000U, //!< X87 Status Word - C1 flag.
  kSpecialReg_X87SW_C2    = 0x00020000U, //!< X87 Status Word - C2 flag.
  kSpecialReg_X87SW_TOP   = 0x00040000U, //!< X87 Status Word - Top of the FPU stack.
  kSpecialReg_X87SW_C3    = 0x00080000U, //!< X87 Status Word - C3 flag.

  kSpecialReg_MSR         = 0x00100000U, //!< MSR register.
  kSpecialReg_XCR         = 0x00200000U  //!< XCR register.
};

// ============================================================================
// [asmjit::x86defs::X87SW]
// ============================================================================

//! FPU status word.
ASMJIT_ENUM(X87SW) {
  kX87SW_Invalid        = 0x0001U,
  kX87SW_Denormalized   = 0x0002U,
  kX87SW_DivByZero      = 0x0004U,
  kX87SW_Overflow       = 0x0008U,
  kX87SW_Underflow      = 0x0010U,
  kX87SW_Precision      = 0x0020U,
  kX87SW_StackFault     = 0x0040U,
  kX87SW_Interrupt      = 0x0080U,
  kX87SW_C0             = 0x0100U,
  kX87SW_C1             = 0x0200U,
  kX87SW_C2             = 0x0400U,
  kX87SW_Top            = 0x3800U,
  kX87SW_C3             = 0x4000U,
  kX87SW_Busy           = 0x8000U
};

// ============================================================================
// [asmjit::x86defs::X87CW]
// ============================================================================

//! FPU control word.
ASMJIT_ENUM(X87CW) {
  // Bits 0-5.
  kX87CW_EM_Mask        = 0x003FU,
  kX87CW_EM_Invalid     = 0x0001U,
  kX87CW_EM_Denormal    = 0x0002U,
  kX87CW_EM_DivByZero   = 0x0004U,
  kX87CW_EM_Overflow    = 0x0008U,
  kX87CW_EM_Underflow   = 0x0010U,
  kX87CW_EM_Inexact     = 0x0020U,

  // Bits 8-9.
  kX87CW_PC_Mask        = 0x0300U,
  kX87CW_PC_Float       = 0x0000U,
  kX87CW_PC_Reserved    = 0x0100U,
  kX87CW_PC_Double      = 0x0200U,
  kX87CW_PC_Extended    = 0x0300U,

  // Bits 10-11.
  kX87CW_RC_Mask        = 0x0C00U,
  kX87CW_RC_Nearest     = 0x0000U,
  kX87CW_RC_Down        = 0x0400U,
  kX87CW_RC_Up          = 0x0800U,
  kX87CW_RC_Truncate    = 0x0C00U,

  // Bit 12.
  kX87CW_IC_Mask        = 0x1000U,
  kX87CW_IC_Projective  = 0x0000U,
  kX87CW_IC_Affine      = 0x1000U
};

// ============================================================================
// [asmjit::x86defs::Cond]
// ============================================================================

//! Condition codes.
ASMJIT_ENUM(Cond) {
  kCondO                = 0x00U,         //!<                 OF==1
  kCondNO               = 0x01U,         //!<                 OF==0
  kCondB                = 0x02U,         //!< CF==1                  (unsigned < )
  kCondC                = 0x02U,         //!< CF==1
  kCondNAE              = 0x02U,         //!< CF==1                  (unsigned < )
  kCondAE               = 0x03U,         //!< CF==0                  (unsigned >=)
  kCondNB               = 0x03U,         //!< CF==0                  (unsigned >=)
  kCondNC               = 0x03U,         //!< CF==0
  kCondE                = 0x04U,         //!<         ZF==1          (any_sign ==)
  kCondZ                = 0x04U,         //!<         ZF==1          (any_sign ==)
  kCondNE               = 0x05U,         //!<         ZF==0          (any_sign !=)
  kCondNZ               = 0x05U,         //!<         ZF==0          (any_sign !=)
  kCondBE               = 0x06U,         //!< CF==1 | ZF==1          (unsigned <=)
  kCondNA               = 0x06U,         //!< CF==1 | ZF==1          (unsigned <=)
  kCondA                = 0x07U,         //!< CF==0 & ZF==0          (unsigned > )
  kCondNBE              = 0x07U,         //!< CF==0 & ZF==0          (unsigned > )
  kCondS                = 0x08U,         //!<                 SF==1  (is negative)
  kCondNS               = 0x09U,         //!<                 SF==0  (is positive or zero)
  kCondP                = 0x0AU,         //!< PF==1
  kCondPE               = 0x0AU,         //!< PF==1
  kCondPO               = 0x0BU,         //!< PF==0
  kCondNP               = 0x0BU,         //!< PF==0
  kCondL                = 0x0CU,         //!<                 SF!=OF (signed   < )
  kCondNGE              = 0x0CU,         //!<                 SF!=OF (signed   < )
  kCondGE               = 0x0DU,         //!<                 SF==OF (signed   >=)
  kCondNL               = 0x0DU,         //!<                 SF==OF (signed   >=)
  kCondLE               = 0x0EU,         //!<         ZF==1 | SF!=OF (signed   <=)
  kCondNG               = 0x0EU,         //!<         ZF==1 | SF!=OF (signed   <=)
  kCondG                = 0x0FU,         //!<         ZF==0 & SF==OF (signed   > )
  kCondNLE              = 0x0FU,         //!<         ZF==0 & SF==OF (signed   > )
  kCondCount            = 0x10U,

  // Simplified condition codes.
  kCondSign             = kCondS,        //!< Sign.
  kCondNotSign          = kCondNS,       //!< Not Sign.

  kCondOverflow         = kCondO,        //!< Signed overflow.
  kCondNotOverflow      = kCondNO,       //!< Not signed overflow.

  kCondEqual            = kCondE,        //!< Equal      `a == b`.
  kCondNotEqual         = kCondNE,       //!< Not Equal  `a != b`.

  kCondSignedLT         = kCondL,        //!< Signed     `a <  b`.
  kCondSignedLE         = kCondLE,       //!< Signed     `a <= b`.
  kCondSignedGT         = kCondG,        //!< Signed     `a >  b`.
  kCondSignedGE         = kCondGE,       //!< Signed     `a >= b`.

  kCondUnsignedLT       = kCondB,        //!< Unsigned   `a <  b`.
  kCondUnsignedLE       = kCondBE,       //!< Unsigned   `a <= b`.
  kCondUnsignedGT       = kCondA,        //!< Unsigned   `a >  b`.
  kCondUnsignedGE       = kCondAE,       //!< Unsigned   `a >= b`.

  kCondZero             = kCondZ,
  kCondNotZero          = kCondNZ,

  kCondNegative         = kCondS,
  kCondPositive         = kCondNS,

  kCondParityEven       = kCondP,
  kCondParityOdd        = kCondPO
};

// ============================================================================
// [asmjit::x86defs::CmpPredicate]
// ============================================================================

//! A predicate used by CMP[PD|PS|SD|SS] instructions.
ASMJIT_ENUM(CmpPredicate) {
  kCmpEQ                = 0x00U,         //!< Equal             (Quiet).
  kCmpLT                = 0x01U,         //!< Less              (Signaling).
  kCmpLE                = 0x02U,         //!< Less/Equal        (Signaling).
  kCmpUNORD             = 0x03U,         //!< Unordered         (Quiet).
  kCmpNEQ               = 0x04U,         //!< Not Equal         (Quiet).
  kCmpNLT               = 0x05U,         //!< Not Less          (Signaling).
  kCmpNLE               = 0x06U,         //!< Not Less/Equal    (Signaling).
  kCmpORD               = 0x07U          //!< Ordered           (Quiet).
};

// ============================================================================
// [asmjit::x86defs::VCmpPredicate]
// ============================================================================

//! A predicate used by VCMP[PD|PS|SD|SS] instructions.
//!
//! The first 8 values are compatible with \ref CmpPredicate.
ASMJIT_ENUM(VCmpPredicate) {
  kVCmpEQ_OQ            = 0x00U,         //!< Equal             (Quiet    , Ordered).
  kVCmpLT_OS            = 0x01U,         //!< Less              (Signaling, Ordered).
  kVCmpLE_OS            = 0x02U,         //!< Less/Equal        (Signaling, Ordered).
  kVCmpUNORD_Q          = 0x03U,         //!< Unordered         (Quiet).
  kVCmpNEQ_UQ           = 0x04U,         //!< Not Equal         (Quiet    , Unordered).
  kVCmpNLT_US           = 0x05U,         //!< Not Less          (Signaling, Unordered).
  kVCmpNLE_US           = 0x06U,         //!< Not Less/Equal    (Signaling, Unordered).
  kVCmpORD_Q            = 0x07U,         //!< Ordered           (Quiet).
  kVCmpEQ_UQ            = 0x08U,         //!< Equal             (Quiet    , Unordered).
  kVCmpNGE_US           = 0x09U,         //!< Not Greater/Equal (Signaling, Unordered).
  kVCmpNGT_US           = 0x0AU,         //!< Not Greater       (Signaling, Unordered).
  kVCmpFALSE_OQ         = 0x0BU,         //!< False             (Quiet    , Ordered).
  kVCmpNEQ_OQ           = 0x0CU,         //!< Not Equal         (Quiet    , Ordered).
  kVCmpGE_OS            = 0x0DU,         //!< Greater/Equal     (Signaling, Ordered).
  kVCmpGT_OS            = 0x0EU,         //!< Greater           (Signaling, Ordered).
  kVCmpTRUE_UQ          = 0x0FU,         //!< True              (Quiet    , Unordered).
  kVCmpEQ_OS            = 0x10U,         //!< Equal             (Signaling, Ordered).
  kVCmpLT_OQ            = 0x11U,         //!< Less              (Quiet    , Ordered).
  kVCmpLE_OQ            = 0x12U,         //!< Less/Equal        (Quiet    , Ordered).
  kVCmpUNORD_S          = 0x13U,         //!< Unordered         (Signaling).
  kVCmpNEQ_US           = 0x14U,         //!< Not Equal         (Signaling, Unordered).
  kVCmpNLT_UQ           = 0x15U,         //!< Not Less          (Quiet    , Unordered).
  kVCmpNLE_UQ           = 0x16U,         //!< Not Less/Equal    (Quiet    , Unordered).
  kVCmpORD_S            = 0x17U,         //!< Ordered           (Signaling).
  kVCmpEQ_US            = 0x18U,         //!< Equal             (Signaling, Unordered).
  kVCmpNGE_UQ           = 0x19U,         //!< Not Greater/Equal (Quiet    , Unordered).
  kVCmpNGT_UQ           = 0x1AU,         //!< Not Greater       (Quiet    , Unordered).
  kVCmpFALSE_OS         = 0x1BU,         //!< False             (Signaling, Ordered).
  kVCmpNEQ_OS           = 0x1CU,         //!< Not Equal         (Signaling, Ordered).
  kVCmpGE_OQ            = 0x1DU,         //!< Greater/Equal     (Quiet    , Ordered).
  kVCmpGT_OQ            = 0x1EU,         //!< Greater           (Quiet    , Ordered).
  kVCmpTRUE_US          = 0x1FU          //!< True              (Signaling, Unordered).
};

// ============================================================================
// [asmjit::x86defs::PCmpStrPredicate]
// ============================================================================

//! A predicate used by [V]PCMP[I|E]STR[I|M] instructions.
ASMJIT_ENUM(PCmpStrPredicate) {
  // Source data format:
  kPCmpStrUB            = 0x00U << 0,    //!< The source data format is unsigned bytes.
  kPCmpStrUW            = 0x01U << 0,    //!< The source data format is unsigned words.
  kPCmpStrSB            = 0x02U << 0,    //!< The source data format is signed bytes.
  kPCmpStrSW            = 0x03U << 0,    //!< The source data format is signed words.

  // Aggregation operation:
  kPCmpStrEqualAny      = 0x00U << 2,    //!< The arithmetic comparison is "equal".
  kPCmpStrRanges        = 0x01U << 2,    //!< The arithmetic comparison is “greater than or equal”
                                         //!< between even indexed elements and “less than or equal”
                                         //!< between odd indexed elements.
  kPCmpStrEqualEach     = 0x02U << 2,    //!< The arithmetic comparison is "equal".
  kPCmpStrEqualOrdered  = 0x03U << 2,    //!< The arithmetic comparison is "equal".

  // Polarity:
  kPCmpStrPosPolarity   = 0x00U << 4,    //!< IntRes2 = IntRes1.
  kPCmpStrNegPolarity   = 0x01U << 4,    //!< IntRes2 = -1 XOR IntRes1.
  kPCmpStrPosMasked     = 0x02U << 4,    //!< IntRes2 = IntRes1.
  kPCmpStrNegMasked     = 0x03U << 4,    //!< IntRes2[i] = second[i] == invalid ? IntRes1[i] : ~IntRes1[i].

  // Output selection (pcmpstri):
  kPCmpStrOutputLSI     = 0x00U << 6,    //!< The index returned to ECX is of the least significant set bit in IntRes2.
  kPCmpStrOutputMSI     = 0x01U << 6,    //!< The index returned to ECX is of the most significant set bit in IntRes2.

  // Output selection (pcmpstrm):
  kPCmpStrBitMask       = 0x00U << 6,    //!< IntRes2 is returned as the mask to the least significant bits of XMM0.
  kPCmpStrIndexMask     = 0x01U << 6     //!< IntRes2 is expanded into a byte/word mask and placed in XMM0.
};

// ============================================================================
// [asmjit::x86defs::VPCmpPredicate]
// ============================================================================

//! A predicate used by VPCMP[U][B|W|D|Q] instructions (AVX-512).
ASMJIT_ENUM(VPCmpPredicate) {
  kVPCmpEQ              = 0x00U,         //!< Equal.
  kVPCmpLT              = 0x01U,         //!< Less.
  kVPCmpLE              = 0x02U,         //!< Less/Equal.
  kVPCmpFALSE           = 0x03U,         //!< False.
  kVPCmpNE              = 0x04U,         //!< Not Equal.
  kVPCmpGE              = 0x05U,         //!< Greater/Equal.
  kVPCmpGT              = 0x06U,         //!< Greater.
  kVPCmpTRUE            = 0x07U          //!< True.
};

// ============================================================================
// [asmjit::x86defs::VPComPredicate]
// ============================================================================

//! A predicate used by VPCOM[U][B|W|D|Q] instructions (XOP).
ASMJIT_ENUM(VPComPredicate) {
  kVPComLT              = 0x00U,         //!< Less.
  kVPComLE              = 0x01U,         //!< Less/Equal
  kVPComGT              = 0x02U,         //!< Greater.
  kVPComGE              = 0x03U,         //!< Greater/Equal.
  kVPComEQ              = 0x04U,         //!< Equal.
  kVPComNE              = 0x05U,         //!< Not Equal.
  kVPComFALSE           = 0x06U,         //!< False.
  kVPComTRUE            = 0x07U          //!< True.
};

// ============================================================================
// [asmjit::x86defs::VFPClassPredicate]
// ============================================================================

//! A predicate used by VFPCLASS[PD|PS|SD|SS] instructions (AVX-512).
ASMJIT_ENUM(VFPClassPredicate) {
  kVFPClassQNaN         = 0x00U,
  kVFPClassPZero        = 0x01U,
  kVFPClassNZero        = 0x02U,
  kVFPClassPInf         = 0x03U,
  kVFPClassNInf         = 0x04U,
  kVFPClassDenormal     = 0x05U,
  kVFPClassNegative     = 0x06U,
  kVFPClassSNaN         = 0x07U
};

// ============================================================================
// [asmjit::x86defs::VFixupImmPredicate]
// ============================================================================

//! A predicate used by VFIXUPIMM[PD|PS|SD|SS] instructions (AVX-512).
ASMJIT_ENUM(VFixupImmPredicate) {
  kVFixupImmZEOnZero    = 0x01U,
  kVFixupImmIEOnZero    = 0x02U,
  kVFixupImmZEOnOne     = 0x04U,
  kVFixupImmIEOnOne     = 0x08U,
  kVFixupImmIEOnSNaN    = 0x10U,
  kVFixupImmIEOnNInf    = 0x20U,
  kVFixupImmIEOnNegative= 0x40U,
  kVFixupImmIEOnPInf    = 0x80U
};

// ============================================================================
// [asmjit::x86defs::VGetMantPredicate]
// ============================================================================

//! A predicate used by VGETMANT[PD|PS|SD|SS] instructions (AVX-512).
ASMJIT_ENUM(VGetMantPredicate) {
  kVGetMant1To2         = 0x00U,
  kVGetMant1Div2To2     = 0x01U,
  kVGetMant1Div2To1     = 0x02U,
  kVGetMant3Div4To3Div2 = 0x03U,
  kVGetMantNoSign       = 0x04U,
  kVGetMantQNaNIfSign   = 0x08U
};

// ============================================================================
// [asmjit::x86defs::VRangePredicate]
// ============================================================================

//! A predicate used by VRANGE[PD|PS|SD|SS] instructions (AVX-512).
ASMJIT_ENUM(VRangePredicate) {
  kVRangeSelectMin      = 0x00U,         //!< Select minimum value.
  kVRangeSelectMax      = 0x01U,         //!< Select maximum value.
  kVRangeSelectAbsMin   = 0x02U,         //!< Select minimum absolute value.
  kVRangeSelectAbsMax   = 0x03U,         //!< Select maximum absolute value.
  kVRangeSignSrc1       = 0x00U,         //!< Select sign of SRC1.
  kVRangeSignSrc2       = 0x04U,         //!< Select sign of SRC2.
  kVRangeSign0          = 0x08U,         //!< Set sign to 0.
  kVRangeSign1          = 0x0CU          //!< Set sign to 1.
};

// ============================================================================
// [asmjit::x86defs::VReducePredicate]
// ============================================================================

//! A predicate used by VREDUCE[PD|PS|SD|SS] instructions (AVX-512).
ASMJIT_ENUM(VReducePredicate) {
  kVReduceRoundCurrent  = 0x00U,         //!< Round to the current mode set.
  kVReduceRoundEven     = 0x04U,         //!< Round to nearest even.
  kVReduceRoundDown     = 0x05U,         //!< Round down.
  kVReduceRoundUp       = 0x06U,         //!< Round up.
  kVReduceRoundTrunc    = 0x07U,         //!< Truncate.
  kVReduceSuppress      = 0x08U          //!< Suppress exceptions.
};

// ============================================================================
// [asmjit::x86defs::TLogPredicate]
// ============================================================================

//! A predicate that can be used to create an immediate for VTERNLOG[D|Q].
ASMJIT_ENUM(TLogPredicate) {
  kTLog0                = 0x00U,
  kTLog1                = 0xFFU,
  kTLogA                = 0xF0U,
  kTLogB                = 0xCCU,
  kTLogC                = 0xAAU,
  kTLogNotA             = kTLogA ^ 0xFFU,
  kTLogNotB             = kTLogB ^ 0xFFU,
  kTLogNotC             = kTLogC ^ 0xFFU,

  kTLogAB               = kTLogA & kTLogB,
  kTLogAC               = kTLogA & kTLogC,
  kTLogBC               = kTLogB & kTLogC,
  kTLogNotAB            = kTLogAB ^ 0xFFU,
  kTLogNotAC            = kTLogAC ^ 0xFFU,
  kTLogNotBC            = kTLogBC ^ 0xFFU,

  kTLogABC              = kTLogA & kTLogB & kTLogC,
  kTLogNotABC           = kTLogABC ^ 0xFFU
};

// ============================================================================
// [asmjit::x86defs::RoundPredicate]
// ============================================================================

//! A predicate used by ROUND[PD|PS|SD|SS] instructions.
ASMJIT_ENUM(RoundPredicate) {
  kRoundNearest         = 0x00U,         //!< Round to nearest (even).
  kRoundDown            = 0x01U,         //!< Round to down toward -INF (floor),
  kRoundUp              = 0x02U,         //!< Round to up toward +INF (ceil).
  kRoundTrunc           = 0x03U,         //!< Round toward zero (truncate).
  kRoundCurrent         = 0x04U,         //!< Round to the current rounding mode set (ignores other RC bits).
  kRoundInexact         = 0x08U          //!< Avoids inexact exception, if set.
};

} // x86defs namespace

// ============================================================================
// [asmjit::x86::]
// ============================================================================

//! X86 constants, registers, and utilities.
namespace x86 {

// Include all x86 specific namespaces here.
using namespace x86defs;
using namespace x86regs;

//! Pack a shuffle constant to be used by SSE/AVX/AVX-512 instructions (2 values).
//!
//! \param a Position of the first  component [0, 1].
//! \param b Position of the second component [0, 1].
//!
//! Shuffle constants can be used to encode an immediate for these instructions:
//!   - `shufpd`
static ASMJIT_INLINE int shufImm(uint32_t a, uint32_t b) noexcept {
  ASMJIT_ASSERT(a <= 1 && b <= 1);
  return static_cast<int>((a << 1) | b);
}

//! Pack a shuffle constant to be used by SSE/AVX/AVX-512 instructions (4 values).
//!
//! \param a Position of the first  component [0, 3].
//! \param b Position of the second component [0, 3].
//! \param c Position of the third  component [0, 3].
//! \param d Position of the fourth component [0, 3].
//!
//! Shuffle constants can be used to encode an immediate for these instructions:
//!   - `pshufw()`
//!   - `pshufd()`
//!   - `pshuflw()`
//!   - `pshufhw()`
//!   - `shufps()`
static ASMJIT_INLINE int shufImm(uint32_t a, uint32_t b, uint32_t c, uint32_t d) noexcept {
  ASMJIT_ASSERT(a <= 3 && b <= 3 && c <= 3 && d <= 3);
  return static_cast<int>((a << 6) | (b << 4) | (c << 2) | d);
}

//! Create an immediate that can be used by VTERNLOG[D|Q] instructions.
static ASMJIT_INLINE int tlogImm(
  uint32_t b000, uint32_t b001, uint32_t b010, uint32_t b011,
  uint32_t b100, uint32_t b101, uint32_t b110, uint32_t b111) noexcept {

  ASMJIT_ASSERT(b000 <= 1 && b001 <= 1 && b010 <= 1 && b011 <= 1 &&
                b100 <= 1 && b101 <= 1 && b110 <= 1 && b111 <= 1);
  return static_cast<int>((b000 << 0) | (b001 << 1) | (b010 << 2) | (b011 << 3) |
                          (b100 << 4) | (b101 << 5) | (b110 << 6) | (b111 << 7));
}

//! Create an immediate that can be used by VTERNLOG[D|Q] instructions.
static ASMJIT_INLINE int tlogVal(int x) noexcept { return x & 0xFF; }
//! Negate an immediate that can be used by VTERNLOG[D|Q] instructions.
static ASMJIT_INLINE int tlogNot(int x) noexcept { return x ^ 0xFF; }
//! Create an if/else logic that can be used by VTERNLOG[D|Q] instructions.
static ASMJIT_INLINE int tlogIf(int cond, int a, int b) noexcept { return (cond & a) | (tlogNot(cond) & b); }

} // x86 namespace

//! \}

} // asmjit namespace
} // namespace PLMD

// [Api-End]
#include "./asmjit_apiend.h"

// [Guard]
#endif // _ASMJIT_X86_X86GLOBALS_H
#pragma GCC diagnostic pop
#endif // __PLUMED_HAS_ASMJIT
#endif
