Skip to content

arm64: Add support for BFI and BFX instruction#123138

Open
jonathandavies-arm wants to merge 18 commits intodotnet:mainfrom
jonathandavies-arm:upstream/co/bitfield-manipulation
Open

arm64: Add support for BFI and BFX instruction#123138
jonathandavies-arm wants to merge 18 commits intodotnet:mainfrom
jonathandavies-arm:upstream/co/bitfield-manipulation

Conversation

@jonathandavies-arm
Copy link
Contributor

This patch adds support for the Arm BFI and BFX instructions. I've added a optimisation in lowering for bit packing and unpacking using each instruction respectively.

BFI

This is used when you pack 2 or more values into an integer. e.g.
return (a & 0xf) | ((b & 0x3) << 4);
This is the node pattern it is looking for

N009 (  9, 12) [000008] -----+-----                         *  OR        int    $103
N003 (  3,  4) [000002] -----+-----                         +--*  AND       int    $100
N001 (  1,  1) [000000] -----+-----                         |  +--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N002 (  1,  2) [000001] -c---+-----                         |  \--*  CNS_INT   int    15 $43
N008 (  5,  7) [000007] -----+-----                         \--*  LSH       int    $102
N006 (  3,  4) [000005] -----+-----                            +--*  AND       int    $101
N004 (  1,  1) [000003] -----+-----                            |  +--*  LCL_VAR   int    V01 arg1         u:1 (last use) $81
N005 (  1,  2) [000004] -c---+-----                            |  \--*  CNS_INT   int    3 $44
N007 (  1,  2) [000006] -c---+-----                            \--*  CNS_INT   int    4 $45

and changes to

     (  9, 12) [000011] -----------                         \--*  BFI       int   
N003 (  3,  4) [000002] -----+-----                            +--*  AND       int    $100
N001 (  1,  1) [000000] -----+-----                            |  +--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N002 (  1,  2) [000001] -c---+-----                            |  \--*  CNS_INT   int    15 $43
N004 (  1,  1) [000003] -----+-----                            \--*  LCL_VAR   int    V01 arg1         u:1 (last use) $81

BFX

When you extract a continuous range of bits from an integer. This is the inverse of above. e.g.
return (x >> 5) & 0x1F;

This is the node pattern it's looking for

N005 (  5,  7) [000004] -----+-----                         \--*  AND       int    $101
N003 (  3,  4) [000002] -----+-----                            +--*  RSH       int    $100
N001 (  1,  1) [000000] -----+-----                            |  +--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80
N002 (  1,  2) [000001] -----+-----                            |  \--*  CNS_INT   int    6 $42
N004 (  1,  2) [000003] -----+-----                            \--*  CNS_INT   int    63 $43

and changes to

     (  5,  7) [000007] -----------                         \--*  BFX       int   
N001 (  1,  1) [000000] -----+-----                            \--*  LCL_VAR   int    V00 arg0         u:1 (last use) $80

@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 13, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jan 13, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@a74nh
Copy link
Contributor

a74nh commented Jan 26, 2026

Spmidiff errors

[05:14:28] ISSUE: <ASSERT> #9081 /Users/runner/work/1/s/src/coreclr/jit/codegenarm64.cpp (5916) - Assertion failed '(lsb + width) <= bitWidth' in 'Microsoft.AspNetCore.Connections.CorrelationIdGenerator+<>c:<GenerateId>b__3_0(System.Span`1[char],long):this' during 'Generate code' (IL size 267; hash 0xbd4b4083; Tier1)

https://helixr1107v0xdeko0k025g8.blob.core.windows.net/dotnet-runtime-refs-pull-123138-merge-73d1af1f3b444777be/linux-arm64-0/1/console.704b2183.log?helixlogtype=result

@jonathandavies-arm
Copy link
Contributor Author

Spmidiff errors

[05:14:28] ISSUE: <ASSERT> #9081 /Users/runner/work/1/s/src/coreclr/jit/codegenarm64.cpp (5916) - Assertion failed '(lsb + width) <= bitWidth' in 'Microsoft.AspNetCore.Connections.CorrelationIdGenerator+<>c:<GenerateId>b__3_0(System.Span`1[char],long):this' during 'Generate code' (IL size 267; hash 0xbd4b4083; Tier1)

https://helixr1107v0xdeko0k025g8.blob.core.windows.net/dotnet-runtime-refs-pull-123138-merge-73d1af1f3b444777be/linux-arm64-0/1/console.704b2183.log?helixlogtype=result

Fixed

@jakobbotsch
Copy link
Member

/azp run runtime-coreclr superpmi-replay

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member

Looks like there are replay failures.

[12:10:56] ISSUE: #367597 D:\a_work\1\s\src\coreclr\jit\gentree.cpp (7036) - Assertion failed 'this->OperIsBinary()' in 'System.Text.Unicode.Utf8Utility:TranscodeToUtf8(ptr,int,ptr,int,byref,byref):int' during 'LSRA allocate' (IL size 1666; hash 0xb2a9635e; FullOpts)

Comment on lines +6902 to +6910
#ifdef TARGET_ARM64
case GT_BFX:
if (operand == this->AsOp()->gtOp1)
{
*pUse = &this->AsOp()->gtOp1;
return true;
}
return false;
#endif
Copy link
Member

Choose a reason for hiding this comment

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

What about GT_BFI?

Copy link
Member

Choose a reason for hiding this comment

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

(Multiple places)

Copy link
Member

Choose a reason for hiding this comment

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

Please double check with another node type like GT_AND that this is being added to all the general utilities.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think in this case the BFI is fine falling into the default case. I can't see any other cases where BFI needs something other than the default.

Comment on lines +224 to +226
GTNODE(BFI , GenTreeBfm ,0,0,GTK_BINOP|GTK_EXOP|DBK_NOTHIR) // Bitfield Insert.
GTNODE(BFIZ , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero.
GTNODE(BFX , GenTreeBfm ,0,0,GTK_UNOP|GTK_EXOP|DBK_NOTHIR) // Bitfield Extract.
Copy link
Member

Choose a reason for hiding this comment

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

I assume bfiz is subsumed by bfi? It might be nice to replace uses of one by the other and confirm that you see no regressions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think BFI and BFIZ aren't similar enough to merge. I also have a another task after this is work to look into more UBFIZ/UBFX opportunities and I'd that would be better with the separate node.

return false;
}

BlockRange().Remove(tree);
Copy link
Member

Choose a reason for hiding this comment

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

The loop above seems to be able to match more nodes than are being removed here. I would expect that to hit asserts -- you remove some of the nodes and those nodes may have operands that you aren't marking as unused values.

Do you have test cases where the loop above matches a large number of nodes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The test case ComposeBits_Pack32Values_Int in Bfi.cs tries to pack 32 values into an int. It converts a lot of the ors into bfi but not all of them. There are several ors at the end. The JitDump of this test case doesn't have any asserts or errors.
ComposeBits_Pack32Values_Int JitDump

Change-Id: I6ed28f62956404fb7d803c20bd3d1f8113996e14
Change-Id: Ib707d9ca89d85e66f7d37ad593a95048f7ff7ced
Change-Id: Ie4d17eabc9710c88927be211863b07d4e2933650
Change-Id: I08b0a2e4515a0fb445f646d545648e180ebdb893
Change-Id: I015989fa1653edf79fb494ec727ca12555389420
Change-Id: I00caf785bfe1fb9ac1a56ea1f13248084200608d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants