19#include "llvm/ADT/StringRef.h"
27#define GEN_PASS_DEF_IDIOMRECOGNIZER
28#include "clang/CIR/Dialect/Passes.h.inc"
35bool isNoBuiltin(CallOp call, llvm::StringRef
name) {
36 if (call->hasAttr(cir::CIRDialect::getBuiltinAttrName()))
38 if (call->hasAttr(cir::CIRDialect::getNoBuiltinAttrName()))
40 auto noBuiltins = call->getAttrOfType<mlir::ArrayAttr>(
41 cir::CIRDialect::getNoBuiltinsAttrName());
44 return noBuiltins.empty() ||
45 llvm::any_of(noBuiltins, [
name](mlir::Attribute entry) {
46 auto builtinName = mlir::dyn_cast<mlir::StringAttr>(entry);
47 return builtinName && builtinName.getValue() ==
name;
52template <
typename... TargetOps>
class StdRecognizer {
53 template <
typename TargetOp,
size_t... Indices>
54 static TargetOp buildCall(cir::CIRBaseBuilderTy &builder, CallOp call,
55 std::index_sequence<Indices...>) {
56 return TargetOp::create(builder, call.getLoc(),
57 call->getResult(0).getType(),
58 call.getOperand(Indices)..., call.getCalleeAttr());
61 template <
typename TargetOp>
62 static bool raiseOne(CallOp call, mlir::MLIRContext &context,
63 mlir::SymbolTableCollection &symbolTables) {
65 if (!call.getCallee() || call.getMusttail() ||
66 !TargetOp::signatureMatches(call->getOperandTypes(),
67 call->getResultTypes()))
70 if constexpr (TargetOp::hasKnownFuncKind()) {
74 cir::FuncOp callee = call.resolveCalleeInTable(symbolTables);
75 if (!callee || callee.getFunctionType().isVarArg())
77 auto funcIdentity = mlir::dyn_cast_if_present<cir::FuncIdentityAttr>(
78 callee.getFuncInfoAttr());
79 if (!funcIdentity || funcIdentity.getKind() != TargetOp::getFuncKind())
86 if (*call.getCallee() != TargetOp::getFunctionName() ||
87 isNoBuiltin(call, TargetOp::getFunctionName()))
92 cir::FuncOp callee = call.resolveCalleeInTable(symbolTables);
93 if (callee && callee.getFunctionType().isVarArg())
97 cir::CIRBaseBuilderTy builder(context);
98 builder.setInsertionPointAfter(call.getOperation());
99 constexpr unsigned numArgs = TargetOp::getNumArgs();
101 buildCall<TargetOp>(builder, call, std::make_index_sequence<numArgs>());
107 call->getName().walkInherentAttrs(
108 call, [&](llvm::StringRef name, mlir::Attribute &attr) {
109 if (name != call.getCalleeAttrName().getValue())
110 op->setDiscardableAttr(name, attr);
112 for (mlir::NamedAttribute attr : call->getDiscardableAttrs())
113 op->setDiscardableAttr(
attr.getName(),
attr.getValue());
114 call.replaceAllUsesWith(op);
121 static bool raise(CallOp call, mlir::MLIRContext &context,
122 mlir::SymbolTableCollection &symbolTables) {
123 return (raiseOne<TargetOps>(call, context, symbolTables) || ...);
128using RecognizedStdOps = StdRecognizer<StdFindOp, StrLenOp>;
130struct IdiomRecognizerPass
131 :
public impl::IdiomRecognizerBase<IdiomRecognizerPass> {
132 IdiomRecognizerPass() =
default;
134 void runOnOperation()
override;
136 void recognizeStandardLibraryCall(CallOp call,
137 mlir::SymbolTableCollection &symbolTables);
141void IdiomRecognizerPass::recognizeStandardLibraryCall(
142 CallOp call, mlir::SymbolTableCollection &symbolTables) {
143 RecognizedStdOps::raise(call, getContext(), symbolTables);
146void IdiomRecognizerPass::runOnOperation() {
149 mlir::SymbolTableCollection symbolTables;
151 getOperation()->walk([&](CallOp callOp) {
153 std::optional<llvm::StringRef> callee = callOp.getCallee();
157 recognizeStandardLibraryCall(callOp, symbolTables);
162 return std::make_unique<IdiomRecognizerPass>();
const internal::VariadicAllOfMatcher< Attr > attr
std::unique_ptr< Pass > createIdiomRecognizerPass()