195b4e88bSRiver Riddle //===- MLIRGen.cpp --------------------------------------------------------===//
295b4e88bSRiver Riddle //
395b4e88bSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
495b4e88bSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
595b4e88bSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
695b4e88bSRiver Riddle //
795b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
895b4e88bSRiver Riddle
995b4e88bSRiver Riddle #include "mlir/Tools/PDLL/CodeGen/MLIRGen.h"
10c60b897dSRiver Riddle #include "mlir/AsmParser/AsmParser.h"
1195b4e88bSRiver Riddle #include "mlir/Dialect/PDL/IR/PDL.h"
1295b4e88bSRiver Riddle #include "mlir/Dialect/PDL/IR/PDLOps.h"
1395b4e88bSRiver Riddle #include "mlir/Dialect/PDL/IR/PDLTypes.h"
1495b4e88bSRiver Riddle #include "mlir/IR/Builders.h"
1595b4e88bSRiver Riddle #include "mlir/IR/BuiltinOps.h"
1695b4e88bSRiver Riddle #include "mlir/IR/Verifier.h"
1795b4e88bSRiver Riddle #include "mlir/Tools/PDLL/AST/Context.h"
1895b4e88bSRiver Riddle #include "mlir/Tools/PDLL/AST/Nodes.h"
1995b4e88bSRiver Riddle #include "mlir/Tools/PDLL/AST/Types.h"
2081f2f4dfSRiver Riddle #include "mlir/Tools/PDLL/ODS/Context.h"
2181f2f4dfSRiver Riddle #include "mlir/Tools/PDLL/ODS/Operation.h"
2295b4e88bSRiver Riddle #include "llvm/ADT/ScopedHashTable.h"
2395b4e88bSRiver Riddle #include "llvm/ADT/StringExtras.h"
2495b4e88bSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
25a1fe1f5fSKazu Hirata #include <optional>
2695b4e88bSRiver Riddle
2795b4e88bSRiver Riddle using namespace mlir;
2895b4e88bSRiver Riddle using namespace mlir::pdll;
2995b4e88bSRiver Riddle
3095b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
3195b4e88bSRiver Riddle // CodeGen
3295b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
3395b4e88bSRiver Riddle
3495b4e88bSRiver Riddle namespace {
3595b4e88bSRiver Riddle class CodeGen {
3695b4e88bSRiver Riddle public:
CodeGen(MLIRContext * mlirContext,const ast::Context & context,const llvm::SourceMgr & sourceMgr)3795b4e88bSRiver Riddle CodeGen(MLIRContext *mlirContext, const ast::Context &context,
3895b4e88bSRiver Riddle const llvm::SourceMgr &sourceMgr)
3981f2f4dfSRiver Riddle : builder(mlirContext), odsContext(context.getODSContext()),
4081f2f4dfSRiver Riddle sourceMgr(sourceMgr) {
4195b4e88bSRiver Riddle // Make sure that the PDL dialect is loaded.
4295b4e88bSRiver Riddle mlirContext->loadDialect<pdl::PDLDialect>();
4395b4e88bSRiver Riddle }
4495b4e88bSRiver Riddle
4595b4e88bSRiver Riddle OwningOpRef<ModuleOp> generate(const ast::Module &module);
4695b4e88bSRiver Riddle
4795b4e88bSRiver Riddle private:
4895b4e88bSRiver Riddle /// Generate an MLIR location from the given source location.
4995b4e88bSRiver Riddle Location genLoc(llvm::SMLoc loc);
genLoc(llvm::SMRange loc)5095b4e88bSRiver Riddle Location genLoc(llvm::SMRange loc) { return genLoc(loc.Start); }
5195b4e88bSRiver Riddle
5295b4e88bSRiver Riddle /// Generate an MLIR type from the given source type.
5395b4e88bSRiver Riddle Type genType(ast::Type type);
5495b4e88bSRiver Riddle
5595b4e88bSRiver Riddle /// Generate MLIR for the given AST node.
5695b4e88bSRiver Riddle void gen(const ast::Node *node);
5795b4e88bSRiver Riddle
5895b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
5995b4e88bSRiver Riddle // Statements
6095b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
6195b4e88bSRiver Riddle
6295b4e88bSRiver Riddle void genImpl(const ast::CompoundStmt *stmt);
6395b4e88bSRiver Riddle void genImpl(const ast::EraseStmt *stmt);
6495b4e88bSRiver Riddle void genImpl(const ast::LetStmt *stmt);
6595b4e88bSRiver Riddle void genImpl(const ast::ReplaceStmt *stmt);
6695b4e88bSRiver Riddle void genImpl(const ast::RewriteStmt *stmt);
6795b4e88bSRiver Riddle void genImpl(const ast::ReturnStmt *stmt);
6895b4e88bSRiver Riddle
6995b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
7095b4e88bSRiver Riddle // Decls
7195b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
7295b4e88bSRiver Riddle
7395b4e88bSRiver Riddle void genImpl(const ast::UserConstraintDecl *decl);
7495b4e88bSRiver Riddle void genImpl(const ast::UserRewriteDecl *decl);
7595b4e88bSRiver Riddle void genImpl(const ast::PatternDecl *decl);
7695b4e88bSRiver Riddle
7795b4e88bSRiver Riddle /// Generate the set of MLIR values defined for the given variable decl, and
7895b4e88bSRiver Riddle /// apply any attached constraints.
7995b4e88bSRiver Riddle SmallVector<Value> genVar(const ast::VariableDecl *varDecl);
8095b4e88bSRiver Riddle
8195b4e88bSRiver Riddle /// Generate the value for a variable that does not have an initializer
8295b4e88bSRiver Riddle /// expression, i.e. create the PDL value based on the type/constraints of the
8395b4e88bSRiver Riddle /// variable.
8495b4e88bSRiver Riddle Value genNonInitializerVar(const ast::VariableDecl *varDecl, Location loc);
8595b4e88bSRiver Riddle
8695b4e88bSRiver Riddle /// Apply the constraints of the given variable to `values`, which correspond
8795b4e88bSRiver Riddle /// to the MLIR values of the variable.
8895b4e88bSRiver Riddle void applyVarConstraints(const ast::VariableDecl *varDecl, ValueRange values);
8995b4e88bSRiver Riddle
9095b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
9195b4e88bSRiver Riddle // Expressions
9295b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
9395b4e88bSRiver Riddle
9495b4e88bSRiver Riddle Value genSingleExpr(const ast::Expr *expr);
9595b4e88bSRiver Riddle SmallVector<Value> genExpr(const ast::Expr *expr);
9695b4e88bSRiver Riddle Value genExprImpl(const ast::AttributeExpr *expr);
9795b4e88bSRiver Riddle SmallVector<Value> genExprImpl(const ast::CallExpr *expr);
9895b4e88bSRiver Riddle SmallVector<Value> genExprImpl(const ast::DeclRefExpr *expr);
9995b4e88bSRiver Riddle Value genExprImpl(const ast::MemberAccessExpr *expr);
10095b4e88bSRiver Riddle Value genExprImpl(const ast::OperationExpr *expr);
1019e57210aSRiver Riddle Value genExprImpl(const ast::RangeExpr *expr);
10295b4e88bSRiver Riddle SmallVector<Value> genExprImpl(const ast::TupleExpr *expr);
10395b4e88bSRiver Riddle Value genExprImpl(const ast::TypeExpr *expr);
10495b4e88bSRiver Riddle
10595b4e88bSRiver Riddle SmallVector<Value> genConstraintCall(const ast::UserConstraintDecl *decl,
106930916c7SMogball Location loc, ValueRange inputs,
107930916c7SMogball bool isNegated = false);
10895b4e88bSRiver Riddle SmallVector<Value> genRewriteCall(const ast::UserRewriteDecl *decl,
10995b4e88bSRiver Riddle Location loc, ValueRange inputs);
11095b4e88bSRiver Riddle template <typename PDLOpT, typename T>
11195b4e88bSRiver Riddle SmallVector<Value> genConstraintOrRewriteCall(const T *decl, Location loc,
112930916c7SMogball ValueRange inputs,
113930916c7SMogball bool isNegated = false);
11495b4e88bSRiver Riddle
11595b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
11695b4e88bSRiver Riddle // Fields
11795b4e88bSRiver Riddle //===--------------------------------------------------------------------===//
11895b4e88bSRiver Riddle
11995b4e88bSRiver Riddle /// The MLIR builder used for building the resultant IR.
12095b4e88bSRiver Riddle OpBuilder builder;
12195b4e88bSRiver Riddle
12295b4e88bSRiver Riddle /// A map from variable declarations to the MLIR equivalent.
12395b4e88bSRiver Riddle using VariableMapTy =
12495b4e88bSRiver Riddle llvm::ScopedHashTable<const ast::VariableDecl *, SmallVector<Value>>;
12595b4e88bSRiver Riddle VariableMapTy variables;
12695b4e88bSRiver Riddle
12781f2f4dfSRiver Riddle /// A reference to the ODS context.
12881f2f4dfSRiver Riddle const ods::Context &odsContext;
12981f2f4dfSRiver Riddle
13095b4e88bSRiver Riddle /// The source manager of the PDLL ast.
13195b4e88bSRiver Riddle const llvm::SourceMgr &sourceMgr;
13295b4e88bSRiver Riddle };
13395b4e88bSRiver Riddle } // namespace
13495b4e88bSRiver Riddle
generate(const ast::Module & module)13595b4e88bSRiver Riddle OwningOpRef<ModuleOp> CodeGen::generate(const ast::Module &module) {
13695b4e88bSRiver Riddle OwningOpRef<ModuleOp> mlirModule =
13795b4e88bSRiver Riddle builder.create<ModuleOp>(genLoc(module.getLoc()));
13895b4e88bSRiver Riddle builder.setInsertionPointToStart(mlirModule->getBody());
13995b4e88bSRiver Riddle
14095b4e88bSRiver Riddle // Generate code for each of the decls within the module.
14195b4e88bSRiver Riddle for (const ast::Decl *decl : module.getChildren())
14295b4e88bSRiver Riddle gen(decl);
14395b4e88bSRiver Riddle
14495b4e88bSRiver Riddle return mlirModule;
14595b4e88bSRiver Riddle }
14695b4e88bSRiver Riddle
genLoc(llvm::SMLoc loc)14795b4e88bSRiver Riddle Location CodeGen::genLoc(llvm::SMLoc loc) {
14895b4e88bSRiver Riddle unsigned fileID = sourceMgr.FindBufferContainingLoc(loc);
14995b4e88bSRiver Riddle
15095b4e88bSRiver Riddle // TODO: Fix performance issues in SourceMgr::getLineAndColumn so that we can
15195b4e88bSRiver Riddle // use it here.
15295b4e88bSRiver Riddle auto &bufferInfo = sourceMgr.getBufferInfo(fileID);
15395b4e88bSRiver Riddle unsigned lineNo = bufferInfo.getLineNumber(loc.getPointer());
15495b4e88bSRiver Riddle unsigned column =
15595b4e88bSRiver Riddle (loc.getPointer() - bufferInfo.getPointerForLineNumber(lineNo)) + 1;
15695b4e88bSRiver Riddle auto *buffer = sourceMgr.getMemoryBuffer(fileID);
15795b4e88bSRiver Riddle
15895b4e88bSRiver Riddle return FileLineColLoc::get(builder.getContext(),
15995b4e88bSRiver Riddle buffer->getBufferIdentifier(), lineNo, column);
16095b4e88bSRiver Riddle }
16195b4e88bSRiver Riddle
genType(ast::Type type)16295b4e88bSRiver Riddle Type CodeGen::genType(ast::Type type) {
16395b4e88bSRiver Riddle return TypeSwitch<ast::Type, Type>(type)
16495b4e88bSRiver Riddle .Case([&](ast::AttributeType astType) -> Type {
16595b4e88bSRiver Riddle return builder.getType<pdl::AttributeType>();
16695b4e88bSRiver Riddle })
16795b4e88bSRiver Riddle .Case([&](ast::OperationType astType) -> Type {
16895b4e88bSRiver Riddle return builder.getType<pdl::OperationType>();
16995b4e88bSRiver Riddle })
17095b4e88bSRiver Riddle .Case([&](ast::TypeType astType) -> Type {
17195b4e88bSRiver Riddle return builder.getType<pdl::TypeType>();
17295b4e88bSRiver Riddle })
17395b4e88bSRiver Riddle .Case([&](ast::ValueType astType) -> Type {
17495b4e88bSRiver Riddle return builder.getType<pdl::ValueType>();
17595b4e88bSRiver Riddle })
17695b4e88bSRiver Riddle .Case([&](ast::RangeType astType) -> Type {
17795b4e88bSRiver Riddle return pdl::RangeType::get(genType(astType.getElementType()));
17895b4e88bSRiver Riddle });
17995b4e88bSRiver Riddle }
18095b4e88bSRiver Riddle
gen(const ast::Node * node)18195b4e88bSRiver Riddle void CodeGen::gen(const ast::Node *node) {
18295b4e88bSRiver Riddle TypeSwitch<const ast::Node *>(node)
18395b4e88bSRiver Riddle .Case<const ast::CompoundStmt, const ast::EraseStmt, const ast::LetStmt,
18495b4e88bSRiver Riddle const ast::ReplaceStmt, const ast::RewriteStmt,
18595b4e88bSRiver Riddle const ast::ReturnStmt, const ast::UserConstraintDecl,
18695b4e88bSRiver Riddle const ast::UserRewriteDecl, const ast::PatternDecl>(
18795b4e88bSRiver Riddle [&](auto derivedNode) { this->genImpl(derivedNode); })
18895b4e88bSRiver Riddle .Case([&](const ast::Expr *expr) { genExpr(expr); });
18995b4e88bSRiver Riddle }
19095b4e88bSRiver Riddle
19195b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
19295b4e88bSRiver Riddle // CodeGen: Statements
19395b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
19495b4e88bSRiver Riddle
genImpl(const ast::CompoundStmt * stmt)19595b4e88bSRiver Riddle void CodeGen::genImpl(const ast::CompoundStmt *stmt) {
19695b4e88bSRiver Riddle VariableMapTy::ScopeTy varScope(variables);
19795b4e88bSRiver Riddle for (const ast::Stmt *childStmt : stmt->getChildren())
19895b4e88bSRiver Riddle gen(childStmt);
19995b4e88bSRiver Riddle }
20095b4e88bSRiver Riddle
20195b4e88bSRiver Riddle /// If the given builder is nested under a PDL PatternOp, build a rewrite
20295b4e88bSRiver Riddle /// operation and update the builder to nest under it. This is necessary for
20395b4e88bSRiver Riddle /// PDLL operation rewrite statements that are directly nested within a Pattern.
checkAndNestUnderRewriteOp(OpBuilder & builder,Value rootExpr,Location loc)20495b4e88bSRiver Riddle static void checkAndNestUnderRewriteOp(OpBuilder &builder, Value rootExpr,
20595b4e88bSRiver Riddle Location loc) {
20695b4e88bSRiver Riddle if (isa<pdl::PatternOp>(builder.getInsertionBlock()->getParentOp())) {
2079595f356SRiver Riddle pdl::RewriteOp rewrite =
2089595f356SRiver Riddle builder.create<pdl::RewriteOp>(loc, rootExpr, /*name=*/StringAttr(),
2099595f356SRiver Riddle /*externalArgs=*/ValueRange());
21072fddfb5SRiver Riddle builder.createBlock(&rewrite.getBodyRegion());
21195b4e88bSRiver Riddle }
21295b4e88bSRiver Riddle }
21395b4e88bSRiver Riddle
genImpl(const ast::EraseStmt * stmt)21495b4e88bSRiver Riddle void CodeGen::genImpl(const ast::EraseStmt *stmt) {
21595b4e88bSRiver Riddle OpBuilder::InsertionGuard insertGuard(builder);
21695b4e88bSRiver Riddle Value rootExpr = genSingleExpr(stmt->getRootOpExpr());
21795b4e88bSRiver Riddle Location loc = genLoc(stmt->getLoc());
21895b4e88bSRiver Riddle
21995b4e88bSRiver Riddle // Make sure we are nested in a RewriteOp.
22095b4e88bSRiver Riddle OpBuilder::InsertionGuard guard(builder);
22195b4e88bSRiver Riddle checkAndNestUnderRewriteOp(builder, rootExpr, loc);
22295b4e88bSRiver Riddle builder.create<pdl::EraseOp>(loc, rootExpr);
22395b4e88bSRiver Riddle }
22495b4e88bSRiver Riddle
genImpl(const ast::LetStmt * stmt)22595b4e88bSRiver Riddle void CodeGen::genImpl(const ast::LetStmt *stmt) { genVar(stmt->getVarDecl()); }
22695b4e88bSRiver Riddle
genImpl(const ast::ReplaceStmt * stmt)22795b4e88bSRiver Riddle void CodeGen::genImpl(const ast::ReplaceStmt *stmt) {
22895b4e88bSRiver Riddle OpBuilder::InsertionGuard insertGuard(builder);
22995b4e88bSRiver Riddle Value rootExpr = genSingleExpr(stmt->getRootOpExpr());
23095b4e88bSRiver Riddle Location loc = genLoc(stmt->getLoc());
23195b4e88bSRiver Riddle
23295b4e88bSRiver Riddle // Make sure we are nested in a RewriteOp.
23395b4e88bSRiver Riddle OpBuilder::InsertionGuard guard(builder);
23495b4e88bSRiver Riddle checkAndNestUnderRewriteOp(builder, rootExpr, loc);
23595b4e88bSRiver Riddle
23695b4e88bSRiver Riddle SmallVector<Value> replValues;
23795b4e88bSRiver Riddle for (ast::Expr *replExpr : stmt->getReplExprs())
23895b4e88bSRiver Riddle replValues.push_back(genSingleExpr(replExpr));
23995b4e88bSRiver Riddle
24095b4e88bSRiver Riddle // Check to see if the statement has a replacement operation, or a range of
24195b4e88bSRiver Riddle // replacement values.
24295b4e88bSRiver Riddle bool usesReplOperation =
24395b4e88bSRiver Riddle replValues.size() == 1 &&
2445550c821STres Popp isa<pdl::OperationType>(replValues.front().getType());
24595b4e88bSRiver Riddle builder.create<pdl::ReplaceOp>(
24695b4e88bSRiver Riddle loc, rootExpr, usesReplOperation ? replValues[0] : Value(),
24795b4e88bSRiver Riddle usesReplOperation ? ValueRange() : ValueRange(replValues));
24895b4e88bSRiver Riddle }
24995b4e88bSRiver Riddle
genImpl(const ast::RewriteStmt * stmt)25095b4e88bSRiver Riddle void CodeGen::genImpl(const ast::RewriteStmt *stmt) {
25195b4e88bSRiver Riddle OpBuilder::InsertionGuard insertGuard(builder);
25295b4e88bSRiver Riddle Value rootExpr = genSingleExpr(stmt->getRootOpExpr());
25395b4e88bSRiver Riddle
25495b4e88bSRiver Riddle // Make sure we are nested in a RewriteOp.
25595b4e88bSRiver Riddle OpBuilder::InsertionGuard guard(builder);
25695b4e88bSRiver Riddle checkAndNestUnderRewriteOp(builder, rootExpr, genLoc(stmt->getLoc()));
25795b4e88bSRiver Riddle gen(stmt->getRewriteBody());
25895b4e88bSRiver Riddle }
25995b4e88bSRiver Riddle
genImpl(const ast::ReturnStmt * stmt)26095b4e88bSRiver Riddle void CodeGen::genImpl(const ast::ReturnStmt *stmt) {
26195b4e88bSRiver Riddle // ReturnStmt generation is handled by the respective constraint or rewrite
26295b4e88bSRiver Riddle // parent node.
26395b4e88bSRiver Riddle }
26495b4e88bSRiver Riddle
26595b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
26695b4e88bSRiver Riddle // CodeGen: Decls
26795b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
26895b4e88bSRiver Riddle
genImpl(const ast::UserConstraintDecl * decl)26995b4e88bSRiver Riddle void CodeGen::genImpl(const ast::UserConstraintDecl *decl) {
27095b4e88bSRiver Riddle // All PDLL constraints get inlined when called, and the main native
27195b4e88bSRiver Riddle // constraint declarations doesn't require any MLIR to be generated, only uses
27295b4e88bSRiver Riddle // of it do.
27395b4e88bSRiver Riddle }
27495b4e88bSRiver Riddle
genImpl(const ast::UserRewriteDecl * decl)27595b4e88bSRiver Riddle void CodeGen::genImpl(const ast::UserRewriteDecl *decl) {
27695b4e88bSRiver Riddle // All PDLL rewrites get inlined when called, and the main native
27795b4e88bSRiver Riddle // rewrite declarations doesn't require any MLIR to be generated, only uses
27895b4e88bSRiver Riddle // of it do.
27995b4e88bSRiver Riddle }
28095b4e88bSRiver Riddle
genImpl(const ast::PatternDecl * decl)28195b4e88bSRiver Riddle void CodeGen::genImpl(const ast::PatternDecl *decl) {
28295b4e88bSRiver Riddle const ast::Name *name = decl->getName();
28395b4e88bSRiver Riddle
28495b4e88bSRiver Riddle // FIXME: Properly model HasBoundedRecursion in PDL so that we don't drop it
28595b4e88bSRiver Riddle // here.
28695b4e88bSRiver Riddle pdl::PatternOp pattern = builder.create<pdl::PatternOp>(
28795b4e88bSRiver Riddle genLoc(decl->getLoc()), decl->getBenefit(),
2880a81ace0SKazu Hirata name ? std::optional<StringRef>(name->getName())
2890a81ace0SKazu Hirata : std::optional<StringRef>());
29095b4e88bSRiver Riddle
29195b4e88bSRiver Riddle OpBuilder::InsertionGuard savedInsertPoint(builder);
29295b4e88bSRiver Riddle builder.setInsertionPointToStart(pattern.getBody());
29395b4e88bSRiver Riddle gen(decl->getBody());
29495b4e88bSRiver Riddle }
29595b4e88bSRiver Riddle
genVar(const ast::VariableDecl * varDecl)29695b4e88bSRiver Riddle SmallVector<Value> CodeGen::genVar(const ast::VariableDecl *varDecl) {
29795b4e88bSRiver Riddle auto it = variables.begin(varDecl);
29895b4e88bSRiver Riddle if (it != variables.end())
29995b4e88bSRiver Riddle return *it;
30095b4e88bSRiver Riddle
30195b4e88bSRiver Riddle // If the variable has an initial value, use that as the base value.
30295b4e88bSRiver Riddle // Otherwise, generate a value using the constraint list.
30395b4e88bSRiver Riddle SmallVector<Value> values;
30495b4e88bSRiver Riddle if (const ast::Expr *initExpr = varDecl->getInitExpr())
30595b4e88bSRiver Riddle values = genExpr(initExpr);
30695b4e88bSRiver Riddle else
30795b4e88bSRiver Riddle values.push_back(genNonInitializerVar(varDecl, genLoc(varDecl->getLoc())));
30895b4e88bSRiver Riddle
30995b4e88bSRiver Riddle // Apply the constraints of the values of the variable.
31095b4e88bSRiver Riddle applyVarConstraints(varDecl, values);
31195b4e88bSRiver Riddle
31295b4e88bSRiver Riddle variables.insert(varDecl, values);
31395b4e88bSRiver Riddle return values;
31495b4e88bSRiver Riddle }
31595b4e88bSRiver Riddle
genNonInitializerVar(const ast::VariableDecl * varDecl,Location loc)31695b4e88bSRiver Riddle Value CodeGen::genNonInitializerVar(const ast::VariableDecl *varDecl,
31795b4e88bSRiver Riddle Location loc) {
31895b4e88bSRiver Riddle // A functor used to generate expressions nested
31995b4e88bSRiver Riddle auto getTypeConstraint = [&]() -> Value {
32095b4e88bSRiver Riddle for (const ast::ConstraintRef &constraint : varDecl->getConstraints()) {
32195b4e88bSRiver Riddle Value typeValue =
32295b4e88bSRiver Riddle TypeSwitch<const ast::Node *, Value>(constraint.constraint)
32395b4e88bSRiver Riddle .Case<ast::AttrConstraintDecl, ast::ValueConstraintDecl,
3241c2edb02SRiver Riddle ast::ValueRangeConstraintDecl>(
3251c2edb02SRiver Riddle [&, this](auto *cst) -> Value {
32695b4e88bSRiver Riddle if (auto *typeConstraintExpr = cst->getTypeExpr())
32747ddf382SMehdi Amini return this->genSingleExpr(typeConstraintExpr);
32895b4e88bSRiver Riddle return Value();
32995b4e88bSRiver Riddle })
33095b4e88bSRiver Riddle .Default(Value());
33195b4e88bSRiver Riddle if (typeValue)
33295b4e88bSRiver Riddle return typeValue;
33395b4e88bSRiver Riddle }
33495b4e88bSRiver Riddle return Value();
33595b4e88bSRiver Riddle };
33695b4e88bSRiver Riddle
33795b4e88bSRiver Riddle // Generate a value based on the type of the variable.
33895b4e88bSRiver Riddle ast::Type type = varDecl->getType();
33995b4e88bSRiver Riddle Type mlirType = genType(type);
340*d2353695SPeiming Liu if (isa<ast::ValueType>(type))
34195b4e88bSRiver Riddle return builder.create<pdl::OperandOp>(loc, mlirType, getTypeConstraint());
342*d2353695SPeiming Liu if (isa<ast::TypeType>(type))
34395b4e88bSRiver Riddle return builder.create<pdl::TypeOp>(loc, mlirType, /*type=*/TypeAttr());
344*d2353695SPeiming Liu if (isa<ast::AttributeType>(type))
34595b4e88bSRiver Riddle return builder.create<pdl::AttributeOp>(loc, getTypeConstraint());
346*d2353695SPeiming Liu if (ast::OperationType opType = dyn_cast<ast::OperationType>(type)) {
34795b4e88bSRiver Riddle Value operands = builder.create<pdl::OperandsOp>(
34895b4e88bSRiver Riddle loc, pdl::RangeType::get(builder.getType<pdl::ValueType>()),
34995b4e88bSRiver Riddle /*type=*/Value());
35095b4e88bSRiver Riddle Value results = builder.create<pdl::TypesOp>(
35195b4e88bSRiver Riddle loc, pdl::RangeType::get(builder.getType<pdl::TypeType>()),
35295b4e88bSRiver Riddle /*types=*/ArrayAttr());
3531a36588eSKazu Hirata return builder.create<pdl::OperationOp>(
3541a36588eSKazu Hirata loc, opType.getName(), operands, std::nullopt, ValueRange(), results);
35595b4e88bSRiver Riddle }
35695b4e88bSRiver Riddle
357*d2353695SPeiming Liu if (ast::RangeType rangeTy = dyn_cast<ast::RangeType>(type)) {
35895b4e88bSRiver Riddle ast::Type eleTy = rangeTy.getElementType();
359*d2353695SPeiming Liu if (isa<ast::ValueType>(eleTy))
36095b4e88bSRiver Riddle return builder.create<pdl::OperandsOp>(loc, mlirType,
36195b4e88bSRiver Riddle getTypeConstraint());
362*d2353695SPeiming Liu if (isa<ast::TypeType>(eleTy))
36395b4e88bSRiver Riddle return builder.create<pdl::TypesOp>(loc, mlirType, /*types=*/ArrayAttr());
36495b4e88bSRiver Riddle }
36595b4e88bSRiver Riddle
36695b4e88bSRiver Riddle llvm_unreachable("invalid non-initialized variable type");
36795b4e88bSRiver Riddle }
36895b4e88bSRiver Riddle
applyVarConstraints(const ast::VariableDecl * varDecl,ValueRange values)36995b4e88bSRiver Riddle void CodeGen::applyVarConstraints(const ast::VariableDecl *varDecl,
37095b4e88bSRiver Riddle ValueRange values) {
37195b4e88bSRiver Riddle // Generate calls to any user constraints that were attached via the
37295b4e88bSRiver Riddle // constraint list.
37395b4e88bSRiver Riddle for (const ast::ConstraintRef &ref : varDecl->getConstraints())
37495b4e88bSRiver Riddle if (const auto *userCst = dyn_cast<ast::UserConstraintDecl>(ref.constraint))
37595b4e88bSRiver Riddle genConstraintCall(userCst, genLoc(ref.referenceLoc), values);
37695b4e88bSRiver Riddle }
37795b4e88bSRiver Riddle
37895b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
37995b4e88bSRiver Riddle // CodeGen: Expressions
38095b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
38195b4e88bSRiver Riddle
genSingleExpr(const ast::Expr * expr)38295b4e88bSRiver Riddle Value CodeGen::genSingleExpr(const ast::Expr *expr) {
38395b4e88bSRiver Riddle return TypeSwitch<const ast::Expr *, Value>(expr)
38495b4e88bSRiver Riddle .Case<const ast::AttributeExpr, const ast::MemberAccessExpr,
3859e57210aSRiver Riddle const ast::OperationExpr, const ast::RangeExpr,
3869e57210aSRiver Riddle const ast::TypeExpr>(
38795b4e88bSRiver Riddle [&](auto derivedNode) { return this->genExprImpl(derivedNode); })
38895b4e88bSRiver Riddle .Case<const ast::CallExpr, const ast::DeclRefExpr, const ast::TupleExpr>(
38995b4e88bSRiver Riddle [&](auto derivedNode) {
39095b4e88bSRiver Riddle SmallVector<Value> results = this->genExprImpl(derivedNode);
39195b4e88bSRiver Riddle assert(results.size() == 1 && "expected single expression result");
39295b4e88bSRiver Riddle return results[0];
39395b4e88bSRiver Riddle });
39495b4e88bSRiver Riddle }
39595b4e88bSRiver Riddle
genExpr(const ast::Expr * expr)39695b4e88bSRiver Riddle SmallVector<Value> CodeGen::genExpr(const ast::Expr *expr) {
39795b4e88bSRiver Riddle return TypeSwitch<const ast::Expr *, SmallVector<Value>>(expr)
39895b4e88bSRiver Riddle .Case<const ast::CallExpr, const ast::DeclRefExpr, const ast::TupleExpr>(
39995b4e88bSRiver Riddle [&](auto derivedNode) { return this->genExprImpl(derivedNode); })
40095b4e88bSRiver Riddle .Default([&](const ast::Expr *expr) -> SmallVector<Value> {
40195b4e88bSRiver Riddle return {genSingleExpr(expr)};
40295b4e88bSRiver Riddle });
40395b4e88bSRiver Riddle }
40495b4e88bSRiver Riddle
genExprImpl(const ast::AttributeExpr * expr)40595b4e88bSRiver Riddle Value CodeGen::genExprImpl(const ast::AttributeExpr *expr) {
40695b4e88bSRiver Riddle Attribute attr = parseAttribute(expr->getValue(), builder.getContext());
40795b4e88bSRiver Riddle assert(attr && "invalid MLIR attribute data");
40895b4e88bSRiver Riddle return builder.create<pdl::AttributeOp>(genLoc(expr->getLoc()), attr);
40995b4e88bSRiver Riddle }
41095b4e88bSRiver Riddle
genExprImpl(const ast::CallExpr * expr)41195b4e88bSRiver Riddle SmallVector<Value> CodeGen::genExprImpl(const ast::CallExpr *expr) {
41295b4e88bSRiver Riddle Location loc = genLoc(expr->getLoc());
41395b4e88bSRiver Riddle SmallVector<Value> arguments;
41495b4e88bSRiver Riddle for (const ast::Expr *arg : expr->getArguments())
41595b4e88bSRiver Riddle arguments.push_back(genSingleExpr(arg));
41695b4e88bSRiver Riddle
41795b4e88bSRiver Riddle // Resolve the callable expression of this call.
41895b4e88bSRiver Riddle auto *callableExpr = dyn_cast<ast::DeclRefExpr>(expr->getCallableExpr());
41995b4e88bSRiver Riddle assert(callableExpr && "unhandled CallExpr callable");
42095b4e88bSRiver Riddle
42195b4e88bSRiver Riddle // Generate the PDL based on the type of callable.
42295b4e88bSRiver Riddle const ast::Decl *callable = callableExpr->getDecl();
42395b4e88bSRiver Riddle if (const auto *decl = dyn_cast<ast::UserConstraintDecl>(callable))
424930916c7SMogball return genConstraintCall(decl, loc, arguments, expr->getIsNegated());
42595b4e88bSRiver Riddle if (const auto *decl = dyn_cast<ast::UserRewriteDecl>(callable))
42695b4e88bSRiver Riddle return genRewriteCall(decl, loc, arguments);
42795b4e88bSRiver Riddle llvm_unreachable("unhandled CallExpr callable");
42895b4e88bSRiver Riddle }
42995b4e88bSRiver Riddle
genExprImpl(const ast::DeclRefExpr * expr)43095b4e88bSRiver Riddle SmallVector<Value> CodeGen::genExprImpl(const ast::DeclRefExpr *expr) {
43195b4e88bSRiver Riddle if (const auto *varDecl = dyn_cast<ast::VariableDecl>(expr->getDecl()))
43295b4e88bSRiver Riddle return genVar(varDecl);
43395b4e88bSRiver Riddle llvm_unreachable("unknown decl reference expression");
43495b4e88bSRiver Riddle }
43595b4e88bSRiver Riddle
genExprImpl(const ast::MemberAccessExpr * expr)43695b4e88bSRiver Riddle Value CodeGen::genExprImpl(const ast::MemberAccessExpr *expr) {
43795b4e88bSRiver Riddle Location loc = genLoc(expr->getLoc());
43895b4e88bSRiver Riddle StringRef name = expr->getMemberName();
43995b4e88bSRiver Riddle SmallVector<Value> parentExprs = genExpr(expr->getParentExpr());
44095b4e88bSRiver Riddle ast::Type parentType = expr->getParentExpr()->getType();
44195b4e88bSRiver Riddle
44295b4e88bSRiver Riddle // Handle operation based member access.
443*d2353695SPeiming Liu if (ast::OperationType opType = dyn_cast<ast::OperationType>(parentType)) {
44495b4e88bSRiver Riddle if (isa<ast::AllResultsMemberAccessExpr>(expr)) {
44595b4e88bSRiver Riddle Type mlirType = genType(expr->getType());
4465550c821STres Popp if (isa<pdl::ValueType>(mlirType))
44795b4e88bSRiver Riddle return builder.create<pdl::ResultOp>(loc, mlirType, parentExprs[0],
44895b4e88bSRiver Riddle builder.getI32IntegerAttr(0));
44995b4e88bSRiver Riddle return builder.create<pdl::ResultsOp>(loc, mlirType, parentExprs[0]);
45095b4e88bSRiver Riddle }
45181f2f4dfSRiver Riddle
4521c2edb02SRiver Riddle const ods::Operation *odsOp = opType.getODSOperation();
453c088fbe7SChia-hung Duan if (!odsOp) {
4541c2edb02SRiver Riddle assert(llvm::isDigit(name[0]) &&
4551c2edb02SRiver Riddle "unregistered op only allows numeric indexing");
456c088fbe7SChia-hung Duan unsigned resultIndex;
457c088fbe7SChia-hung Duan name.getAsInteger(/*Radix=*/10, resultIndex);
458c088fbe7SChia-hung Duan IntegerAttr index = builder.getI32IntegerAttr(resultIndex);
459c088fbe7SChia-hung Duan return builder.create<pdl::ResultOp>(loc, genType(expr->getType()),
460c088fbe7SChia-hung Duan parentExprs[0], index);
461c088fbe7SChia-hung Duan }
46281f2f4dfSRiver Riddle
46381f2f4dfSRiver Riddle // Find the result with the member name or by index.
46481f2f4dfSRiver Riddle ArrayRef<ods::OperandOrResult> results = odsOp->getResults();
46581f2f4dfSRiver Riddle unsigned resultIndex = results.size();
46681f2f4dfSRiver Riddle if (llvm::isDigit(name[0])) {
46781f2f4dfSRiver Riddle name.getAsInteger(/*Radix=*/10, resultIndex);
46881f2f4dfSRiver Riddle } else {
46981f2f4dfSRiver Riddle auto findFn = [&](const ods::OperandOrResult &result) {
47081f2f4dfSRiver Riddle return result.getName() == name;
47181f2f4dfSRiver Riddle };
47281f2f4dfSRiver Riddle resultIndex = llvm::find_if(results, findFn) - results.begin();
47381f2f4dfSRiver Riddle }
47481f2f4dfSRiver Riddle assert(resultIndex < results.size() && "invalid result index");
47581f2f4dfSRiver Riddle
47681f2f4dfSRiver Riddle // Generate the result access.
47781f2f4dfSRiver Riddle IntegerAttr index = builder.getI32IntegerAttr(resultIndex);
47881f2f4dfSRiver Riddle return builder.create<pdl::ResultsOp>(loc, genType(expr->getType()),
47981f2f4dfSRiver Riddle parentExprs[0], index);
48095b4e88bSRiver Riddle }
48195b4e88bSRiver Riddle
48295b4e88bSRiver Riddle // Handle tuple based member access.
483*d2353695SPeiming Liu if (auto tupleType = dyn_cast<ast::TupleType>(parentType)) {
48495b4e88bSRiver Riddle auto elementNames = tupleType.getElementNames();
48595b4e88bSRiver Riddle
48695b4e88bSRiver Riddle // The index is either a numeric index, or a name.
48795b4e88bSRiver Riddle unsigned index = 0;
48895b4e88bSRiver Riddle if (llvm::isDigit(name[0]))
48995b4e88bSRiver Riddle name.getAsInteger(/*Radix=*/10, index);
49095b4e88bSRiver Riddle else
49195b4e88bSRiver Riddle index = llvm::find(elementNames, name) - elementNames.begin();
49295b4e88bSRiver Riddle
49395b4e88bSRiver Riddle assert(index < parentExprs.size() && "invalid result index");
49495b4e88bSRiver Riddle return parentExprs[index];
49595b4e88bSRiver Riddle }
49695b4e88bSRiver Riddle
49795b4e88bSRiver Riddle llvm_unreachable("unhandled member access expression");
49895b4e88bSRiver Riddle }
49995b4e88bSRiver Riddle
genExprImpl(const ast::OperationExpr * expr)50095b4e88bSRiver Riddle Value CodeGen::genExprImpl(const ast::OperationExpr *expr) {
50195b4e88bSRiver Riddle Location loc = genLoc(expr->getLoc());
5020a81ace0SKazu Hirata std::optional<StringRef> opName = expr->getName();
50395b4e88bSRiver Riddle
50495b4e88bSRiver Riddle // Operands.
50595b4e88bSRiver Riddle SmallVector<Value> operands;
50695b4e88bSRiver Riddle for (const ast::Expr *operand : expr->getOperands())
50795b4e88bSRiver Riddle operands.push_back(genSingleExpr(operand));
50895b4e88bSRiver Riddle
50995b4e88bSRiver Riddle // Attributes.
51095b4e88bSRiver Riddle SmallVector<StringRef> attrNames;
51195b4e88bSRiver Riddle SmallVector<Value> attrValues;
51295b4e88bSRiver Riddle for (const ast::NamedAttributeDecl *attr : expr->getAttributes()) {
51395b4e88bSRiver Riddle attrNames.push_back(attr->getName().getName());
51495b4e88bSRiver Riddle attrValues.push_back(genSingleExpr(attr->getValue()));
51595b4e88bSRiver Riddle }
51695b4e88bSRiver Riddle
51795b4e88bSRiver Riddle // Results.
51895b4e88bSRiver Riddle SmallVector<Value> results;
51995b4e88bSRiver Riddle for (const ast::Expr *result : expr->getResultTypes())
52095b4e88bSRiver Riddle results.push_back(genSingleExpr(result));
52195b4e88bSRiver Riddle
52295b4e88bSRiver Riddle return builder.create<pdl::OperationOp>(loc, opName, operands, attrNames,
52395b4e88bSRiver Riddle attrValues, results);
52495b4e88bSRiver Riddle }
52595b4e88bSRiver Riddle
genExprImpl(const ast::RangeExpr * expr)5269e57210aSRiver Riddle Value CodeGen::genExprImpl(const ast::RangeExpr *expr) {
5279e57210aSRiver Riddle SmallVector<Value> elements;
5289e57210aSRiver Riddle for (const ast::Expr *element : expr->getElements())
5299e57210aSRiver Riddle llvm::append_range(elements, genExpr(element));
5309e57210aSRiver Riddle
5319e57210aSRiver Riddle return builder.create<pdl::RangeOp>(genLoc(expr->getLoc()),
5329e57210aSRiver Riddle genType(expr->getType()), elements);
5339e57210aSRiver Riddle }
5349e57210aSRiver Riddle
genExprImpl(const ast::TupleExpr * expr)53595b4e88bSRiver Riddle SmallVector<Value> CodeGen::genExprImpl(const ast::TupleExpr *expr) {
53695b4e88bSRiver Riddle SmallVector<Value> elements;
53795b4e88bSRiver Riddle for (const ast::Expr *element : expr->getElements())
53895b4e88bSRiver Riddle elements.push_back(genSingleExpr(element));
53995b4e88bSRiver Riddle return elements;
54095b4e88bSRiver Riddle }
54195b4e88bSRiver Riddle
genExprImpl(const ast::TypeExpr * expr)54295b4e88bSRiver Riddle Value CodeGen::genExprImpl(const ast::TypeExpr *expr) {
54395b4e88bSRiver Riddle Type type = parseType(expr->getValue(), builder.getContext());
54495b4e88bSRiver Riddle assert(type && "invalid MLIR type data");
54595b4e88bSRiver Riddle return builder.create<pdl::TypeOp>(genLoc(expr->getLoc()),
54695b4e88bSRiver Riddle builder.getType<pdl::TypeType>(),
54795b4e88bSRiver Riddle TypeAttr::get(type));
54895b4e88bSRiver Riddle }
54995b4e88bSRiver Riddle
55095b4e88bSRiver Riddle SmallVector<Value>
genConstraintCall(const ast::UserConstraintDecl * decl,Location loc,ValueRange inputs,bool isNegated)55195b4e88bSRiver Riddle CodeGen::genConstraintCall(const ast::UserConstraintDecl *decl, Location loc,
552930916c7SMogball ValueRange inputs, bool isNegated) {
55395b4e88bSRiver Riddle // Apply any constraints defined on the arguments to the input values.
55495b4e88bSRiver Riddle for (auto it : llvm::zip(decl->getInputs(), inputs))
55595b4e88bSRiver Riddle applyVarConstraints(std::get<0>(it), std::get<1>(it));
55695b4e88bSRiver Riddle
55795b4e88bSRiver Riddle // Generate the constraint call.
55895b4e88bSRiver Riddle SmallVector<Value> results =
559930916c7SMogball genConstraintOrRewriteCall<pdl::ApplyNativeConstraintOp>(
560930916c7SMogball decl, loc, inputs, isNegated);
56195b4e88bSRiver Riddle
56295b4e88bSRiver Riddle // Apply any constraints defined on the results of the constraint.
56395b4e88bSRiver Riddle for (auto it : llvm::zip(decl->getResults(), results))
56495b4e88bSRiver Riddle applyVarConstraints(std::get<0>(it), std::get<1>(it));
56595b4e88bSRiver Riddle return results;
56695b4e88bSRiver Riddle }
56795b4e88bSRiver Riddle
genRewriteCall(const ast::UserRewriteDecl * decl,Location loc,ValueRange inputs)56895b4e88bSRiver Riddle SmallVector<Value> CodeGen::genRewriteCall(const ast::UserRewriteDecl *decl,
56995b4e88bSRiver Riddle Location loc, ValueRange inputs) {
57095b4e88bSRiver Riddle return genConstraintOrRewriteCall<pdl::ApplyNativeRewriteOp>(decl, loc,
57195b4e88bSRiver Riddle inputs);
57295b4e88bSRiver Riddle }
57395b4e88bSRiver Riddle
57495b4e88bSRiver Riddle template <typename PDLOpT, typename T>
575930916c7SMogball SmallVector<Value>
genConstraintOrRewriteCall(const T * decl,Location loc,ValueRange inputs,bool isNegated)576930916c7SMogball CodeGen::genConstraintOrRewriteCall(const T *decl, Location loc,
577930916c7SMogball ValueRange inputs, bool isNegated) {
57895b4e88bSRiver Riddle const ast::CompoundStmt *cstBody = decl->getBody();
57995b4e88bSRiver Riddle
58095b4e88bSRiver Riddle // If the decl doesn't have a statement body, it is a native decl.
58195b4e88bSRiver Riddle if (!cstBody) {
58295b4e88bSRiver Riddle ast::Type declResultType = decl->getResultType();
58395b4e88bSRiver Riddle SmallVector<Type> resultTypes;
584*d2353695SPeiming Liu if (ast::TupleType tupleType = dyn_cast<ast::TupleType>(declResultType)) {
58595b4e88bSRiver Riddle for (ast::Type type : tupleType.getElementTypes())
58695b4e88bSRiver Riddle resultTypes.push_back(genType(type));
58795b4e88bSRiver Riddle } else {
58895b4e88bSRiver Riddle resultTypes.push_back(genType(declResultType));
58995b4e88bSRiver Riddle }
590*d2353695SPeiming Liu PDLOpT pdlOp = builder.create<PDLOpT>(loc, resultTypes,
591*d2353695SPeiming Liu decl->getName().getName(), inputs);
592930916c7SMogball if (isNegated && std::is_same_v<PDLOpT, pdl::ApplyNativeConstraintOp>)
593930916c7SMogball cast<pdl::ApplyNativeConstraintOp>(pdlOp).setIsNegated(true);
59495b4e88bSRiver Riddle return pdlOp->getResults();
59595b4e88bSRiver Riddle }
59695b4e88bSRiver Riddle
59795b4e88bSRiver Riddle // Otherwise, this is a PDLL decl.
59895b4e88bSRiver Riddle VariableMapTy::ScopeTy varScope(variables);
59995b4e88bSRiver Riddle
60095b4e88bSRiver Riddle // Map the inputs of the call to the decl arguments.
60195b4e88bSRiver Riddle // Note: This is only valid because we do not support recursion, meaning
60295b4e88bSRiver Riddle // we don't need to worry about conflicting mappings here.
60395b4e88bSRiver Riddle for (auto it : llvm::zip(inputs, decl->getInputs()))
60495b4e88bSRiver Riddle variables.insert(std::get<1>(it), {std::get<0>(it)});
60595b4e88bSRiver Riddle
60695b4e88bSRiver Riddle // Visit the body of the call as normal.
60795b4e88bSRiver Riddle gen(cstBody);
60895b4e88bSRiver Riddle
60995b4e88bSRiver Riddle // If the decl has no results, there is nothing to do.
61095b4e88bSRiver Riddle if (cstBody->getChildren().empty())
61195b4e88bSRiver Riddle return SmallVector<Value>();
61295b4e88bSRiver Riddle auto *returnStmt = dyn_cast<ast::ReturnStmt>(cstBody->getChildren().back());
61395b4e88bSRiver Riddle if (!returnStmt)
61495b4e88bSRiver Riddle return SmallVector<Value>();
61595b4e88bSRiver Riddle
61695b4e88bSRiver Riddle // Otherwise, grab the results from the return statement.
61795b4e88bSRiver Riddle return genExpr(returnStmt->getResultExpr());
61895b4e88bSRiver Riddle }
61995b4e88bSRiver Riddle
62095b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
62195b4e88bSRiver Riddle // MLIRGen
62295b4e88bSRiver Riddle //===----------------------------------------------------------------------===//
62395b4e88bSRiver Riddle
codegenPDLLToMLIR(MLIRContext * mlirContext,const ast::Context & context,const llvm::SourceMgr & sourceMgr,const ast::Module & module)62495b4e88bSRiver Riddle OwningOpRef<ModuleOp> mlir::pdll::codegenPDLLToMLIR(
62595b4e88bSRiver Riddle MLIRContext *mlirContext, const ast::Context &context,
62695b4e88bSRiver Riddle const llvm::SourceMgr &sourceMgr, const ast::Module &module) {
62795b4e88bSRiver Riddle CodeGen codegen(mlirContext, context, sourceMgr);
62895b4e88bSRiver Riddle OwningOpRef<ModuleOp> mlirModule = codegen.generate(module);
62995b4e88bSRiver Riddle if (failed(verify(*mlirModule)))
63095b4e88bSRiver Riddle return nullptr;
63195b4e88bSRiver Riddle return mlirModule;
63295b4e88bSRiver Riddle }
633