前回の解析に基づき、FIRRTLのParseを続けている。
Circuit
を構築すると、MLIRで作成したCircitOp
を構築するようだ。
/// file ::= circuit /// circuit ::= 'circuit' id ':' info? INDENT module* DEDENT EOF /// ParseResult FIRCircuitParser::parseCircuit() { /* ... 中略 ... */ OpBuilder b(mlirModule.getBodyRegion()); // Create the top-level circuit op in the MLIR module. auto circuit = b.create<CircuitOp>(info.getLoc(), name, annotationVec);
CircitOp
をOpBuilder
を使って構築する。CircuitOp
はTarget Descriptionを使って構築しているようだ。
circt/include/circt/Dialect/FIRRTL/FIRRTLStructure.td
def CircuitOp : FIRRTLOp<"circuit", [IsolatedFromAbove, SymbolTable, SingleBlockImplicitTerminator<"DoneOp">]> { let summary = "FIRRTL Circuit"; let description = [{ The "firrtl.circuit" operation represents an overall Verilog circuit, containing a list of modules. }]; /* ... 中略 ... */
これはTarget Descriptionにより、circt/Dialect/FIRRTL/FIRRTL.h.inc
に変換されている。
class CircuitOp : public ::mlir::Op<CircuitOp, ::mlir::OpTrait::OneRegion, ::mlir::OpTrait::ZeroResult, ::mlir::OpTrait::ZeroSuccessor, ::mlir::OpTrait::ZeroOperands, ::mlir::OpTrait::IsIsolatedFromAbove, ::mlir::OpTrait::SymbolTable, ::mlir::OpTrait::SingleBlockImplic\ itTerminator<DoneOp>::Impl> { public: using Op::Op; using Op::print; using Adaptor = CircuitOpAdaptor; static constexpr ::llvm::StringLiteral getOperationName() { return ::llvm::StringLiteral("firrtl.circuit"); } std::pair<unsigned, unsigned> getODSOperandIndexAndLength(unsigned index); ::mlir::Operation::operand_range getODSOperands(unsigned index); std::pair<unsigned, unsigned> getODSResultIndexAndLength(unsigned index); ::mlir::Operation::result_range getODSResults(unsigned index); ::mlir::Region &body(); ::mlir::StringAttr nameAttr(); ::llvm::StringRef name(); ::mlir::ArrayAttr annotationsAttr(); ::mlir::ArrayAttr annotations(); void nameAttr(::mlir::StringAttr attr); void annotationsAttr(::mlir::ArrayAttr attr); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, StringAttr name, ArrayAttr annotations = ArrayAttr()); static ::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result); void print(::mlir::OpAsmPrinter &p); ::mlir::LogicalResult verify(); /* ... ここの部分はTarget Descriptionからそのまま引用されてきている ... */ OpBuilder getBodyBuilder() { assert(!body().empty() && "Unexpected empty 'body' region."); Block &bodyBlock = body().front(); return OpBuilder(&bodyBlock, std::prev(bodyBlock.end())); } /// Return body of this circuit. Region &getBodyRegion(); Block *getBody(); // Return the main module that is the entry point of the circuit. This may // be either an FModuleOp or an FExtModuleOp. Operation *getMainModule(); /* ... Target Description の引用ここまでで終わり ... */ };
getBodyRegion()
, getBody()
は以下で定義されていた。
circt/lib/Dialect/FIRRTL/FIRRTLOps.cpp
Region &CircuitOp::getBodyRegion() { return getOperation()->getRegion(0); } Block *CircuitOp::getBody() { return &getBodyRegion().front(); }
Block
の定義は以下のようだ。
circt/llvm/mlir/include/mlir/IR/Block.h
/// `Block` represents an ordered list of `Operation`s. class Block : public IRObjectWithUseList<BlockOperand>, public llvm::ilist_node_with_parent<Block, Region> { public: explicit Block() {} ~Block(); void clear() { // Drop all references from within this block. /* ... 中略 ... */