Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

Report SIMD intrinsics to RyuJIT#3678

Merged
MichalStrehovsky merged 7 commits intodotnet:masterfrom
MichalStrehovsky:simd
Jun 1, 2017
Merged

Report SIMD intrinsics to RyuJIT#3678
MichalStrehovsky merged 7 commits intodotnet:masterfrom
MichalStrehovsky:simd

Conversation

@MichalStrehovsky
Copy link
Member

  • Implement isInSIMDModule
  • Implement appendClassName
  • Implement a type name formatter that roughly approximates
    typestring.cpp in the CLR. Should be enough for the purposes of
    recognizing SIMD intrinsics. Hopefully, we won't ever have to be
    complete. This is the formatter used by reflection - the rules are
    complex and long.

* Implement `isInSIMDModule`
* Implement `appendClassName`
* Implement a type name formatter that roughly approximates
typestring.cpp in the CLR. Should be enough for the purposes of
recognizing SIMD intrinsics. Hopefully, we won't ever have to be
complete. This is the formatter used by reflection - the rules are
complex and long.
@jkotas
Copy link
Member

jkotas commented May 23, 2017

Do we also need to adjust the size of Vector<T> accordingly, or are we getting lucky?

(Look for https://github.com/dotnet/coreclr/search?q=getMaxIntrinsicSIMDVectorLength in CoreCLR.)

@MichalStrehovsky
Copy link
Member Author

Do we also need to adjust the size of Vector<T> accordingly, or are we getting lucky?

Without AVX, the size in IL (16) matches the size used by RyuJIT. But I made the changes to also support AVX in the future (once we make RyuJIT stop conditioning it on conditions that might make sense for a JIT, but don't make sense for an AOT compiler).

Instead of CompilerTypeSystemContext calling back into RyuJIT to determine sizes of things, I'm guarding this with asserts. I don't think we should have a RyuJitTypeSystemContext or a set of weird callbacks between Compilation and CompilerTypeSystemContext. The native vector sizes should be specified by the driver, not by the codegen in an AOT compiler.

I don't particularly like how ingrained Vector<T> became into the type system, but I guess there's no way around it. We might also want to make it a WellKnownType, actually, to make checking for it cheaper...

Cc @davidwrighton

{
// We support enough of this to make SIMD work, but not much else.

// TODO: figure out why the marshalling for fFullInst and fAssembly is wrong.
Copy link
Member Author

Choose a reason for hiding this comment

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

This kinda looks like a bug in marshalling. I couldn't figure out what's wrong with the signature. Suggestions welcome.

Copy link
Member

Choose a reason for hiding this comment

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

Should be UnmanagedType.Bool from what I can see.

Copy link
Member Author

Choose a reason for hiding this comment

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

Found the culprit: the generated jitinterface.h we use as the wrapper declares this method as int (__stdcall * appendClassName)(void * thisHandle, CorInfoException** ppException, wchar_t** ppBuf, int* pnBufLen, void* cls, bool fNamespace, bool fFullInst, bool fAssembly);. There's a bool/BOOL mismatch.

We need to either fix the generated wrapper code, or our mashalling annotations. Probably former rather than the latter.

Either way, out of scope of this pull request.

Jit * pJit,
CORJIT_FLAGS flags)
{
// BUGBUG: the signature on the Jit side is actually "pass by value", but for reasons that escape me,
Copy link
Member Author

Choose a reason for hiding this comment

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

Again, couldn't figure out why the ABI doesn't match. The flags that come from the managed side look alright in the debugger, but become broken on the RyuJIT side. Of course it can't be checked in like this, but I already spent too much time on this and need a fresh pair of eyes to have a look.

Copy link
Member

Choose a reason for hiding this comment

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

This may have to do with different calling convention for Plain-Old-Datatype structs vs. C++ structs. Does it change if you add constructor to CORJIT_FLAGS ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding a copy constructor did the trick. Thanks!


namespace Internal.TypeSystem
{
// Extension to TargetDetails related to code generation
Copy link
Member Author

Choose a reason for hiding this comment

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

We might want to kick things like the Abi to this flavor of TargetDetails too.


public MaximumSimdVectorLength MaximumSimdVectorLength
{
get;
Copy link
Member Author

Choose a reason for hiding this comment

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

Now that I had a chance to think about this a little on the way to get lunch: would we just want to introduce this as a TargetArchitecture flavor? E.g. TargetArchitecture.x64, TargetArchitecture.x64_Avx, with a IsX64 convenience property on TargetDetails? (Similar for other arches, in the future.) Yes, it feels weird to put instruction set details on a type system object, but as we see here, this does affect type layout, and it is a type system concern.

Copy link
Member

Choose a reason for hiding this comment

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

I don't really like that idea. Its very much readable to have a switch case arrangement around use of target architecture, and while it doesn't cover all cases, its pretty good. Forcing the use of a series of helper functions is a bit of a kludge.

Copy link
Member

@davidwrighton davidwrighton left a comment

Choose a reason for hiding this comment

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

Looks basically good, but please fix or at the very least understand the marshaling issues before checking in.


public MaximumSimdVectorLength MaximumSimdVectorLength
{
get;
Copy link
Member

Choose a reason for hiding this comment

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

I don't really like that idea. Its very much readable to have a switch case arrangement around use of target architecture, and while it doesn't cover all cases, its pretty good. Forcing the use of a series of helper functions is a bit of a kludge.

None,
VectorLength16,
VectorLength32,
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't like these enum names. What does the 16 or 32 refer to? Bytes? Bits? Elements? In general, I've seen vectors named based on bit length more than on byte length. (For instance, AVX512) I'd prefer something like Vector64Bit

{
// We support enough of this to make SIMD work, but not much else.

// TODO: figure out why the marshalling for fFullInst and fAssembly is wrong.
Copy link
Member

Choose a reason for hiding this comment

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

Should be UnmanagedType.Bool from what I can see.

Only stomp over the field size and byte count for maximum CLR compat.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants