Folds redundant add and sub ops that are part of an and. Cases handled: 1 & (b + 2) = b & 1 1 & (b - 2) = b & 1
| 3976 | // 1 & (b + 2) = b & 1 |
| 3977 | // 1 & (b - 2) = b & 1 |
| 3978 | FoldingRule RedundantAndAddSub() { |
| 3979 | return [](IRContext* context, Instruction* inst, |
| 3980 | const std::vector<const analysis::Constant*>& constants) { |
| 3981 | assert(inst->opcode() == spv::Op::OpBitwiseAnd && "Wrong opcode."); |
| 3982 | const analysis::Type* type = |
| 3983 | context->get_type_mgr()->GetType(inst->type_id()); |
| 3984 | uint32_t width = ElementWidth(type); |
| 3985 | if ((width != 32) && (width != 64)) return false; |
| 3986 | |
| 3987 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 3988 | const analysis::Constant* const_input1 = ConstInput(constants); |
| 3989 | if (!const_input1) return false; |
| 3990 | Instruction* other_inst = NonConstInput(context, constants[0], inst); |
| 3991 | |
| 3992 | if (other_inst->opcode() != spv::Op::OpIAdd && |
| 3993 | other_inst->opcode() != spv::Op::OpISub) { |
| 3994 | return false; |
| 3995 | } |
| 3996 | std::vector<const analysis::Constant*> other_constants = |
| 3997 | const_mgr->GetOperandConstants(other_inst); |
| 3998 | const analysis::Constant* const_input2 = ConstInput(other_constants); |
| 3999 | if (!const_input2) return false; |
| 4000 | |
| 4001 | // Only valid for subtraction if const is on the right |
| 4002 | if ((other_inst->opcode() == spv::Op::OpISub) && other_constants[0]) { |
| 4003 | return false; |
| 4004 | } |
| 4005 | |
| 4006 | bool can_remove_inner = true; |
| 4007 | ForEachIntegerConstantPair(const_mgr, const_input1, const_input2, |
| 4008 | [&can_remove_inner](auto and_op, auto add_op) { |
| 4009 | if (can_remove_inner) { |
| 4010 | // Only valid if no bits from the +/- could |
| 4011 | // affect bits from the & operation. |
| 4012 | can_remove_inner = |
| 4013 | utils::LSB(add_op) > and_op; |
| 4014 | } |
| 4015 | }); |
| 4016 | |
| 4017 | if (can_remove_inner) { |
| 4018 | Instruction* non_const_input = |
| 4019 | NonConstInput(context, other_constants[0], other_inst); |
| 4020 | Instruction* const_inst = const_mgr->GetDefiningInstruction(const_input1); |
| 4021 | inst->SetInOperands( |
| 4022 | {{SPV_OPERAND_TYPE_ID, {non_const_input->result_id()}}, |
| 4023 | {SPV_OPERAND_TYPE_ID, {const_inst->result_id()}}}); |
| 4024 | return true; |
| 4025 | } |
| 4026 | return false; |
| 4027 | }; |
| 4028 | } |
| 4029 | |
| 4030 | // Folds redundant shift ops that are part of an and. |
| 4031 | // Cases handled: |
no test coverage detected