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

Code before:
    // but not always. For example, for imm = 0x739B'8000'FC80'05F4,
    // the larger add offset (0xFC80'05F4) produces a 5-instruction sequence,
    // while the smaller subtract offset (0x037F'FA0C) produces 8 instructions.

    // STEP 1: Determine x & y

    int x;
    int y;
    if (((uint64_t)imm >> 63) & 0b1)
    {
        // last one position from MSB
        y = 63 - BitOperations::LeadingZeroCount((uint64_t)~imm) + 1;
    }
    else
    {
        // last zero position from MSB
        y = 63 - BitOperations::LeadingZeroCount((uint64_t)imm) + 1;
    }
    if (imm & 0b1)
    {
        // first zero position from LSB
        x = BitOperations::TrailingZeroCount((uint64_t)~imm);
    }
    else
    {
        // first one position from LSB
        x = BitOperations::TrailingZeroCount((uint64_t)imm);
    }

    // STEP 2: Determine whether to utilize SRLI or not.

    // SRLI can be utilized when the input has the following pattern:
    //
    // 0...01...10...x
    // <-n-><-m->
    //
    // It will emit instructions to load the left shifted immediate then
    // followed by a single SRLI instruction.
    //
    // Since it adds 1 instruction, loading the new form should at least remove
    // two instruction. Two instructions can be removed IF:
    //  (1) y - x > 31, AND
    //  one of:
    //      (2) (b - a) < 32
    //      (3) (y - x) - (b - a) >= 11
    //  -> (1) && ( (2) || (3) )
    //
    // Visualization aid:
    // - Original immediate
    //   0...01...10...x
    //       y       <-x

Review comment (performance):
If you're looking to optimize this routine, this is a low-hanging fruit -- we currently don't use all 12 bits of `addi`.

Code after:
//    The immediate is constructed using a combination of LUI/ADDIW for the high
//    32 bits and SLLI/ADDI for the offset, unless the required instruction count
//    exceeds five, in which case the function falls back to "emitDataConst".
//    When materializing the offset, the emitter heuristically selects between
//    add mode and subtract mode to minimize the instruction count.
//
template <bool doEmit>
int emitter::emitLoadImmediate(emitAttr size, regNumber reg, ssize_t imm)
{
    assert(!EA_IS_RELOC(size));
    assert(!doEmit || isGeneralRegister(reg));

    if (isValidSimm12(imm))
    {
        if (doEmit)
        {
            emitIns_R_R_I(INS_addi, size, reg, REG_R0, imm & 0xFFF);
        }
        return 1;
    }

    // The following algorithm works based on the following equation:
    // `imm = high32 + offset1` OR `imm = high32 - offset2`
    //
    // high32 will be loaded with `lui + addiw`, while offset
    // will be loaded with `slli + addi` in 11-bits chunks
    //
    // First, determine at which position to partition imm into high32 and offset,
    // so that it yields the least instruction.
    // Where high32 = imm[y:x] and imm[63:y] are all zeroes or all ones.
    //
    // From the above equation, the value of offset1 & offset2 are:
    // -> offset1 = imm[x-1:0]
    // -> offset2 = ~(imm[x-1:0] - 1)
    // The smaller offset is likely to yield fewer instructions,
    // but not always. For example, for imm = 0x739B'8000'FC80'05F4,
    // the larger add offset (0xFC80'05F4) produces a 5-instruction sequence,
    // while the smaller subtract offset (0x037F'FA0C) produces 8 instructions.

    // STEP 1: Determine x & y

    int x;
    int y;
    if (((uint64_t)imm >> 63) & 0b1)
    {
        // last one position from MSB
        y = 63 - BitOperations::LeadingZeroCount((uint64_t)~imm) + 1;
    }
    else
    {
        // last zero position from MSB