Folds subtraction of a subtraction where each operand has a constant operand. Cases: (x - 2) - 2 = x - 4 (2 - x) - 2 = 0 - x 2 - (x - 2) = 4 - x 2 - (2 - x) = x + 0
| 1434 | // 2 - (x - 2) = 4 - x |
| 1435 | // 2 - (2 - x) = x + 0 |
| 1436 | FoldingRule MergeSubSubArithmetic() { |
| 1437 | return [](IRContext* context, Instruction* inst, |
| 1438 | const std::vector<const analysis::Constant*>& constants) { |
| 1439 | assert(inst->opcode() == spv::Op::OpFSub || |
| 1440 | inst->opcode() == spv::Op::OpISub); |
| 1441 | const analysis::Type* type = |
| 1442 | context->get_type_mgr()->GetType(inst->type_id()); |
| 1443 | |
| 1444 | if (type->IsCooperativeMatrix()) { |
| 1445 | return false; |
| 1446 | } |
| 1447 | |
| 1448 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 1449 | bool uses_float = HasFloatingPoint(type); |
| 1450 | if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; |
| 1451 | |
| 1452 | uint32_t width = ElementWidth(type); |
| 1453 | if (width != 32 && width != 64) return false; |
| 1454 | |
| 1455 | const analysis::Constant* const_input1 = ConstInput(constants); |
| 1456 | if (!const_input1) return false; |
| 1457 | Instruction* other_inst = NonConstInput(context, constants[0], inst); |
| 1458 | if (uses_float && !other_inst->IsFloatingPointFoldingAllowed()) |
| 1459 | return false; |
| 1460 | |
| 1461 | if (other_inst->opcode() == spv::Op::OpFSub || |
| 1462 | other_inst->opcode() == spv::Op::OpISub) { |
| 1463 | std::vector<const analysis::Constant*> other_constants = |
| 1464 | const_mgr->GetOperandConstants(other_inst); |
| 1465 | const analysis::Constant* const_input2 = ConstInput(other_constants); |
| 1466 | if (!const_input2) return false; |
| 1467 | |
| 1468 | Instruction* non_const_input = |
| 1469 | NonConstInput(context, other_constants[0], other_inst); |
| 1470 | |
| 1471 | // Merge the constants. |
| 1472 | uint32_t merged_id = 0; |
| 1473 | spv::Op merge_op = inst->opcode(); |
| 1474 | if (other_constants[0] == nullptr) { |
| 1475 | merge_op = uses_float ? spv::Op::OpFAdd : spv::Op::OpIAdd; |
| 1476 | } else if (constants[0] == nullptr) { |
| 1477 | std::swap(const_input1, const_input2); |
| 1478 | } |
| 1479 | merged_id = |
| 1480 | PerformOperation(const_mgr, merge_op, const_input1, const_input2); |
| 1481 | if (merged_id == 0) return false; |
| 1482 | |
| 1483 | spv::Op op = inst->opcode(); |
| 1484 | if (constants[0] != nullptr && other_constants[0] != nullptr) { |
| 1485 | // Change the operation. |
| 1486 | op = uses_float ? spv::Op::OpFAdd : spv::Op::OpIAdd; |
| 1487 | } |
| 1488 | |
| 1489 | uint32_t op1 = 0; |
| 1490 | uint32_t op2 = 0; |
| 1491 | if ((constants[0] == nullptr) ^ (other_constants[0] == nullptr)) { |
| 1492 | op1 = merged_id; |
| 1493 | op2 = non_const_input->result_id(); |
no test coverage detected