github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/IR/MLIRContext.cpp (about) 1 //===- MLIRContext.cpp - MLIR Type Classes --------------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 18 #include "mlir/IR/MLIRContext.h" 19 #include "AffineExprDetail.h" 20 #include "AffineMapDetail.h" 21 #include "AttributeDetail.h" 22 #include "IntegerSetDetail.h" 23 #include "LocationDetail.h" 24 #include "TypeDetail.h" 25 #include "mlir/IR/AffineExpr.h" 26 #include "mlir/IR/AffineMap.h" 27 #include "mlir/IR/Attributes.h" 28 #include "mlir/IR/Diagnostics.h" 29 #include "mlir/IR/Dialect.h" 30 #include "mlir/IR/Function.h" 31 #include "mlir/IR/Identifier.h" 32 #include "mlir/IR/IntegerSet.h" 33 #include "mlir/IR/Location.h" 34 #include "mlir/IR/Module.h" 35 #include "mlir/IR/Types.h" 36 #include "mlir/Support/STLExtras.h" 37 #include "llvm/ADT/DenseMap.h" 38 #include "llvm/ADT/DenseSet.h" 39 #include "llvm/ADT/SetVector.h" 40 #include "llvm/ADT/StringMap.h" 41 #include "llvm/ADT/Twine.h" 42 #include "llvm/Support/Allocator.h" 43 #include "llvm/Support/RWMutex.h" 44 #include "llvm/Support/raw_ostream.h" 45 #include <memory> 46 47 using namespace mlir; 48 using namespace mlir::detail; 49 50 using llvm::hash_combine; 51 using llvm::hash_combine_range; 52 53 /// A utility function to safely get or create a uniqued instance within the 54 /// given set container. 55 template <typename ValueT, typename DenseInfoT, typename KeyT, 56 typename ConstructorFn> 57 static ValueT safeGetOrCreate(DenseSet<ValueT, DenseInfoT> &container, 58 KeyT &&key, llvm::sys::SmartRWMutex<true> &mutex, 59 ConstructorFn &&constructorFn) { 60 { // Check for an existing instance in read-only mode. 61 llvm::sys::SmartScopedReader<true> instanceLock(mutex); 62 auto it = container.find_as(key); 63 if (it != container.end()) 64 return *it; 65 } 66 67 // Aquire a writer-lock so that we can safely create the new instance. 68 llvm::sys::SmartScopedWriter<true> instanceLock(mutex); 69 70 // Check for an existing instance again here, because another writer thread 71 // may have already created one. 72 auto existing = container.insert_as(ValueT(), key); 73 if (!existing.second) 74 return *existing.first; 75 76 // Otherwise, construct a new instance of the value. 77 return *existing.first = constructorFn(); 78 } 79 80 namespace { 81 /// A builtin dialect to define types/etc that are necessary for the validity of 82 /// the IR. 83 struct BuiltinDialect : public Dialect { 84 BuiltinDialect(MLIRContext *context) : Dialect(/*name=*/"", context) { 85 addAttributes<AffineMapAttr, ArrayAttr, BoolAttr, DenseElementsAttr, 86 DictionaryAttr, FloatAttr, SymbolRefAttr, IntegerAttr, 87 IntegerSetAttr, OpaqueAttr, OpaqueElementsAttr, 88 SparseElementsAttr, StringAttr, TypeAttr, UnitAttr>(); 89 addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, UnknownLoc>(); 90 91 addTypes<ComplexType, FloatType, FunctionType, IndexType, IntegerType, 92 MemRefType, NoneType, OpaqueType, RankedTensorType, TupleType, 93 UnrankedTensorType, VectorType>(); 94 95 // TODO: These operations should be moved to a different dialect when they 96 // have been fully decoupled from the core. 97 addOperations<FuncOp, ModuleOp, ModuleTerminatorOp>(); 98 } 99 }; 100 101 struct AffineMapKeyInfo : DenseMapInfo<AffineMap> { 102 // Affine maps are uniqued based on their dim/symbol counts and affine 103 // expressions. 104 using KeyTy = std::tuple<unsigned, unsigned, ArrayRef<AffineExpr>>; 105 using DenseMapInfo<AffineMap>::isEqual; 106 107 static unsigned getHashValue(const AffineMap &key) { 108 return getHashValue( 109 KeyTy(key.getNumDims(), key.getNumSymbols(), key.getResults())); 110 } 111 112 static unsigned getHashValue(KeyTy key) { 113 return hash_combine( 114 std::get<0>(key), std::get<1>(key), 115 hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end())); 116 } 117 118 static bool isEqual(const KeyTy &lhs, AffineMap rhs) { 119 if (rhs == getEmptyKey() || rhs == getTombstoneKey()) 120 return false; 121 return lhs == std::make_tuple(rhs.getNumDims(), rhs.getNumSymbols(), 122 rhs.getResults()); 123 } 124 }; 125 126 struct IntegerSetKeyInfo : DenseMapInfo<IntegerSet> { 127 // Integer sets are uniqued based on their dim/symbol counts, affine 128 // expressions appearing in the LHS of constraints, and eqFlags. 129 using KeyTy = 130 std::tuple<unsigned, unsigned, ArrayRef<AffineExpr>, ArrayRef<bool>>; 131 using DenseMapInfo<IntegerSet>::isEqual; 132 133 static unsigned getHashValue(const IntegerSet &key) { 134 return getHashValue(KeyTy(key.getNumDims(), key.getNumSymbols(), 135 key.getConstraints(), key.getEqFlags())); 136 } 137 138 static unsigned getHashValue(KeyTy key) { 139 return hash_combine( 140 std::get<0>(key), std::get<1>(key), 141 hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end()), 142 hash_combine_range(std::get<3>(key).begin(), std::get<3>(key).end())); 143 } 144 145 static bool isEqual(const KeyTy &lhs, IntegerSet rhs) { 146 if (rhs == getEmptyKey() || rhs == getTombstoneKey()) 147 return false; 148 return lhs == std::make_tuple(rhs.getNumDims(), rhs.getNumSymbols(), 149 rhs.getConstraints(), rhs.getEqFlags()); 150 } 151 }; 152 } // end anonymous namespace. 153 154 namespace mlir { 155 /// This is the implementation of the MLIRContext class, using the pImpl idiom. 156 /// This class is completely private to this file, so everything is public. 157 class MLIRContextImpl { 158 public: 159 //===--------------------------------------------------------------------===// 160 // Identifier uniquing 161 //===--------------------------------------------------------------------===// 162 163 // Identifier allocator and mutex for thread safety. 164 llvm::BumpPtrAllocator identifierAllocator; 165 llvm::sys::SmartRWMutex<true> identifierMutex; 166 167 //===--------------------------------------------------------------------===// 168 // Diagnostics 169 //===--------------------------------------------------------------------===// 170 DiagnosticEngine diagEngine; 171 172 //===--------------------------------------------------------------------===// 173 // Other 174 //===--------------------------------------------------------------------===// 175 176 /// A general purpose mutex to lock access to parts of the context that do not 177 /// have a more specific mutex, e.g. registry operations. 178 llvm::sys::SmartRWMutex<true> contextMutex; 179 180 /// This is a list of dialects that are created referring to this context. 181 /// The MLIRContext owns the objects. 182 std::vector<std::unique_ptr<Dialect>> dialects; 183 184 /// This is a mapping from operation name to AbstractOperation for registered 185 /// operations. 186 llvm::StringMap<AbstractOperation> registeredOperations; 187 188 /// This is a mapping from class identifier to Dialect for registered 189 /// attributes and types. 190 DenseMap<const ClassID *, Dialect *> registeredDialectSymbols; 191 192 /// These are identifiers uniqued into this MLIRContext. 193 llvm::StringMap<char, llvm::BumpPtrAllocator &> identifiers; 194 195 //===--------------------------------------------------------------------===// 196 // Affine uniquing 197 //===--------------------------------------------------------------------===// 198 199 // Affine allocator and mutex for thread safety. 200 llvm::BumpPtrAllocator affineAllocator; 201 llvm::sys::SmartRWMutex<true> affineMutex; 202 203 // Affine map uniquing. 204 using AffineMapSet = DenseSet<AffineMap, AffineMapKeyInfo>; 205 AffineMapSet affineMaps; 206 207 // Integer set uniquing. 208 using IntegerSets = DenseSet<IntegerSet, IntegerSetKeyInfo>; 209 IntegerSets integerSets; 210 211 // Affine expression uniqui'ing. 212 StorageUniquer affineUniquer; 213 214 //===--------------------------------------------------------------------===// 215 // Type uniquing 216 //===--------------------------------------------------------------------===// 217 StorageUniquer typeUniquer; 218 219 /// Cached Type Instances. 220 FloatType bf16Ty, f16Ty, f32Ty, f64Ty; 221 IndexType indexTy; 222 IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty; 223 NoneType noneType; 224 225 //===--------------------------------------------------------------------===// 226 // Attribute uniquing 227 //===--------------------------------------------------------------------===// 228 StorageUniquer attributeUniquer; 229 230 /// Cached Attribute Instances. 231 BoolAttr falseAttr, trueAttr; 232 UnitAttr unitAttr; 233 UnknownLoc unknownLocAttr; 234 235 public: 236 MLIRContextImpl() : identifiers(identifierAllocator) {} 237 }; 238 } // end namespace mlir 239 240 MLIRContext::MLIRContext() : impl(new MLIRContextImpl()) { 241 new BuiltinDialect(this); 242 registerAllDialects(this); 243 244 // Initialize several common attributes and types to avoid the need to lock 245 // the context when accessing them. 246 247 //// Types. 248 /// Floating-point Types. 249 impl->bf16Ty = TypeUniquer::get<FloatType>(this, StandardTypes::BF16); 250 impl->f16Ty = TypeUniquer::get<FloatType>(this, StandardTypes::F16); 251 impl->f32Ty = TypeUniquer::get<FloatType>(this, StandardTypes::F32); 252 impl->f64Ty = TypeUniquer::get<FloatType>(this, StandardTypes::F64); 253 /// Index Type. 254 impl->indexTy = TypeUniquer::get<IndexType>(this, StandardTypes::Index); 255 /// Integer Types. 256 impl->int1Ty = TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 1); 257 impl->int8Ty = TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 8); 258 impl->int16Ty = 259 TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 16); 260 impl->int32Ty = 261 TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 32); 262 impl->int64Ty = 263 TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 64); 264 impl->int128Ty = 265 TypeUniquer::get<IntegerType>(this, StandardTypes::Integer, 128); 266 /// None Type. 267 impl->noneType = TypeUniquer::get<NoneType>(this, StandardTypes::None); 268 269 //// Attributes. 270 //// Note: These must be registered after the types as they may generate one 271 //// of the above types internally. 272 /// Bool Attributes. 273 // Note: The context is also used within the BoolAttrStorage. 274 impl->falseAttr = AttributeUniquer::get<BoolAttr>( 275 this, StandardAttributes::Bool, this, false); 276 impl->trueAttr = AttributeUniquer::get<BoolAttr>( 277 this, StandardAttributes::Bool, this, true); 278 /// Unit Attribute. 279 impl->unitAttr = 280 AttributeUniquer::get<UnitAttr>(this, StandardAttributes::Unit); 281 /// Unknown Location Attribute. 282 impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>( 283 this, StandardAttributes::UnknownLocation); 284 } 285 286 MLIRContext::~MLIRContext() {} 287 288 /// Copy the specified array of elements into memory managed by the provided 289 /// bump pointer allocator. This assumes the elements are all PODs. 290 template <typename T> 291 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator, 292 ArrayRef<T> elements) { 293 auto result = allocator.Allocate<T>(elements.size()); 294 std::uninitialized_copy(elements.begin(), elements.end(), result); 295 return ArrayRef<T>(result, elements.size()); 296 } 297 298 //===----------------------------------------------------------------------===// 299 // Diagnostic Handlers 300 //===----------------------------------------------------------------------===// 301 302 /// Returns the diagnostic engine for this context. 303 DiagnosticEngine &MLIRContext::getDiagEngine() { return getImpl().diagEngine; } 304 305 //===----------------------------------------------------------------------===// 306 // Dialect and Operation Registration 307 //===----------------------------------------------------------------------===// 308 309 /// Return information about all registered IR dialects. 310 std::vector<Dialect *> MLIRContext::getRegisteredDialects() { 311 // Lock access to the context registry. 312 llvm::sys::SmartScopedReader<true> registryLock(getImpl().contextMutex); 313 314 std::vector<Dialect *> result; 315 result.reserve(getImpl().dialects.size()); 316 for (auto &dialect : getImpl().dialects) 317 result.push_back(dialect.get()); 318 return result; 319 } 320 321 /// Get a registered IR dialect with the given namespace. If none is found, 322 /// then return nullptr. 323 Dialect *MLIRContext::getRegisteredDialect(StringRef name) { 324 // Lock access to the context registry. 325 llvm::sys::SmartScopedReader<true> registryLock(getImpl().contextMutex); 326 for (auto &dialect : getImpl().dialects) 327 if (name == dialect->getNamespace()) 328 return dialect.get(); 329 return nullptr; 330 } 331 332 /// Register this dialect object with the specified context. The context 333 /// takes ownership of the heap allocated dialect. 334 void Dialect::registerDialect(MLIRContext *context) { 335 auto &impl = context->getImpl(); 336 std::unique_ptr<Dialect> dialect(this); 337 338 // Lock access to the context registry. 339 llvm::sys::SmartScopedWriter<true> registryLock(impl.contextMutex); 340 341 // Get the correct insertion position sorted by namespace. 342 auto insertPt = 343 llvm::lower_bound(impl.dialects, dialect, 344 [](const std::unique_ptr<Dialect> &lhs, 345 const std::unique_ptr<Dialect> &rhs) { 346 return lhs->getNamespace() < rhs->getNamespace(); 347 }); 348 349 // Abort if dialect with namespace has already been registered. 350 if (insertPt != impl.dialects.end() && 351 (*insertPt)->getNamespace() == getNamespace()) { 352 llvm::report_fatal_error("a dialect with namespace '" + getNamespace() + 353 "' has already been registered"); 354 } 355 impl.dialects.insert(insertPt, std::move(dialect)); 356 } 357 358 /// Return information about all registered operations. This isn't very 359 /// efficient, typically you should ask the operations about their properties 360 /// directly. 361 std::vector<AbstractOperation *> MLIRContext::getRegisteredOperations() { 362 std::vector<std::pair<StringRef, AbstractOperation *>> opsToSort; 363 364 { // Lock access to the context registry. 365 llvm::sys::SmartScopedReader<true> registryLock(getImpl().contextMutex); 366 367 // We just have the operations in a non-deterministic hash table order. Dump 368 // into a temporary array, then sort it by operation name to get a stable 369 // ordering. 370 llvm::StringMap<AbstractOperation> ®isteredOps = 371 getImpl().registeredOperations; 372 373 opsToSort.reserve(registeredOps.size()); 374 for (auto &elt : registeredOps) 375 opsToSort.push_back({elt.first(), &elt.second}); 376 } 377 378 llvm::array_pod_sort(opsToSort.begin(), opsToSort.end()); 379 380 std::vector<AbstractOperation *> result; 381 result.reserve(opsToSort.size()); 382 for (auto &elt : opsToSort) 383 result.push_back(elt.second); 384 return result; 385 } 386 387 void Dialect::addOperation(AbstractOperation opInfo) { 388 assert((getNamespace().empty() || 389 opInfo.name.split('.').first == getNamespace()) && 390 "op name doesn't start with dialect namespace"); 391 assert(&opInfo.dialect == this && "Dialect object mismatch"); 392 auto &impl = context->getImpl(); 393 394 // Lock access to the context registry. 395 llvm::sys::SmartScopedWriter<true> registryLock(impl.contextMutex); 396 if (!impl.registeredOperations.insert({opInfo.name, opInfo}).second) { 397 llvm::errs() << "error: operation named '" << opInfo.name 398 << "' is already registered.\n"; 399 abort(); 400 } 401 } 402 403 /// Register a dialect-specific symbol(e.g. type) with the current context. 404 void Dialect::addSymbol(const ClassID *const classID) { 405 auto &impl = context->getImpl(); 406 407 // Lock access to the context registry. 408 llvm::sys::SmartScopedWriter<true> registryLock(impl.contextMutex); 409 if (!impl.registeredDialectSymbols.insert({classID, this}).second) { 410 llvm::errs() << "error: dialect symbol already registered.\n"; 411 abort(); 412 } 413 } 414 415 /// Look up the specified operation in the operation set and return a pointer 416 /// to it if present. Otherwise, return a null pointer. 417 const AbstractOperation *AbstractOperation::lookup(StringRef opName, 418 MLIRContext *context) { 419 auto &impl = context->getImpl(); 420 421 // Lock access to the context registry. 422 llvm::sys::SmartScopedReader<true> registryLock(impl.contextMutex); 423 auto it = impl.registeredOperations.find(opName); 424 if (it != impl.registeredOperations.end()) 425 return &it->second; 426 return nullptr; 427 } 428 429 //===----------------------------------------------------------------------===// 430 // Identifier uniquing 431 //===----------------------------------------------------------------------===// 432 433 /// Return an identifier for the specified string. 434 Identifier Identifier::get(StringRef str, MLIRContext *context) { 435 assert(!str.empty() && "Cannot create an empty identifier"); 436 assert(str.find('\0') == StringRef::npos && 437 "Cannot create an identifier with a nul character"); 438 439 auto &impl = context->getImpl(); 440 441 { // Check for an existing identifier in read-only mode. 442 llvm::sys::SmartScopedReader<true> contextLock(impl.identifierMutex); 443 auto it = impl.identifiers.find(str); 444 if (it != impl.identifiers.end()) 445 return Identifier(it->getKeyData()); 446 } 447 448 // Aquire a writer-lock so that we can safely create the new instance. 449 llvm::sys::SmartScopedWriter<true> contextLock(impl.identifierMutex); 450 auto it = impl.identifiers.insert({str, char()}).first; 451 return Identifier(it->getKeyData()); 452 } 453 454 //===----------------------------------------------------------------------===// 455 // Type uniquing 456 //===----------------------------------------------------------------------===// 457 458 static Dialect &lookupDialectForSymbol(MLIRContext *ctx, 459 const ClassID *const classID) { 460 auto &impl = ctx->getImpl(); 461 auto it = impl.registeredDialectSymbols.find(classID); 462 assert(it != impl.registeredDialectSymbols.end() && 463 "symbol is not registered."); 464 return *it->second; 465 } 466 467 /// Returns the storage unqiuer used for constructing type storage instances. 468 /// This should not be used directly. 469 StorageUniquer &MLIRContext::getTypeUniquer() { return getImpl().typeUniquer; } 470 471 /// Get the dialect that registered the type with the provided typeid. 472 Dialect &TypeUniquer::lookupDialectForType(MLIRContext *ctx, 473 const ClassID *const typeID) { 474 return lookupDialectForSymbol(ctx, typeID); 475 } 476 477 FloatType FloatType::get(StandardTypes::Kind kind, MLIRContext *context) { 478 assert(kindof(kind) && "Not a FP kind."); 479 switch (kind) { 480 case StandardTypes::BF16: 481 return context->getImpl().bf16Ty; 482 case StandardTypes::F16: 483 return context->getImpl().f16Ty; 484 case StandardTypes::F32: 485 return context->getImpl().f32Ty; 486 case StandardTypes::F64: 487 return context->getImpl().f64Ty; 488 default: 489 llvm_unreachable("unexpected floating-point kind"); 490 } 491 } 492 493 /// Get an instance of the IndexType. 494 IndexType IndexType::get(MLIRContext *context) { 495 return context->getImpl().indexTy; 496 } 497 498 /// Return an existing integer type instance if one is cached within the 499 /// context. 500 static IntegerType getCachedIntegerType(unsigned width, MLIRContext *context) { 501 switch (width) { 502 case 1: 503 return context->getImpl().int1Ty; 504 case 8: 505 return context->getImpl().int8Ty; 506 case 16: 507 return context->getImpl().int16Ty; 508 case 32: 509 return context->getImpl().int32Ty; 510 case 64: 511 return context->getImpl().int64Ty; 512 case 128: 513 return context->getImpl().int128Ty; 514 default: 515 return IntegerType(); 516 } 517 } 518 519 IntegerType IntegerType::get(unsigned width, MLIRContext *context) { 520 if (auto cached = getCachedIntegerType(width, context)) 521 return cached; 522 return Base::get(context, StandardTypes::Integer, width); 523 } 524 525 IntegerType IntegerType::getChecked(unsigned width, MLIRContext *context, 526 Location location) { 527 if (auto cached = getCachedIntegerType(width, context)) 528 return cached; 529 return Base::getChecked(location, context, StandardTypes::Integer, width); 530 } 531 532 /// Get an instance of the NoneType. 533 NoneType NoneType::get(MLIRContext *context) { 534 return context->getImpl().noneType; 535 } 536 537 //===----------------------------------------------------------------------===// 538 // Attribute uniquing 539 //===----------------------------------------------------------------------===// 540 541 /// Returns the storage uniquer used for constructing attribute storage 542 /// instances. This should not be used directly. 543 StorageUniquer &MLIRContext::getAttributeUniquer() { 544 return getImpl().attributeUniquer; 545 } 546 547 /// Returns a functor used to initialize new attribute storage instances. 548 std::function<void(AttributeStorage *)> 549 AttributeUniquer::getInitFn(MLIRContext *ctx, const ClassID *const attrID) { 550 return [ctx, attrID](AttributeStorage *storage) { 551 storage->initializeDialect(lookupDialectForSymbol(ctx, attrID)); 552 553 // If the attribute did not provide a type, then default to NoneType. 554 if (!storage->getType()) 555 storage->setType(NoneType::get(ctx)); 556 }; 557 } 558 559 BoolAttr BoolAttr::get(bool value, MLIRContext *context) { 560 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr; 561 } 562 563 UnitAttr UnitAttr::get(MLIRContext *context) { 564 return context->getImpl().unitAttr; 565 } 566 567 Location UnknownLoc::get(MLIRContext *context) { 568 return context->getImpl().unknownLocAttr; 569 } 570 571 //===----------------------------------------------------------------------===// 572 // AffineMap uniquing 573 //===----------------------------------------------------------------------===// 574 575 StorageUniquer &MLIRContext::getAffineUniquer() { 576 return getImpl().affineUniquer; 577 } 578 579 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount, 580 ArrayRef<AffineExpr> results, 581 MLIRContext *context) { 582 auto &impl = context->getImpl(); 583 auto key = std::make_tuple(dimCount, symbolCount, results); 584 585 // Safely get or create an AffineMap instance. 586 return safeGetOrCreate(impl.affineMaps, key, impl.affineMutex, [&] { 587 auto *res = impl.affineAllocator.Allocate<detail::AffineMapStorage>(); 588 589 // Copy the results into the bump pointer. 590 results = copyArrayRefInto(impl.affineAllocator, results); 591 592 // Initialize the memory using placement new. 593 new (res) detail::AffineMapStorage{dimCount, symbolCount, results, context}; 594 return AffineMap(res); 595 }); 596 } 597 598 AffineMap AffineMap::get(MLIRContext *context) { 599 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context); 600 } 601 602 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount, 603 ArrayRef<AffineExpr> results) { 604 // The number of results can't be zero. 605 assert(!results.empty()); 606 return getImpl(dimCount, symbolCount, results, results[0].getContext()); 607 } 608 609 //===----------------------------------------------------------------------===// 610 // Integer Sets: these are allocated into the bump pointer, and are immutable. 611 // Unlike AffineMap's, these are uniqued only if they are small. 612 //===----------------------------------------------------------------------===// 613 614 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount, 615 ArrayRef<AffineExpr> constraints, 616 ArrayRef<bool> eqFlags) { 617 // The number of constraints can't be zero. 618 assert(!constraints.empty()); 619 assert(constraints.size() == eqFlags.size()); 620 621 auto &impl = constraints[0].getContext()->getImpl(); 622 623 // A utility function to construct a new IntegerSetStorage instance. 624 auto constructorFn = [&] { 625 auto *res = impl.affineAllocator.Allocate<detail::IntegerSetStorage>(); 626 627 // Copy the results and equality flags into the bump pointer. 628 constraints = copyArrayRefInto(impl.affineAllocator, constraints); 629 eqFlags = copyArrayRefInto(impl.affineAllocator, eqFlags); 630 631 // Initialize the memory using placement new. 632 new (res) 633 detail::IntegerSetStorage{dimCount, symbolCount, constraints, eqFlags}; 634 return IntegerSet(res); 635 }; 636 637 // If this instance is uniqued, then we handle it separately so that multiple 638 // threads may simulatenously access existing instances. 639 if (constraints.size() < IntegerSet::kUniquingThreshold) { 640 auto key = std::make_tuple(dimCount, symbolCount, constraints, eqFlags); 641 return safeGetOrCreate(impl.integerSets, key, impl.affineMutex, 642 constructorFn); 643 } 644 645 // Otherwise, aquire a writer-lock so that we can safely create the new 646 // instance. 647 llvm::sys::SmartScopedWriter<true> affineLock(impl.affineMutex); 648 return constructorFn(); 649 }