Skip to content

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Mar 22, 2025

Closes #79257

And replaces unsafe array access in FormattingHelpers.CountDigits.cs

Example:

nint CountDigits(ulong value)
{
    ReadOnlySpan<byte> log2ToPow10 =
    [
        1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  4,  5,  5,  5,
        6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9,  10, 10, 10,
        10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
        15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20
    ];
    return log2ToPow10[(int)ulong.Log2(value)];
}

Was:

; Assembly listing for method C:CountDigits(ulong):long:this (FullOpts)
       sub      rsp, 40
       or       rdx, 1
       xor      eax, eax
       lzcnt    rax, rdx
       xor      eax, 63
       cmp      eax, 64
       jae      SHORT G_M15126_IG04
       mov      rcx, 0x2058DCA2A08
       movzx    rax, byte  ptr [rax+rcx]
       add      rsp, 40
       ret      
G_M15126_IG04:
       call     CORINFO_HELP_RNGCHKFAIL
       int3     
; Total bytes of code 48

Now:

; Assembly listing for method C:CountDigits(ulong):long (FullOpts)
       or       rcx, 1
       xor      eax, eax
       lzcnt    rax, rcx
       xor      eax, 63
       mov      rcx, 0x2452FB82A08
       movzx    rax, byte  ptr [rax+rcx]
       ret      
; Total bytes of code 29

@ghost ghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 22, 2025
@EgorBo EgorBo marked this pull request as ready for review March 24, 2025 07:35
@Copilot Copilot AI review requested due to automatic review settings March 24, 2025 07:35
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR removes bounds checks and unsafe array access in the Log2-based digit lookup in FormattingHelpers.CountDigits, improving both performance and clarity.

  • Replaces Unsafe.Add pointer arithmetic with direct array indexing for the ulong-based digit lookup.
  • Applies the same change for the uint-based computation using a lookup table.
Files not reviewed (3)
  • src/coreclr/jit/rangecheck.cpp: Language not supported
  • src/coreclr/jit/valuenum.cpp: Language not supported
  • src/coreclr/jit/valuenum.h: Language not supported

@EgorBo
Copy link
Member Author

EgorBo commented Mar 24, 2025

@jakobbotsch @dotnet/jit-contrib PTAL - removes unsafe array access from two places. Just a couple of diffs, but, hopefully, this introduces more convenient helpers to do pattern matching on top of VNs. the GetVNFunc patter is quite verbose

@EgorBo EgorBo requested a review from jakobbotsch March 24, 2025 07:37
Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool monIncreasing DEBUGARG(int indent))
{
assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));
assert(binop->OperIs(GT_ADD, GT_XOR, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: ideally, we should have handled XOR/OR/HWINTRINSIC all separately for GetRange, but it seems that it has no diffs outside of Log2 pattern, so I decided to just do an ad-hoc Log2 matching.

int xorBy;
ValueNum op;
// First, see if it's "X ^ 31" or "X ^ 63".
if (IsVNBinFuncWithConst(vn, VNF_XOR, &op, &xorBy) && ((xorBy == 31) || (xorBy == 63)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This is missing handling for X86Base_BitScanReverse which is used for R2R and NAOT, since LZCNT isn't baseline.

#endif
// Next, see if it's "LZCNT32(X | 1)" or "LZCNT64(X | 1)".
int orBy;
if (IsVNBinFunc(op, lzcntFunc, &op) && IsVNBinFuncWithConst(op, VNF_OR, &op, &orBy) && (orBy == 1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting, that X | 1 isn't required if we know that X != 0, but its probably not necessary to handle.

@xtqqczze
Copy link
Contributor

@MihuBot

@jakobbotsch
Copy link
Member

jakobbotsch commented Mar 25, 2025

@xtqqczze for changes that do not change JIT-EE GUID and with few misses we generally use superpmi-diffs, which has much wider and generally more realistic coverage than PMI based diffs. You can see that @EgorBo linked to those above (press the "Extensions" tab).

Comment on lines +1415 to +1420
bool IsVNBinFunc(ValueNum vn, VNFunc func, ValueNum* op1 = nullptr, ValueNum* op2 = nullptr);

// Returns "true" iff "vn" is a function application of the form "func(op, cns)"
// the cns can be on the left side if the function is commutative.
template <typename T>
bool IsVNBinFuncWithConst(ValueNum vn, VNFunc func, ValueNum* op, T* cns)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Other functions in this class seem to write out Binary in full (e.g. EvalMathFuncBinary above).

Feel free to ignore or address as part of a separate PR.

@stephentoub
Copy link
Member

@EgorBo, can this be merged?

@EgorBo
Copy link
Member Author

EgorBo commented May 29, 2025

@EgorBo, can this be merged?

Yeah, I wanted to generalize the jit part a bit, but I think I'll merge as is, let me check again

@EgorBo
Copy link
Member Author

EgorBo commented May 30, 2025

/ba-g same issue as #116041

@EgorBo EgorBo merged commit a950953 into dotnet:main May 30, 2025
155 of 157 checks passed
@EgorBo EgorBo deleted the fix-log2-bc branch May 30, 2025 15:10
@github-actions github-actions bot locked and limited conversation to collaborators Jun 30, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI reduce-unsafe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: Improve rangecheck for certain binops

5 participants