[flang-commits] [flang] [flang] Add a MLIRToLLVMPassPipeline callbacks for plugins (PR #212195)
Tarun Prabhu via flang-commits
flang-commits at lists.llvm.org
Thu Sep 24 05:58:14 PDT 2026
================
@@ -127,4 +128,81 @@ TEST(HLFIRExtensionPoint, MarkersAreAtTheDocumentedPositions) {
EXPECT_LT(lastMarker, lowerIntrinsics) << pipeline;
}
+// The registry is process-global and append-only, so a callback capturing a
+// local by reference would be re-invoked by a later test with the referent
+// destroyed. Tests record into this process-lifetime recorder instead, and each
+// asserts only on the markers it wrote, so they do not depend on test order.
+struct ConfigCallbackRecorder {
+ std::vector<std::string> order;
+ MLIRToLLVMPassPipelineConfig *seenConfig = nullptr;
+ bool epRan = false;
+
+ void reset() {
+ order.clear();
+ seenConfig = nullptr;
+ epRan = false;
+ }
+ /// Index of \p marker in `order`, or npos.
+ size_t indexOf(llvm::StringRef marker) const {
+ for (size_t i = 0, e = order.size(); i != e; ++i)
+ if (order[i] == marker)
+ return i;
+ return std::string::npos;
+ }
+};
+
+ConfigCallbackRecorder &recorder() {
+ static ConfigCallbackRecorder r;
+ return r;
+}
+
+TEST(PassPipelineConfigCallback, CallbacksRunInRegistrationOrderOnTheConfig) {
+ fir::registerPassPipelineConfigCallback(
+ [](MLIRToLLVMPassPipelineConfig &config) {
+ recorder().order.push_back("order-first");
+ recorder().seenConfig = &config;
+ });
+ fir::registerPassPipelineConfigCallback([](MLIRToLLVMPassPipelineConfig &) {
+ recorder().order.push_back("order-second");
+ });
+
+ recorder().reset();
+ MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);
+ fir::invokePassPipelineConfigCallbacks(config);
+
+ size_t first = recorder().indexOf("order-first");
+ size_t second = recorder().indexOf("order-second");
+ ASSERT_NE(first, std::string::npos);
+ ASSERT_NE(second, std::string::npos);
+ EXPECT_LT(first, second);
+ EXPECT_EQ(recorder().seenConfig, &config);
+}
+
+// The plugin shape: the config callback registers an extension point
+// callback, which then contributes a pass when the pipeline is built.
+TEST(PassPipelineConfigCallback, CanRegisterHLFIRExtensionPoints) {
+ fir::registerPassPipelineConfigCallback(
+ [](MLIRToLLVMPassPipelineConfig &config) {
+ config.registerHLFIROptEarlyEPCallbacks(
+ [](mlir::PassManager &pm, llvm::OptimizationLevel) {
+ recorder().epRan = true;
+ pm.addPass(std::make_unique<MarkerPass>());
+ });
+ });
+
+ recorder().reset();
+ mlir::MLIRContext context;
+ mlir::PassManager pm(&context, mlir::ModuleOp::getOperationName());
+ MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);
+ fir::invokePassPipelineConfigCallbacks(config);
+ fir::createHLFIRToFIRPassPipeline(pm, fir::EnableOpenMP::None, config);
+
+ std::string pipeline;
+ llvm::raw_string_ostream os(pipeline);
+ pm.printAsTextualPipeline(os);
+
+ EXPECT_TRUE(recorder().epRan);
+ EXPECT_NE(pipeline.find("ep-marker"), std::string::npos) << pipeline;
----------------
tarunprabhu wrote:
Do we need both `epRan` and the check for `"ep-marker"`?
https://github.com/llvm/llvm-project/pull/212195
More information about the flang-commits
mailing list