Perform the following factoring identity, handling all operand order combinations: (a * b) + (a * c) = a * (b + c) (a * b) - (a * c) = a * (b - c)
| 1588 | // (a * b) + (a * c) = a * (b + c) |
| 1589 | // (a * b) - (a * c) = a * (b - c) |
| 1590 | FoldingRule FactorAddSubMuls() { |
| 1591 | return [](IRContext* context, Instruction* inst, |
| 1592 | const std::vector<const analysis::Constant*>&) { |
| 1593 | assert(inst->opcode() == spv::Op::OpFAdd || |
| 1594 | inst->opcode() == spv::Op::OpFSub || |
| 1595 | inst->opcode() == spv::Op::OpIAdd || |
| 1596 | inst->opcode() == spv::Op::OpISub); |
| 1597 | const analysis::Type* type = |
| 1598 | context->get_type_mgr()->GetType(inst->type_id()); |
| 1599 | bool uses_float = HasFloatingPoint(type); |
| 1600 | if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; |
| 1601 | |
| 1602 | analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| 1603 | uint32_t add_op0 = inst->GetSingleWordInOperand(0); |
| 1604 | Instruction* add_op0_inst = def_use_mgr->GetDef(add_op0); |
| 1605 | if (add_op0_inst->opcode() != spv::Op::OpFMul && |
| 1606 | add_op0_inst->opcode() != spv::Op::OpIMul) |
| 1607 | return false; |
| 1608 | uint32_t add_op1 = inst->GetSingleWordInOperand(1); |
| 1609 | Instruction* add_op1_inst = def_use_mgr->GetDef(add_op1); |
| 1610 | if (add_op1_inst->opcode() != spv::Op::OpFMul && |
| 1611 | add_op1_inst->opcode() != spv::Op::OpIMul) |
| 1612 | return false; |
| 1613 | |
| 1614 | // Only perform this optimization if both of the muls only have one use. |
| 1615 | // Otherwise this is a deoptimization in size and performance. |
| 1616 | if (def_use_mgr->NumUses(add_op0_inst) > 1) return false; |
| 1617 | if (def_use_mgr->NumUses(add_op1_inst) > 1) return false; |
| 1618 | |
| 1619 | if (add_op0_inst->opcode() == spv::Op::OpFMul && |
| 1620 | (!add_op0_inst->IsFloatingPointFoldingAllowed() || |
| 1621 | !add_op1_inst->IsFloatingPointFoldingAllowed())) |
| 1622 | return false; |
| 1623 | |
| 1624 | for (int i = 0; i < 2; i++) { |
| 1625 | for (int j = 0; j < 2; j++) { |
| 1626 | // Check if operand i in add_op0_inst matches operand j in add_op1_inst. |
| 1627 | if (FactorAddSubMulsOpnds(add_op0_inst->GetSingleWordInOperand(i), |
| 1628 | add_op0_inst->GetSingleWordInOperand(1 - i), |
| 1629 | add_op1_inst->GetSingleWordInOperand(j), |
| 1630 | add_op1_inst->GetSingleWordInOperand(1 - j), |
| 1631 | inst)) |
| 1632 | return true; |
| 1633 | } |
| 1634 | } |
| 1635 | return false; |
| 1636 | }; |
| 1637 | } |
| 1638 | |
| 1639 | // Reassociate integer instructions where both operands share the same opcode |
| 1640 | // and both source instructions contain a constant. |
no test coverage detected