2020-01-18 01:16:07 +08:00
|
|
|
//===- LLVMIntrinsicGen.cpp - TableGen utility for converting intrinsics --===//
|
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2020-01-18 01:16:07 +08:00
|
|
|
// 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"
|
|
|
|
|
[mlir] Fix LLVM intrinsic convesion generator for overloadable types.
Summary:
If an intrinsic has overloadable types like llvm_anyint_ty or
llvm_anyfloat_ty then to getDeclaration() we need to pass a list
of the types that are "undefined" essentially concretizing them.
This patch add support for deriving such types from the MLIR op
that has been matched.
Reviewers: andydavis1, ftynse, nicolasvasilache, antiagainst
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72974
2020-01-18 11:26:46 +08:00
|
|
|
#include "llvm/ADT/SmallBitVector.h"
|
2020-01-18 01:16:07 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
[mlir] Fix LLVM intrinsic convesion generator for overloadable types.
Summary:
If an intrinsic has overloadable types like llvm_anyint_ty or
llvm_anyfloat_ty then to getDeclaration() we need to pass a list
of the types that are "undefined" essentially concretizing them.
This patch add support for deriving such types from the MLIR op
that has been matched.
Reviewers: andydavis1, ftynse, nicolasvasilache, antiagainst
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72974
2020-01-18 11:26:46 +08:00
|
|
|
#include "llvm/Support/MachineValueType.h"
|
2020-01-18 01:16:07 +08:00
|
|
|
#include "llvm/Support/PrettyStackTrace.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<std::string>
|
|
|
|
nameFilter("llvmir-intrinsics-filter",
|
|
|
|
llvm::cl::desc("Only keep the intrinsics with the specified "
|
|
|
|
"substring in their record name"),
|
|
|
|
llvm::cl::cat(IntrinsicGenCat));
|
|
|
|
|
[mlir] Add option to use custom base class for dialect in LLVMIRIntrinsicGen.
Summary:
LLVMIRIntrinsicGen is using LLVM_Op as the base class for intrinsics.
This works for LLVM intrinsics in the LLVM Dialect, but when we are
trying to convert custom intrinsics that originate from a custom
LLVM dialect (like NVVM or ROCDL) these usually have a different
"cppNamespace" that needs to be applied to these dialect.
These dialect specific characteristics (like "cppNamespace")
are typically organized by creating a custom op (like NVVM_Op or
ROCDL_Op) that passes the correct dialect to the LLVM_OpBase class.
It seems natural to allow LLVMIRIntrinsicGen to take that into
consideration when generating the conversion code from one of these
dialect to a set of target specific intrinsics.
Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse
Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73233
2020-01-23 06:22:29 +08:00
|
|
|
static llvm::cl::opt<std::string>
|
|
|
|
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));
|
|
|
|
|
[mlir] Fix LLVM intrinsic convesion generator for overloadable types.
Summary:
If an intrinsic has overloadable types like llvm_anyint_ty or
llvm_anyfloat_ty then to getDeclaration() we need to pass a list
of the types that are "undefined" essentially concretizing them.
This patch add support for deriving such types from the MLIR op
that has been matched.
Reviewers: andydavis1, ftynse, nicolasvasilache, antiagainst
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72974
2020-01-18 11:26:46 +08:00
|
|
|
// 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 (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;
|
|
|
|
}
|
|
|
|
|
2020-01-18 01:16:07 +08:00
|
|
|
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_") &&
|
2020-01-20 11:14:37 +08:00
|
|
|
"LLVM intrinsic names are expected to start with 'int_'");
|
2020-01-18 01:16:07 +08:00
|
|
|
name = name.drop_front(4);
|
|
|
|
llvm::SmallVector<llvm::StringRef, 8> chunks;
|
[mlir] Add option to use custom base class for dialect in LLVMIRIntrinsicGen.
Summary:
LLVMIRIntrinsicGen is using LLVM_Op as the base class for intrinsics.
This works for LLVM intrinsics in the LLVM Dialect, but when we are
trying to convert custom intrinsics that originate from a custom
LLVM dialect (like NVVM or ROCDL) these usually have a different
"cppNamespace" that needs to be applied to these dialect.
These dialect specific characteristics (like "cppNamespace")
are typically organized by creating a custom op (like NVVM_Op or
ROCDL_Op) that passes the correct dialect to the LLVM_OpBase class.
It seems natural to allow LLVMIRIntrinsicGen to take that into
consideration when generating the conversion code from one of these
dialect to a set of target specific intrinsics.
Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse
Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73233
2020-01-23 06:22:29 +08:00
|
|
|
llvm::StringRef targetPrefix = record.getValueAsString("TargetPrefix");
|
2020-01-18 01:16:07 +08:00
|
|
|
name.split(chunks, '_');
|
[mlir] Add option to use custom base class for dialect in LLVMIRIntrinsicGen.
Summary:
LLVMIRIntrinsicGen is using LLVM_Op as the base class for intrinsics.
This works for LLVM intrinsics in the LLVM Dialect, but when we are
trying to convert custom intrinsics that originate from a custom
LLVM dialect (like NVVM or ROCDL) these usually have a different
"cppNamespace" that needs to be applied to these dialect.
These dialect specific characteristics (like "cppNamespace")
are typically organized by creating a custom op (like NVVM_Op or
ROCDL_Op) that passes the correct dialect to the LLVM_OpBase class.
It seems natural to allow LLVMIRIntrinsicGen to take that into
consideration when generating the conversion code from one of these
dialect to a set of target specific intrinsics.
Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse
Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73233
2020-01-23 06:22:29 +08:00
|
|
|
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(), ".");
|
2020-01-18 01:16:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the name of the record without the "intrinsic" prefix.
|
|
|
|
llvm::StringRef getProperRecordName() const {
|
|
|
|
llvm::StringRef name = record.getName();
|
|
|
|
assert(name.startswith("int_") &&
|
2020-01-20 11:14:37 +08:00
|
|
|
"LLVM intrinsic names are expected to start with 'int_'");
|
2020-01-18 01:16:07 +08:00
|
|
|
return name.drop_front(4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the number of operands.
|
|
|
|
unsigned getNumOperands() const {
|
|
|
|
auto operands = record.getValueAsListOfDefs(fieldOperands);
|
2020-01-24 18:27:17 +08:00
|
|
|
assert(llvm::all_of(operands,
|
|
|
|
[](const llvm::Record *r) {
|
|
|
|
return r->isSubClassOf("LLVMType");
|
|
|
|
}) &&
|
|
|
|
"expected operands to be of LLVM type");
|
2020-01-18 01:16:07 +08:00
|
|
|
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 {
|
2021-02-10 08:48:08 +08:00
|
|
|
return llvm::none_of(
|
|
|
|
record.getValueAsListOfDefs(fieldTraits),
|
|
|
|
[](const llvm::Record *r) { return r->getName() == "IntrNoMem"; });
|
2020-01-18 01:16:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if the intrinsic is commutative, i.e. has the respective
|
|
|
|
/// property.
|
|
|
|
bool isCommutative() const {
|
2021-02-10 08:48:08 +08:00
|
|
|
return llvm::any_of(
|
|
|
|
record.getValueAsListOfDefs(fieldTraits),
|
|
|
|
[](const llvm::Record *r) { return r->getName() == "Commutative"; });
|
2020-01-18 01:16:07 +08:00
|
|
|
}
|
|
|
|
|
[mlir] Fix LLVM intrinsic convesion generator for overloadable types.
Summary:
If an intrinsic has overloadable types like llvm_anyint_ty or
llvm_anyfloat_ty then to getDeclaration() we need to pass a list
of the types that are "undefined" essentially concretizing them.
This patch add support for deriving such types from the MLIR op
that has been matched.
Reviewers: andydavis1, ftynse, nicolasvasilache, antiagainst
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72974
2020-01-18 11:26:46 +08:00
|
|
|
IndicesTy getOverloadableOperandsIdxs() const {
|
|
|
|
return getOverloadableTypeIdxs(record, fieldOperands);
|
|
|
|
}
|
|
|
|
|
|
|
|
IndicesTy getOverloadableResultsIdxs() const {
|
|
|
|
return getOverloadableTypeIdxs(record, fieldResults);
|
|
|
|
}
|
|
|
|
|
2020-01-18 01:16:07 +08:00
|
|
|
private:
|
2020-01-20 11:14:37 +08:00
|
|
|
/// Names of the fields in the Intrinsic LLVM Tablegen class.
|
2020-01-18 01:16:07 +08:00
|
|
|
const char *fieldName = "LLVMName";
|
|
|
|
const char *fieldOperands = "ParamTypes";
|
|
|
|
const char *fieldResults = "RetTypes";
|
|
|
|
const char *fieldTraits = "IntrProperties";
|
|
|
|
|
|
|
|
const llvm::Record &record;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2020-02-21 21:46:14 +08:00
|
|
|
/// Prints the elements in "range" separated by commas and surrounded by "[]".
|
|
|
|
template <typename Range>
|
|
|
|
void printBracketedRange(const Range &range, llvm::raw_ostream &os) {
|
|
|
|
os << '[';
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(range, os);
|
2020-02-21 21:46:14 +08:00
|
|
|
os << ']';
|
2020-01-18 01:16:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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);
|
|
|
|
|
|
|
|
// Prepare strings for traits, if any.
|
|
|
|
llvm::SmallVector<llvm::StringRef, 2> traits;
|
|
|
|
if (intr.isCommutative())
|
|
|
|
traits.push_back("Commutative");
|
|
|
|
if (!intr.hasSideEffects())
|
|
|
|
traits.push_back("NoSideEffect");
|
|
|
|
|
|
|
|
// Prepare strings for operands.
|
|
|
|
llvm::SmallVector<llvm::StringRef, 8> operands(intr.getNumOperands(),
|
|
|
|
"LLVM_Type");
|
|
|
|
|
|
|
|
// Emit the definition.
|
[mlir] Add option to use custom base class for dialect in LLVMIRIntrinsicGen.
Summary:
LLVMIRIntrinsicGen is using LLVM_Op as the base class for intrinsics.
This works for LLVM intrinsics in the LLVM Dialect, but when we are
trying to convert custom intrinsics that originate from a custom
LLVM dialect (like NVVM or ROCDL) these usually have a different
"cppNamespace" that needs to be applied to these dialect.
These dialect specific characteristics (like "cppNamespace")
are typically organized by creating a custom op (like NVVM_Op or
ROCDL_Op) that passes the correct dialect to the LLVM_OpBase class.
It seems natural to allow LLVMIRIntrinsicGen to take that into
consideration when generating the conversion code from one of these
dialect to a set of target specific intrinsics.
Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse
Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73233
2020-01-23 06:22:29 +08:00
|
|
|
os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass
|
2020-02-21 21:46:14 +08:00
|
|
|
<< "<\"" << intr.getOperationName() << "\", ";
|
|
|
|
printBracketedRange(intr.getOverloadableResultsIdxs().set_bits(), os);
|
|
|
|
os << ", ";
|
|
|
|
printBracketedRange(intr.getOverloadableOperandsIdxs().set_bits(), os);
|
|
|
|
os << ", ";
|
|
|
|
printBracketedRange(traits, os);
|
2020-11-19 16:54:31 +08:00
|
|
|
os << ", " << intr.getNumResults() << ">, Arguments<(ins"
|
2020-02-21 21:46:14 +08:00
|
|
|
<< (operands.empty() ? "" : " ");
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(operands, os);
|
2020-02-21 21:46:14 +08:00
|
|
|
os << ")>;\n\n";
|
2020-01-18 01:16:07 +08:00
|
|
|
|
|
|
|
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);
|
2020-03-13 05:05:41 +08:00
|
|
|
os << "include \"mlir/Dialect/LLVMIR/LLVMOpBase.td\"\n";
|
2020-05-07 03:52:00 +08:00
|
|
|
os << "include \"mlir/Interfaces/SideEffectInterfaces.td\"\n\n";
|
2020-01-18 01:16:07 +08:00
|
|
|
|
|
|
|
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);
|