[mlir] Intrinsics generator: use TableGen-defined builder function

Originally, intrinsics generator for the LLVM dialect has been producing
customized code fragments for the translation of MLIR operations to LLVM IR
intrinsics. LLVM dialect ODS now provides a generalized version of the
translation code, parameterizable with the properties of the operation.
Generate ODS that uses this version of the translation code instead of
generating a new version of it for each intrinsic.

Differential Revision: https://reviews.llvm.org/D74893
This commit is contained in:
Alex Zinenko 2020-02-21 14:46:14 +01:00
parent 00d4814f49
commit 3a1b34ff69
3 changed files with 34 additions and 51 deletions

View File

@ -75,10 +75,6 @@ class LLVM_OpBase<Dialect dialect, string mnemonic, list<OpTrait> traits = []> :
class LLVM_Op<string mnemonic, list<OpTrait> traits = []> : class LLVM_Op<string mnemonic, list<OpTrait> traits = []> :
LLVM_OpBase<LLVM_Dialect, mnemonic, traits>; LLVM_OpBase<LLVM_Dialect, mnemonic, traits>;
// Compatibility class for LLVM intrinsic operations.
class LLVM_IntrOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<"intr."#mnemonic, traits>;
// Case of the LLVM enum attribute backed by I64Attr with customized string // Case of the LLVM enum attribute backed by I64Attr with customized string
// representation that corresponds to what is visible in the textual IR form. // representation that corresponds to what is visible in the textual IR form.
// The parameters are as follows: // The parameters are as follows:
@ -163,6 +159,14 @@ class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
}]; }];
} }
// Base class for LLVM intrinsic operations, should not be used directly. Places
// the intrinsic into the LLVM dialect and prefixes its name with "intr.".
class LLVM_IntrOp<string mnem, list<int> overloadedResults,
list<int> overloadedOperands, list<OpTrait> traits,
bit hasResult>
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem),
overloadedResults, overloadedOperands, traits, hasResult>;
// Base class for LLVM intrinsic operations returning no results. Places the // Base class for LLVM intrinsic operations returning no results. Places the
// intrinsic into the LLVM dialect and prefixes its name with "intr.". // intrinsic into the LLVM dialect and prefixes its name with "intr.".
// //
@ -179,8 +183,7 @@ class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
// The Op has no results. // The Op has no results.
class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [], class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [],
list<OpTrait> traits = []> list<OpTrait> traits = []>
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem), : LLVM_IntrOp<mnem, [], overloadedOperands, traits, 0>;
[], overloadedOperands, traits, 0>;
// Base class for LLVM intrinsic operations returning one result. Places the // Base class for LLVM intrinsic operations returning one result. Places the
// intrinsic into the LLVM dialect and prefixes its name with "intr.". This is // intrinsic into the LLVM dialect and prefixes its name with "intr.". This is
@ -191,8 +194,7 @@ class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [],
class LLVM_OneResultIntrOp<string mnem, list<int> overloadedResults = [], class LLVM_OneResultIntrOp<string mnem, list<int> overloadedResults = [],
list<int> overloadedOperands = [], list<int> overloadedOperands = [],
list<OpTrait> traits = []> list<OpTrait> traits = []>
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem), : LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 1>;
overloadedResults, overloadedOperands, traits, 1>;
// LLVM vector reduction over a single vector. // LLVM vector reduction over a single vector.
class LLVM_VectorReduction<string mnem> class LLVM_VectorReduction<string mnem>

View File

@ -15,15 +15,15 @@
// CHECK-LABEL: def LLVM_ptrmask // CHECK-LABEL: def LLVM_ptrmask
// CHECK: LLVM_IntrOp<"ptrmask // CHECK: LLVM_IntrOp<"ptrmask
// CHECK: Arguments<(ins // The result of this intrinsic result is overloadable.
// CHECK: Results<(outs // CHECK: [0]
// CHECK: llvm::Function *fn = llvm::Intrinsic::getDeclaration( // Both its operands are overloadable.
// CHECK: module, llvm::Intrinsic::ptrmask, { // CHECK: [0, 1]
// CHECK: opInst.getResult(0).getType().cast<LLVM::LLVMType>().getUnderlyingType(), // It has no additional traits.
// CHECK: opInst.getOperand(0).getType().cast<LLVM::LLVMType>().getUnderlyingType(), // CHECK: []
// CHECK: opInst.getOperand(1).getType().cast<LLVM::LLVMType>().getUnderlyingType(), // It has a result.
// CHECK: }); // CHECK: 1>
// CHECK: lookupValues(opInst.getOperands()); // CHECK: Arguments<(ins LLVM_Type, LLVM_Type
//---------------------------------------------------------------------------// //---------------------------------------------------------------------------//

View File

@ -179,31 +179,12 @@ private:
}; };
} // namespace } // namespace
/// Emits C++ code constructing an LLVM IR intrinsic given the generated MLIR /// Prints the elements in "range" separated by commas and surrounded by "[]".
/// operation. In LLVM IR, intrinsics are constructed as function calls. template <typename Range>
static void emitBuilder(const LLVMIntrinsic &intr, llvm::raw_ostream &os) { void printBracketedRange(const Range &range, llvm::raw_ostream &os) {
auto overloadedRes = intr.getOverloadableResultsIdxs(); os << '[';
auto overloadedOps = intr.getOverloadableOperandsIdxs(); mlir::interleaveComma(range, os);
os << " llvm::Module *module = builder.GetInsertBlock()->getModule();\n"; os << ']';
os << " llvm::Function *fn = llvm::Intrinsic::getDeclaration(\n";
os << " module, llvm::Intrinsic::" << intr.getProperRecordName()
<< ", {";
for (unsigned idx : overloadedRes.set_bits()) {
os << "\n opInst.getResult(" << idx << ").getType()"
<< ".cast<LLVM::LLVMType>().getUnderlyingType(),";
}
for (unsigned idx : overloadedOps.set_bits()) {
os << "\n opInst.getOperand(" << idx << ").getType()"
<< ".cast<LLVM::LLVMType>().getUnderlyingType(),";
}
if (overloadedRes.any() || overloadedOps.any())
os << "\n ";
os << "});\n";
os << " auto operands =\n";
os << " lookupValues(opInst.getOperands());\n";
os << " " << (intr.getNumResults() > 0 ? "$res = " : "")
<< "builder.CreateCall(fn, operands);\n";
os << " ";
} }
/// Emits ODS (TableGen-based) code for `record` representing an LLVM intrinsic. /// Emits ODS (TableGen-based) code for `record` representing an LLVM intrinsic.
@ -224,16 +205,16 @@ static bool emitIntrinsic(const llvm::Record &record, llvm::raw_ostream &os) {
// Emit the definition. // Emit the definition.
os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass
<< "<\"" << intr.getOperationName() << "\", ["; << "<\"" << intr.getOperationName() << "\", ";
mlir::interleaveComma(traits, os); printBracketedRange(intr.getOverloadableResultsIdxs().set_bits(), os);
os << "]>, Arguments<(ins" << (operands.empty() ? "" : " "); os << ", ";
printBracketedRange(intr.getOverloadableOperandsIdxs().set_bits(), os);
os << ", ";
printBracketedRange(traits, os);
os << ", " << (intr.getNumResults() == 0 ? 0 : 1) << ">, Arguments<(ins"
<< (operands.empty() ? "" : " ");
mlir::interleaveComma(operands, os); mlir::interleaveComma(operands, os);
os << ")>, Results<(outs" os << ")>;\n\n";
<< (intr.getNumResults() == 0 ? "" : " LLVM_Type:$res") << ")> {\n"
<< " let llvmBuilder = [{\n";
emitBuilder(intr, os);
os << "}];\n";
os << "}\n\n";
return false; return false;
} }