165 lines · cpp
1//===- MlirTblgenMain.cpp - MLIR Tablegen Driver main -----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Main entry function for mlir-tblgen for when built as standalone binary.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Tools/mlir-tblgen/MlirTblgenMain.h"14 15#include "mlir/TableGen/GenInfo.h"16#include "mlir/TableGen/GenNameParser.h"17#include "llvm/Support/CommandLine.h"18#include "llvm/Support/InitLLVM.h"19#include "llvm/Support/Signals.h"20#include "llvm/TableGen/Error.h"21#include "llvm/TableGen/Main.h"22#include "llvm/TableGen/Record.h"23 24using namespace mlir;25using namespace llvm;26 27enum DeprecatedAction { None, Warn, Error };28 29static DeprecatedAction actionOnDeprecatedValue;30 31// Returns if there is a use of `deprecatedInit` in `field`.32static bool findUse(const Init *field, const Init *deprecatedInit,33 llvm::DenseMap<const Init *, bool> &known) {34 if (field == deprecatedInit)35 return true;36 37 auto it = known.find(field);38 if (it != known.end())39 return it->second;40 41 auto memoize = [&](bool val) {42 known[field] = val;43 return val;44 };45 46 if (auto *defInit = dyn_cast<DefInit>(field)) {47 // Only recurse into defs if they are anonymous.48 // Non-anonymous defs are handled by the main loop, with a proper49 // deprecation warning for each. Returning true here, would cause50 // all users of a def to also emit a deprecation warning.51 if (!defInit->getDef()->isAnonymous())52 // Purposefully not memoize as to not include every def use in the map.53 // This is also a trivial case we return false for in constant time.54 return false;55 56 return memoize(57 llvm::any_of(defInit->getDef()->getValues(), [&](const RecordVal &val) {58 return findUse(val.getValue(), deprecatedInit, known);59 }));60 }61 62 if (auto *dagInit = dyn_cast<DagInit>(field)) {63 if (findUse(dagInit->getOperator(), deprecatedInit, known))64 return memoize(true);65 66 return memoize(llvm::any_of(dagInit->getArgs(), [&](const Init *arg) {67 return findUse(arg, deprecatedInit, known);68 }));69 }70 71 if (const ListInit *li = dyn_cast<ListInit>(field)) {72 return memoize(llvm::any_of(li->getElements(), [&](const Init *jt) {73 return findUse(jt, deprecatedInit, known);74 }));75 }76 77 // Purposefully don't use memoize here. There is no need to cache the result78 // for every kind of init (e.g. BitInit or StringInit), which will always79 // return false. Doing so would grow the DenseMap to include almost every Init80 // within the main file.81 return false;82}83 84// Returns if there is a use of `deprecatedInit` in `record`.85static bool findUse(Record &record, const Init *deprecatedInit,86 llvm::DenseMap<const Init *, bool> &known) {87 return llvm::any_of(record.getValues(), [&](const RecordVal &val) {88 return findUse(val.getValue(), deprecatedInit, known);89 });90}91 92static void warnOfDeprecatedUses(const RecordKeeper &records) {93 // This performs a direct check for any def marked as deprecated and then94 // finds all uses of deprecated def. Deprecated defs are not expected to be95 // either numerous or long lived.96 bool deprecatedDefsFounds = false;97 for (auto &it : records.getDefs()) {98 const RecordVal *r = it.second->getValue("odsDeprecated");99 if (!r || !r->getValue())100 continue;101 102 llvm::DenseMap<const Init *, bool> hasUse;103 if (auto *si = dyn_cast<StringInit>(r->getValue())) {104 for (auto &jt : records.getDefs()) {105 // Skip anonymous defs.106 if (jt.second->isAnonymous())107 continue;108 109 if (findUse(*jt.second, it.second->getDefInit(), hasUse)) {110 PrintWarning(jt.second->getLoc(),111 "Using deprecated def `" + it.first + "`");112 PrintNote(si->getAsUnquotedString());113 deprecatedDefsFounds = true;114 }115 }116 }117 }118 if (deprecatedDefsFounds &&119 actionOnDeprecatedValue == DeprecatedAction::Error)120 PrintFatalNote("Error'ing out due to deprecated defs");121}122 123// Generator to invoke.124static const mlir::GenInfo *generator;125 126// TableGenMain requires a function pointer so this function is passed in which127// simply wraps the call to the generator.128static bool mlirTableGenMain(raw_ostream &os, const RecordKeeper &records) {129 if (actionOnDeprecatedValue != DeprecatedAction::None)130 warnOfDeprecatedUses(records);131 132 if (!generator) {133 os << records;134 return false;135 }136 return generator->invoke(records, os);137}138 139int mlir::MlirTblgenMain(int argc, char **argv) {140 141 llvm::InitLLVM y(argc, argv);142 143 llvm::cl::opt<DeprecatedAction, true> actionOnDeprecated(144 "on-deprecated", llvm::cl::desc("Action to perform on deprecated def"),145 llvm::cl::values(146 clEnumValN(DeprecatedAction::None, "none", "No action"),147 clEnumValN(DeprecatedAction::Warn, "warn", "Warn on use"),148 clEnumValN(DeprecatedAction::Error, "error", "Error on use")),149 cl::location(actionOnDeprecatedValue), llvm::cl::init(Warn));150 151 llvm::cl::opt<const mlir::GenInfo *, true, mlir::GenNameParser> generator(152 "", llvm::cl::desc("Generator to run"), cl::location(::generator));153 154 cl::ParseCommandLineOptions(argc, argv);155 156 return TableGenMain(157 argv[0], [](TableGenOutputFiles &OutFiles, const RecordKeeper &RK) {158 std::string S;159 raw_string_ostream OS(S);160 bool Res = mlirTableGenMain(OS, RK);161 OutFiles = {S, {}};162 return Res;163 });164}165