diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index de8bc84e8feb..3c2ac9129e6f 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3391,6 +3391,8 @@ private: struct LLVMIRLoweringPass : public mlir::PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass) + using Printer = fir::LLVMIRLoweringPrinter; LLVMIRLoweringPass(raw_ostream &output, Printer p) : output{output}, printer{p} {} diff --git a/flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp b/flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp index 246eedf3a515..0039f8377376 100644 --- a/flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp +++ b/flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp @@ -63,6 +63,8 @@ namespace { /// loop-carried, then the arrays are conflict-free and no copies are required. class ArrayCopyAnalysis { public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ArrayCopyAnalysis) + using ConflictSetT = llvm::SmallPtrSet; using UseSetT = llvm::SmallPtrSet; using LoadMapSetsT = llvm::DenseMap; diff --git a/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp b/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp index 408cdc6e2525..d2a0c70575cf 100644 --- a/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp +++ b/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp @@ -37,6 +37,8 @@ struct MemoryAllocationOptions { class ReturnAnalysis { public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ReturnAnalysis) + ReturnAnalysis(mlir::Operation *op) { if (auto func = mlir::dyn_cast(op)) for (mlir::Block &block : func) diff --git a/mlir/examples/toy/Ch4/mlir/ShapeInferencePass.cpp b/mlir/examples/toy/Ch4/mlir/ShapeInferencePass.cpp index 8b8a55d69eab..cf3e492989b0 100644 --- a/mlir/examples/toy/Ch4/mlir/ShapeInferencePass.cpp +++ b/mlir/examples/toy/Ch4/mlir/ShapeInferencePass.cpp @@ -44,9 +44,10 @@ namespace { /// d) infer the shape of its output from the argument types. /// 3) If the worklist is empty, the algorithm succeeded. /// -class ShapeInferencePass +struct ShapeInferencePass : public mlir::PassWrapper> { -public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ShapeInferencePass) + void runOnOperation() override { auto f = getOperation(); diff --git a/mlir/examples/toy/Ch5/mlir/LowerToAffineLoops.cpp b/mlir/examples/toy/Ch5/mlir/LowerToAffineLoops.cpp index e459477ad7b3..000f99886b01 100644 --- a/mlir/examples/toy/Ch5/mlir/LowerToAffineLoops.cpp +++ b/mlir/examples/toy/Ch5/mlir/LowerToAffineLoops.cpp @@ -310,6 +310,8 @@ struct TransposeOpLowering : public ConversionPattern { namespace { struct ToyToAffineLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ToyToAffineLoweringPass) + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } diff --git a/mlir/examples/toy/Ch5/mlir/ShapeInferencePass.cpp b/mlir/examples/toy/Ch5/mlir/ShapeInferencePass.cpp index 8b8a55d69eab..cf3e492989b0 100644 --- a/mlir/examples/toy/Ch5/mlir/ShapeInferencePass.cpp +++ b/mlir/examples/toy/Ch5/mlir/ShapeInferencePass.cpp @@ -44,9 +44,10 @@ namespace { /// d) infer the shape of its output from the argument types. /// 3) If the worklist is empty, the algorithm succeeded. /// -class ShapeInferencePass +struct ShapeInferencePass : public mlir::PassWrapper> { -public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ShapeInferencePass) + void runOnOperation() override { auto f = getOperation(); diff --git a/mlir/examples/toy/Ch6/mlir/LowerToAffineLoops.cpp b/mlir/examples/toy/Ch6/mlir/LowerToAffineLoops.cpp index e459477ad7b3..000f99886b01 100644 --- a/mlir/examples/toy/Ch6/mlir/LowerToAffineLoops.cpp +++ b/mlir/examples/toy/Ch6/mlir/LowerToAffineLoops.cpp @@ -310,6 +310,8 @@ struct TransposeOpLowering : public ConversionPattern { namespace { struct ToyToAffineLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ToyToAffineLoweringPass) + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } diff --git a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp index 83ee0104a32a..09ef49a49bc6 100644 --- a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp +++ b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp @@ -172,6 +172,8 @@ private: namespace { struct ToyToLLVMLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ToyToLLVMLoweringPass) + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } diff --git a/mlir/examples/toy/Ch6/mlir/ShapeInferencePass.cpp b/mlir/examples/toy/Ch6/mlir/ShapeInferencePass.cpp index 8b8a55d69eab..cf3e492989b0 100644 --- a/mlir/examples/toy/Ch6/mlir/ShapeInferencePass.cpp +++ b/mlir/examples/toy/Ch6/mlir/ShapeInferencePass.cpp @@ -44,9 +44,10 @@ namespace { /// d) infer the shape of its output from the argument types. /// 3) If the worklist is empty, the algorithm succeeded. /// -class ShapeInferencePass +struct ShapeInferencePass : public mlir::PassWrapper> { -public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ShapeInferencePass) + void runOnOperation() override { auto f = getOperation(); diff --git a/mlir/examples/toy/Ch7/mlir/LowerToAffineLoops.cpp b/mlir/examples/toy/Ch7/mlir/LowerToAffineLoops.cpp index e459477ad7b3..000f99886b01 100644 --- a/mlir/examples/toy/Ch7/mlir/LowerToAffineLoops.cpp +++ b/mlir/examples/toy/Ch7/mlir/LowerToAffineLoops.cpp @@ -310,6 +310,8 @@ struct TransposeOpLowering : public ConversionPattern { namespace { struct ToyToAffineLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ToyToAffineLoweringPass) + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } diff --git a/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp b/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp index 83ee0104a32a..09ef49a49bc6 100644 --- a/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp +++ b/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp @@ -172,6 +172,8 @@ private: namespace { struct ToyToLLVMLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ToyToLLVMLoweringPass) + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } diff --git a/mlir/examples/toy/Ch7/mlir/ShapeInferencePass.cpp b/mlir/examples/toy/Ch7/mlir/ShapeInferencePass.cpp index 8b8a55d69eab..cf3e492989b0 100644 --- a/mlir/examples/toy/Ch7/mlir/ShapeInferencePass.cpp +++ b/mlir/examples/toy/Ch7/mlir/ShapeInferencePass.cpp @@ -44,9 +44,10 @@ namespace { /// d) infer the shape of its output from the argument types. /// 3) If the worklist is empty, the algorithm succeeded. /// -class ShapeInferencePass +struct ShapeInferencePass : public mlir::PassWrapper> { -public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ShapeInferencePass) + void runOnOperation() override { auto f = getOperation(); diff --git a/mlir/include/mlir/Conversion/SCFToGPU/SCFToGPUPass.h b/mlir/include/mlir/Conversion/SCFToGPU/SCFToGPUPass.h index c1b0eb0a60ea..08f34b9e22f3 100644 --- a/mlir/include/mlir/Conversion/SCFToGPU/SCFToGPUPass.h +++ b/mlir/include/mlir/Conversion/SCFToGPU/SCFToGPUPass.h @@ -8,12 +8,12 @@ #ifndef MLIR_CONVERSION_SCFTOGPU_SCFTOGPUPASS_H_ #define MLIR_CONVERSION_SCFTOGPU_SCFTOGPUPASS_H_ +#include "mlir/IR/FunctionInterfaces.h" #include "mlir/Support/LLVM.h" #include namespace mlir { -class FunctionOpInterface; template class InterfacePass; class Pass; diff --git a/mlir/include/mlir/Pass/AnalysisManager.h b/mlir/include/mlir/Pass/AnalysisManager.h index 9dab7b7b5950..6a124dbc9321 100644 --- a/mlir/include/mlir/Pass/AnalysisManager.h +++ b/mlir/include/mlir/Pass/AnalysisManager.h @@ -28,7 +28,7 @@ namespace detail { /// A utility class to represent the analyses that are known to be preserved. class PreservedAnalyses { /// A type used to represent all potential analyses. - struct AllAnalysesType; + struct AllAnalysesType {}; public: /// Mark all analyses as preserved. diff --git a/mlir/include/mlir/Support/TypeID.h b/mlir/include/mlir/Support/TypeID.h index 53b448f68b1d..433ab12e539a 100644 --- a/mlir/include/mlir/Support/TypeID.h +++ b/mlir/include/mlir/Support/TypeID.h @@ -17,14 +17,15 @@ #include "mlir/Support/LLVM.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/TypeName.h" namespace mlir { - -namespace detail { -struct TypeIDExported; -} // namespace detail +//===----------------------------------------------------------------------===// +// TypeID +//===----------------------------------------------------------------------===// /// This class provides an efficient unique identifier for a specific C++ type. /// This allows for a C++ type to be compared, hashed, and stored in an opaque @@ -50,6 +51,56 @@ struct TypeIDExported; /// ... /// } /// +/// C++ RTTI is a notoriously difficult topic; given the nature of shared +/// libraries many different approaches fundamentally break down in either the +/// area of support (i.e. only certain types of classes are supported), or in +/// terms of performance (e.g. by using string comparison). This class intends +/// to strike a balance between performance and the setup required to enable its +/// use. +/// +/// Assume we are adding support for some class Foo, below are the set of ways +/// in which a given c++ type may be supported: +/// +/// * Explicitly via `MLIR_DECLARE_EXPLICIT_TYPE_ID` and +/// `MLIR_DEFINE_EXPLICIT_TYPE_ID` +/// +/// - This method explicitly defines the type ID for a given type using the +/// given macros. These should be placed at the top-level of the file (i.e. +/// not within any namespace or class). This is the most effective and +/// efficient method, but requires explicit annotations for each type. +/// +/// Example: +/// +/// // Foo.h +/// MLIR_DECLARE_EXPLICIT_TYPE_ID(Foo); +/// +/// // Foo.cpp +/// MLIR_DEFINE_EXPLICIT_TYPE_ID(Foo); +/// +/// * Explicitly via `MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID` +/// - This method explicitly defines the type ID for a given type by +/// annotating the class directly. This has similar effectiveness and +/// efficiency to the above method, but should only be used on internal +/// classes; i.e. those with definitions constrained to a specific library +/// (generally classes in anonymous namespaces). +/// +/// Example: +/// +/// namespace { +/// class Foo { +/// public: +/// MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(Foo) +/// }; +/// } // namespace +/// +/// * Implicitly via a fallback using the type name +/// - This method implicitly defines a type ID for a given type by using the +/// type name. This method requires nothing explicitly from the user, but +/// pays additional access and initialization cost. Given that this method +/// uses the name of the type, it may not be used for types defined in +/// anonymous namespaces (which is asserted when it can be detected). String +/// names do not provide any guarantees on uniqueness in these contexts. +/// class TypeID { /// This class represents the storage of a type info object. /// Note: We specify an explicit alignment here to allow use with @@ -91,9 +142,6 @@ private: /// The storage of this type info object. const Storage *storage; - // See TypeIDExported below for an explanation of the trampoline behavior. - friend struct detail::TypeIDExported; - friend class TypeIDAllocator; }; @@ -102,45 +150,142 @@ inline ::llvm::hash_code hash_value(TypeID id) { return DenseMapInfo::getHashValue(id.storage); } -namespace detail { +//===----------------------------------------------------------------------===// +// TypeIDResolver +//===----------------------------------------------------------------------===// -/// The static local instance of each get method must be emitted with -/// "default" (public) visibility across all shared libraries, regardless of -/// whether they are compiled with hidden visibility or not. The only reliable -/// way to make this happen is to set the visibility attribute at the -/// containing namespace/struct scope. We don't do this on the TypeID (internal -/// API) class in order to reduce the scope of what gets exported with -/// public visibility. Instead, the get() methods on TypeID trampoline -/// through those on this detail class with specific visibility controls -/// applied, making visibility declarations on the internal TypeID class not -/// required (all visibility relevant pieces are here). -/// TODO: This currently won't work when using DLLs as it requires properly -/// attaching dllimport and dllexport. Fix this when that information is -/// available within LLVM. -struct LLVM_EXTERNAL_VISIBILITY TypeIDExported { - template - static TypeID get() { - static TypeID::Storage instance; - return TypeID(&instance); - } - template