diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index f1c1b49b2578b7..bdce5471ad6823 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1378,6 +1378,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #if defined(TARGET_ARM64) void genCodeForJumpCompare(GenTreeOp* tree); void genCodeForMadd(GenTreeOp* tree); + void genCodeForMsub(GenTreeOp* tree); void genCodeForBfiz(GenTreeOp* tree); void genCodeForAddEx(GenTreeOp* tree); #endif // TARGET_ARM64 diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 69fc1885da3e9e..209c603e0bf0c9 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -10040,7 +10040,7 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) } //----------------------------------------------------------------------------------- -// genCodeForMadd: Emit a madd/msub (Multiply-Add) instruction +// genCodeForMadd: Emit a madd (Multiply-Add) instruction // // Arguments: // tree - GT_MADD tree where op1 or op2 is GT_ADD @@ -10084,6 +10084,31 @@ void CodeGen::genCodeForMadd(GenTreeOp* tree) genProduceReg(tree); } +//----------------------------------------------------------------------------------- +// genCodeForMsub: Emit a msub (Multiply-Subtract) instruction +// +// Arguments: +// tree - GT_MSUB tree where op2 is GT_MUL +// +void CodeGen::genCodeForMsub(GenTreeOp* tree) +{ + assert(tree->OperIs(GT_MSUB) && varTypeIsIntegral(tree) && !(tree->gtFlags & GTF_SET_FLAGS)); + genConsumeOperands(tree); + + assert(tree->gtGetOp2()->OperIs(GT_MUL)); + assert(tree->gtGetOp2()->isContained()); + + GenTree* a = tree->gtGetOp1(); + GenTree* b = tree->gtGetOp2()->gtGetOp1(); + GenTree* c = tree->gtGetOp2()->gtGetOp2(); + + // d = a - b * c + // MSUB d, b, c, a + GetEmitter()->emitIns_R_R_R_R(INS_msub, emitActualTypeSize(tree), tree->GetRegNum(), b->GetRegNum(), c->GetRegNum(), + a->GetRegNum()); + genProduceReg(tree); +} + //------------------------------------------------------------------------ // genCodeForBfiz: Generates the code sequence for a GenTree node that // represents a bitfield insert in zero with sign/zero extension. diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 460a2b1635d93c..126cb194d60904 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -306,6 +306,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genCodeForMadd(treeNode->AsOp()); break; + case GT_MSUB: + genCodeForMsub(treeNode->AsOp()); + break; + case GT_INC_SATURATE: genCodeForIncSaturate(treeNode); break; diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index c902b21ec72f47..8bce06ed8b3999 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -221,8 +221,10 @@ GTNODE(MUL_LONG , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR) GTNODE(AND_NOT , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) #ifdef TARGET_ARM64 -GTNODE(MADD , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Generates the Multiply-Add instruction (madd/msub) In the future, we might consider +GTNODE(MADD , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Generates the Multiply-Add instruction. In the future, we might consider // enabling it for both armarch and xarch for floating-point MADD "unsafe" math. +GTNODE(MSUB , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Generates the Multiply-Subtract instruction. In the future, we might consider + // enabling it for both armarch and xarch for floating-point MSUB "unsafe" math. GTNODE(ADDEX, GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Add with sign/zero extension. GTNODE(BFIZ , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero. #endif diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 8f4f1204f08dbb..89b590adcab5f8 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1609,43 +1609,59 @@ void Lowering::ContainCheckBinary(GenTreeOp* node) CheckImmedAndMakeContained(node, op2); #ifdef TARGET_ARM64 - // Find "a * b + c" or "c + a * b" in order to emit MADD/MSUB - if (comp->opts.OptimizationEnabled() && varTypeIsIntegral(node) && !node->isContained() && node->OperIs(GT_ADD) && - !node->gtOverflow() && (op1->OperIs(GT_MUL) || op2->OperIs(GT_MUL))) + if (comp->opts.OptimizationEnabled() && varTypeIsIntegral(node) && !node->isContained()) { - GenTree* mul; - GenTree* c; - if (op1->OperIs(GT_MUL)) + // Find "a * b + c" or "c + a * b" in order to emit MADD/MSUB + if (node->OperIs(GT_ADD) && !node->gtOverflow() && (op1->OperIs(GT_MUL) || op2->OperIs(GT_MUL))) { - mul = op1; - c = op2; - } - else - { - mul = op2; - c = op1; - } + GenTree* mul; + GenTree* c; + if (op1->OperIs(GT_MUL)) + { + mul = op1; + c = op2; + } + else + { + mul = op2; + c = op1; + } - GenTree* a = mul->gtGetOp1(); - GenTree* b = mul->gtGetOp2(); + GenTree* a = mul->gtGetOp1(); + GenTree* b = mul->gtGetOp2(); - if (!mul->isContained() && !mul->gtOverflow() && !a->isContained() && !b->isContained() && !c->isContained() && - varTypeIsIntegral(mul)) - { - if (a->OperIs(GT_NEG) && !a->gtGetOp1()->isContained() && !a->gtGetOp1()->IsRegOptional()) + if (!mul->isContained() && !mul->gtOverflow() && !a->isContained() && !b->isContained() && + !c->isContained() && varTypeIsIntegral(mul)) { - // "-a * b + c" to MSUB - MakeSrcContained(mul, a); + if (a->OperIs(GT_NEG) && !a->gtGetOp1()->isContained() && !a->gtGetOp1()->IsRegOptional()) + { + // "-a * b + c" to MSUB + MakeSrcContained(mul, a); + } + if (b->OperIs(GT_NEG) && !b->gtGetOp1()->isContained()) + { + // "a * -b + c" to MSUB + MakeSrcContained(mul, b); + } + // If both 'a' and 'b' are GT_NEG - MADD will be emitted. + + node->ChangeOper(GT_MADD); + MakeSrcContained(node, mul); } - if (b->OperIs(GT_NEG) && !b->gtGetOp1()->isContained()) + } + // Find "a - b * c" in order to emit MSUB + else if (node->OperIs(GT_SUB) && !node->gtOverflow() && op2->OperIs(GT_MUL) && !op2->isContained() && + !op2->gtOverflow() && varTypeIsIntegral(op2)) + { + GenTree* a = op1; + GenTree* b = op2->gtGetOp1(); + GenTree* c = op2->gtGetOp2(); + + if (!a->isContained() && !b->isContained() && !c->isContained()) { - // "a * -b + c" to MSUB - MakeSrcContained(mul, b); + node->ChangeOper(GT_MSUB); + MakeSrcContained(node, op2); } - // If both 'a' and 'b' are GT_NEG - MADD will be emitted. - - node->ChangeOper(GT_MADD); - MakeSrcContained(node, mul); } }