Skip to content

Commit

Permalink
Fix: thread safety of LLVM legacy pass manager
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed Sep 3, 2024
1 parent 8e94f9c commit 96b6f77
Showing 1 changed file with 43 additions and 46 deletions.
89 changes: 43 additions & 46 deletions src/compiler/crystal/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ module Crystal
CompilationUnit.new(self, program, type_name, llvm_mod, output_dir, bc_flags_changed)
end

{% if LibLLVM::IS_LT_170 %}
# initialize the legacy pass manager once in the main thread/process
# before we start codegen in threads (MT) or processes (fork)
init_llvm_legacy_pass_manager unless optimization_mode.o0?
{% end %}

if @cross_compile
cross_compile program, units, output_filename
else
Expand Down Expand Up @@ -735,57 +741,48 @@ module Crystal
end

{% if LibLLVM::IS_LT_170 %}
property! pass_manager_builder : LLVM::PassManagerBuilder

private def init_llvm_legacy_pass_manager
registry = LLVM::PassRegistry.instance
registry.initialize_all

builder = LLVM::PassManagerBuilder.new
builder.size_level = 0

case optimization_mode
in .o3?
builder.opt_level = 3
builder.use_inliner_with_threshold = 275
in .o2?
builder.opt_level = 2
builder.use_inliner_with_threshold = 275
in .o1?
builder.opt_level = 1
builder.use_inliner_with_threshold = 150
in .o0?
# default behaviour, no optimizations
in .os?
builder.opt_level = 2
builder.size_level = 1
builder.use_inliner_with_threshold = 50
in .oz?
builder.opt_level = 2
builder.size_level = 2
builder.use_inliner_with_threshold = 5
end

@pass_manager_builder = builder
end

private def optimize_with_pass_manager(llvm_mod)
fun_pass_manager = llvm_mod.new_function_pass_manager
pass_manager_builder.populate fun_pass_manager
fun_pass_manager.run llvm_mod
module_pass_manager.run llvm_mod
end

@module_pass_manager : LLVM::ModulePassManager?

private def module_pass_manager
@module_pass_manager ||= begin
mod_pass_manager = LLVM::ModulePassManager.new
pass_manager_builder.populate mod_pass_manager
mod_pass_manager
end
end

@pass_manager_builder : LLVM::PassManagerBuilder?

private def pass_manager_builder
@pass_manager_builder ||= begin
registry = LLVM::PassRegistry.instance
registry.initialize_all

builder = LLVM::PassManagerBuilder.new
builder.size_level = 0

case optimization_mode
in .o3?
builder.opt_level = 3
builder.use_inliner_with_threshold = 275
in .o2?
builder.opt_level = 2
builder.use_inliner_with_threshold = 275
in .o1?
builder.opt_level = 1
builder.use_inliner_with_threshold = 150
in .o0?
# default behaviour, no optimizations
in .os?
builder.opt_level = 2
builder.size_level = 1
builder.use_inliner_with_threshold = 50
in .oz?
builder.opt_level = 2
builder.size_level = 2
builder.use_inliner_with_threshold = 5
end

builder
end
module_pass_manager = LLVM::ModulePassManager.new
pass_manager_builder.populate module_pass_manager
module_pass_manager.run llvm_mod
end
{% end %}

Expand Down

0 comments on commit 96b6f77

Please sign in to comment.