| 133 | } |
| 134 | |
| 135 | vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vertex_program(const u32* data, u32 entry, RSXVertexProgram& dst_prog) |
| 136 | { |
| 137 | vertex_program_utils::vertex_program_metadata result{}; |
| 138 | // u32 last_instruction_address = 0; |
| 139 | // u32 first_instruction_address = entry; |
| 140 | |
| 141 | std::bitset<rsx::max_vertex_program_instructions> instructions_to_patch; |
| 142 | std::pair<u32, u32> instruction_range{umax, 0}; |
| 143 | bool has_branch_instruction = false; |
| 144 | std::stack<u32> call_stack; |
| 145 | |
| 146 | D3 d3{}; |
| 147 | D2 d2{}; |
| 148 | D1 d1{}; |
| 149 | D0 d0{}; |
| 150 | |
| 151 | std::function<void(u32, bool)> walk_function = [&](u32 start, bool fast_exit) |
| 152 | { |
| 153 | u32 current_instruction = start; |
| 154 | std::set<u32> conditional_targets; |
| 155 | |
| 156 | while (true) |
| 157 | { |
| 158 | ensure(current_instruction < rsx::max_vertex_program_instructions); |
| 159 | |
| 160 | if (result.instruction_mask[current_instruction]) |
| 161 | { |
| 162 | if (!fast_exit) |
| 163 | { |
| 164 | // This can be harmless if a dangling RET was encountered before. |
| 165 | // This can also be legal in case of BRB...BRI loops since BRIs are conditional. Might just be a loop with exit cond. |
| 166 | rsx_log.warning("vp_analyser: Possible infinite loop detected"); |
| 167 | } |
| 168 | |
| 169 | // There is never any reason to continue scanning after self-intersecting on the control-flow tree. |
| 170 | break; |
| 171 | } |
| 172 | |
| 173 | const auto instruction = v128::loadu(&data[current_instruction * 4]); |
| 174 | d1.HEX = instruction._u32[1]; |
| 175 | d2.HEX = instruction._u32[2]; |
| 176 | d3.HEX = instruction._u32[3]; |
| 177 | |
| 178 | // Touch current instruction |
| 179 | result.instruction_mask[current_instruction] = true; |
| 180 | instruction_range.first = std::min(current_instruction, instruction_range.first); |
| 181 | instruction_range.second = std::max(current_instruction, instruction_range.second); |
| 182 | |
| 183 | // Whether to check if the current instruction references an input stream |
| 184 | auto input_attribute_ref = [&]() |
| 185 | { |
| 186 | if (!d1.input_src) |
| 187 | { |
| 188 | // It is possible to reference ATTR0, but this is mandatory anyway. No need to explicitly test for it |
| 189 | return; |
| 190 | } |
| 191 | |
| 192 | const auto ref_mask = (1u << d1.input_src); |
nothing calls this directly
no test coverage detected