@@ -3510,6 +3510,8 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore)
35103510 DISPTREERANGE (BlockRange (), lclStore);
35113511 JITDUMP (" \n " );
35123512
3513+ TryRetypingFloatingPointStoreToIntegerStore (lclStore);
3514+
35133515 GenTree* src = lclStore->gtGetOp1 ();
35143516 LclVarDsc* varDsc = comp->lvaGetDesc (lclStore);
35153517 const bool srcIsMultiReg = src->IsMultiRegNode ();
@@ -7211,6 +7213,8 @@ void Lowering::LowerStoreIndirCommon(GenTreeStoreInd* ind)
72117213{
72127214 assert (ind->TypeGet () != TYP_STRUCT);
72137215
7216+ TryRetypingFloatingPointStoreToIntegerStore (ind);
7217+
72147218#if defined(TARGET_ARM64)
72157219 // Verify containment safety before creating an LEA that must be contained.
72167220 //
@@ -7239,51 +7243,6 @@ void Lowering::LowerStoreIndirCommon(GenTreeStoreInd* ind)
72397243 }
72407244#endif
72417245
7242- if (varTypeIsFloating (ind) && ind->Data ()->IsCnsFltOrDbl ())
7243- {
7244- // Optimize *x = DCON to *x = ICON which can be slightly faster and/or smaller.
7245- GenTree* data = ind->Data ();
7246- double dblCns = data->AsDblCon ()->DconValue ();
7247- ssize_t intCns = 0 ;
7248- var_types type = TYP_UNKNOWN;
7249- // XARCH: we can always contain the immediates.
7250- // ARM64: zero can always be contained, other cases will use immediates from the data
7251- // section and it is not a clear win to switch them to inline integers.
7252- // ARM: FP constants are assembled from integral ones, so it is always profitable
7253- // to directly use the integers as it avoids the int -> float conversion.
7254- CLANG_FORMAT_COMMENT_ANCHOR;
7255-
7256- #if defined(TARGET_XARCH) || defined(TARGET_ARM)
7257- bool shouldSwitchToInteger = true ;
7258- #else // TARGET_ARM64
7259- bool shouldSwitchToInteger = !data->IsCnsNonZeroFltOrDbl ();
7260- #endif
7261-
7262- if (shouldSwitchToInteger)
7263- {
7264- if (ind->TypeIs (TYP_FLOAT))
7265- {
7266- float fltCns = static_cast <float >(dblCns); // should be a safe round-trip
7267- intCns = static_cast <ssize_t >(*reinterpret_cast <INT32*>(&fltCns));
7268- type = TYP_INT;
7269- }
7270- #ifdef TARGET_64BIT
7271- else
7272- {
7273- assert (ind->TypeIs (TYP_DOUBLE));
7274- intCns = static_cast <ssize_t >(*reinterpret_cast <INT64*>(&dblCns));
7275- type = TYP_LONG;
7276- }
7277- #endif
7278- }
7279-
7280- if (type != TYP_UNKNOWN)
7281- {
7282- data->BashToConst (intCns, type);
7283- ind->ChangeType (type);
7284- }
7285- }
7286-
72877246 LowerStoreIndir (ind);
72887247 }
72897248}
@@ -7514,6 +7473,89 @@ bool Lowering::TryTransformStoreObjAsStoreInd(GenTreeBlk* blkNode)
75147473 return true ;
75157474}
75167475
7476+ // ------------------------------------------------------------------------
7477+ // TryRetypingFloatingPointStoreToIntegerStore: Retype an FP memory store.
7478+ //
7479+ // On some targets, integer stores are cheaper and/or smaller than their
7480+ // floating-point counterparts, because, e. g., integer immediates can be
7481+ // encoded inline while FP ones need to be loaded from the data section.
7482+ //
7483+ // Arguments:
7484+ // store - The store node
7485+ //
7486+ void Lowering::TryRetypingFloatingPointStoreToIntegerStore (GenTree* store)
7487+ {
7488+ assert (store->OperIsStore () && !store->OperIsAtomicOp ());
7489+
7490+ if (!varTypeIsFloating (store))
7491+ {
7492+ return ;
7493+ }
7494+
7495+ // We only want to transform memory stores, not definitions of candidate locals.
7496+ //
7497+ if (store->OperIs (GT_STORE_LCL_VAR) && !comp->lvaGetDesc (store->AsLclVar ())->lvDoNotEnregister )
7498+ {
7499+ return ;
7500+ }
7501+
7502+ GenTree* data = store->Data ();
7503+ assert (store->TypeGet () == data->TypeGet ());
7504+
7505+ // Optimize *x = DCON to *x = ICON which can be slightly faster and/or smaller.
7506+ //
7507+ if (data->IsCnsFltOrDbl ())
7508+ {
7509+ double dblCns = data->AsDblCon ()->DconValue ();
7510+ ssize_t intCns = 0 ;
7511+ var_types type = TYP_UNKNOWN;
7512+ // XARCH: we can always contain the immediates.
7513+ // ARM64: zero can always be contained, other cases will use immediates from the data
7514+ // section and it is not a clear win to switch them to inline integers.
7515+ // ARM: FP constants are assembled from integral ones, so it is always profitable
7516+ // to directly use the integers as it avoids the int -> float conversion.
7517+ CLANG_FORMAT_COMMENT_ANCHOR;
7518+
7519+ #if defined(TARGET_XARCH) || defined(TARGET_ARM)
7520+ bool shouldSwitchToInteger = true ;
7521+ #else // TARGET_ARM64 || TARGET_LOONGARCH64
7522+ bool shouldSwitchToInteger = FloatingPointUtils::isPositiveZero (dblCns);
7523+ #endif
7524+
7525+ if (shouldSwitchToInteger)
7526+ {
7527+ if (store->TypeIs (TYP_FLOAT))
7528+ {
7529+ float fltCns = static_cast <float >(dblCns);
7530+ intCns = *reinterpret_cast <INT32*>(&fltCns);
7531+ type = TYP_INT;
7532+ }
7533+ #ifdef TARGET_64BIT
7534+ else
7535+ {
7536+ assert (store->TypeIs (TYP_DOUBLE));
7537+ intCns = *reinterpret_cast <INT64*>(&dblCns);
7538+ type = TYP_LONG;
7539+ }
7540+ #endif
7541+ }
7542+
7543+ if (type != TYP_UNKNOWN)
7544+ {
7545+ data->BashToConst (intCns, type);
7546+
7547+ assert (!store->OperIsLocalStore () || comp->lvaGetDesc (store->AsLclVarCommon ())->lvDoNotEnregister );
7548+ if (store->OperIs (GT_STORE_LCL_VAR))
7549+ {
7550+ store->SetOper (GT_STORE_LCL_FLD);
7551+ store->AsLclFld ()->SetLclOffs (0 );
7552+ store->AsLclFld ()->SetLayout (nullptr );
7553+ }
7554+ store->ChangeType (type);
7555+ }
7556+ }
7557+ }
7558+
75177559#ifdef FEATURE_SIMD
75187560// ----------------------------------------------------------------------------------------------
75197561// Lowering::LowerSIMD: Perform containment analysis for a SIMD intrinsic node.
0 commit comments