Folds subtraction of an addition where each operand has a constant operand. Cases: (x + 2) - 2 = x + 0 (2 + x) - 2 = x + 0 2 - (x + 2) = 0 - x 2 - (2 + x) = 0 - x
| 1363 | // 2 - (x + 2) = 0 - x |
| 1364 | // 2 - (2 + x) = 0 - x |
| 1365 | FoldingRule MergeSubAddArithmetic() { |
| 1366 | return [](IRContext* context, Instruction* inst, |
| 1367 | const std::vector<const analysis::Constant*>& constants) { |
| 1368 | assert(inst->opcode() == spv::Op::OpFSub || |
| 1369 | inst->opcode() == spv::Op::OpISub); |
| 1370 | const analysis::Type* type = |
| 1371 | context->get_type_mgr()->GetType(inst->type_id()); |
| 1372 | |
| 1373 | if (type->IsCooperativeMatrix()) { |
| 1374 | return false; |
| 1375 | } |
| 1376 | |
| 1377 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 1378 | bool uses_float = HasFloatingPoint(type); |
| 1379 | if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; |
| 1380 | |
| 1381 | uint32_t width = ElementWidth(type); |
| 1382 | if (width != 32 && width != 64) return false; |
| 1383 | |
| 1384 | const analysis::Constant* const_input1 = ConstInput(constants); |
| 1385 | if (!const_input1) return false; |
| 1386 | Instruction* other_inst = NonConstInput(context, constants[0], inst); |
| 1387 | if (uses_float && !other_inst->IsFloatingPointFoldingAllowed()) |
| 1388 | return false; |
| 1389 | |
| 1390 | if (other_inst->opcode() == spv::Op::OpFAdd || |
| 1391 | other_inst->opcode() == spv::Op::OpIAdd) { |
| 1392 | std::vector<const analysis::Constant*> other_constants = |
| 1393 | const_mgr->GetOperandConstants(other_inst); |
| 1394 | const analysis::Constant* const_input2 = ConstInput(other_constants); |
| 1395 | if (!const_input2) return false; |
| 1396 | |
| 1397 | Instruction* non_const_input = |
| 1398 | NonConstInput(context, other_constants[0], other_inst); |
| 1399 | |
| 1400 | // If the first operand of the sub is not a constant, swap the constants |
| 1401 | // so the subtraction has the correct operands. |
| 1402 | if (constants[0] == nullptr) std::swap(const_input1, const_input2); |
| 1403 | // Subtract the constants. |
| 1404 | uint32_t merged_id = PerformOperation(const_mgr, inst->opcode(), |
| 1405 | const_input1, const_input2); |
| 1406 | spv::Op op = inst->opcode(); |
| 1407 | uint32_t op1 = 0; |
| 1408 | uint32_t op2 = 0; |
| 1409 | if (constants[0] == nullptr) { |
| 1410 | // Non-constant operand is first. Change the opcode. |
| 1411 | op1 = non_const_input->result_id(); |
| 1412 | op2 = merged_id; |
| 1413 | op = other_inst->opcode(); |
| 1414 | } else { |
| 1415 | // Constant operand is first. |
| 1416 | op1 = merged_id; |
| 1417 | op2 = non_const_input->result_id(); |
| 1418 | } |
| 1419 | if (op1 == 0 || op2 == 0) return false; |
| 1420 | |
| 1421 | inst->SetOpcode(op); |
| 1422 | inst->SetInOperands( |
no test coverage detected