lib/IRGen/GenMeta.cpp
void irgen::emitLazyCacheAccessFunction(IRGenModule &IGM,
                                        llvm::Function *accessor,
                                        llvm::GlobalVariable *cacheVariable,
         const llvm::function_ref<llvm::Value*(IRGenFunction &IGF)> &getValue) {
  accessor->setDoesNotThrow();

  // This function is logically 'readnone': the caller does not need
  // to reason about any side effects or stores it might perform.
  accessor->setDoesNotAccessMemory();

  IRGenFunction IGF(IGM, accessor);
  if (IGM.DebugInfo)
    IGM.DebugInfo->emitArtificialFunction(IGF, accessor);

  // If there's no cache variable, just perform the direct access.
  if (cacheVariable == nullptr) {
    IGF.Builder.CreateRet(getValue(IGF));
    return;
  }

  // Set up the cache variable.
  llvm::Constant *null =
    llvm::ConstantPointerNull::get(
                        cast<llvm::PointerType>(cacheVariable->getValueType()));

  cacheVariable->setInitializer(null);
  cacheVariable->setAlignment(IGM.getPointerAlignment().getValue());
  Address cache(cacheVariable, IGM.getPointerAlignment());

  // Okay, first thing, check the cache variable.
  //
  // Conceptually, this needs to establish memory ordering with the
  // store we do later in the function: if the metadata value is
  // non-null, we must be able to see any stores performed by the
  // initialization of the metadata.  However, any attempt to read
  // from the metadata will be address-dependent on the loaded
  // metadata pointer, which is sufficient to provide adequate
  // memory ordering guarantees on all the platforms we care about:
  // ARM has special rules about address dependencies, and x86's
  // memory ordering is strong enough to guarantee the visibility
  // even without the address dependency.
  //
  // And we do not need to worry about the compiler because the
  // address dependency naturally forces an order to the memory
  // accesses.
  //
  // Therefore, we can perform a completely naked load here.
  // FIXME: Technically should be "consume", but that introduces barriers in the
  // current LLVM ARM backend.
  auto load = IGF.Builder.CreateLoad(cache);
  // Make this barrier explicit when building for TSan to avoid false positives.
  if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
    load->setOrdering(llvm::AtomicOrdering::Acquire);


  // Compare the load result against null.
  auto isNullBB = IGF.createBasicBlock("cacheIsNull");
  auto contBB = IGF.createBasicBlock("cont");
  llvm::Value *comparison = IGF.Builder.CreateICmpEQ(load, null);
  IGF.Builder.CreateCondBr(comparison, isNullBB, contBB);
  auto loadBB = IGF.Builder.GetInsertBlock();

  // If the load yielded null, emit the type metadata.
  IGF.Builder.emitBlock(isNullBB);
  llvm::Value *directResult = getValue(IGF);

  // Store it back to the cache variable.  This needs to be a store-release
  // because it needs to propagate memory visibility to the other threads
  // that can access the cache: the initializing stores might be visible
  // to this thread, but they aren't transitively guaranteed to be visible
  // to other threads unless this is a store-release.
  //
  // However, we can skip this if the value was actually loaded from the
  // cache.  This is a simple, if hacky, peephole that's useful for the
  // code in emitInPlaceTypeMetadataAccessFunctionBody.
  if (!isLoadFrom(directResult, cache)) {
    IGF.Builder.CreateStore(directResult, cache)
      ->setAtomic(llvm::AtomicOrdering::Release);
  }

  IGF.Builder.CreateBr(contBB);
  auto storeBB = IGF.Builder.GetInsertBlock();

  // Emit the continuation block.
  IGF.Builder.emitBlock(contBB);
  auto phi = IGF.Builder.CreatePHI(null->getType(), 2);
  phi->addIncoming(load, loadBB);
  phi->addIncoming(directResult, storeBB);

  IGF.Builder.CreateRet(phi);
}
/// Emit the body of a lazy cache accessor.
///
/// If cacheVariable is null, we perform the direct access every time.
/// This is used for metadata accessors that come about due to resilience,
/// where the direct access is completely trivial.
Emit the body of a lazy cache accessor.
If cacheVariable is null, we perform the direct access every time.
This is used for metadata accessors that come about due to resilience,
where the direct access is completely trivial.
Emit the body of a lazy cache accessor . If cacheVariable is null we perform the direct access every time . This is used for metadata accessors that come about due to resilience where the direct access is completely trivial .
void irgen::emitLazyCacheAccessFunction(IRGenModule &IGM,
                                        llvm::Function *accessor,
                                        llvm::GlobalVariable *cacheVariable,
         const llvm::function_ref<llvm::Value*(IRGenFunction &IGF)> &getValue) {
  accessor->setDoesNotThrow();
  accessor->setDoesNotAccessMemory();
  IRGenFunction IGF(IGM, accessor);
  if (IGM.DebugInfo)
    IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
  if (cacheVariable == nullptr) {
    IGF.Builder.CreateRet(getValue(IGF));
    return;
  }
  llvm::Constant *null =
    llvm::ConstantPointerNull::get(
                        cast<llvm::PointerType>(cacheVariable->getValueType()));
  cacheVariable->setInitializer(null);
  cacheVariable->setAlignment(IGM.getPointerAlignment().getValue());
  Address cache(cacheVariable, IGM.getPointerAlignment());
   Conceptually, this needs to establish memory ordering with the
   store we do later in the function: if the metadata value is
   non-null, we must be able to see any stores performed by the
   initialization of the metadata.  However, any attempt to read
   from the metadata will be address-dependent on the loaded
   metadata pointer, which is sufficient to provide adequate
   memory ordering guarantees on all the platforms we care about:
   ARM has special rules about address dependencies, and x86's
   memory ordering is strong enough to guarantee the visibility
   even without the address dependency.
   And we do not need to worry about the compiler because the
   address dependency naturally forces an order to the memory
   accesses.
   Therefore, we can perform a completely naked load here.
   FIXME: Technically should be "consume", but that introduces barriers in the
   current LLVM ARM backend.
  auto load = IGF.Builder.CreateLoad(cache);
   Make this barrier explicit when building for TSan to avoid false positives.
  if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
    load->setOrdering(llvm::AtomicOrdering::Acquire);
   Compare the load result against null.
  auto isNullBB = IGF.createBasicBlock("cacheIsNull");
  auto contBB = IGF.createBasicBlock("cont");
  llvm::Value *comparison = IGF.Builder.CreateICmpEQ(load, null);
  IGF.Builder.CreateCondBr(comparison, isNullBB, contBB);
  auto loadBB = IGF.Builder.GetInsertBlock();
   If the load yielded null, emit the type metadata.
  IGF.Builder.emitBlock(isNullBB);
  llvm::Value *directResult = getValue(IGF);
   Store it back to the cache variable.  This needs to be a store-release
   because it needs to propagate memory visibility to the other threads
   that can access the cache: the initializing stores might be visible
   to this thread, but they aren't transitively guaranteed to be visible
   to other threads unless this is a store-release.
   However, we can skip this if the value was actually loaded from the
   cache.  This is a simple, if hacky, peephole that's useful for the
   code in emitInPlaceTypeMetadataAccessFunctionBody.
  if (!isLoadFrom(directResult, cache)) {
    IGF.Builder.CreateStore(directResult, cache)
      ->setAtomic(llvm::AtomicOrdering::Release);
  }
  IGF.Builder.CreateBr(contBB);
  auto storeBB = IGF.Builder.GetInsertBlock();
   Emit the continuation block.
  IGF.Builder.emitBlock(contBB);
  auto phi = IGF.Builder.CreatePHI(null->getType(), 2);
  phi->addIncoming(load, loadBB);
  phi->addIncoming(directResult, storeBB);
  IGF.Builder.CreateRet(phi);
}
void irgen :: emitLazyCacheAccessFunction ( IRGenModule & IGM , llvm :: Function * accessor , llvm :: GlobalVariable * cacheVariable , const llvm :: function_ref < llvm :: Value * ( IRGenFunction & IGF ) > & getValue ) { accessor -> setDoesNotThrow ( ) ; accessor -> setDoesNotAccessMemory ( ) ; IRGenFunction IGF ( IGM , accessor ) ; if ( IGM . DebugInfo ) IGM . DebugInfo -> emitArtificialFunction ( IGF , accessor ) ; if ( cacheVariable == nullptr ) { IGF . Builder . CreateRet ( getValue ( IGF ) ) ; return ; } llvm :: Constant * null = llvm :: ConstantPointerNull :: get ( cast < llvm :: PointerType > ( cacheVariable -> getValueType ( ) ) ) ; cacheVariable -> setInitializer ( null ) ; cacheVariable -> setAlignment ( IGM . getPointerAlignment ( ) . getValue ( ) ) ; Address cache ( cacheVariable , IGM . getPointerAlignment ( ) ) ; auto load = IGF . Builder . CreateLoad ( cache ) ; if ( IGM . IRGen . Opts . Sanitizers & SanitizerKind :: Thread ) load -> setOrdering ( llvm :: AtomicOrdering :: Acquire ) ; auto isNullBB = IGF . createBasicBlock ( " " ) ; auto contBB = IGF . createBasicBlock ( " " ) ; llvm :: Value * comparison = IGF . Builder . CreateICmpEQ ( load , null ) ; IGF . Builder . CreateCondBr ( comparison , isNullBB , contBB ) ; auto loadBB = IGF . Builder . GetInsertBlock ( ) ; IGF . Builder . emitBlock ( isNullBB ) ; llvm :: Value * directResult = getValue ( IGF ) ; if ( ! isLoadFrom ( directResult , cache ) ) { IGF . Builder . CreateStore ( directResult , cache ) -> setAtomic ( llvm :: AtomicOrdering :: Release ) ; } IGF . Builder . CreateBr ( contBB ) ; auto storeBB = IGF . Builder . GetInsertBlock ( ) ; IGF . Builder . emitBlock ( contBB ) ; auto phi = IGF . Builder . CreatePHI ( null -> getType ( ) , 2 ) ; phi -> addIncoming ( load , loadBB ) ; phi -> addIncoming ( directResult , storeBB ) ; IGF . Builder . CreateRet ( phi ) ; }
Emit the body of a lazy cache accessor.
Emit the body of a lazy cache accessor .
// This function is logically 'readnone': the caller does not need // to reason about any side effects or stores it might perform. // If there's no cache variable, just perform the direct access. // Set up the cache variable. // Okay, first thing, check the cache variable. // // Conceptually, this needs to establish memory ordering with the // store we do later in the function: if the metadata value is // non-null, we must be able to see any stores performed by the // initialization of the metadata.  However, any attempt to read // from the metadata will be address-dependent on the loaded // metadata pointer, which is sufficient to provide adequate // memory ordering guarantees on all the platforms we care about: // ARM has special rules about address dependencies, and x86's // memory ordering is strong enough to guarantee the visibility // even without the address dependency. // // And we do not need to worry about the compiler because the // address dependency naturally forces an order to the memory // accesses. // // Therefore, we can perform a completely naked load here. // FIXME: Technically should be "consume", but that introduces barriers in the // current LLVM ARM backend. // Make this barrier explicit when building for TSan to avoid false positives. // Compare the load result against null. // If the load yielded null, emit the type metadata. // Store it back to the cache variable.  This needs to be a store-release // because it needs to propagate memory visibility to the other threads // that can access the cache: the initializing stores might be visible // to this thread, but they aren't transitively guaranteed to be visible // to other threads unless this is a store-release. // // However, we can skip this if the value was actually loaded from the // cache.  This is a simple, if hacky, peephole that's useful for the // code in emitInPlaceTypeMetadataAccessFunctionBody. // Emit the continuation block.