@@ -639,7 +639,7 @@ bool Compiler::isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd)
639639// For vector calling conventions, a vector is considered a "primitive"
640640// type, as it is passed in a single register.
641641//
642- var_types Compiler::getPrimitiveTypeForStruct (unsigned structSize, CORINFO_CLASS_HANDLE clsHnd, bool isVarArg )
642+ var_types Compiler::getPrimitiveTypeForStruct (unsigned structSize, CORINFO_CLASS_HANDLE clsHnd)
643643{
644644 assert (structSize != 0 );
645645
@@ -648,37 +648,32 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS
648648 // Start by determining if we have an HFA/HVA with a single element.
649649 if (GlobalJitOptions::compFeatureHfa)
650650 {
651- // Arm64 Windows VarArg methods arguments will not classify HFA types, they will need to be treated
652- // as if they are not HFA types.
653- if (!(TargetArchitecture::IsArm64 && TargetOS::IsWindows && isVarArg))
651+ switch (structSize)
654652 {
655- switch (structSize)
656- {
657- case 4 :
658- case 8 :
653+ case 4 :
654+ case 8 :
659655#ifdef TARGET_ARM64
660- case 16 :
656+ case 16 :
661657#endif // TARGET_ARM64
658+ {
659+ var_types hfaType = GetHfaType (clsHnd);
660+ // We're only interested in the case where the struct size is equal to the size of the hfaType.
661+ if (varTypeIsValidHfaType (hfaType))
662662 {
663- var_types hfaType = GetHfaType (clsHnd);
664- // We're only interested in the case where the struct size is equal to the size of the hfaType.
665- if (varTypeIsValidHfaType (hfaType))
663+ if (genTypeSize (hfaType) == structSize)
666664 {
667- if (genTypeSize (hfaType) == structSize)
668- {
669- useType = hfaType;
670- }
671- else
672- {
673- return TYP_UNKNOWN;
674- }
665+ useType = hfaType;
666+ }
667+ else
668+ {
669+ return TYP_UNKNOWN;
675670 }
676671 }
677672 }
678- if (useType != TYP_UNKNOWN)
679- {
680- return useType;
681- }
673+ }
674+ if (useType != TYP_UNKNOWN)
675+ {
676+ return useType;
682677 }
683678 }
684679
@@ -733,230 +728,6 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS
733728 return useType;
734729}
735730
736- // -----------------------------------------------------------------------------
737- // getArgTypeForStruct:
738- // Get the type that is used to pass values of the given struct type.
739- // If you have already retrieved the struct size then it should be
740- // passed as the optional fourth argument, as this allows us to avoid
741- // an extra call to getClassSize(clsHnd)
742- //
743- // Arguments:
744- // clsHnd - the handle for the struct type
745- // wbPassStruct - An "out" argument with information about how
746- // the struct is to be passed
747- // isVarArg - is vararg, used to ignore HFA types for Arm64 windows varargs
748- // structSize - the size of the struct type,
749- // or zero if we should call getClassSize(clsHnd)
750- //
751- // Return Value:
752- // For wbPassStruct you can pass a 'nullptr' and nothing will be written
753- // or returned for that out parameter.
754- // When *wbPassStruct is SPK_PrimitiveType this method's return value
755- // is the primitive type used to pass the struct.
756- // When *wbPassStruct is SPK_ByReference this method's return value
757- // is always TYP_UNKNOWN and the struct type is passed by reference to a copy
758- // When *wbPassStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
759- // is always TYP_STRUCT and the struct type is passed by value either
760- // using multiple registers or on the stack.
761- //
762- // Assumptions:
763- // The size must be the size of the given type.
764- // The given class handle must be for a value type (struct).
765- //
766- // Notes:
767- // About HFA types:
768- // When the clsHnd is a one element HFA type we return the appropriate
769- // floating point primitive type and *wbPassStruct is SPK_PrimitiveType
770- // If there are two or more elements in the HFA type then the this method's
771- // return value is TYP_STRUCT and *wbPassStruct is SPK_ByValueAsHfa
772- //
773- var_types Compiler::getArgTypeForStruct (CORINFO_CLASS_HANDLE clsHnd,
774- structPassingKind* wbPassStruct,
775- bool isVarArg,
776- unsigned structSize)
777- {
778- var_types useType = TYP_UNKNOWN;
779- structPassingKind howToPassStruct = SPK_Unknown; // We must change this before we return
780-
781- assert (structSize != 0 );
782-
783- // Determine if we can pass the struct as a primitive type.
784- // Note that on x86 we only pass specific pointer-sized structs that satisfy isTrivialPointerSizedStruct checks.
785- #ifndef TARGET_X86
786- #ifdef UNIX_AMD64_ABI
787-
788- // An 8-byte struct may need to be passed in a floating point register
789- // So we always consult the struct "Classifier" routine
790- //
791- SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
792- eeGetSystemVAmd64PassStructInRegisterDescriptor (clsHnd, &structDesc);
793-
794- if (structDesc.passedInRegisters && (structDesc.eightByteCount != 1 ))
795- {
796- // We can't pass this as a primitive type.
797- }
798- else if (structDesc.eightByteClassifications [0 ] == SystemVClassificationTypeSSE)
799- {
800- // If this is passed as a floating type, use that.
801- // Otherwise, we'll use the general case - we don't want to use the "EightByteType"
802- // directly, because it returns `TYP_INT` for any integral type <= 4 bytes, and
803- // we need to preserve small types.
804- useType = GetEightByteType (structDesc, 0 );
805- }
806- else
807- #endif // UNIX_AMD64_ABI
808-
809- // The largest arg passed in a single register is MAX_PASS_SINGLEREG_BYTES,
810- // so we can skip calling getPrimitiveTypeForStruct when we
811- // have a struct that is larger than that.
812- //
813- if (structSize <= MAX_PASS_SINGLEREG_BYTES)
814- {
815- // We set the "primitive" useType based upon the structSize
816- // and also examine the clsHnd to see if it is an HFA of count one
817- useType = getPrimitiveTypeForStruct (structSize, clsHnd, isVarArg);
818- }
819- #else
820- if (isTrivialPointerSizedStruct (clsHnd))
821- {
822- useType = TYP_I_IMPL;
823- }
824- #endif // !TARGET_X86
825-
826- // Did we change this struct type into a simple "primitive" type?
827- //
828- if (useType != TYP_UNKNOWN)
829- {
830- // Yes, we should use the "primitive" type in 'useType'
831- howToPassStruct = SPK_PrimitiveType;
832- }
833- else // We can't replace the struct with a "primitive" type
834- {
835- // See if we can pass this struct by value, possibly in multiple registers
836- // or if we should pass it by reference to a copy
837- //
838- if (structSize <= MAX_PASS_MULTIREG_BYTES)
839- {
840- // Structs that are HFA/HVA's are passed by value in multiple registers.
841- // Arm64 Windows VarArg methods arguments will not classify HFA/HVA types, they will need to be treated
842- // as if they are not HFA/HVA types.
843- var_types hfaType;
844- if (TargetArchitecture::IsArm64 && TargetOS::IsWindows && isVarArg)
845- {
846- hfaType = TYP_UNDEF;
847- }
848- else
849- {
850- hfaType = GetHfaType (clsHnd);
851- }
852- if (varTypeIsValidHfaType (hfaType))
853- {
854- // HFA's of count one should have been handled by getPrimitiveTypeForStruct
855- assert (GetHfaCount (clsHnd) >= 2 );
856-
857- // setup wbPassType and useType indicate that this is passed by value as an HFA
858- // using multiple registers
859- // (when all of the parameters registers are used, then the stack will be used)
860- howToPassStruct = SPK_ByValueAsHfa;
861- useType = TYP_STRUCT;
862- }
863- else // Not an HFA struct type
864- {
865-
866- #ifdef UNIX_AMD64_ABI
867- // The case of (structDesc.eightByteCount == 1) should have already been handled
868- if ((structDesc.eightByteCount > 1 ) || !structDesc.passedInRegisters )
869- {
870- // setup wbPassType and useType indicate that this is passed by value in multiple registers
871- // (when all of the parameters registers are used, then the stack will be used)
872- howToPassStruct = SPK_ByValue;
873- useType = TYP_STRUCT;
874- }
875- else
876- {
877- assert (structDesc.eightByteCount == 0 );
878- // Otherwise we pass this struct by reference to a copy
879- // setup wbPassType and useType indicate that this is passed using one register
880- // (by reference to a copy)
881- howToPassStruct = SPK_ByReference;
882- useType = TYP_UNKNOWN;
883- }
884-
885- #elif defined(TARGET_ARM64)
886-
887- // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
888- assert (structSize > TARGET_POINTER_SIZE);
889-
890- // On ARM64 structs that are 9-16 bytes are passed by value in multiple registers
891- //
892- if (structSize <= (TARGET_POINTER_SIZE * 2 ))
893- {
894- // setup wbPassType and useType indicate that this is passed by value in multiple registers
895- // (when all of the parameters registers are used, then the stack will be used)
896- howToPassStruct = SPK_ByValue;
897- useType = TYP_STRUCT;
898- }
899- else // a structSize that is 17-32 bytes in size
900- {
901- // Otherwise we pass this struct by reference to a copy
902- // setup wbPassType and useType indicate that this is passed using one register
903- // (by reference to a copy)
904- howToPassStruct = SPK_ByReference;
905- useType = TYP_UNKNOWN;
906- }
907-
908- #elif defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
909-
910- // Otherwise we pass this struct by value on the stack
911- // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
912- // On LOONGARCH64 and RISCV64 struct that is 1-16 bytes is passed by value in one/two register(s)
913- howToPassStruct = SPK_ByValue;
914- useType = TYP_STRUCT;
915-
916- #else // TARGET_XXX
917-
918- noway_assert (!" Unhandled TARGET in getArgTypeForStruct (with FEATURE_MULTIREG_ARGS=1)" );
919-
920- #endif // TARGET_XXX
921- }
922- }
923- else // (structSize > MAX_PASS_MULTIREG_BYTES)
924- {
925- // We have a (large) struct that can't be replaced with a "primitive" type
926- // and can't be passed in multiple registers
927-
928- #if defined(TARGET_X86) || defined(TARGET_ARM) || defined(UNIX_AMD64_ABI)
929-
930- // Otherwise we pass this struct by value on the stack
931- // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
932- howToPassStruct = SPK_ByValue;
933- useType = TYP_STRUCT;
934-
935- #elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
936-
937- // Otherwise we pass this struct by reference to a copy
938- // setup wbPassType and useType indicate that this is passed using one register (by reference to a copy)
939- howToPassStruct = SPK_ByReference;
940- useType = TYP_UNKNOWN;
941-
942- #else // TARGET_XXX
943-
944- noway_assert (!" Unhandled TARGET in getArgTypeForStruct" );
945-
946- #endif // TARGET_XXX
947- }
948- }
949-
950- // 'howToPassStruct' must be set to one of the valid values before we return
951- assert (howToPassStruct != SPK_Unknown);
952- if (wbPassStruct != nullptr )
953- {
954- *wbPassStruct = howToPassStruct;
955- }
956-
957- return useType;
958- }
959-
960731// -----------------------------------------------------------------------------
961732// getReturnTypeForStruct:
962733// Get the type that is used to return values of the given struct type.
@@ -1136,7 +907,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
1136907 //
1137908 // The ABI for struct returns in varArg methods, is same as the normal case,
1138909 // so pass false for isVararg
1139- useType = getPrimitiveTypeForStruct (structSize, clsHnd, /* isVararg= */ false );
910+ useType = getPrimitiveTypeForStruct (structSize, clsHnd);
1140911
1141912 if (useType != TYP_UNKNOWN)
1142913 {
@@ -4082,8 +3853,8 @@ bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
40823853 JITDUMP (" \n "
40833854 " compRsvdRegCheck\n "
40843855 " frame size = %6d\n "
4085- " compArgSize = %6d\n " ,
4086- frameSize, compArgSize );
3856+ " lvaParameterStackSize = %6d\n " ,
3857+ frameSize, lvaParameterStackSize );
40873858
40883859 if (opts.MinOpts ())
40893860 {
@@ -4153,7 +3924,7 @@ bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
41533924 JITDUMP (" maxR11NegativeEncodingOffset = %6d\n " , maxR11NegativeEncodingOffset);
41543925
41553926 // -1 because otherwise we are computing the address just beyond the last argument, which we don't need to do.
4156- unsigned maxR11PositiveOffset = compArgSize + (2 * REGSIZE_BYTES) - 1 ;
3927+ unsigned maxR11PositiveOffset = lvaParameterStackSize + (2 * REGSIZE_BYTES) - 1 ;
41573928 JITDUMP (" maxR11PositiveOffset = %6d\n " , maxR11PositiveOffset);
41583929
41593930 // The value is positive, but represents a negative offset from R11.
@@ -4184,8 +3955,8 @@ bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
41843955 JITDUMP (" maxSPPositiveEncodingOffset = %6d\n " , maxSPPositiveEncodingOffset);
41853956
41863957 // -1 because otherwise we are computing the address just beyond the last argument, which we don't need to do.
4187- assert (compArgSize + frameSize > 0 );
4188- unsigned maxSPPositiveOffset = compArgSize + frameSize - 1 ;
3958+ assert (lvaParameterStackSize + frameSize > 0 );
3959+ unsigned maxSPPositiveOffset = lvaParameterStackSize + frameSize - 1 ;
41893960
41903961 if (codeGen->isFramePointerUsed ())
41913962 {
0 commit comments