github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp (about)

     1  //===- LLVMIRConversionGen.cpp - MLIR LLVM IR builder generator -----------===//
     2  //
     3  // Copyright 2019 The MLIR Authors.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //   http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  // =============================================================================
    17  //
    18  // This file uses tablegen definitions of the LLVM IR Dialect operations to
    19  // generate the code building the LLVM IR from it.
    20  //
    21  //===----------------------------------------------------------------------===//
    22  
    23  #include "mlir/TableGen/GenInfo.h"
    24  #include "mlir/TableGen/Operator.h"
    25  
    26  #include "llvm/ADT/StringExtras.h"
    27  #include "llvm/ADT/Twine.h"
    28  #include "llvm/Support/FormatVariadic.h"
    29  #include "llvm/Support/raw_ostream.h"
    30  #include "llvm/TableGen/Record.h"
    31  #include "llvm/TableGen/TableGenBackend.h"
    32  
    33  using namespace llvm;
    34  using namespace mlir;
    35  
    36  static bool emitError(const Twine &message) {
    37    llvm::errs() << message << "\n";
    38    return false;
    39  }
    40  
    41  namespace {
    42  // Helper structure to return a position of the substring in a string.
    43  struct StringLoc {
    44    size_t pos;
    45    size_t length;
    46  
    47    // Take a substring identified by this location in the given string.
    48    StringRef in(StringRef str) const { return str.substr(pos, length); }
    49  
    50    // A location is invalid if its position is outside the string.
    51    explicit operator bool() { return pos != std::string::npos; }
    52  };
    53  } // namespace
    54  
    55  // Find the next TableGen variable in the given pattern.  These variables start
    56  // with a `$` character and can contain alphannumeric characters or underscores.
    57  // Return the position of the variable in the pattern and its length, including
    58  // the `$` character.  The escape syntax `$$` is also detected and returned.
    59  static StringLoc findNextVariable(StringRef str) {
    60    size_t startPos = str.find('$');
    61    if (startPos == std::string::npos)
    62      return {startPos, 0};
    63  
    64    // If we see "$$", return immediately.
    65    if (startPos != str.size() - 1 && str[startPos + 1] == '$')
    66      return {startPos, 2};
    67  
    68    // Otherwise, the symbol spans until the first character that is not
    69    // alphanumeric or '_'.
    70    size_t endPos = str.find_if_not([](char c) { return isAlnum(c) || c == '_'; },
    71                                    startPos + 1);
    72    if (endPos == std::string::npos)
    73      endPos = str.size();
    74  
    75    return {startPos, endPos - startPos};
    76  }
    77  
    78  // Check if `name` is the name of the variadic operand of `op`.  The variadic
    79  // operand can only appear at the last position in the list of operands.
    80  static bool isVariadicOperandName(const tblgen::Operator &op, StringRef name) {
    81    unsigned numOperands = op.getNumOperands();
    82    if (numOperands == 0)
    83      return false;
    84    const auto &operand = op.getOperand(numOperands - 1);
    85    return operand.isVariadic() && operand.name == name;
    86  }
    87  
    88  // Check if `result` is a known name of a result of `op`.
    89  static bool isResultName(const tblgen::Operator &op, StringRef name) {
    90    for (int i = 0, e = op.getNumResults(); i < e; ++i)
    91      if (op.getResultName(i) == name)
    92        return true;
    93    return false;
    94  }
    95  
    96  // Check if `name` is a known name of an attribute of `op`.
    97  static bool isAttributeName(const tblgen::Operator &op, StringRef name) {
    98    return llvm::any_of(
    99        op.getAttributes(),
   100        [name](const tblgen::NamedAttribute &attr) { return attr.name == name; });
   101  }
   102  
   103  // Check if `name` is a known name of an operand of `op`.
   104  static bool isOperandName(const tblgen::Operator &op, StringRef name) {
   105    for (int i = 0, e = op.getNumOperands(); i < e; ++i)
   106      if (op.getOperand(i).name == name)
   107        return true;
   108    return false;
   109  }
   110  
   111  // Emit to `os` the operator-name driven check and the call to LLVM IRBuilder
   112  // for one definition of a LLVM IR Dialect operation.  Return true on success.
   113  static bool emitOneBuilder(const Record &record, raw_ostream &os) {
   114    auto op = tblgen::Operator(record);
   115  
   116    if (!record.getValue("llvmBuilder"))
   117      return emitError("no 'llvmBuilder' field for op " + op.getOperationName());
   118  
   119    // Return early if there is no builder specified.
   120    auto builderStrRef = record.getValueAsString("llvmBuilder");
   121    if (builderStrRef.empty())
   122      return true;
   123  
   124    // Progressively create the builder string by replacing $-variables with
   125    // value lookups.  Keep only the not-yet-traversed part of the builder pattern
   126    // to avoid re-traversing the string multiple times.
   127    std::string builder;
   128    llvm::raw_string_ostream bs(builder);
   129    while (auto loc = findNextVariable(builderStrRef)) {
   130      auto name = loc.in(builderStrRef).drop_front();
   131      // First, insert the non-matched part as is.
   132      bs << builderStrRef.substr(0, loc.pos);
   133      // Then, rewrite the name based on its kind.
   134      bool isVariadicOperand = isVariadicOperandName(op, name);
   135      if (isOperandName(op, name)) {
   136        auto result = isVariadicOperand
   137                          ? formatv("lookupValues(op.{0}())", name)
   138                          : formatv("valueMapping.lookup(op.{0}())", name);
   139        bs << result;
   140      } else if (isAttributeName(op, name)) {
   141        bs << formatv("op.{0}()", name);
   142      } else if (isResultName(op, name)) {
   143        bs << formatv("valueMapping[op.{0}()]", name);
   144      } else if (name == "_resultType") {
   145        bs << "op.getResult()->getType().cast<LLVM::LLVMType>()."
   146              "getUnderlyingType()";
   147      } else if (name == "_hasResult") {
   148        bs << "opInst.getNumResults() == 1";
   149      } else if (name == "_location") {
   150        bs << "opInst.getLoc()";
   151      } else if (name == "_numOperands") {
   152        bs << "opInst.getNumOperands()";
   153      } else if (name == "$") {
   154        bs << '$';
   155      } else {
   156        return emitError(name + " is neither an argument nor a result of " +
   157                         op.getOperationName());
   158      }
   159      // Finally, only keep the untraversed part of the string.
   160      builderStrRef = builderStrRef.substr(loc.pos + loc.length);
   161    }
   162  
   163    // Output the check and the rewritten builder string.
   164    os << "if (auto op = dyn_cast<" << op.getQualCppClassName()
   165       << ">(opInst)) {\n";
   166    os << bs.str() << builderStrRef << "\n";
   167    os << "  return success();\n";
   168    os << "}\n";
   169  
   170    return true;
   171  }
   172  
   173  // Emit all builders.  Returns false on success because of the generator
   174  // registration requirements.
   175  static bool emitBuilders(const RecordKeeper &recordKeeper, raw_ostream &os) {
   176    for (const auto *def : recordKeeper.getAllDerivedDefinitions("LLVM_OpBase")) {
   177      if (!emitOneBuilder(*def, os))
   178        return true;
   179    }
   180    return false;
   181  }
   182  
   183  static mlir::GenRegistration
   184      genLLVMIRConversions("gen-llvmir-conversions",
   185                           "Generate LLVM IR conversions", emitBuilders);