Uh oh!
There was an error while loading. Please reload this page.
Consolidate implementation of ExtractBit - #22225
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Change return type to byte
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
grant-d
commented
Jan 28, 2019
OK @tannergooding per your request I have shaken the tree: removed all unused code, and only left the consolidated methods. We can perf-tune those later on. Let me know if that's suitable, I can make any changes needed. |
Uh oh!
There was an error while loading. Please reload this page.
tannergooding
commented
Jan 28, 2019
CC. @GrabYourPitchforks, who I believe was interested in some of this work. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This is adding a bunch of dead methods that are not used from anywhere else in CoreLib (different from previous PRs). We should have the API review discussion first whether these methods are worth adding to public surface. The |
grant-d
commented
Feb 14, 2019
Makes sense, we can wait for api review. |
tannergooding
commented
Feb 14, 2019
I think they are likely useful in the scenario where they can be backed by intrinsics. Whether or not |
jkotas
commented
Feb 14, 2019
I do not think it does today. https://github.com/dotnet/coreclr/issues/11471#issue-227453324 tracks it (look for |
jkotas
commented
Feb 14, 2019
If they are useful, they should be handled as peephole optimization. All code out there is using the idiomatic pattern today, and we should not be asking all of it to be rewritten to do something else to run well. |
grant-d
commented
Feb 14, 2019
OK, closing this PR pending API review |
tannergooding
commented
Feb 14, 2019
I was suggesting that it might be beneficial to both recognize the code pattern and have a standard API for it. Much like |
I agree with that: the callsites I updated in the previous PRs are more self documenting, especially where operator-heavy code is present, like inline
This also opens the door to analysis - we can then directly measure how many callers use (say) |
jkotas
commented
Feb 15, 2019
The difference is that the idiomatic pattern for Rotate is not a simple code. The idiomatic pattern for bit test is compact code (ie the method won't save you much typing). |
tannergooding
commented
Feb 15, 2019
Right, but the point of the method isn't to save on typing. It is to provide clarity in the code. |
jkotas
commented
Feb 15, 2019
It is matter of personal preference. I do not think I have ever created/used There are ~500 occurrences of |
mikedn
commented
Feb 15, 2019
The JIT generates BT for a while now. It could generate BTS & co. from code like As such, it's probably more useful to make the JIT use SHLX/SHRX/SARX instead of the traditional shift instructions when available, these are efficient on both AMD and Intel and cover more scenarios. BTS & co. might still be useful for its "test and set" capability as that saves an additional instruction. But that's more difficult to recognize in the JIT. Perhaps an intrinsic would be useful, though still not extraordinarily valuable. |
Here's an example where I personally believe the utility methods make the code more self-documenting and simpler to digest. In publicboolthis[intperEventSourceSessionId]{get{returnBitOps.ExtractBit(m_mask,perEventSourceSessionId);//return (m_mask & (1 << perEventSourceSessionId)) != 0;}set{if(value)m_mask=BitOps.InsertBit(m_mask,perEventSourceSessionId);//m_mask |= ((uint)1 << perEventSourceSessionId);elsem_mask=BitOps.ClearBit(m_mask,perEventSourceSessionId);//m_mask &= ~((uint)1 << perEventSourceSessionId);// Or, even better, a one-linerBitOps.WriteBit(refm_mask,perEventSourceSessionId,value);}}In publicboolthis[intindex1,intindex2]{get{Debug.Assert(index1<_bits.Length&&index2<_bits.Length,"Index out of range.");return(_bits[index1]&((ulong)1<<index2))!=0;}set{Debug.Assert(index1<_bits.Length&&index2<_bits.Length,"Index out of range.");if(value==true){_bits[index1]|=(ulong)1<<index2;}else{_bits[index1]&=~((ulong)1<<index2);}}} |
[Edited]
It's hard to figure out a narrow search phrase for all these methods, but here's some I came across: In privatestaticboolIsWordSeparator(UnicodeCategorycategory){return(c_wordSeparatorMask&(1<<(int)category))!=0;}In privateboolInAttributeActiveState{get{
#if DEBUGDebug.Assert(0==(AttributeActiveStates&(1<<(int)State.Initial)));Debug.Assert(0!=(AttributeActiveStates&(1<<(int)State.Interactive)));// elided 9 more, which ~might be easier understood as:Debug.Assert(BitOps.ExtractBit(AttributeActiveStates,(int)State.Interactive));
#endif
return0!=(AttributeActiveStates&(1<<(int)_state));}}In privatestaticboolIsTextualNode(XmlNodeTypenodeType){return0!=(s_isTextualNodeBitmap&(1<<(int)nodeType));}In publicboolMatchesPattern(OptimizerPatternNamepattern){Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName),pattern));return(_patterns&(1<<(int)pattern))!=0;}In publicoverrideboolIsFiltered(XPathNavigatornavigator){return((1<<(int)navigator.NodeType)&_mask)==0;}In privatestaticboolCanPrimitiveWiden(Typesource,Typetarget){PrimitiveswiderCodes=s_primitiveConversions[(int)(Type.GetTypeCode(source))];PrimitivestargetCode=(Primitives)(1<<(int)(Type.GetTypeCode(target)));return0!=(widerCodes&targetCode);}In privatevoidSetFlagToAddListSeparatorBeforeNextItem(){// Surprising this is not manually inlined, but it supports the point about helpers_currentDepth|=1<<31;}2 more in Roslyn |
jkotas
commented
Feb 15, 2019
What's interesting about these examples is that there are no two helpers that are the same. Everybody customizes them for their usage pattern. Here are the variations from these 4 examples. |
[Edited - also edited previous message, added more inline examples]
However, it does support there being a use-case for helpers - devs don't always want to inline the algebra. For reference, here's the original PR signatures: // Overloads exist for byte|uint|intpublicstaticboolExtractBit(bytevalue,intbitOffset);// Used in SessionMask example abovepublicstaticboolWriteBit(refbytevalue,intbitOffset,boolon);// Used in SessionMaskpublicstaticbyteWriteBit(bytevalue,intbitOffset,boolon);publicstaticboolInsertBit(refbytevalue,intbitOffset);publicstaticbyteInsertBit(bytevalue,intbitOffset);// Used in SessionMask// ClearBit, ComplementBit similar |
jkotas
commented
Feb 15, 2019
When majority of cases do inline the algebra, is it worth having an API for small minority of cases in the framework? It feels similar to the situation with "throw helpers". Majority of code throws exceptions directly. Some folks like to have helper methods for throwing exceptions, but there is a lot of variety, styles and trade-offs. We had API suggestions for introducing a helper methods for this in the framework (like https://github.com/dotnet/corefx/issues/17068). None of them made it because of the use case is not significant enough, and it is easy enough for folks who likes to have these to have their own local copy that they like. |
Fair point, I agree with you on throw helpers. // Devs would likely need to unit this one to make sure it's rightpublicstaticuintComplementBit(uintvalue,intbitOffset)=>~(~(1u<<bitOffset)^value);// Easy once you know the idiom but at a glance it certainly doesn't say `BTR`publicstaticuintClearBit(uintvalue,intbitOffset)=>value&~(1u<<bitOffset);// True BTR behavior, ie returns original valuepublicstaticboolClearBit(refuintvalue,intbitOffset){uintmask=1u<<bitOffset;boolbtr=(value&mask)!=0;value&=~mask;returnbtr;} |
NickStrupat
commented
Sep 11, 2019
@grant-d Hi Grant, I'm hunting for the latest version of your |
|
@benaadams ah yes, thanks! I saw that the other day, but I'm looking for the unapproved ones like I'm working on a |
grant-d
commented
Sep 11, 2019
This might also help: |
ExtractBit, InsertBit, ClearBit
[Edited]
This is intended to be the last PR in this series (LZCNT, LOG2, TZCNT, ROTL, POPCNT)
Previously, all the above changes were in this PR; I decided to split them into separate PRs to make CR easier.
This PR is now repurposed to focus on the final set of changes.
There are several implementations of
ExtractBit,InsertBit,Clearbitin the stack.BitOpsmethods pass unitsThe benefits here are:
All known callers only use
byte,intoruintarguments.We may decide to add
long,ulongfor consistency.The know callers are mostly downstream (also see review comments):
cc @tannergooding, @jkotas