MCPcopy Create free account
hub / github.com/KhronosGroup/SPIRV-Tools / MergeDivDivArithmetic

Function MergeDivDivArithmetic

source/opt/folding_rules.cpp:978–1043  ·  view source on GitHub ↗

Merges consecutive divides if each instruction contains one constant operand. Does not support integer division. Cases: 2 / (x / 2) = 4 / x 4 / (2 / x) = 2 * x (4 / x) / 2 = 2 / x (x / 2) / 2 = x / 4

Source from the content-addressed store, hash-verified

976// (4 / x) / 2 = 2 / x
977// (x / 2) / 2 = x / 4
978FoldingRule MergeDivDivArithmetic() {
979 return [](IRContext* context, Instruction* inst,
980 const std::vector<const analysis::Constant*>& constants) {
981 assert(inst->opcode() == spv::Op::OpFDiv);
982 analysis::ConstantManager* const_mgr = context->get_constant_mgr();
983 const analysis::Type* type =
984 context->get_type_mgr()->GetType(inst->type_id());
985
986 if (type->IsCooperativeMatrix()) {
987 return false;
988 }
989
990 if (!inst->IsFloatingPointFoldingAllowed()) return false;
991
992 uint32_t width = ElementWidth(type);
993 if (width != 32 && width != 64) return false;
994
995 const analysis::Constant* const_input1 = ConstInput(constants);
996 if (!const_input1 || HasZero(const_input1)) return false;
997 Instruction* other_inst = NonConstInput(context, constants[0], inst);
998 if (!other_inst->IsFloatingPointFoldingAllowed()) return false;
999
1000 bool first_is_variable = constants[0] == nullptr;
1001 if (other_inst->opcode() == inst->opcode()) {
1002 std::vector<const analysis::Constant*> other_constants =
1003 const_mgr->GetOperandConstants(other_inst);
1004 const analysis::Constant* const_input2 = ConstInput(other_constants);
1005 if (!const_input2 || HasZero(const_input2)) return false;
1006
1007 bool other_first_is_variable = other_constants[0] == nullptr;
1008
1009 spv::Op merge_op = inst->opcode();
1010 if (other_first_is_variable) {
1011 // Constants magnify.
1012 merge_op = spv::Op::OpFMul;
1013 }
1014
1015 // This is an x / (*) case. Swap the inputs. Doesn't harm multiply
1016 // because it is commutative.
1017 if (first_is_variable) std::swap(const_input1, const_input2);
1018 uint32_t merged_id =
1019 PerformOperation(const_mgr, merge_op, const_input1, const_input2);
1020 if (merged_id == 0) return false;
1021
1022 uint32_t non_const_id = other_first_is_variable
1023 ? other_inst->GetSingleWordInOperand(0u)
1024 : other_inst->GetSingleWordInOperand(1u);
1025
1026 spv::Op op = inst->opcode();
1027 if (!first_is_variable && !other_first_is_variable) {
1028 // Effectively div of 1/x, so change to multiply.
1029 op = spv::Op::OpFMul;
1030 }
1031
1032 uint32_t op1 = merged_id;
1033 uint32_t op2 = non_const_id;
1034 if (first_is_variable && other_first_is_variable) std::swap(op1, op2);
1035 inst->SetOpcode(op);

Callers 1

AddFoldingRulesMethod · 0.85

Calls 15

ElementWidthFunction · 0.85
ConstInputFunction · 0.85
HasZeroFunction · 0.85
NonConstInputFunction · 0.85
PerformOperationFunction · 0.85
get_constant_mgrMethod · 0.80
get_type_mgrMethod · 0.80
IsCooperativeMatrixMethod · 0.80
GetOperandConstantsMethod · 0.80
SetOpcodeMethod · 0.80

Tested by

no test coverage detected