Generates C++ code within the 'write ' function to serialize the attributes of the given operation by calling the writeOpAttribute helper.
| 429 | /// Generates C++ code within the 'write<OpName>' function to serialize the |
| 430 | /// attributes of the given operation by calling the writeOpAttribute helper. |
| 431 | static void generateAttributeSerialization(const Operator &op, |
| 432 | raw_ostream &os) { |
| 433 | if (op.getNumAttributes() == 0) |
| 434 | return; |
| 435 | os << " // Serialize Attributes.\n"; |
| 436 | for (const auto &namedAttr : op.getAttributes()) { |
| 437 | StringRef attrName = namedAttr.name; |
| 438 | std::string getterName = op.getGetterName(attrName); |
| 439 | bool isOptional = namedAttr.attr.isOptional(); |
| 440 | bool isUnitAttr = |
| 441 | StringRef(namedAttr.attr.getStorageType()).contains("UnitAttr"); |
| 442 | if (isUnitAttr) { |
| 443 | // UnitAttr: only flags field, no serialization needed. |
| 444 | continue; |
| 445 | } else if (isOptional) { |
| 446 | // Optional non-UnitAttr: validation done by flags field, just serialize. |
| 447 | generateAttributeSerializationLogic(os, getterName, attrName); |
| 448 | } else { |
| 449 | // Required attributes: need version checking and default value |
| 450 | // validation. |
| 451 | auto [majorStr, minorStr] = extractVersionFromAttribute(namedAttr, op); |
| 452 | auto defaultValue = extractDefaultValue(namedAttr); |
| 453 | std::string version = majorStr + "." + minorStr; |
| 454 | |
| 455 | os << llvm::formatv(R"( |
| 456 | auto requiredVersionFor_{0} = BytecodeVersion::fromVersion({1}, {2}, 0); |
| 457 | assert(requiredVersionFor_{0} && "TableGen should guarantee valid versions"); |
| 458 | if (config.bytecodeVersion >= *requiredVersionFor_{0}) {{ |
| 459 | )", |
| 460 | attrName, majorStr, minorStr); |
| 461 | generateAttributeSerializationLogic(os, getterName, attrName, " "); |
| 462 | os << " } else {\n"; |
| 463 | if (defaultValue.has_value()) { |
| 464 | os << llvm::formatv(R"( |
| 465 | // Check that attribute equals default value for older versions. |
| 466 | auto nativeAttrValue_{0} = op.{1}(); |
| 467 | if (nativeAttrValue_{0} != {2}) {{ |
| 468 | op.emitError() << "attribute '{0}' requires bytecode version {3}+, but targeting " << config.bytecodeVersion.toString(); |
| 469 | return failure(); |
| 470 | } |
| 471 | )", |
| 472 | attrName, getterName, *defaultValue, version); |
| 473 | } else { |
| 474 | // No default value available. |
| 475 | std::string opVersion = extractVersionFromOperation(op); |
| 476 | if (version != opVersion) { |
| 477 | // Required attributes introduced after the operation must have |
| 478 | // default value. |
| 479 | PrintFatalError( |
| 480 | "Versioned attribute '" + namedAttr.name + "' in operation '" + |
| 481 | op.getOperationName() + "' (since " + version + |
| 482 | ") was introduced after the operation itself (since " + |
| 483 | opVersion + |
| 484 | ") and must have a default value for backward compatibility"); |
| 485 | } |
| 486 | // Note: Attributes introduced with the operation itself don't need |
| 487 | // defaults. |
| 488 | } |
no test coverage detected