Merges negate into a add or sub operation if that operation contains a constant operand. Cases: -(x + 2) = -2 - x -(2 + x) = -2 - x -(x - 2) = 2 - x -(2 - x) = x - 2
| 507 | // -(x - 2) = 2 - x |
| 508 | // -(2 - x) = x - 2 |
| 509 | FoldingRule MergeNegateAddSubArithmetic() { |
| 510 | return [](IRContext* context, Instruction* inst, |
| 511 | const std::vector<const analysis::Constant*>& constants) { |
| 512 | assert(inst->opcode() == spv::Op::OpFNegate || |
| 513 | inst->opcode() == spv::Op::OpSNegate); |
| 514 | (void)constants; |
| 515 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 516 | const analysis::Type* type = |
| 517 | context->get_type_mgr()->GetType(inst->type_id()); |
| 518 | |
| 519 | if (type->IsCooperativeMatrix()) { |
| 520 | return false; |
| 521 | } |
| 522 | |
| 523 | if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed()) |
| 524 | return false; |
| 525 | |
| 526 | Instruction* op_inst = |
| 527 | context->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u)); |
| 528 | if (HasFloatingPoint(type) && !op_inst->IsFloatingPointFoldingAllowed()) |
| 529 | return false; |
| 530 | |
| 531 | uint32_t width = ElementWidth(type); |
| 532 | if (width != 32 && width != 64) return false; |
| 533 | |
| 534 | if (op_inst->opcode() == spv::Op::OpFAdd || |
| 535 | op_inst->opcode() == spv::Op::OpFSub || |
| 536 | op_inst->opcode() == spv::Op::OpIAdd || |
| 537 | op_inst->opcode() == spv::Op::OpISub) { |
| 538 | std::vector<const analysis::Constant*> op_constants = |
| 539 | const_mgr->GetOperandConstants(op_inst); |
| 540 | if (op_constants[0] || op_constants[1]) { |
| 541 | bool zero_is_variable = op_constants[0] == nullptr; |
| 542 | bool is_add = (op_inst->opcode() == spv::Op::OpFAdd) || |
| 543 | (op_inst->opcode() == spv::Op::OpIAdd); |
| 544 | bool swap_operands = !is_add || zero_is_variable; |
| 545 | bool negate_const = is_add; |
| 546 | const analysis::Constant* c = ConstInput(op_constants); |
| 547 | uint32_t const_id = 0; |
| 548 | if (negate_const) { |
| 549 | const_id = NegateConstant(const_mgr, c); |
| 550 | } else { |
| 551 | const_id = zero_is_variable ? op_inst->GetSingleWordInOperand(1u) |
| 552 | : op_inst->GetSingleWordInOperand(0u); |
| 553 | } |
| 554 | |
| 555 | // Swap operands if necessary and make the instruction a subtraction. |
| 556 | uint32_t op0 = |
| 557 | zero_is_variable ? op_inst->GetSingleWordInOperand(0u) : const_id; |
| 558 | uint32_t op1 = |
| 559 | zero_is_variable ? const_id : op_inst->GetSingleWordInOperand(1u); |
| 560 | if (swap_operands) std::swap(op0, op1); |
| 561 | inst->SetOpcode(HasFloatingPoint(type) ? spv::Op::OpFSub |
| 562 | : spv::Op::OpISub); |
| 563 | inst->SetInOperands( |
| 564 | {{SPV_OPERAND_TYPE_ID, {op0}}, {SPV_OPERAND_TYPE_ID, {op1}}}); |
| 565 | return true; |
| 566 | } |
no test coverage detected