From c7b2fafaad24cf9813e72bc72d89ca62dbb5a7e9 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Wed, 26 Nov 2025 17:03:19 +0100 Subject: [PATCH 1/2] LLVM: simplify target initialization and support more targets --- src/llvm.cr | 101 +++++++----------------------------- src/llvm/lib_llvm.cr | 33 ++++++++++++ src/llvm/lib_llvm/target.cr | 32 +++--------- 3 files changed, 58 insertions(+), 108 deletions(-) diff --git a/src/llvm.cr b/src/llvm.cr index 87e8d90ba0ed..9878e294b91f 100644 --- a/src/llvm.cr +++ b/src/llvm.cr @@ -2,8 +2,6 @@ require "./llvm/**" require "c/string" module LLVM - @@initialized = false - # Returns the runtime version of LLVM. # # Starting with LLVM 16, this method returns the version as reported by @@ -20,85 +18,24 @@ module LLVM {% end %} end - def self.init_x86 : Nil - return if @@initialized_x86 - @@initialized_x86 = true - - {% if LibLLVM::BUILT_TARGETS.includes?(:x86) %} - LibLLVM.initialize_x86_target_info - LibLLVM.initialize_x86_target - LibLLVM.initialize_x86_target_mc - LibLLVM.initialize_x86_asm_printer - LibLLVM.initialize_x86_asm_parser - LibLLVM.link_in_mc_jit - {% else %} - raise "ERROR: LLVM was built without X86 target" - {% end %} - end - - def self.init_aarch64 : Nil - return if @@initialized_aarch64 - @@initialized_aarch64 = true - - {% if LibLLVM::BUILT_TARGETS.includes?(:aarch64) %} - LibLLVM.initialize_aarch64_target_info - LibLLVM.initialize_aarch64_target - LibLLVM.initialize_aarch64_target_mc - LibLLVM.initialize_aarch64_asm_printer - LibLLVM.initialize_aarch64_asm_parser - LibLLVM.link_in_mc_jit - {% else %} - raise "ERROR: LLVM was built without AArch64 target" - {% end %} - end - - def self.init_arm : Nil - return if @@initialized_arm - @@initialized_arm = true - - {% if LibLLVM::BUILT_TARGETS.includes?(:arm) %} - LibLLVM.initialize_arm_target_info - LibLLVM.initialize_arm_target - LibLLVM.initialize_arm_target_mc - LibLLVM.initialize_arm_asm_printer - LibLLVM.initialize_arm_asm_parser - LibLLVM.link_in_mc_jit - {% else %} - raise "ERROR: LLVM was built without ARM target" - {% end %} - end + {% for target, name in LibLLVM::TARGETS %} + @@initialized_{{name.id}} = Atomic(Bool).new(false) - def self.init_avr : Nil - return if @@initialized_avr - @@initialized_avr = true - - {% if LibLLVM::BUILT_TARGETS.includes?(:avr) %} - LibLLVM.initialize_avr_target_info - LibLLVM.initialize_avr_target - LibLLVM.initialize_avr_target_mc - LibLLVM.initialize_avr_asm_printer - LibLLVM.initialize_avr_asm_parser - LibLLVM.link_in_mc_jit - {% else %} - raise "ERROR: LLVM was built without AVR target" - {% end %} - end + def self.init_{{name.id}} : Nil + return if @@initialized_{{name.id}}.swap(true) - def self.init_webassembly : Nil - return if @@initialized_webassembly - @@initialized_webassembly = true - - {% if LibLLVM::BUILT_TARGETS.includes?(:webassembly) %} - LibLLVM.initialize_webassembly_target_info - LibLLVM.initialize_webassembly_target - LibLLVM.initialize_webassembly_target_mc - LibLLVM.initialize_webassembly_asm_printer - LibLLVM.initialize_webassembly_asm_parser - LibLLVM.link_in_mc_jit - {% else %} - raise "ERROR: LLVM was built without WebAssembly target" - {% end %} - end + \{% if LibLLVM::BUILT_TARGETS.includes?({{name}}) %} + LibLLVM.initialize_{{name.id}}_target_info + LibLLVM.initialize_{{name.id}}_target + LibLLVM.initialize_{{name.id}}_target_mc + LibLLVM.initialize_{{name.id}}_asm_printer + LibLLVM.initialize_{{name.id}}_asm_parser + LibLLVM.link_in_mc_jit + \{% else %} + raise "ERROR: LLVM was built without {{target.id}} target" + \{% end %} + end + {% end %} def self.init_native_target : Nil {% if flag?(:i386) || flag?(:x86_64) %} @@ -117,10 +54,8 @@ module LLVM end def self.init_all_targets : Nil - {% for target in %i(x86 aarch64 arm avr webassembly) %} - {% if LibLLVM::BUILT_TARGETS.includes?(target) %} - init_{{ target.id }} - {% end %} + {% for name in LibLLVM::BUILT_TARGETS %} + init_{{name.id}} {% end %} end diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 3339942d7cea..3e06c8713115 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -51,6 +51,39 @@ lib LibLLVM VERSION = {{ llvm_version.strip.gsub(/git/, "").gsub(/-?rc.*/, "") }} BUILT_TARGETS = {{ llvm_targets.strip.downcase.gsub(/;|,/, " ").split(' ').map(&.id.symbolize) }} + + # The list of targets is hardcoded at: + # https://github.com/llvm/llvm-project/blob/main/llvm/CMakeLists.txt + TARGETS = { + # enabled by default + "AArch64" => :aarch64, + "AMDGPU" => :amdgpu, + "ARM" => :arm, + "AVR" => :avr, + "BPF" => :bpf, + "Hexagon" => :hexagon, + "Lanai" => :lanai, + "LoongArch" => :loongarch, + "MSP430" => :msp430, + "Mips" => :mips, + "NVPTX" => :nvptx, + "PowerPC" => :powerpc, + "RISCV" => :riscv, + "SPIRV" => :spirv, + "Sparc" => :sparc, + "SystemZ" => :systemz, + "VE" => :ve, + "WebAssembly" => :webassembly, + "X86" => :x86, + "XCore" => :xcore, + + # experimental + "ARC" => :arc, + "CSKY" => :csky, + "DirectX" => :directx, + "M68k" => :m68k, + "Xtensa" => :xtensa, + } end {% end %} diff --git a/src/llvm/lib_llvm/target.cr b/src/llvm/lib_llvm/target.cr index 7e50e5d663fa..4dad434b368c 100644 --- a/src/llvm/lib_llvm/target.cr +++ b/src/llvm/lib_llvm/target.cr @@ -3,31 +3,13 @@ require "./types" lib LibLLVM type TargetDataRef = Void* - fun initialize_aarch64_target_info = LLVMInitializeAArch64TargetInfo - fun initialize_aarch64_target = LLVMInitializeAArch64Target - fun initialize_aarch64_target_mc = LLVMInitializeAArch64TargetMC - fun initialize_aarch64_asm_printer = LLVMInitializeAArch64AsmPrinter - fun initialize_aarch64_asm_parser = LLVMInitializeAArch64AsmParser - fun initialize_arm_target_info = LLVMInitializeARMTargetInfo - fun initialize_arm_target = LLVMInitializeARMTarget - fun initialize_arm_target_mc = LLVMInitializeARMTargetMC - fun initialize_arm_asm_printer = LLVMInitializeARMAsmPrinter - fun initialize_arm_asm_parser = LLVMInitializeARMAsmParser - fun initialize_avr_target_info = LLVMInitializeAVRTargetInfo - fun initialize_avr_target = LLVMInitializeAVRTarget - fun initialize_avr_target_mc = LLVMInitializeAVRTargetMC - fun initialize_avr_asm_printer = LLVMInitializeAVRAsmPrinter - fun initialize_avr_asm_parser = LLVMInitializeAVRAsmParser - fun initialize_webassembly_target_info = LLVMInitializeWebAssemblyTargetInfo - fun initialize_webassembly_target = LLVMInitializeWebAssemblyTarget - fun initialize_webassembly_target_mc = LLVMInitializeWebAssemblyTargetMC - fun initialize_webassembly_asm_printer = LLVMInitializeWebAssemblyAsmPrinter - fun initialize_webassembly_asm_parser = LLVMInitializeWebAssemblyAsmParser - fun initialize_x86_target_info = LLVMInitializeX86TargetInfo - fun initialize_x86_target = LLVMInitializeX86Target - fun initialize_x86_target_mc = LLVMInitializeX86TargetMC - fun initialize_x86_asm_printer = LLVMInitializeX86AsmPrinter - fun initialize_x86_asm_parser = LLVMInitializeX86AsmParser + {% for target, name in TARGETS %} + fun initialize_{{name.id}}_target_info = LLVMInitialize{{target.id}}TargetInfo + fun initialize_{{name.id}}_target = LLVMInitialize{{target.id}}Target + fun initialize_{{name.id}}_target_mc = LLVMInitialize{{target.id}}TargetMC + fun initialize_{{name.id}}_asm_printer = LLVMInitialize{{target.id}}AsmPrinter + fun initialize_{{name.id}}_asm_parser = LLVMInitialize{{target.id}}AsmParser + {% end %} fun set_module_data_layout = LLVMSetModuleDataLayout(m : ModuleRef, dl : TargetDataRef) From d1d30b63400ab625a748bf72250e1123e31d8d25 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Thu, 27 Nov 2025 11:22:10 +0100 Subject: [PATCH 2/2] Rename ALL_TARGETS + Hash to Array + remove dup from scripts/generate_llvm_version_info.cr --- scripts/generate_llvm_version_info.cr | 33 ++----------------------- src/llvm.cr | 32 +++++++++++++----------- src/llvm/lib_llvm.cr | 34 +------------------------- src/llvm/lib_llvm/config.cr | 35 +++++++++++++++++++++++++++ src/llvm/lib_llvm/target.cr | 13 +++++----- 5 files changed, 63 insertions(+), 84 deletions(-) create mode 100644 src/llvm/lib_llvm/config.cr diff --git a/scripts/generate_llvm_version_info.cr b/scripts/generate_llvm_version_info.cr index bfe7e1f2ce96..e331f49056fa 100755 --- a/scripts/generate_llvm_version_info.cr +++ b/scripts/generate_llvm_version_info.cr @@ -5,36 +5,7 @@ # LLVM installation different from the one bundled with Crystal. require "c/libloaderapi" - -# The list of supported targets are hardcoded in: -# https://github.com/llvm/llvm-project/blob/main/llvm/CMakeLists.txt -LLVM_ALL_TARGETS = %w( - AArch64 - AMDGPU - ARM - AVR - BPF - Hexagon - Lanai - LoongArch - Mips - MSP430 - NVPTX - PowerPC - RISCV - Sparc - SPIRV - SystemZ - VE - WebAssembly - X86 - XCore - ARC - CSKY - DirectX - M68k - Xtensa -) +require "llvm/lib_llvm/config" def find_dll_in_env_path ENV["PATH"]?.try &.split(Process::PATH_DELIMITER, remove_empty: true) do |path| @@ -62,7 +33,7 @@ begin patch = uninitialized LibC::UInt llvm_get_version.call(pointerof(major), pointerof(minor), pointerof(patch)) - targets_built = LLVM_ALL_TARGETS.select do |target| + targets_built = LibLLVM::ALL_TARGETS.select do |target| LibC.GetProcAddress(dll, "LLVMInitialize#{target}Target") && LibC.GetProcAddress(dll, "LLVMInitialize#{target}TargetInfo") end diff --git a/src/llvm.cr b/src/llvm.cr index 9878e294b91f..8865f6a54268 100644 --- a/src/llvm.cr +++ b/src/llvm.cr @@ -18,18 +18,19 @@ module LLVM {% end %} end - {% for target, name in LibLLVM::TARGETS %} - @@initialized_{{name.id}} = Atomic(Bool).new(false) - - def self.init_{{name.id}} : Nil - return if @@initialized_{{name.id}}.swap(true) - - \{% if LibLLVM::BUILT_TARGETS.includes?({{name}}) %} - LibLLVM.initialize_{{name.id}}_target_info - LibLLVM.initialize_{{name.id}}_target - LibLLVM.initialize_{{name.id}}_target_mc - LibLLVM.initialize_{{name.id}}_asm_printer - LibLLVM.initialize_{{name.id}}_asm_parser + {% for target in LibLLVM::ALL_TARGETS %} + {% name = target.downcase.id %} + @@initialized_{{name}} = Atomic(Bool).new(false) + + def self.init_{{name}} : Nil + return if @@initialized_{{name}}.swap(true) + + \{% if LibLLVM::BUILT_TARGETS.includes?({{name.symbolize}}) %} + LibLLVM.initialize_{{name}}_target_info + LibLLVM.initialize_{{name}}_target + LibLLVM.initialize_{{name}}_target_mc + LibLLVM.initialize_{{name}}_asm_printer + LibLLVM.initialize_{{name}}_asm_parser LibLLVM.link_in_mc_jit \{% else %} raise "ERROR: LLVM was built without {{target.id}} target" @@ -54,8 +55,11 @@ module LLVM end def self.init_all_targets : Nil - {% for name in LibLLVM::BUILT_TARGETS %} - init_{{name.id}} + {% for target in LibLLVM::ALL_TARGETS %} + {% name = target.downcase.id %} + \{% if LibLLVM::BUILT_TARGETS.includes?({{name.symbolize}}) %} + init_{{name}} + \{% end %} {% end %} end diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 3e06c8713115..d907be9fbeeb 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -51,39 +51,6 @@ lib LibLLVM VERSION = {{ llvm_version.strip.gsub(/git/, "").gsub(/-?rc.*/, "") }} BUILT_TARGETS = {{ llvm_targets.strip.downcase.gsub(/;|,/, " ").split(' ').map(&.id.symbolize) }} - - # The list of targets is hardcoded at: - # https://github.com/llvm/llvm-project/blob/main/llvm/CMakeLists.txt - TARGETS = { - # enabled by default - "AArch64" => :aarch64, - "AMDGPU" => :amdgpu, - "ARM" => :arm, - "AVR" => :avr, - "BPF" => :bpf, - "Hexagon" => :hexagon, - "Lanai" => :lanai, - "LoongArch" => :loongarch, - "MSP430" => :msp430, - "Mips" => :mips, - "NVPTX" => :nvptx, - "PowerPC" => :powerpc, - "RISCV" => :riscv, - "SPIRV" => :spirv, - "Sparc" => :sparc, - "SystemZ" => :systemz, - "VE" => :ve, - "WebAssembly" => :webassembly, - "X86" => :x86, - "XCore" => :xcore, - - # experimental - "ARC" => :arc, - "CSKY" => :csky, - "DirectX" => :directx, - "M68k" => :m68k, - "Xtensa" => :xtensa, - } end {% end %} @@ -120,4 +87,5 @@ lib LibLLVM alias SizeT = LibC::SizeT end +require "./lib_llvm/config" require "./lib_llvm/**" diff --git a/src/llvm/lib_llvm/config.cr b/src/llvm/lib_llvm/config.cr new file mode 100644 index 000000000000..c90d6d9c74d7 --- /dev/null +++ b/src/llvm/lib_llvm/config.cr @@ -0,0 +1,35 @@ +# The list of supported targets are hardcoded in: +# https://github.com/llvm/llvm-project/blob/main/llvm/CMakeLists.txt + +lib LibLLVM + ALL_TARGETS = [ + # default targets (as of LLVM 21) + "AArch64", + "AMDGPU", + "ARM", + "AVR", + "BPF", + "Hexagon", + "Lanai", + "LoongArch", + "MSP430", + "Mips", + "NVPTX", + "PowerPC", + "RISCV", + "SPIRV", + "Sparc", + "SystemZ", + "VE", + "WebAssembly", + "X86", + "XCore", + + # experimental targets (as of LLVM 21) + "ARC", + "CSKY", + "DirectX", + "M68k", + "Xtensa", + ] +end diff --git a/src/llvm/lib_llvm/target.cr b/src/llvm/lib_llvm/target.cr index 4dad434b368c..cd076658d574 100644 --- a/src/llvm/lib_llvm/target.cr +++ b/src/llvm/lib_llvm/target.cr @@ -3,12 +3,13 @@ require "./types" lib LibLLVM type TargetDataRef = Void* - {% for target, name in TARGETS %} - fun initialize_{{name.id}}_target_info = LLVMInitialize{{target.id}}TargetInfo - fun initialize_{{name.id}}_target = LLVMInitialize{{target.id}}Target - fun initialize_{{name.id}}_target_mc = LLVMInitialize{{target.id}}TargetMC - fun initialize_{{name.id}}_asm_printer = LLVMInitialize{{target.id}}AsmPrinter - fun initialize_{{name.id}}_asm_parser = LLVMInitialize{{target.id}}AsmParser + {% for target in ALL_TARGETS %} + {% name = target.downcase.id %} + fun initialize_{{name}}_target_info = LLVMInitialize{{target.id}}TargetInfo + fun initialize_{{name}}_target = LLVMInitialize{{target.id}}Target + fun initialize_{{name}}_target_mc = LLVMInitialize{{target.id}}TargetMC + fun initialize_{{name}}_asm_printer = LLVMInitialize{{target.id}}AsmPrinter + fun initialize_{{name}}_asm_parser = LLVMInitialize{{target.id}}AsmParser {% end %} fun set_module_data_layout = LLVMSetModuleDataLayout(m : ModuleRef, dl : TargetDataRef)