Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow more than 64 ISA flags for jit interface. #73965

Merged
merged 1 commit into from
Aug 24, 2022

Conversation

DeepakRajendrakumaran
Copy link
Contributor

Currently since _flags is a 64 bit variable, only 64 ISAs can be represented using this design. This change makes this an array thus enabling us to represent more than 64 ISAs.

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 15, 2022
@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Aug 15, 2022
@ghost
Copy link

ghost commented Aug 15, 2022

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

Issue Details

Currently since _flags is a 64 bit variable, only 64 ISAs can be represented using this design. This change makes this an array thus enabling us to represent more than 64 ISAs.

Author: DeepakRajendrakumaran
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@DeepakRajendrakumaran
Copy link
Contributor Author

@tannergooding
Copy link
Member

CC. @davidwrighton and @dotnet/crossgen-contrib

This needs review and sign-off to ensure this doesn't negatively impact the CG2 scenarios. Please call out any other outerloop validation that should be done as well.

public:
static const int FlagsArrSize = 1;
Copy link
Member

Choose a reason for hiding this comment

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

Move this up to the beginning of the struct and use it in the definition of _flags?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, will move FlagsArrSize . It is currently used for definition of _flags but I'm using the actual calculated value instead of the variable since we know at the time of generating this file what the value is. But I don't see a problem with switching to var as you suggested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Slight correction here - the reason FlagsArrSize is currently public is because it's used from compiler.h. I see that you have another comment there. Will address that first before changing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

src/coreclr/inc/corinfoinstructionset.h Outdated Show resolved Hide resolved
@@ -8966,19 +8973,23 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
JitFlags* jitFlags; // all flags passed from the EE

// The instruction sets that the compiler is allowed to emit.
uint64_t compSupportsISA;
uint64_t compSupportsISA[CORINFO_InstructionSetFlags::FlagsArrSize];
Copy link
Member

Choose a reason for hiding this comment

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

Is there any reason we cannot use CORINFO_InstructionSetFlags here and avoid all this manual bit fiddling when setting/getting members?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean have this as following and use the CORINFO_InstructionSetFlags methods to do the manipulation?

    CORINFO_InstructionSetFlags compSupportsISA;
    ..........................
    CORINFO_InstructionSetFlags compSupportsISAReported;
    ........................
    CORINFO_InstructionSetFlags compSupportsISAExactly;

Copy link
Member

Choose a reason for hiding this comment

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

Yep, exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it! Changed

Comment on lines 244 to 245
private static int _flagsArrSize = 1;
private fixed ulong _flags[1];
Copy link
Member

Choose a reason for hiding this comment

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

Seems this can use a const too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

I don't have any specific suggestions in addition to @jakobbotsch .

I'd like to see if we can reduce the number of uses of the "Raw" APIs, but that's for a follow-up.

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 17, 2022
_flags = _flags | (((uint64_t)1) << instructionSet);
int arrayIdx = instructionSet / 64;
int bit = instructionSet % 64;
_flags[arrayIdx] = _flags[arrayIdx] | (((uint64_t)1) << bit);
Copy link
Member

Choose a reason for hiding this comment

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

nit: use |= ?

Suggested change
_flags[arrayIdx] = _flags[arrayIdx] | (((uint64_t)1) << bit);
_flags[arrayIdx] |= ((uint64_t)1) << bit;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

_flags = _flags & ~(((uint64_t)1) << instructionSet);
int arrayIdx = instructionSet / 64;
int bit = instructionSet % 64;
_flags[arrayIdx] = _flags[arrayIdx] & ~(((uint64_t)1) << bit);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_flags[arrayIdx] = _flags[arrayIdx] & ~(((uint64_t)1) << bit);
_flags[arrayIdx] &= ~(((uint64_t)1) << bit);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 17, 2022
Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

This LGTM. It'd like @davidwrighton to take a look at the AOT side.

@BruceForstall
Copy link
Member

BTW, is it reasonable to convert this from a "Draft" to a "normal" PR? Normally, I think of "Draft" as something that is not ready to be reviewed.

@DeepakRajendrakumaran DeepakRajendrakumaran marked this pull request as ready for review August 17, 2022 23:24
@DeepakRajendrakumaran
Copy link
Contributor Author

BTW, is it reasonable to convert this from a "Draft" to a "normal" PR? Normally, I think of "Draft" as something that is not ready to be reviewed.

Yes, this is ready to be reviewed and I've taken out the 'draft' tag. Will keep this in mind for newer PRs(i.e., tagging as draft initially to see test run results and if it broke something unexpected and then removing 'draft' tag once it looks good)

public void AddInstructionSet(InstructionSet instructionSet)
{
_flags = _flags | (((ulong)1) << (int)instructionSet);
int arrayIdx = (int)instructionSet / 64;
Copy link
Member

Choose a reason for hiding this comment

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

It is better to use uint in this pattern. Signed division is less efficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah. Good catch- it's a power of 2 division. Changed

Comment on lines 269 to 280
uint64_t* GetFlagsRaw()
{
return _flags;
}

void SetFromFlagsRaw(uint64_t flags)
void SetFromFlagsRaw(uint64_t* flags)
{
_flags = flags;
for (int i = 0; i < FlagsArrSize; i++)
{
_flags[i] = flags[i];
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Do we want/need to still allow getting the raw flags? I think we could just return and enforce usage of CORINFO_InstructionSetFlags instead.

It looks like the "raw" APIs are really only used from class CORJIT_FLAGS and setSupportedISAs which normally abstracts away the underlying CORINFO_InstructionSetFlags.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed that it makes sense to remove the SetFromFlagsRaw but GetFlagsRaw is used from SuperPMI(see changes in src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp). I might be missing something here but I am not sure how I can work around that.

@JulieLeeMSFT JulieLeeMSFT added this to the 8.0.0 milestone Aug 18, 2022
@BruceForstall
Copy link
Member

@DeepakRajendrakumaran Can you fix the JIT formatting? (See the "Formatting" job failures)

Also, there are some SuperPMI asm diffs:

https://dev.azure.com/dnceng/public/_build/results?buildId=1952690&view=ms.vss-build-web.run-extensions-tab

I would expect this change to not have any asm diffs. Agreed?

@DeepakRajendrakumaran
Copy link
Contributor Author

@DeepakRajendrakumaran Can you fix the JIT formatting? (See the "Formatting" job failures)

Also, there are some SuperPMI asm diffs:

https://dev.azure.com/dnceng/public/_build/results?buildId=1952690&view=ms.vss-build-web.run-extensions-tab

I would expect this change to not have any asm diffs. Agreed?

There is a small change in the SuperPMI tool but it ideally shouldn't have any effect as far as I understand. Will check it out.

@BruceForstall
Copy link
Member

Ah, you've changed CORINFO_InstructionSetFlags and thus CORJIT_FLAGS, which is passed across the JIT interface. You should change the JIT-EE GUID in jiteeversionguid.h.

I thought your change wouldn't change data layout so maybe it should "just work" with a SPMI collection with the previous layout, but maybe not?


static uint64_t GetRelativeBitIndex(CORINFO_InstructionSet instructionSet)
{
return ((uint64_t)1) << (instructionSet & 0x3F);
Copy link
Member

Choose a reason for hiding this comment

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

This looks like a bug, since it ignores the top 2 bits

Suggested change
return ((uint64_t)1) << (instructionSet & 0x3F);
uint32_t bitIndex = (uint32_t)instructionSet;
return (uint32_t)(bitIndex % (uint32_t)BitsPerFlagsField);

Copy link
Member

Choose a reason for hiding this comment

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

GetFlagsFieldIndex gets the 64-bit field in which a given instructionSet is tagged (only the bits 6 and higher matter).

GetRelativeBitIndex then gets the bit offset within that field, which can only be 0-63, so 0x3F should be the correct mask.

Copy link
Member

Choose a reason for hiding this comment

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

GetRelativeBitMask might have been a better name, since its not getting the index but rather a mask that only includes the given index.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have changed name to GetRelativeBitMask


private static ulong GetRelativeBitIndex(InstructionSet instructionSet)
{
return ((ulong)1) << ((int)instructionSet & 0x3F);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return ((ulong)1) << ((int)instructionSet & 0x3F);
uint bitIndex = (uint)instructionSet;
return (uint)(bitIndex % (uint)BitsPerFlagsField);


private static ulong GetRelativeBitIndex(InstructionSet instructionSet)
{
return ((ulong)1) << ((int)instructionSet & 0x3F);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return ((ulong)1) << ((int)instructionSet & 0x3F);
uint bitIndex = (uint)instructionSet;
return (uint)(bitIndex % (uint)BitsPerFlagsField);


static uint64_t GetRelativeBitIndex(CORINFO_InstructionSet instructionSet)
{
return ((uint64_t)1) << (instructionSet & 0x3F);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return ((uint64_t)1) << (instructionSet & 0x3F);
uint32_t bitIndex = (uint32_t)instructionSet;
return (uint32_t)(bitIndex % (uint32_t)BitsPerFlagsField);

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 19, 2022
@DeepakRajendrakumaran
Copy link
Contributor Author

CORINFO_InstructionSetFlags

Another question is, right now I'm just copying the struct(CORINFO_InstructionSetFlags ) when I have to. It has an array and an integer as fields now so shouldn't be a problem. Do you think it makes sense to add a copy constructor to explicitly copy the struct content in case some other field gets added in future which possibly causes an issue here or do I just leave it as is?

Refer src/coreclr/jit/jitee.h for example

@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Aug 19, 2022
@DeepakRajendrakumaran
Copy link
Contributor Author

DeepakRajendrakumaran commented Aug 19, 2022

Ah, you've changed CORINFO_InstructionSetFlags and thus CORJIT_FLAGS, which is passed across the JIT interface. You should change the JIT-EE GUID in jiteeversionguid.h.

I thought your change wouldn't change data layout so maybe it should "just work" with a SPMI collection with the previous layout, but maybe not?

Yeah. I didn't excpect any changes. I followed the instruction here(link) and ran the following

superpmi.py asmdiffs -target_os windows -target_arch x64 -arch x64

Users\deepakra\Dotnet\runtime>python src\coreclr\scripts\superpmi.py  asmdiffs -core_root=C:\Users\deepakra\Dotnet\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root -target_os windows -target_arch x64 -arch x64
[15:28:31] ================ Logging to C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\superpmi.2.log
[15:28:31] Using JIT/EE Version from jiteeversionguid.h: 1b9551b8-21f4-4233-9c90-f3eabd6a322b
[15:28:31] Baseline hash: f142128e89b63577a9bbba7e2b760ec82102a7a9
[15:28:31] Using baseline C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\basejit\080f708e7018f6c0529b6c875a44d84fc4d74419.windows.x64.Checked\clrjit.dll
[15:28:31] Using coredistools found at C:\Users\deepakra\Dotnet\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\coredistools.dll
[15:28:31] Found download cache directory "C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64" and --force_download not set; skipping download
[15:28:31] SuperPMI ASM diffs
[15:28:31] Base JIT Path: C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\basejit\080f708e7018f6c0529b6c875a44d84fc4d74419.windows.x64.Checked\clrjit.dll
[15:28:31] Diff JIT Path: C:\Users\deepakra\Dotnet\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\clrjit.dll
[15:28:31] Using MCH files:
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\aspnet.run.windows.x64.checked.mch
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\benchmarks.run.windows.x64.checked.mch
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\coreclr_tests.pmi.windows.x64.checked.mch
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries.crossgen2.windows.x64.checked.mch
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries.pmi.windows.x64.checked.mch
[15:28:31]   C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries_tests.pmi.windows.x64.checked.mch
[15:28:31] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\aspnet.run.windows.x64.checked.mch
[15:29:10] Clean SuperPMI diff (126706 contexts processed)
[15:29:10] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\benchmarks.run.windows.x64.checked.mch
[15:29:25] Clean SuperPMI diff (38864 contexts processed)
[15:29:25] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\coreclr_tests.pmi.windows.x64.checked.mch
[15:31:59] Clean SuperPMI diff (255160 contexts processed)
[15:31:59] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries.crossgen2.windows.x64.checked.mch
[15:32:35] Clean SuperPMI diff (224125 contexts processed)
[15:32:35] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries.pmi.windows.x64.checked.mch
[15:33:37] Clean SuperPMI diff (250246 contexts processed)
[15:33:37] Running asm diffs of C:\Users\deepakra\Dotnet\runtime\artifacts\spmi\mch\1b9551b8-21f4-4233-9c90-f3eabd6a322b.windows.x64\libraries_tests.pmi.windows.x64.checked.mch
[15:35:47] Clean SuperPMI diff (331817 contexts processed)
[15:35:47] Asm diffs summary:
[15:35:47]   No asm diffs

I take the last line No asm diffs to mean that there is no diff

@BruceForstall
Copy link
Member

I take the last line No asm diffs to mean that there is no diff

True. I wonder why the superpmi-diffs jobs showed diffs.

Note that now that you've changed the JIT-EE GUID, you won't be able to run SuperPMI diffs.

python src\coreclr\scripts\superpmi.py asmdiffs -core_root=C:\Users\deepakra\Dotnet\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root -target_os windows -target_arch x64 -arch x64

Normally, I would recommend using a Checked build (just because it's faster).

Also, if you're on a Windows x64 machine, the -target_os / -target_arch / -arch will be defaulted as you've specified.

@DeepakRajendrakumaran
Copy link
Contributor Author

True. I wonder why the superpmi-diffs jobs showed diffs.

Is this something you have seen before with JITInterface changes?(specifically this - No textual differences. Is this an issue with coredistools?)

image

Note that now that you've changed the JIT-EE GUID, you won't be able to run SuperPMI diffs.

This makes it difficult to check the original failures. Is there some way to see the original SuperPMI failures we need to look at/fix? Or do I have to revert this temporarily and get the CI to re-run everything?

@BruceForstall
Copy link
Member

I wonder why the superpmi-diffs jobs showed diffs.

It turns out we realized late last week that our automatic JIT baseline build system wasn't working properly. That should now be fixed. If you rebase on top of current main (and re-push), the system should pick up a current baseline.

Or do I have to revert this temporarily and get the CI to re-run everything?

It might make sense to temporarily revert the JIT-EE version GUID change if you want to re-run testing. Note this will only work if there is no binary difference in the JIT-EE traffic (including the CORFLAGS stuff), which I believe should be the case with your change.

@DeepakRajendrakumaran
Copy link
Contributor Author

It might make sense to temporarily revert the JIT-EE version GUID change if you want to re-run testing. Note this will only work if there is no binary difference in the JIT-EE traffic (including the CORFLAGS stuff), which I believe should be the case with your change.

Yep. It worked. All tests passed. I'll remove the 'revert' commit and change GetRelativeBitIndex to GetRelativeBitMask as per the conversation above.

@jakobbotsch
Copy link
Member

I didn't read the full thread -- is the JIT-EE GUID change still necessary now that we established the diffs were spurious?

@BruceForstall
Copy link
Member

I didn't read the full thread -- is the JIT-EE GUID change still necessary now that we established the diffs were spurious?

It's a fair question. The data representation changed, but at least currently in a binary identical way. When the number of flags is increased, we'll certainly need to change the GUID.

So for now, it's ok not to change the GUID (and not changing it leads to less churn).

@DeepakRajendrakumaran
Copy link
Contributor Author

DeepakRajendrakumaran commented Aug 23, 2022

I didn't read the full thread -- is the JIT-EE GUID change still necessary now that we established the diffs were spurious?

In the GUID file it says

This GUID represents the version of the JIT/EE interface. Any time the interface between the JIT and the EE changes (by adding or removing methods to any interface shared between them), this GUID should be changed. This is the identifier verified by ICorJitCompiler::getVersionIdentifier().

Also from updating-jitinterface.md

The JitInterface is versioned by a GUID. Any change to JitInterface is required to update the JitInterface GUID located in jiteeversionguid.h (look for JITEEVersionIdentifier). Not doing so has consequences that are sometimes hard to debug.

There has been some changes in the interface code. But as you pointed out, no diff changes exist. So, I'll leave it to the reviewers to decide. :)

Edit : Didn't see the reply above when I posted this comment. Will follow the guidance there.

Details:
Previously ISA flags were represented as bits in a 64 bit variable.
This limited the total number of possible ISAs to 64. This change
modifies this and starts using an array of 64 bit vars to store ISA flags.
The main changes are in InstructionSetGenerator.cs. This drives a lot of other
changes in this commit which are generated files.
@BruceForstall
Copy link
Member

CC. @davidwrighton and @dotnet/crossgen-contrib

This needs review and sign-off to ensure this doesn't negatively impact the CG2 scenarios. Please call out any other outerloop validation that should be done as well.

@dotnet/crossgen-contrib @davidwrighton @trylek -- Anyone want to take a look at this JIT-EE interface format change for potential crossgen2 impact?

Copy link
Member

@trylek trylek left a comment

Choose a reason for hiding this comment

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

As no jitinterface changes are part of this PR, I believe our only interaction with the JIT flags is in JitConfigProvider and we seem to be consistently using CorJitFlag arrays to represent them; I believe this change should have zero Crossgen2 impact.

@tannergooding
Copy link
Member

@trylek, are there any concerns with how this will impact crossgen each time we do need to increase the field count?

We are definitely going to need at least 2 fields for the .NET 8 AVX-512 work, so ensuring that this schema will work and work over time without too much additional effort is also important.

Ideally simply changing the FlagsFieldCount and potentially JIT/EE Version GUID should be enough. If there are additional changes needed in such a scenario, such as documenting a R2R metadata format version change, we should ensure its covered in the generation script so its visible as part of the required work anytime this changes.

@trylek
Copy link
Member

trylek commented Aug 24, 2022

@tannergooding - going over the code a second time I have found one place where we still manipulate JIT flags using the uint64 bit mask:

In Crossgen2 its only users seem to be two places that use the IsSet method to check for CORJIT_FLAG_IL_STUB; I'm not sure about its use in NativeAOT, @MichalStrehovsky should know.

To my knowledge today Crossgen2 doesn't support command-line parameters for specifying arbitrary JIT flags, it only uses about a dozen flags that are hard-coded in the source code (a bunch of flags affecting optimizations, instruction sets and the like). From this viewpoint future extensions of Crossgen2 support for JIT flags may be twofold:

  1. Modifying the source code to set additional JIT flags in certain situations. If the developer decides to use the CORJIT_FLAGS struct with a flag with index greater than or equal to 64, they'll need to fix its implementation. Please note that they don't really have to, JitConfigProvider implement a method HasFlag that doesn't have the 64-bit limitation (it searches the array) at the expense of slightly lower performance.

  2. Adding command line support for specifying arbitrary JIT flags, perhaps by using their indices or a hexadecimal bit mask. Its actual implementation may need to further tweak the existing code manipulating JIT flags but likely in a very minimal manner.

@tannergooding
Copy link
Member

@trylek Thanks for the explanation!

To my knowledge today Crossgen2 doesn't support command-line parameters for specifying arbitrary JIT flags, it only uses about a dozen flags that are hard-coded in the source code (a bunch of flags affecting optimizations, instruction sets and the like).

In particular, I was considering the metadata used to track the instruction sets that a given method uses (required vs opportunistic). I believe this is related to the InstructionSetFlags field (rather than the _corJitFlags field):

public InstructionSetFlags InstructionSetFlags;

Extending the number of CORINFO_InstructionSet enum entries beyond 64 means that an additional field is required to track which instruction sets a given method needs and that would in turn impact the R2R metadata version, as far as I'm aware.

@trylek
Copy link
Member

trylek commented Aug 24, 2022

I believe that today implementation of instruction sets uses ReadyToRun fixups, the exact encoding is implemented here:

As you can easily see, it doesn't have the 64-bit limitation as it encodes the individual instruction sets as signature-encoded uints.

You are right that we'd need to revamp the R2R format if we wanted to support multitargeting compilation (where a function could have several implementations compiled for various instruction sets and a suitable version would be picked dynamically at runtime) but that would be a completely new feature so it would require design in any case.

@tannergooding
Copy link
Member

Thanks for confirming. Just wanted to ensure that us going over wasn't going to cause unexpected breakages in R2R due to some missed edge case.

@BruceForstall, I think this is ready to merge then once your "change requested" is resolved.

@BruceForstall BruceForstall merged commit 040c7bd into dotnet:main Aug 24, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Sep 23, 2022
@BruceForstall BruceForstall added the avx512 Related to the AVX-512 architecture label Mar 27, 2023
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 avx512 Related to the AVX-512 architecture 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.

7 participants