216 lines · cpp
1//===----------------------------------------------------------------------===//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// TosaUtilsGen generates common utility functions for Tosa validation.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/TableGen/Attribute.h"14#include "mlir/TableGen/CodeGenHelpers.h"15#include "mlir/TableGen/EnumInfo.h"16#include "mlir/TableGen/Format.h"17#include "mlir/TableGen/GenInfo.h"18#include "mlir/TableGen/Operator.h"19#include "llvm/ADT/STLExtras.h"20#include "llvm/ADT/Sequence.h"21#include "llvm/ADT/SmallVector.h"22#include "llvm/ADT/StringExtras.h"23#include "llvm/ADT/StringMap.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/ADT/StringSet.h"26#include "llvm/Support/FormatVariadic.h"27#include "llvm/Support/raw_ostream.h"28#include "llvm/TableGen/Error.h"29#include "llvm/TableGen/Record.h"30#include "llvm/TableGen/TableGenBackend.h"31 32#include <list>33#include <optional>34 35using llvm::formatv;36using llvm::raw_ostream;37using llvm::Record;38using llvm::RecordKeeper;39using llvm::StringMap;40using llvm::StringRef;41using mlir::tblgen::Operator;42 43//===----------------------------------------------------------------------===//44// Availability Wrapper Class45//===----------------------------------------------------------------------===//46 47namespace {48// Wrapper class with helper methods for accessing availability defined in49// TableGen.50class Availability {51public:52 explicit Availability(const Record *def);53 54 // Returns the name of the direct TableGen class for this availability55 // instance.56 StringRef getClass() const;57 58 // Returns the name of the query function insided the generated C++ interface.59 StringRef getQueryFnName() const;60 61 // Returns the return type of the query function insided the generated C++62 // interface.63 StringRef getQueryFnRetType() const;64 65 // Returns the code for merging availability requirements.66 StringRef getMergeActionCode() const;67 68 // Returns the initializer expression for initializing the final availability69 // requirements.70 StringRef getMergeInitializer() const;71 72 // Returns the C++ statements for preparing availability instance.73 StringRef getMergeInstancePreparation() const;74 75 // Returns the concrete availability instance carried in this case.76 StringRef getMergeInstance() const;77 78 // Returns the underlying LLVM TableGen Record.79 const llvm::Record *getDef() const { return def; }80 81private:82 // The TableGen definition of this availability.83 const llvm::Record *def;84};85} // namespace86 87Availability::Availability(const llvm::Record *def) : def(def) {88 assert(def->isSubClassOf("Availability") &&89 "must be subclass of TableGen 'Availability' class");90}91 92StringRef Availability::getClass() const {93 if (def->getDirectSuperClasses().size() != 1) {94 PrintFatalError(def->getLoc(),95 "expected to only have one direct superclass");96 }97 return def->getDirectSuperClasses().front().first->getName();98}99 100StringRef Availability::getQueryFnRetType() const {101 return def->getValueAsString("queryFnRetType");102}103 104StringRef Availability::getQueryFnName() const {105 return def->getValueAsString("queryFnName");106}107 108StringRef Availability::getMergeActionCode() const {109 return def->getValueAsString("mergeAction");110}111 112StringRef Availability::getMergeInitializer() const {113 return def->getValueAsString("initializer");114}115 116StringRef Availability::getMergeInstancePreparation() const {117 return def->getValueAsString("instancePreparation");118}119 120StringRef Availability::getMergeInstance() const {121 return def->getValueAsString("instance");122}123 124// Returns the availability spec of the given `def`.125static std::vector<Availability> getAvailabilities(const Record &def) {126 std::vector<Availability> availabilities;127 128 if (def.getValue("availability")) {129 std::vector<const Record *> availDefs =130 def.getValueAsListOfDefs("availability");131 availabilities.reserve(availDefs.size());132 for (const Record *avail : availDefs)133 availabilities.emplace_back(avail);134 }135 136 return availabilities;137}138 139//===----------------------------------------------------------------------===//140// Tosa Availability Impl AutoGen141//===----------------------------------------------------------------------===//142 143static void emitAvailabilityImpl(const Operator &srcOp, raw_ostream &os) {144 mlir::tblgen::FmtContext fctx;145 fctx.addSubst("overall", "tblgen_overall");146 147 std::vector<Availability> opAvailabilities =148 getAvailabilities(srcOp.getDef());149 150 // First collect all availability classes this op should implement.151 // All availability instances keep information for the generated interface and152 // the instance's specific requirement. Here we remember a random instance so153 // we can get the information regarding the generated interface.154 llvm::StringMap<Availability> availClasses;155 for (const Availability &avail : opAvailabilities)156 availClasses.try_emplace(avail.getClass(), avail);157 158 // Then generate implementation for each availability class.159 for (const auto &availClass : availClasses) {160 StringRef availClassName = availClass.getKey();161 Availability avail = availClass.getValue();162 163 // Generate the implementation method signature.164 os << formatv("{0} {1}::{2}() {{\n", avail.getQueryFnRetType(),165 srcOp.getCppClassName(), avail.getQueryFnName());166 167 // Create the variable for the final requirement and initialize it.168 os << formatv(" {0} tblgen_overall = {1};\n", avail.getQueryFnRetType(),169 avail.getMergeInitializer());170 171 // Update with the op's specific availability spec.172 for (const Availability &avail : opAvailabilities)173 if (avail.getClass() == availClassName &&174 (!avail.getMergeInstancePreparation().empty() ||175 !avail.getMergeActionCode().empty())) {176 os << " {\n "177 // Prepare this instance.178 << avail.getMergeInstancePreparation()179 << "\n "180 // Merge this instance.181 << std::string(182 tgfmt(avail.getMergeActionCode(),183 &fctx.addSubst("instance", avail.getMergeInstance())))184 << ";\n }\n";185 }186 187 os << " return tblgen_overall;\n";188 os << "}\n";189 }190}191 192static bool emitAvailabilityImpl(const RecordKeeper &recordKeeper,193 raw_ostream &os) {194 llvm::emitSourceFileHeader("Tosa Op Availability Implementations", os,195 recordKeeper);196 197 auto defs = recordKeeper.getAllDerivedDefinitions("Tosa_Op");198 for (const auto *def : defs) {199 Operator op(def);200 if (def->getValueAsBit("autogenAvailability"))201 emitAvailabilityImpl(op, os);202 }203 return false;204}205 206//===----------------------------------------------------------------------===//207// Op Availability Implementation Hook Registration208//===----------------------------------------------------------------------===//209 210static mlir::GenRegistration211 genOpAvailabilityImpl("gen-tosa-avail-impls",212 "Generate Tosa operation utility definitions",213 [](const RecordKeeper &records, raw_ostream &os) {214 return emitAvailabilityImpl(records, os);215 });216