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-exception 6 // 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/FormatVariadic.h" 19 #include "llvm/Support/InitLLVM.h" 20 #include "llvm/Support/Signals.h" 21 #include "llvm/TableGen/Error.h" 22 #include "llvm/TableGen/Main.h" 23 #include "llvm/TableGen/Record.h" 24 25 using namespace mlir; 26 using namespace llvm; 27 28 enum DeprecatedAction { None, Warn, Error }; 29 30 static DeprecatedAction actionOnDeprecatedValue; 31 32 // Returns if there is a use of `deprecatedInit` in `field`. 33 static bool findUse(const Init *field, const Init *deprecatedInit, 34 llvm::DenseMap<const Init *, bool> &known) { 35 if (field == deprecatedInit) 36 return true; 37 38 auto it = known.find(field); 39 if (it != known.end()) 40 return it->second; 41 42 auto memoize = [&](bool val) { 43 known[field] = val; 44 return val; 45 }; 46 47 if (auto *defInit = dyn_cast<DefInit>(field)) { 48 // Only recurse into defs if they are anonymous. 49 // Non-anonymous defs are handled by the main loop, with a proper 50 // deprecation warning for each. Returning true here, would cause 51 // all users of a def to also emit a deprecation warning. 52 if (!defInit->getDef()->isAnonymous()) 53 // Purposefully not memoize as to not include every def use in the map. 54 // This is also a trivial case we return false for in constant time. 55 return false; 56 57 return memoize( 58 llvm::any_of(defInit->getDef()->getValues(), [&](const RecordVal &val) { 59 return findUse(val.getValue(), deprecatedInit, known); 60 })); 61 } 62 63 if (auto *dagInit = dyn_cast<DagInit>(field)) { 64 if (findUse(dagInit->getOperator(), deprecatedInit, known)) 65 return memoize(true); 66 67 return memoize(llvm::any_of(dagInit->getArgs(), [&](const Init *arg) { 68 return findUse(arg, deprecatedInit, known); 69 })); 70 } 71 72 if (const ListInit *li = dyn_cast<ListInit>(field)) { 73 return memoize(llvm::any_of(li->getValues(), [&](const Init *jt) { 74 return findUse(jt, deprecatedInit, known); 75 })); 76 } 77 78 // Purposefully don't use memoize here. There is no need to cache the result 79 // for every kind of init (e.g. BitInit or StringInit), which will always 80 // return false. Doing so would grow the DenseMap to include almost every Init 81 // within the main file. 82 return false; 83 } 84 85 // Returns if there is a use of `deprecatedInit` in `record`. 86 static bool findUse(Record &record, const Init *deprecatedInit, 87 llvm::DenseMap<const Init *, bool> &known) { 88 return llvm::any_of(record.getValues(), [&](const RecordVal &val) { 89 return findUse(val.getValue(), deprecatedInit, known); 90 }); 91 } 92 93 static void warnOfDeprecatedUses(const RecordKeeper &records) { 94 // This performs a direct check for any def marked as deprecated and then 95 // finds all uses of deprecated def. Deprecated defs are not expected to be 96 // either numerous or long lived. 97 bool deprecatedDefsFounds = false; 98 for (auto &it : records.getDefs()) { 99 const RecordVal *r = it.second->getValue("odsDeprecated"); 100 if (!r || !r->getValue()) 101 continue; 102 103 llvm::DenseMap<const Init *, bool> hasUse; 104 if (auto *si = dyn_cast<StringInit>(r->getValue())) { 105 for (auto &jt : records.getDefs()) { 106 // Skip anonymous defs. 107 if (jt.second->isAnonymous()) 108 continue; 109 110 if (findUse(*jt.second, it.second->getDefInit(), hasUse)) { 111 PrintWarning(jt.second->getLoc(), 112 "Using deprecated def `" + it.first + "`"); 113 PrintNote(si->getAsUnquotedString()); 114 deprecatedDefsFounds = true; 115 } 116 } 117 } 118 } 119 if (deprecatedDefsFounds && 120 actionOnDeprecatedValue == DeprecatedAction::Error) 121 PrintFatalNote("Error'ing out due to deprecated defs"); 122 } 123 124 // Generator to invoke. 125 static const mlir::GenInfo *generator; 126 127 // TableGenMain requires a function pointer so this function is passed in which 128 // simply wraps the call to the generator. 129 static bool mlirTableGenMain(raw_ostream &os, const RecordKeeper &records) { 130 if (actionOnDeprecatedValue != DeprecatedAction::None) 131 warnOfDeprecatedUses(records); 132 133 if (!generator) { 134 os << records; 135 return false; 136 } 137 return generator->invoke(records, os); 138 } 139 140 int mlir::MlirTblgenMain(int argc, char **argv) { 141 142 llvm::InitLLVM y(argc, argv); 143 144 llvm::cl::opt<DeprecatedAction, true> actionOnDeprecated( 145 "on-deprecated", llvm::cl::desc("Action to perform on deprecated def"), 146 llvm::cl::values( 147 clEnumValN(DeprecatedAction::None, "none", "No action"), 148 clEnumValN(DeprecatedAction::Warn, "warn", "Warn on use"), 149 clEnumValN(DeprecatedAction::Error, "error", "Error on use")), 150 cl::location(actionOnDeprecatedValue), llvm::cl::init(Warn)); 151 152 llvm::cl::opt<const mlir::GenInfo *, true, mlir::GenNameParser> generator( 153 "", llvm::cl::desc("Generator to run"), cl::location(::generator)); 154 155 cl::ParseCommandLineOptions(argc, argv); 156 157 return TableGenMain(argv[0], &mlirTableGenMain); 158 } 159