| 277 | } |
| 278 | |
| 279 | spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { |
| 280 | const auto merge_id = inst->GetOperandAs<uint32_t>(0); |
| 281 | const auto merge = _.FindDef(merge_id); |
| 282 | if (!merge || merge->opcode() != spv::Op::OpLabel) { |
| 283 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 284 | << "Merge Block " << _.getIdName(merge_id) << " must be an OpLabel"; |
| 285 | } |
| 286 | if (merge_id == inst->block()->id()) { |
| 287 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 288 | << "Merge Block may not be the block containing the OpLoopMerge\n"; |
| 289 | } |
| 290 | |
| 291 | const auto continue_id = inst->GetOperandAs<uint32_t>(1); |
| 292 | const auto continue_target = _.FindDef(continue_id); |
| 293 | if (!continue_target || continue_target->opcode() != spv::Op::OpLabel) { |
| 294 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 295 | << "Continue Target " << _.getIdName(continue_id) |
| 296 | << " must be an OpLabel"; |
| 297 | } |
| 298 | |
| 299 | if (merge_id == continue_id) { |
| 300 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 301 | << "Merge Block and Continue Target must be different ids"; |
| 302 | } |
| 303 | |
| 304 | const auto loop_control = inst->GetOperandAs<spv::LoopControlShift>(2); |
| 305 | if ((loop_control >> spv::LoopControlShift::Unroll) & 0x1 && |
| 306 | (loop_control >> spv::LoopControlShift::DontUnroll) & 0x1) { |
| 307 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 308 | << "Unroll and DontUnroll loop controls must not both be specified"; |
| 309 | } |
| 310 | if ((loop_control >> spv::LoopControlShift::DontUnroll) & 0x1 && |
| 311 | (loop_control >> spv::LoopControlShift::PeelCount) & 0x1) { |
| 312 | return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PeelCount and DontUnroll " |
| 313 | "loop controls must not " |
| 314 | "both be specified"; |
| 315 | } |
| 316 | if ((loop_control >> spv::LoopControlShift::DontUnroll) & 0x1 && |
| 317 | (loop_control >> spv::LoopControlShift::PartialCount) & 0x1) { |
| 318 | return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PartialCount and " |
| 319 | "DontUnroll loop controls " |
| 320 | "must not both be specified"; |
| 321 | } |
| 322 | |
| 323 | uint32_t operand = 3; |
| 324 | if ((loop_control >> spv::LoopControlShift::DependencyLength) & 0x1) { |
| 325 | ++operand; |
| 326 | } |
| 327 | if ((loop_control >> spv::LoopControlShift::MinIterations) & 0x1) { |
| 328 | ++operand; |
| 329 | } |
| 330 | if ((loop_control >> spv::LoopControlShift::MaxIterations) & 0x1) { |
| 331 | ++operand; |
| 332 | } |
| 333 | if ((loop_control >> spv::LoopControlShift::IterationMultiple) & 0x1) { |
| 334 | if (inst->operands().size() < operand || |
| 335 | inst->GetOperandAs<uint32_t>(operand) == 0) { |
| 336 | return _.diag(SPV_ERROR_INVALID_DATA, inst) << "IterationMultiple loop " |