Merges negate into a mul or div operation if that operation contains a constant operand. Cases: -(x * 2) = x * -2 -(2 * x) = x * -2 -(x / 2) = x / -2 -(2 / x) = -2 / x
| 440 | // -(x / 2) = x / -2 |
| 441 | // -(2 / x) = -2 / x |
| 442 | FoldingRule MergeNegateMulDivArithmetic() { |
| 443 | return [](IRContext* context, Instruction* inst, |
| 444 | const std::vector<const analysis::Constant*>& constants) { |
| 445 | assert(inst->opcode() == spv::Op::OpFNegate || |
| 446 | inst->opcode() == spv::Op::OpSNegate); |
| 447 | (void)constants; |
| 448 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 449 | const analysis::Type* type = |
| 450 | context->get_type_mgr()->GetType(inst->type_id()); |
| 451 | |
| 452 | if (type->IsCooperativeMatrix()) { |
| 453 | return false; |
| 454 | } |
| 455 | |
| 456 | if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed()) |
| 457 | return false; |
| 458 | |
| 459 | Instruction* op_inst = |
| 460 | context->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u)); |
| 461 | if (HasFloatingPoint(type) && !op_inst->IsFloatingPointFoldingAllowed()) |
| 462 | return false; |
| 463 | |
| 464 | uint32_t width = ElementWidth(type); |
| 465 | if (width != 32 && width != 64) return false; |
| 466 | |
| 467 | spv::Op opcode = op_inst->opcode(); |
| 468 | if (opcode != spv::Op::OpFMul && opcode != spv::Op::OpFDiv && |
| 469 | opcode != spv::Op::OpIMul && opcode != spv::Op::OpSDiv) { |
| 470 | return false; |
| 471 | } |
| 472 | |
| 473 | std::vector<const analysis::Constant*> op_constants = |
| 474 | const_mgr->GetOperandConstants(op_inst); |
| 475 | // Merge negate into mul or div if one operand is constant. |
| 476 | if (op_constants[0] == nullptr && op_constants[1] == nullptr) { |
| 477 | return false; |
| 478 | } |
| 479 | |
| 480 | bool zero_is_variable = op_constants[0] == nullptr; |
| 481 | const analysis::Constant* c = ConstInput(op_constants); |
| 482 | uint32_t neg_id = NegateConstant(const_mgr, c); |
| 483 | uint32_t non_const_id = zero_is_variable |
| 484 | ? op_inst->GetSingleWordInOperand(0u) |
| 485 | : op_inst->GetSingleWordInOperand(1u); |
| 486 | // Change this instruction to a mul/div. |
| 487 | inst->SetOpcode(op_inst->opcode()); |
| 488 | if (opcode == spv::Op::OpFDiv || opcode == spv::Op::OpUDiv || |
| 489 | opcode == spv::Op::OpSDiv) { |
| 490 | uint32_t op0 = zero_is_variable ? non_const_id : neg_id; |
| 491 | uint32_t op1 = zero_is_variable ? neg_id : non_const_id; |
| 492 | inst->SetInOperands( |
| 493 | {{SPV_OPERAND_TYPE_ID, {op0}}, {SPV_OPERAND_TYPE_ID, {op1}}}); |
| 494 | } else { |
| 495 | inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {non_const_id}}, |
| 496 | {SPV_OPERAND_TYPE_ID, {neg_id}}}); |
| 497 | } |
| 498 | return true; |
| 499 | }; |
no test coverage detected