friend class TempDsc;
friend class LIR;
friend class ObjectAllocator;
+ friend struct GenTree;
#ifndef _TARGET_64BIT_
friend class DecomposeLongs;
// 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;
}
#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,
}
#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;
bool OperIsCommutative()
{
- return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic());
+ return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic()) ||
+ (OperIsHWIntrinsic(gtOper) && isCommutativeHWIntrinsic());
}
static bool OperIsAssignment(genTreeOps gtOper)
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;
}
}
}
- 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: