Generates the flags field serialization for optional attributes and operands. Version checking is only done for optional attributes and operands. The flags field is a varint that uses individual bits to encode the presence of optional attributes and operands. The bit layout is version-ordered to ensure backward compatibility: - Bits are assigned in version order (earliest versions first) - Within
| 261 | /// Special case: UnitAttr presence is ONLY encoded in the flags field. |
| 262 | /// No actual attribute data is written to the stream for UnitAttr. |
| 263 | static void generateFlagsFieldSerialization(const Operator &op, |
| 264 | raw_ostream &os) { |
| 265 | // Get version-ordered bit assignments and earliest optional field version. |
| 266 | auto [bitAssignments, minOptionalVersion] = |
| 267 | getVersionOrderedBitAssignments(op); |
| 268 | if (bitAssignments.empty()) |
| 269 | return; |
| 270 | |
| 271 | std::string opVersion = extractVersionFromOperation(op); |
| 272 | os << " // Write flags field for optional attributes/operands.\n" |
| 273 | << " uint64_t flags = 0;\n"; |
| 274 | |
| 275 | // Set flags bits for optional attributes and validate their versions. |
| 276 | for (const auto &namedAttr : op.getAttributes()) { |
| 277 | if (namedAttr.attr.isOptional()) { |
| 278 | StringRef attrName = namedAttr.name; |
| 279 | std::string getterName = op.getGetterName(attrName); |
| 280 | size_t bitPos = bitAssignments.lookup(attrName); |
| 281 | |
| 282 | auto [majorStr, minorStr] = extractVersionFromAttribute(namedAttr, op); |
| 283 | std::string version = majorStr + "." + minorStr; |
| 284 | |
| 285 | if (version == opVersion) { |
| 286 | // Attribute from original operation - simple flag setting. |
| 287 | os << llvm::formatv(R"( |
| 288 | auto flagsAttrValue_{0} = op.{1}(); |
| 289 | if (flagsAttrValue_{0}) flags |= (1ULL << {2}); |
| 290 | )", |
| 291 | attrName, getterName, bitPos); |
| 292 | } else { |
| 293 | // Versioned attribute - validate version compatibility. |
| 294 | os << llvm::formatv(R"( |
| 295 | auto flagsAttrValue_{0} = op.{1}(); |
| 296 | if (flagsAttrValue_{0}) {{ |
| 297 | auto flagsRequiredVersionFor_{0} = BytecodeVersion::fromVersion({2}, {3}, 0); |
| 298 | assert(flagsRequiredVersionFor_{0} && "TableGen should guarantee valid versions"); |
| 299 | if (config.bytecodeVersion < *flagsRequiredVersionFor_{0}) {{ |
| 300 | op.emitError() << "optional attribute '{0}' is provided but requires bytecode version {4}, targeting " << config.bytecodeVersion.toString(); |
| 301 | return failure(); |
| 302 | } |
| 303 | // Attribute provided and compatible - set flag. |
| 304 | flags |= (1ULL << {5}); |
| 305 | } |
| 306 | // Attribute not provided - don't set flag. |
| 307 | )", |
| 308 | attrName, getterName, majorStr, minorStr, version, |
| 309 | bitPos); |
| 310 | } |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | // Set flags bits for optional operands and validate them. |
| 315 | if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) { |
| 316 | for (const auto &[operandIndex, odsOperand] : |
| 317 | llvm::enumerate(op.getOperands())) { |
| 318 | if (!odsOperand.isOptional() |
| 319 | ) { |
| 320 | // Validate that required operands were introduced with the operation |
no test coverage detected