single-threaded code-gen and how to make it support multi-thread

Hi llvm-dev,

Our code base has a ancient copy of llvm (ver 3.5.1), and it uses the LLVM
code gen for some domain-specific language.

The previous dev left a global lock around the usage of LLVM code gen
stating that because LLVM code gen can only be accessed single-threaded it
needs to be protected with this global lock.

But now this lock has caused some perf issues as we pretty much lose
concurrency when having to compile a large number of source files.

I've tried to remove the global lock and what I have observed in crashing
stack is something like below:

(I did make sure LLVM_ENABLE_THREADS is defined to be 1, apparently it
didn't seem to help)

The document around this seems vague, I have not found a clear instruction
as to how to solve this, hence this post. Can anyone help with some
pointers?

Any guidance is appreciated:)

  ntdll.dll!RtlReportCriticalFailure(long StatusCode, void * FailureInfo,
unsigned long BreakIfDbgPresent) Line 201 C
  ntdll.dll!RtlpHeapHandleError(long ErrorLevel) Line 344 C
  ntdll.dll!RtlpHpHeapHandleError(_HEAP_FAILURE_TYPE FailureType, unsigned
__int64 HeapAddress, unsigned __int64 Address) Line 670 C
  ntdll.dll!RtlpLogHeapFailure(_HEAP_FAILURE_TYPE FailureType, void *
HeapAddress, void * Address, void * Param1, void * Param2, void * Param3)
Line 158 C
  ntdll.dll!RtlFreeHeap(void * HeapHandle, unsigned long Flags, void *
BaseAddress) Line 352 C
  ucrtbase.dll!_free_base(void * block) Line 105 C++
  XXXTest.exe!llvm::StringMapImpl::RehashTable(unsigned int BucketNo) Line
238 C++
  XXXTest.exe!llvm::StringMap<llvm::ConstantDataSequential *
__ptr64,llvm::MallocAllocator>::insert(std::pair<llvm::StringRef,llvm::ConstantDataSequential
*> KV) Line 344 C++
  [Inline Frame] XXXTest.exe!llvm::StringMap<llvm::Value
*,llvm::MallocAllocator>::GetOrCreateValue(llvm::StringRef) Line 371 C++
  [Inline Frame] XXXTest.exe!llvm::StringMap<llvm::Value
*,llvm::MallocAllocator>::GetOrCreateValue(llvm::StringRef) Line 375 C++
  XXXTest.exe!llvm::ValueSymbolTable::createValueName(llvm::StringRef Name,
llvm::Value * V) Line 98 C++
  XXXTest.exe!llvm::Value::setName(const llvm::Twine & NewName) Line 236 C++
  XXXTest.exe!llvm::IRBuilder<1,llvm::ConstantFolder,llvm::IRBuilderDefaultInserter<1>

::Insert<llvm::GetElementPtrInst>(llvm::GetElementPtrInst * I, const

llvm::Twine & Name) Line 497 C++
  XXXTest.exe!llvm::IRBuilder<1,llvm::ConstantFolder,llvm::IRBuilderDefaultInserter<1>

::CreateConstInBoundsGEP1_32(llvm::Value * Ptr, unsigned int Idx0, const

llvm::Twine & Name) Line 1014 C++

XXXTest.exe!XXX::LlvmCodeGenerator::Visit(const XXX::FeatureRefExpression

& p_expr) Line 953 C++
  XXXTest.exe!XXX::FeatureRefExpression::Accept(XXX::Visitor & p_visitor)
Line 46 C++

Do you use one llvm context or one per thread that interacts with llvm? I’m not an expert but the former might not be supported.

Cheers,

Johannes

Thank you Johannes, I looked it up and it seems that we’re creating one LLVMContext per compilation “unit”, not sure if that matters. i.e. there’s no single globally shared LLVMContext object.

Is LLVMContext the concurrency isolation (or unit) here?

I thought isolation is guaranteed per LLVMContext, but I might be wrong. Maybe somebody else can help.

Yes, the LLVM Context is the unit of isolation.

In the LLVM tree, the best example is likely ThinLTO using a ThreadPool to codegen modules in parallel, see:

https://github.com/llvm/llvm-project/blob/master/llvm/lib/LTO/LTOBackend.cpp#L347

and/or:
https://github.com/llvm/llvm-project/blob/master/llvm/lib/LTO/ThinLTOCodeGenerator.cpp#L833

Hope this’ll help!