forked from OSchip/llvm-project
[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:
parent
00d4814f49
commit
3a1b34ff69
|
@ -75,10 +75,6 @@ class LLVM_OpBase<Dialect dialect, string mnemonic, list<OpTrait> traits = []> :
|
|||
class LLVM_Op<string mnemonic, list<OpTrait> 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
|
||||
// representation that corresponds to what is visible in the textual IR form.
|
||||
// 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
|
||||
// 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.
|
||||
class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [],
|
||||
list<OpTrait> traits = []>
|
||||
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem),
|
||||
[], overloadedOperands, traits, 0>;
|
||||
: LLVM_IntrOp<mnem, [], overloadedOperands, traits, 0>;
|
||||
|
||||
// Base class for LLVM intrinsic operations returning one result. Places the
|
||||
// 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 = [],
|
||||
list<int> overloadedOperands = [],
|
||||
list<OpTrait> traits = []>
|
||||
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem),
|
||||
overloadedResults, overloadedOperands, traits, 1>;
|
||||
: LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 1>;
|
||||
|
||||
// LLVM vector reduction over a single vector.
|
||||
class LLVM_VectorReduction<string mnem>
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
|
||||
// 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::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());
|
||||
// The result of this intrinsic result is overloadable.
|
||||
// CHECK: [0]
|
||||
// Both its operands are overloadable.
|
||||
// CHECK: [0, 1]
|
||||
// It has no additional traits.
|
||||
// CHECK: []
|
||||
// It has a result.
|
||||
// CHECK: 1>
|
||||
// CHECK: Arguments<(ins LLVM_Type, LLVM_Type
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
|
|
|
@ -179,31 +179,12 @@ private:
|
|||
};
|
||||
} // namespace
|
||||
|
||||
/// Emits C++ code constructing an LLVM IR intrinsic given the generated MLIR
|
||||
/// operation. In LLVM IR, intrinsics are constructed as function calls.
|
||||
static void emitBuilder(const LLVMIntrinsic &intr, llvm::raw_ostream &os) {
|
||||
auto overloadedRes = intr.getOverloadableResultsIdxs();
|
||||
auto overloadedOps = intr.getOverloadableOperandsIdxs();
|
||||
os << " llvm::Module *module = builder.GetInsertBlock()->getModule();\n";
|
||||
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 << " ";
|
||||
/// Prints the elements in "range" separated by commas and surrounded by "[]".
|
||||
template <typename Range>
|
||||
void printBracketedRange(const Range &range, llvm::raw_ostream &os) {
|
||||
os << '[';
|
||||
mlir::interleaveComma(range, os);
|
||||
os << ']';
|
||||
}
|
||||
|
||||
/// 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.
|
||||
os << "def LLVM_" << intr.getProperRecordName() << " : " << opBaseClass
|
||||
<< "<\"" << intr.getOperationName() << "\", [";
|
||||
mlir::interleaveComma(traits, os);
|
||||
os << "]>, Arguments<(ins" << (operands.empty() ? "" : " ");
|
||||
<< "<\"" << intr.getOperationName() << "\", ";
|
||||
printBracketedRange(intr.getOverloadableResultsIdxs().set_bits(), os);
|
||||
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);
|
||||
os << ")>, Results<(outs"
|
||||
<< (intr.getNumResults() == 0 ? "" : " LLVM_Type:$res") << ")> {\n"
|
||||
<< " let llvmBuilder = [{\n";
|
||||
emitBuilder(intr, os);
|
||||
os << "}];\n";
|
||||
os << "}\n\n";
|
||||
os << ")>;\n\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue