-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Hardware instruction set support for crossgen2 #33274
Changes from all commits
ad99cce
b3231bd
79f6040
8427ef9
f3afae3
eff6176
2c1052a
e3bc096
51583ef
923c53b
28e7800
3481eb7
5b09c68
dafa2a2
75d25db
4e73d85
e8d8cae
c505b2c
7347efc
ab4a9bb
4146867
8f763bf
d0eb39d
e011f1b
d6dfaa9
b45ac9b
d0c54ab
c7875f8
93f44a2
8bb2d1c
113173d
c6662ef
e9c19a0
0d7d587
f68ac24
3e998f5
617c2ac
670d042
f200242
4138f7c
4814331
0ba367f
e535940
b8e07bc
9feef51
0b8b9f4
f399ccd
67ed9e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -7635,12 +7635,12 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
SIMDLevel getSIMDSupportLevel() | ||||||||||
{ | ||||||||||
#if defined(TARGET_XARCH) | ||||||||||
if (compSupports(InstructionSet_AVX2)) | ||||||||||
if (compOpportunisticallyDependsOn(InstructionSet_AVX2)) | ||||||||||
{ | ||||||||||
return SIMD_AVX2_Supported; | ||||||||||
} | ||||||||||
|
||||||||||
if (compSupports(InstructionSet_SSE42)) | ||||||||||
if (compOpportunisticallyDependsOn(InstructionSet_SSE42)) | ||||||||||
{ | ||||||||||
return SIMD_SSE4_Supported; | ||||||||||
} | ||||||||||
|
@@ -7786,7 +7786,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
unreached(); | ||||||||||
} | ||||||||||
} | ||||||||||
assert(emitTypeSize(simdType) <= maxSIMDStructBytes()); | ||||||||||
assert(emitTypeSize(simdType) <= largestEnregisterableStructSize()); | ||||||||||
switch (simdBaseType) | ||||||||||
{ | ||||||||||
case TYP_FLOAT: | ||||||||||
|
@@ -8032,13 +8032,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
// Whether SIMD vector occupies part of SIMD register. | ||||||||||
// SSE2: vector2f/3f are considered sub register SIMD types. | ||||||||||
// AVX: vector2f, 3f and 4f are all considered sub register SIMD types. | ||||||||||
bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd) | ||||||||||
{ | ||||||||||
unsigned sizeBytes = 0; | ||||||||||
var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes); | ||||||||||
return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength()); | ||||||||||
} | ||||||||||
|
||||||||||
bool isSubRegisterSIMDType(GenTreeSIMD* simdNode) | ||||||||||
{ | ||||||||||
return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength()); | ||||||||||
|
@@ -8055,6 +8048,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
} | ||||||||||
else | ||||||||||
{ | ||||||||||
// Verify and record that AVX2 isn't supported | ||||||||||
compVerifyInstructionSetUnuseable(InstructionSet_AVX2); | ||||||||||
assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported); | ||||||||||
return TYP_SIMD16; | ||||||||||
} | ||||||||||
|
@@ -8095,6 +8090,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
else | ||||||||||
{ | ||||||||||
assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported); | ||||||||||
|
||||||||||
// Verify and record that AVX2 isn't supported | ||||||||||
compVerifyInstructionSetUnuseable(InstructionSet_AVX2); | ||||||||||
return XMM_REGSIZE_BYTES; | ||||||||||
} | ||||||||||
#elif defined(TARGET_ARM64) | ||||||||||
|
@@ -8115,7 +8113,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
unsigned int maxSIMDStructBytes() | ||||||||||
{ | ||||||||||
#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH) | ||||||||||
if (compSupports(InstructionSet_AVX)) | ||||||||||
if (compOpportunisticallyDependsOn(InstructionSet_AVX)) | ||||||||||
{ | ||||||||||
return YMM_REGSIZE_BYTES; | ||||||||||
} | ||||||||||
|
@@ -8128,6 +8126,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
return getSIMDVectorRegisterByteLength(); | ||||||||||
#endif | ||||||||||
} | ||||||||||
|
||||||||||
unsigned int minSIMDStructBytes() | ||||||||||
{ | ||||||||||
return emitTypeSize(TYP_SIMD8); | ||||||||||
|
@@ -8187,14 +8186,40 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
unsigned largestEnregisterableStructSize() | ||||||||||
{ | ||||||||||
#ifdef FEATURE_SIMD | ||||||||||
unsigned vectorRegSize = getSIMDVectorRegisterByteLength(); | ||||||||||
#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH) | ||||||||||
if (opts.IsReadyToRun()) | ||||||||||
{ | ||||||||||
// Return constant instead of maxSIMDStructBytes, as maxSIMDStructBytes performs | ||||||||||
// checks that are effected by the current level of instruction set support would | ||||||||||
// otherwise cause the highest level of instruction set support to be reported to crossgen2. | ||||||||||
// and this api is only ever used as an optimization or assert, so no reporting should | ||||||||||
// ever happen. | ||||||||||
return YMM_REGSIZE_BYTES; | ||||||||||
} | ||||||||||
#endif // defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH) | ||||||||||
unsigned vectorRegSize = maxSIMDStructBytes(); | ||||||||||
assert(vectorRegSize >= TARGET_POINTER_SIZE); | ||||||||||
return vectorRegSize; | ||||||||||
#else // !FEATURE_SIMD | ||||||||||
return TARGET_POINTER_SIZE; | ||||||||||
#endif // !FEATURE_SIMD | ||||||||||
} | ||||||||||
|
||||||||||
// Use to determine if a struct *might* be a SIMD type. As this function only takes a size, many | ||||||||||
// structs will fit the criteria. | ||||||||||
bool structSizeMightRepresentSIMDType(size_t structSize) | ||||||||||
{ | ||||||||||
#ifdef FEATURE_SIMD | ||||||||||
// Do not use maxSIMDStructBytes as that api in R2R on X86 and X64 may notify the JIT | ||||||||||
// about the size of a struct under the assumption that the struct size needs to be recorded. | ||||||||||
// By using largestEnregisterableStructSize here, the detail of whether or not Vector256<T> is | ||||||||||
// enregistered or not will not be messaged to the R2R compiler. | ||||||||||
return (structSize >= minSIMDStructBytes()) && (structSize <= largestEnregisterableStructSize()); | ||||||||||
#else | ||||||||||
return false; | ||||||||||
#endif // FEATURE_SIMD | ||||||||||
} | ||||||||||
|
||||||||||
#ifdef FEATURE_SIMD | ||||||||||
static bool vnEncodesResultTypeForSIMDIntrinsic(SIMDIntrinsicID intrinsicId); | ||||||||||
#endif // !FEATURE_SIMD | ||||||||||
|
@@ -8272,21 +8297,74 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
return false; | ||||||||||
} | ||||||||||
|
||||||||||
bool compSupports(CORINFO_InstructionSet isa) const | ||||||||||
#ifdef DEBUG | ||||||||||
// Answer the question: Is a particular ISA supported? | ||||||||||
// Use this api when asking the question so that future | ||||||||||
// ISA questions can be asked correctly or when asserting | ||||||||||
// support/nonsupport for an instruction set | ||||||||||
bool compIsaSupportedDebugOnly(CORINFO_InstructionSet isa) const | ||||||||||
{ | ||||||||||
#if defined(TARGET_XARCH) || defined(TARGET_ARM64) | ||||||||||
return (opts.compSupportsISA & (1ULL << isa)) != 0; | ||||||||||
#else | ||||||||||
return false; | ||||||||||
#endif | ||||||||||
} | ||||||||||
#endif // DEBUG | ||||||||||
|
||||||||||
void notifyInstructionSetUsage(CORINFO_InstructionSet isa, bool supported) const; | ||||||||||
|
||||||||||
// Answer the question: Is a particular ISA supported? | ||||||||||
// The result of this api call will exactly match the target machine | ||||||||||
// on which the function is executed (except for CoreLib, where there are special rules) | ||||||||||
bool compExactlyDependsOn(CORINFO_InstructionSet isa) const | ||||||||||
{ | ||||||||||
|
||||||||||
#if defined(TARGET_XARCH) || defined(TARGET_ARM64) | ||||||||||
uint64_t isaBit = (1ULL << isa); | ||||||||||
bool isaSupported = (opts.compSupportsISA & (1ULL << isa)) != 0; | ||||||||||
if ((opts.compSupportsISAReported & isaBit) == 0) | ||||||||||
{ | ||||||||||
notifyInstructionSetUsage(isa, isaSupported); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a jitdump here? Eg
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. notifyInstructionSetUsage does a jitdump internally. (All calls to the api are dumped) |
||||||||||
((Compiler*)this)->opts.compSupportsISAReported |= isaBit; | ||||||||||
} | ||||||||||
|
||||||||||
return isaSupported; | ||||||||||
#else | ||||||||||
return false; | ||||||||||
#endif | ||||||||||
} | ||||||||||
|
||||||||||
// Ensure that code will not execute if an instruction set is useable. Call only | ||||||||||
// if the instruction set has previously reported as unuseable, but when | ||||||||||
// that that status has not yet been recorded to the AOT compiler | ||||||||||
void compVerifyInstructionSetUnuseable(CORINFO_InstructionSet isa) | ||||||||||
{ | ||||||||||
// use compExactlyDependsOn to capture are record the use of the isa | ||||||||||
bool isaUseable = compExactlyDependsOn(isa); | ||||||||||
// Assert that the is unuseable. If true, this function should never be called. | ||||||||||
assert(!isaUseable); | ||||||||||
} | ||||||||||
|
||||||||||
// Answer the question: Is a particular ISA supported? | ||||||||||
// The result of this api call will match the target machine if the result is true | ||||||||||
// If the result is false, then the target machine may have support for the instruction | ||||||||||
bool compOpportunisticallyDependsOn(CORINFO_InstructionSet isa) const | ||||||||||
{ | ||||||||||
if ((opts.compSupportsISA & (1ULL << isa)) != 0) | ||||||||||
{ | ||||||||||
return compExactlyDependsOn(isa); | ||||||||||
} | ||||||||||
else | ||||||||||
{ | ||||||||||
return false; | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
bool canUseVexEncoding() const | ||||||||||
{ | ||||||||||
#ifdef TARGET_XARCH | ||||||||||
return compSupports(InstructionSet_AVX); | ||||||||||
return compOpportunisticallyDependsOn(InstructionSet_AVX); | ||||||||||
#else | ||||||||||
return false; | ||||||||||
#endif | ||||||||||
|
@@ -8381,14 +8459,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |||||||||
{ | ||||||||||
JitFlags* jitFlags; // all flags passed from the EE | ||||||||||
|
||||||||||
#if defined(TARGET_XARCH) || defined(TARGET_ARM64) | ||||||||||
uint64_t compSupportsISA; | ||||||||||
#endif | ||||||||||
uint64_t compSupportsISAReported; | ||||||||||
void setSupportedISAs(CORINFO_InstructionSetFlags isas) | ||||||||||
{ | ||||||||||
#if defined(TARGET_XARCH) || defined(TARGET_ARM64) | ||||||||||
compSupportsISA = isas.GetFlagsRaw(); | ||||||||||
#endif | ||||||||||
} | ||||||||||
|
||||||||||
unsigned compFlags; // method attributes | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you may have addressed this in an earlier discussion, but I believe that these need to be the same as the
TARGET_AMD64
ones - is there a reason they can't share code here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are autogenerated, and it would add a fair amount of complexity to have the autogenerator write them out once. In this particular part of the code, they don't actually have to be the same (that's restricted to a small bit of logic that is in crossgen2, which have explicit asserts for the details that must remain the same.) At the same time, the way they are authored in the InstructionSetDesc.txt, the autogenerator will happen to keep things the same and as long as new code follows the pattern in there, stuff will remain the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I recall that now. Seems reasonable.