22#include "llvm/ADT/ScopedHashTable.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/TypeSwitch.h"
38 CodeGen(MLIRContext *mlirContext,
const ast::Context &context,
39 const llvm::SourceMgr &sourceMgr)
40 : builder(mlirContext), odsContext(context.getODSContext()),
41 sourceMgr(sourceMgr) {
46 OwningOpRef<ModuleOp> generate(
const ast::Module &module);
50 Location genLoc(llvm::SMLoc loc);
51 Location genLoc(llvm::SMRange loc) {
return genLoc(loc.Start); }
54 Type genType(ast::Type type);
57 void gen(
const ast::Node *node);
63 void genImpl(
const ast::CompoundStmt *stmt);
64 void genImpl(
const ast::EraseStmt *stmt);
65 void genImpl(
const ast::LetStmt *stmt);
66 void genImpl(
const ast::ReplaceStmt *stmt);
67 void genImpl(
const ast::RewriteStmt *stmt);
68 void genImpl(
const ast::ReturnStmt *stmt);
74 void genImpl(
const ast::UserConstraintDecl *decl);
75 void genImpl(
const ast::UserRewriteDecl *decl);
76 void genImpl(
const ast::PatternDecl *decl);
80 SmallVector<Value> genVar(
const ast::VariableDecl *varDecl);
85 Value genNonInitializerVar(
const ast::VariableDecl *varDecl, Location loc);
89 void applyVarConstraints(
const ast::VariableDecl *varDecl,
ValueRange values);
95 Value genSingleExpr(
const ast::Expr *expr);
96 SmallVector<Value> genExpr(
const ast::Expr *expr);
97 Value genExprImpl(
const ast::AttributeExpr *expr);
98 SmallVector<Value> genExprImpl(
const ast::CallExpr *expr);
99 SmallVector<Value> genExprImpl(
const ast::DeclRefExpr *expr);
100 Value genExprImpl(
const ast::MemberAccessExpr *expr);
101 Value genExprImpl(
const ast::OperationExpr *expr);
102 Value genExprImpl(
const ast::RangeExpr *expr);
103 SmallVector<Value> genExprImpl(
const ast::TupleExpr *expr);
104 Value genExprImpl(
const ast::TypeExpr *expr);
106 SmallVector<Value> genConstraintCall(
const ast::UserConstraintDecl *decl,
108 bool isNegated =
false);
109 SmallVector<Value> genRewriteCall(
const ast::UserRewriteDecl *decl,
111 template <
typename PDLOpT,
typename T>
112 SmallVector<Value> genConstraintOrRewriteCall(
const T *decl, Location loc,
114 bool isNegated =
false);
124 using VariableMapTy =
125 llvm::ScopedHashTable<const ast::VariableDecl *, SmallVector<Value>>;
126 VariableMapTy variables;
129 const ods::Context &odsContext;
132 const llvm::SourceMgr &sourceMgr;
137 OwningOpRef<ModuleOp> mlirModule =
138 ModuleOp::create(builder, genLoc(module.
getLoc()));
139 builder.setInsertionPointToStart(mlirModule->getBody());
148Location CodeGen::genLoc(llvm::SMLoc loc) {
149 unsigned fileID = sourceMgr.FindBufferContainingLoc(loc);
151 auto [lineNo, column] = sourceMgr.getLineAndColumn(loc);
152 auto *buffer = sourceMgr.getMemoryBuffer(fileID);
155 buffer->getBufferIdentifier(), lineNo, column);
158Type CodeGen::genType(ast::Type type) {
160 .Case([&](ast::AttributeType astType) -> Type {
161 return builder.getType<pdl::AttributeType>();
163 .Case([&](ast::OperationType astType) -> Type {
164 return builder.getType<pdl::OperationType>();
166 .Case([&](ast::TypeType astType) -> Type {
167 return builder.getType<pdl::TypeType>();
169 .Case([&](ast::ValueType astType) -> Type {
170 return builder.getType<pdl::ValueType>();
172 .Case([&](ast::RangeType astType) -> Type {
177void CodeGen::gen(
const ast::Node *node) {
179 .Case<
const ast::CompoundStmt,
const ast::EraseStmt,
const ast::LetStmt,
180 const ast::ReplaceStmt,
const ast::RewriteStmt,
181 const ast::ReturnStmt,
const ast::UserConstraintDecl,
182 const ast::UserRewriteDecl,
const ast::PatternDecl>(
183 [&](
auto derivedNode) { this->genImpl(derivedNode); })
184 .Case([&](
const ast::Expr *expr) { genExpr(expr); });
191void CodeGen::genImpl(
const ast::CompoundStmt *stmt) {
192 VariableMapTy::ScopeTy varScope(variables);
193 for (
const ast::Stmt *childStmt : stmt->
getChildren())
204 pdl::RewriteOp::create(builder, loc, rootExpr, StringAttr(),
210void CodeGen::genImpl(
const ast::EraseStmt *stmt) {
211 OpBuilder::InsertionGuard insertGuard(builder);
213 Location loc = genLoc(stmt->
getLoc());
216 OpBuilder::InsertionGuard guard(builder);
218 pdl::EraseOp::create(builder, loc, rootExpr);
221void CodeGen::genImpl(
const ast::LetStmt *stmt) { genVar(stmt->
getVarDecl()); }
223void CodeGen::genImpl(
const ast::ReplaceStmt *stmt) {
224 OpBuilder::InsertionGuard insertGuard(builder);
226 Location loc = genLoc(stmt->
getLoc());
229 OpBuilder::InsertionGuard guard(builder);
232 SmallVector<Value> replValues;
234 replValues.push_back(genSingleExpr(replExpr));
238 bool usesReplOperation =
239 replValues.size() == 1 &&
240 isa<pdl::OperationType>(replValues.front().getType());
241 pdl::ReplaceOp::create(
242 builder, loc, rootExpr, usesReplOperation ? replValues[0] : Value(),
246void CodeGen::genImpl(
const ast::RewriteStmt *stmt) {
247 OpBuilder::InsertionGuard insertGuard(builder);
251 OpBuilder::InsertionGuard guard(builder);
256void CodeGen::genImpl(
const ast::ReturnStmt *stmt) {
265void CodeGen::genImpl(
const ast::UserConstraintDecl *decl) {
271void CodeGen::genImpl(
const ast::UserRewriteDecl *decl) {
277void CodeGen::genImpl(
const ast::PatternDecl *decl) {
278 const ast::Name *name = decl->
getName();
282 pdl::PatternOp pattern = pdl::PatternOp::create(
284 name ? std::optional<StringRef>(name->
getName())
285 : std::optional<StringRef>());
287 OpBuilder::InsertionGuard savedInsertPoint(builder);
288 builder.setInsertionPointToStart(pattern.getBody());
292SmallVector<Value> CodeGen::genVar(
const ast::VariableDecl *varDecl) {
293 auto it = variables.begin(varDecl);
294 if (it != variables.end())
299 SmallVector<Value> values;
300 if (
const ast::Expr *initExpr = varDecl->
getInitExpr())
301 values = genExpr(initExpr);
303 values.push_back(genNonInitializerVar(varDecl, genLoc(varDecl->
getLoc())));
306 applyVarConstraints(varDecl, values);
308 variables.insert(varDecl, values);
312Value CodeGen::genNonInitializerVar(
const ast::VariableDecl *varDecl,
315 auto getTypeConstraint = [&]() -> Value {
316 for (
const ast::ConstraintRef &constraint : varDecl->
getConstraints()) {
319 .Case<ast::AttrConstraintDecl, ast::ValueConstraintDecl,
320 ast::ValueRangeConstraintDecl>(
321 [&,
this](
auto *cst) -> Value {
322 if (
auto *typeConstraintExpr = cst->getTypeExpr())
323 return this->genSingleExpr(typeConstraintExpr);
334 ast::Type type = varDecl->
getType();
335 Type mlirType = genType(type);
336 if (isa<ast::ValueType>(type))
337 return pdl::OperandOp::create(builder, loc, mlirType, getTypeConstraint());
338 if (isa<ast::TypeType>(type))
339 return pdl::TypeOp::create(builder, loc, mlirType, TypeAttr());
340 if (isa<ast::AttributeType>(type))
341 return pdl::AttributeOp::create(builder, loc, getTypeConstraint());
342 if (ast::OperationType opType = dyn_cast<ast::OperationType>(type)) {
343 Value operands = pdl::OperandsOp::create(
344 builder, loc, pdl::RangeType::get(builder.getType<pdl::ValueType>()),
346 Value results = pdl::TypesOp::create(
347 builder, loc, pdl::RangeType::get(builder.getType<pdl::TypeType>()),
349 return pdl::OperationOp::create(builder, loc, opType.getName(), operands,
354 if (ast::RangeType rangeTy = dyn_cast<ast::RangeType>(type)) {
355 ast::Type eleTy = rangeTy.getElementType();
356 if (isa<ast::ValueType>(eleTy))
357 return pdl::OperandsOp::create(builder, loc, mlirType,
358 getTypeConstraint());
359 if (isa<ast::TypeType>(eleTy))
360 return pdl::TypesOp::create(builder, loc, mlirType,
364 llvm_unreachable(
"invalid non-initialized variable type");
367void CodeGen::applyVarConstraints(
const ast::VariableDecl *varDecl,
372 if (
const auto *userCst = dyn_cast<ast::UserConstraintDecl>(ref.constraint))
373 genConstraintCall(userCst, genLoc(ref.referenceLoc), values);
380Value CodeGen::genSingleExpr(
const ast::Expr *expr) {
382 .Case<
const ast::AttributeExpr,
const ast::MemberAccessExpr,
383 const ast::OperationExpr,
const ast::RangeExpr,
384 const ast::TypeExpr>(
385 [&](
auto derivedNode) {
return this->genExprImpl(derivedNode); })
386 .Case<const ast::CallExpr, const ast::DeclRefExpr, const ast::TupleExpr>(
387 [&](
auto derivedNode) {
388 return llvm::getSingleElement(this->genExprImpl(derivedNode));
392SmallVector<Value> CodeGen::genExpr(
const ast::Expr *expr) {
394 .Case<const ast::CallExpr, const ast::DeclRefExpr, const ast::TupleExpr>(
395 [&](
auto derivedNode) {
return this->genExprImpl(derivedNode); })
396 .Default([&](
const ast::Expr *expr) -> SmallVector<Value> {
397 return {genSingleExpr(expr)};
401Value CodeGen::genExprImpl(
const ast::AttributeExpr *expr) {
403 assert(attr &&
"invalid MLIR attribute data");
404 return pdl::AttributeOp::create(builder, genLoc(expr->
getLoc()), attr);
407SmallVector<Value> CodeGen::genExprImpl(
const ast::CallExpr *expr) {
408 Location loc = genLoc(expr->
getLoc());
409 SmallVector<Value> arguments;
411 arguments.push_back(genSingleExpr(arg));
414 auto *callableExpr = dyn_cast<ast::DeclRefExpr>(expr->
getCallableExpr());
415 assert(callableExpr &&
"unhandled CallExpr callable");
418 const ast::Decl *callable = callableExpr->getDecl();
419 if (
const auto *decl = dyn_cast<ast::UserConstraintDecl>(callable))
420 return genConstraintCall(decl, loc, arguments, expr->
getIsNegated());
421 if (
const auto *decl = dyn_cast<ast::UserRewriteDecl>(callable))
422 return genRewriteCall(decl, loc, arguments);
423 llvm_unreachable(
"unhandled CallExpr callable");
426SmallVector<Value> CodeGen::genExprImpl(
const ast::DeclRefExpr *expr) {
427 if (
const auto *varDecl = dyn_cast<ast::VariableDecl>(expr->
getDecl()))
428 return genVar(varDecl);
429 llvm_unreachable(
"unknown decl reference expression");
432Value CodeGen::genExprImpl(
const ast::MemberAccessExpr *expr) {
433 Location loc = genLoc(expr->
getLoc());
435 SmallVector<Value> parentExprs = genExpr(expr->
getParentExpr());
439 if (ast::OperationType opType = dyn_cast<ast::OperationType>(parentType)) {
440 if (isa<ast::AllResultsMemberAccessExpr>(expr)) {
441 Type mlirType = genType(expr->
getType());
442 if (isa<pdl::ValueType>(mlirType))
443 return pdl::ResultOp::create(builder, loc, mlirType, parentExprs[0],
444 builder.getI32IntegerAttr(0));
445 return pdl::ResultsOp::create(builder, loc, mlirType, parentExprs[0],
449 const ods::Operation *odsOp = opType.getODSOperation();
451 assert(llvm::isDigit(name[0]) &&
452 "unregistered op only allows numeric indexing");
453 int32_t resultIndex = 0;
454 if (name.getAsInteger(10, resultIndex))
455 llvm_unreachable(
"result index should have been validated");
456 IntegerAttr index = builder.getI32IntegerAttr(resultIndex);
457 return pdl::ResultOp::create(builder, loc, genType(expr->
getType()),
458 parentExprs[0], index);
462 ArrayRef<ods::OperandOrResult> results = odsOp->
getResults();
463 unsigned resultIndex = results.size();
464 if (llvm::isDigit(name[0])) {
465 name.getAsInteger(10, resultIndex);
467 auto findFn = [&](
const ods::OperandOrResult &
result) {
468 return result.getName() == name;
470 resultIndex = llvm::find_if(results, findFn) - results.begin();
472 assert(resultIndex < results.size() &&
"invalid result index");
475 IntegerAttr index = builder.getI32IntegerAttr(resultIndex);
476 return pdl::ResultsOp::create(builder, loc, genType(expr->
getType()),
477 parentExprs[0], index);
481 if (
auto tupleType = dyn_cast<ast::TupleType>(parentType)) {
482 auto elementNames = tupleType.getElementNames();
486 if (llvm::isDigit(name[0]))
487 name.getAsInteger(10, index);
489 index = llvm::find(elementNames, name) - elementNames.begin();
491 assert(index < parentExprs.size() &&
"invalid result index");
492 return parentExprs[index];
495 llvm_unreachable(
"unhandled member access expression");
498Value CodeGen::genExprImpl(
const ast::OperationExpr *expr) {
499 Location loc = genLoc(expr->
getLoc());
500 std::optional<StringRef> opName = expr->
getName();
503 SmallVector<Value> operands;
504 for (
const ast::Expr *operand : expr->
getOperands())
505 operands.push_back(genSingleExpr(operand));
508 SmallVector<StringRef> attrNames;
509 SmallVector<Value> attrValues;
510 for (
const ast::NamedAttributeDecl *attr : expr->
getAttributes()) {
511 attrNames.push_back(attr->getName().getName());
512 attrValues.push_back(genSingleExpr(attr->getValue()));
516 SmallVector<Value> results;
518 results.push_back(genSingleExpr(
result));
520 return pdl::OperationOp::create(builder, loc, opName, operands, attrNames,
521 attrValues, results);
524Value CodeGen::genExprImpl(
const ast::RangeExpr *expr) {
525 SmallVector<Value> elements;
526 for (
const ast::Expr *element : expr->
getElements())
527 llvm::append_range(elements, genExpr(element));
529 return pdl::RangeOp::create(builder, genLoc(expr->
getLoc()),
530 genType(expr->
getType()), elements);
533SmallVector<Value> CodeGen::genExprImpl(
const ast::TupleExpr *expr) {
534 SmallVector<Value> elements;
535 for (
const ast::Expr *element : expr->
getElements())
536 elements.push_back(genSingleExpr(element));
540Value CodeGen::genExprImpl(
const ast::TypeExpr *expr) {
542 assert(type &&
"invalid MLIR type data");
543 return pdl::TypeOp::create(builder, genLoc(expr->
getLoc()),
544 builder.getType<pdl::TypeType>(),
545 TypeAttr::get(type));
549CodeGen::genConstraintCall(
const ast::UserConstraintDecl *decl, Location loc,
552 for (
auto it : llvm::zip(decl->
getInputs(), inputs))
553 applyVarConstraints(std::get<0>(it), std::get<1>(it));
556 SmallVector<Value> results =
557 genConstraintOrRewriteCall<pdl::ApplyNativeConstraintOp>(
558 decl, loc, inputs, isNegated);
561 for (
auto it : llvm::zip(decl->
getResults(), results))
562 applyVarConstraints(std::get<0>(it), std::get<1>(it));
566SmallVector<Value> CodeGen::genRewriteCall(
const ast::UserRewriteDecl *decl,
568 return genConstraintOrRewriteCall<pdl::ApplyNativeRewriteOp>(decl, loc,
572template <
typename PDLOpT,
typename T>
574CodeGen::genConstraintOrRewriteCall(
const T *decl, Location loc,
576 const ast::CompoundStmt *cstBody = decl->getBody();
580 ast::Type declResultType = decl->getResultType();
581 SmallVector<Type> resultTypes;
582 if (ast::TupleType tupleType = dyn_cast<ast::TupleType>(declResultType)) {
583 for (ast::Type type : tupleType.getElementTypes())
584 resultTypes.push_back(genType(type));
586 resultTypes.push_back(genType(declResultType));
588 PDLOpT pdlOp = PDLOpT::create(builder, loc, resultTypes,
589 decl->getName().getName(), inputs);
590 if (isNegated && std::is_same_v<PDLOpT, pdl::ApplyNativeConstraintOp>)
591 cast<pdl::ApplyNativeConstraintOp>(pdlOp).setIsNegated(
true);
592 return pdlOp->getResults();
596 VariableMapTy::ScopeTy varScope(variables);
601 for (
auto it : llvm::zip(inputs, decl->getInputs()))
602 variables.insert(std::get<1>(it), {std::get<0>(it)});
609 return SmallVector<Value>();
610 auto *returnStmt = dyn_cast<ast::ReturnStmt>(cstBody->
getChildren().back());
612 return SmallVector<Value>();
615 return genExpr(returnStmt->getResultExpr());
624 const llvm::SourceMgr &sourceMgr,
const ast::Module &module) {
625 CodeGen codegen(mlirContext, context, sourceMgr);
627 if (failed(
verify(*mlirModule)))
static void checkAndNestUnderRewriteOp(OpBuilder &builder, Value rootExpr, Location loc)
If the given builder is nested under a PDL PatternOp, build a rewrite operation and update the builde...
static void rewrite(DataFlowSolver &solver, MLIRContext *context, MutableArrayRef< Region > initialRegions)
Rewrite the given regions using the computing analysis.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
void loadDialect()
Load a dialect in the context.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
This class acts as an owning reference to an op, and will automatically destroy the held op on destru...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
StringRef getValue() const
Get the raw value of this expression.
Expr * getCallableExpr() const
Return the callable of this call.
MutableArrayRef< Expr * > getArguments()
Return the arguments of this call.
bool getIsNegated() const
Returns whether the result of this call is to be negated.
MutableArrayRef< Stmt * > getChildren()
Return the children of this compound statement.
This class represents the main context of the PDLL AST.
Decl * getDecl() const
Get the decl referenced by this expression.
const Name * getName() const
Return the name of the decl, or nullptr if it doesn't have one.
Type getType() const
Return the type of this expression.
VariableDecl * getVarDecl() const
Return the variable defined by this statement.
const Expr * getParentExpr() const
Get the parent expression of this access.
StringRef getMemberName() const
Return the name of the member being accessed.
This class represents a top-level AST module.
MutableArrayRef< Decl * > getChildren()
Return the children of this module.
SMRange getLoc() const
Return the location of this node.
Expr * getRootOpExpr() const
Return the root operation of this rewrite.
MutableArrayRef< Expr * > getOperands()
Return the operands of this operation.
MutableArrayRef< NamedAttributeDecl * > getAttributes()
Return the attributes of this operation.
MutableArrayRef< Expr * > getResultTypes()
Return the result types of this operation.
std::optional< StringRef > getName() const
Return the name of the operation, or std::nullopt if there isn't one.
const CompoundStmt * getBody() const
Return the body of this pattern.
std::optional< uint16_t > getBenefit() const
Return the benefit of this pattern if specified, or std::nullopt.
RangeType getType() const
Return the range result type of this expression.
MutableArrayRef< Expr * > getElements()
Return the element expressions of this range.
Type getElementType() const
Return the element type of this range.
MutableArrayRef< Expr * > getReplExprs()
Return the replacement values of this statement.
CompoundStmt * getRewriteBody() const
Return the compound rewrite body.
MutableArrayRef< Expr * > getElements()
Return the element expressions of this tuple.
StringRef getValue() const
Get the raw value of this expression.
MutableArrayRef< VariableDecl * > getResults()
Return the explicit results of the constraint declaration.
MutableArrayRef< VariableDecl * > getInputs()
Return the input arguments of this constraint.
MutableArrayRef< ConstraintRef > getConstraints()
Return the constraints of this variable.
Expr * getInitExpr() const
Return the initializer expression of this statement, or nullptr if there was no initializer.
Type getType() const
Return the type of the decl.
ArrayRef< OperandOrResult > getResults() const
Returns the results of this operation.
OwningOpRef< ModuleOp > codegenPDLLToMLIR(MLIRContext *mlirContext, const ast::Context &context, const llvm::SourceMgr &sourceMgr, const ast::Module &module)
Given a PDLL module, generate an MLIR PDL pattern module within the given MLIR context.
Include the generated interface declarations.
Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context, Type type={}, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR attribute to an MLIR context if it was valid.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
StringRef getName() const
Return the raw string name.