brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · daf3d49 Raw
278 lines · cpp
1//===- LLVMIntrinsicGen.cpp - TableGen utility for converting intrinsics --===//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// This is a TableGen generator that converts TableGen definitions for LLVM10// intrinsics to TableGen definitions for MLIR operations.11//12//===----------------------------------------------------------------------===//13 14#include "mlir/TableGen/GenInfo.h"15 16#include "llvm/ADT/SmallBitVector.h"17#include "llvm/ADT/StringSwitch.h"18#include "llvm/CodeGenTypes/MachineValueType.h"19#include "llvm/Support/CommandLine.h"20#include "llvm/Support/PrettyStackTrace.h"21#include "llvm/Support/Regex.h"22#include "llvm/Support/Signals.h"23#include "llvm/TableGen/Error.h"24#include "llvm/TableGen/Main.h"25#include "llvm/TableGen/Record.h"26#include "llvm/TableGen/TableGenBackend.h"27 28using llvm::Record;29using llvm::RecordKeeper;30using llvm::Regex;31using namespace mlir;32 33static llvm::cl::OptionCategory intrinsicGenCat("Intrinsics Generator Options");34 35static llvm::cl::opt<std::string>36    nameFilter("llvmir-intrinsics-filter",37               llvm::cl::desc("Only keep the intrinsics with the specified "38                              "substring in their record name"),39               llvm::cl::cat(intrinsicGenCat));40 41static llvm::cl::opt<std::string>42    opBaseClass("dialect-opclass-base",43                llvm::cl::desc("The base class for the ops in the dialect we "44                               "are planning to emit"),45                llvm::cl::init("LLVM_IntrOp"), llvm::cl::cat(intrinsicGenCat));46 47static llvm::cl::opt<std::string> accessGroupRegexp(48    "llvmir-intrinsics-access-group-regexp",49    llvm::cl::desc("Mark intrinsics that match the specified "50                   "regexp as taking an access group metadata"),51    llvm::cl::cat(intrinsicGenCat));52 53static llvm::cl::opt<std::string> aliasAnalysisRegexp(54    "llvmir-intrinsics-alias-analysis-regexp",55    llvm::cl::desc("Mark intrinsics that match the specified "56                   "regexp as taking alias.scopes, noalias, and tbaa metadata"),57    llvm::cl::cat(intrinsicGenCat));58 59// Used to represent the indices of overloadable operands/results.60using IndicesTy = llvm::SmallBitVector;61 62/// Return a CodeGen value type entry from a type record.63static llvm::MVT::SimpleValueType getValueType(const Record *rec) {64  return StringSwitch<llvm::MVT::SimpleValueType>(65             rec->getValueAsDef("VT")->getValueAsString("LLVMName"))66#define GET_VT_ATTR(Ty, Sz, Any, Int, FP, Vec, Sc, Tup, NF, NElem, EltTy)      \67  .Case(#Ty, llvm::MVT::Ty)68#include "llvm/CodeGen/GenVT.inc"69#undef GET_VT_ATTR70      .Case("INVALID_SIMPLE_VALUE_TYPE", llvm::MVT::INVALID_SIMPLE_VALUE_TYPE);71}72 73/// Return the indices of the definitions in a list of definitions that74/// represent overloadable types75static IndicesTy getOverloadableTypeIdxs(const Record &record,76                                         const char *listName) {77  auto results = record.getValueAsListOfDefs(listName);78  IndicesTy overloadedOps(results.size());79  for (const auto &r : llvm::enumerate(results)) {80    llvm::MVT::SimpleValueType vt = getValueType(r.value());81    switch (vt) {82    case llvm::MVT::iAny:83    case llvm::MVT::fAny:84    case llvm::MVT::Any:85    case llvm::MVT::pAny:86    case llvm::MVT::vAny:87      overloadedOps.set(r.index());88      break;89    default:90      continue;91    }92  }93  return overloadedOps;94}95 96namespace {97/// A wrapper for LLVM's Tablegen class `Intrinsic` that provides accessors to98/// the fields of the record.99class LLVMIntrinsic {100public:101  LLVMIntrinsic(const Record &record) : record(record) {}102 103  /// Get the name of the operation to be used in MLIR.  Uses the appropriate104  /// field if not empty, constructs a name by replacing underscores with dots105  /// in the record name otherwise.106  std::string getOperationName() const {107    StringRef name = record.getValueAsString(fieldName);108    if (!name.empty())109      return name.str();110 111    name = record.getName();112    assert(name.starts_with("int_") &&113           "LLVM intrinsic names are expected to start with 'int_'");114    name = name.drop_front(4);115    SmallVector<StringRef, 8> chunks;116    StringRef targetPrefix = record.getValueAsString("TargetPrefix");117    name.split(chunks, '_');118    auto *chunksBegin = chunks.begin();119    // Remove the target prefix from target specific intrinsics.120    if (!targetPrefix.empty()) {121      assert(targetPrefix == *chunksBegin &&122             "Intrinsic has TargetPrefix, but "123             "record name doesn't begin with it");124      assert(chunks.size() >= 2 &&125             "Intrinsic has TargetPrefix, but "126             "chunks has only one element meaning the intrinsic name is empty");127      ++chunksBegin;128    }129    return llvm::join(chunksBegin, chunks.end(), ".");130  }131 132  /// Get the name of the record without the "intrinsic" prefix.133  StringRef getProperRecordName() const {134    StringRef name = record.getName();135    assert(name.starts_with("int_") &&136           "LLVM intrinsic names are expected to start with 'int_'");137    return name.drop_front(4);138  }139 140  /// Get the number of operands.141  unsigned getNumOperands() const {142    auto operands = record.getValueAsListOfDefs(fieldOperands);143    assert(llvm::all_of(144               operands,145               [](const Record *r) { return r->isSubClassOf("LLVMType"); }) &&146           "expected operands to be of LLVM type");147    return operands.size();148  }149 150  /// Get the number of results.  Note that LLVM does not support multi-value151  /// operations so, in fact, multiple results will be returned as a value of152  /// structure type.153  unsigned getNumResults() const {154    auto results = record.getValueAsListOfDefs(fieldResults);155    for (const Record *r : results) {156      (void)r;157      assert(r->isSubClassOf("LLVMType") &&158             "expected operands to be of LLVM type");159    }160    return results.size();161  }162 163  /// Return true if the intrinsic may have side effects, i.e. does not have the164  /// `IntrNoMem` property.165  bool hasSideEffects() const {166    return llvm::none_of(167        record.getValueAsListOfDefs(fieldTraits),168        [](const Record *r) { return r->getName() == "IntrNoMem"; });169  }170 171  /// Return true if the intrinsic is commutative, i.e. has the respective172  /// property.173  bool isCommutative() const {174    return llvm::any_of(175        record.getValueAsListOfDefs(fieldTraits),176        [](const Record *r) { return r->getName() == "Commutative"; });177  }178 179  IndicesTy getOverloadableOperandsIdxs() const {180    return getOverloadableTypeIdxs(record, fieldOperands);181  }182 183  IndicesTy getOverloadableResultsIdxs() const {184    return getOverloadableTypeIdxs(record, fieldResults);185  }186 187private:188  /// Names of the fields in the Intrinsic LLVM Tablegen class.189  const char *fieldName = "LLVMName";190  const char *fieldOperands = "ParamTypes";191  const char *fieldResults = "RetTypes";192  const char *fieldTraits = "IntrProperties";193 194  const Record &record;195};196} // namespace197 198/// Prints the elements in "range" separated by commas and surrounded by "[]".199template <typename Range>200void printBracketedRange(const Range &range, llvm::raw_ostream &os) {201  os << '[';202  llvm::interleaveComma(range, os);203  os << ']';204}205 206/// Emits ODS (TableGen-based) code for `record` representing an LLVM intrinsic.207/// Returns true on error, false on success.208static bool emitIntrinsic(const Record &record, llvm::raw_ostream &os) {209  LLVMIntrinsic intr(record);210 211  Regex accessGroupMatcher(accessGroupRegexp);212  bool requiresAccessGroup =213      !accessGroupRegexp.empty() && accessGroupMatcher.match(record.getName());214 215  Regex aliasAnalysisMatcher(aliasAnalysisRegexp);216  bool requiresAliasAnalysis = !aliasAnalysisRegexp.empty() &&217                               aliasAnalysisMatcher.match(record.getName());218 219  // Prepare strings for traits, if any.220  SmallVector<StringRef, 2> traits;221  if (intr.isCommutative())222    traits.push_back("Commutative");223  if (!intr.hasSideEffects())224    traits.push_back("NoMemoryEffect");225 226  // Prepare strings for operands.227  SmallVector<StringRef, 8> operands(intr.getNumOperands(), "LLVM_Type");228  if (requiresAccessGroup)229    operands.push_back(230        "OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups");231  if (requiresAliasAnalysis) {232    operands.push_back("OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes");233    operands.push_back(234        "OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes");235    operands.push_back("OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa");236  }237 238  // Emit the definition.239  os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass240     << "<\"" << intr.getOperationName() << "\", ";241  printBracketedRange(intr.getOverloadableResultsIdxs().set_bits(), os);242  os << ", ";243  printBracketedRange(intr.getOverloadableOperandsIdxs().set_bits(), os);244  os << ", ";245  printBracketedRange(traits, os);246  os << ", " << intr.getNumResults() << ", "247     << (requiresAccessGroup ? "1" : "0") << ", "248     << (requiresAliasAnalysis ? "1" : "0") << ">, Arguments<(ins"249     << (operands.empty() ? "" : " ");250  llvm::interleaveComma(operands, os);251  os << ")>;\n\n";252 253  return false;254}255 256/// Traverses the list of TableGen definitions derived from the "Intrinsic"257/// class and generates MLIR ODS definitions for those intrinsics that have258/// the name matching the filter.259static bool emitIntrinsics(const RecordKeeper &records, llvm::raw_ostream &os) {260  llvm::emitSourceFileHeader("Operations for LLVM intrinsics", os, records);261  os << "include \"mlir/Dialect/LLVMIR/LLVMOpBase.td\"\n";262  os << "include \"mlir/Interfaces/SideEffectInterfaces.td\"\n\n";263 264  auto defs = records.getAllDerivedDefinitions("Intrinsic");265  for (const Record *r : defs) {266    if (!nameFilter.empty() && !r->getName().contains(nameFilter))267      continue;268    if (emitIntrinsic(*r, os))269      return true;270  }271 272  return false;273}274 275static mlir::GenRegistration genLLVMIRIntrinsics("gen-llvmir-intrinsics",276                                                 "Generate LLVM IR intrinsics",277                                                 emitIntrinsics);278