Repository: dotnet/runtime
File: src/coreclr/jit/emitwasm.cpp (C++)

Code before:
    // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
    return (x * 37) >> 8;
}

unsigned SizeOfSLEB128(int64_t value)
{
    // The same as SizeOfULEB128 calculation but we have to account for the sign bit.
    unsigned x = 1 + 6 + 64 - (unsigned)BitOperations::LeadingZeroCount((uint64_t)(value ^ (value >> 63)) | 1UL);
    return (x * 37) >> 8;
}

unsigned emitter::instrDesc::idCodeSize() const
{
#ifdef TARGET_WASM32
    static const unsigned PADDED_RELOC_SIZE = 5;
#else
#error WASM64
#endif

    // Currently, all our instructions have 1 byte opcode.
    unsigned size = 1;
    assert(FitsIn<uint8_t>(GetInsOpcode(idIns())));
    switch (idInsFmt())
    {
        case IF_NONE:
            return 0;
        case IF_OPCODE:
            break;
        case IF_BLOCK:
            size += 1;
            break;
        case IF_LABEL:
            assert(!idIsCnsReloc());
            size = SizeOfULEB128(emitGetInsSC(this));
            break;
        case IF_ULEB128:
            size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this));
            break;
        case IF_SLEB128:
            size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfSLEB128(emitGetInsSC(this));
            break;
        case IF_F32:
            size += 4;
            break;
        case IF_F64:
            size += 8;
            break;
        case IF_MEMARG:
        {
            uint64_t align = 0; // FIXME
            assert(align < 64); // spec says align > 2^6 produces a memidx for multiple memories.

Review comment (suggestion):
```suggestion
```
We should never produce this kind of instrDesc.

Code after:
unsigned emitter::SizeOfULEB128(uint64_t value)
{
    // bits_to_encode = (data != 0) ? 64 - CLZ(x) : 1 = 64 - CLZ(data | 1)
    // bytes = ceil(bits_to_encode / 7.0);            = (6 + bits_to_encode) / 7
    unsigned x = 6 + 64 - (unsigned)BitOperations::LeadingZeroCount(value | 1UL);
    // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7).
    // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
    return (x * 37) >> 8;
}

unsigned emitter::SizeOfSLEB128(int64_t value)
{
    // The same as SizeOfULEB128 calculation but we have to account for the sign bit.
    unsigned x = 1 + 6 + 64 - (unsigned)BitOperations::LeadingZeroCount((uint64_t)(value ^ (value >> 63)) | 1UL);
    return (x * 37) >> 8;
}

unsigned emitter::instrDesc::idCodeSize() const
{
#ifdef TARGET_WASM32
    static const unsigned PADDED_RELOC_SIZE = 5;
#else
#error WASM64
#endif

    // Currently, all our instructions have 1 byte opcode.
    unsigned size = 1;
    assert(FitsIn<uint8_t>(GetInsOpcode(idIns())));
    switch (idInsFmt())
    {
        case IF_OPCODE:
            break;
        case IF_BLOCK:
            size += 1;
            break;
        case IF_LABEL:
            assert(!idIsCnsReloc());
            size = SizeOfULEB128(emitGetInsSC(this));
            break;
        case IF_ULEB128:
            size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this));
            break;
        case IF_SLEB128:
            size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfSLEB128(emitGetInsSC(this));
            break;
        case IF_F32:
            size += 4;
            break;
        case IF_F64:
            size += 8;
            break;