diff options
-rw-r--r-- | src/jit/compiler.h | 1 | ||||
-rw-r--r-- | src/jit/gentree.cpp | 42 | ||||
-rw-r--r-- | src/jit/gentree.h | 24 | ||||
-rw-r--r-- | src/jit/lsraxarch.cpp | 29 |
4 files changed, 70 insertions, 26 deletions
diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 7266c738e0..0d5326a9a5 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -1529,6 +1529,7 @@ class Compiler friend class TempDsc; friend class LIR; friend class ObjectAllocator; + friend struct GenTree; #ifndef _TARGET_64BIT_ friend class DecomposeLongs; diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index 9b8f88bd85..99b64312bc 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -16640,7 +16640,7 @@ bool GenTree::canBeContained() const // It is not possible for nodes that do not produce values or that are not containable values // to be contained. - if ((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) + if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic())) { return false; } @@ -17982,6 +17982,46 @@ bool GenTree::isCommutativeSIMDIntrinsic() #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS +bool GenTree::isCommutativeHWIntrinsic() const +{ + assert(gtOper == GT_HWIntrinsic); + +#ifdef _TARGET_XARCH_ + HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId); + return ((flags & HW_Flag_Commutative) != 0); +#else + return false; +#endif // _TARGET_XARCH_ +} + +bool GenTree::isContainableHWIntrinsic() const +{ + assert(gtOper == GT_HWIntrinsic); + +#ifdef _TARGET_XARCH_ + HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId); + return ((flags & HW_Flag_NoContainment) == 0); +#else + return false; +#endif // _TARGET_XARCH_ +} + +bool GenTree::isRMWHWIntrinsic(Compiler* comp) +{ + assert(gtOper == GT_HWIntrinsic); + assert(comp != nullptr); + +#ifdef _TARGET_XARCH_ + if (!comp->canUseVexEncoding()) + { + HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId); + return ((flags & HW_Flag_NoRMWSemantics) == 0); + } +#endif // _TARGET_XARCH_ + + return false; +} + GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type, NamedIntrinsic hwIntrinsicID, var_types baseType, diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 25d5a286fd..35c215cf21 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -1471,6 +1471,27 @@ public: } #endif // FEATURE_SIMD +#ifdef FEATURE_HW_INTRINSICS + bool isCommutativeHWIntrinsic() const; + bool isContainableHWIntrinsic() const; + bool isRMWHWIntrinsic(Compiler* comp); +#else + bool isCommutativeHWIntrinsic() const + { + return false; + } + + bool isContainableHWIntrinsic() const + { + return false; + } + + bool isRMWHWIntrinsic(Compiler* comp) + { + return false; + } +#endif // FEATURE_HW_INTRINSICS + static bool OperIsCommutative(genTreeOps gtOper) { return (OperKind(gtOper) & GTK_COMMUTE) != 0; @@ -1478,7 +1499,8 @@ public: bool OperIsCommutative() { - return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic()); + return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic()) || + (OperIsHWIntrinsic(gtOper) && isCommutativeHWIntrinsic()); } static bool OperIsAssignment(genTreeOps gtOper) diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp index b0e95ae31f..a9f0207d8d 100644 --- a/src/jit/lsraxarch.cpp +++ b/src/jit/lsraxarch.cpp @@ -821,6 +821,11 @@ bool LinearScan::isRMWRegOper(GenTree* tree) case GT_MUL: return (!tree->gtOp.gtOp2->isContainedIntOrIImmed() && !tree->gtOp.gtOp1->isContainedIntOrIImmed()); +#ifdef FEATURE_HW_INTRINSICS + case GT_HWIntrinsic: + return tree->isRMWHWIntrinsic(compiler); +#endif // FEATURE_HW_INTRINSICS + default: return true; } @@ -2309,30 +2314,6 @@ void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } } - if (!compiler->canUseVexEncoding()) - { - // On machines without VEX support, we sometimes have to inject an intermediate - // `movaps targetReg, op1Reg` in order to maintain the correct behavior. This - // becomes a problem if `op2Reg == targetReg` since that means we will overwrite - // op2. In order to resolve this, we currently mark the second operand as delay free. - - if ((flags & HW_Flag_NoRMWSemantics) == 0) - { - assert(category != HW_Category_MemoryLoad); - assert(category != HW_Category_MemoryStore); - - assert((flags & HW_Flag_NoCodeGen) == 0); - - if (info->srcCount >= 2) - { - assert(numArgs >= 2); - LocationInfoListNode* op2Info = useList.Begin()->Next(); - op2Info->info.isDelayFree = true; - info->hasDelayFreeSrc = true; - } - } - } - switch (intrinsicID) { case NI_SSE_CompareEqualOrderedScalar: |