Folds addition of a subtraction where each operation has a constant operand. Cases: (x - 2) + 2 = x + 0 (2 - x) + 2 = 4 - x 2 + (x - 2) = x + 0 2 + (2 - x) = 4 - x
| 1298 | // 2 + (x - 2) = x + 0 |
| 1299 | // 2 + (2 - x) = 4 - x |
| 1300 | FoldingRule MergeAddSubArithmetic() { |
| 1301 | return [](IRContext* context, Instruction* inst, |
| 1302 | const std::vector<const analysis::Constant*>& constants) { |
| 1303 | assert(inst->opcode() == spv::Op::OpFAdd || |
| 1304 | inst->opcode() == spv::Op::OpIAdd); |
| 1305 | const analysis::Type* type = |
| 1306 | context->get_type_mgr()->GetType(inst->type_id()); |
| 1307 | |
| 1308 | if (type->IsCooperativeMatrix()) { |
| 1309 | return false; |
| 1310 | } |
| 1311 | |
| 1312 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 1313 | bool uses_float = HasFloatingPoint(type); |
| 1314 | if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; |
| 1315 | |
| 1316 | uint32_t width = ElementWidth(type); |
| 1317 | if (width != 32 && width != 64) return false; |
| 1318 | |
| 1319 | const analysis::Constant* const_input1 = ConstInput(constants); |
| 1320 | if (!const_input1) return false; |
| 1321 | Instruction* other_inst = NonConstInput(context, constants[0], inst); |
| 1322 | if (uses_float && !other_inst->IsFloatingPointFoldingAllowed()) |
| 1323 | return false; |
| 1324 | |
| 1325 | if (other_inst->opcode() == spv::Op::OpFSub || |
| 1326 | other_inst->opcode() == spv::Op::OpISub) { |
| 1327 | std::vector<const analysis::Constant*> other_constants = |
| 1328 | const_mgr->GetOperandConstants(other_inst); |
| 1329 | const analysis::Constant* const_input2 = ConstInput(other_constants); |
| 1330 | if (!const_input2) return false; |
| 1331 | |
| 1332 | bool first_is_variable = other_constants[0] == nullptr; |
| 1333 | spv::Op op = inst->opcode(); |
| 1334 | uint32_t op1 = 0; |
| 1335 | uint32_t op2 = 0; |
| 1336 | if (first_is_variable) { |
| 1337 | // Subtract constants. Non-constant operand is first. |
| 1338 | op1 = other_inst->GetSingleWordInOperand(0u); |
| 1339 | op2 = PerformOperation(const_mgr, other_inst->opcode(), const_input1, |
| 1340 | const_input2); |
| 1341 | } else { |
| 1342 | // Add constants. Constant operand is first. Change the opcode. |
| 1343 | op1 = PerformOperation(const_mgr, inst->opcode(), const_input1, |
| 1344 | const_input2); |
| 1345 | op2 = other_inst->GetSingleWordInOperand(1u); |
| 1346 | op = other_inst->opcode(); |
| 1347 | } |
| 1348 | if (op1 == 0 || op2 == 0) return false; |
| 1349 | |
| 1350 | inst->SetOpcode(op); |
| 1351 | inst->SetInOperands( |
| 1352 | {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}); |
| 1353 | return true; |
| 1354 | } |
| 1355 | return false; |
| 1356 | }; |
| 1357 | } |
no test coverage detected