Validates all opcode assignments for consistency and correctness. Checks: - Opcode values are within designated ranges for each opcode class. - No duplicate opcode values across all assignments. - No duplicate operation assignments. - Opcode class matches operation type.
| 66 | /// - No duplicate operation assignments. |
| 67 | /// - Opcode class matches operation type. |
| 68 | static void |
| 69 | validateAllOpcodeAssignments(const RecordKeeper &records, |
| 70 | ArrayRef<const Record *> opcodeRecords) { |
| 71 | // Track seen opcode values and operations to detect duplicates. |
| 72 | llvm::DenseMap<unsigned, const Record *> seenOpcodes; |
| 73 | llvm::DenseMap<StringRef, const Record *> seenOperations; |
| 74 | llvm::DenseSet<StringRef> opsWithOpcodes; |
| 75 | |
| 76 | for (const Record *record : opcodeRecords) { |
| 77 | const Record *opRecord = record->getValueAsDef("operation"); |
| 78 | unsigned opcodeValue = record->getValueAsInt("opcodeValue"); |
| 79 | StringRef opName = opRecord->getName(); |
| 80 | |
| 81 | // Check for duplicate opcode values. |
| 82 | if (auto it = seenOpcodes.find(opcodeValue); it != seenOpcodes.end()) { |
| 83 | PrintFatalError( |
| 84 | record->getLoc(), |
| 85 | "duplicate opcode value 0x" + llvm::utohexstr(opcodeValue) + |
| 86 | " - already assigned to operation in " + it->second->getName()); |
| 87 | } |
| 88 | seenOpcodes[opcodeValue] = record; |
| 89 | |
| 90 | // Check for duplicate operation assignments. |
| 91 | if (auto it = seenOperations.find(opName); it != seenOperations.end()) { |
| 92 | PrintFatalError(record->getLoc(), |
| 93 | "operation '" + opName + |
| 94 | "' has multiple opcode assignments - already " |
| 95 | "assigned in " + |
| 96 | it->second->getName()); |
| 97 | } |
| 98 | seenOperations[opName] = record; |
| 99 | opsWithOpcodes.insert(opName); |
| 100 | |
| 101 | // Validate opcode ranges and operation type consistency. |
| 102 | if (record->isSubClassOf("PublicOpcode")) { |
| 103 | auto publicRange = getOpcodeRange(records, "PublicOpcodeRange"); |
| 104 | auto testingRange = getOpcodeRange(records, "TestingOpcodeRange"); |
| 105 | |
| 106 | // Public opcodes must be in public range or testing range. |
| 107 | auto inRange = [&](auto &range) { |
| 108 | return range && opcodeValue >= range->first && |
| 109 | opcodeValue <= range->second; |
| 110 | }; |
| 111 | |
| 112 | if (!inRange(publicRange) && !inRange(testingRange)) { |
| 113 | std::string rangeMsg = "PublicOpcode value 0x" + |
| 114 | llvm::utohexstr(opcodeValue) + |
| 115 | " is out of range (must be "; |
| 116 | if (publicRange) |
| 117 | rangeMsg += "0x" + llvm::utohexstr(publicRange->first) + " - 0x" + |
| 118 | llvm::utohexstr(publicRange->second); |
| 119 | if (publicRange && testingRange) |
| 120 | rangeMsg += " or "; |
| 121 | if (testingRange) |
| 122 | rangeMsg += ">= 0x" + llvm::utohexstr(testingRange->first); |
| 123 | rangeMsg += ")"; |
| 124 | PrintFatalError(record->getLoc(), rangeMsg); |
| 125 | } |
no test coverage detected