Update intrinsics doc based on recent discussions#28
Conversation
|
@eerhardt @fiigii @sdmaclea @tannergooding @mikedn @4creators @terrajobst @russellhadley Also, please ping anyone else I should have included. |
| 1. A platform intrinsic should expose a specific feature or semantic that is not universally available on all platforms, and for which the implemented function is not easily recognizable by the JIT. | ||
| * If the functionality is common and performant - make it platform | ||
| independent. | ||
| independent. |
There was a problem hiding this comment.
I think I commented on this during the initial design as well, but it might be worth extending this section here.
There is some functionality that is common and performant but which, when exposed in a platform independent manner, loses some of the flexibility that makes it not suitable for use in all cases.
I think a good number of the vector intrinsics fall into this category. They are generally available on all architectures we support, are performant, and we exposed general functionality via the System.Numerics.Vector APIs. However, they lost some of their flexibility, required more complex (custom) support in the JIT, etc.
Additionally, even in the case where we know a general purpose API should be exposed for certain functionality and that functionality is generally supported on modern hardware (CRC32, BitOps, etc) there will need to be custom JIT support for the "fast-path". Exposing that custom support in the form of an intrinsic, and then having the general purpose API call the intrinsic, IMO, is the right way to do such APIs as it provides a general purpose API, but also gives direct access for users who may want or require it.
There was a problem hiding this comment.
@tannergooding 's suggestion is consistent with the push back I got for a common crc32 API.
| - On Intel architecture, there are intrinsics that are only available on float vectors in earlier classes, but are offered for a broader range of types in later classes (e.g. Add over 256-bit vectors on AVX vs. AVX2). For these, it makes sense to explicitly declare the supported types. | ||
| - ARM64 intrinsics include comparisons against zero, but they do not support unsigned types. For these, a trivial JIT expansion could be used to enable all the primitive types to be supported. | ||
|
|
||
| In general, it is preferable for a particular instantiated type to not be visible in the API, rather than for the use of an unsupported type to result in a runtime error. |
There was a problem hiding this comment.
The wording on the sentence is a little confusing.
| supported for the current architecture. See [Supporting Generic Intrinsics](#suporting-generic-intrinsics) above. | ||
| * If the intrinsic fails to meet the necessary criteria: | ||
| * If the method is recursive, i.e. `gtIsRecursiveCall()` returns true: | ||
| * If the constraint is one that the JIT must expand in order to support reflection and diagnostic tools (currently only the immediate operand case), it will produce an expanded implementation (e.g. a switchtable of possible immediate values). |
There was a problem hiding this comment.
Is it worthwhile explicitly calling out that a software implementation is undesirable (that is, an implementation that emulates the functionality, rather than a compiler fallback which still ends up executing the target instruction with the given inputs, such as via a switchtable), since it may behave differently/etc?
|
|
||
| Q: Is a software fallback implementation allowed? (Discussed above a bit) | ||
| A: Fallback is allowed but not required. For very low level | ||
| A: Fallback is allowed but not required, except in the immediate operand as described above. For very low level |
There was a problem hiding this comment.
Is there any reason a fallback should be allowed, I can't think of any cases (outside an immediate operand) where some other fallback is needed. All other cases should be able to emit the instruction (even if that is in the recursive call).
There was a problem hiding this comment.
I am with @tannergooding on not allowing software fallback except when required to support tools or reflection
There was a problem hiding this comment.
Also immediate case is a JIT/codegen fallback, not a software fallback. The original doc was talking about a C# fallback.
| A: We're planning to add support for this through Roslyn but haven't | ||
| settled on an implementation yet. Stay tuned. | ||
| Q: If C# adds support for a const qualifier, will this eliminate the need for switchtable expansion in the JIT? | ||
| A: Probably not. While it would improve the usability. |
There was a problem hiding this comment.
Even with C# support, there are other compilers that may not recognize the attribute and indirect calls would still end up with a non-constant value.
There was a problem hiding this comment.
Perhaps it would be a good place to inform about the plans to use analyzers for enforcing constant parameters
| ## Versioning and Partial Implementation | ||
|
|
||
| The platform intrinsics will be versioned with the runtime. New intrinsics can be added within an existing platform class, but all intrinsics declared in the platform class must be implemented in the JIT at the same time that it is exposed in the library. | ||
|
|
There was a problem hiding this comment.
Target Framework was the term @eerhardt recommended.
sdmaclea
left a comment
There was a problem hiding this comment.
- Add comments regarding lack of compile time type safety.
- Add comments regarding PlatformNotSupportedException, TypeNotSupportedException, and ArgumentRangeException being typical/exhaustive set of exceptions
- Add comments regarding use of analyzers.
- Add comments regarding expectation that code using intrinsics will be carefully scrutinized/optimized/profiled by implementors
At high-level intrinsics are methods of
static classes that are marked with the [Intrinsic] attribute.
We are currently using the namespace and/or a recursive implementation in CoreCLR.
throw new NotImplementedException();
We do not use this in any on the C# implementations.
- CoreFX reference uses
throw null; - CoreCLR uses recursive call
- OR CoreCLR uses platform not supported exception.
Note: This example hasn't been implemented yet - thus NotImplementedException
rather than PlatformNotSupportedException. So details could change going
forward.
This could be edited
| 1. A platform intrinsic should expose a specific feature or semantic that is not universally available on all platforms, and for which the implemented function is not easily recognizable by the JIT. | ||
| * If the functionality is common and performant - make it platform | ||
| independent. | ||
| independent. |
There was a problem hiding this comment.
@tannergooding 's suggestion is consistent with the push back I got for a common crc32 API.
| user problem. Stated another way, platform intrinsics add complexity to the | ||
| runtime implementation and language stack so they should help a concrete user | ||
| scenario. | ||
| * If a set of intrinsics are logically associated (e.g. a vector intrinsic that operates over multiple base types), those intrinsics should generally be implemented together, even if only a subset have compelling impact. |
| @@ -14,30 +14,30 @@ consistent, imposes a performance penalty unacceptable to implementors seeking | |||
| maximum app/service throughput. To enable this last bit of performance | |||
There was a problem hiding this comment.
nit: in original, not modified text, Intel is sometimes used without first uppercase letter
I know this was existing, and not part of your change. But can you fix this to be a property Refers to: accepted/platform-intrinsics.md:54 in 9606675. [](commit_id = 9606675, deletion_comment = False) |
|
@CarolEidt - can we get the edits merged sometime soon? |
|
@eerhardt @sdmaclea @4creators @fiigii - I believe that I have incorporated all of the feedback, and have merged the edits. |
No description provided.