@@ -21909,7 +21909,6 @@ GenTree* Compiler::gtNewSimdBinOpNode(
2190921909
2191021910 case GT_MUL:
2191121911 {
21912- assert(!varTypeIsLong(simdBaseType));
2191321912 GenTree** scalarOp = nullptr;
2191421913
2191521914 if (varTypeIsArithmetic(op1))
@@ -21973,6 +21972,42 @@ GenTree* Compiler::gtNewSimdBinOpNode(
2197321972 break;
2197421973 }
2197521974
21975+ case TYP_LONG:
21976+ case TYP_ULONG:
21977+ {
21978+ if (simdSize == 8)
21979+ {
21980+ // Vector64<long> vec = Vector64.CreateScalar(op1.ToScalar() * op2.ToScalar())
21981+ op1 = gtNewBitCastNode(TYP_LONG, op1);
21982+ op2 = gtNewBitCastNode(TYP_LONG, op2);
21983+ GenTreeOp* mul = gtNewOperNode(GT_MUL, TYP_LONG, op1, op2);
21984+ return gtNewSimdCreateScalarNode(TYP_SIMD8, mul, simdBaseJitType, 8);
21985+ }
21986+
21987+ // Make op1 and op2 multi-use:
21988+ GenTree* op1Dup = fgMakeMultiUse(&op1);
21989+ GenTree* op2Dup = fgMakeMultiUse(&op2);
21990+
21991+ // long left0 = op1.GetElement(0)
21992+ // long right0 = op2.GetElement(0)
21993+ GenTree* left0 = gtNewSimdToScalarNode(TYP_LONG, op1, simdBaseJitType, 16);
21994+ GenTree* right0 =
21995+ scalarOp != nullptr ? op2 : gtNewSimdToScalarNode(TYP_LONG, op2, simdBaseJitType, 16);
21996+
21997+ // long left1 = op1.GetElement(1)
21998+ // long right1 = op2.GetElement(1)
21999+ GenTree* left1 = gtNewSimdGetElementNode(TYP_LONG, op1Dup, gtNewIconNode(1), simdBaseJitType, 16);
22000+ GenTree* right1 = scalarOp != nullptr ? op2Dup
22001+ : gtNewSimdGetElementNode(TYP_LONG, op2Dup, gtNewIconNode(1),
22002+ simdBaseJitType, 16);
22003+
22004+ // Vector128<long> vec = Vector128.Create(left0 * right0, left1 * right1)
22005+ op1 = gtNewOperNode(GT_MUL, TYP_LONG, left0, right0);
22006+ op2 = gtNewOperNode(GT_MUL, TYP_LONG, left1, right1);
22007+ GenTree* vec = gtNewSimdCreateScalarUnsafeNode(type, op1, simdBaseJitType, 16);
22008+ return gtNewSimdWithElementNode(type, vec, gtNewIconNode(1), op2, simdBaseJitType, 16);
22009+ }
22010+
2197622011 default:
2197722012 {
2197822013 unreached();
0 commit comments