Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/zydis/Zydis/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 154 kB image not shown  

Quelle  Encoder.c   Sprache: C

 
/***************************************************************************************************

  Zyan Disassembler Library (Zydis)

  Original Author : Mappa

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.

***************************************************************************************************/


// ReSharper disable CppClangTidyClangDiagnosticSwitchEnum
// ReSharper disable CppClangTidyClangDiagnosticCoveredSwitchDefault
// ReSharper disable CppClangTidyClangDiagnosticImplicitFallthrough

#include "zydis/Zycore/LibC.h"
#include "zydis/Zydis/Encoder.h"
#include "zydis/Zydis/Utils.h"
#include "zydis/Zydis/Internal/EncoderData.h"
#include "zydis/Zydis/Internal/SharedData.h"

/* ============================================================================================== */
/* Macros                                                                                         */
/* ============================================================================================== */

/* ---------------------------------------------------------------------------------------------- */
/* Constants                                                                                      */
/* ---------------------------------------------------------------------------------------------- */

#define ZYDIS_OPSIZE_MAP_BYTEOP                 1
#define ZYDIS_OPSIZE_MAP_DEFAULT64              4
#define ZYDIS_OPSIZE_MAP_FORCE64                5
#define ZYDIS_ADSIZE_MAP_IGNORED                1
#define ZYDIS_LEGACY_SEGMENTS                   (ZYDIS_ATTRIB_HAS_SEGMENT_CS | \
                                                 ZYDIS_ATTRIB_HAS_SEGMENT_SS | \
                                                 ZYDIS_ATTRIB_HAS_SEGMENT_DS | \
                                                 ZYDIS_ATTRIB_HAS_SEGMENT_ES)
#define ZYDIS_ENCODABLE_PREFIXES_NO_SEGMENTS    (ZYDIS_ENCODABLE_PREFIXES ^ \
                                                 ZYDIS_ATTRIB_HAS_SEGMENT)

/* ---------------------------------------------------------------------------------------------- */

/* ============================================================================================== */
/* Internal enums and types                                                                       */
/* ============================================================================================== */

/**
 * Usage of `REX.W` prefix makes it impossible to use some byte-sized registers. Values of this
 * enum are used to track and facilitate enforcement of these restrictions.
 */

typedef enum ZydisEncoderRexType_
{
    ZYDIS_REX_TYPE_UNKNOWN,
    ZYDIS_REX_TYPE_REQUIRED,
    ZYDIS_REX_TYPE_FORBIDDEN,

    /**
     * Maximum value of this enum.
     */

    ZYDIS_REX_TYPE_MAX_VALUE = ZYDIS_REX_TYPE_FORBIDDEN,
    /**
     * The minimum number of bits required to represent all values of this enum.
     */

    ZYDIS_REX_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REX_TYPE_MAX_VALUE)
} ZydisEncoderRexType;

/**
 * Primary structure used during instruction matching phase. Once filled it contains information
 * about matched instruction definition and some values deduced from encoder request. It gets
 * converted to `ZydisEncoderInstruction` during instruction building phase.
 */

typedef struct ZydisEncoderInstructionMatch_
{
    /**
     * A pointer to the `ZydisEncoderRequest` instance.
     */

    const ZydisEncoderRequest *request;
    /**
     * A pointer to the `ZydisEncodableInstruction` instance.
     */

    const ZydisEncodableInstruction *definition;
    /**
     * A pointer to the `ZydisInstructionDefinition` instance.
     */

    const ZydisInstructionDefinition *base_definition;
    /**
     * A pointer to the `ZydisOperandDefinition` array.
     */

    const ZydisOperandDefinition *operands;
    /**
     * Encodable attributes for this instruction.
     */

    ZydisInstructionAttributes attributes;
    /**
     * Effective operand size attribute.
     */

    ZyanU8 eosz;
    /**
     * Effective address size attribute.
     */

    ZyanU8 easz;
    /**
     * Effective displacement size.
     */

    ZyanU8 disp_size;
    /**
     * Effective immediate size.
     */

    ZyanU8 imm_size;
    /**
     * Exponent of compressed displacement scale factor (2^cd8_scale)
     */

    ZyanU8 cd8_scale;
    /**
     * `REX` prefix constraints.
     */

    ZydisEncoderRexType rex_type;
    /**
     * True for special cases where operand size attribute must be lower than 64 bits.
     */

    ZyanBool eosz64_forbidden;
    /**
     * True when instruction definition has relative operand (used for branching instructions).
     */

    ZyanBool has_rel_operand;
} ZydisEncoderInstructionMatch;

/**
 * Encapsulates information about writable buffer.
 */

typedef struct ZydisEncoderBuffer_
{
    /**
     * A pointer to actual data buffer.
     */

    ZyanU8 *buffer;
    /**
     * Size of this buffer.
     */

    ZyanUSize size;
    /**
     * Current write offset.
     */

    ZyanUSize offset;
} ZydisEncoderBuffer;

/**
 * Low-level instruction representation. Once filled this structure contains all information
 * required for final instruction emission phase.
 */

typedef struct ZydisEncoderInstruction_
{
    /**
     * Encodable attributes for this instruction.
     */

    ZydisInstructionAttributes attributes;
    /**
     * The instruction encoding.
     */

    ZydisInstructionEncoding encoding;
    /**
     * The opcode map.
     */

    ZydisOpcodeMap opcode_map;
    /**
     * The opcode.
     */

    ZyanU8 opcode;
    /**
     * The `vvvv` field (`VEX`, `EVEX`, `MVEX`, `XOP`).
     */

    ZyanU8 vvvv;
    /**
     * The `sss` field (`MVEX`).
     */

    ZyanU8 sss;
    /**
     * The mask register ID.
     */

    ZyanU8 mask;
    /**
     * The vector length.
     */

    ZyanU8 vector_length;
    /**
     * The `mod` component of Mod/RM byte.
     */

    ZyanU8 mod;
    /**
     * The `reg` component of Mod/RM byte.
     */

    ZyanU8 reg;
    /**
     * The `rm` component of Mod/RM byte.
     */

    ZyanU8 rm;
    /**
     * The scale component of SIB byte.
     */

    ZyanU8 scale;
    /**
     * The index component of SIB byte.
     */

    ZyanU8 index;
    /**
     * The base component of SIB byte.
     */

    ZyanU8 base;
    /**
     * The `REX.W` bit.
     */

    ZyanBool rex_w;
    /**
     * True if using zeroing mask (`EVEX`).
     */

    ZyanBool zeroing;
    /**
     * True if using eviction hint (`MVEX`).
     */

    ZyanBool eviction_hint;
    /**
     * Size of displacement value.
     */

    ZyanU8 disp_size;
    /**
     * Size of immediate value.
     */

    ZyanU8 imm_size;
    /**
     * The displacement value.
     */

    ZyanU64 disp;
    /**
     * The immediate value.
     */

    ZyanU64 imm;
} ZydisEncoderInstruction;

/* ============================================================================================== */
/* Internal functions                                                                             */
/* ============================================================================================== */

/**
 * Converts `ZydisInstructionEncoding` to `ZydisEncodableEncoding`.
 *
 * @param   encoding `ZydisInstructionEncoding` value to convert.
 *
 * @return  Equivalent `ZydisEncodableEncoding` value.
 */

static ZydisEncodableEncoding ZydisGetEncodableEncoding(ZydisInstructionEncoding encoding)
{
    static const ZydisEncodableEncoding encoding_lookup[6] =
    {
        ZYDIS_ENCODABLE_ENCODING_LEGACY,
        ZYDIS_ENCODABLE_ENCODING_3DNOW,
        ZYDIS_ENCODABLE_ENCODING_XOP,
        ZYDIS_ENCODABLE_ENCODING_VEX,
        ZYDIS_ENCODABLE_ENCODING_EVEX,
        ZYDIS_ENCODABLE_ENCODING_MVEX,
    };
    ZYAN_ASSERT((ZyanUSize)encoding <= ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE);
    return encoding_lookup[encoding];
}

/**
 * Converts `ZydisMachineMode` to default stack width value expressed in bits.
 *
 * @param   machine_mode `ZydisMachineMode` value to convert.
 *
 * @return  Stack width for requested machine mode.
 */

static ZyanU8 ZydisGetMachineModeWidth(ZydisMachineMode machine_mode)
{
    ZYAN_ASSERT((ZyanUSize)machine_mode <= ZYDIS_MACHINE_MODE_MAX_VALUE);
    static const ZyanU8 lookup[6] =
    {
        /* ZYDIS_MACHINE_MODE_LONG_64 */            64,
        /* ZYDIS_MACHINE_MODE_LONG_COMPAT_32 */     32,
        /* ZYDIS_MACHINE_MODE_LONG_COMPAT_16 */     16,
        /* ZYDIS_MACHINE_MODE_LEGACY_32 */          32,
        /* ZYDIS_MACHINE_MODE_LEGACY_16 */          16,
        /* ZYDIS_MACHINE_MODE_REAL_16 */            16,
    };
    return lookup[machine_mode];
}

/**
 * Converts `ZydisAddressSizeHint` to address size expressed in bits.
 *
 * @param   hint Address size hint.
 *
 * @return  Address size in bits.
 */

static ZyanU8 ZydisGetAszFromHint(ZydisAddressSizeHint hint)
{
    ZYAN_ASSERT((ZyanUSize)hint <= ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE);
    static const ZyanU8 lookup[ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE + 1] = { 0, 16, 32, 64 };
    return lookup[hint];
}

/**
 * Converts `ZydisOperandSizeHint` to operand size expressed in bits.
 *
 * @param   hint Operand size hint.
 *
 * @return  Operand size in bits.
 */

static ZyanU8 ZydisGetOszFromHint(ZydisOperandSizeHint hint)
{
    ZYAN_ASSERT((ZyanUSize)hint <= ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE);
    static const ZyanU8 lookup[ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE + 1] = { 0, 8, 16, 32, 64 };
    return lookup[hint];
}

/**
 * Calculates maximum size of absolute address value based on address size hint.
 *
 * @param   request A pointer to `ZydisEncoderRequest` struct.
 *
 * @return  Maximum address size in bits.
 */

static ZyanU8 ZydisGetMaxAddressSize(const ZydisEncoderRequest *request)
{
    ZyanU8 addr_size = ZydisGetAszFromHint(request->address_size_hint);
    if (addr_size == 0)
    {
        addr_size = ZydisGetMachineModeWidth(request->machine_mode);
    }
    return addr_size;
}

/**
 * Calculates effective operand size.
 *
 * @param   match            A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   size_table       Array of possible size values for different operand sizes.
 * @param   desired_size     Operand size requested by caller.
 * @param   exact_match_mode True if desired_size must be matched exactly, false when
 *                           "not lower than" matching is desired.
 *
 * @return  Effective operand size in bits.
 */

static ZyanU8 ZydisGetOperandSizeFromElementSize(ZydisEncoderInstructionMatch *match,
    const ZyanU16 *size_table, ZyanU16 desired_size, ZyanBool exact_match_mode)
{
    if ((match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_DEFAULT64) &&
        (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
    {
        if ((exact_match_mode && (size_table[2] == desired_size)) ||
            (!exact_match_mode && (size_table[2] >= desired_size)))
        {
            return 64;
        }
        else if (size_table[0] == desired_size)
        {
            return 16;
        }
    }
    else if ((match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_FORCE64) &&
             (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
    {
        if (size_table[2] == desired_size)
        {
            return 64;
        }
    }
    else
    {
        static const ZyanI8 eosz_priority_lookup[4][3] =
        {
            {  0,  1, -1 },
            {  1,  0, -1 },
            {  1,  2,  0 },
        };
        const ZyanU8 eosz_index = ZydisGetMachineModeWidth(match->request->machine_mode) >> 5;
        for (int i = 0; i < 3; ++i)
        {
            const ZyanI8 eosz_candidate = eosz_priority_lookup[eosz_index][i];
            if ((eosz_candidate == -1) ||
                !(match->definition->operand_sizes & (1 << eosz_candidate)))
            {
                continue;
            }
            if ((exact_match_mode && (size_table[eosz_candidate] == desired_size)) ||
                (!exact_match_mode && (size_table[eosz_candidate] >= desired_size)))
            {
                return 16 << eosz_candidate;
            }
        }
    }

    return 0;
}

/**
 * Calculates effective immediate size.
 *
 * @param   match        A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   size_table   Array of possible size values for different operand sizes.
 * @param   min_imm_size Minimum immediate size.
 *
 * @return  Effective operand size in bits.
 */

static ZyanU8 ZydisGetScaledImmSize(ZydisEncoderInstructionMatch *match, const ZyanU16 *size_table,
    ZyanU8 min_imm_size)
{
    if (match->eosz == 0)
    {
        match->eosz = ZydisGetOperandSizeFromElementSize(match, size_table, min_imm_size,
            ZYAN_FALSE);
        return match->eosz != 0 ? (ZyanU8)size_table[match->eosz >> 5] : 0;
    }

    const ZyanU8 index = match->eosz >> 5;
    return size_table[index] >= min_imm_size ? (ZyanU8)size_table[index] : 0;
}

/**
 * Calculates size of smallest integral type able to represent provided signed value.
 *
 * @param   imm Immediate to be represented.
 *
 * @return  Size of smallest integral type able to represent provided signed value.
 */

static ZyanU8 ZydisGetSignedImmSize(ZyanI64 imm)
{
    if (imm >= ZYAN_INT8_MIN && imm <= ZYAN_INT8_MAX)
    {
        return 8;
    }
    if (imm >= ZYAN_INT16_MIN && imm <= ZYAN_INT16_MAX)
    {
        return 16;
    }
    if (imm >= ZYAN_INT32_MIN && imm <= ZYAN_INT32_MAX)
    {
        return 32;
    }

    return 64;
}

/**
 * Calculates size of smallest integral type able to represent provided unsigned value.
 *
 * @param   imm Immediate to be represented.
 *
 * @return  Size of smallest integral type able to represent provided unsigned value.
 */

static ZyanU8 ZydisGetUnsignedImmSize(ZyanU64 imm)
{
    if (imm <= ZYAN_UINT8_MAX)
    {
        return 8;
    }
    if (imm <= ZYAN_UINT16_MAX)
    {
        return 16;
    }
    if (imm <= ZYAN_UINT32_MAX)
    {
        return 32;
    }

    return 64;
}

/**
 * Checks if operand encoding encodes a signed immediate value.
 *
 * @param   encoding Operand encoding for immediate value.
 *
 * @return  True for encodings that represent signed values, false otherwise.
 */

static ZyanBool ZydisIsImmSigned(ZydisOperandEncoding encoding)
{
    switch (encoding)
    {
    case ZYDIS_OPERAND_ENCODING_SIMM8:
    case ZYDIS_OPERAND_ENCODING_SIMM16:
    case ZYDIS_OPERAND_ENCODING_SIMM32:
    case ZYDIS_OPERAND_ENCODING_SIMM64:
    case ZYDIS_OPERAND_ENCODING_SIMM16_32_64:
    case ZYDIS_OPERAND_ENCODING_SIMM32_32_64:
    case ZYDIS_OPERAND_ENCODING_SIMM16_32_32:
    case ZYDIS_OPERAND_ENCODING_JIMM8:
    case ZYDIS_OPERAND_ENCODING_JIMM16:
    case ZYDIS_OPERAND_ENCODING_JIMM32:
    case ZYDIS_OPERAND_ENCODING_JIMM64:
    case ZYDIS_OPERAND_ENCODING_JIMM16_32_64:
    case ZYDIS_OPERAND_ENCODING_JIMM32_32_64:
    case ZYDIS_OPERAND_ENCODING_JIMM16_32_32:
    case ZYDIS_OPERAND_ENCODING_DISP8:
    case ZYDIS_OPERAND_ENCODING_DISP16:
    case ZYDIS_OPERAND_ENCODING_DISP32:
    case ZYDIS_OPERAND_ENCODING_DISP64:
    case ZYDIS_OPERAND_ENCODING_DISP16_32_64:
    case ZYDIS_OPERAND_ENCODING_DISP32_32_64:
    case ZYDIS_OPERAND_ENCODING_DISP16_32_32:
        return ZYAN_TRUE;
    case ZYDIS_OPERAND_ENCODING_UIMM8:
    case ZYDIS_OPERAND_ENCODING_UIMM16:
    case ZYDIS_OPERAND_ENCODING_UIMM32:
    case ZYDIS_OPERAND_ENCODING_UIMM64:
    case ZYDIS_OPERAND_ENCODING_UIMM16_32_64:
    case ZYDIS_OPERAND_ENCODING_UIMM32_32_64:
    case ZYDIS_OPERAND_ENCODING_UIMM16_32_32:
    case ZYDIS_OPERAND_ENCODING_IS4:
        return ZYAN_FALSE;
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Calculates effective immediate size.
 *
 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   imm     Immediate value to encode.
 * @param   def_op  Operand definition for immediate operand.
 *
 * @return  Effective operand size in bits (0 if function failed).
 */

static ZyanU8 ZydisGetEffectiveImmSize(ZydisEncoderInstructionMatch *match, ZyanI64 imm,
    const ZydisOperandDefinition *def_op)
{
    ZyanU8 eisz = 0;
    ZyanU8 min_size = ZydisIsImmSigned((ZydisOperandEncoding)def_op->op.encoding)
        ? ZydisGetSignedImmSize(imm)
        : ZydisGetUnsignedImmSize((ZyanU64)imm);

    switch (def_op->op.encoding)
    {
    case ZYDIS_OPERAND_ENCODING_UIMM8:
    case ZYDIS_OPERAND_ENCODING_SIMM8:
        eisz = 8;
        break;
    case ZYDIS_OPERAND_ENCODING_IS4:
        ZYAN_ASSERT(def_op->element_type == ZYDIS_IELEMENT_TYPE_UINT8);
        eisz = ((ZyanU64)imm <= 15) ? 8 : 0;
        break;
    case ZYDIS_OPERAND_ENCODING_UIMM16:
    case ZYDIS_OPERAND_ENCODING_SIMM16:
        eisz = 16;
        break;
    case ZYDIS_OPERAND_ENCODING_UIMM32:
    case ZYDIS_OPERAND_ENCODING_SIMM32:
        eisz = 32;
        break;
    case ZYDIS_OPERAND_ENCODING_UIMM64:
    case ZYDIS_OPERAND_ENCODING_SIMM64:
        eisz = 64;
        break;
    case ZYDIS_OPERAND_ENCODING_UIMM16_32_64:
    case ZYDIS_OPERAND_ENCODING_SIMM16_32_64:
    {
        static const ZyanU16 simm16_32_64_sizes[3] = { 16, 32, 64 };
        return ZydisGetScaledImmSize(match, simm16_32_64_sizes, min_size);
    }
    case ZYDIS_OPERAND_ENCODING_UIMM32_32_64:
    case ZYDIS_OPERAND_ENCODING_SIMM32_32_64:
    {
        static const ZyanU16 simm32_32_64_sizes[3] = { 32, 32, 64 };
        return ZydisGetScaledImmSize(match, simm32_32_64_sizes, min_size);
    }
    case ZYDIS_OPERAND_ENCODING_UIMM16_32_32:
    case ZYDIS_OPERAND_ENCODING_SIMM16_32_32:
    {
        static const ZyanU16 simm16_32_32_sizes[3] = { 16, 32, 32 };
        return ZydisGetScaledImmSize(match, simm16_32_32_sizes, min_size);
    }
    case ZYDIS_OPERAND_ENCODING_DISP16_32_64:
    {
        ZYAN_ASSERT(match->easz == 0);
        const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request);
        const ZyanU64 uimm = imm & (~(0xFFFFFFFFFFFFFFFFULL << (addr_size - 1) << 1));
        if (min_size < addr_size && ZydisGetUnsignedImmSize(uimm) > min_size)
        {
            min_size = addr_size;
        }
        if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
        {
            if (min_size < 32)
            {
                min_size = 32;
            }
            match->easz = eisz = min_size;
        }
        else
        {
            if (min_size < 16)
            {
                min_size = 16;
            }
            if (min_size == 16 || min_size == 32)
            {
                match->easz = eisz = min_size;
            }
        }
        break;
    }
    case ZYDIS_OPERAND_ENCODING_JIMM8:
    case ZYDIS_OPERAND_ENCODING_JIMM16:
    case ZYDIS_OPERAND_ENCODING_JIMM32:
    case ZYDIS_OPERAND_ENCODING_JIMM64:
    {
        ZyanU8 jimm_index = def_op->op.encoding - ZYDIS_OPERAND_ENCODING_JIMM8;
        if ((match->request->branch_width != ZYDIS_BRANCH_WIDTH_NONE) &&
            (match->request->branch_width != (ZydisBranchWidth)(ZYDIS_BRANCH_WIDTH_8 + jimm_index)))
        {
            return 0;
        }
        eisz = 8 << jimm_index;
        break;
    }
    case ZYDIS_OPERAND_ENCODING_JIMM16_32_32:
        switch (match->request->branch_width)
        {
        case ZYDIS_BRANCH_WIDTH_NONE:
        {
            static const ZyanU16 jimm16_32_32_sizes[3] = { 16, 32, 32 };
            return ZydisGetScaledImmSize(match, jimm16_32_32_sizes, min_size);
        }
        case ZYDIS_BRANCH_WIDTH_16:
            eisz = 16;
            break;
        case ZYDIS_BRANCH_WIDTH_32:
            eisz = 32;
            break;
        case ZYDIS_BRANCH_WIDTH_8:
        case ZYDIS_BRANCH_WIDTH_64:
            return 0;
        default:
            ZYAN_UNREACHABLE;
        }
        break;
    default:
        ZYAN_UNREACHABLE;
    }

    return eisz >= min_size ? eisz : 0;
}

/**
 * Checks if register width is compatible with effective operand size.
 *
 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   reg_width   Register width in bits.
 *
 * @return  True if width is compatible, false otherwise.
 */

static ZyanBool ZydisCheckOsz(ZydisEncoderInstructionMatch *match, ZydisRegisterWidth reg_width)
{
    ZYAN_ASSERT(reg_width <= ZYAN_UINT8_MAX);
    if (match->eosz == 0)
    {
        if (reg_width == 8)
        {
            return ZYAN_FALSE;
        }
        match->eosz = (ZyanU8)reg_width;
        return ZYAN_TRUE;
    }

    return match->eosz == (ZyanU8)reg_width ? ZYAN_TRUE : ZYAN_FALSE;
}

/**
 * Checks if register width is compatible with effective address size.
 *
 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   reg_width   Register width in bits.
 *
 * @return  True if width is compatible, false otherwise.
 */

static ZyanBool ZydisCheckAsz(ZydisEncoderInstructionMatch *match, ZydisRegisterWidth reg_width)
{
    ZYAN_ASSERT(reg_width <= ZYAN_UINT8_MAX);
    if (match->easz == 0)
    {
        if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
            (reg_width == 16))
        {
            return ZYAN_FALSE;
        }
        match->easz = (ZyanU8)reg_width;
        return ZYAN_TRUE;
    }

    return match->easz == (ZyanU8)reg_width ? ZYAN_TRUE : ZYAN_FALSE;
}

/**
 * Checks if specified register is valid for provided register class, encoding and machine mode.
 *
 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   reg         `ZydisRegister` value.
 * @param   reg_class   Register class.
 *
 * @return  True if register value is allowed, false otherwise.
 */

static ZyanBool ZydisIsRegisterAllowed(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
    ZydisRegisterClass reg_class)
{
    const ZyanI8 reg_id = ZydisRegisterGetId(reg);
    ZYAN_ASSERT(reg_id >= 0 && reg_id <= 31);
    if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
    {
        if ((match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_EVEX) &&
            (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_MVEX) &&
            (reg_class != ZYDIS_REGCLASS_GPR8) &&
            (reg_id >= 16))
        {
            return ZYAN_FALSE;
        }
    }
    else
    {
        if (reg_class == ZYDIS_REGCLASS_GPR64)
        {
            return ZYAN_FALSE;
        }
        if (reg_id >= 8)
        {
            return ZYAN_FALSE;
        }
    }

    return ZYAN_TRUE;
}

/**
 * Checks if specified scale value is valid for use with SIB addressing.
 *
 * @param   scale Scale value.
 *
 * @return  True if value is valid, false otherwise.
 */

static ZyanBool ZydisIsScaleValid(ZyanU8 scale)
{
    switch (scale)
    {
    case 0:
    case 1:
    case 2:
    case 4:
    case 8:
        return ZYAN_TRUE;
    default:
        return ZYAN_FALSE;
    }
}

/**
 * Enforces register usage constraints associated with usage of `REX` prefix.
 *
 * @param   match               A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   reg                 `ZydisRegister` value.
 * @param   addressing_mode     True if checked address is used for address calculations. This
 *                              implies more permissive checks.
 *
 * @return  True if register usage is allowed, false otherwise.
 */

static ZyanBool ZydisValidateRexType(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
    ZyanBool addressing_mode)
{
    switch (reg)
    {
    case ZYDIS_REGISTER_AL:
    case ZYDIS_REGISTER_CL:
    case ZYDIS_REGISTER_DL:
    case ZYDIS_REGISTER_BL:
        return ZYAN_TRUE;
    case ZYDIS_REGISTER_AH:
    case ZYDIS_REGISTER_CH:
    case ZYDIS_REGISTER_DH:
    case ZYDIS_REGISTER_BH:
        if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
        {
            match->rex_type = ZYDIS_REX_TYPE_FORBIDDEN;
        }
        else if (match->rex_type == ZYDIS_REX_TYPE_REQUIRED)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_REGISTER_SPL:
    case ZYDIS_REGISTER_BPL:
    case ZYDIS_REGISTER_SIL:
    case ZYDIS_REGISTER_DIL:
    case ZYDIS_REGISTER_R8B:
    case ZYDIS_REGISTER_R9B:
    case ZYDIS_REGISTER_R10B:
    case ZYDIS_REGISTER_R11B:
    case ZYDIS_REGISTER_R12B:
    case ZYDIS_REGISTER_R13B:
    case ZYDIS_REGISTER_R14B:
    case ZYDIS_REGISTER_R15B:
        if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
        {
            match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
        }
        else if (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
        {
            return ZYAN_FALSE;
        }
        break;
    default:
        if ((ZydisRegisterGetId(reg) > 7) ||
            (!addressing_mode && (ZydisRegisterGetClass(reg) == ZYDIS_REGCLASS_GPR64)))
        {
            if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
            {
                match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
            }
            else if (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
            {
                return ZYAN_FALSE;
            }
        }
        break;
    }

    return ZYAN_TRUE;
}

/**
 * Checks if specified register is valid for use with SIB addressing.
 *
 * @param   match          A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   reg_class      Register class.
 * @param   reg            `ZydisRegister` value.
 *
 * @return  True if register value is allowed, false otherwise.
 */

static ZyanBool ZydisIsValidAddressingClass(ZydisEncoderInstructionMatch *match,
    ZydisRegisterClass reg_class, ZydisRegister reg)
{
    ZyanBool result;
    const ZyanBool is_64 = (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64);
    switch (reg_class)
    {
    case ZYDIS_REGCLASS_INVALID:
        return ZYAN_TRUE;
    case ZYDIS_REGCLASS_GPR16:
        result = !is_64;
        break;
    case ZYDIS_REGCLASS_GPR32:
        result = is_64 || ZydisRegisterGetId(reg) < 8;
        break;
    case ZYDIS_REGCLASS_GPR64:
        result = is_64;
        break;
    default:
        return ZYAN_FALSE;
    }

    return result && ZydisValidateRexType(match, reg, ZYAN_TRUE);
}

/**
 * Helper function that determines correct `ModR/M.RM` value for 16-bit addressing mode.
 *
 * @param   base   `ZydisRegister` used as `SIB.base`.
 * @param   index  `ZydisRegister` used as `SIB.index`.
 *
 * @return  `ModR/M.RM` value (-1 if function failed).
 */

static ZyanI8 ZydisGetRm16(ZydisRegister base, ZydisRegister index)
{
    static const ZydisRegister modrm16_lookup[8][2] =
    {
        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_SI },
        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_DI },
        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_SI },
        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_DI },
        { ZYDIS_REGISTER_SI, ZYDIS_REGISTER_NONE },
        { ZYDIS_REGISTER_DI, ZYDIS_REGISTER_NONE },
        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_NONE },
        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_NONE },
    };
    for (ZyanI8 i = 0; i < (ZyanI8)ZYAN_ARRAY_LENGTH(modrm16_lookup); ++i)
    {
        if ((modrm16_lookup[i][0] == base) &&
            (modrm16_lookup[i][1] == index))
        {
            return i;
        }
    }

    return -1;
}

/**
 * Encodes `MVEX.sss` field for specified broadcast mode.
 *
 * @param   broadcast Broadcast mode.
 *
 * @return  Corresponding `MVEX.sss` value.
 */

static ZyanU8 ZydisEncodeMvexBroadcastMode(ZydisBroadcastMode broadcast)
{
    switch (broadcast)
    {
    case ZYDIS_BROADCAST_MODE_INVALID:
        return 0;
    case ZYDIS_BROADCAST_MODE_1_TO_16:
    case ZYDIS_BROADCAST_MODE_1_TO_8:
        return 1;
    case ZYDIS_BROADCAST_MODE_4_TO_16:
    case ZYDIS_BROADCAST_MODE_4_TO_8:
        return 2;
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Encodes `MVEX.sss` field for specified conversion mode.
 *
 * @param   conversion Conversion mode.
 *
 * @return  Corresponding `MVEX.sss` value.
 */

static ZyanU8 ZydisEncodeMvexConversionMode(ZydisConversionMode conversion)
{
    switch (conversion)
    {
    case ZYDIS_CONVERSION_MODE_INVALID:
        return 0;
    case ZYDIS_CONVERSION_MODE_FLOAT16:
        return 3;
    case ZYDIS_CONVERSION_MODE_UINT8:
        return 4;
    case ZYDIS_CONVERSION_MODE_SINT8:
        return 5;
    case ZYDIS_CONVERSION_MODE_UINT16:
        return 6;
    case ZYDIS_CONVERSION_MODE_SINT16:
        return 7;
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Determines scale factor for compressed 8-bit displacement (`EVEX` instructions only).
 *
 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
 *
 * @return  log2(scale factor)
 */

static ZyanU8 ZydisGetCompDispScaleEvex(const ZydisEncoderInstructionMatch *match)
{
    const ZydisInstructionDefinitionEVEX *evex_def =
        (const ZydisInstructionDefinitionEVEX *)match->base_definition;

    ZYAN_ASSERT(match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
    ZYAN_ASSERT(evex_def->tuple_type);
    ZYAN_ASSERT(evex_def->element_size);
    const ZyanU8 vector_length = match->definition->vector_length - ZYDIS_VECTOR_LENGTH_128;
    static const ZyanU8 size_indexes[ZYDIS_IELEMENT_SIZE_MAX_VALUE + 1] =
    {
        0, 0, 0, 1, 2, 4
    };
    ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(size_indexes));
    const ZyanU8 size_index = size_indexes[evex_def->element_size];
    switch (evex_def->tuple_type)
    {
    case ZYDIS_TUPLETYPE_FV:
    {
        static const ZyanU8 scales[2][3][3] =
        {
            /*B0*/ { /*16*/ { 4, 5, 6 }, /*32*/ { 4, 5, 6 }, /*64*/ { 4, 5, 6 } },
            /*B1*/ { /*16*/ { 1, 1, 1 }, /*32*/ { 2, 2, 2 }, /*64*/ { 3, 3, 3 } }
        };
        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
        ZYAN_ASSERT(size_index < 3);
        return scales[broadcast][size_index][vector_length];
    }
    case ZYDIS_TUPLETYPE_HV:
    {
        static const ZyanU8 scales[2][2][3] =
        {
            /*B0*/ { /*16*/ {  3, 4, 5 }, /*32*/ {  3, 4, 5 } },
            /*B1*/ { /*16*/ {  1, 1, 1 }, /*32*/ {  2, 2, 2 } }
        };
        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
        ZYAN_ASSERT(size_index < 3);
        return scales[broadcast][size_index][vector_length];
    }
    case ZYDIS_TUPLETYPE_FVM:
    {
        static const ZyanU8 scales[3] =
        {
            4, 5, 6
        };
        return scales[vector_length];
    }
    case ZYDIS_TUPLETYPE_GSCAT:
    case ZYDIS_TUPLETYPE_T1S:
    {
        static const ZyanU8 scales[6] =
        {
            /*   */ 0,
            /*  8*/ 0,
            /* 16*/ 1,
            /* 32*/ 2,
            /* 64*/ 3,
            /*128*/ 4
        };
        ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(scales));
        return scales[evex_def->element_size];
    }
    case ZYDIS_TUPLETYPE_T1F:
    {
        static const ZyanU8 scales[3] =
        {
            /* 16*/ 1,
            /* 32*/ 2,
            /* 64*/ 3
        };
        ZYAN_ASSERT(size_index < 3);
        return scales[size_index];
    }
    case ZYDIS_TUPLETYPE_T1_4X:
        return 4;
    case ZYDIS_TUPLETYPE_T2:
        return match->definition->rex_w ? 4 : 3;
    case ZYDIS_TUPLETYPE_T4:
        return match->definition->rex_w ? 5 : 4;
    case ZYDIS_TUPLETYPE_T8:
        return 5;
    case ZYDIS_TUPLETYPE_HVM:
    {
        static const ZyanU8 scales[3] =
        {
            3, 4, 5
        };
        return scales[vector_length];
    }
    case ZYDIS_TUPLETYPE_QVM:
    {
        static const ZyanU8 scales[3] =
        {
            2, 3, 4
        };
        return scales[vector_length];
    }
    case ZYDIS_TUPLETYPE_OVM:
    {
        static const ZyanU8 scales[3] =
        {
            1, 2, 3
        };
        return scales[vector_length];
    }
    case ZYDIS_TUPLETYPE_M128:
        return 4;
    case ZYDIS_TUPLETYPE_DUP:
    {
        static const ZyanU8 scales[3] =
        {
            3, 5, 6
        };
        return scales[vector_length];
    }
    case ZYDIS_TUPLETYPE_QUARTER:
    {
        static const ZyanU8 scales[2][3] =
        {
            /*B0*/ { 2, 3, 4 },
            /*B1*/ { 1, 1, 1 }
        };
        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
        return scales[broadcast][vector_length];
    }
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Determines scale factor for compressed 8-bit displacement (`MVEX` instructions only).
 *
 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
 *
 * @return  log2(scale factor)
 */

static ZyanU8 ZydisGetCompDispScaleMvex(const ZydisEncoderInstructionMatch *match)
{
    const ZydisInstructionDefinitionMVEX *mvex_def =
        (const ZydisInstructionDefinitionMVEX *)match->base_definition;

    ZyanU8 index = mvex_def->has_element_granularity;
    ZYAN_ASSERT(!index || !mvex_def->broadcast);
    if (!index && mvex_def->broadcast)
    {
        switch (mvex_def->broadcast)
        {
        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8:
        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
            index = 1;
            break;
        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8:
        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
            index = 2;
            break;
        default:
            ZYAN_UNREACHABLE;
        }
    }

    const ZyanU8 sss = ZydisEncodeMvexBroadcastMode(match->request->mvex.broadcast) |
                       ZydisEncodeMvexConversionMode(match->request->mvex.conversion);
    switch (mvex_def->functionality)
    {
    case ZYDIS_MVEX_FUNC_IGNORED:
    case ZYDIS_MVEX_FUNC_INVALID:
    case ZYDIS_MVEX_FUNC_RC:
    case ZYDIS_MVEX_FUNC_SAE:
    case ZYDIS_MVEX_FUNC_SWIZZLE_32:
    case ZYDIS_MVEX_FUNC_SWIZZLE_64:
        return 0;
    case ZYDIS_MVEX_FUNC_F_32:
    case ZYDIS_MVEX_FUNC_I_32:
    case ZYDIS_MVEX_FUNC_F_64:
    case ZYDIS_MVEX_FUNC_I_64:
        return 6;
    case ZYDIS_MVEX_FUNC_SF_32:
    case ZYDIS_MVEX_FUNC_SF_32_BCST:
    case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
    case ZYDIS_MVEX_FUNC_UF_32:
    {
        static const ZyanU8 lookup[3][8] =
        {
            { 6, 2, 4, 5, 4, 4, 5, 5 },
            { 2, 0, 0, 1, 0, 0, 1, 1 },
            { 4, 0, 0, 3, 2, 2, 3, 3 }
        };
        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
        return lookup[index][sss];
    }
    case ZYDIS_MVEX_FUNC_SI_32:
    case ZYDIS_MVEX_FUNC_UI_32:
    case ZYDIS_MVEX_FUNC_SI_32_BCST:
    case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
    {
        static const ZyanU8 lookup[3][8] =
        {
            { 6, 2, 4, 0, 4, 4, 5, 5 },
            { 2, 0, 0, 0, 0, 0, 1, 1 },
            { 4, 0, 0, 0, 2, 2, 3, 3 }
        };
        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
        return lookup[index][sss];
    }
    case ZYDIS_MVEX_FUNC_SF_64:
    case ZYDIS_MVEX_FUNC_UF_64:
    case ZYDIS_MVEX_FUNC_SI_64:
    case ZYDIS_MVEX_FUNC_UI_64:
    {
        static const ZyanU8 lookup[3][3] =
        {
            { 6, 3, 5 },
            { 3, 0, 0 },
            { 5, 0, 0 }
        };
        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
        return lookup[index][sss];
    }
    case ZYDIS_MVEX_FUNC_DF_32:
    case ZYDIS_MVEX_FUNC_DI_32:
    {
        static const ZyanU8 lookup[2][8] =
        {
            { 6, 0, 0, 5, 4, 4, 5, 5 },
            { 2, 0, 0, 1, 0, 0, 1, 1 }
        };
        ZYAN_ASSERT(index < 2);
        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
        return lookup[index][sss];
    }
    case ZYDIS_MVEX_FUNC_DF_64:
    case ZYDIS_MVEX_FUNC_DI_64:
        ZYAN_ASSERT(index < 2);
        return index == 0 ? 6 : 3;
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Determines scale factor for compressed 8-bit displacement.
 *
 * @param   match A pointer to `ZydisEncoderInstructionMatch` struct.
 *
 * @return  log2(scale factor)
 */

static ZyanU8 ZydisGetCompDispScale(const ZydisEncoderInstructionMatch *match)
{
    switch (match->definition->encoding)
    {
    case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
    case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
    case ZYDIS_INSTRUCTION_ENCODING_XOP:
    case ZYDIS_INSTRUCTION_ENCODING_VEX:
        return 0;
    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
        return ZydisGetCompDispScaleEvex(match);
    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
        return ZydisGetCompDispScaleMvex(match);
    default:
        ZYAN_UNREACHABLE;
    }
}

/**
 * Checks if requested operand matches register operand from instruction definition.
 *
 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
 * @param   def_op      Decoder's operand definition from current instruction definition.
 *
 * @return  True if operands match, false otherwise.
 */

static ZyanBool ZydisIsRegisterOperandCompatible(ZydisEncoderInstructionMatch *match,
    const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
{
    const ZydisRegisterClass reg_class = ZydisRegisterGetClass(user_op->reg.value);
    const ZydisRegisterWidth reg_width = ZydisRegisterClassGetWidth(match->request->machine_mode,
        reg_class);
    if (reg_width == 0)
    {
        return ZYAN_FALSE;
    }

    ZyanBool is4_expected_value = ZYAN_FALSE;
    switch (def_op->type)
    {
    case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG:
        switch (def_op->op.reg.type)
        {
        case ZYDIS_IMPLREG_TYPE_STATIC:
            if (def_op->op.reg.reg.reg != user_op->reg.value)
            {
                return ZYAN_FALSE;
            }
            break;
        case ZYDIS_IMPLREG_TYPE_GPR_OSZ:
            if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
                (reg_class != ZYDIS_REGCLASS_GPR16) &&
                (reg_class != ZYDIS_REGCLASS_GPR32) &&
                (reg_class != ZYDIS_REGCLASS_GPR64))
            {
                return ZYAN_FALSE;
            }
            if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
            {
                return ZYAN_FALSE;
            }
            if (!ZydisCheckOsz(match, reg_width))
            {
                return ZYAN_FALSE;
            }
            break;
        case ZYDIS_IMPLREG_TYPE_GPR_ASZ:
            if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
                (reg_class != ZYDIS_REGCLASS_GPR16) &&
                (reg_class != ZYDIS_REGCLASS_GPR32) &&
                (reg_class != ZYDIS_REGCLASS_GPR64))
            {
                return ZYAN_FALSE;
            }
            if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
            {
                return ZYAN_FALSE;
            }
            if (!ZydisCheckAsz(match, reg_width))
            {
                return ZYAN_FALSE;
            }
            break;
        default:
            ZYAN_UNREACHABLE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR8:
        if (reg_class != ZYDIS_REGCLASS_GPR8)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR16:
        if (reg_class != ZYDIS_REGCLASS_GPR16)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR32:
        if (reg_class != ZYDIS_REGCLASS_GPR32)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR64:
        if (reg_class != ZYDIS_REGCLASS_GPR64)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64:
        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
            (reg_class != ZYDIS_REGCLASS_GPR32) &&
            (reg_class != ZYDIS_REGCLASS_GPR64))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisCheckOsz(match, reg_width))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64:
        if ((reg_class != ZYDIS_REGCLASS_GPR32) &&
            (reg_class != ZYDIS_REGCLASS_GPR64))
        {
            return ZYAN_FALSE;
        }
        if (match->eosz == 0)
        {
            if (reg_class == ZYDIS_REGCLASS_GPR64)
            {
                match->eosz = 64;
            }
            else
            {
                match->eosz64_forbidden = ZYAN_TRUE;
            }
        }
        else if (match->eosz != (ZyanU8)reg_width)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32:
        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
            (reg_class != ZYDIS_REGCLASS_GPR32))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisCheckOsz(match, reg_width))
        {
            if (match->eosz != 64 || reg_class != ZYDIS_REGCLASS_GPR32)
            {
                return ZYAN_FALSE;
            }
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ:
        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
            (reg_class != ZYDIS_REGCLASS_GPR32) &&
            (reg_class != ZYDIS_REGCLASS_GPR64))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisCheckAsz(match, reg_width))
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_FPR:
        if (reg_class != ZYDIS_REGCLASS_X87)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_MMX:
        if (reg_class != ZYDIS_REGCLASS_MMX)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_XMM:
        if (reg_class != ZYDIS_REGCLASS_XMM)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4;
        break;
    case ZYDIS_SEMANTIC_OPTYPE_YMM:
        if (reg_class != ZYDIS_REGCLASS_YMM)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4;
        break;
    case ZYDIS_SEMANTIC_OPTYPE_ZMM:
        if (reg_class != ZYDIS_REGCLASS_ZMM)
        {
            return ZYAN_FALSE;
        }
        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_TMM:
        if (reg_class != ZYDIS_REGCLASS_TMM)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_BND:
        if (reg_class != ZYDIS_REGCLASS_BOUND)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_SREG:
        if (reg_class != ZYDIS_REGCLASS_SEGMENT)
        {
            return ZYAN_FALSE;
        }
        if ((def_op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) &&
            (user_op->reg.value == ZYDIS_REGISTER_CS))
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_CR:
    {
        if (reg_class != ZYDIS_REGCLASS_CONTROL)
        {
            return ZYAN_FALSE;
        }
        static const ZyanU8 cr_lookup[16] =
        {
            1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
        };
        const ZyanI8 reg_id = ZydisRegisterGetId(user_op->reg.value);
        if ((match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) &&
            (reg_id == 8))
        {
            return ZYAN_FALSE;
        }
        if (!cr_lookup[reg_id])
        {
            return ZYAN_FALSE;
        }
        break;
    }
    case ZYDIS_SEMANTIC_OPTYPE_DR:
        if (reg_class != ZYDIS_REGCLASS_DEBUG)
        {
            return ZYAN_FALSE;
        }
        if (user_op->reg.value >= ZYDIS_REGISTER_DR8)
        {
            return ZYAN_FALSE;
        }
        break;
    case ZYDIS_SEMANTIC_OPTYPE_MASK:
        if (reg_class != ZYDIS_REGCLASS_MASK)
        {
            return ZYAN_FALSE;
        }

        // MVEX does not require similar policy check
        if ((match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) &&
            (def_op->op.encoding == ZYDIS_OPERAND_ENCODING_MASK))
        {
            const ZydisInstructionDefinitionEVEX *evex_def =
                (const ZydisInstructionDefinitionEVEX *)match->base_definition;
            ZYAN_ASSERT((evex_def->mask_policy != ZYDIS_MASK_POLICY_INVALID) &&
                        (evex_def->mask_policy != ZYDIS_MASK_POLICY_FORBIDDEN));
            if ((evex_def->mask_policy == ZYDIS_MASK_POLICY_REQUIRED) &&
                (user_op->reg.value == ZYDIS_REGISTER_K0))
            {
                return ZYAN_FALSE;
            }
            if ((evex_def->mask_policy == ZYDIS_MASK_POLICY_ALLOWED) &&
                (match->request->evex.zeroing_mask) &&
                (user_op->reg.value == ZYDIS_REGISTER_K0))
            {
                return ZYAN_FALSE;
            }
        }
        break;
    default:
        ZYAN_UNREACHABLE;
    }

    if (user_op->reg.is4 != is4_expected_value)
    {
        return ZYAN_FALSE;
    }

    return ZYAN_TRUE;
}

/**
 * Checks if requested operand matches memory operand from instruction definition.
 *
 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
 * @param   def_op      Decoder's operand definition from current instruction definition.
 *
 * @return  True if operands match, false otherwise.
 */

static ZyanBool ZydisIsMemoryOperandCompatible(ZydisEncoderInstructionMatch *match,
    const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
{
    switch (def_op->type)
    {
    case ZYDIS_SEMANTIC_OPTYPE_MEM:
    case ZYDIS_SEMANTIC_OPTYPE_AGEN:
    case ZYDIS_SEMANTIC_OPTYPE_MIB:
    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ:
    {
        if ((def_op->type == ZYDIS_SEMANTIC_OPTYPE_MIB) &&
            (user_op->mem.scale != 0))
        {
            return ZYAN_FALSE;
        }
        const ZyanI64 displacement = user_op->mem.displacement;
        ZyanU8 disp_size = 0;
        if (displacement)
        {
            disp_size = ZydisGetSignedImmSize(displacement);
            if (disp_size > 32)
            {
                return ZYAN_FALSE;
            }

            match->cd8_scale = ZydisGetCompDispScale(match);
            if (match->cd8_scale)
            {
                const ZyanI64 mask = (1 << match->cd8_scale) - 1;
                if (!(displacement & mask))
                {
                    if (ZydisGetSignedImmSize(displacement >> match->cd8_scale) == 8)
                    {
                        disp_size = 8;
                    }
                }
                else if (disp_size == 8)
                {
                    disp_size = 16;
                }
            }
        }

        if (def_op->type != ZYDIS_SEMANTIC_OPTYPE_AGEN)
        {
            if (match->eosz != 0)
            {
                const ZyanU8 eosz_index = match->eosz >> 5;
                if (def_op->size[eosz_index] != user_op->mem.size)
                {
                    return ZYAN_FALSE;
                }
            }
            else if ((match->definition->vector_length != ZYDIS_VECTOR_LENGTH_INVALID) ||
                     (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
            {
                ZyanU8 eosz_index = ZydisGetMachineModeWidth(match->request->machine_mode) >> 5;
                if (match->eosz64_forbidden && (eosz_index == 2))
                {
                    eosz_index = 1;
                }
                ZyanU16 allowed_mem_size = def_op->size[eosz_index];
                if ((!allowed_mem_size) &&
                    (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_VEX))
                {
                    ZYAN_ASSERT((match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
                                (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX));
                    switch (match->definition->vector_length)
                    {
                    case ZYDIS_VECTOR_LENGTH_128:
                        allowed_mem_size = 16;
                        break;
                    case ZYDIS_VECTOR_LENGTH_256:
                        allowed_mem_size = 32;
                        break;
                    case ZYDIS_VECTOR_LENGTH_INVALID:
                        ZYAN_ASSERT(match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);
                        ZYAN_FALLTHROUGH;
                    case ZYDIS_VECTOR_LENGTH_512:
                        allowed_mem_size = 64;
                        break;
                    default:
                        ZYAN_UNREACHABLE;
                    }
                    if (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
                    {
                        const ZydisInstructionDefinitionEVEX *evex_def =
                            (const ZydisInstructionDefinitionEVEX *)match->base_definition;
                        static const ZyanU8 element_sizes[ZYDIS_IELEMENT_SIZE_MAX_VALUE + 1] =
                        {
                              0, 1, 2, 4, 8, 16
                        };
                        ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(element_sizes));
                        const ZyanU8 element_size = element_sizes[evex_def->element_size];
                        if (match->request->evex.broadcast || evex_def->broadcast)
                        {
                            allowed_mem_size = element_size;
                        }
                        else
                        {
                            switch (evex_def->tuple_type)
                            {
                            case ZYDIS_TUPLETYPE_FV:
                                break;
                            case ZYDIS_TUPLETYPE_HV:
                                allowed_mem_size /= 2;
                                break;
                            case ZYDIS_TUPLETYPE_QUARTER:
                                allowed_mem_size /= 4;
                                break;
                            default:
                                ZYAN_UNREACHABLE;
                            }
                        }
                    }
                    else
                    {
                        const ZydisInstructionDefinitionMVEX *mvex_def =
                            (const ZydisInstructionDefinitionMVEX *)match->base_definition;
                        ZyanU16 element_size;
                        switch (match->request->mvex.conversion)
                        {
                        case ZYDIS_CONVERSION_MODE_INVALID:

                            switch (mvex_def->functionality)
                            {
                            case ZYDIS_MVEX_FUNC_SF_32:
                            case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
                            case ZYDIS_MVEX_FUNC_UF_32:
                            case ZYDIS_MVEX_FUNC_DF_32:
                            case ZYDIS_MVEX_FUNC_SI_32:
                            case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
                            case ZYDIS_MVEX_FUNC_UI_32:
                            case ZYDIS_MVEX_FUNC_DI_32:
                                allowed_mem_size = 64;
                                element_size = 4;
                                break;
                            case ZYDIS_MVEX_FUNC_SF_64:
                            case ZYDIS_MVEX_FUNC_UF_64:
                            case ZYDIS_MVEX_FUNC_DF_64:
                            case ZYDIS_MVEX_FUNC_SI_64:
                            case ZYDIS_MVEX_FUNC_UI_64:
                            case ZYDIS_MVEX_FUNC_DI_64:
                                allowed_mem_size = 64;
                                element_size = 8;
                                break;
                            case ZYDIS_MVEX_FUNC_SF_32_BCST:
                            case ZYDIS_MVEX_FUNC_SI_32_BCST:
                                allowed_mem_size = 32;
                                element_size = 4;
                                break;
                            default:
                                ZYAN_UNREACHABLE;
                            }
                            break;
                        case ZYDIS_CONVERSION_MODE_FLOAT16:
                        case ZYDIS_CONVERSION_MODE_SINT16:
                        case ZYDIS_CONVERSION_MODE_UINT16:
                            allowed_mem_size = 32;
                            element_size = 2;
                            break;
                        case ZYDIS_CONVERSION_MODE_SINT8:
                        case ZYDIS_CONVERSION_MODE_UINT8:
                            allowed_mem_size = 16;
                            element_size = 1;
                            break;
                        default:
                            ZYAN_UNREACHABLE;
                        }
                        ZYAN_ASSERT(!mvex_def->broadcast || !match->request->mvex.broadcast);
                        switch (mvex_def->broadcast)
                        {
                        case ZYDIS_MVEX_STATIC_BROADCAST_NONE:
                            break;
                        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8:
                        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
                            allowed_mem_size = element_size;
                            break;
                        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8:
                        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
                            allowed_mem_size = element_size * 4;
                            break;
                        default:
                            ZYAN_UNREACHABLE;
                        }
                        switch (match->request->mvex.broadcast)
                        {
                        case ZYDIS_BROADCAST_MODE_INVALID:
                            break;
                        case ZYDIS_BROADCAST_MODE_1_TO_8:
                        case ZYDIS_BROADCAST_MODE_1_TO_16:
                            allowed_mem_size = element_size;
                            break;
                        case ZYDIS_BROADCAST_MODE_4_TO_8:
                        case ZYDIS_BROADCAST_MODE_4_TO_16:
                            allowed_mem_size = element_size * 4;
                            break;
                        default:
                            ZYAN_UNREACHABLE;
                        }
                    }
                }
                if (user_op->mem.size != allowed_mem_size)
                {
                    return ZYAN_FALSE;
                }
            }
            else if (match->definition->rex_w)
            {
                match->eosz = 64;
            }
            else if (match->definition->vector_length == ZYDIS_VECTOR_LENGTH_INVALID)
            {
                match->eosz = ZydisGetOperandSizeFromElementSize(match, def_op->size,
                    user_op->mem.size, ZYAN_TRUE);
                if (match->eosz == 0)
                {
                    return ZYAN_FALSE;
                }
            }
            else
            {
                ZYAN_UNREACHABLE;
            }
        }
        else
        {
            if (match->easz != 0)
            {
                if (match->easz != user_op->mem.size)
                {
                    return ZYAN_FALSE;
                }
            }
            else
            {
                switch (user_op->mem.size)
                {
                case 2:
                case 4:
                case 8:
                    match->easz = (ZyanU8)user_op->mem.size << 3;
                    break;
                default:
                    return ZYAN_FALSE;
                }
            }
        }

        ZydisRegisterClass vsib_index_class = ZYDIS_REGCLASS_INVALID;
        ZyanBool is_vsib = ZYAN_TRUE;
        switch (def_op->type)
        {
        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
            vsib_index_class = ZYDIS_REGCLASS_XMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
            vsib_index_class = ZYDIS_REGCLASS_YMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ:
            vsib_index_class = ZYDIS_REGCLASS_ZMM;
            break;
        default:
            is_vsib = ZYAN_FALSE;
            break;
        }
        const ZyanBool is_rip_relative = (user_op->mem.base == ZYDIS_REGISTER_RIP) ||
                                         (user_op->mem.base == ZYDIS_REGISTER_EIP);
        if (is_rip_relative)
        {
            const ZyanBool no_rip_rel = ZYDIS_OPDEF_GET_MEM_HIGH_BIT(match->base_definition->op_rm);
            if (no_rip_rel || ((match->definition->modrm & 7) == 4))
            {
                return ZYAN_FALSE;
            }
        }
        const ZydisRegisterClass reg_base_class = ZydisRegisterGetClass(user_op->mem.base);
        if ((reg_base_class == ZYDIS_REGCLASS_INVALID) &&
            (user_op->mem.base != ZYDIS_REGISTER_NONE))
        {
            return ZYAN_FALSE;
        }
        const ZydisRegisterClass reg_index_class = ZydisRegisterGetClass(user_op->mem.index);
        if ((reg_index_class == ZYDIS_REGCLASS_INVALID) &&
            (user_op->mem.index != ZYDIS_REGISTER_NONE))
        {
            return ZYAN_FALSE;
        }
        if (is_vsib)
        {
            const ZyanU8 mode_width = ZydisGetMachineModeWidth(match->request->machine_mode);
            const ZyanI8 reg_index_id = ZydisRegisterGetId(user_op->mem.index);
            if (((match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) ||
                 (reg_base_class != ZYDIS_REGCLASS_GPR64)) &&
                 (reg_base_class != ZYDIS_REGCLASS_GPR32) &&
                 (reg_base_class != ZYDIS_REGCLASS_INVALID))
            {
                return ZYAN_FALSE;
            }
            if ((reg_base_class == ZYDIS_REGCLASS_GPR32) &&
                (mode_width != 64) &&
                (ZydisRegisterGetId(user_op->mem.base) > 7))
            {
                return ZYAN_FALSE;
            }
            ZyanU8 max_reg_id = 7;
            if (mode_width == 64)
            {
                max_reg_id = match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_VEX ?
                    31 : 15;
            }
            if ((reg_index_class != vsib_index_class) ||
                (reg_index_id > max_reg_id))
            {
                return ZYAN_FALSE;
            }
        }
        else
        {
            if (!ZydisIsValidAddressingClass(match, reg_base_class, user_op->mem.base))
            {
                if (!is_rip_relative || match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
                {
                    return ZYAN_FALSE;
                }
            }
            if (!ZydisIsValidAddressingClass(match, reg_index_class, user_op->mem.index))
            {
                return ZYAN_FALSE;
            }
            if (reg_base_class != ZYDIS_REGCLASS_INVALID &&
                reg_index_class != ZYDIS_REGCLASS_INVALID &&
                reg_base_class != reg_index_class)
            {
                return ZYAN_FALSE;
            }
            if (user_op->mem.index == ZYDIS_REGISTER_ESP ||
                user_op->mem.index == ZYDIS_REGISTER_RSP)
            {
                return ZYAN_FALSE;
            }
        }
        if (reg_index_class != ZYDIS_REGCLASS_INVALID &&
            user_op->mem.scale == 0 &&
            def_op->type != ZYDIS_SEMANTIC_OPTYPE_MIB)
        {
            return ZYAN_FALSE;
        }
        if (reg_index_class == ZYDIS_REGCLASS_INVALID &&
            user_op->mem.scale != 0)
        {
            return ZYAN_FALSE;
        }
        ZyanU8 candidate_easz = 0;
        ZyanBool disp_only = ZYAN_FALSE;
        if (reg_base_class != ZYDIS_REGCLASS_INVALID)
        {
            if (is_rip_relative)
            {
                candidate_easz = user_op->mem.base == ZYDIS_REGISTER_RIP ? 64 : 32;
            }
            else
            {
                candidate_easz = (ZyanU8)ZydisRegisterClassGetWidth(match->request->machine_mode,
                    reg_base_class);
            }
        }
        else if (reg_index_class != ZYDIS_REGCLASS_INVALID)
        {
            if (is_vsib)
            {
                candidate_easz = ZydisGetMachineModeWidth(match->request->machine_mode);
            }
            else
            {
                candidate_easz = (ZyanU8)ZydisRegisterClassGetWidth(match->request->machine_mode,
                    reg_index_class);
            }
        }
        else if (disp_size != 8 || !match->cd8_scale)
        {
            const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request);
            if (disp_size > addr_size)
            {
                return ZYAN_FALSE;
            }
            ZyanU8 min_disp_size = match->easz ? match->easz : 16;
            if (((min_disp_size == 16) && !(match->definition->address_sizes & ZYDIS_WIDTH_16)) ||
                 (min_disp_size == 64) ||
                 (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
            {
                min_disp_size = 32;
            }
            if (disp_size < min_disp_size)
            {
                disp_size = min_disp_size;
            }
            const ZyanI64 disp = user_op->mem.displacement;
            if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
            {
                candidate_easz = addr_size;
                if (addr_size == 32 && disp >= 0 && match->easz != 32)
                {
                    candidate_easz = 64;
                }
            }
            else
            {
                const ZyanU64 uimm = disp & (~(0xFFFFFFFFFFFFFFFFULL << (addr_size - 1) << 1));
                if (disp_size < addr_size && ZydisGetUnsignedImmSize(uimm) > disp_size)
                {
                    disp_size = addr_size;
                }
                candidate_easz = disp_size;
            }
            disp_only = ZYAN_TRUE;
        }
        if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
        {
            if (is_rip_relative && reg_index_class != ZYDIS_REGCLASS_INVALID)
            {
                return ZYAN_FALSE;
            }
        }
        else
        {
            if (candidate_easz == 16 && !disp_only)
            {
                if (disp_size > 16)
                {
                    return ZYAN_FALSE;
                }
                const ZyanI8 rm16 = ZydisGetRm16(user_op->mem.base, user_op->mem.index);
                if (rm16 == -1)
                {
                    return ZYAN_FALSE;
                }
                const ZyanU8 allowed_scale = rm16 < 4 ? 1 : 0;
                if (user_op->mem.scale != allowed_scale)
                {
                    return ZYAN_FALSE;
                }
            }
        }
        if (match->easz != 0)
        {
            if (match->easz != candidate_easz)
            {
                return ZYAN_FALSE;
            }
        }
        else
        {
            match->easz = candidate_easz;
        }
        if ((match->base_definition->address_size_map == ZYDIS_ADSIZE_MAP_IGNORED) &&
            (match->easz != ZydisGetMachineModeWidth(match->request->machine_mode)))
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=99 G=96

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.