/* Copyright (c) 2008, 2015 ZAO "MCST". All rights reserved. */

#ifndef _E2KINTRIN_H
#define _E2KINTRIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* *****************************************************************************
 *
 * В этом файле описаны интринсики на основные операции системы команд процессоров
 * Эльбрус, которые могут понадобиться для оптимизации или низкоуровневого программирования.
 * Каждый интринсик описывает одну команду Эльбруса. Для параметров и результатов
 * используются целые типы данных: unsigned int для данных формата 32, unsigned long long
 * для данных формата 64 и вектор из 2-х unsigned long long для формата 128.
 * За деталями работы операций см. систему команд.
 *
 * Примеры использования:
 *
 * #include <e2kintrin.h>
 *
 * unsigned src1;
 * unsigned dst = __builtin_e2k_scls (src1, 5);
 *
 * __di src2;
 * __di dst = __builtin_e2k_paddb (0x0102030405060708LL, src2);
 *
 * __v2di qsrc1;
 * __v2di qdst = __builtin_e2k_qpaddb (qsrc1, (__v2di) {0x0102030405060708LL, 0x090a0b0c0d0e0f00LL});
 *
 * *****************************************************************************/

/* Internal data types for implementing the intrinsics */

typedef unsigned long long __di;

typedef char __v8qi __attribute__ ((__vector_size__ (8)));
typedef short __v4hi __attribute__ ((__vector_size__ (8)));
typedef int __v2si __attribute__ ((__vector_size__ (8)));
typedef long long __v1di __attribute__ ((__vector_size__ (8)));
typedef float __v2sf __attribute__ ((__vector_size__ (8)));

typedef char __v16qi __attribute__ ((__vector_size__ (16)));
typedef unsigned char __v16qu __attribute__ ((__vector_size__ (16)));
typedef short __v8hi __attribute__ ((__vector_size__ (16)));
typedef unsigned short __v8hu __attribute__ ((__vector_size__ (16)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
typedef unsigned int __v4su __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
typedef unsigned long long __v2du __attribute__ ((__vector_size__ (16)));
typedef float __v4sf __attribute__ ((__vector_size__ (16)));
typedef double __v2df __attribute__ ((__vector_size__ (16)));

typedef union {
    int i;
    float f;
} __attribute__ ((__may_alias__)) type_union_32;

typedef union {
    double d0;
    unsigned long long l0;
    struct {
        int i0, i1;
    } i;
    struct {
        float f0, f1;
    } f;
    char __v8qi __attribute__ ((__vector_size__ (8)));
    short __v4hi __attribute__ ((__vector_size__ (8)));
    int __v2si __attribute__ ((__vector_size__ (8)));
    long long __v1di __attribute__ ((__vector_size__ (8)));
    float __v2sf __attribute__ ((__vector_size__ (8)));
} __attribute__ ((__may_alias__)) type_union_64;

typedef union {
    struct {
        double d0, d1;
    } d;
    struct {
        unsigned long long l0, l1;
    } l;
    struct {
        int i0, i1, i2, i3;
    } i;
    struct {
        float f0, f1, f2, f3;
    } f;
    struct {
        short h0, h1, h2, h3, h4, h5, h6, h7;
    } h;
    struct {
        char c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15;
    } c;
    char __v16qi __attribute__ ((__vector_size__ (16)));
    short __v8hi __attribute__ ((__vector_size__ (16)));
    int __v4si __attribute__ ((__vector_size__ (16)));
    long long __v2di __attribute__ ((__vector_size__ (16)));
    float __v4sf __attribute__ ((__vector_size__ (16)));
    double __v2df __attribute__ ((__vector_size__ (16)));
} __attribute__ ((__may_alias__)) type_union_128;


#ifndef __E2K_INLINE
#if 0 /* ifdef __OPTIMIZE__ */
#define __E2K_INLINE extern __inline
#else
#define __E2K_INLINE static __inline
# endif  /* __OPTIMIZE__ */
# endif  /* __E2K_INLINE */

/* *****************************************************************************
 *      Реализация оставшихся неподдержанными через билтыны операций Эльбрус
 * *****************************************************************************/

#define TWO_OPERANDS_INSTRUCTIONS(instr)                     \
__E2K_INLINE __di __attribute__((__always_inline__))         \
__builtin_e2k_##instr (__di src1, __di src2)                 \
{                                                            \
    __di dst;                                                \
_Pragma ("asm_inline")                                       \
    asm (""#instr" %[src1_name], %[src2_name], %[dst_name]"  \
        : [dst_name] "=r" (dst)                              \
        : [src1_name] "rI" (src1), [src2_name] "ri" (src2)); \
    return dst;                                              \
}

#define TWO_OPERANDS_INSTRUCTIONS_QSQ(instr)                 \
__E2K_INLINE __v2di __attribute__((__always_inline__))       \
__builtin_e2k_##instr (__v2di src1, unsigned int src2)       \
{                                                            \
    __v2di dst;                                              \
_Pragma ("asm_inline")                                       \
    asm (""#instr" %[src1_name], %[src2_name], %[dst_name]"  \
        : [dst_name] "=r" (dst)                              \
        : [src1_name] "rI" (src1), [src2_name] "ri" (src2)); \
    return dst;                                              \
}

#define __GETPFPFR(cw) _Pragma ("asm_inline") __asm__ __volatile__ ("rrs %%pfpfr, %0" : "=r" (cw))
#define __SETPFPFR(cw) _Pragma ("asm_inline") __asm__ __volatile__ ("rws %0, %%pfpfr" : : "r" (cw))

/* *****************************************************************************
 *                         Сложение и вычитание по модулю
 * *****************************************************************************/

/* сложение 8-ми байт (8S/8U)
 * uint64 __builtin_e2k_paddb (uint64, uint64) */

/* сложение 4-х шортов (16S/16U)
 * uint64 __builtin_e2k_paddh (uint64, uint64) */

/* сложение 2-х интов (32S/32U)
 * uint64 __builtin_e2k_paddw (uint64, uint64) */

/* сложение 1-го лонга (64S/64U)
 * uint64 __builtin_e2k_paddd (uint64, uint64) */

/* вычитание 8-ми байт (8S/8U)
 * uint64 __builtin_e2k_psubb (uint64, uint64) */

/* вычитание 4-х шортов (16S/16U)
 * uint64 __builtin_e2k_psubh (uint64, uint64) */

/* вычитание 2-х интов (32S/32U)
 * uint64 __builtin_e2k_psubw (uint64, uint64) */

/* вычитание 1-го лонга (64S/64U)
 * uint64 __builtin_e2k_psubd (uint64, uint64) */

/* *****************************************************************************
 *                         Сложение и вычитание c насыщением
 * *****************************************************************************/

/* сложение 8-ми знаковых байт (8S)
 * uint64 __builtin_e2k_paddsb (uint64, uint64) */

/* сложение 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_paddsh (uint64, uint64) */

/* сложение 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_paddusb (uint64, uint64) */

/* сложение 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_paddush (uint64, uint64) */

/* вычитание 8-ми знаковых байт (8S)
 * uint64 __builtin_e2k_psubsb (uint64, uint64) */

/* вычитание 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_psubsh (uint64, uint64) */

/* вычитание 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_psubusb (uint64, uint64) */

/* вычитание 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_psubush (uint64, uint64) */

/* *****************************************************************************
 *                         Среднее арифметическое
 * *****************************************************************************/

/* среднее 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_pavgusb (uint64, uint64) */

/* среднее 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_pavgush (uint64, uint64) */

/* *****************************************************************************
 *                             Махимум и минимум
 * *****************************************************************************/

/* максимум 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_pmaxub (uint64, uint64) */

/* максимум 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_pmaxsh (uint64, uint64) */

/* минимум 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_pminub (uint64, uint64) */

/* минимум 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_pminsh (uint64, uint64) */

/* *****************************************************************************
 *                             Умножение шортов
 * *****************************************************************************/

/* умножение 4-х беззнаковых шортов (16U) и выдача старших 16 разрядов произведений
 * uint64 __builtin_e2k_pmulhuh (uint64, uint64) */

/* умножение 4-х знаковых шортов (16S) и выдача старших 16 разрядов произведений
 * uint64 __builtin_e2k_pmulhh (uint64, uint64) */

/* умножение 4-х шортов (16S/16U) и выдача младших 16 разрядов произведений
 * uint64 __builtin_e2k_pmullh (uint64, uint64) */

/* *****************************************************************************
 *                             Умножение интов
 * *****************************************************************************/

/* умножение беззнаковых интов (32U) и получение 64-х разрядного произведения
 * uint64 __builtin_e2k_umulx (uint32, uint32) */

/* умножение знаковых интов (32S) и получение 64-х разрядного произведения
 * uint64 __builtin_e2k_smulx (uint32, uint32) */

/* *****************************************************************************
 *                 Умножение шортов с горизонтальным сложением
 * *****************************************************************************/

/* умножение 4-х знаковых шортов (16S) и попарное сложение смежных интовых произведений
 * uint64 __builtin_e2k_pmaddh (uint64, uint64) */

/* *****************************************************************************
 *                Cложение абсолютных разностей беззнаковых байт
 * *****************************************************************************/

/* cложение абсолютных разностей 8-ми беззнаковых байт (8U)
 * uint64 __builtin_e2k_psadbw (uint64, uint64) */

/* *****************************************************************************
 *                                Cравнение
 * *****************************************************************************/

/* сравнение на "равно" 8-ми байт (8S/8U)
 * uint64 __builtin_e2k_pcmpeqb (uint64, uint64) */

/* сравнение на "равно" 4-х шортов (16S/16U)
 * uint64 __builtin_e2k_pcmpeqh (uint64, uint64) */

/* сравнение на "равно" 2-х интов (32S/32U)
 * uint64 __builtin_e2k_pcmpeqw (uint64, uint64) */

/* сравнение на "больше" 8-ми знаковых байт (8S)
 * uint64 __builtin_e2k_pcmpgtb (uint64, uint64) */

/* сравнение на "больше" 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_pcmpgth (uint64, uint64) */

/* сравнение на "больше" 2-х знаковых интов (32S)
 * uint64 __builtin_e2k_pcmpgtw (uint64, uint64) */

/* *****************************************************************************
 *                           Логические операции
 * *****************************************************************************/

/* поразрядное логическое AND 64-х разрядов (64S/64U)
 * uint64 __builtin_e2k_pandd (uint64, uint64) */

/* поразрядное логическое AND 64-х разрядов c инверсией второго операнда (64S/64U)
 * uint64 __builtin_e2k_pandnd (uint64, uint64) */

/* поразрядное логическое OR 64-х разрядов (64S/64U)
 * uint64 __builtin_e2k_pord (uint64, uint64) */

/* поразрядное логическое XOR 64-х разрядов (64S/64U)
 * uint64 __builtin_e2k_pxord (uint64, uint64) */

/* *****************************************************************************
 *                               Выделение маски
 * *****************************************************************************/

/* формирование 16-разрядной маски из знаков каждого байта (8S)
 * uint64 __builtin_e2k_pmovmskb (uint64, uint64) */

/* формирование 4-разрядной маски из знаков каждого инта (32S)
 * uint64 __builtin_e2k_pmovmskps (uint64, uint64) */

/* формирование 2-разрядной маски из знаков каждого лонга (64S)
 * uint64 __builtin_e2k_pmovmskpd (uint64, uint64) */

/* *****************************************************************************
 *                               Битовый сдвиг
 * *****************************************************************************/

/* сдвиг влево 4-х шортов (16S/16U)
 * uint64 __builtin_e2k_psllh (uint64, uint64) */

/* сдвиг влево 2-х интов (32S/32U)
 * uint64 __builtin_e2k_psllw (uint64, uint64) */

/* сдвиг влево лонга (64S/64U)
 * uint64 __builtin_e2k_pslld (uint64, uint64) */

/* логический сдвиг вправо 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_psrlh (uint64, uint64) */

/* логический сдвиг вправо 2-х беззнаковых интов (32U)
 * uint64 __builtin_e2k_psrlw (uint64, uint64) */

/* логический сдвиг вправо беззнакового лонга (64U)
 * uint64 __builtin_e2k_psrld (uint64, uint64) */

/* арифметический сдвиг вправо 4-х знаковых шортов (16S)
 * uint64 __builtin_e2k_psrah (uint64, uint64) */

/* арифметический сдвиг вправо 2-х знаковых интов (32S)
 * uint64 __builtin_e2k_psraw (uint64, uint64) */

/* *****************************************************************************
 *                              Байтовый сдвиг
 * *****************************************************************************/

/* сдвиг влево 16-ти байт (сцепленные первые 2 операнда) на число байт,
 * равное константе в 3-м операнде, и выдача старших 8 байт
 * uint64 __builtin_e2k_psllqh (uint64, uint64, imm8) */

/* сдвиг влево 16-ти байт (сцепленные первые 2 операнда) на число байт,
 * равное константе в 3-м операнде, и выдача младших 8 байт
 * uint64 __builtin_e2k_psllql (uint64, uint64, imm8) */

/* логический сдвиг вправо 16-ти байт (сцепленные первые 2 операнда) на число байт,
 * равное константе в 3-м операнде, и выдача старших 8 байт
 * uint64 __builtin_e2k_psrlqh (uint64, uint64, imm8) */

/* логический сдвиг вправо 16-ти байт (сцепленные первые 2 операнда) на число байт,
 * равное константе в 3-м операнде, и выдача младших 8 байт
 * uint64 __builtin_e2k_psrlql (uint64, uint64, imm8) */

/* *****************************************************************************
 *                          Вставка / выделение шорта
 * *****************************************************************************/

/* выделение беззнакового шорта из 8-ми шортов (сцепленные первые 2 операнда) с номером,
 * задаваемым константой в 3-м операнде (ноль соответствует младшему шорту)
 * uint64 __builtin_e2k_pextrh (uint64, uint64, imm8) */

/* вcтавка шорта из младшей части операнда 2 в операнд 1 на место с номером,
 * задаваемым константой в 3-м операнде (ноль соответствует младшему шорту)
 * uint64 __builtin_e2k_pinsh (uint64, uint64, imm8) */

/* *****************************************************************************
 *                                 Перестановка
 * *****************************************************************************/

/* выделение из 4-х входных интов двух, положение которых определяется 4-мя
 * младшими разрядами константы 3-го операнда
 * uint64 __builtin_e2k_pshufw (uint64, uint64, imm8) */

/* перестановка 4-х шортов в соответствии с порядком, определенным в 8-ми младших
 * разрядах константы 2-го операнда
 * uint64 __builtin_e2k_pshufh (uint64, imm8) */

/* *****************************************************************************
 *                                 Упаковка
 * *****************************************************************************/

/* упаковка 8-ми знаковых шортов (16S) в знаковые байты (8S) с насыщением
 * uint64 __builtin_e2k_packsshb (uint64, uint64) */

/* упаковка 8-ми знаковых шортов (16S) в беззнаковые байты (8U) с насыщением
 * uint64 __builtin_e2k_packushb (uint64, uint64) */

/* упаковка 4-х знаковых интов (32S) в знаковые шорты (16S) с насыщением
 * uint64 __builtin_e2k_packsswh (uint64, uint64) */

/* *****************************************************************************
 *                                Распаковка
 * *****************************************************************************/

/* чередование 4-х старших байт (8U) операнда 1 и 4-х старших байт (8U) операнда 2
 * uint64 __builtin_e2k_punpckhbh (uint64, uint64) */

/* чередование 4-х младших байт (8U) операнда 1 и 4-х младших байт (8U) операнда 2
 * uint64 __builtin_e2k_punpcklbh (uint64, uint64) */

/* чередование 2-х старших шортов (16U) операнда 1 и 2-х старших шортов (16U) операнда 2
 * uint64 __builtin_e2k_punpckhhw (uint64, uint64) */

/* чередование 2-х младших шортов (16U) операнда 1 и 2-х младших шортов (16U) операнда 2
 * uint64 __builtin_e2k_punpcklhw (uint64, uint64) */

/* чередование старшего инта (32U) операнда 1 и старшего инта (32U) операнда 2
 * uint64 __builtin_e2k_punpckhwd (uint64, uint64) */

/* чередование младшего инта (32U) операнда 1 и младшего инта (32U) операнда 2
 * uint64 __builtin_e2k_punpcklwd (uint64, uint64) */

/* *****************************************************************************
 *    Упакованные операции над числами c плавающей точкой одинарного формата
 * *****************************************************************************/

/* сложение 2-х флотов (32F)
 * uint64 __builtin_e2k_pfadds (uint64, uint64) */

/* вычитание 2-х флотов (32F)
 * uint64 __builtin_e2k_pfsubs (uint64, uint64) */

/* максимум 2-х флотов (32F)
 * uint64 __builtin_e2k_pfmaxs (uint64, uint64) */

/* минимум 2-х флотов (32F)
 * uint64 __builtin_e2k_pfmins (uint64, uint64) */

/* умножение 2-х флотов (32F)
 * uint64 __builtin_e2k_pfmuls (uint64, uint64) */

/* преобразование 2-х флотов (32F) в 2 инта (32S) в текущем режиме округления
 * uint64 __builtin_e2k_pfstois (uint64) */

/* преобразование 2-х флотов (32F) в 2 инта (32S) c обрубанием
 * uint64 __builtin_e2k_pfstoistr (uint64) */

/* преобразование 2-х интов (32S) в 2 флота (32F) в текущем режиме округления
 * uint64 __builtin_e2k_pistofs (uint64) */

/* сравнение 2-х флотов (32F) на равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpeqs (uint64, uint64) */

/* сравнение 2-х флотов (32F) на меньше с формированием битовой маски
 * uint64 __builtin_e2k_pfcmplts (uint64, uint64) */

/* сравнение 2-х флотов (32F) на меньше или равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmples (uint64, uint64) */

/* сравнение 2-х флотов (32F) на неупорядочено с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpuods (uint64, uint64) */

/* сравнение 2-х флотов (32F) на не равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpneqs (uint64, uint64) */

/* сравнение 2-х флотов (32F) на не меньше с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpnlts (uint64, uint64) */

/* сравнение 2-х флотов (32F) на не меньше или равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpnles (uint64, uint64) */

/* сравнение 2-х флотов (32F) на упорядочено с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpods (uint64, uint64) */

/* *****************************************************************************
 *      Операции преобразования из формата чисел с плавающей точкой в целые
 * *****************************************************************************/

/*  преобразование дабла (64F) в лонг (64S) в текущем режиме округления
 * uint64 __builtin_e2k_fdtoid (uint64) */

/*  преобразование флота (32F) в инт (32S) в текущем режиме округления
 * uint32 __builtin_e2k_fstois (uint32) */

/*  преобразование дабла (64F) в инт (32S) в текущем режиме округления
 * uint32 __builtin_e2k_fdtois (uint64) */

/* *****************************************************************************
 *          Операции над числами c плавающей точкой одинарного формата
 * *****************************************************************************/

/* "упорядоченное" сравнение флотов (32F) с результатом в виде флагов
 * uint32 __builtin_e2k_fcmpodsf (uint32, uint32) */

/* "неупорядоченное" сравнение флотов (32F) с результатом в виде флагов
 * uint32 __builtin_e2k_fcmpudsf (uint32, uint32) */

/* *****************************************************************************
 *          Операции над числами c плавающей точкой двойного формата
 * *****************************************************************************/

/* максимум даблов (64F)
 * uint64 __builtin_e2k_pfmaxd (uint64, uint64) */

/* минимум даблов (64F)
 * uint64 __builtin_e2k_pfmind (uint64, uint64) */

/*  преобразование лонгa (64S) в дабл (64F) в текущем режиме округления
 * uint64 __builtin_e2k_idtofd (uint64) */

/* сравнение даблов (64F) на равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpeqd (uint64, uint64) */

/* сравнение даблов (64F) на меньше с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpltd (uint64, uint64) */

/* сравнение даблов (64F) на меньше или равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpled (uint64, uint64) */

/* сравнение даблов (64F) на неупорядочено с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpuodd (uint64, uint64) */

/* сравнение даблов (64F) на не равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpneqd (uint64, uint64) */

/* сравнение даблов (64F) на не меньше с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpnltd (uint64, uint64) */

/* сравнение даблов (64F) на не меньше или равно с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpnled (uint64, uint64) */

/* сравнение даблов (64F) на упорядочено с формированием битовой маски
 * uint64 __builtin_e2k_pfcmpodd (uint64, uint64) */

/* "упорядоченное" сравнение даблов (64F) с результатом в виде флагов
 * uint32 __builtin_e2k_fcmpoddf (uint64, uint64) */

/* "неупорядоченное" сравнение даблов (64F) с результатом в виде флагов
 * uint32 __builtin_e2k_fcmpuddf (uint64, uint64) */

/* *****************************************************************************
 *                         Циклический битовый сдвиг
 * *****************************************************************************/

/* циклический сдвиг влево инта (32S/32U)
 * uint32 __builtin_e2k_scls (uint32, uint32) */

/* циклический сдвиг влево лонга (64S/64U)
 * uint64 __builtin_e2k_scld (uint64, uint64) */

/* циклический сдвиг вправо инта (32S/32U)
 * uint64 __builtin_e2k_scrs (uint32, uint32) */

/* циклический сдвиг вправо лонга (64S/64U)
 * uint64 __builtin_e2k_scrd (uint64, uint64) */

/* *****************************************************************************
 *         Сложение/вычитание с результатом в виде интелловских флагов
 * *****************************************************************************/

/* сложение интов (32S/32U)
 * uint32 __builtin_e2k_adds_fw (uint32, uint32) */

/* вычитание интов (32S/32U)
 * uint32 __builtin_e2k_subs_fw (uint32, uint32) */

/* *****************************************************************************
 *                              Вставление поля
 * *****************************************************************************/

/* вставление поля в инт (32S/32U)
 * uint32 __builtin_e2k_insfs (uint32, uint32, uint32) */

/* вставление поля в лонг (64S/64U)
 * uint64 __builtin_e2k_insfd (uint64, uint64, uint64) */

/* *****************************************************************************
 *                              Выделение поля
 * *****************************************************************************/

/* выделение поля из инта (32S/32U)
 * uint32 __builtin_e2k_getfs (uint32, uint32) */

/* выделение поля из лонга (64S/64U)
 * uint64 __builtin_e2k_getfd (uint64, uint64) */

/* *****************************************************************************
 *                        Вставить поле внешнего тэга
 * *****************************************************************************/

/* Осторожно: если компилятор вставит дополнительную безусловную пересылку
 * аргумента этой операции, то на ней может произойти падение еще до
 * выполнения операции */

/* вставление тэга в лонг (64S/64U) */
TWO_OPERANDS_INSTRUCTIONS (puttagd)

/* *****************************************************************************
 *                         Операции чтения/записи
 * *****************************************************************************/

/* чтение инта (32S/32U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_ld_32u_be(pval) __builtin_loadmas_32u (pval, 8, __LCC_CHAN_ANY)

/* чтение инта (32S/32U) без заведения в L1 кэше */
#define __builtin_e2k_ld_32u_t1(pval) __builtin_loadmas_32u (pval, 0x20, __LCC_CHAN_ANY)

/* чтение инта (32S/32U) без заведения в L1 и L2 кэше */
#define __builtin_e2k_ld_32u_t2(pval) __builtin_loadmas_32u (pval, 0x40, __LCC_CHAN_ANY)

/* чтение инта (32S/32U) без заведения во всех кэшах */
#define __builtin_e2k_ld_32u_nta(pval) __builtin_loadmas_32u (pval, 0x60, __LCC_CHAN_ANY)

/* чтение лонга (64S/64U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_ld_64s_be(pval) ((__di) __builtin_loadmas_64u (pval, 8, __LCC_CHAN_ANY))

/* чтение лонга (64S/64U) без заведения в L1 кэше */
#define __builtin_e2k_ld_64s_t1(pval) ((__di) __builtin_loadmas_64u (pval, 0x20, __LCC_CHAN_ANY))

/* чтение лонга (64S/64U) без заведения в L1 и L2 кэше */
#define __builtin_e2k_ld_64s_t2(pval) ((__di) __builtin_loadmas_64u (pval, 0x40, __LCC_CHAN_ANY))

/* чтение лонга (64S/64U) без заведения во всех кэшах */
#define __builtin_e2k_ld_64s_nta(pval) ((__di) __builtin_loadmas_64u (pval, 0x60, __LCC_CHAN_ANY))

/* чтение лонга (64S/64U) в спекулятивном режиме */
#define __builtin_e2k_ld_64s_sm(pval, ind) ((__di) __builtin_loadmas_64u ((char *) (pval) + (ind), __LCC_MAS_SPEC, __LCC_CHAN_ANY))

/* чтение лонга (64S/64U) в спекулятивном режиме c обнулением тега */
#define __builtin_e2k_ld_64s_cleartag(pval, ind) __builtin_loadmas_64u ((char *) (pval) + (ind), __LCC_MAS_SPEC | __LCC_MAS_CLEARTAG, __LCC_CHAN_ANY)

/* запись инта (32S/32U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_st_32u_be(val, pval) __builtin_storemas_32u (val, pval, 8, __LCC_CHAN_ANY)

/* запись инта (32S/32U) мимо кэшей, напрямую в память (non temporal) */
#define __builtin_e2k_st_32u_nt(val, pval) __builtin_storemas_32u (val, pval, 0x60, __LCC_CHAN_ANY)

/* запись лонга (64S/64U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_st_64s_be(val, pval) __builtin_storemas_64u (val, pval, 8, __LCC_CHAN_ANY)

/* запись лонга (64S/64U) мимо кэшей, напрямую в память (non temporal) */
#define __builtin_e2k_st_64s_nt(val, pval) __builtin_storemas_64u (val, pval, 0x60, __LCC_CHAN_ANY)

/* Очистка строки кэша и удаление ее из всех кэшей */
#define __builtin_e2k_clflush(p) __builtin_storemas_64u (0, (void *) (p), 0xf, 2)

/* константы для использования с prefetch */
enum __e2k_hint {
    E2K_HINT_T0 = 3,  /* обычное функционирование кэш-памятей всех уровней */
    E2K_HINT_T1 = 2,  /* запрещение заведения строки в DCACHE1 */
    E2K_HINT_T2 = 1,  /* запрещение заведения строки в DCACHE1, DCACHE2 */
    E2K_HINT_NTA = 0  /* запрещение заведения строки в DCACHE1, DCACHE2, ECACHE */
};

/* подкачка строки в кэш соответствующего уровня */
#define __builtin_e2k_prefetch(P, I) \
    __builtin_prefetch (/* void * */(P), 0, /* __e2k_hint */(I))


#if __iset__ >= 2 /* __elbrus_2cplus__ */

/* *****************************************************************************
 *                         Новые операции в Эльбрус-2C+
 * *****************************************************************************
 *                   Перестановка разрядов в обратном порядке
 * *****************************************************************************/

/* перестановка разрядов в обратном порядке в инте (32S/32U)
 * uint32 __builtin_e2k_bitrevs (uint32) */

/* перестановка разрядов в обратном порядке в лонге (64S/64U)
 * uint64 __builtin_e2k_bitrevd (uint64) */

/* *****************************************************************************
 *                      Подсчет количества лидирующих нулей
 * *****************************************************************************/

/* подсчет количества лидирующих нулей в инте (32S/32U)
 * uint32 __builtin_e2k_lzcnts (uint32) */

/* подсчет количества лидирующих нулей в лонге (64S/64U)
 * uint64 __builtin_e2k_lzcntd (uint64) */

/* *****************************************************************************
 *                         Подсчет количества единиц
 * *****************************************************************************/

/* подсчет количества единиц в инте (32S/32U)
 * uint32 __builtin_e2k_popcnts (uint32) */

/* подсчет количества единиц в лонге (64S/64U)
 * uint64 __builtin_e2k_popcntd (uint64) */

/* *****************************************************************************
 *                          Умножение байт на шорты
 * *****************************************************************************/

/* умножение 4-х беззнаковых байт (8U) на 4-ре знаковых шорта (16S) со сдвигом
 * результата вправо на 8 и округлением к ближайшему
 * uint64 __builtin_e2k_pmulubhh (uint64, uint64) */

/* *****************************************************************************
 *                             Перестановка байт
 * *****************************************************************************/

/* выделение из 16-ти входных байт восьми, положение которых определяется значениями
 * в соответствующих байтах 3-го операнда. Либо заполнение предопределенными константами.
 * Для p1/p2/p9 и далее - дополнительно работает инверсия, реверсивная перестановка бит
 * или заполнение знаком
 * uint64 __builtin_e2k_pshufb (uint64, uint64, uint64) */

/* *****************************************************************************
 *                                Выбор байт
 * *****************************************************************************/

/* выбор 8-ми байт либо из операнда 1, либо из операнда 2 в зависимости от значения масок,
 * содержащихся в операнде 3
 * uint64 __builtin_e2k_pmerge (uint64, uint64, uint64) */

/* *****************************************************************************
 *          Операции над числами c плавающей точкой двойного формата
 * *****************************************************************************/

/*  преобразование дабла (64F) в лонг (64S) с обрубанием
 * uint64 __builtin_e2k_fdtoidtr (uint64) */

#endif /* __iset__ >= 2 */


#if __iset__ >= 3 /* __elbrus_4c__ */

/* *****************************************************************************
 *                         Новые операции в Эльбрус-4C
 * *****************************************************************************
 *                  Горизонтальное сложение и вычитание по модулю
 * *****************************************************************************/

/* Аргументы выкладываются в обратном порядке перед операцией : src2, src1 */

/* четыре горизонтальных сложения соседних шортов (16S/16U)
 * uint64 __builtin_e2k_phaddh (uint64, uint64) */

/* два горизонтальных сложения соседних интов (32S/32U)
 * uint64 __builtin_e2k_phaddw (uint64, uint64) */

/* четыре горизонтальных вычитания соседних шортов (16S/16U)
 * uint64 __builtin_e2k_phsubh (uint64, uint64) */

/* два горизонтальных вычитания соседних интов (32S/32U)
 * uint64 __builtin_e2k_phsubw (uint64, uint64) */

/* *****************************************************************************
 *                Горизонтальное сложение и вычитание c насыщением
 * *****************************************************************************/

/* четыре горизонтальных сложения соседних знаковых шортов (16S)
 * uint64 __builtin_e2k_phaddsh (uint64, uint64) */

/* четыре горизонтальных вычитания соседних знаковых шортов (16S)
 * uint64 __builtin_e2k_phsubsh (uint64, uint64) */

/* *****************************************************************************
 *                             Махимум и минимум
 * *****************************************************************************/

/* максимум 8-ми знаковых байт (8S)
 * uint64 __builtin_e2k_pmaxsb (uint64, uint64) */

/* максимум 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_pmaxuh (uint64, uint64) */

/* максимум 2-х беззнаковых интов (32U)
 * uint64 __builtin_e2k_pmaxuw (uint64, uint64) */

/* максимум 2-х знаковых интов (32S)
 * uint64 __builtin_e2k_pmaxsw (uint64, uint64) */

/* минимум 8-ми знаковых байт (8S)
 * uint64 __builtin_e2k_pminsb (uint64, uint64) */

/* минимум 4-х беззнаковых шортов (16U)
 * uint64 __builtin_e2k_pminuh (uint64, uint64) */

/* минимум 2-х беззнаковых интов (32U)
 * uint64 __builtin_e2k_pminuw (uint64, uint64) */

/* минимум 2-х знаковых интов (32S)
 * uint64 __builtin_e2k_pminsw (uint64, uint64) */

/* *****************************************************************************
 *                             Минимум и его позиция
 * *****************************************************************************/

/* поиск минимального из 8-ми беззнаковых шортов (16U) и его позиции
 * uint64 __builtin_e2k_phminposuh (uint64, uint64) */

/* *****************************************************************************
 *                 Умножение байт с горизонтальным сложением
 * *****************************************************************************/

/* умножение 8-ми знаковых байт (8S) на 8 беззнаковых байт (8U) и попарное сложение
 * смежных шортовых произведений с сатурацией
 * uint64 __builtin_e2k_pmaddubsh (uint64, uint64) */

/* *****************************************************************************
 *                    Умножение шортов с масштабированием
 * *****************************************************************************/

/* умножение 4-х знаковых шортов (16S) c масштабированием (>> 15) и округлением
 * uint64 __builtin_e2k_pmulhrsh (uint64, uint64) */

/* *****************************************************************************
 *                             Умножение лонгов
 * *****************************************************************************/

/* умножение беззнаковых лонгов (64S) и выдача старших 64 разрядов произведения
 * uint64 __builtin_e2k_umulhd (uint64, uint64) */

/* умножение знаковых лонгов (64S) и выдача старших 64 разрядов произведения
 * uint64 __builtin_e2k_smulhd (uint64, uint64) */

/* *****************************************************************************
 *         Сложение/вычитание с результатом в виде интелловских флагов
 * *****************************************************************************/

/* сложение лонгов (64S/64U)
 * uint32 __builtin_e2k_addd_fd (uint64, uint64) */

/* вычитание лонгов (64S/64U)
 * uint32 __builtin_e2k_subd_fd (uint64, uint64) */

/* *****************************************************************************
 *         Множественное сложение абсолютных разностей беззнаковых байт
 * *****************************************************************************/

/* Четыре cложения абсолютных разностей 4-х беззнаковых байт (8U) со сдвигом операндов
 * первого аргумента и 4-х беззнаковых байт (8U) второго аргумента с формированием 4-х
 * беззнаковых шортов (16U)
 * uint64 __builtin_e2k_mpsadbh (uint64, uint64) */

/* *****************************************************************************
 *                             Cравнение лонгов
 * *****************************************************************************/

/* сравнение на "равно" лонгов (64S/64U)
 * uint64 __builtin_e2k_pcmpeqd (uint64, uint64) */

/* сравнение на "больше" знаковых лонгов (64S)
 * uint64 __builtin_e2k_pcmpgtd (uint64, uint64) */

/* *****************************************************************************
 *                               Упаковка интов
 * *****************************************************************************/

/* упаковка 4-х знаковых интов (32S) в беззнаковые шорты (16U) с насыщением
 * uint64 __builtin_e2k_packuswh (uint64, uint64) */

/* *****************************************************************************
 *                            Изменение знака
 * *****************************************************************************/

/* умножение 8-ми знаковых байт (8S) на знаки 8-ми байт (8S) второго аргумента
 * uint64 __builtin_e2k_psignb (uint64, uint64) */

/* умножение 4-х знаковых шортов (16S) на знаки 4-х шортов (16S) второго аргумента
 * uint64 __builtin_e2k_psignh (uint64, uint64) */

/* умножение 2-х знаковых интов (32S) на знаки 2-х интов (32S) второго аргумента
 * uint64 __builtin_e2k_psignw (uint64, uint64) */

/* *****************************************************************************
 *    Упакованные операции над числами c плавающей точкой одинарного формата
 * *****************************************************************************/

/* два горизонтальных сложения соседних флотов (32F)
 * uint64 __builtin_e2k_pfhadds (uint64, uint64) */

/* два горизонтальных вычитания соседних флотов (32F)
 * uint64 __builtin_e2k_pfhsubs (uint64, uint64) */

/* сложение старших и вычитание младших 2-х флотов (32F)
 * uint64 __builtin_e2k_pfaddsubs (uint64, uint64) */

/* *****************************************************************************
 *                 Операции преобразования c плавающей точкой
 * *****************************************************************************/

/* управление округлением - первый аргумент 3-х следующих операций */
#define _TOIF_RC_NEAREST        0x0
#define _TOIF_RC_DOWN           0x1
#define _TOIF_RC_UP             0x2
#define _TOIF_RC_ZERO           0x3
#define _TOIF_RC_CURRENT        0x4 /* режим округления из регистра pfpfr */
#define _TOIF_RC_IGNORE_INEXACT 0x8 /* исключение inexact не вырабатывается */

/* выделение целой части значения флота (32F) в заданном режиме округления
 * uint32 __builtin_e2k_fstoifs (uint32, uint32) */

/* выделение целой части значений 2-х флотов (32F) в заданном режиме округления
 * uint64 __builtin_e2k_pfstoifs (uint64, uint64) */

/*  выделение целой части значения дабла (64F) в заданном режиме округления
 * uint64 __builtin_e2k_fdtoifd (uint64, uint64) */

#endif /*  __iset__ >= 3 */

#if __iset__ >= 4 /* __elbrus_8c__ и __elbrus_1cplus__ */

/* *****************************************************************************
 *                      Новые операции в Эльбрус-1C+/8C
 * *****************************************************************************
 *              Умножение вещественного числа на целую степень двойки
 * *****************************************************************************/

/* умножение флота (32F) на целую степень двойки
 * uint32 __builtin_e2k_fscales (uint32, sint32) */

/* умножение дабла (64F) на целую степень двойки
 * uint64 __builtin_e2k_fscaled (uint64, sint32) */

/* умножение лонг дабла (80F) на целую степень двойки
long double __builtin_e2k_fxscalesx (long double src1, sint32 src2) */

/* расширены возможности операции pshufb - теперь она может дополнительно делать
 * инвертирование байта (4 бит), обратную перестановку бит (5 бит) и размножение
 * знака (6 бит) */

#endif /* __iset__ >= 4 */

#if __iset__ >= 5 /* __elbrus_8c2__ */

/* *****************************************************************************
 *                         Новые операции в Эльбрус-8C2
 * *****************************************************************************
 *                         Сложение и вычитание по модулю
 * *****************************************************************************/

/* сложение 16-ти байт (8S/8U)
 * v2uint64 __builtin_e2k_qpaddb (v2uint64, v2uint64) */

/* сложение 8-ми шортов (16S/16U)
 * v2uint64 __builtin_e2k_qpaddh (v2uint64, v2uint64) */

/* сложение 4-х интов (32S/32U)
 * v2uint64 __builtin_e2k_qpaddw (v2uint64, v2uint64) */

/* сложение 2-х лонгов (64S/64U)
 * v2uint64 __builtin_e2k_qpaddd (v2uint64, v2uint64) */

/* вычитание 16-ти байт (8S/8U)
 * v2uint64 __builtin_e2k_qpsubb (v2uint64, v2uint64) */

/* вычитание 8-ми шортов (16S/16U)
 * v2uint64 __builtin_e2k_qpsubh (v2uint64, v2uint64) */

/* вычитание 4-х интов (32S/32U)
 * v2uint64 __builtin_e2k_qpsubw (v2uint64, v2uint64) */

/* вычитание 2-х лонгов (64S/64U)
 * v2uint64 __builtin_e2k_qpsubd (v2uint64, v2uint64) */

/* *****************************************************************************
 *                  Горизонтальное сложение и вычитание по модулю
 * *****************************************************************************/

/* восемь горизонтальных сложений соседних шортов (16S/16U)
 * v2uint64 __builtin_e2k_qphaddh (v2uint64, v2uint64) */

/* четыре горизонтальных сложения соседних интов (32S/32U)
 * v2uint64 __builtin_e2k_qphaddw (v2uint64, v2uint64) */

/* восемь горизонтальных вычитаний соседних шортов (16S/16U)
 * v2uint64 __builtin_e2k_qphsubh (v2uint64, v2uint64) */

/* четыре горизонтальных вычитания соседних интов (32S/32U)
 * v2uint64 __builtin_e2k_qphsubw (v2uint64, v2uint64) */

/* *****************************************************************************
 *                         Сложение и вычитание c насыщением
 * *****************************************************************************/

/* сложение 16-ти знаковых байт (8S)
 * v2uint64 __builtin_e2k_qpaddsb (v2uint64, v2uint64) */

/* сложение 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpaddsh (v2uint64, v2uint64) */

/* сложение 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpaddusb (v2uint64, v2uint64) */

/* сложение 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpaddush (v2uint64, v2uint64) */

/* вычитание 16-ти знаковых байт (8S)
 * v2uint64 __builtin_e2k_qpsubsb (v2uint64, v2uint64) */

/* вычитание 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpsubsh (v2uint64, v2uint64) */

/* вычитание 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpsubusb (v2uint64, v2uint64) */

/* вычитание 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpsubush (v2uint64, v2uint64) */

/* *****************************************************************************
 *                Горизонтальное сложение и вычитание c насыщением
 * *****************************************************************************/

/* восемь горизонтальных сложений соседних знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qphaddsh (v2uint64, v2uint64) */

/* восемь горизонтальных вычитаний соседних знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qphsubsh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                             Махимум и минимум
 * *****************************************************************************/

/* максимум 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpmaxub (v2uint64, v2uint64) */

/* максимум 16-ти знаковых байт (8S)
 * v2uint64 __builtin_e2k_qpmaxsb (v2uint64, v2uint64) */

/* максимум 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpmaxuh (v2uint64, v2uint64) */

/* максимум 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpmaxsh (v2uint64, v2uint64) */

/* максимум 4-х беззнаковых интов (32U)
 * v2uint64 __builtin_e2k_qpmaxuw (v2uint64, v2uint64) */

/* максимум 4-х знаковых интов (32S)
 * v2uint64 __builtin_e2k_qpmaxsw (v2uint64, v2uint64) */

/* минимум 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpminub (v2uint64, v2uint64) */

/* минимум 16-ти знаковых байт (8S)
 * v2uint64 __builtin_e2k_qpminsb (v2uint64, v2uint64) */

/* минимум 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpminuh (v2uint64, v2uint64) */

/* минимум 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpminsh (v2uint64, v2uint64) */

/* минимум 4-х беззнаковых интов (32U)
 * v2uint64 __builtin_e2k_qpminuw (v2uint64, v2uint64) */

/* минимум 4-х знаковых интов (32S)
 * v2uint64 __builtin_e2k_qpminsw (v2uint64, v2uint64) */

/* *****************************************************************************
 *                             Минимум и его позиция
 * *****************************************************************************/

/* поиск минимального из 16-ти беззнаковых шортов (16U) и его позиции
 * uint64 __builtin_e2k_qphminposuh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                             Умножение шортов
 * *****************************************************************************/

/* умножение 8-ми беззнаковых шортов (16U) и выдача старших 16 разрядов произведений
 * v2uint64 __builtin_e2k_qpmulhuh (v2uint64, v2uint64) */

/* умножение 8-ми знаковых шортов (16S) и выдача старших 16 разрядов произведений
 * v2uint64 __builtin_e2k_qpmulhh (v2uint64, v2uint64) */

/* умножение 8-ми шортов (16S/16U) и выдача младших 16 разрядов произведений
 * v2uint64 __builtin_e2k_qpmullh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                             Умножение интов
 * *****************************************************************************/

/* умножение 2-х интов (32S/32U) и выдача младших 32 разрядов произведений
 * uint64 __builtin_e2k_pmullw (uint64, uint64) */

/* умножение 4-х интов (32S/32U) и выдача младших 32 разрядов произведений
 * v2uint64 __builtin_e2k_qpmullw (v2uint64, v2uint64) */

/* *****************************************************************************
 *                          Умножение байт на шорты
 * *****************************************************************************/

/* умножение 8-ми беззнаковых байт (8U) на 8-мь знаковых шортов (16S) со сдвигом
 * результата вправо на 8 и округлением к ближайшему
 * v2uint64 __builtin_e2k_qpmulubhh (uint64, v2uint64) */

/* *****************************************************************************
 *                    Умножение шортов с масштабированием
 * *****************************************************************************/

/* умножение 8-ми знаковых шортов (16S) c масштабированием (>> 15) и округлением
 * v2uint64 __builtin_e2k_qpmulhrsh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                 Умножение шортов с горизонтальным сложением
 * *****************************************************************************/

/* умножение 8-ми знаковых шортов (16S) и попарное сложение смежных интовых произведений
 * v2uint64 __builtin_e2k_qpmaddh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                 Умножение байт с горизонтальным сложением
 * *****************************************************************************/

/* умножение 16-ти знаковых байт (8S) на 16 беззнаковых байт (8U) и попарное сложение
 * смежных шортовых произведений с сатурацией
 * v2uint64 __builtin_e2k_qpmaddubsh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                            Изменение знака
 * *****************************************************************************/

/* умножение 16-ти знаковых байт (8S) на знаки 16-ти байт (8S) второго аргумента
 * v2uint64 __builtin_e2k_qpsignb (v2uint64, v2uint64) */

/* умножение 8-ми знаковых шортов (16S) на знаки 8-ми шортов (16S) второго аргумента
 * v2uint64 __builtin_e2k_qpsignh (v2uint64, v2uint64) */

/* умножение 4-х знаковых интов (32S) на знаки 4-х интов (32S) второго аргумента
 * v2uint64 __builtin_e2k_qpsignw (v2uint64, v2uint64) */

/* *****************************************************************************
 *                Cложение абсолютных разностей беззнаковых байт
 * *****************************************************************************/

/* cложение абсолютных разностей 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpsadbw (v2uint64, v2uint64) */

/* *****************************************************************************
 *         Множественное сложение абсолютных разностей беззнаковых байт
 * *****************************************************************************/

/* две операции mpsadbh над младшей и старшей половинами операнда 1 и общим
 * операндом 2
 * v2uint64 __builtin_e2k_qpmpsadbh (v2uint64, uint32) */

/* *****************************************************************************
 *                         Среднее арифметическое
 * *****************************************************************************/

/* среднее 16-ти беззнаковых байт (8U)
 * v2uint64 __builtin_e2k_qpavgusb (v2uint64, v2uint64) */

/* среднее 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpavgush (v2uint64, v2uint64) */

/* *****************************************************************************
 *                                Cравнение
 * *****************************************************************************/

/* сравнение на "равно" 16-ти байт (8S/8U)
 * v2uint64 __builtin_e2k_qpcmpeqb (v2uint64, v2uint64) */

/* сравнение на "равно" 8-ми шортов (16S/16U)
 * v2uint64 __builtin_e2k_qpcmpeqh (v2uint64, v2uint64) */

/* сравнение на "равно" 4-х интов (32S/32U)
 * v2uint64 __builtin_e2k_qpcmpeqw (v2uint64, v2uint64) */

/* сравнение на "равно" 2-х лонгов (64S/64U)
 * v2uint64 __builtin_e2k_qpcmpeqd (v2uint64, v2uint64) */

/* сравнение на "больше" 16-ти знаковых байт (8S)
 * v2uint64 __builtin_e2k_qpcmpgtb (v2uint64, v2uint64) */

/* сравнение на "больше" 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpcmpgth (v2uint64, v2uint64) */

/* сравнение на "больше" 4-х знаковых интов (32S)
 * v2uint64 __builtin_e2k_qpcmpgtw (v2uint64, v2uint64) */

/* сравнение на "больше" 2-х знаковых лонгов (64S)
 * v2uint64 __builtin_e2k_qpcmpgtd (v2uint64, v2uint64) */

/* *****************************************************************************
 *                             Перестановка байт
 * *****************************************************************************/

/* выделение из 32-х входных байт 16-ти, положение которых определяется значениями
 * в соответствующих байтах 3-го операнда. Выделение байт возможно только локально
 * внутри старшей и младшей половин аргументов и результата. Далее возможно
 * заполнение предопределенными константами, инверсия, реверсивная перестановка бит
 * или заполнение знаком. Поле [3:0] определяет номер байта, а поле [7:4] - тип
 * операции над выбранным байтом
 * v2uint64 __builtin_e2k_qpshufb (v2uint64, v2uint64, v2uint64) */

/* выделение из 32-х входных байт произвольных 16-ти, положение которых определяется
 * значениями в соответствующих байтах 3-го операнда и выполнение над ними логических
 * операций в зависимости от значений управляющих байт в src3. Поле [4:0] определяет
 * номер байта, а поле [7:5] - тип операции над выбранным байтом
 * v2uint64 __builtin_e2k_qppermb (v2uint64, v2uint64, v2uint64) */

/* *****************************************************************************
 *                                Выбор байт
 * *****************************************************************************/

/* выбор 16-ти байт либо из операнда 1, либо из операнда 2 в зависимости от значения
 * масок, содержащихся в операнде 3
 * v2uint64 __builtin_e2k_qpmerge (v2uint64, v2uint64, v2uint64) */

/* *****************************************************************************
 *                                Упаковка лонгов
 * *****************************************************************************/

/* упаковка 2-х лонгов (64S/64U) в квадро-регистр
 * v2uint64 __builtin_e2k_qppackdl (uint64, uint64) */

/* *****************************************************************************
 *                                Перестановки
 * *****************************************************************************/

/* меняет местами двойные слова (64S)
 * v2uint64 __builtin_e2k_qpswitchd (v2uint64) */

/* меняет местами значения внутри 2-х пар интов (32S)
 * v2uint64 __builtin_e2k_qpswitchw (v2uint64) */

/* *****************************************************************************
 *                             Формирование маски
 * *****************************************************************************/

/* формирование маски из знака байтов
 * uint32 __builtin_e2k_qpsgn2mskb (v2uint64) */

/* *****************************************************************************
 *                          Модификация разрядов знака
 * *****************************************************************************/

/* модификация разрядов знака упакованных байтов (8S) значениями битов 16-разрядной
 * инверсной маски
 * v2uint64 __builtin_e2k_qpmsk2sgnb (v2uint64, uint32) */

/* *****************************************************************************
 *                           Логические операции
 * *****************************************************************************/

/* поразрядное логическое AND 128-и разрядов (128U)
 * v2uint64 __builtin_e2k_qpand (v2uint64, v2uint64) */

/* поразрядное логическое AND 128-и разрядов c инверсией второго операнда (128U)
 * v2uint64 __builtin_e2k_qpandn (v2uint64, v2uint64) */

/* поразрядное логическое OR 128-и разрядов (128U)
 * v2uint64 __builtin_e2k_qpor (v2uint64, v2uint64) */

/* поразрядное логическое XOR 128-и разрядов (128U)
 * v2uint64 __builtin_e2k_qpxor (v2uint64, v2uint64) */

/* *****************************************************************************
 *                       Произвольные логическая операции
 * *****************************************************************************/

/* произвольная поразрядная логическая операция 64-х разрядов (64S/64U)
 * uint64 __builtin_e2k_plog (N, uint64, uint64, uint64) */

/* произвольная поразрядная логическая операция 128-и разрядов (128U)
 * v2uint64 __builtin_e2k_qplog (N, v2uint64, v2uint64, v2uint64) */

/* *****************************************************************************
 *                               Битовый сдвиг
 * *****************************************************************************/

/* сдвиг влево 8-ми шортов (16S/16U)
 * v2uint64 __builtin_e2k_qpsllh (v2uint64, uint64) */

/* сдвиг влево 4-х интов (32S/32U)
 * v2uint64 __builtin_e2k_qpsllw (v2uint64, uint64) */

/* сдвиг влево 2-х лонгов (64S/64U)
 * v2uint64 __builtin_e2k_qpslld (v2uint64, uint64) */

/* логический сдвиг вправо 8-ми беззнаковых шортов (16U)
 * v2uint64 __builtin_e2k_qpsrlh (v2uint64, uint64) */

/* логический сдвиг вправо 4-х беззнаковых интов (32U)
 * v2uint64 __builtin_e2k_qpsrlw (v2uint64, uint64) */

/* логический сдвиг вправо 2-х беззнаковых лонгов (64U)
 * v2uint64 __builtin_e2k_qpsrld (v2uint64, uint64) */

/* арифметический сдвиг вправо 8-ми знаковых шортов (16S)
 * v2uint64 __builtin_e2k_qpsrah (v2uint64, uint64) */

/* арифметический сдвиг вправо 4-х знаковых интов (32S)
 * v2uint64 __builtin_e2k_qpsraw (v2uint64, uint64) */

/* *****************************************************************************
 *                       Циклический битовый сдвиг вправо
 * *****************************************************************************/

/* циклический сдвиг вправо 2-х интов (32S/32U)
 * uint64 __builtin_e2k_psrcw (uint64, uint64) */

/* циклический сдвиг вправо лонга (64S/64U)
 * uint64 __builtin_e2k_psrcd (uint64, uint64) */

/* циклический сдвиг вправо 4-х интов (32S/32U)
 * v2uint64 __builtin_e2k_qpsrcw (v2uint64, uint64) */

/* циклический сдвиг вправо 2-х лонгов (64S/64U)
 * v2uint64 __builtin_e2k_qpsrcd (v2uint64, uint64) */

/* *****************************************************************************
 *                                 Упаковка
 * *****************************************************************************/

/* упаковка 16-ти знаковых шортов (16S) в знаковые байты (8S) с насыщением
 * v2uint64 __builtin_e2k_qpacksshb (v2uint64, v2uint64) */

/* упаковка 16-ти знаковых шортов (16S) в беззнаковые байты (8U) с насыщением
 * v2uint64 __builtin_e2k_qpackushb (v2uint64, v2uint64) */

/* упаковка 8-ми знаковых интов (32S) в знаковые шорты (16S) с насыщением
 * v2uint64 __builtin_e2k_qpacksswh (v2uint64, v2uint64) */

/* упаковка 8-ми знаковых интов (32S) в беззнаковые шорты (16U) с насыщением
 * v2uint64 __builtin_e2k_qpackuswh (v2uint64, v2uint64) */

/* *****************************************************************************
 *                                Распаковка
 * *****************************************************************************/

/* чередование 8-ми старших байт (8U) операнда 1 и 8-ми старших байт (8U) операнда 2
 * v2uint64 __builtin_e2k_qpunpckhbh (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpckhbh(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1b0b1a0a19091808LL, 0x1f0f1e0e1d0d1c0cLL})

/* чередование 8-ми младших байт (8U) операнда 1 и 8-ми младших байт (8U) операнда 2
 * v2uint64 __builtin_e2k_qpunpcklbh (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpcklbh(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1303120211011000LL, 0x1707160615051404LL})

/* чередование 4-х старших шортов (16U) операнда 1 и 4-х старших шортов (16U) операнда 2
 * v2uint64 __builtin_e2k_qpunpckhhw (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpckhhw(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1b1a0b0a19180908LL, 0x1f1e0f0e1d1c0d0cLL})

/* чередование 4-х младших шортов (16U) операнда 1 и 4-х младших шортов (16U) операнда 2
 * v2uint64 __builtin_e2k_qpunpcklhw (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpcklhw(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1312030211100100LL, 0x1716070615140504LL})

/* чередование 2-х старших интов (32U) операнда 1 и 2-х старших интов (32U) операнда 2
 * v2uint64 __builtin_e2k_qpunpckhwd (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpckhwd(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1b1a19180b0a0908LL, 0x1f1e1d1c0f0e0d0cLL})

/* чередование 2-х младших интов (32U) операнда 1 и 2-х младших интов (32U) операнда 2
 * v2uint64 __builtin_e2k_qpunpcklwd (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpcklwd(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x1312111003020100LL, 0x1716151407060504LL})

/* чередование старшего лонга (64U) операнда 1 и старшего лонга (64U) операнда 2
 * v2uint64 __builtin_e2k_qpunpckhdq (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpckhdq(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x0f0e0d0c0b0a0908LL, 0x1f1e1d1c1b1a1918LL})

/* чередование младшего лонга (64U) операнда 1 и младшего лонга (64U) операнда 2
 * v2uint64 __builtin_e2k_qpunpckldq (v2uint64, v2uint64) */

#define __builtin_e2k_qpunpckldq(src1, src2)                                                  \
    __builtin_e2k_qppermb (src1, src2, (__v2di) {0x0706050403020100LL, 0x1716151413121110LL})

/* *****************************************************************************
 *                Выделение поля c обнулением младших разрядов
 * *****************************************************************************/

/* выделение поля из инта (32S/32U) c обнулением младших разрядов
 * uint32 __builtin_e2k_getfzs (uint32, uint32) */

/* выделение поля из лонга (64S/64U) c обнулением младших разрядов
 * uint64 __builtin_e2k_getfzd (uint64, uint64) */

/* *****************************************************************************
 *                        Вставить поле внешнего тэга
 * *****************************************************************************/

/* Осторожно: если компилятор вставит дополнительную безусловную пересылку
 * аргумента этой операции, то на ней может произойти падение еще до
 * выполнения операции */

/* вставление тэга в 128-ми разрядное значение (128U) */
TWO_OPERANDS_INSTRUCTIONS_QSQ (puttagqp)

/* *****************************************************************************
 *             Сложение и вычитание c битом переноса (carry)
 * *****************************************************************************/

/* сложение лонгов (64S/64U) и бита переноса c выработкой числового результата
 * uint64 __builtin_e2k_addcd (uint64, uint64, uint32) */

/* вычитание лонгов (64S/64U) и бита переноса c выработкой числового результата
 * uint64 __builtin_e2k_subcd (uint64, uint64, uint32) */

/* сложение лонгов (64S/64U) и бита переноса c выработкой нового переноса
 * uint64 __builtin_e2k_addcd_c (uint64, uint64, uint32) */

/* вычитание лонгов (64S/64U) и бита переноса c выработкой нового переноса
 * uint64 __builtin_e2k_subcd_c (uint64, uint64, uint32) */

/* *****************************************************************************
 *    Упакованные операции над числами c плавающей точкой одинарного формата
 * *****************************************************************************/

/* сложение 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfadds (v2uint64, v2uint64) */

/* горизонтальное сложение 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfhadds (v2uint64, v2uint64) */

/* вычитание 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfsubs (v2uint64, v2uint64) */

/* горизонтальное вычитание 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfhsubs (v2uint64, v2uint64) */

/* сложение/вычитание 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfaddsubs (v2uint64, v2uint64) */

/* максимум 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfmaxs (v2uint64, v2uint64) */

/* минимум 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfmins (v2uint64, v2uint64) */

/* умножение 4-х флотов (32F)
 * v2uint64 __builtin_e2k_qpfmuls (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpeqs (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на меньше с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmplts (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на меньше или равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmples (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на не упорядочено с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpuods (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на не равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpneqs (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на не меньше с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpnlts (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на не меньше или равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpnles (v2uint64, v2uint64) */

/* сравнение 4-х флотов (32F) на упорядочено с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpods (v2uint64, v2uint64) */

/* преобразование 4-х флотов (32F) в 4 инта (32S) в текущем режиме округления
 * v2uint64 __builtin_e2k_qpfstois (v2uint64) */

/* преобразование 4-х флотов (32F) в 4 инта (32S) c обрубанием
 * v2uint64 __builtin_e2k_qpfstoistr (v2uint64) */

/* преобразование 4-х интов (32S) в 4 флота (32F) в текущем режиме округления
 * v2uint64 __builtin_e2k_qpistofs (v2uint64) */

/* преобразование 2-х лонгов (64S) в 2 флота (32F)
 * uint64 __builtin_e2k_qpidtofs (v2uint64) */

/* выделение целой части значений 4-х флотов (32F) в заданном режиме округления
 * v2uint64 __builtin_e2k_qpfstoifs (uint64, v2uint64) */

/* преобразование 2-х флотов (32F) в 2 дабла (64F)
 * v2uint64 __builtin_e2k_qpfstofd (uint64) */

/* преобразование 2-х флотов (32F) в 2 лонга (64S) в текущем режиме округления
 * v2uint64 __builtin_e2k_qpfstoid (uint64) */

/* преобразование 2-х флотов (32F) в 2 лонга (64S) c обрубанием
 * v2uint64 __builtin_e2k_qpfstoidtr (uint64) */

/* *****************************************************************************
 *     Упакованные операции над числами c плавающей точкой двойного формата
 * *****************************************************************************/

/* сложение 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfaddd (v2uint64, v2uint64) */

/* вычитание 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfsubd (v2uint64, v2uint64) */

/* сложение/вычитание 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfaddsubd (v2uint64, v2uint64) */

/* максимум 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfmaxd (v2uint64, v2uint64) */

/* минимум 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfmind (v2uint64, v2uint64) */

/* умножение 2-х даблов (64F)
 * v2uint64 __builtin_e2k_qpfmuld (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpeqd (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на меньше с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpltd (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на меньше или равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpled (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на не упорядочено с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpuodd (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на не равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpneqd (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на не меньше с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpnltd (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на не меньше или равно с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpnled (v2uint64, v2uint64) */

/* сравнение 2-х даблов (64F) на упорядочено с формированием битовой маски
 * v2uint64 __builtin_e2k_qpfcmpodd (v2uint64, v2uint64) */

/* преобразование 2-х даблов (64F) в 2 инта (32S) в текущем режиме округления
 * uint64 __builtin_e2k_qpfdtois (v2uint64) */

/* преобразование 2-х даблов (64F) в 2 инта (32S) c обрубанием
 * uint64 __builtin_e2k_qpfdtoistr (v2uint64) */

/* преобразование 2-х интов (32S) в 2 дабла (64F)
 * v2uint64 __builtin_e2k_qpistofd (uint64) */

/* преобразование 2-х лонгов (64S) в 2 дабла (64F)
 * v2uint64 __builtin_e2k_qpidtofd (v2uint64) */

/* выделение целой части значений 2-х даблов (64F) в заданном режиме округления
 * v2uint64 __builtin_e2k_qpfdtoifd (uint64, v2uint64) */

/* преобразование 2-х даблов (64F) в 2 флота (32F)
 * uint64 __builtin_e2k_qpfdtofs (v2uint64) */

/* преобразование 2-х даблов (64F) в 2 лонга (64S) в текущем режиме округления
 * v2uint64 __builtin_e2k_qpfdtoid (v2uint64) */

/* преобразование 2-х даблов (64F) в 2 лонга (64S) c обрубанием
 * v2uint64 __builtin_e2k_qpfdtoidtr (v2uint64) */

/* *****************************************************************************
 *                         Операции чтения/записи
 * *****************************************************************************/

/* чтение 16 байт (2*64U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_ld_128_be(pval) __builtin_loadmas_128v (pval, 8, __LCC_CHAN_ANY)

/* чтение 16 байт (2*64U) без заведения в L1 кэше */
#define __builtin_e2k_ld_128_t1(pval) __builtin_loadmas_128v (pval, 0x20, __LCC_CHAN_ANY)

/* чтение 16 байт (2*64U) без заведения в L1 и L2 кэше */
#define __builtin_e2k_ld_128_t2(pval) __builtin_loadmas_128v (pval, 0x40, __LCC_CHAN_ANY)

/* чтение 16 байт (2*64U) без заведения во всех кэшах */
#define __builtin_e2k_ld_128_nta(pval) __builtin_loadmas_128v (pval, 0x60, __LCC_CHAN_ANY)

/* чтение 16 байт (2*64U) в спекулятивном режиме */
#define __builtin_e2k_ld_128_sm(pval, ind) __builtin_loadmas_128v ((char *) (pval) + (ind), __LCC_MAS_SPEC, __LCC_CHAN_ANY)

/* чтение 16 байт (2*64U) в спекулятивном режиме c обнулением тега */
#define __builtin_e2k_ld_128_cleartag(pval, ind) __builtin_loadmas_128v ((char *) (pval) + (ind), __LCC_MAS_SPEC | __LCC_MAS_CLEARTAG, __LCC_CHAN_ANY)

/* запись 16 байт (2*64U) в big endian режиме (с разворотом байт) */
#define __builtin_e2k_st_128_be(val, pval) __builtin_storemas_128v (val, pval, 8, __LCC_CHAN_ANY)

/* запись 16 байт (2*64U) мимо кэшей, напрямую в память (non temporal) */
#define __builtin_e2k_st_128_nt(val, pval) __builtin_storemas_128v (val, pval, 0x60, __LCC_CHAN_ANY)

/* запись 16 байт (2*64U) по маске */
#define __builtin_e2k_pst_128(val, pval, mask) \
    __builtin_pstoremas_128v (val, pval, mask, __LCC_MAS_NO, __LCC_CHAN_ANY)

/* запись 16 байт (2*64U) по маске в big endian режиме (с разворотом байт) */
#define __builtin_e2k_pst_128_be(val, pval, mask) \
    __builtin_pstoremas_128v (val, pval, mask, 8, __LCC_CHAN_ANY)

#endif /* __iset__ >= 5 */

#if __iset__ >= 6 /* __elbrus_2c3__, __elbrus_12c__ и __elbrus_16c__ */

/* *****************************************************************************
 *                    Новые операции в Эльбрус-2C3/12C/16C
 * *****************************************************************************
 *   Умножение вещественных чисел со сложением без промежуточного округления
 * *****************************************************************************/

/* умножение cо сложением флотов (32F) : src1 * src2 + src3
 * uint32 __builtin_e2k_fmas (uint32, uint32, uint32) */

/* умножение c вычитанием флотов (32F) : src1 * src2 - src3
 * uint32 __builtin_e2k_fmss (uint32, uint32, uint32) */

/* обратное умножение cо сложением флотов (32F) : -(src1 * src2) + src3
 * uint32 __builtin_e2k_fnmas (uint32, uint32, uint32) */

/* обратное умножение c вычитанием флотов (32F) : -(src1 * src2) - src3
 * uint32 __builtin_e2k_fnmss (uint32, uint32, uint32) */

/* умножение cо сложением даблов (64F) : src1 * src2 + src3
 * uint64 __builtin_e2k_fmad (uint64, uint64, uint64) */

/* умножение c вычитанием даблов (64F) : src1 * src2 - src3
 * uint64 __builtin_e2k_fmsd (uint64, uint64, uint64) */

/* обратное умножение cо сложением даблов (64F) : -(src1 * src2) + src3
 * uint64 __builtin_e2k_fnmad (uint64, uint64, uint64) */

/* обратное умножение c вычитанием даблов (64F) : -(src1 * src2) - src3
 * uint64 __builtin_e2k_fnmsd (uint64, uint64, uint64) */

/* *****************************************************************************
 * Упакованное умножение вещественных чисел со сложением без промежуточного округления
 * *****************************************************************************/

/* умножение 4-х флотов (32F) cо сложением : src1 * src2 + src3
 * v2uint64 __builtin_e2k_qpfmas (v2uint64, v2uint64, v2uint64) */

/* умножение 4-х флотов (32F) c вычитанием : src1 * src2 - src3
 * v2uint64 __builtin_e2k_qpfmss (v2uint64, v2uint64, v2uint64) */

/* обратное умножение 4-х флотов (32F) cо сложением : -(src1 * src2) + src3
 * v2uint64 __builtin_e2k_qpfnmas (v2uint64, v2uint64, v2uint64) */

/* обратное умножение 4-х флотов (32F) c вычитанием : -(src1 * src2) - src3
 * v2uint64 __builtin_e2k_qpfnmss (v2uint64, v2uint64, v2uint64) */

/* умножение 4-х флотов (32F) cо сложением четных элементов : src1 * src2 + src3
 * и c вычитанием нечетных элементов : src1 * src2 - src3
 * v2uint64 __builtin_e2k_qpfmass (v2uint64, v2uint64, v2uint64) */

/* умножение 4-х флотов (32F) c вычитанием четных элементов : src1 * src2 - src3
 * и cо сложением нечетных элементов : src1 * src2 + src3
 * v2uint64 __builtin_e2k_qpfmsas (v2uint64, v2uint64, v2uint64) */

/* умножение 2-х даблов (64F) cо сложением : src1 * src2 + src3
 * v2uint64 __builtin_e2k_qpfmad (v2uint64, v2uint64, v2uint64) */

/* умножение 2-х даблов (64F) c вычитанием : src1 * src2 - src3
 * v2uint64 __builtin_e2k_qpfmsd (v2uint64, v2uint64, v2uint64) */

/* обратное умножение 2-х даблов (64F) cо сложением : -(src1 * src2) + src3
 * v2uint64 __builtin_e2k_qpfnmad (v2uint64, v2uint64, v2uint64) */

/* обратное умножение 2-х даблов (64F) c вычитанием : -(src1 * src2) - src3
 * v2uint64 __builtin_e2k_qpfnmsd (v2uint64, v2uint64, v2uint64) */

/* умножение 2-х даблов (64F) cо сложением четных элементов : src1 * src2 + src3
 * и c вычитанием нечетных элементов : src1 * src2 - src3
 * v2uint64 __builtin_e2k_qpfmasd (v2uint64, v2uint64, v2uint64) */

/* умножение 2-х даблов (64F) c вычитанием четных элементов : src1 * src2 - src3
 * и cо сложением нечетных элементов : src1 * src2 + src3
 * v2uint64 __builtin_e2k_qpfmsad (v2uint64, v2uint64, v2uint64) */

/* *****************************************************************************
 *                Cравнение c выработкой предиката для 64-х бит
 * *****************************************************************************/

/* сравнение на "равно" 8-ми байт (8S/8U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpeqbop (uint64, uint64) */

/* сравнение на "равно" 4-х шортов (16S/16U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpeqhop (uint64, uint64) */

/* сравнение на "равно" 2-х интов (32S/32U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpeqwop (uint64, uint64) */

/* сравнение на "равно" лонгов (64S/64U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpeqdop (uint64, uint64) */

/* сравнение на "больше" 8-ми знаковых байт (8S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpgtbop (uint64, uint64) */

/* сравнение на "больше" 4-х знаковых шортов (16S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpgthop (uint64, uint64) */

/* сравнение на "больше" 2-х знаковых интов (32S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpgtwop (uint64, uint64) */

/* сравнение на "больше" знаковых лонгов (64S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_pcmpgtdop (uint64, uint64) */

/* сравнение на "равно" 8-ми байт (8S/8U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpeqbap (uint64, uint64) */

/* сравнение на "равно" 4-х шортов (16S/16U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpeqhap (uint64, uint64) */

/* сравнение на "равно" 2-х интов (32S/32U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpeqwap (uint64, uint64) */

/* сравнение на "равно" лонгов (64S/64U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpeqdap (uint64, uint64) */

/* сравнение на "больше" 8-ми знаковых байт (8S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpgtbap (uint64, uint64) */

/* сравнение на "больше" 4-х знаковых шортов (16S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpgthap (uint64, uint64) */

/* сравнение на "больше" 2-х знаковых интов (32S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpgtwap (uint64, uint64) */

/* сравнение на "больше" знаковых лонгов (64S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_pcmpgtdap (uint64, uint64) */

/* *****************************************************************************
 *                Cравнение c выработкой предиката для 128-и бит
 * *****************************************************************************/

/* сравнение на "равно" 16-ти байт (8S/8U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqbop (v2uint64, v2uint64) */

/* сравнение на "равно" 8-ми шортов (16S/16U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqhop (v2uint64, v2uint64) */

/* сравнение на "равно" 4-х интов (32S/32U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqwop (v2uint64, v2uint64) */

/* сравнение на "равно" 2-х лонгов (64S/64U) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqdop (v2uint64, v2uint64) */

/* сравнение на "больше" 16-ти знаковых байт (8S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtbop (v2uint64, v2uint64) */

/* сравнение на "больше" 8-ми знаковых шортов (16S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpgthop (v2uint64, v2uint64) */

/* сравнение на "больше" 4-х знаковых интов (32S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtwop (v2uint64, v2uint64) */

/* сравнение на "больше" 2-х знаковых лонгов (64S) c последующим OR результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtdop (v2uint64, v2uint64) */

/* сравнение на "равно" 16-ти байт (8S/8U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqbap (v2uint64, v2uint64) */

/* сравнение на "равно" 8-ми шортов (16S/16U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqhap (v2uint64, v2uint64) */

/* сравнение на "равно" 4-х интов (32S/32U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqwap (v2uint64, v2uint64) */

/* сравнение на "равно" 2-х лонгов (64S/64U) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpeqdap (v2uint64, v2uint64) */

/* сравнение на "больше" 16-ти знаковых байт (8S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtbap (v2uint64, v2uint64) */

/* сравнение на "больше" 8-ми знаковых шортов (16S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpgthap (v2uint64, v2uint64) */

/* сравнение на "больше" 4-х знаковых интов (32S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtwap (v2uint64, v2uint64) */

/* сравнение на "больше" 2-х знаковых лонгов (64S) c последующим AND результатов сравнений
 * uint32 __builtin_e2k_qpcmpgtdap (v2uint64, v2uint64) */

/* *****************************************************************************
 *                      Беспереносное умножение целых
 * *****************************************************************************/

/* беспереносное умножение беззнаковых лонгов (64U) с выдачей младших 64-х бит результата
 * uint64 __builtin_e2k_clmull (uint64, uint64) */

/* беспереносное умножение беззнаковых лонгов (64U) с выдачей старших 64-х бит результата
 * uint64 __builtin_e2k_clmulh (uint64, uint64) */

/* *****************************************************************************
 *                               Битовый сдвиг
 * *****************************************************************************/

/* арифметический сдвиг вправо 2-х знаковых лонгов (64S)
 * v2uint64 __builtin_e2k_qpsrad (v2uint64, uint64) */

#endif /* __iset__ >= 6 */

#undef TWO_OPERANDS_INSTRUCTIONS
#undef TWO_OPERANDS_INSTRUCTIONS_QSQ

/* *****************************************************************************
 *                                   Макросы
 * *****************************************************************************/

/* *****************************************************************************
 *                       Выравнивание данных в Эльбрус
 *
 *    Используется, например, для выравнивания данных, считанных операциями
 *    mova(d,w), работающими только с выровненными адресами. Или, например, для
 *    сдвига на заранее неизвестное число байт
 *
 *    Примеры использования можно найти в <e2kbuiltin.h>
 * *****************************************************************************/

#define E2K_BYTES_TO_ALIGN(ptr, align) ((-(long)(ptr))&((align)-1))
#define E2K_BYTES_FROM_ALIGN(ptr, align) (((long)(ptr))&((align)-1))

#ifdef __ptr128__
#define E2K_ALIGN_PTR(ptr, align) \
    __builtin_assume_aligned ((char*)(ptr) + (E2K_BYTES_TO_ALIGN(ptr, align)), align)
#define E2K_ALIGN_PTR_BACK(ptr, align) \
    __builtin_assume_aligned ((char*)(ptr) - (E2K_BYTES_FROM_ALIGN(ptr, align)), align)
#else /* __ptr128__ */
#define E2K_ALIGN_PTR(ptr, align) \
    __builtin_assume_aligned ((void*) (((long)(ptr) + ((align)-1)) & ~((align)-1)), align)
#define E2K_ALIGN_PTR_BACK(ptr, align) \
    __builtin_assume_aligned ((void*) ((long)(ptr) & ~((align)-1)), align)
#endif /* __ptr128__ */

/* вариант на арифметических операциях для данных формата 64 */
#define E2K_PREPARE_ALIGN_ARITH(pointer, align)           \
    align <<= 3
#define E2K_ALIGN_DATA_ARITH(src1, src2, dst, align)      \
    dst = (((__di)(src1)) >> align) | (((src2) << (64 - align)) & ((- (long long) align) >> 63))

/* вариант на арифметических операциях для данных формата 64, считанных в big-endian режиме */
#define E2K_PREPARE_ALIGN_ARITH_BE(pointer, align)        \
    E2K_PREPARE_ALIGN_ARITH(pointer, align)
#define E2K_ALIGN_DATA_ARITH_BE(src1, src2, dst, align)   \
    dst = ((src1) << align) | ((((__di)(src2)) >> (64 - align)) & ((- (long long) align) >> 63))

/* вариант на арифметических операциях для данных формата 32 */
#define E2K_PREPARE_ALIGN_ARITH32(pointer, align)         \
    align <<= 3
#define E2K_ALIGN_DATA_ARITH32(src1, src2, dst, align)    \
    dst = ((__di) (src1) >> align) | (((__di) (src2) << (32 - align)) & ((- (long long) align) >> 31))

/* вариант на операциях insfs/scrs для данных формата 32 */
#define E2K_PREPARE_ALIGN_INSF32(pointer, align)          \
    align <<= 9
#define E2K_ALIGN_DATA_INSF32(src1, src2, dst, align)     \
    dst = __builtin_e2k_scrs (__builtin_e2k_insfs (src1, align, src2), align >> 6)

/* вариант на операции pshufb для данных формата 64 */
#define E2K_PREPARE_ALIGN(align, spec)                    \
    spec = __builtin_e2k_paddd (__builtin_e2k_pshufb (0, align, 0), 0x0706050403020100LL)
#define E2K_ALIGN_DATA(src1, src2, dst, spec)             \
    dst = __builtin_e2k_pshufb (src2, src1, spec)

/* вариант на операции pshufb для данных формата 64, считанных в big-endian режиме */
#define E2K_PREPARE_ALIGN_BE(align, spec)                 \
    spec = __builtin_e2k_psubd (0x0f0e0d0c0b0a0908LL, __builtin_e2k_pshufb (0, align, 0))
#define E2K_ALIGN_DATA_BE(src1, src2, dst, spec)          \
    dst = __builtin_e2k_pshufb (src1, src2, spec)

#if __iset__ >= 5 /* p9 и старше */

/* вариант на операции qppermb для данных формата 128 */
#define E2K_PREPARE_ALIGN128(align, spec) {                                               \
    __di __xx = __builtin_e2k_pshufb (0, align, 0);                                       \
    spec = __builtin_e2k_qppackdl (__builtin_e2k_paddd (__xx, 0x0f0e0d0c0b0a0908LL),      \
                                   __builtin_e2k_paddd (__xx, 0x0706050403020100LL));     \
}
#define E2K_ALIGN_DATA128(src1, src2, dst, spec)                                          \
    dst = __builtin_e2k_qppermb (src2, src1, spec)

/* вариант на операции qppermb для данных формата 128, считанных в big-endian режиме */
#define E2K_PREPARE_ALIGN128_BE(align, spec) {                                            \
    __di __xx = __builtin_e2k_pshufb (0, align, 0);                                       \
    spec = __builtin_e2k_qppackdl (__builtin_e2k_psubd (0x1f1e1d1c1b1a1918LL, __xx),      \
                                   __builtin_e2k_psubd (0x1716151413121110LL, __xx));     \
}
#define E2K_ALIGN_DATA128_BE(src1, src2, dst, spec)                                       \
    dst = __builtin_e2k_qppermb (src1, src2, spec)

#endif /* __iset__ >= 5 */


/* *****************************************************************************
 *       Вычисление номера первого ненулевого байта (для strlen) в 64S/64U
 * *****************************************************************************/

#define __CTZB(count, x) /* count trailng zero bytes */   \
    (count) = __builtin_e2k_lzcntd (__builtin_e2k_bitrevd (x)) >> 3

#define __CLZB(count, x) /* count leading zero bytes */   \
    (count) = __builtin_e2k_lzcntd (x) >> 3

/* *****************************************************************************
 *                       Размеры L1/L2/L3 кэшей в Эльбрус
 * *****************************************************************************/

#define SIZE_L1 65536            /* размер L1 кэша в байтах */

#if __iset__ <= 2 /* __elbrus_2cplus__ */

#define SIZE_L2 1048576          /* размер L2 кэша в байтах (e3s) */

#elif __iset__ <= 3 || (__iset__ == 4 && defined (__elbrus_1cplus__) && !defined (__elbrus_8c__)) || \
     (__iset__ == 6 && defined (__elbrus_2c3__)) /* __elbrus_4c__, __elbrus_1cplus__, __elbrus_2c3__ */

#define SIZE_L2 2097152          /* размер L2 кэша в байтах (e2s/p2/p2c3) */

#elif __iset__ <= 5 /* __elbrus_8c__ и __elbrus_8c2__ */

#define SIZE_L2 524288           /* размер L2 кэша в байтах (p1/p9) */
#define SIZE_L3 16777216         /* размер L3 кэша в байтах (p1/p9) */

#elif __iset__ <= 6 /* __elbrus_12c__ и __elbrus_16c__ */

#define SIZE_L2 1048576          /* размер L2 кэша в байтах (p12c/p16c) */
#define SIZE_L3 33554432         /* размер L3 кэша в байтах (p12c/p16c) */

#endif /* __iset__ <= 6 */

#ifdef __cplusplus
}
#endif

#endif /* _E2KINTRIN_H */
