diff --git a/mlir/test/mlir-tblgen/llvm-intrinsics.td b/mlir/test/mlir-tblgen/llvm-intrinsics.td deleted file mode 100644 --- a/mlir/test/mlir-tblgen/llvm-intrinsics.td +++ /dev/null @@ -1,99 +0,0 @@ -// This checks that we can consume LLVM's Intrinsic definitions from TableGen -// files and produce ODS. Unlike MLIR, LLVM's main Intrinsics.td file that -// contains the definition of the Intrinsic class also includes files for -// platform-specific intrinsics, so we need to give it to TableGen instead of -// writing a local test source. We filter out platform-specific intrinsic -// includes from the main file to avoid unnecessary dependencies and decrease -// the test cost. The command-line flags further ensure a specific intrinsic is -// processed and we only check the output below. -// We also verify emission of type specialization for overloadable intrinsics. -// -// RUN: cat %S/../../../llvm/include/llvm/IR/Intrinsics.td \ -// RUN: | grep -v "llvm/IR/Intrinsics" \ -// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=ptrmask \ -// RUN: | FileCheck %s - -// CHECK-LABEL: def LLVM_ptrmask -// CHECK: LLVM_IntrOp<"ptrmask -// The result of this intrinsic result is overloadable. -// CHECK: [0] -// The second operand is overloadable, but the first operand needs to -// match the result type. -// CHECK: [1] -// It has no side effects. -// CHECK: [NoMemoryEffect] -// It has a result. -// CHECK: 1, -// It does not require an access group. -// CHECK: 0, -// It does not require alias scopes. -// CHECK: 0> -// CHECK: Arguments<(ins LLVM_Type, LLVM_Type - -//---------------------------------------------------------------------------// - -// This checks that we can define an op that takes in an access group metadata. -// -// RUN: cat %S/../../../llvm/include/llvm/IR/Intrinsics.td \ -// RUN: | grep -v "llvm/IR/Intrinsics" \ -// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=ptrmask --llvmir-intrinsics-access-group-regexp=ptrmask \ -// RUN: | FileCheck --check-prefix=GROUPS %s - -// GROUPS-LABEL: def LLVM_ptrmask -// GROUPS: LLVM_IntrOp<"ptrmask -// It has no side effects. -// GROUPS: [NoMemoryEffect] -// It has a result. -// GROUPS: 1, -// It requires generation of an access group LLVM metadata. -// GROUPS: 1, -// It does not require alias scopes. -// GROUPS: 0> -// It has an access group attribute. -// GROUPS: OptionalAttr:$access_groups - -//---------------------------------------------------------------------------// - -// This checks that we can define an op that takes in alias scopes metadata. -// -// RUN: cat %S/../../../llvm/include/llvm/IR/Intrinsics.td \ -// RUN: | grep -v "llvm/IR/Intrinsics" \ -// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=ptrmask --llvmir-intrinsics-alias-scopes-regexp=ptrmask \ -// RUN: | FileCheck --check-prefix=ALIAS %s - -// ALIAS-LABEL: def LLVM_ptrmask -// ALIAS: LLVM_IntrOp<"ptrmask -// It has no side effects. -// ALIAS: [NoMemoryEffect] -// It has a result. -// ALIAS: 1, -// It does not require an access group. -// ALIAS: 0, -// It requires generation of alias scopes LLVM metadata. -// ALIAS: 1> -// It has alias scopes and noalias. -// ALIAS: OptionalAttr:$alias_scopes -// ALIAS: OptionalAttr:$noalias_scopes -// ALIAS: OptionalAttr:$tbaa - -//---------------------------------------------------------------------------// - -// This checks that the ODS we produce can be consumed by MLIR tablegen. We only -// make sure the entire process does not fail and produces some C++. The shape -// of this C++ code is tested by ODS tests. - -// RUN: cat %S/../../../llvm/include/llvm/IR/Intrinsics.td \ -// RUN: | grep -v "llvm/IR/Intrinsics" \ -// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=vastart \ -// RUN: | mlir-tblgen -gen-op-decls -I %S/../../include \ -// RUN: | FileCheck --check-prefix=ODS %s - -// ODS-LABEL: class vastart - -// RUN: cat %S/../../../llvm/include/llvm/IR/Intrinsics.td \ -// RUN: | grep -v "llvm/IR/Intrinsics" \ -// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=ptrmask -dialect-opclass-base My_OpBase \ -// RUN: | FileCheck %s --check-prefix=DIALECT-OPBASE - -// DIALECT-OPBASE-LABEL: def LLVM_ptrmask -// DIALECT-OPBASE: My_OpBase<"ptrmask diff --git a/mlir/tools/mlir-tblgen/CMakeLists.txt b/mlir/tools/mlir-tblgen/CMakeLists.txt --- a/mlir/tools/mlir-tblgen/CMakeLists.txt +++ b/mlir/tools/mlir-tblgen/CMakeLists.txt @@ -14,7 +14,6 @@ EnumsGen.cpp FormatGen.cpp LLVMIRConversionGen.cpp - LLVMIRIntrinsicGen.cpp mlir-tblgen.cpp OpClass.cpp OpDefinitionsGen.cpp diff --git a/mlir/tools/mlir-tblgen/LLVMIRIntrinsicGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRIntrinsicGen.cpp deleted file mode 100644 --- a/mlir/tools/mlir-tblgen/LLVMIRIntrinsicGen.cpp +++ /dev/null @@ -1,267 +0,0 @@ -//===- LLVMIntrinsicGen.cpp - TableGen utility for converting intrinsics --===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This is a TableGen generator that converts TableGen definitions for LLVM -// intrinsics to TableGen definitions for MLIR operations. -// -//===----------------------------------------------------------------------===// - -#include "mlir/TableGen/GenInfo.h" - -#include "llvm/ADT/SmallBitVector.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/MachineValueType.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Regex.h" -#include "llvm/Support/Signals.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Main.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" - -static llvm::cl::OptionCategory intrinsicGenCat("Intrinsics Generator Options"); - -static llvm::cl::opt - nameFilter("llvmir-intrinsics-filter", - llvm::cl::desc("Only keep the intrinsics with the specified " - "substring in their record name"), - llvm::cl::cat(intrinsicGenCat)); - -static llvm::cl::opt - opBaseClass("dialect-opclass-base", - llvm::cl::desc("The base class for the ops in the dialect we " - "are planning to emit"), - llvm::cl::init("LLVM_IntrOp"), llvm::cl::cat(intrinsicGenCat)); - -static llvm::cl::opt accessGroupRegexp( - "llvmir-intrinsics-access-group-regexp", - llvm::cl::desc("Mark intrinsics that match the specified " - "regexp as taking an access group metadata"), - llvm::cl::cat(intrinsicGenCat)); - -static llvm::cl::opt aliasScopesRegexp( - "llvmir-intrinsics-alias-scopes-regexp", - llvm::cl::desc("Mark intrinsics that match the specified " - "regexp as taking alias.scopes and noalias metadata"), - llvm::cl::cat(intrinsicGenCat)); - -// Used to represent the indices of overloadable operands/results. -using IndicesTy = llvm::SmallBitVector; - -/// Return a CodeGen value type entry from a type record. -static llvm::MVT::SimpleValueType getValueType(const llvm::Record *rec) { - return (llvm::MVT::SimpleValueType)rec->getValueAsDef("VT")->getValueAsInt( - "Value"); -} - -/// Return the indices of the definitions in a list of definitions that -/// represent overloadable types -static IndicesTy getOverloadableTypeIdxs(const llvm::Record &record, - const char *listName) { - auto results = record.getValueAsListOfDefs(listName); - IndicesTy overloadedOps(results.size()); - for (const auto &r : llvm::enumerate(results)) { - llvm::MVT::SimpleValueType vt = getValueType(r.value()); - switch (vt) { - case llvm::MVT::iAny: - case llvm::MVT::fAny: - case llvm::MVT::Any: - case llvm::MVT::iPTRAny: - case llvm::MVT::vAny: - overloadedOps.set(r.index()); - break; - default: - continue; - } - } - return overloadedOps; -} - -namespace { -/// A wrapper for LLVM's Tablegen class `Intrinsic` that provides accessors to -/// the fields of the record. -class LLVMIntrinsic { -public: - LLVMIntrinsic(const llvm::Record &record) : record(record) {} - - /// Get the name of the operation to be used in MLIR. Uses the appropriate - /// field if not empty, constructs a name by replacing underscores with dots - /// in the record name otherwise. - std::string getOperationName() const { - llvm::StringRef name = record.getValueAsString(fieldName); - if (!name.empty()) - return name.str(); - - name = record.getName(); - assert(name.startswith("int_") && - "LLVM intrinsic names are expected to start with 'int_'"); - name = name.drop_front(4); - llvm::SmallVector chunks; - llvm::StringRef targetPrefix = record.getValueAsString("TargetPrefix"); - name.split(chunks, '_'); - auto *chunksBegin = chunks.begin(); - // Remove the target prefix from target specific intrinsics. - if (!targetPrefix.empty()) { - assert(targetPrefix == *chunksBegin && - "Intrinsic has TargetPrefix, but " - "record name doesn't begin with it"); - assert(chunks.size() >= 2 && - "Intrinsic has TargetPrefix, but " - "chunks has only one element meaning the intrinsic name is empty"); - ++chunksBegin; - } - return llvm::join(chunksBegin, chunks.end(), "."); - } - - /// Get the name of the record without the "intrinsic" prefix. - llvm::StringRef getProperRecordName() const { - llvm::StringRef name = record.getName(); - assert(name.startswith("int_") && - "LLVM intrinsic names are expected to start with 'int_'"); - return name.drop_front(4); - } - - /// Get the number of operands. - unsigned getNumOperands() const { - auto operands = record.getValueAsListOfDefs(fieldOperands); - assert(llvm::all_of(operands, - [](const llvm::Record *r) { - return r->isSubClassOf("LLVMType"); - }) && - "expected operands to be of LLVM type"); - return operands.size(); - } - - /// Get the number of results. Note that LLVM does not support multi-value - /// operations so, in fact, multiple results will be returned as a value of - /// structure type. - unsigned getNumResults() const { - auto results = record.getValueAsListOfDefs(fieldResults); - for (const llvm::Record *r : results) { - (void)r; - assert(r->isSubClassOf("LLVMType") && - "expected operands to be of LLVM type"); - } - return results.size(); - } - - /// Return true if the intrinsic may have side effects, i.e. does not have the - /// `IntrNoMem` property. - bool hasSideEffects() const { - return llvm::none_of( - record.getValueAsListOfDefs(fieldTraits), - [](const llvm::Record *r) { return r->getName() == "IntrNoMem"; }); - } - - /// Return true if the intrinsic is commutative, i.e. has the respective - /// property. - bool isCommutative() const { - return llvm::any_of( - record.getValueAsListOfDefs(fieldTraits), - [](const llvm::Record *r) { return r->getName() == "Commutative"; }); - } - - IndicesTy getOverloadableOperandsIdxs() const { - return getOverloadableTypeIdxs(record, fieldOperands); - } - - IndicesTy getOverloadableResultsIdxs() const { - return getOverloadableTypeIdxs(record, fieldResults); - } - -private: - /// Names of the fields in the Intrinsic LLVM Tablegen class. - const char *fieldName = "LLVMName"; - const char *fieldOperands = "ParamTypes"; - const char *fieldResults = "RetTypes"; - const char *fieldTraits = "IntrProperties"; - - const llvm::Record &record; -}; -} // namespace - -/// Prints the elements in "range" separated by commas and surrounded by "[]". -template -void printBracketedRange(const Range &range, llvm::raw_ostream &os) { - os << '['; - llvm::interleaveComma(range, os); - os << ']'; -} - -/// Emits ODS (TableGen-based) code for `record` representing an LLVM intrinsic. -/// Returns true on error, false on success. -static bool emitIntrinsic(const llvm::Record &record, llvm::raw_ostream &os) { - LLVMIntrinsic intr(record); - - llvm::Regex accessGroupMatcher(accessGroupRegexp); - bool requiresAccessGroup = - !accessGroupRegexp.empty() && accessGroupMatcher.match(record.getName()); - - llvm::Regex aliasScopesMatcher(aliasScopesRegexp); - bool requiresAliasAnalysis = - !aliasScopesRegexp.empty() && aliasScopesMatcher.match(record.getName()); - - // Prepare strings for traits, if any. - llvm::SmallVector traits; - if (intr.isCommutative()) - traits.push_back("Commutative"); - if (!intr.hasSideEffects()) - traits.push_back("NoMemoryEffect"); - - // Prepare strings for operands. - llvm::SmallVector operands(intr.getNumOperands(), - "LLVM_Type"); - if (requiresAccessGroup) - operands.push_back("OptionalAttr:$access_groups"); - if (requiresAliasAnalysis) { - operands.push_back("OptionalAttr:$alias_scopes"); - operands.push_back("OptionalAttr:$noalias_scopes"); - operands.push_back("OptionalAttr:$tbaa"); - } - - // Emit the definition. - os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass - << "<\"" << intr.getOperationName() << "\", "; - printBracketedRange(intr.getOverloadableResultsIdxs().set_bits(), os); - os << ", "; - printBracketedRange(intr.getOverloadableOperandsIdxs().set_bits(), os); - os << ", "; - printBracketedRange(traits, os); - os << ", " << intr.getNumResults() << ", " - << (requiresAccessGroup ? "1" : "0") << ", " - << (requiresAliasAnalysis ? "1" : "0") << ">, Arguments<(ins" - << (operands.empty() ? "" : " "); - llvm::interleaveComma(operands, os); - os << ")>;\n\n"; - - return false; -} - -/// Traverses the list of TableGen definitions derived from the "Intrinsic" -/// class and generates MLIR ODS definitions for those intrinsics that have -/// the name matching the filter. -static bool emitIntrinsics(const llvm::RecordKeeper &records, - llvm::raw_ostream &os) { - llvm::emitSourceFileHeader("Operations for LLVM intrinsics", os); - os << "include \"mlir/Dialect/LLVMIR/LLVMOpBase.td\"\n"; - os << "include \"mlir/Interfaces/SideEffectInterfaces.td\"\n\n"; - - auto defs = records.getAllDerivedDefinitions("Intrinsic"); - for (const llvm::Record *r : defs) { - if (!nameFilter.empty() && !r->getName().contains(nameFilter)) - continue; - if (emitIntrinsic(*r, os)) - return true; - } - - return false; -} - -static mlir::GenRegistration genLLVMIRIntrinsics("gen-llvmir-intrinsics", - "Generate LLVM IR intrinsics", - emitIntrinsics);