diff --git a/mlir/include/mlir/IR/MLIRContext.h b/mlir/include/mlir/IR/MLIRContext.h --- a/mlir/include/mlir/IR/MLIRContext.h +++ b/mlir/include/mlir/IR/MLIRContext.h @@ -120,9 +120,13 @@ Dialect *getOrLoadDialect(StringRef name); /// Return true if we allow to create operation for unregistered dialects. + /// This is a sequentially-consistent atomic operation. bool allowsUnregisteredDialects(); /// Enables creating operations in unregistered dialects. + /// If the current value (returned by `allowsUnregisteredDialects`) is `true` + /// then it is illegal to pass `allow = false` here. + /// This is a sequentially-consistent atomic operation. void allowUnregisteredDialects(bool allow = true); /// Return true if multi-threading is enabled by the context. diff --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp --- a/mlir/lib/IR/MLIRContext.cpp +++ b/mlir/lib/IR/MLIRContext.cpp @@ -136,8 +136,20 @@ /// In most cases, creating operation in unregistered dialect is not desired /// and indicate a misconfiguration of the compiler. This option enables to - /// detect such use cases - bool allowUnregisteredDialects = false; + /// detect such use cases. + /// + /// This hasn't always been an atomic, but before it was, there was a data + /// race on this member as some users were setting this inside of passes, + /// and that wasn't convenient to fix by adding a lock. + /// + /// So we made it an atomic, which technically removed the data race on + /// `allowUnregisteredDialects` itself, but didn't by itself prevent threads + /// from changing its value under each others' feet. To avoid that without + /// needing to introduce a lock, we introduced this restriction in + /// `setAllowUnregisteredDialects`: + /// + /// The only possible mutation is from `false` to `true`. + std::atomic allowUnregisteredDialects{false}; /// Enable support for multi-threading within MLIR. bool threadingIsEnabled = true; @@ -467,11 +479,19 @@ } bool MLIRContext::allowsUnregisteredDialects() { - return impl->allowUnregisteredDialects; + // Note: using the default sequentially-consistent memory order here. + // See the comment in `allowUnregisteredDialects(bool)`. + return impl->allowUnregisteredDialects.load(); } void MLIRContext::allowUnregisteredDialects(bool allowing) { - impl->allowUnregisteredDialects = allowing; + // It is illegal to mutate this from `true` back to `false`. + // See the `allowUnregisteredDialects` class member comment. + assert(allowing || !impl->allowUnregisteredDialects.load()); + // Note: using the default sequentially-consistent memory order here. + // Weakly-ordered atomics are error-prone, so they need to be motivated by a + // specific performance reason. This method is not frequently called. + impl->allowUnregisteredDialects.store(allowing); } /// Return true if multi-threading is enabled by the context. diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c --- a/mlir/test/CAPI/ir.c +++ b/mlir/test/CAPI/ir.c @@ -557,7 +557,6 @@ mlirOperationDump(op); mlirOperationDestroy(op); - mlirContextSetAllowUnregisteredDialects(ctx, false); // clang-format off // CHECK-LABEL: "insertion.order.test" // CHECK: ^{{.*}}(%{{.*}}: i1