Reassociate add/sub instructions, which have add/sub inputs, both of which contain a constant. e.g: (a + C0) - (C1 - b) = (C0 - C1) + (a + b) (C0 - a) + (b - C1) = (C0 - C1) + (b - a) (a - C0) - (b + C1) = (-C0 - C1) + (a - b)
| 1876 | // (C0 - a) + (b - C1) = (C0 - C1) + (b - a) |
| 1877 | // (a - C0) - (b + C1) = (-C0 - C1) + (a - b) |
| 1878 | FoldingRule ReassociateNestedAddSub() { |
| 1879 | return [](IRContext* context, Instruction* inst, |
| 1880 | const std::vector<const analysis::Constant*>& constants) { |
| 1881 | assert(inst->opcode() == spv::Op::OpFAdd || |
| 1882 | inst->opcode() == spv::Op::OpIAdd || |
| 1883 | inst->opcode() == spv::Op::OpFSub || |
| 1884 | inst->opcode() == spv::Op::OpISub); |
| 1885 | |
| 1886 | // Handled by other folding rules. |
| 1887 | if (constants[0] || constants[1]) { |
| 1888 | return false; |
| 1889 | } |
| 1890 | |
| 1891 | const analysis::Type* type = |
| 1892 | context->get_type_mgr()->GetType(inst->type_id()); |
| 1893 | |
| 1894 | if (type->IsCooperativeMatrix()) { |
| 1895 | return false; |
| 1896 | } |
| 1897 | |
| 1898 | uint32_t width = ElementWidth(type); |
| 1899 | if (width != 32 && width != 64) return false; |
| 1900 | |
| 1901 | bool uses_float = HasFloatingPoint(type); |
| 1902 | if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; |
| 1903 | |
| 1904 | analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| 1905 | Instruction* lhs = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| 1906 | Instruction* rhs = def_use_mgr->GetDef(inst->GetSingleWordInOperand(1)); |
| 1907 | |
| 1908 | spv::Op add_op = uses_float ? spv::Op::OpFAdd : spv::Op::OpIAdd; |
| 1909 | spv::Op sub_op = uses_float ? spv::Op::OpFSub : spv::Op::OpISub; |
| 1910 | |
| 1911 | bool lhs_is_add = lhs->opcode() == add_op; |
| 1912 | bool lhs_is_sub = lhs->opcode() == sub_op; |
| 1913 | bool rhs_is_add = rhs->opcode() == add_op; |
| 1914 | bool rhs_is_sub = rhs->opcode() == sub_op; |
| 1915 | if (!(lhs_is_add || lhs_is_sub) || !(rhs_is_add || rhs_is_sub)) { |
| 1916 | return false; |
| 1917 | } |
| 1918 | |
| 1919 | if (uses_float && (!lhs->IsFloatingPointFoldingAllowed() || |
| 1920 | !rhs->IsFloatingPointFoldingAllowed())) { |
| 1921 | return false; |
| 1922 | } |
| 1923 | |
| 1924 | analysis::ConstantManager* const_mgr = context->get_constant_mgr(); |
| 1925 | std::vector<const analysis::Constant*> lhs_constants = |
| 1926 | const_mgr->GetOperandConstants(lhs); |
| 1927 | if (!lhs_constants[0] && !lhs_constants[1]) { |
| 1928 | return false; |
| 1929 | } |
| 1930 | |
| 1931 | std::vector<const analysis::Constant*> rhs_constants = |
| 1932 | const_mgr->GetOperandConstants(rhs); |
| 1933 | if (!rhs_constants[0] && !rhs_constants[1]) { |
| 1934 | return false; |
| 1935 | } |
no test coverage detected