| 59 | } |
| 60 | |
| 61 | void GcnDivergentFlow::divergeCode(GcnToken* token) |
| 62 | { |
| 63 | // Split the original instruction list into |
| 64 | // many small groups, each with same executing |
| 65 | // strategy. (divergent action) |
| 66 | // Then bracket them using ifs. |
| 67 | |
| 68 | auto& code = token->getCode(); |
| 69 | auto& insList = code.insList; |
| 70 | auto zeroScalarInst = makeClearInstruction(); |
| 71 | |
| 72 | // erase branch instruction, |
| 73 | // it's no longer needed. |
| 74 | const auto& lastInst = insList.back(); |
| 75 | if (isBranchInstruction(lastInst)) |
| 76 | { |
| 77 | insList.pop_back(); |
| 78 | } |
| 79 | |
| 80 | // record the insert position |
| 81 | auto insertPtr = token->getIterator(); |
| 82 | |
| 83 | // Instruction group |
| 84 | // instructions in a same group have same divergent action |
| 85 | struct InstGroup |
| 86 | { |
| 87 | uint32_t pc; |
| 88 | GcnInstructionList insList; |
| 89 | }; |
| 90 | |
| 91 | InstGroup lastGroup; |
| 92 | InstGroup lastZsGroup; // last zero scalar group |
| 93 | GcnToken* lastIf = nullptr; |
| 94 | |
| 95 | auto insertCodeToken = [&](InstGroup&& group) |
| 96 | { |
| 97 | if (group.insList.empty()) |
| 98 | { |
| 99 | return; |
| 100 | } |
| 101 | |
| 102 | GcnTokenCode newCode = {}; |
| 103 | newCode.vertexId = code.vertexId; |
| 104 | newCode.pc = group.pc; |
| 105 | newCode.insList = std::move(group.insList); |
| 106 | auto codeToken = m_factory.createCode(std::move(newCode)); |
| 107 | insertPtr = m_tokens->insertAfter(insertPtr, codeToken); |
| 108 | }; |
| 109 | |
| 110 | auto resetPc = [](InstGroup& group, uint32_t pc) |
| 111 | { |
| 112 | if (group.insList.empty()) |
| 113 | { |
| 114 | group.pc = pc; |
| 115 | } |
| 116 | }; |
| 117 | |
| 118 | auto openScope = [&]() |
nothing calls this directly
no test coverage detected