[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
This commit is contained in:
Marcello Maggioni 2020-01-22 14:22:29 -08:00
parent 794b8a0329
commit be9f09c768
3 changed files with 41 additions and 7 deletions

View File

@ -56,4 +56,10 @@ class LLVM_OpBase<Dialect dialect, string mnemonic, list<OpTrait> traits = []> :
class LLVM_Op<string mnemonic, list<OpTrait> traits = []> :
LLVM_OpBase<LLVM_Dialect, mnemonic, traits>;
// Base class for LLVM intrinsics operation. It is the same as an LLVM_Op
// but the operation has a ".intr." element in the prefix becoming
// "llvm.intr.*".
class LLVM_IntrOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<"intr."#mnemonic, traits>;
#endif // LLVMIR_OP_BASE

View File

@ -10,16 +10,18 @@
//
// 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=is_constant \
// RUN: | mlir-tblgen -gen-llvmir-intrinsics -I %S/../../../llvm/include/ --llvmir-intrinsics-filter=ptrmask \
// RUN: | FileCheck %s
// CHECK-LABEL: def LLVM_is_constant
// CHECK: LLVM_Op<"intr
// CHECK-LABEL: def LLVM_ptrmask
// CHECK: LLVM_IntrOp<"ptrmask
// CHECK: Arguments<(ins
// CHECK: Results<(outs
// CHECK: llvm::Function *fn = llvm::Intrinsic::getDeclaration(
// CHECK: module, llvm::Intrinsic::is_constant, {
// CHECK: module, llvm::Intrinsic::ptrmask, {
// CHECK: opInst.getResult(0).getType().cast<LLVM::LLVMType>().getUnderlyingType(),
// CHECK: opInst.getOperand(0).getType().cast<LLVM::LLVMType>().getUnderlyingType(),
// CHECK: opInst.getOperand(1).getType().cast<LLVM::LLVMType>().getUnderlyingType(),
// CHECK: });
// CHECK: lookupValues(opInst.getOperands());
@ -36,3 +38,11 @@
// 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

View File

@ -32,6 +32,12 @@ static llvm::cl::opt<std::string>
"substring in their record name"),
llvm::cl::cat(IntrinsicGenCat));
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));
// Used to represent the indices of overloadable operands/results.
using IndicesTy = llvm::SmallBitVector;
@ -84,8 +90,20 @@ public:
"LLVM intrinsic names are expected to start with 'int_'");
name = name.drop_front(4);
llvm::SmallVector<llvm::StringRef, 8> chunks;
llvm::StringRef targetPrefix = record.getValueAsString("TargetPrefix");
name.split(chunks, '_');
return llvm::join(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.
@ -205,8 +223,8 @@ static bool emitIntrinsic(const llvm::Record &record, llvm::raw_ostream &os) {
"LLVM_Type");
// Emit the definition.
os << "def LLVM_" << intr.getProperRecordName() << " : LLVM_Op<\"intr."
<< intr.getOperationName() << "\", [";
os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass
<< "<\"" << intr.getOperationName() << "\", [";
mlir::interleaveComma(traits, os);
os << "]>, Arguments<(ins" << (operands.empty() ? "" : " ");
mlir::interleaveComma(operands, os);