Use dataflow analysis on each parameter to see if there are uses that would be problematic when generating input data. Returns the list of instructions that correspond to their uses. Should be paired with the CreateLiteralForConstrainedUses() function below.
| 499 | // |
| 500 | // Should be paired with the CreateLiteralForConstrainedUses() function below. |
| 501 | std::vector<HloInstruction*> FindConstrainedUses( |
| 502 | const HloDataflowAnalysis& dataflow, const HloInstruction& param) { |
| 503 | std::vector<HloInstruction*> constrained_uses; |
| 504 | for (const auto& pair : dataflow.GetInstructionValueSet(¶m)) { |
| 505 | const HloValue& value = dataflow.GetUniqueValueAt(¶m, pair.first); |
| 506 | for (const HloUse& use : value.uses()) { |
| 507 | HloInstruction* instruction = use.instruction; |
| 508 | const HloOpcode opcode = instruction->opcode(); |
| 509 | const int64 op_num = use.operand_number; |
| 510 | if ((opcode == HloOpcode::kDynamicSlice && op_num >= 1) || |
| 511 | (opcode == HloOpcode::kDynamicUpdateSlice && op_num >= 2)) { |
| 512 | constrained_uses.push_back(instruction); |
| 513 | } else if ((opcode == HloOpcode::kGather || |
| 514 | opcode == HloOpcode::kScatter) && |
| 515 | op_num == 1) { |
| 516 | constrained_uses.push_back(instruction); |
| 517 | } else if (opcode == HloOpcode::kFusion) { |
| 518 | const HloInstruction* const to_analyze = |
| 519 | instruction->fused_parameter(op_num); |
| 520 | auto fused_uses = FindConstrainedUses(dataflow, *to_analyze); |
| 521 | constrained_uses.insert(constrained_uses.end(), fused_uses.begin(), |
| 522 | fused_uses.end()); |
| 523 | } else if (NeedsInitValue(use)) { |
| 524 | constrained_uses.push_back(instruction); |
| 525 | } else if (opcode == HloOpcode::kConvert || |
| 526 | opcode == HloOpcode::kReducePrecision) { |
| 527 | auto converted_uses = FindConstrainedUses(dataflow, *instruction); |
| 528 | constrained_uses.insert(constrained_uses.end(), converted_uses.begin(), |
| 529 | converted_uses.end()); |
| 530 | } else if (opcode == HloOpcode::kSort && |
| 531 | instruction->operand_count() >= 2 && op_num == 0) { |
| 532 | // Operand 0 of sort is the array of keys used for key/value |
| 533 | // (two-operand) kSort instructions. Since sort stability is not |
| 534 | // guaranteed, constrain keys of key-value sort not to have duplicates, |
| 535 | // since otherwise the value order may legitimately differ. |
| 536 | constrained_uses.push_back(instruction); |
| 537 | } |
| 538 | } |
| 539 | } |
| 540 | return constrained_uses; |
| 541 | } |
| 542 | |
| 543 | // Given a parameter, generate a random Literal to use as input if there exist |
| 544 | // no constrained uses in the dataflow graph. If such constraints exist, |
no test coverage detected