├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.rdoc ├── Rakefile ├── ext └── ruby-llvm-support │ ├── Rakefile │ └── support.cpp ├── lib ├── llvm.rb └── llvm │ ├── analysis.rb │ ├── analysis_ffi.rb │ ├── core.rb │ ├── core │ ├── bitcode.rb │ ├── bitcode_ffi.rb │ ├── builder.rb │ ├── context.rb │ ├── module.rb │ ├── pass_manager.rb │ ├── type.rb │ └── value.rb │ ├── core_ffi.rb │ ├── execution_engine.rb │ ├── execution_engine_ffi.rb │ ├── support.rb │ ├── target.rb │ ├── target_ffi.rb │ ├── transforms │ ├── ipo.rb │ ├── ipo_ffi.rb │ ├── scalar.rb │ └── scalar_ffi.rb │ └── version.rb ├── ruby-llvm.gemspec ├── samples ├── factorial.rb └── fp.rb ├── test ├── array_test.rb ├── basic_block_test.rb ├── basic_test.rb ├── binary_operations_test.rb ├── bitcode_test.rb ├── branch_test.rb ├── call_test.rb ├── comparisons_test.rb ├── conversions_test.rb ├── double_test.rb ├── equality_test.rb ├── generic_value_test.rb ├── instruction_test.rb ├── ipo_test.rb ├── memory_access_test.rb ├── module_test.rb ├── parameter_collection_test.rb ├── phi_test.rb ├── select_test.rb ├── struct_test.rb ├── test_helper.rb ├── type_test.rb └── vector_test.rb └── yardlib └── llvm.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.dylib 3 | *.la 4 | *.lo 5 | *.o 6 | *.rbc 7 | *.so 8 | *~ 9 | .rvmrc 10 | .yardoc 11 | coverage/* 12 | doc/* 13 | .bundle 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | ruby-llvm (3.1.0.beta.1) 5 | ffi (>= 1.0.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | ffi (1.1.5) 11 | ffi_gen (1.1.0) 12 | ffi (>= 1.0.0) 13 | rake (0.9.2) 14 | rcov (0.9.11) 15 | yard (0.7.4) 16 | 17 | PLATFORMS 18 | ruby 19 | 20 | DEPENDENCIES 21 | ffi_gen (>= 1.1.0) 22 | rake 23 | rcov 24 | ruby-llvm! 25 | yard 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2011 Jeremy Voorhis 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the author nor the names of his contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = ruby-llvm has moved to ruby-llvm/ruby-llvm 2 | 3 | This repository has been deprecated in favor of https://github.com/ruby-llvm/ruby-llvm. 4 | 5 | = LLVM 6 | 7 | Author:: Jeremy Voorhis 8 | Contributors:: Evan Phoenix, David Holroyd, Takanori Ishikawa, Ronaldo M. Ferraz, Mac Malone, Chris Wailes, Ary Borenszweig, Richard Musiol, Juan Wajnerman, Steven Farlie 9 | Copyright:: Copyright (c) 2010-2012 Jeremy Voorhis 10 | License:: BSD 3-clause (see LICENSE) 11 | 12 | This package contains Ruby bindings to the LLVM api, enabling users to 13 | make use of LLVM's optimization passes and JIT compilation for 14 | implementing compiled DSLs, callback functions, or fast Ruby method 15 | implementations. 16 | 17 | ruby-llvm has been tested on OS X 10.7 using the following Ruby interpreters: 18 | 19 | * MRI 1.8.7-p174 20 | * MRI 1.9.2-p290 21 | * MRI 1.9.3-preview1 22 | * JRuby 1.4.0 23 | 24 | If using MRI, ffi >= 1.0.7 is recommended (only ffi >= 1.0.0 is required). 25 | 26 | == Requirements 27 | * LLVM 3.0, including libLLVM-3.0 (compile LLVM with --enable-shared). 28 | * In order to ensure the usability of JIT features (i.e. create_jit_compiler), compile LLVM with --enable-jit as well. 29 | 30 | == Homebrew 31 | LLVM can be installed with Homebrew by executing `brew install llvm --shared` 32 | 33 | == About version numbers 34 | 35 | The first two digits of ruby-llvm's version number refer to the required 36 | major and minor version of LLVM. The third digit refers to the ruby-llvm 37 | release itself. Because LLVM's api changes often, this coupling between 38 | LLVM and ruby-llvm versions is useful. 39 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake/testtask' 3 | 4 | begin 5 | require 'rcov/rcovtask' 6 | 7 | Rcov::RcovTask.new do |t| 8 | t.libs << "test" 9 | t.rcov_opts << "--exclude gems" 10 | t.test_files = FileList["test/**/*_test.rb"] 11 | end 12 | rescue LoadError 13 | warn "Proceeding without Rcov. gem install rcov on supported platforms." 14 | end 15 | 16 | begin 17 | require 'yard' 18 | 19 | YARD::Rake::YardocTask.new do |t| 20 | yardlib = File.join(File.dirname(__FILE__), "yardlib/llvm.rb") 21 | t.options = %W[-e #{yardlib} --no-private] 22 | t.files = Dir['lib/**/*.rb'] 23 | end 24 | rescue LoadError 25 | warn "Yard is not installed. `gem install yard` to build documentation." 26 | end 27 | 28 | Rake::TestTask.new do |t| 29 | t.libs << "test" 30 | t.test_files = FileList["test/**/*_test.rb"] 31 | end 32 | 33 | task :generate_ffi do 34 | require 'ffi_gen' 35 | 36 | mappings = { 37 | ["llvm-c/Core.h"] => "core_ffi.rb", 38 | ["llvm-c/Analysis.h"] => "analysis_ffi.rb", 39 | ["llvm-c/ExecutionEngine.h"] => "execution_engine_ffi.rb", 40 | ["llvm-c/Target.h"] => "target_ffi.rb", 41 | ["llvm-c/BitReader.h", "llvm-c/BitWriter.h"] => "core/bitcode_ffi.rb", 42 | ["llvm-c/Transforms/IPO.h"] => "transforms/ipo_ffi.rb", 43 | ["llvm-c/Transforms/Scalar.h"] => "transforms/scalar_ffi.rb", 44 | } 45 | 46 | mappings.each do |headers, ruby_file| 47 | FFIGen.generate( 48 | :module_name => "LLVM::C", 49 | :ffi_lib => "LLVM-3.1", 50 | :headers => headers, 51 | :cflags => `llvm-config --cflags`.split(" "), 52 | :prefixes => ["LLVM"], 53 | :blacklist => ["LLVMGetMDNodeNumOperands", "LLVMGetMDNodeOperand", 54 | "LLVMInitializeAllTargetInfos", "LLVMInitializeAllTargets", "LLVMInitializeNativeTarget"], 55 | :output => "lib/llvm/#{ruby_file}" 56 | ) 57 | end 58 | end 59 | 60 | task :default => [:test] 61 | -------------------------------------------------------------------------------- /ext/ruby-llvm-support/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/clean' 2 | require 'rubygems' 3 | require 'ffi' 4 | 5 | CC = "g++" 6 | LLVM_CONFIG = `llvm-config --cxxflags --ldflags --libs all`.gsub("\n"," ") 7 | OUTPUT = FFI.map_library_name "RubyLLVMSupport-3.1.0" 8 | OUTPUT_DIR = "../../lib" 9 | SRC = "support.cpp" 10 | CLOBBER.include(OUTPUT) 11 | 12 | task :default => [:build] 13 | 14 | desc "Build the shared library" 15 | task :build => [OUTPUT] 16 | 17 | file OUTPUT => [SRC] do 18 | sh "#{CC} -shared #{SRC} #{LLVM_CONFIG} -o #{OUTPUT_DIR}/#{OUTPUT}" 19 | end 20 | -------------------------------------------------------------------------------- /ext/ruby-llvm-support/support.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Extended bindings for LLVM. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | extern "C" { 9 | int LLVMLoadLibraryPermanently(const char* filename) { 10 | return llvm::sys::DynamicLibrary::LoadLibraryPermanently(filename); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /lib/llvm.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'ffi' 3 | 4 | require 'llvm/support' 5 | 6 | module LLVM 7 | # @private 8 | module C 9 | extend ::FFI::Library 10 | ffi_lib ['LLVM-3.1'] 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/llvm/analysis.rb: -------------------------------------------------------------------------------- 1 | require 'llvm' 2 | require 'llvm/core' 3 | require 'llvm/target' 4 | require 'llvm/analysis_ffi' 5 | 6 | module LLVM 7 | class Module 8 | # Verify that the module is valid. 9 | # @return [nil, String] human-readable description of any invalid 10 | # constructs if invalid. 11 | def verify 12 | do_verification(:return_status) 13 | end 14 | 15 | # Verify that a module is valid, and abort the process if not. 16 | # @return [nil] 17 | def verify! 18 | do_verification(:abort_process) 19 | end 20 | 21 | private 22 | def do_verification(action) 23 | result = nil 24 | FFI::MemoryPointer.new(FFI.type_size(:pointer)) do |str| 25 | status = C.verify_module(self, action, str) 26 | result = str.read_string if status == 1 27 | C.dispose_message str.read_pointer 28 | end 29 | result 30 | end 31 | end 32 | 33 | class Function 34 | # Verify that a function is valid. 35 | # @return [true, false] 36 | def verify 37 | do_verification(:return_status) 38 | end 39 | 40 | # Verify that a function is valid, and abort the process if not. 41 | # @return [true, false] 42 | def verify! 43 | do_verification(:abort_process) 44 | end 45 | 46 | private 47 | 48 | def do_verification(action) 49 | C.verify_function(self, action) != 0 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/llvm/analysis_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # This entry is only for documentation and no real method. The FFI::Enum can be accessed via #enum_type(:verifier_failure_action). 18 | # 19 | # === Options: 20 | # :abort_process :: 21 | # 22 | # :print_message :: 23 | # verifier will print to stderr and abort() 24 | # :return_status :: 25 | # verifier will print to stderr and return 1 26 | # 27 | # @method _enum_verifier_failure_action_ 28 | # @return [Symbol] 29 | # @scope class 30 | enum :verifier_failure_action, [ 31 | :abort_process, 0, 32 | :print_message, 1, 33 | :return_status, 2 34 | ] 35 | 36 | # Verifies that a module is valid, taking the specified action if not. 37 | # Optionally returns a human-readable description of any invalid constructs. 38 | # OutMessage must be disposed with LLVMDisposeMessage. 39 | # 40 | # @method verify_module(m, action, out_message) 41 | # @param [FFI::Pointer(ModuleRef)] m 42 | # @param [Symbol from _enum_verifier_failure_action_] action 43 | # @param [FFI::Pointer(**CharS)] out_message 44 | # @return [Integer] 45 | # @scope class 46 | attach_function :verify_module, :LLVMVerifyModule, [:pointer, :verifier_failure_action, :pointer], :int 47 | 48 | # Verifies that a single function is valid, taking the specified action. Useful 49 | # for debugging. 50 | # 51 | # @method verify_function(fn, action) 52 | # @param [FFI::Pointer(ValueRef)] fn 53 | # @param [Symbol from _enum_verifier_failure_action_] action 54 | # @return [Integer] 55 | # @scope class 56 | attach_function :verify_function, :LLVMVerifyFunction, [:pointer, :verifier_failure_action], :int 57 | 58 | # Open up a ghostview window that displays the CFG of the current function. 59 | # Useful for debugging. 60 | # 61 | # @method view_function_cfg(fn) 62 | # @param [FFI::Pointer(ValueRef)] fn 63 | # @return [nil] 64 | # @scope class 65 | attach_function :view_function_cfg, :LLVMViewFunctionCFG, [:pointer], :void 66 | 67 | # (Not documented) 68 | # 69 | # @method view_function_cfg_only(fn) 70 | # @param [FFI::Pointer(ValueRef)] fn 71 | # @return [nil] 72 | # @scope class 73 | attach_function :view_function_cfg_only, :LLVMViewFunctionCFGOnly, [:pointer], :void 74 | 75 | end 76 | -------------------------------------------------------------------------------- /lib/llvm/core.rb: -------------------------------------------------------------------------------- 1 | require 'llvm' 2 | require 'llvm/core_ffi' 3 | 4 | module LLVM 5 | # @private 6 | module C 7 | attach_function :dispose_message, :LLVMDisposeMessage, [:pointer], :void 8 | end 9 | 10 | require 'llvm/core/context' 11 | require 'llvm/core/module' 12 | require 'llvm/core/type' 13 | require 'llvm/core/value' 14 | require 'llvm/core/builder' 15 | require 'llvm/core/pass_manager' 16 | require 'llvm/core/bitcode' 17 | end 18 | -------------------------------------------------------------------------------- /lib/llvm/core/bitcode.rb: -------------------------------------------------------------------------------- 1 | require 'llvm/core/bitcode_ffi' 2 | 3 | module LLVM 4 | class Module 5 | # Parse a module from a memory buffer 6 | # @param [String, LLVM::MemoryBuffer] path_or_memory_buffer 7 | # @return [LLVM::Module] 8 | def self.parse_bitcode(path_or_memory_buffer) 9 | memory_buffer = case path_or_memory_buffer 10 | when MemoryBuffer then path_or_memory_buffer 11 | else MemoryBuffer.from_file(path_or_memory_buffer) 12 | end 13 | FFI::MemoryPointer.new(:pointer) do |mod_ref| 14 | FFI::MemoryPointer.new(:pointer) do |msg_ref| 15 | status = C.parse_bitcode(memory_buffer, mod_ref, msg_ref) 16 | raise msg_ref.get_pointer(0).get_string(0) if status != 0 17 | return from_ptr(mod_ref.get_pointer(0)) 18 | end 19 | end 20 | end 21 | 22 | # Write bitcode to the given path, IO object or file descriptor 23 | # @param [String, IO, Integer] path_or_io Pathname, IO object or file descriptor 24 | # @return [true, false] Success 25 | def write_bitcode(path_or_io) 26 | status = if path_or_io.respond_to?(:path) 27 | C.write_bitcode_to_file(self, path_or_io.path) 28 | elsif path_or_io.respond_to?(:fileno) 29 | C.write_bitcode_to_fd(self, path_or_io.fileno, 0, 1) 30 | elsif path_or_io.kind_of?(Integer) 31 | C.write_bitcode_to_fd(self, path_or_io, 0, 1) 32 | else 33 | C.write_bitcode_to_file(self, path_or_io.to_str) 34 | end 35 | return status == 0 36 | end 37 | end 38 | 39 | # @private 40 | class MemoryBuffer 41 | private_class_method :new 42 | 43 | # @private 44 | def initialize(ptr) 45 | @ptr = ptr 46 | end 47 | 48 | # @private 49 | def to_ptr 50 | @ptr 51 | end 52 | 53 | # Read the contents of a file into a memory buffer 54 | # @param [String] path 55 | # @return [LLVM::MemoryBuffer] 56 | def self.from_file(path) 57 | FFI::MemoryPointer.new(:pointer) do |buf_ref| 58 | FFI::MemoryPointer.new(:pointer) do |msg_ref| 59 | status = C.create_memory_buffer_with_contents_of_file(path.to_str, buf_ref, msg_ref) 60 | raise msg_ref.get_pointer(0).get_string(0) if status != 0 61 | return new(buf_ref.get_pointer(0)) 62 | end 63 | end 64 | end 65 | 66 | # Read STDIN into a memory buffer 67 | # @return [LLVM::MemoryBuffer] 68 | def self.from_stdin 69 | FFI::Buffer.new(:pointer) do |buf_ref| 70 | FFI::Buffer.new(:pointer) do |msg_ref| 71 | status = C.create_memory_buffer_with_stdin(buf_ref, msg_ref) 72 | raise msg_ref.get_pointer(0).get_string(0) if status != 0 73 | return new(buf_ref.get_pointer(0)) 74 | end 75 | end 76 | end 77 | 78 | def dispose 79 | return if @ptr.nil? 80 | C.dispose_memory_buffer(@ptr) 81 | @ptr = nil 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /lib/llvm/core/bitcode_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # @method parse_bitcode(mem_buf, out_module, out_message) 18 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 19 | # @param [FFI::Pointer(*ModuleRef)] out_module 20 | # @param [FFI::Pointer(**CharS)] out_message 21 | # @return [Integer] 22 | # @scope class 23 | attach_function :parse_bitcode, :LLVMParseBitcode, [:pointer, :pointer, :pointer], :int 24 | 25 | # (Not documented) 26 | # 27 | # @method parse_bitcode_in_context(context_ref, mem_buf, out_module, out_message) 28 | # @param [FFI::Pointer(ContextRef)] context_ref 29 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 30 | # @param [FFI::Pointer(*ModuleRef)] out_module 31 | # @param [FFI::Pointer(**CharS)] out_message 32 | # @return [Integer] 33 | # @scope class 34 | attach_function :parse_bitcode_in_context, :LLVMParseBitcodeInContext, [:pointer, :pointer, :pointer, :pointer], :int 35 | 36 | # Reads a module from the specified path, returning via the OutMP parameter 37 | # a module provider which performs lazy deserialization. Returns 0 on success. 38 | # Optionally returns a human-readable error message via OutMessage. 39 | # 40 | # @method get_bitcode_module_in_context(context_ref, mem_buf, out_m, out_message) 41 | # @param [FFI::Pointer(ContextRef)] context_ref 42 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 43 | # @param [FFI::Pointer(*ModuleRef)] out_m 44 | # @param [FFI::Pointer(**CharS)] out_message 45 | # @return [Integer] 46 | # @scope class 47 | attach_function :get_bitcode_module_in_context, :LLVMGetBitcodeModuleInContext, [:pointer, :pointer, :pointer, :pointer], :int 48 | 49 | # (Not documented) 50 | # 51 | # @method get_bitcode_module(mem_buf, out_m, out_message) 52 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 53 | # @param [FFI::Pointer(*ModuleRef)] out_m 54 | # @param [FFI::Pointer(**CharS)] out_message 55 | # @return [Integer] 56 | # @scope class 57 | attach_function :get_bitcode_module, :LLVMGetBitcodeModule, [:pointer, :pointer, :pointer], :int 58 | 59 | # Deprecated: Use LLVMGetBitcodeModuleInContext instead. 60 | # 61 | # @method get_bitcode_module_provider_in_context(context_ref, mem_buf, out_mp, out_message) 62 | # @param [FFI::Pointer(ContextRef)] context_ref 63 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 64 | # @param [FFI::Pointer(*ModuleProviderRef)] out_mp 65 | # @param [FFI::Pointer(**CharS)] out_message 66 | # @return [Integer] 67 | # @scope class 68 | attach_function :get_bitcode_module_provider_in_context, :LLVMGetBitcodeModuleProviderInContext, [:pointer, :pointer, :pointer, :pointer], :int 69 | 70 | # Deprecated: Use LLVMGetBitcodeModule instead. 71 | # 72 | # @method get_bitcode_module_provider(mem_buf, out_mp, out_message) 73 | # @param [FFI::Pointer(MemoryBufferRef)] mem_buf 74 | # @param [FFI::Pointer(*ModuleProviderRef)] out_mp 75 | # @param [FFI::Pointer(**CharS)] out_message 76 | # @return [Integer] 77 | # @scope class 78 | attach_function :get_bitcode_module_provider, :LLVMGetBitcodeModuleProvider, [:pointer, :pointer, :pointer], :int 79 | 80 | # (Not documented) 81 | # 82 | # @method write_bitcode_to_file(m, path) 83 | # @param [FFI::Pointer(ModuleRef)] m 84 | # @param [String] path 85 | # @return [Integer] 86 | # @scope class 87 | attach_function :write_bitcode_to_file, :LLVMWriteBitcodeToFile, [:pointer, :string], :int 88 | 89 | # Writes a module to an open file descriptor. Returns 0 on success. 90 | # 91 | # @method write_bitcode_to_fd(m, fd, should_close, unbuffered) 92 | # @param [FFI::Pointer(ModuleRef)] m 93 | # @param [Integer] fd 94 | # @param [Integer] should_close 95 | # @param [Integer] unbuffered 96 | # @return [Integer] 97 | # @scope class 98 | attach_function :write_bitcode_to_fd, :LLVMWriteBitcodeToFD, [:pointer, :int, :int, :int], :int 99 | 100 | # Deprecated for LLVMWriteBitcodeToFD. Writes a module to an open file 101 | # descriptor. Returns 0 on success. Closes the Handle. 102 | # 103 | # @method write_bitcode_to_file_handle(m, handle) 104 | # @param [FFI::Pointer(ModuleRef)] m 105 | # @param [Integer] handle 106 | # @return [Integer] 107 | # @scope class 108 | attach_function :write_bitcode_to_file_handle, :LLVMWriteBitcodeToFileHandle, [:pointer, :int], :int 109 | 110 | end 111 | -------------------------------------------------------------------------------- /lib/llvm/core/builder.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | class Builder 3 | # Important: Call #dispose to free backend memory after use. 4 | def initialize 5 | @ptr = C.create_builder() 6 | end 7 | 8 | def dispose 9 | return if @ptr.nil? 10 | C.dispose_builder(@ptr) 11 | @ptr = nil 12 | end 13 | 14 | # @private 15 | def to_ptr 16 | @ptr 17 | end 18 | 19 | # Position the builder at the given Instruction within the given BasicBlock. 20 | # @param [LLVM::BasicBlock] 21 | # @param [LLVM::Instruction] 22 | # @return [LLVM::Builder] 23 | def position(block, instruction) 24 | raise "Block must not be nil" if block.nil? 25 | C.position_builder(self, block, instruction) 26 | self 27 | end 28 | 29 | # Positions the builder before the given Instruction. 30 | # @param [LLVM::Instruction] 31 | # @return [LLVM::Builder] 32 | def position_before(instruction) 33 | raise "Instruction must not be nil" if instruction.nil? 34 | C.position_builder_before(self, instruction) 35 | self 36 | end 37 | 38 | # Positions the builder at the end of the given BasicBlock. 39 | # @param [LLVM::BasicBlock] 40 | # @return [LLVM::Builder] 41 | def position_at_end(block) 42 | raise "Block must not be nil" if block.nil? 43 | C.position_builder_at_end(self, block) 44 | self 45 | end 46 | 47 | # The BasicBlock at which the Builder is currently positioned. 48 | # @return [LLVM::BasicBlock] 49 | def insert_block 50 | BasicBlock.from_ptr(C.get_insert_block(self)) 51 | end 52 | 53 | # @return [LLVM::Instruction] 54 | # @LLVMinst ret 55 | def ret_void 56 | Instruction.from_ptr(C.build_ret_void(self)) 57 | end 58 | 59 | # @param [LLVM::Value] val The value to return 60 | # @return [LLVM::Instruction] 61 | # @LLVMinst ret 62 | def ret(val) 63 | Instruction.from_ptr(C.build_ret(self, val)) 64 | end 65 | 66 | # Builds a ret instruction returning multiple values. 67 | # @param [Array] vals 68 | # @return [LLVM::Instruction] 69 | # @LLVMinst ret 70 | def aggregate_ret(*vals) 71 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * vals.size) do |vals_ptr| 72 | vals_ptr.write_array_of_pointer(vals) 73 | Instruction.from_ptr(C.build_aggregate_ret(self, vals_ptr, vals.size)) 74 | end 75 | end 76 | 77 | # Unconditional branching (i.e. goto) 78 | # @param [LLVM::BasicBlock] block Where to jump 79 | # @return [LLVM::Instruction] 80 | # @LLVMinst br 81 | def br(block) 82 | raise "Block must not be nil" if block.nil? 83 | Instruction.from_ptr( 84 | C.build_br(self, block)) 85 | end 86 | 87 | # Conditional branching (i.e. if) 88 | # @param [LLVM::Value] cond The condition 89 | # @param [LLVM::BasicBlock] iftrue Where to jump if condition is true 90 | # @param [LLVM::BasicBlock] iffalse Where to jump if condition is false 91 | # @return [LLVM::Instruction] 92 | # @LLVMinst br 93 | def cond(cond, iftrue, iffalse) 94 | Instruction.from_ptr( 95 | C.build_cond_br(self, cond, iftrue, iffalse)) 96 | end 97 | 98 | # @LLVMinst switch 99 | # @param [LLVM::Value] val The value to switch on 100 | # @param [LLVM::BasicBlock] default The default case 101 | # @param [Hash{LLVM::Value => LLVM::BasicBlock}] cases A Hash mapping 102 | # values to basic blocks. When a value is matched, control will jump 103 | # to the corresponding basic block. 104 | # @return [LLVM::Instruction] 105 | def switch(val, default, cases) 106 | inst = SwitchInst.from_ptr(C.build_switch(self, val, default, cases.size)) 107 | cases.each do |(val, block)| 108 | inst.add_case(val, block) 109 | end 110 | inst 111 | end 112 | 113 | # Invoke a function which may potentially unwind 114 | # @param [LLVM::Function] fun The function to invoke 115 | # @param [Array] args Arguments passed to fun 116 | # @param [LLVM::BasicBlock] normal Where to jump if fun does not unwind 117 | # @param [LLVM::BasicBlock] exception Where to jump if fun unwinds 118 | # @param [String] name Name of the result in LLVM IR 119 | # @return [LLVM::Instruction] The value returned by 'fun', unless an 120 | # unwind instruction occurs 121 | # @LLVMinst invoke 122 | def invoke(fun, args, normal, exception, name = "") 123 | s = args.size 124 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * s) do |args_ptr| 125 | args_ptr.write_array_of_pointer(args) 126 | return Instruction.from_ptr( 127 | C.build_invoke(self, 128 | fun, args_ptr, s, normal, exception, name)) 129 | end 130 | end 131 | 132 | # Builds an unwind Instruction. 133 | # @LLVMinst unwind 134 | def unwind 135 | Instruction.from_ptr(C.LLVMBuildUnwind(self)) 136 | end 137 | 138 | # Generates an instruction with no defined semantics. Can be used to 139 | # provide hints to the optimizer. 140 | # @return [LLVM::Instruction] 141 | # @LLVMinst unreachable 142 | def unreachable 143 | Instruction.from_ptr(C.build_unreachable(self)) 144 | end 145 | 146 | # @param [LLVM::Value] lhs Integer or vector of integers 147 | # @param [LLVM::Value] rhs Integer or vector of integers 148 | # @param [String] name Name of the result in LLVM IR 149 | # @return [LLVM::Instruction] The integer sum of the two operands 150 | # @LLVMinst add 151 | def add(lhs, rhs, name = "") 152 | Instruction.from_ptr(C.build_add(self, lhs, rhs, name)) 153 | end 154 | 155 | # No signed wrap addition. 156 | # @param [LLVM::Value] lhs Integer or vector of integers 157 | # @param [LLVM::Value] rhs Integer or vector of integers 158 | # @param [String] name Name of the result in LLVM IR 159 | # @return [LLVM::Instruction] The integer sum of the two operands 160 | # @LLVMinst add 161 | def nsw_add(lhs, rhs, name = "") 162 | Instruction.from_ptr(C.build_nsw_add(self, lhs, rhs, name)) 163 | end 164 | 165 | # @param [LLVM::Value] lhs Floating point or vector of floating points 166 | # @param [LLVM::Value] rhs Floating point or vector of floating points 167 | # @param [String] name Name of the result in LLVM IR 168 | # @return [LLVM::Instruction] The floating point sum of the two operands 169 | # @LLVMinst fadd 170 | def fadd(lhs, rhs, name = "") 171 | Instruction.from_ptr(C.build_f_add(self, lhs, rhs, name)) 172 | end 173 | 174 | # @param [LLVM::Value] lhs Integer or vector of integers 175 | # @param [LLVM::Value] rhs Integer or vector of integers 176 | # @param [String] name Name of the result in LLVM IR 177 | # @return [LLVM::Instruction] The integer difference of the two operands 178 | # @LLVMinst sub 179 | def sub(lhs, rhs, name = "") 180 | Instruction.from_ptr(C.build_sub(self, lhs, rhs, name)) 181 | end 182 | 183 | # @param [LLVM::Value] lhs Floating point or vector of floating points 184 | # @param [LLVM::Value] rhs Floating point or vector of floating points 185 | # @param [String] name Name of the result in LLVM IR 186 | # @return [LLVM::Instruction] The floating point difference of the two 187 | # operands 188 | # @LLVMinst fsub 189 | def fsub(lhs, rhs, name = "") 190 | Instruction.from_ptr(C.build_f_sub(self, lhs, rhs, name)) 191 | end 192 | 193 | # @param [LLVM::Value] lhs Integer or vector of integers 194 | # @param [LLVM::Value] rhs Integer or vector of integers 195 | # @param [String] name Name of the result in LLVM IR 196 | # @return [LLVM::Instruction] The integer product of the two operands 197 | # @LLVMinst mul 198 | def mul(lhs, rhs, name = "") 199 | Instruction.from_ptr(C.build_mul(self, lhs, rhs, name)) 200 | end 201 | 202 | # @param [LLVM::Value] lhs Floating point or vector of floating points 203 | # @param [LLVM::Value] rhs Floating point or vector of floating points 204 | # @param [String] name Name of the result in LLVM IR 205 | # @return [LLVM::Instruction] The floating point product of the two 206 | # operands 207 | # @LLVMinst fmul 208 | def fmul(lhs, rhs, name = "") 209 | Instruction.from_ptr(C.build_f_mul(self, lhs, rhs, name)) 210 | end 211 | 212 | # Unsigned integer division 213 | # @param [LLVM::Value] lhs Integer or vector of integers 214 | # @param [LLVM::Value] rhs Integer or vector of integers 215 | # @param [String] name Name of the result in LLVM IR 216 | # @return [LLVM::Instruction] The integer quotient of the two operands 217 | # @LLVMinst udiv 218 | def udiv(lhs, rhs, name = "") 219 | Instruction.from_ptr(C.build_u_div(self, lhs, rhs, name)) 220 | end 221 | 222 | # Signed division 223 | # @param [LLVM::Value] lhs Integer or vector of integers 224 | # @param [LLVM::Value] rhs Integer or vector of integers 225 | # @param [String] name Name of the result in LLVM IR 226 | # @return [LLVM::Instruction] The integer quotient of the two operands 227 | # @LLVMinst sdiv 228 | def sdiv(lhs, rhs, name = "") 229 | Instruction.from_ptr(C.build_s_div(self, lhs, rhs, name)) 230 | end 231 | 232 | # Signed exact division 233 | # @param [LLVM::Value] lhs Integer or vector of integers 234 | # @param [LLVM::Value] rhs Integer or vector of integers 235 | # @param [String] name Name of the result in LLVM IR 236 | # @return [LLVM::Instruction] The integer quotient of the two operands 237 | # @LLVMinst sdiv 238 | def exact_sdiv(lhs, rhs, name = "") 239 | Instruction.from_ptr(C.build_exact_s_div(self, lhs, rhs, name)) 240 | end 241 | 242 | # @param [LLVM::Value] lhs Floating point or vector of floating points 243 | # @param [LLVM::Value] rhs Floating point or vector of floating points 244 | # @param [String] name Name of the result in LLVM IR 245 | # @return [LLVM::Instruction] The floating point quotient of the two 246 | # operands 247 | # @LLVMinst fdiv 248 | def fdiv(lhs, rhs, name = "") 249 | Instruction.from_ptr(C.build_f_div(self, lhs, rhs, name)) 250 | end 251 | 252 | # Unsigned remainder 253 | # @param [LLVM::Value] lhs Integer or vector of integers 254 | # @param [LLVM::Value] rhs Integer or vector of integers 255 | # @param [String] name Name of the result in LLVM IR 256 | # @return [LLVM::Instruction] The integer remainder 257 | # @LLVMinst urem 258 | def urem(lhs, rhs, name = "") 259 | Instruction.from_ptr(C.build_u_rem(self, lhs, rhs, name)) 260 | end 261 | 262 | # Signed remainder 263 | # @param [LLVM::Value] lhs Integer or vector of integers 264 | # @param [LLVM::Value] rhs Integer or vector of integers 265 | # @param [String] name Name of the result in LLVM IR 266 | # @return [LLVM::Instruction] The integer remainder 267 | # @LLVMinst srem 268 | def srem(lhs, rhs, name = "") 269 | Instruction.from_ptr(C.build_s_rem(self, lhs, rhs, name)) 270 | end 271 | 272 | # @param [LLVM::Value] lhs Floating point or vector of floating points 273 | # @param [LLVM::Value] rhs Floating point or vector of floating points 274 | # @param [String] name Name of the result in LLVM IR 275 | # @return [LLVM::Instruction] The floating point remainder 276 | # @LLVMinst frem 277 | def frem(lhs, rhs, name = "") 278 | Instruction.from_ptr(C.build_f_rem(self, lhs, rhs, name)) 279 | end 280 | 281 | # @param [LLVM::Value] lhs Integer or vector of integers 282 | # @param [LLVM::Value] rhs Integer or vector of integers 283 | # @param [String] name Name of the result in LLVM IR 284 | # @return [LLVM::Instruction] An integer instruction 285 | # @LLVMinst shl 286 | def shl(lhs, rhs, name = "") 287 | Instruction.from_ptr(C.build_shl(self, lhs, rhs, name)) 288 | end 289 | 290 | # Shifts right with zero fill. 291 | # @param [LLVM::Value] lhs Integer or vector of integers 292 | # @param [LLVM::Value] rhs Integer or vector of integers 293 | # @param [String] name Name of the result in LLVM IR 294 | # @return [LLVM::Instruction] An integer instruction 295 | # @LLVMinst lshr 296 | def lshr(lhs, rhs, name = "") 297 | Instruction.from_ptr(C.build_l_shr(self, lhs, rhs, name)) 298 | end 299 | 300 | # Arithmatic shift right. 301 | # @param [LLVM::Value] lhs Integer or vector of integers 302 | # @param [LLVM::Value] rhs Integer or vector of integers 303 | # @param [String] name Name of the result in LLVM IR 304 | # @return [LLVM::Instruction] An integer instruction 305 | # @LLVMinst ashr 306 | def ashr(lhs, rhs, name = "") 307 | Instruction.from_ptr(C.build_a_shr(self, lhs, rhs, name)) 308 | end 309 | 310 | # @param [LLVM::Value] lhs Integer or vector of integers 311 | # @param [LLVM::Value] rhs Integer or vector of integers 312 | # @param [String] name Name of the result in LLVM IR 313 | # @return [LLVM::Instruction] An integer instruction 314 | # @LLVMinst and 315 | def and(lhs, rhs, name = "") 316 | Instruction.from_ptr(C.build_and(self, lhs, rhs, name)) 317 | end 318 | 319 | # @param [LLVM::Value] lhs Integer or vector of integers 320 | # @param [LLVM::Value] rhs Integer or vector of integers 321 | # @param [String] name Name of the result in LLVM IR 322 | # @return [LLVM::Instruction] An integer instruction 323 | # @LLVMinst or 324 | def or(lhs, rhs, name = "") 325 | Instruction.from_ptr(C.build_or(self, lhs, rhs, name)) 326 | end 327 | 328 | # @param [LLVM::Value] lhs Integer or vector of integers 329 | # @param [LLVM::Value] rhs Integer or vector of integers 330 | # @param [String] name Name of the result in LLVM IR 331 | # @return [LLVM::Instruction] An integer instruction 332 | # @LLVMinst xor 333 | def xor(lhs, rhs, name = "") 334 | Instruction.from_ptr(C.build_xor(self, lhs, rhs, name)) 335 | end 336 | 337 | # Integer negation. Implemented as a shortcut to the equivalent sub 338 | # instruction. 339 | # @param [LLVM::Value] arg Integer or vector of integers 340 | # @param [String] name Name of the result in LLVM IR 341 | # @return [LLVM::Instruction] The negated operand 342 | # @LLVMinst sub 343 | def neg(arg, name = "") 344 | Instruction.from_ptr(C.build_neg(self, arg, name)) 345 | end 346 | 347 | # Boolean negation. 348 | # @param [LLVM::Value] arg Integer or vector of integers 349 | # @param [String] name The name of the result in LLVM IR 350 | # @return [LLVM::Instruction] The negated operand 351 | def not(arg, name = "") 352 | Instruction.from_ptr(C.build_not(self, arg, name)) 353 | end 354 | 355 | # @param [LLVM::Type, #type] ty The type or value whose type 356 | # should be malloced 357 | # @param [String] name The name of the result in LLVM IR 358 | # @return [LLVM::Instruction] A pointer to the malloced bytes 359 | def malloc(ty, name = "") 360 | Instruction.from_ptr(C.build_malloc(self, LLVM::Type(ty), name)) 361 | end 362 | 363 | # @param [LLVM::Type, #type] ty The type or value whose type will be the 364 | # element type of the malloced array 365 | # @param [LLVM::Value] sz Unsigned integer representing size of the array 366 | # @param [String] name The name of the result in LLVM IR 367 | # @return [LLVM::Instruction] A pointer to the malloced array 368 | def array_malloc(ty, sz, name = "") 369 | Instruction.from_ptr(C.build_array_malloc(self, LLVM::Type(ty), sz, name)) 370 | end 371 | 372 | # Stack allocation. 373 | # @param [LLVM::Type, #type] ty The type or value whose type should be 374 | # allocad 375 | # @param [String] name The name of the result in LLVM IR 376 | # @return [LLVM::Instruction] A pointer to the allocad bytes 377 | # @LLVMinst alloca 378 | def alloca(ty, name = "") 379 | Instruction.from_ptr(C.build_alloca(self, LLVM::Type(ty), name)) 380 | end 381 | 382 | # Array stack allocation 383 | # @param [LLVM::Type, #type] ty The type or value whose type will be the 384 | # element type of the allocad array 385 | # @param [LLVM::Value] sz Unsigned integer representing size of the array 386 | # @param [String] name The name of the result in LLVM IR 387 | # @return [LLVM::Instruction] A pointer to the allocad array 388 | # @LLVMinst alloca 389 | def array_alloca(ty, sz, name = "") 390 | Instruction.from_ptr(C.build_array_alloca(self, LLVM::Type(ty), sz, name)) 391 | end 392 | 393 | # @param [LLVM::Value] ptr The pointer to be freed 394 | # @return [LLVM::Instruction] The result of the free instruction 395 | def free(ptr) 396 | Instruction.from_ptr(C.build_free(self, ptr)) 397 | end 398 | 399 | # Load the value of a given pointer 400 | # @param [LLVM::Value] ptr The pointer to be loaded 401 | # @param [String] name The name of the result in LLVM IR 402 | # @return [LLVM::Instruction] The result of the load operation. Represents 403 | # a value of the pointer's type. 404 | # @LLVMinst load 405 | def load(ptr, name = "") 406 | Instruction.from_ptr(C.build_load(self, ptr, name)) 407 | end 408 | 409 | # Store a value at a given pointer 410 | # @param [LLVM::Value] val The value to be stored 411 | # @param [LLVM::Value] ptr A pointer to the same type as val 412 | # @return [LLVM::Instruction] The result of the store operation 413 | # @LLVMinst store 414 | def store(val, ptr) 415 | raise "val must be a Value, got #{val.class.name}" unless Value === val 416 | Instruction.from_ptr(C.build_store(self, val, ptr)) 417 | end 418 | 419 | # Obtain a pointer to the element at the given indices 420 | # @param [LLVM::Value] ptr A pointer to an aggregate value 421 | # @param [Array] indices Ruby array of LLVM::Value representing 422 | # indices into the aggregate 423 | # @param [String] name The name of the result in LLVM IR 424 | # @return [LLVM::Instruction] The resulting pointer 425 | # @LLVMinst gep 426 | # @see http://llvm.org/docs/GetElementPtr.html 427 | def gep(ptr, indices, name = "") 428 | indices = Array(indices) 429 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * indices.size) do |indices_ptr| 430 | indices_ptr.write_array_of_pointer(indices) 431 | return Instruction.from_ptr( 432 | C.build_gep(self, ptr, indices_ptr, indices.size, name)) 433 | end 434 | end 435 | 436 | # Builds a inbounds getelementptr instruction. If the indices are outside 437 | # the allocated pointer the value is undefined. 438 | # @param [LLVM::Value] ptr A pointer to an aggregate value 439 | # @param [Array] indices Ruby array of LLVM::Value representing 440 | # indices into the aggregate 441 | # @param [String] name The name of the result in LLVM IR 442 | # @return [LLVM::Instruction] The resulting pointer 443 | # @LLVMinst gep 444 | # @see http://llvm.org/docs/GetElementPtr.html 445 | def inbounds_gep(ptr, indices, name = "") 446 | indices = Array(indices) 447 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * indices.size) do |indices_ptr| 448 | indices_ptr.write_array_of_pointer(indices) 449 | return Instruction.from_ptr( 450 | C.build_in_bounds_gep(self, ptr, indices_ptr, indices.size, name)) 451 | end 452 | end 453 | 454 | # Builds a struct getelementptr Instruction. 455 | # @param [LLVM::Value] ptr A pointer to a structure 456 | # @param [LLVM::Value] idx Unsigned integer representing the index of a 457 | # structure member 458 | # @param [String] name The name of the result in LLVM IR 459 | # @return [LLVM::Instruction] The resulting pointer 460 | # @LLVMinst gep 461 | # @see http://llvm.org/docs/GetElementPtr.html 462 | def struct_gep(pointer, idx, name = "") 463 | Instruction.from_ptr(C.build_struct_gep(self, pointer, idx, name)) 464 | end 465 | 466 | # Creates a global string initialized to a given value. 467 | # @param [String] string The string used by the initialize 468 | # @param [Name] name Name of the result in LLVM IR 469 | # @return [LLVM::Instruction] Reference to the global string 470 | def global_string(string, name = "") 471 | Instruction.from_ptr(C.build_global_string(self, string, name)) 472 | end 473 | 474 | # Creates a pointer to a global string initialized to a given value. 475 | # @param [String] string The string used by the initializer 476 | # @param [String] name The name of the result in LLVM IR 477 | # @return [LLVM::Instruction] Reference to the global string pointer 478 | def global_string_pointer(string, name = "") 479 | Instruction.from_ptr(C.build_global_string_ptr(self, string, name)) 480 | end 481 | 482 | # Truncates its operand to the given type. The size of the value type must 483 | # be greater than the size of the target type. 484 | # @param [LLVM::Value] val Integer or vector of integers to be truncated 485 | # @param [LLVM::Type, #type] ty Integer or vector of integers of equal size 486 | # to val 487 | # @param [String] name The name of the result in LLVM IR 488 | # @return [LLVM::Instruction] The truncated value 489 | # @LLVMinst trunc 490 | def trunc(val, ty, name = "") 491 | Instruction.from_ptr(C.build_trunc(self, val, LLVM::Type(ty), name)) 492 | end 493 | 494 | # Zero extends its operand to the given type. The size of the value type 495 | # must be greater than the size of the target type. 496 | # @param [LLVM::Value] val Integer or vector of integers to be extended 497 | # @param [LLVM::Type, #type] ty Integer or vector of integer type of 498 | # greater size than val 499 | # @param [String] name The name of the result in LLVM IR 500 | # @return [LLVM::Instruction] The extended value 501 | # @LLVMinst zext 502 | def zext(val, ty, name = "") 503 | Instruction.from_ptr(C.build_z_ext(self, val, LLVM::Type(ty), name)) 504 | end 505 | 506 | # Sign extension by copying the sign bit (highest order bit) of the value 507 | # until it reaches the bit size of the given type. 508 | # @param [LLVM::Value] val Integer or vector of integers to be extended 509 | # @param [LLVM::Type] ty Integer or vector of integer type of greater size 510 | # than the size of val 511 | # @param [String] name The name of the result in LLVM IR 512 | # @return [LLVM::Instruction] The extended value 513 | # @LLVMinst sext 514 | def sext(val, ty, name = "") 515 | Instruction.from_ptr(C.build_s_ext(self, val, LLVM::Type(ty), name)) 516 | end 517 | 518 | # Convert a floating point to an unsigned integer 519 | # @param [LLVM::Value] val Floating point or vector of floating points to 520 | # convert 521 | # @param [LLVM::Type, #type] ty Integer or vector of integer target type 522 | # @param [String] name The name of the result in LLVM IR 523 | # @return [LLVM::Instruction] The converted value 524 | # @LLVMinst fptoui 525 | def fp2ui(val, ty, name = "") 526 | Instruction.from_ptr(C.build_fp_to_ui(self, val, LLVM::Type(ty), name)) 527 | end 528 | 529 | # Convert a floating point to a signed integer 530 | # @param [LLVM::Value] val Floating point or vector of floating points to 531 | # convert 532 | # @param [LLVM::Type, #type] ty Integer or vector of integer target type 533 | # @param [String] name The name of the result in LLVM IR 534 | # @return [LLVM::Instruction] The converted value 535 | # @LLVMinst fptosi 536 | def fp2si(val, ty, name = "") 537 | Instruction.from_ptr(C.build_fp_to_si(self, val, LLVM::Type(ty), name)) 538 | end 539 | 540 | # Convert an unsigned integer to a floating point 541 | # @param [LLVM::Value] val Unsigned integer or vector of unsigned integer 542 | # to convert 543 | # @param [LLVM::Type, #type] ty Floating point or vector of floating point 544 | # target type 545 | # @param [String] name The name of the result in LLVM IR 546 | # @return [LLVM::Instruction] The converted value 547 | # @LLVMinst uitofp 548 | def ui2fp(val, ty, name = "") 549 | Instruction.from_ptr(C.build_ui_to_fp(self, val, LLVM::Type(ty), name)) 550 | end 551 | 552 | # Convert a signed integer to a floating point 553 | # @param [LLVM::Value] val Signed integer or vector of signed integer 554 | # to convert 555 | # @param [LLVM::Type, #type] ty Floating point or vector of floating point 556 | # target type 557 | # @param [String] name The name of the result in LLVM IR 558 | # @return [LLVM::Instruction] The converted value 559 | # @LLVMinst sitofp 560 | def si2fp(val, ty, name = "") 561 | Instruction.from_ptr(C.build_si_to_fp(self, val, LLVM::Type(ty), name)) 562 | end 563 | 564 | # Truncate a floating point value 565 | # @param [LLVM::Value] val Floating point or vector of floating point 566 | # @param [LLVM::Type, #type] ty Floating point or vector of floating point 567 | # type of lesser size than val's type 568 | # @param [String] name The name of the result in LLVM IR 569 | # @return [LLVM::Instruction] The truncated value 570 | # @LLVMinst fptrunc 571 | def fp_trunc(val, ty, name = "") 572 | Instruction.from_ptr(C.build_fp_trunc(self, val, LLVM::Type(ty), name)) 573 | end 574 | 575 | # Extend a floating point value 576 | # @param [LLVM::Value] val Floating point or vector of floating point 577 | # @param [LLVM::Type, #type] ty Floating point or vector of floating point 578 | # type of greater size than val's type 579 | # @param [String] name The name of the result in LLVM IR 580 | # @return [LLVM::Instruction] The extended value 581 | # @LLVMinst fpext 582 | def fp_ext(val, ty, name = "") 583 | Instruction.from_ptr(C.build_fp_ext(self, val, LLVM::Type(ty), name)) 584 | end 585 | 586 | # Cast a pointer to an int. Useful for pointer arithmetic. 587 | # @param [LLVM::Value] val A pointer 588 | # @param [LLVM::Type, #type] ty An integer type 589 | # @param [String] name The name of the result in LLVM IR 590 | # @return [LLVM::Instruction] An integer of the given type representing 591 | # the pointer's address 592 | # @LLVMinst ptrtoint 593 | def ptr2int(val, ty, name = "") 594 | Instruction.from_ptr(C.build_ptr_to_int(self, val, LLVM::Type(ty), name)) 595 | end 596 | 597 | # Cast an int to a pointer 598 | # @param [LLVM::Value] val An integer value 599 | # @param [LLVM::Type, #ty] ty A pointer type 600 | # @param [String] name The name of the result in LLVM IR 601 | # @return [LLVM::Instruction] A pointer of the given type and the address 602 | # held in val 603 | # @LLVMinst inttoptr 604 | def int2ptr(val, ty, name = "") 605 | Instruction.from_ptr(C.build_int_to_ptr(self, val, LLVM::Type(ty), name)) 606 | end 607 | 608 | # Cast a value to the given type without changing any bits 609 | # @param [LLVM::Value] val The value to cast 610 | # @param [LLVM::Type, #ty] ty The target type 611 | # @param [String] name The name of the result in LLVM IR 612 | # @return [LLVM::Instruction] A value of the target type 613 | # @LLVMinst bitcast 614 | def bit_cast(val, ty, name = "") 615 | Instruction.from_ptr(C.build_bit_cast(self, val, LLVM::Type(ty), name)) 616 | end 617 | 618 | # @param [LLVM::Value] val 619 | # @param [LLVM::Type, #ty] ty 620 | # @param [String] name The name of the result in LLVM IR 621 | # @return [LLVM::Instruction] 622 | # @LLVMinst zext 623 | # @LLVMinst bitcast 624 | def zext_or_bit_cast(val, ty, name = "") 625 | Instruction.from_ptr(C.build_z_ext_or_bit_cast(self, val, LLVM::Type(ty), name)) 626 | end 627 | 628 | # @param [LLVM::Value] val 629 | # @param [LLVM::Type, #ty] ty 630 | # @param [String] name The name of the result in LLVM IR 631 | # @return [LLVM::Instruction] 632 | # @LLVMinst sext 633 | # @LLVMinst bitcast 634 | def sext_or_bit_cast(val, ty, name = "") 635 | Instruction.from_ptr(C.build_s_ext_or_bit_cast(self, val, LLVM::Type(ty), name)) 636 | end 637 | 638 | # @param [LLVM::Value] val 639 | # @param [LLVM::Type, #ty] ty 640 | # @param [String] name The name of the result in LLVM IR 641 | # @return [LLVM::Instruction] 642 | # @LLVMinst trunc 643 | # @LLVMinst bitcast 644 | def trunc_or_bit_cast(val, ty, name = "") 645 | Instruction.from_ptr(C.build_trunc_or_bit_cast(self, val, LLVM::Type(ty), name)) 646 | end 647 | 648 | # @param [LLVM::Value] val 649 | # @param [LLVM::Type, #ty] ty 650 | # @param [String] name The name of the result in LLVM IR 651 | # @return [LLVM::Instruction] 652 | def pointer_cast(val, ty, name = "") 653 | Instruction.from_ptr(C.build_pointer_cast(self, val, LLVM::Type(ty), name)) 654 | end 655 | 656 | # @param [LLVM::Value] val 657 | # @param [LLVM::Type, #ty] ty 658 | # @param [String] name The name of the result in LLVM IR 659 | # @return [LLVM::Instruction] 660 | def int_cast(val, ty, name = "") 661 | Instruction.from_ptr(C.build_int_cast(self, val, LLVM::Type(ty), name)) 662 | end 663 | 664 | # @param [LLVM::Value] val 665 | # @param [LLVM::Type, #ty] ty 666 | # @param [String] name The name of the result in LLVM IR 667 | # @return [LLVM::Instruction] 668 | def fp_cast(val, ty, name = "") 669 | Instruction.from_ptr(C.build_fp_cast(self, val, LLVM::Type(ty), name)) 670 | end 671 | 672 | # Builds an icmp Instruction. Compares lhs to rhs (Instructions) 673 | # using the given symbol predicate (pred): 674 | # :eq - equal to 675 | # :ne - not equal to 676 | # :ugt - unsigned greater than 677 | # :uge - unsigned greater than or equal to 678 | # :ult - unsigned less than 679 | # :ule - unsigned less than or equal to 680 | # :sgt - signed greater than 681 | # :sge - signed greater than or equal to 682 | # :slt - signed less than 683 | # :sle - signed less than or equal to 684 | # @param [Symbol] pred A predicate 685 | # @param [LLVM::Value] lhs The left hand side of the comparison, of integer 686 | # or pointer type 687 | # @param [LLVM::Value] rhs The right hand side of the comparison, of the 688 | # same type as lhs 689 | # @param [String] name The name of the result in LLVM IR 690 | # @return [LLVM::Instruction] A boolean represented as i1 691 | # @LLVMinst icmp 692 | def icmp(pred, lhs, rhs, name = "") 693 | Instruction.from_ptr(C.build_i_cmp(self, pred, lhs, rhs, name)) 694 | end 695 | 696 | # Builds an fcmp Instruction. Compares lhs to rhs (Instructions) as Reals 697 | # using the given symbol predicate (pred): 698 | # :ord - ordered 699 | # :uno - unordered: isnan(X) | isnan(Y) 700 | # :oeq - ordered and equal to 701 | # :oeq - unordered and equal to 702 | # :one - ordered and not equal to 703 | # :one - unordered and not equal to 704 | # :ogt - ordered and greater than 705 | # :uge - unordered and greater than or equal to 706 | # :olt - ordered and less than 707 | # :ule - unordered and less than or equal to 708 | # :oge - ordered and greater than or equal to 709 | # :sge - unordered and greater than or equal to 710 | # :ole - ordered and less than or equal to 711 | # :sle - unordered and less than or equal to 712 | # :true - always true and folded 713 | # :false - always false and folded 714 | # @param [Symbol] pred A predicate 715 | # @param [LLVM::Value] lhs The left hand side of the comparison, of 716 | # floating point type 717 | # @param [LLVM::Value] rhs The right hand side of the comparison, of 718 | # the same type as lhs 719 | # @param [String] name The name of the result in LLVM IR 720 | # @return [LLVM::Instruction] A boolean represented as i1 721 | # @LLVMinst fcmp 722 | def fcmp(pred, lhs, rhs, name = "") 723 | Instruction.from_ptr(C.build_f_cmp(self, pred, lhs, rhs, name)) 724 | end 725 | 726 | # Build a Phi node of the given type with the given incoming branches 727 | # @param [LLVM::Type] ty Specifies the result type 728 | # @param [Hash{LLVM::BasicBlock => LLVM::Value}] incoming A hash mapping 729 | # basic blocks to a corresponding value. If the phi node is jumped to 730 | # from a given basic block, the phi instruction takes on its 731 | # corresponding value. 732 | # @param [String] name The name of the result in LLVM IR 733 | # @return [LLVM::Instruction] The phi node 734 | # @LLVMinst phi 735 | def phi(ty, incoming, name = "") 736 | 737 | phi = Phi.from_ptr(C.build_phi(self, LLVM::Type(ty), name)) 738 | phi.add_incoming(incoming) 739 | phi 740 | end 741 | 742 | # Builds a call Instruction. Calls the given Function with the given 743 | # args (Instructions). 744 | # @param [LLVM::Function] fun 745 | # @param [Array] args 746 | # @param [LLVM::Instruction] 747 | # @LLVMinst call 748 | def call(fun, *args) 749 | raise "No fun" if fun.nil? 750 | if args.last.kind_of? String 751 | name = args.pop 752 | else 753 | name = "" 754 | end 755 | 756 | args_ptr = FFI::MemoryPointer.new(FFI.type_size(:pointer) * args.size) 757 | args_ptr.write_array_of_pointer(args) 758 | CallInst.from_ptr(C.build_call(self, fun, args_ptr, args.size, name)) 759 | end 760 | 761 | # Return a value based on a condition. This differs from 'cond' in that 762 | # its operands are values rather than basic blocks. As a consequence, both 763 | # arguments must be evaluated. 764 | # @param [LLVM::Value] _if An i1 or a vector of i1 765 | # @param [LLVM::Value] _then A value or vector of the same arity as _if 766 | # @param [LLVM::Value] _else A value or vector of values of the same arity 767 | # as _if, and of the same type as _then 768 | # @param [String] name The name of the result in LLVM IR 769 | # @return [LLVM::Instruction] An instruction representing either _then or 770 | # _else 771 | # @LLVMinst select 772 | def select(_if, _then, _else, name = "") 773 | Instruction.from_ptr(C.build_select(self, _if, _then, _else, name)) 774 | end 775 | 776 | # Extract an element from a vector 777 | # @param [LLVM::Value] vector The vector from which to extract a value 778 | # @param [LLVM::Value] idx The index of the element to extract, an 779 | # unsigned integer 780 | # @param [String] name The value of the result in LLVM IR 781 | # @return [LLVM::Instruction] The extracted element 782 | # @LLVMinst extractelement 783 | def extract_element(vector, idx, name = "") 784 | Instruction.from_ptr(C.build_extract_element(self, vector, idx, name)) 785 | end 786 | 787 | # Insert an element into a vector 788 | # @param [LLVM::Value] vector The vector into which to insert the element 789 | # @param [LLVM::Value] elem The element to be inserted into the vector 790 | # @param [LLVM::Value] idx The index at which to insert the element 791 | # @param [String] name The name of the result in LLVM IR 792 | # @return [LLVM::Instruction] A vector the same type as 'vector' 793 | # @LLVMinst insertelement 794 | def insert_element(vector, elem, idx, name = "") 795 | Instruction.from_ptr(C.build_insert_element(self, vector, elem, idx, name)) 796 | end 797 | 798 | # Shuffle two vectors according to a given mask 799 | # @param [LLVM::Value] vec1 A vector 800 | # @param [LLVM::Value] vec2 A vector of the same type and arity as vec1 801 | # @param [LLVM::Value] mask A vector of i1 of the same arity as vec1 and 802 | # vec2 803 | # @param [String] name The name of the result in LLVM IR 804 | # @return [LLVM::Instruction] The shuffled vector 805 | # @LLVMinst shufflevector 806 | def shuffle_vector(vec1, vec2, mask, name = "") 807 | Instruction.from_ptr(C.build_shuffle_vector(self, vec1, vec2, mask, name)) 808 | end 809 | 810 | # Extract the value of a member field from an aggregate value 811 | # @param [LLVM::Value] aggregate An aggregate value 812 | # @param [LLVM::Value] idx The index of the member to extract 813 | # @param [String] name The name of the result in LLVM IR 814 | # @return [LLVM::Instruction] The extracted value 815 | # @LLVMinst extractvalue 816 | def extract_value(aggregate, idx, name = "") 817 | Instruction.from_ptr(C.build_extract_value(self, aggregate, idx, name)) 818 | end 819 | 820 | # Insert a value into an aggregate value's member field 821 | # @param [LLVM::Value] aggregate An aggregate value 822 | # @param [LLVM::Value] elem The value to insert into 'aggregate' 823 | # @param [LLVM::Value] idx The index at which to insert the value 824 | # @param [String] name The name of the result in LLVM IR 825 | # @return [LLVM::Instruction] An aggregate value of the same type as 'aggregate' 826 | # @LLVMinst insertvalue 827 | def insert_value(aggregate, elem, idx, name = "") 828 | Instruction.from_ptr(C.build_insert_value(self, aggregate, elem, idx, name)) 829 | end 830 | 831 | # Check if a value is null 832 | # @param [LLVM::Value] val The value to check 833 | # @param [String] name The name of the result in LLVM IR 834 | # @return [LLVM::Instruction] An i1 835 | def is_null(val, name = "") 836 | Instruction.from_ptr(C.build_is_null(self, val, name)) 837 | end 838 | 839 | # Check if a value is not null 840 | # @param [LLVM::Value] val The value to check 841 | # @param [String] name The name of the result in LLVM IR 842 | # @return [LLVM::Instruction] An i1 843 | def is_not_null(val, name = "") 844 | Instruction.from_ptr(C.build_is_not_null(self, val, name)) 845 | end 846 | 847 | # Calculate the difference between two pointers 848 | # @param [LLVM::Value] lhs A pointer 849 | # @param [LLVM::Value] rhs A pointer 850 | # @param [String] name The name of the result in LLVM IR 851 | # @return [LLVM::Instruction] The integer difference between the two 852 | # pointers 853 | def ptr_diff(lhs, rhs, name = "") 854 | Instruction.from_ptr(C.build_ptr_diff(lhs, rhs, name)) 855 | end 856 | end 857 | end 858 | -------------------------------------------------------------------------------- /lib/llvm/core/context.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | class Context 3 | def initialize(ptr = nil) 4 | @ptr = ptr || C.context_create() 5 | end 6 | 7 | # @private 8 | def to_ptr 9 | @ptr 10 | end 11 | 12 | # Obtains a reference to the global Context. 13 | def self.global 14 | new(C.get_global_context()) 15 | end 16 | 17 | # Diposes the Context. 18 | def dispose 19 | return if @ptr.nil? 20 | C.context_dispose(@ptr) 21 | @ptr = nil 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/llvm/core/module.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | class Module 3 | # @private 4 | def self.from_ptr(ptr) 5 | return if ptr.null? 6 | mod = allocate 7 | mod.instance_variable_set(:@ptr, ptr) 8 | mod 9 | end 10 | 11 | # Important: Call #dispose to free backend memory after use, but not when using JITCompiler with this module. 12 | def initialize(name) 13 | @ptr = C.module_create_with_name(name) 14 | end 15 | 16 | def dispose 17 | return if @ptr.nil? 18 | C.dispose_module(@ptr) 19 | @ptr = nil 20 | end 21 | 22 | # @private 23 | def to_ptr 24 | @ptr 25 | end 26 | 27 | # Checks if the module is equal to other. 28 | def ==(other) 29 | case other 30 | when LLVM::Module 31 | @ptr == other.to_ptr 32 | else 33 | false 34 | end 35 | end 36 | 37 | # Checks if the module is equal to other. 38 | def eql?(other) 39 | other.instance_of?(self.class) && self == other 40 | end 41 | 42 | # Returns a TypeCollection of all the Types in the module. 43 | def types 44 | @types ||= TypeCollection.new(self) 45 | end 46 | 47 | class TypeCollection 48 | def initialize(mod) 49 | @module = mod 50 | end 51 | 52 | # Returns the Type with the given name (symbol or string). 53 | def named(name) 54 | Type.from_ptr(C.get_type_by_name(@module, name.to_s), nil) 55 | end 56 | 57 | # Returns the Type with the a name equal to key (symbol or string). 58 | def [](key) 59 | named(key) 60 | end 61 | 62 | # Adds the given Type to the collection with a name equal to key (symbol or string). 63 | def []=(key, type) 64 | add(key, type) 65 | end 66 | end 67 | 68 | # Returns an Enumerable of all the GlobalVariables in the module. 69 | def globals 70 | @globals ||= GlobalCollection.new(self) 71 | end 72 | 73 | class GlobalCollection 74 | include Enumerable 75 | 76 | def initialize(mod) 77 | @module = mod 78 | end 79 | 80 | # Adds a GlobalVariable with the given type and name to the collection (symbol or string). 81 | def add(ty, name) 82 | GlobalVariable.from_ptr(C.add_global(@module, LLVM::Type(ty), name.to_s)) 83 | end 84 | 85 | # Returns the GlobalVariable with the given name (symbol or string). 86 | def named(name) 87 | GlobalValue.from_ptr(C.get_named_global(@module, name.to_s)) 88 | end 89 | 90 | # Returns the first GlobalVariable in the collection. 91 | def first 92 | GlobalValue.from_ptr(C.get_first_global(@module)) 93 | end 94 | 95 | # Returns the last GlobalVariable in the collection. 96 | def last 97 | GlobalValue.from_ptr(C.get_last_global(@module)) 98 | end 99 | 100 | # Returns the next GlobalVariable in the collection after global. 101 | def next(global) 102 | GlobalValue.from_ptr(C.get_next_global(global)) 103 | end 104 | 105 | # Returns the previous GlobalVariable in the collection before global. 106 | def previous(global) 107 | GlobalValue.from_ptr(C.get_previous_global(global)) 108 | end 109 | 110 | # Deletes the GlobalVariable from the collection. 111 | def delete(global) 112 | C.delete_global(global) 113 | end 114 | 115 | # Returns the GlobalVariable with a name equal to key (symbol or string) or at key (integer). 116 | def [](key) 117 | case key 118 | when String, Symbol then named(key) 119 | when Integer then 120 | i = 0 121 | g = first 122 | until i >= key || g.nil? 123 | g = self.next(g) 124 | i += 1 125 | end 126 | g 127 | end 128 | end 129 | 130 | # Iterates through each GlobalVariable in the collection. 131 | def each 132 | g = first 133 | until g.nil? 134 | yield g 135 | g = self.next(g) 136 | end 137 | end 138 | end 139 | 140 | # Returns a FunctionCollection of all the Functions in the module. 141 | def functions 142 | @functions ||= FunctionCollection.new(self) 143 | end 144 | 145 | class FunctionCollection 146 | include Enumerable 147 | 148 | def initialize(mod) 149 | @module = mod 150 | end 151 | 152 | # Adds a Function with the given name (symbol or string) and args (Types). 153 | def add(name, *args) 154 | if args.first.kind_of? FunctionType 155 | type = args.first 156 | else 157 | type = Type.function(*args) 158 | end 159 | function = Function.from_ptr(C.add_function(@module, name.to_s, type)) 160 | 161 | if block_given? 162 | params = (0...function.params.size).map { |i| function.params[i] } 163 | yield function, *params 164 | end 165 | 166 | function 167 | end 168 | 169 | # Returns the Function with the given name (symbol or string). 170 | def named(name) 171 | Function.from_ptr(C.get_named_function(@module, name.to_s)) 172 | end 173 | 174 | # Returns the first Function in the collection. 175 | def first 176 | Function.from_ptr(C.get_first_function(@module)) 177 | end 178 | 179 | # Returns the last Function in the collection. 180 | def last 181 | Function.from_ptr(C.get_last_function(@module)) 182 | end 183 | 184 | # Returns the next Function in the collection after function. 185 | def next(function) 186 | Function.from_ptr(C.get_next_function(function)) 187 | end 188 | 189 | # Returns the previous Function in the collection before function. 190 | def previous(function) 191 | Function.from_ptr(C.get_previous_function(function)) 192 | end 193 | 194 | # Deletes the Function from the collection. 195 | def delete(function) 196 | C.delete_function(function) 197 | end 198 | 199 | # Returns the Function with a name equal to key (symbol or string) or at key (integer). 200 | def [](key) 201 | case key 202 | when String, Symbol then named(key) 203 | when Integer 204 | i = 0 205 | f = first 206 | until i >= key || f.nil? 207 | f = self.next(f) 208 | i += 1 209 | end 210 | f 211 | end 212 | end 213 | 214 | # Iterates through each Function in the collection. 215 | def each 216 | f = first 217 | until f.nil? 218 | yield f 219 | f = self.next(f) 220 | end 221 | end 222 | end 223 | 224 | # Print the module's IR to stdout. 225 | def dump 226 | C.dump_module(self) 227 | end 228 | end 229 | end 230 | -------------------------------------------------------------------------------- /lib/llvm/core/pass_manager.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | # The PassManager runs a queue of passes on a module. See 3 | # http://llvm.org/docs/Passes.html for the list of available passes. 4 | class PassManager 5 | # Creates a new pass manager on the given ExecutionEngine. 6 | def initialize(execution_engine) 7 | ptr = C.create_pass_manager() 8 | C.add_target_data( 9 | C.get_execution_engine_target_data(execution_engine), ptr) 10 | @ptr = ptr 11 | 12 | do_initialization 13 | end 14 | 15 | # @private 16 | def to_ptr 17 | @ptr 18 | end 19 | 20 | # Append a pass to the pass queue. 21 | # @param [Symbol] 22 | # @return [LLVM::PassManager] 23 | def <<(name) 24 | send(:"#{name}!") 25 | self 26 | end 27 | 28 | # Run the pass queue on the given module. 29 | # @param [LLVM::Module] 30 | # @return [true, false] Indicates whether the module was modified. 31 | def run(mod) 32 | C.run_pass_manager(self, mod) != 0 33 | end 34 | 35 | # Disposes the pass manager. 36 | def dispose 37 | return if @ptr.nil? 38 | do_finalization 39 | C.dispose_pass_manager(@ptr) 40 | @ptr = nil 41 | end 42 | 43 | protected 44 | 45 | def do_initialization 46 | end 47 | 48 | def do_finalization 49 | end 50 | end 51 | 52 | class FunctionPassManager < PassManager 53 | # Creates a new pass manager on the given ExecutionEngine and Module. 54 | def initialize(execution_engine, mod) 55 | ptr = C.create_function_pass_manager_for_module(mod) 56 | C.add_target_data( 57 | C.get_execution_engine_target_data(execution_engine), ptr) 58 | @ptr = ptr 59 | end 60 | 61 | # Run the pass queue on the given function. 62 | # @param [LLVM::Function] 63 | # @return [true, false] indicates whether the function was modified. 64 | def run(fn) 65 | C.run_function_pass_manager(self, fn) != 0 66 | end 67 | 68 | protected 69 | 70 | def do_initialization 71 | C.initialize_function_pass_manager(self) != 0 72 | end 73 | 74 | def do_finalization 75 | C.finalize_function_pass_manager(self) != 0 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /lib/llvm/core/type.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | class Type 3 | # @private 4 | def to_ptr 5 | @ptr 6 | end 7 | 8 | # LLVM's represents types uniquely, and supports pointer equality. 9 | def ==(type) 10 | case type 11 | when LLVM::Type 12 | @ptr == type.to_ptr 13 | else 14 | false 15 | end 16 | end 17 | 18 | def hash 19 | @ptr.address.hash 20 | end 21 | 22 | # Checks if the type is equal to other. 23 | def eql?(other) 24 | other.instance_of?(self.class) && self == other 25 | end 26 | 27 | # Returns a symbol representation of the types kind (ex. :pointer, :vector, :array.) 28 | def kind 29 | @kind 30 | end 31 | 32 | # Returns the size of the type. 33 | def size 34 | LLVM::Int64.from_ptr(C.size_of(self)) 35 | end 36 | 37 | def align 38 | LLVM::Int64.from_ptr(C.align_of(self)) 39 | end 40 | 41 | # Returns the type of this types elements (works only for Pointer, Vector, and Array types.) 42 | def element_type 43 | case self.kind 44 | when :pointer, :vector, :array 45 | Type.from_ptr(C.get_element_type(self), nil) 46 | end 47 | end 48 | 49 | # Returns a null pointer ConstantExpr of this type. 50 | def null_pointer 51 | ConstantExpr.from_ptr(C.const_pointer_null(self)) 52 | end 53 | 54 | # Returns a null ConstantExpr of this type. 55 | def null 56 | ConstantExpr.from_ptr(C.const_null(self)) 57 | end 58 | 59 | # Creates a pointer type with this type and the given address space. 60 | def pointer(address_space = 0) 61 | Type.pointer(self, address_space) 62 | end 63 | 64 | # @private 65 | def self.from_ptr(ptr, kind) 66 | return if ptr.null? 67 | kind ||= C.get_type_kind(ptr) 68 | ty = case kind 69 | when :integer then IntType.allocate 70 | when :function then FunctionType.allocate 71 | when :struct then StructType.allocate 72 | else allocate 73 | end 74 | ty.instance_variable_set(:@ptr, ptr) 75 | ty.instance_variable_set(:@kind, kind) 76 | ty 77 | end 78 | 79 | # Creates an array type of Type with the given size. 80 | def self.array(ty, sz = 0) 81 | from_ptr(C.array_type(LLVM::Type(ty), sz), :array) 82 | end 83 | 84 | # Creates the pointer type of Type with the given address space. 85 | def self.pointer(ty, address_space = 0) 86 | from_ptr(C.pointer_type(LLVM::Type(ty), address_space), :pointer) 87 | end 88 | 89 | # Creates a vector type of Type with the given element count. 90 | def self.vector(ty, element_count) 91 | from_ptr(C.vector_type(LLVM::Type(ty), element_count), :vector) 92 | end 93 | 94 | # Creates a function type. Takes an array of argument Types and the result Type. The only option is :varargs, 95 | # which when set to true makes the function type take a variable number of args. 96 | def self.function(arg_types, result_type, options = {}) 97 | arg_types.map! { |ty| LLVM::Type(ty) } 98 | arg_types_ptr = FFI::MemoryPointer.new(FFI.type_size(:pointer) * arg_types.size) 99 | arg_types_ptr.write_array_of_pointer(arg_types) 100 | from_ptr(C.function_type(LLVM::Type(result_type), arg_types_ptr, arg_types.size, options[:varargs] ? 1 : 0), :function) 101 | end 102 | 103 | # Creates a struct type with the given array of element types. 104 | def self.struct(elt_types, is_packed, name = nil) 105 | elt_types.map! { |ty| LLVM::Type(ty) } 106 | elt_types_ptr = FFI::MemoryPointer.new(FFI.type_size(:pointer) * elt_types.size) 107 | elt_types_ptr.write_array_of_pointer(elt_types) 108 | if name 109 | struct = from_ptr(C.struct_create_named(Context.global, name), :struct) 110 | C.struct_set_body(struct, elt_types_ptr, elt_types.size, is_packed ? 1 : 0) unless elt_types.empty? 111 | struct 112 | else 113 | from_ptr(C.struct_type(elt_types_ptr, elt_types.size, is_packed ? 1 : 0), :struct) 114 | end 115 | end 116 | 117 | # Creates a void type. 118 | def self.void 119 | from_ptr(C.void_type, :void) 120 | end 121 | 122 | def self.rec 123 | h = opaque 124 | ty = yield h 125 | h.refine(ty) 126 | ty 127 | end 128 | end 129 | 130 | class IntType < Type 131 | def width 132 | C.get_int_type_width(self) 133 | end 134 | end 135 | 136 | class FunctionType < Type 137 | def return_type 138 | Type.from_ptr(C.get_return_type(self), nil) 139 | end 140 | 141 | def argument_types 142 | size = C.count_param_types(self) 143 | result = nil 144 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * size) do |types_ptr| 145 | C.LLVMGetParamTypes(self, types_ptr) 146 | result = types_ptr.read_array_of_pointer(size) 147 | end 148 | result.map{ |p| Type.from_ptr(p) } 149 | end 150 | 151 | def vararg? 152 | C.LLVMIsFunctionVarArg(self) 153 | end 154 | end 155 | 156 | class StructType < Type 157 | # Returns the name of the struct. 158 | def name 159 | C.get_struct_name(self) 160 | end 161 | 162 | # Returns the element types of the struct. 163 | def element_types 164 | count = C.count_struct_element_types(self) 165 | elt_types = nil 166 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * count) do |types_ptr| 167 | C.get_struct_element_types(self, types_ptr) 168 | elt_types = types_ptr.read_array_of_pointer(count).map { |type_ptr| Type.from_ptr(type_ptr, nil) } 169 | end 170 | elt_types 171 | end 172 | 173 | # Sets the struct body. 174 | def element_types=(elt_types) 175 | elt_types.map! { |ty| LLVM::Type(ty) } 176 | elt_types_ptr = FFI::MemoryPointer.new(FFI.type_size(:pointer) * elt_types.size) 177 | elt_types_ptr.write_array_of_pointer(elt_types) 178 | C.struct_set_body(self, elt_types_ptr, elt_types.size, 0) 179 | end 180 | end 181 | 182 | module_function 183 | 184 | # Creates a Type from the given object. 185 | def Type(ty) 186 | case ty 187 | when LLVM::Type then ty 188 | else ty.type 189 | end 190 | end 191 | 192 | # Shortcut to Type.array. 193 | def Array(ty, sz = 0) 194 | LLVM::Type.array(ty, sz) 195 | end 196 | 197 | # Shortcut to Type.pointer. 198 | def Pointer(ty) 199 | LLVM::Type.pointer(ty) 200 | end 201 | 202 | # Shortcut to Type.vector. 203 | def Vector(ty, sz) 204 | LLVM::Type.vector(ty, sz) 205 | end 206 | 207 | # Shortcut to Type.function. 208 | def Function(argtypes, rettype, options = {}) 209 | LLVM::Type.function(argtypes, rettype, options) 210 | end 211 | 212 | # Shortcut to Type.struct. 213 | def Struct(*elt_types) 214 | name = if elt_types.last.is_a? String 215 | elt_types.pop 216 | else 217 | nil 218 | end 219 | LLVM::Type.struct(elt_types, false, name) 220 | end 221 | 222 | # Shortcut to Type.void. 223 | def Void 224 | LLVM::Type.void 225 | end 226 | 227 | end 228 | -------------------------------------------------------------------------------- /lib/llvm/core/value.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | class Value 3 | # @private 4 | def self.from_ptr(ptr) 5 | return if ptr.null? 6 | val = allocate 7 | val.instance_variable_set(:@ptr, ptr) 8 | val 9 | end 10 | 11 | # @private 12 | def to_ptr 13 | @ptr 14 | end 15 | 16 | # Checks if the value is equal to other. 17 | def ==(other) 18 | case other 19 | when LLVM::Value 20 | @ptr == other.to_ptr 21 | else 22 | false 23 | end 24 | end 25 | 26 | def hash 27 | @ptr.address.hash 28 | end 29 | 30 | # Checks if the value is equal to other. 31 | def eql?(other) 32 | other.instance_of?(self.class) && self == other 33 | end 34 | 35 | # Returns the Value type. This is abstract and is overidden by its subclasses. 36 | def self.type 37 | raise NotImplementedError, "#{self.name}.type() is abstract." 38 | end 39 | 40 | def self.to_ptr 41 | type.to_ptr 42 | end 43 | 44 | # Returns the value's type. 45 | def type 46 | Type.from_ptr(C.type_of(self), nil) 47 | end 48 | 49 | # Returns the value's name. 50 | def name 51 | C.get_value_name(self) 52 | end 53 | 54 | # Sets the value's name to str. 55 | def name=(str) 56 | C.set_value_name(self, str) 57 | str 58 | end 59 | 60 | # Print the value's IR to stdout. 61 | def dump 62 | C.dump_value(self) 63 | end 64 | 65 | # Returns whether the value is constant. 66 | def constant? 67 | case C.is_constant(self) 68 | when 0 then false 69 | when 1 then true 70 | end 71 | end 72 | 73 | # Returns whether the value is null. 74 | def null? 75 | case C.is_null(self) 76 | when 0 then false 77 | when 1 then true 78 | end 79 | end 80 | 81 | # Returns whether the value is undefined. 82 | def undefined? 83 | case C.is_undef(self) 84 | when 0 then false 85 | when 1 then true 86 | end 87 | end 88 | 89 | # Adds attr to this value's attributes. 90 | def add_attribute(attr) 91 | C.add_attribute(self, attr) 92 | end 93 | end 94 | 95 | class Argument < Value 96 | end 97 | 98 | class BasicBlock < Value 99 | # Creates a basic block for the given function with the given name. 100 | def self.create(fun = nil, name = "") 101 | self.from_ptr(C.append_basic_block(fun, name)) 102 | end 103 | 104 | # Build the basic block with the given builder. Creates a new one if nil. Yields the builder. 105 | def build(builder = nil) 106 | if builder.nil? 107 | builder = Builder.new 108 | builder.position_at_end(self) 109 | yield builder 110 | builder.dispose 111 | else 112 | builder.position_at_end(self) 113 | yield builder 114 | end 115 | end 116 | 117 | # Returns the parent of this basic block (a Function). 118 | def parent 119 | fp = C.get_basic_block_parent(self) 120 | LLVM::Function.from_ptr(fp) unless fp.null? 121 | end 122 | 123 | # Returns the next basic block in the sequence. 124 | def next 125 | ptr = C.get_next_basic_block(self) 126 | BasicBlock.from_ptr(ptr) unless ptr.null? 127 | end 128 | 129 | # Returns the previous basic block in the sequence. 130 | def previous 131 | ptr = C.get_previous_basic_block(self) 132 | BasicBlock.from_ptr(ptr) unless ptr.null? 133 | end 134 | 135 | def first_instruction # deprecated 136 | instructions.first 137 | end 138 | 139 | def last_instruction # deprecated 140 | instructions.last 141 | end 142 | 143 | # Returns an Enumerable of the Instructions in the current block. 144 | def instructions 145 | @instructions ||= InstructionCollection.new(self) 146 | end 147 | 148 | # @private 149 | class InstructionCollection 150 | include Enumerable 151 | 152 | def initialize(block) 153 | @block = block 154 | end 155 | 156 | # Iterates through each Instruction in the collection. 157 | def each 158 | return to_enum :each unless block_given? 159 | inst, last = first, last 160 | 161 | while inst 162 | yield inst 163 | break if inst == last 164 | inst = inst.next 165 | end 166 | 167 | self 168 | end 169 | 170 | # Returns the first Instruction in the collection. 171 | def first 172 | ptr = C.get_first_instruction(@block) 173 | LLVM::Instruction.from_ptr(ptr) unless ptr.null? 174 | end 175 | 176 | # Returns the last Instruction in the collection. 177 | def last 178 | ptr = C.get_last_instruction(@block) 179 | LLVM::Instruction.from_ptr(ptr) unless ptr.null? 180 | end 181 | end 182 | end 183 | 184 | class User < Value 185 | # Returns an Enumerable of the operands in this user. 186 | def operands 187 | @operand_collection ||= OperandCollection.new(self) 188 | end 189 | 190 | # @private 191 | class OperandCollection 192 | include Enumerable 193 | 194 | def initialize(user) 195 | @user = user 196 | end 197 | 198 | # Get a reference to an operand by index. 199 | def [](i) 200 | ptr = C.get_operand(@user, i) 201 | Value.from_ptr(ptr) unless ptr.null? 202 | end 203 | 204 | # Set or replace an operand by index. 205 | def []=(i, v) 206 | C.set_operand(@user, i, v) 207 | end 208 | 209 | # Returns the number of operands in the collection. 210 | def size 211 | C.get_num_operands(@user) 212 | end 213 | 214 | # Iterates through each operand in the collection. 215 | def each 216 | return to_enum :each unless block_given? 217 | 0.upto(size-1) { |i| yield self[i] } 218 | self 219 | end 220 | end 221 | end 222 | 223 | class Constant < User 224 | # Creates a null constant of Type. 225 | def self.null(type) 226 | from_ptr(C.const_null(type)) 227 | end 228 | 229 | # Creates a undefined constant of Type. 230 | def self.undef(type) 231 | from_ptr(C.get_undef(type)) 232 | end 233 | 234 | # Creates a null pointer constant of Type. 235 | def self.null_ptr(type) 236 | from_ptr(C.const_pointer_null(type)) 237 | end 238 | 239 | # Bitcast this constant to Type. 240 | def bitcast_to(type) 241 | ConstantExpr.from_ptr(C.const_bit_cast(self, type)) 242 | end 243 | 244 | # Returns the element pointer at the given indices of the constant. 245 | # For more information on gep go to: http://llvm.org/docs/GetElementPtr.html 246 | def gep(*indices) 247 | indices = Array(indices) 248 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * indices.size) do |indices_ptr| 249 | indices_ptr.write_array_of_pointer(indices) 250 | return ConstantExpr.from_ptr( 251 | C.const_gep(self, indices_ptr, indices.size)) 252 | end 253 | end 254 | 255 | def bit_cast(type) 256 | return ConstantExpr.from_ptr(C.const_bit_cast(self, type)) 257 | end 258 | end 259 | 260 | module Support 261 | def allocate_pointers(size_or_values, &block) 262 | if size_or_values.is_a?(Integer) 263 | raise ArgumentError, 'block not given' unless block_given? 264 | size = size_or_values 265 | values = (0...size).map { |i| yield i } 266 | else 267 | values = size_or_values 268 | size = values.size 269 | end 270 | FFI::MemoryPointer.new(:pointer, size).write_array_of_pointer(values) 271 | end 272 | 273 | module_function :allocate_pointers 274 | end 275 | 276 | class ConstantArray < Constant 277 | def self.string(str, null_terminate = true) 278 | from_ptr(C.const_string(str, str.length, null_terminate ? 0 : 1)) 279 | end 280 | 281 | # ConstantArray.const(type, 3) {|i| ... } or 282 | # ConstantArray.const(type, [...]) 283 | def self.const(type, size_or_values, &block) 284 | vals = LLVM::Support.allocate_pointers(size_or_values, &block) 285 | from_ptr C.const_array(type, vals, vals.size / vals.type_size) 286 | end 287 | 288 | def size 289 | C.get_array_length(type) 290 | end 291 | end 292 | 293 | class ConstantExpr < Constant 294 | end 295 | 296 | class ConstantInt < Constant 297 | def self.all_ones 298 | from_ptr(C.const_all_ones(type)) 299 | end 300 | 301 | # Creates a ConstantInt from an integer. 302 | def self.from_i(n, signed = true) 303 | from_ptr(C.const_int(type, n, signed ? 1 : 0)) 304 | end 305 | 306 | def self.parse(str, radix = 10) 307 | from_ptr(C.const_int_of_string(type, str, radix)) 308 | end 309 | 310 | # Negation. 311 | def -@ 312 | self.class.from_ptr(C.const_neg(self)) 313 | end 314 | 315 | # Boolean negation. 316 | def not 317 | self.class.from_ptr(C.const_not(self)) 318 | end 319 | 320 | # Addition. 321 | def +(rhs) 322 | self.class.from_ptr(C.const_add(self, rhs)) 323 | end 324 | 325 | # "No signed wrap" addition. See 326 | # http://llvm.org/docs/LangRef.html#i_add for discusison. 327 | def nsw_add(rhs) 328 | self.class.from_ptr(C.const_nsw_add(self, rhs)) 329 | end 330 | 331 | # Multiplication. 332 | def *(rhs) 333 | self.class.from_ptr(C.const_mul(self, rhs)) 334 | end 335 | 336 | # Unsigned division. 337 | def udiv(rhs) 338 | self.class.from_ptr(C.const_u_div(self, rhs)) 339 | end 340 | 341 | # Signed division. 342 | def /(rhs) 343 | self.class.from_ptr(C.const_s_div(self, rhs)) 344 | end 345 | 346 | # Unsigned remainder. 347 | def urem(rhs) 348 | self.class.from_ptr(C.const_u_rem(self, rhs)) 349 | end 350 | 351 | # Signed remainder. 352 | def rem(rhs) 353 | self.class.from_ptr(C.const_s_rem(self, rhs)) 354 | end 355 | 356 | # Integer AND. 357 | def and(rhs) 358 | self.class.from_ptr(C.const_and(self, rhs)) 359 | end 360 | 361 | # Integer OR. 362 | def or(rhs) 363 | self.class.from_ptr(C.const_or(self, rhs)) 364 | end 365 | 366 | # Integer XOR. 367 | def xor(rhs) 368 | self.class.from_ptr(C.const_xor(self, rhs)) 369 | end 370 | 371 | # Integer comparison using the predicate specified via the first parameter. 372 | # Predicate can be any of: 373 | # :eq - equal to 374 | # :ne - not equal to 375 | # :ugt - unsigned greater than 376 | # :uge - unsigned greater than or equal to 377 | # :ult - unsigned less than 378 | # :ule - unsigned less than or equal to 379 | # :sgt - signed greater than 380 | # :sge - signed greater than or equal to 381 | # :slt - signed less than 382 | # :sle - signed less than or equal to 383 | def icmp(pred, rhs) 384 | self.class.from_ptr(C.const_i_cmp(pred, self, rhs)) 385 | end 386 | 387 | # Shift left. 388 | def <<(bits) 389 | self.class.from_ptr(C.const_shl(self, bits)) 390 | end 391 | 392 | # Shift right. 393 | def >>(bits) 394 | self.class.from_ptr(C.const_l_shr(self, bits)) 395 | end 396 | 397 | # Arithmatic shift right. 398 | def ashr(bits) 399 | self.class.from_ptr(C.const_a_shr(self, bits)) 400 | end 401 | end 402 | 403 | def LLVM.const_missing(const) 404 | case const.to_s 405 | when /Int(\d+)/ 406 | width = $1.to_i 407 | name = "Int#{width}" 408 | eval <<-KLASS 409 | class #{name} < ConstantInt 410 | def self.type 411 | Type.from_ptr(C.int_type(#{width}), :integer) 412 | end 413 | end 414 | KLASS 415 | const_get(name) 416 | else 417 | super 418 | end 419 | end 420 | 421 | # Native integer type 422 | bits = FFI.type_size(:int) * 8 423 | ::LLVM::Int = const_get("Int#{bits}") 424 | 425 | # Creates a LLVM Int (subclass of ConstantInt) at the NATIVE_INT_SIZE from a integer (val). 426 | def LLVM.Int(val) 427 | case val 428 | when LLVM::ConstantInt then val 429 | when Integer then Int.from_i(val) 430 | when Value 431 | return val if val.type.kind == :integer 432 | raise "value not of integer type: #{val.type.kind}" 433 | else raise "can't make an LLVM::ConstantInt from #{val.class.name}" 434 | end 435 | end 436 | 437 | # Boolean values 438 | ::LLVM::TRUE = ::LLVM::Int1.from_i(-1) 439 | ::LLVM::FALSE = ::LLVM::Int1.from_i(0) 440 | 441 | class ConstantReal < Constant 442 | # Creates a ConstantReal from a float of Type. 443 | def self.from_f(n) 444 | from_ptr(C.const_real(type, n)) 445 | end 446 | 447 | def self.parse(type, str) 448 | from_ptr(C.const_real_of_string(type, str)) 449 | end 450 | 451 | # Negation. 452 | def -@ 453 | self.class.from_ptr(C.const_f_neg(self)) 454 | end 455 | 456 | # Returns the result of adding this ConstantReal to rhs. 457 | def +(rhs) 458 | self.class.from_ptr(C.const_f_add(self, rhs)) 459 | end 460 | 461 | # Returns the result of multiplying this ConstantReal by rhs. 462 | def *(rhs) 463 | self.class.from_ptr(C.const_f_mul(self, rhs)) 464 | end 465 | 466 | # Returns the result of dividing this ConstantReal by rhs. 467 | def /(rhs) 468 | self.class.from_ptr(C.const_f_div(self, rhs)) 469 | end 470 | 471 | # Remainder. 472 | def rem(rhs) 473 | self.class.from_ptr(C.const_f_rem(self, rhs)) 474 | end 475 | 476 | # Floating point comparison using the predicate specified via the first 477 | # parameter. Predicate can be any of: 478 | # :ord - ordered 479 | # :uno - unordered: isnan(X) | isnan(Y) 480 | # :oeq - ordered and equal to 481 | # :oeq - unordered and equal to 482 | # :one - ordered and not equal to 483 | # :one - unordered and not equal to 484 | # :ogt - ordered and greater than 485 | # :uge - unordered and greater than or equal to 486 | # :olt - ordered and less than 487 | # :ule - unordered and less than or equal to 488 | # :oge - ordered and greater than or equal to 489 | # :sge - unordered and greater than or equal to 490 | # :ole - ordered and less than or equal to 491 | # :sle - unordered and less than or equal to 492 | # :true - always true 493 | # :false- always false 494 | def fcmp(pred, rhs) 495 | self.class.from_ptr(C.llmv_const_f_cmp(pred, self, rhs)) 496 | end 497 | end 498 | 499 | class Float < ConstantReal 500 | # Return a Type representation of the float. 501 | def self.type 502 | Type.from_ptr(C.float_type, :float) 503 | end 504 | end 505 | 506 | # Create a LLVM::Float from a Ruby Float (val). 507 | def LLVM.Float(val) 508 | Float.from_f(val) 509 | end 510 | 511 | class Double < ConstantReal 512 | def self.type 513 | Type.from_ptr(C.double_type, :double) 514 | end 515 | end 516 | 517 | def LLVM.Double(val) 518 | Double.from_f(val) 519 | end 520 | 521 | class ConstantStruct < Constant 522 | # ConstantStruct.const(size) {|i| ... } or 523 | # ConstantStruct.const([...]) 524 | def self.const(size_or_values, packed = false, &block) 525 | vals = LLVM::Support.allocate_pointers(size_or_values, &block) 526 | from_ptr C.const_struct(vals, vals.size / vals.type_size, packed ? 1 : 0) 527 | end 528 | end 529 | 530 | class ConstantVector < Constant 531 | def self.all_ones 532 | from_ptr(C.const_all_ones(type)) 533 | end 534 | 535 | def self.const(size_or_values, &block) 536 | vals = LLVM::Support.allocate_pointers(size_or_values, &block) 537 | from_ptr(C.const_vector(vals, vals.size / vals.type_size)) 538 | end 539 | 540 | def size 541 | C.get_vector_size(type) 542 | end 543 | end 544 | 545 | class GlobalValue < Constant 546 | def declaration? 547 | C.is_declaration(self) 548 | end 549 | 550 | def linkage 551 | C.get_linkage(self) 552 | end 553 | 554 | def linkage=(linkage) 555 | C.set_linkage(self, linkage) 556 | end 557 | 558 | def section 559 | C.get_section(self) 560 | end 561 | 562 | def section=(section) 563 | C.set_section(self, section) 564 | end 565 | 566 | def visibility 567 | C.get_visibility(self) 568 | end 569 | 570 | def visibility=(viz) 571 | C.set_visibility(self, viz) 572 | end 573 | 574 | def alignment 575 | C.get_alignment(self) 576 | end 577 | 578 | def alignment=(bytes) 579 | C.set_alignment(self, bytes) 580 | end 581 | 582 | def initializer 583 | Value.from_ptr(C.get_initializer(self)) 584 | end 585 | 586 | def initializer=(val) 587 | C.set_initializer(self, val) 588 | end 589 | 590 | def global_constant? 591 | C.is_global_constant(self) 592 | end 593 | 594 | def global_constant=(flag) 595 | C.set_global_constant(self, flag) 596 | end 597 | end 598 | 599 | class Function < GlobalValue 600 | # Sets the function's calling convention and returns it. 601 | def call_conv=(conv) 602 | C.set_function_call_conv(self, conv) 603 | conv 604 | end 605 | 606 | # Adds the given attribute to the function. 607 | def add_attribute(attr) 608 | C.add_function_attr(self, attr) 609 | end 610 | 611 | # Removes the given attribute from the function. 612 | def remove_attribute(attr) 613 | C.remove_function_attr(self, attr) 614 | end 615 | 616 | # Returns an Enumerable of the BasicBlocks in this function. 617 | def basic_blocks 618 | @basic_block_collection ||= BasicBlockCollection.new(self) 619 | end 620 | 621 | def type 622 | Type.from_ptr(C.type_of(self), :function) 623 | end 624 | 625 | # @private 626 | class BasicBlockCollection 627 | include Enumerable 628 | 629 | def initialize(fun) 630 | @fun = fun 631 | end 632 | 633 | # Returns the number of BasicBlocks in the collection. 634 | def size 635 | C.count_basic_blocks(@fun) 636 | end 637 | 638 | # Iterates through each BasicBlock in the collection. 639 | def each 640 | return to_enum :each unless block_given? 641 | 642 | ptr = C.get_first_basic_block(@fun) 643 | 0.upto(size-1) do |i| 644 | yield BasicBlock.from_ptr(ptr) 645 | ptr = C.get_next_basic_block(ptr) 646 | end 647 | 648 | self 649 | end 650 | 651 | # Adds a BasicBlock with the given name to the end of the collection. 652 | def append(name = "") 653 | BasicBlock.create(@fun, name) 654 | end 655 | 656 | # Returns the entry BasicBlock in the collection. This is the block the 657 | # function starts on. 658 | def entry 659 | BasicBlock.from_ptr(C.get_entry_basic_block(@fun)) 660 | end 661 | 662 | # Returns the first BasicBlock in the collection. 663 | def first 664 | ptr = C.get_first_basic_block(@fun) 665 | BasicBlock.from_ptr(ptr) unless ptr.null? 666 | end 667 | 668 | # Returns the last BasicBlock in the collection. 669 | def last 670 | ptr = C.get_last_basic_block(@fun) 671 | BasicBlock.from_ptr(ptr) unless ptr.null? 672 | end 673 | end 674 | 675 | # Returns an Enumerable of the parameters in the function. 676 | def params 677 | @parameter_collection ||= ParameterCollection.new(self) 678 | end 679 | 680 | # @private 681 | class ParameterCollection 682 | def initialize(fun) 683 | @fun = fun 684 | end 685 | 686 | # Returns a Value representation of the parameter at the given index. 687 | def [](i) 688 | sz = self.size 689 | i = sz + i if i < 0 690 | return unless 0 <= i && i < sz 691 | Value.from_ptr(C.get_param(@fun, i)) 692 | end 693 | 694 | # Returns the number of paramters in the collection. 695 | def size 696 | C.count_params(@fun) 697 | end 698 | 699 | include Enumerable 700 | 701 | # Iteraters through each parameter in the collection. 702 | def each 703 | return to_enum :each unless block_given? 704 | 0.upto(size-1) { |i| yield self[i] } 705 | self 706 | end 707 | end 708 | 709 | def gc=(name) 710 | C.set_gc(self, name) 711 | end 712 | def gc 713 | C.get_gc(self) 714 | end 715 | end 716 | 717 | class GlobalAlias < GlobalValue 718 | end 719 | 720 | class GlobalVariable < GlobalValue 721 | def initializer 722 | Value.from_ptr(C.get_initializer(self)) 723 | end 724 | 725 | def initializer=(val) 726 | C.set_initializer(self, val) 727 | end 728 | 729 | def thread_local? 730 | case C.is_thread_local(self) 731 | when 0 then false 732 | else true 733 | end 734 | end 735 | 736 | def thread_local=(local) 737 | C.set_thread_local(self, local ? 1 : 0) 738 | end 739 | end 740 | 741 | class Instruction < User 742 | # Returns the parent of the instruction (a BasicBlock). 743 | def parent 744 | ptr = C.get_instruction_parent(self) 745 | LLVM::BasicBlock.from_ptr(ptr) unless ptr.null? 746 | end 747 | 748 | # Returns the next instruction after this one. 749 | def next 750 | ptr = C.get_next_instruction(self) 751 | LLVM::Instruction.from_ptr(ptr) unless ptr.null? 752 | end 753 | 754 | # Returns the previous instruction before this one. 755 | def previous 756 | ptr = C.get_previous_instruction(self) 757 | LLVM::Instruction.from_ptr(ptr) unless ptr.null? 758 | end 759 | end 760 | 761 | class CallInst < Instruction 762 | # Sets the call convention to conv. 763 | def call_conv=(conv) 764 | C.set_instruction_call_conv(self, conv) 765 | conv 766 | end 767 | 768 | # Returns the call insatnce's call convention. 769 | def call_conv 770 | C.get_instruction_call_conv(self) 771 | end 772 | end 773 | 774 | # @private 775 | class Phi < Instruction 776 | # Add incoming branches to a phi node by passing an alternating list of 777 | # resulting values and BasicBlocks. e.g. 778 | # phi.add_incoming(val1, block1, val2, block2, ...) 779 | def add_incoming(incoming) 780 | blks = incoming.keys 781 | vals = incoming.values_at(*blks) 782 | size = incoming.size 783 | 784 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * size) do |vals_ptr| 785 | vals_ptr.write_array_of_pointer(vals) 786 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * size) do |blks_ptr| 787 | blks_ptr.write_array_of_pointer(blks) 788 | C.add_incoming(self, vals_ptr, blks_ptr, vals.size) 789 | end 790 | end 791 | 792 | nil 793 | end 794 | end 795 | 796 | # @private 797 | class SwitchInst < Instruction 798 | # Adds a case to a switch instruction. First the value to match on, then 799 | # the basic block. 800 | def add_case(val, block) 801 | C.add_case(self, val, block) 802 | end 803 | end 804 | end 805 | -------------------------------------------------------------------------------- /lib/llvm/execution_engine.rb: -------------------------------------------------------------------------------- 1 | require 'llvm' 2 | require 'llvm/core' 3 | require 'llvm/target' 4 | require 'llvm/analysis' 5 | require 'llvm/execution_engine_ffi' 6 | 7 | module LLVM 8 | # @private 9 | module C 10 | attach_function :initialize_x86_target_info, :LLVMInitializeX86TargetInfo, [], :void 11 | attach_function :initialize_x86_target, :LLVMInitializeX86Target, [], :void 12 | attach_function :initialize_x86_target_mc, :LLVMInitializeX86TargetMC, [], :void 13 | end 14 | 15 | def LLVM.init_x86 16 | LLVM::C.initialize_x86_target 17 | LLVM::C.initialize_x86_target_info 18 | LLVM::C.initialize_x86_target_mc 19 | end 20 | 21 | class JITCompiler 22 | # Important: Call #dispose to free backend memory after use. Do not call #dispose on mod any more. 23 | def initialize(mod, opt_level = 3) 24 | FFI::MemoryPointer.new(FFI.type_size(:pointer)) do |ptr| 25 | error = FFI::MemoryPointer.new(FFI.type_size(:pointer)) 26 | status = C.create_jit_compiler_for_module(ptr, mod, opt_level, error) 27 | errorp = error.read_pointer 28 | message = errorp.read_string unless errorp.null? 29 | 30 | if status.zero? 31 | @ptr = ptr.read_pointer 32 | else 33 | C.dispose_message(error) 34 | error.autorelease=false 35 | raise RuntimeError, "Error creating JIT compiler: #{message}" 36 | end 37 | end 38 | end 39 | 40 | def dispose 41 | return if @ptr.nil? 42 | C.dispose_execution_engine(@ptr) 43 | @ptr = nil 44 | end 45 | 46 | # @private 47 | def to_ptr 48 | @ptr 49 | end 50 | 51 | # Execute the given LLVM::Function with the supplied args (as 52 | # GenericValues). 53 | # Important: Call #dispose on the returned GenericValue to 54 | # free backend memory after use. 55 | def run_function(fun, *args) 56 | FFI::MemoryPointer.new(FFI.type_size(:pointer) * args.size) do |args_ptr| 57 | new_values = [] 58 | args_ptr.write_array_of_pointer fun.params.zip(args).map { |p, a| 59 | if a.kind_of?(GenericValue) 60 | a 61 | else 62 | value = LLVM.make_generic_value(p.type, a) 63 | new_values << value 64 | value 65 | end 66 | } 67 | result = LLVM::GenericValue.from_ptr( 68 | C.run_function(self, fun, args.size, args_ptr)) 69 | new_values.each(&:dispose) 70 | return result 71 | end 72 | end 73 | 74 | # Obtain an FFI::Pointer to a global within the current module. 75 | def pointer_to_global(global) 76 | C.get_pointer_to_global(self, global) 77 | end 78 | end 79 | 80 | class GenericValue 81 | # @private 82 | def to_ptr 83 | @ptr 84 | end 85 | 86 | # Casts an FFI::Pointer pointing to a GenericValue to an instance. 87 | def self.from_ptr(ptr) 88 | return if ptr.null? 89 | val = allocate 90 | val.instance_variable_set(:@ptr, ptr) 91 | val 92 | end 93 | 94 | def dispose 95 | return if @ptr.nil? 96 | C.dispose_generic_value(@ptr) 97 | @ptr = nil 98 | end 99 | 100 | # Creates a Generic Value from an integer. Type is the size of integer to 101 | # create (ex. Int32, Int8, etc.) 102 | def self.from_i(i, options = {}) 103 | type = options.fetch(:type, LLVM::Int) 104 | signed = options.fetch(:signed, true) 105 | from_ptr(C.create_generic_value_of_int(type, i, signed ? 1 : 0)) 106 | end 107 | 108 | # Creates a Generic Value from a Float. 109 | def self.from_f(f) 110 | from_ptr(C.create_generic_value_of_float(LLVM::Float, f)) 111 | end 112 | 113 | def self.from_d(val) 114 | from_ptr(C.create_generic_value_of_float(LLVM::Double, val)) 115 | end 116 | 117 | # Creates a GenericValue from a Ruby boolean. 118 | def self.from_b(b) 119 | from_i(b ? 1 : 0, LLVM::Int1, false) 120 | end 121 | 122 | # Creates a GenericValue from an FFI::Pointer pointing to some arbitrary value. 123 | def self.from_value_ptr(ptr) 124 | from_ptr(LLVM::C.create_generic_value_of_pointer(ptr)) 125 | end 126 | 127 | # Converts a GenericValue to a Ruby Integer. 128 | def to_i(signed = true) 129 | v = C.generic_value_to_int(self, signed ? 1 : 0) 130 | v -= 2**64 if signed and v >= 2**63 131 | v 132 | end 133 | 134 | # Converts a GenericValue to a Ruby Float. 135 | def to_f(type = LLVM::Float.type) 136 | C.generic_value_to_float(type, self) 137 | end 138 | 139 | # Converts a GenericValue to a Ruby boolean. 140 | def to_b 141 | to_i(false) != 0 142 | end 143 | 144 | def to_value_ptr 145 | C.generic_value_to_pointer(self) 146 | end 147 | end 148 | 149 | # @private 150 | def make_generic_value(ty, val) 151 | case ty.kind 152 | when :double then GenericValue.from_d(val) 153 | when :float then GenericValue.from_f(val) 154 | when :pointer then GenericValue.from_value_ptr(val) 155 | when :integer then GenericValue.from_i(val, :type => ty) 156 | else 157 | raise "Unsupported type #{ty.kind}." 158 | end 159 | end 160 | module_function :make_generic_value 161 | end 162 | -------------------------------------------------------------------------------- /lib/llvm/execution_engine_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # @method link_in_jit() 18 | # @return [nil] 19 | # @scope class 20 | attach_function :link_in_jit, :LLVMLinkInJIT, [], :void 21 | 22 | # (Not documented) 23 | # 24 | # @method link_in_interpreter() 25 | # @return [nil] 26 | # @scope class 27 | attach_function :link_in_interpreter, :LLVMLinkInInterpreter, [], :void 28 | 29 | # (Not documented) 30 | class OpaqueGenericValue < FFI::Struct 31 | layout :dummy, :char 32 | end 33 | 34 | # (Not documented) 35 | class OpaqueExecutionEngine < FFI::Struct 36 | layout :dummy, :char 37 | end 38 | 39 | # ===-- Operations on generic values --------------------------------------=== 40 | # 41 | # @method create_generic_value_of_int(ty, n, is_signed) 42 | # @param [FFI::Pointer(TypeRef)] ty 43 | # @param [Integer] n 44 | # @param [Integer] is_signed 45 | # @return [OpaqueGenericValue] 46 | # @scope class 47 | attach_function :create_generic_value_of_int, :LLVMCreateGenericValueOfInt, [:pointer, :ulong_long, :int], OpaqueGenericValue 48 | 49 | # (Not documented) 50 | # 51 | # @method create_generic_value_of_pointer(p) 52 | # @param [FFI::Pointer(*Void)] p 53 | # @return [OpaqueGenericValue] 54 | # @scope class 55 | attach_function :create_generic_value_of_pointer, :LLVMCreateGenericValueOfPointer, [:pointer], OpaqueGenericValue 56 | 57 | # (Not documented) 58 | # 59 | # @method create_generic_value_of_float(ty, n) 60 | # @param [FFI::Pointer(TypeRef)] ty 61 | # @param [Float] n 62 | # @return [OpaqueGenericValue] 63 | # @scope class 64 | attach_function :create_generic_value_of_float, :LLVMCreateGenericValueOfFloat, [:pointer, :double], OpaqueGenericValue 65 | 66 | # (Not documented) 67 | # 68 | # @method generic_value_int_width(gen_val_ref) 69 | # @param [OpaqueGenericValue] gen_val_ref 70 | # @return [Integer] 71 | # @scope class 72 | attach_function :generic_value_int_width, :LLVMGenericValueIntWidth, [OpaqueGenericValue], :uint 73 | 74 | # (Not documented) 75 | # 76 | # @method generic_value_to_int(gen_val, is_signed) 77 | # @param [OpaqueGenericValue] gen_val 78 | # @param [Integer] is_signed 79 | # @return [Integer] 80 | # @scope class 81 | attach_function :generic_value_to_int, :LLVMGenericValueToInt, [OpaqueGenericValue, :int], :ulong_long 82 | 83 | # (Not documented) 84 | # 85 | # @method generic_value_to_pointer(gen_val) 86 | # @param [OpaqueGenericValue] gen_val 87 | # @return [FFI::Pointer(*Void)] 88 | # @scope class 89 | attach_function :generic_value_to_pointer, :LLVMGenericValueToPointer, [OpaqueGenericValue], :pointer 90 | 91 | # (Not documented) 92 | # 93 | # @method generic_value_to_float(ty_ref, gen_val) 94 | # @param [FFI::Pointer(TypeRef)] ty_ref 95 | # @param [OpaqueGenericValue] gen_val 96 | # @return [Float] 97 | # @scope class 98 | attach_function :generic_value_to_float, :LLVMGenericValueToFloat, [:pointer, OpaqueGenericValue], :double 99 | 100 | # (Not documented) 101 | # 102 | # @method dispose_generic_value(gen_val) 103 | # @param [OpaqueGenericValue] gen_val 104 | # @return [nil] 105 | # @scope class 106 | attach_function :dispose_generic_value, :LLVMDisposeGenericValue, [OpaqueGenericValue], :void 107 | 108 | # ===-- Operations on execution engines -----------------------------------=== 109 | # 110 | # @method create_execution_engine_for_module(out_ee, m, out_error) 111 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_ee 112 | # @param [FFI::Pointer(ModuleRef)] m 113 | # @param [FFI::Pointer(**CharS)] out_error 114 | # @return [Integer] 115 | # @scope class 116 | attach_function :create_execution_engine_for_module, :LLVMCreateExecutionEngineForModule, [:pointer, :pointer, :pointer], :int 117 | 118 | # (Not documented) 119 | # 120 | # @method create_interpreter_for_module(out_interp, m, out_error) 121 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_interp 122 | # @param [FFI::Pointer(ModuleRef)] m 123 | # @param [FFI::Pointer(**CharS)] out_error 124 | # @return [Integer] 125 | # @scope class 126 | attach_function :create_interpreter_for_module, :LLVMCreateInterpreterForModule, [:pointer, :pointer, :pointer], :int 127 | 128 | # (Not documented) 129 | # 130 | # @method create_jit_compiler_for_module(out_jit, m, opt_level, out_error) 131 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_jit 132 | # @param [FFI::Pointer(ModuleRef)] m 133 | # @param [Integer] opt_level 134 | # @param [FFI::Pointer(**CharS)] out_error 135 | # @return [Integer] 136 | # @scope class 137 | attach_function :create_jit_compiler_for_module, :LLVMCreateJITCompilerForModule, [:pointer, :pointer, :uint, :pointer], :int 138 | 139 | # Deprecated: Use LLVMCreateExecutionEngineForModule instead. 140 | # 141 | # @method create_execution_engine(out_ee, mp, out_error) 142 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_ee 143 | # @param [FFI::Pointer(ModuleProviderRef)] mp 144 | # @param [FFI::Pointer(**CharS)] out_error 145 | # @return [Integer] 146 | # @scope class 147 | attach_function :create_execution_engine, :LLVMCreateExecutionEngine, [:pointer, :pointer, :pointer], :int 148 | 149 | # Deprecated: Use LLVMCreateInterpreterForModule instead. 150 | # 151 | # @method create_interpreter(out_interp, mp, out_error) 152 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_interp 153 | # @param [FFI::Pointer(ModuleProviderRef)] mp 154 | # @param [FFI::Pointer(**CharS)] out_error 155 | # @return [Integer] 156 | # @scope class 157 | attach_function :create_interpreter, :LLVMCreateInterpreter, [:pointer, :pointer, :pointer], :int 158 | 159 | # Deprecated: Use LLVMCreateJITCompilerForModule instead. 160 | # 161 | # @method create_jit_compiler(out_jit, mp, opt_level, out_error) 162 | # @param [FFI::Pointer(*ExecutionEngineRef)] out_jit 163 | # @param [FFI::Pointer(ModuleProviderRef)] mp 164 | # @param [Integer] opt_level 165 | # @param [FFI::Pointer(**CharS)] out_error 166 | # @return [Integer] 167 | # @scope class 168 | attach_function :create_jit_compiler, :LLVMCreateJITCompiler, [:pointer, :pointer, :uint, :pointer], :int 169 | 170 | # (Not documented) 171 | # 172 | # @method dispose_execution_engine(ee) 173 | # @param [OpaqueExecutionEngine] ee 174 | # @return [nil] 175 | # @scope class 176 | attach_function :dispose_execution_engine, :LLVMDisposeExecutionEngine, [OpaqueExecutionEngine], :void 177 | 178 | # (Not documented) 179 | # 180 | # @method run_static_constructors(ee) 181 | # @param [OpaqueExecutionEngine] ee 182 | # @return [nil] 183 | # @scope class 184 | attach_function :run_static_constructors, :LLVMRunStaticConstructors, [OpaqueExecutionEngine], :void 185 | 186 | # (Not documented) 187 | # 188 | # @method run_static_destructors(ee) 189 | # @param [OpaqueExecutionEngine] ee 190 | # @return [nil] 191 | # @scope class 192 | attach_function :run_static_destructors, :LLVMRunStaticDestructors, [OpaqueExecutionEngine], :void 193 | 194 | # (Not documented) 195 | # 196 | # @method run_function_as_main(ee, f, arg_c, arg_v, env_p) 197 | # @param [OpaqueExecutionEngine] ee 198 | # @param [FFI::Pointer(ValueRef)] f 199 | # @param [Integer] arg_c 200 | # @param [FFI::Pointer(**CharS)] arg_v 201 | # @param [FFI::Pointer(**CharS)] env_p 202 | # @return [Integer] 203 | # @scope class 204 | attach_function :run_function_as_main, :LLVMRunFunctionAsMain, [OpaqueExecutionEngine, :pointer, :uint, :pointer, :pointer], :int 205 | 206 | # (Not documented) 207 | # 208 | # @method run_function(ee, f, num_args, args) 209 | # @param [OpaqueExecutionEngine] ee 210 | # @param [FFI::Pointer(ValueRef)] f 211 | # @param [Integer] num_args 212 | # @param [FFI::Pointer(*GenericValueRef)] args 213 | # @return [OpaqueGenericValue] 214 | # @scope class 215 | attach_function :run_function, :LLVMRunFunction, [OpaqueExecutionEngine, :pointer, :uint, :pointer], OpaqueGenericValue 216 | 217 | # (Not documented) 218 | # 219 | # @method free_machine_code_for_function(ee, f) 220 | # @param [OpaqueExecutionEngine] ee 221 | # @param [FFI::Pointer(ValueRef)] f 222 | # @return [nil] 223 | # @scope class 224 | attach_function :free_machine_code_for_function, :LLVMFreeMachineCodeForFunction, [OpaqueExecutionEngine, :pointer], :void 225 | 226 | # (Not documented) 227 | # 228 | # @method add_module(ee, m) 229 | # @param [OpaqueExecutionEngine] ee 230 | # @param [FFI::Pointer(ModuleRef)] m 231 | # @return [nil] 232 | # @scope class 233 | attach_function :add_module, :LLVMAddModule, [OpaqueExecutionEngine, :pointer], :void 234 | 235 | # Deprecated: Use LLVMAddModule instead. 236 | # 237 | # @method add_module_provider(ee, mp) 238 | # @param [OpaqueExecutionEngine] ee 239 | # @param [FFI::Pointer(ModuleProviderRef)] mp 240 | # @return [nil] 241 | # @scope class 242 | attach_function :add_module_provider, :LLVMAddModuleProvider, [OpaqueExecutionEngine, :pointer], :void 243 | 244 | # (Not documented) 245 | # 246 | # @method remove_module(ee, m, out_mod, out_error) 247 | # @param [OpaqueExecutionEngine] ee 248 | # @param [FFI::Pointer(ModuleRef)] m 249 | # @param [FFI::Pointer(*ModuleRef)] out_mod 250 | # @param [FFI::Pointer(**CharS)] out_error 251 | # @return [Integer] 252 | # @scope class 253 | attach_function :remove_module, :LLVMRemoveModule, [OpaqueExecutionEngine, :pointer, :pointer, :pointer], :int 254 | 255 | # Deprecated: Use LLVMRemoveModule instead. 256 | # 257 | # @method remove_module_provider(ee, mp, out_mod, out_error) 258 | # @param [OpaqueExecutionEngine] ee 259 | # @param [FFI::Pointer(ModuleProviderRef)] mp 260 | # @param [FFI::Pointer(*ModuleRef)] out_mod 261 | # @param [FFI::Pointer(**CharS)] out_error 262 | # @return [Integer] 263 | # @scope class 264 | attach_function :remove_module_provider, :LLVMRemoveModuleProvider, [OpaqueExecutionEngine, :pointer, :pointer, :pointer], :int 265 | 266 | # (Not documented) 267 | # 268 | # @method find_function(ee, name, out_fn) 269 | # @param [OpaqueExecutionEngine] ee 270 | # @param [String] name 271 | # @param [FFI::Pointer(*ValueRef)] out_fn 272 | # @return [Integer] 273 | # @scope class 274 | attach_function :find_function, :LLVMFindFunction, [OpaqueExecutionEngine, :string, :pointer], :int 275 | 276 | # (Not documented) 277 | # 278 | # @method recompile_and_relink_function(ee, fn) 279 | # @param [OpaqueExecutionEngine] ee 280 | # @param [FFI::Pointer(ValueRef)] fn 281 | # @return [FFI::Pointer(*Void)] 282 | # @scope class 283 | attach_function :recompile_and_relink_function, :LLVMRecompileAndRelinkFunction, [OpaqueExecutionEngine, :pointer], :pointer 284 | 285 | # (Not documented) 286 | # 287 | # @method get_execution_engine_target_data(ee) 288 | # @param [OpaqueExecutionEngine] ee 289 | # @return [FFI::Pointer(TargetDataRef)] 290 | # @scope class 291 | attach_function :get_execution_engine_target_data, :LLVMGetExecutionEngineTargetData, [OpaqueExecutionEngine], :pointer 292 | 293 | # (Not documented) 294 | # 295 | # @method add_global_mapping(ee, global, addr) 296 | # @param [OpaqueExecutionEngine] ee 297 | # @param [FFI::Pointer(ValueRef)] global 298 | # @param [FFI::Pointer(*Void)] addr 299 | # @return [nil] 300 | # @scope class 301 | attach_function :add_global_mapping, :LLVMAddGlobalMapping, [OpaqueExecutionEngine, :pointer, :pointer], :void 302 | 303 | # (Not documented) 304 | # 305 | # @method get_pointer_to_global(ee, global) 306 | # @param [OpaqueExecutionEngine] ee 307 | # @param [FFI::Pointer(ValueRef)] global 308 | # @return [FFI::Pointer(*Void)] 309 | # @scope class 310 | attach_function :get_pointer_to_global, :LLVMGetPointerToGlobal, [OpaqueExecutionEngine, :pointer], :pointer 311 | 312 | end 313 | -------------------------------------------------------------------------------- /lib/llvm/support.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | module Support 3 | # @private 4 | module C 5 | extend FFI::Library 6 | support_lib = File.expand_path( 7 | File.join( 8 | File.dirname(__FILE__), 9 | '../', 10 | FFI.map_library_name('RubyLLVMSupport-3.1.0'))) 11 | ffi_lib [support_lib] 12 | attach_function :load_library_permanently, :LLVMLoadLibraryPermanently, [:string], :int 13 | end 14 | end 15 | 16 | def load_library(libname) 17 | Support::C.load_library_permanently(libname) 18 | nil 19 | end 20 | 21 | module_function :load_library 22 | end 23 | -------------------------------------------------------------------------------- /lib/llvm/target.rb: -------------------------------------------------------------------------------- 1 | require 'llvm' 2 | require 'llvm/core' 3 | require 'llvm/target_ffi' 4 | 5 | module LLVM 6 | # nothing here 7 | end 8 | -------------------------------------------------------------------------------- /lib/llvm/target_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # This entry is only for documentation and no real method. The FFI::Enum can be accessed via #enum_type(:byte_ordering). 18 | # 19 | # === Options: 20 | # :big_endian :: 21 | # 22 | # :little_endian :: 23 | # 24 | # 25 | # @method _enum_byte_ordering_ 26 | # @return [Symbol] 27 | # @scope class 28 | enum :byte_ordering, [ 29 | :big_endian, 0, 30 | :little_endian, 1 31 | ] 32 | 33 | # (Not documented) 34 | class OpaqueTargetData < FFI::Struct 35 | layout :dummy, :char 36 | end 37 | 38 | # (Not documented) 39 | class OpaqueTargetLibraryInfotData < FFI::Struct 40 | layout :dummy, :char 41 | end 42 | 43 | # (Not documented) 44 | class StructLayout < FFI::Struct 45 | layout :dummy, :char 46 | end 47 | 48 | # (Not documented) 49 | # 50 | # @method initialize_all_target_infos() 51 | # @return [nil] 52 | # @scope class 53 | attach_function :initialize_all_target_infos, :LLVMInitializeAllTargetInfos, [], :void 54 | 55 | # LLVMInitializeAllTargets - The main program should call this function if it 56 | # wants to link in all available targets that LLVM is configured to 57 | # support. 58 | # 59 | # @method initialize_all_targets() 60 | # @return [nil] 61 | # @scope class 62 | attach_function :initialize_all_targets, :LLVMInitializeAllTargets, [], :void 63 | 64 | # LLVMInitializeAllTargetMCs - The main program should call this function if 65 | # it wants access to all available target MC that LLVM is configured to 66 | # support. 67 | # 68 | # @method initialize_all_target_m_cs() 69 | # @return [nil] 70 | # @scope class 71 | attach_function :initialize_all_target_m_cs, :LLVMInitializeAllTargetMCs, [], :void 72 | 73 | # LLVMInitializeAllAsmPrinters - The main program should call this function if 74 | # it wants all asm printers that LLVM is configured to support, to make them 75 | # available via the TargetRegistry. 76 | # 77 | # @method initialize_all_asm_printers() 78 | # @return [nil] 79 | # @scope class 80 | attach_function :initialize_all_asm_printers, :LLVMInitializeAllAsmPrinters, [], :void 81 | 82 | # LLVMInitializeAllAsmParsers - The main program should call this function if 83 | # it wants all asm parsers that LLVM is configured to support, to make them 84 | # available via the TargetRegistry. 85 | # 86 | # @method initialize_all_asm_parsers() 87 | # @return [nil] 88 | # @scope class 89 | attach_function :initialize_all_asm_parsers, :LLVMInitializeAllAsmParsers, [], :void 90 | 91 | # LLVMInitializeAllDisassemblers - The main program should call this function 92 | # if it wants all disassemblers that LLVM is configured to support, to make 93 | # them available via the TargetRegistry. 94 | # 95 | # @method initialize_all_disassemblers() 96 | # @return [nil] 97 | # @scope class 98 | attach_function :initialize_all_disassemblers, :LLVMInitializeAllDisassemblers, [], :void 99 | 100 | # LLVMInitializeNativeTarget - The main program should call this function to 101 | # initialize the native target corresponding to the host. This is useful 102 | # for JIT applications to ensure that the target gets linked in correctly. 103 | # 104 | # @method initialize_native_target() 105 | # @return [Integer] 106 | # @scope class 107 | attach_function :initialize_native_target, :LLVMInitializeNativeTarget, [], :int 108 | 109 | # Creates target data from a target layout string. 110 | # See the constructor llvm::TargetData::TargetData. 111 | # 112 | # @method create_target_data(string_rep) 113 | # @param [String] string_rep 114 | # @return [OpaqueTargetData] 115 | # @scope class 116 | attach_function :create_target_data, :LLVMCreateTargetData, [:string], OpaqueTargetData 117 | 118 | # Adds target data information to a pass manager. This does not take ownership 119 | # of the target data. 120 | # See the method llvm::PassManagerBase::add. 121 | # 122 | # @method add_target_data(opaque_target_data, pass_manager_ref) 123 | # @param [OpaqueTargetData] opaque_target_data 124 | # @param [FFI::Pointer(PassManagerRef)] pass_manager_ref 125 | # @return [nil] 126 | # @scope class 127 | attach_function :add_target_data, :LLVMAddTargetData, [OpaqueTargetData, :pointer], :void 128 | 129 | # Adds target library information to a pass manager. This does not take 130 | # ownership of the target library info. 131 | # See the method llvm::PassManagerBase::add. 132 | # 133 | # @method add_target_library_info(opaque_target_library_infot_data, pass_manager_ref) 134 | # @param [OpaqueTargetLibraryInfotData] opaque_target_library_infot_data 135 | # @param [FFI::Pointer(PassManagerRef)] pass_manager_ref 136 | # @return [nil] 137 | # @scope class 138 | attach_function :add_target_library_info, :LLVMAddTargetLibraryInfo, [OpaqueTargetLibraryInfotData, :pointer], :void 139 | 140 | # Converts target data to a target layout string. The string must be disposed 141 | # with LLVMDisposeMessage. 142 | # See the constructor llvm::TargetData::TargetData. 143 | # 144 | # @method copy_string_rep_of_target_data(opaque_target_data) 145 | # @param [OpaqueTargetData] opaque_target_data 146 | # @return [String] 147 | # @scope class 148 | attach_function :copy_string_rep_of_target_data, :LLVMCopyStringRepOfTargetData, [OpaqueTargetData], :string 149 | 150 | # Returns the byte order of a target, either LLVMBigEndian or 151 | # LLVMLittleEndian. 152 | # See the method llvm::TargetData::isLittleEndian. 153 | # 154 | # @method byte_order(opaque_target_data) 155 | # @param [OpaqueTargetData] opaque_target_data 156 | # @return [Symbol from _enum_byte_ordering_] 157 | # @scope class 158 | attach_function :byte_order, :LLVMByteOrder, [OpaqueTargetData], :byte_ordering 159 | 160 | # Returns the pointer size in bytes for a target. 161 | # See the method llvm::TargetData::getPointerSize. 162 | # 163 | # @method pointer_size(opaque_target_data) 164 | # @param [OpaqueTargetData] opaque_target_data 165 | # @return [Integer] 166 | # @scope class 167 | attach_function :pointer_size, :LLVMPointerSize, [OpaqueTargetData], :uint 168 | 169 | # Returns the integer type that is the same size as a pointer on a target. 170 | # See the method llvm::TargetData::getIntPtrType. 171 | # 172 | # @method int_ptr_type(opaque_target_data) 173 | # @param [OpaqueTargetData] opaque_target_data 174 | # @return [FFI::Pointer(TypeRef)] 175 | # @scope class 176 | attach_function :int_ptr_type, :LLVMIntPtrType, [OpaqueTargetData], :pointer 177 | 178 | # Computes the size of a type in bytes for a target. 179 | # See the method llvm::TargetData::getTypeSizeInBits. 180 | # 181 | # @method size_of_type_in_bits(opaque_target_data, type_ref) 182 | # @param [OpaqueTargetData] opaque_target_data 183 | # @param [FFI::Pointer(TypeRef)] type_ref 184 | # @return [Integer] 185 | # @scope class 186 | attach_function :size_of_type_in_bits, :LLVMSizeOfTypeInBits, [OpaqueTargetData, :pointer], :ulong_long 187 | 188 | # Computes the storage size of a type in bytes for a target. 189 | # See the method llvm::TargetData::getTypeStoreSize. 190 | # 191 | # @method store_size_of_type(opaque_target_data, type_ref) 192 | # @param [OpaqueTargetData] opaque_target_data 193 | # @param [FFI::Pointer(TypeRef)] type_ref 194 | # @return [Integer] 195 | # @scope class 196 | attach_function :store_size_of_type, :LLVMStoreSizeOfType, [OpaqueTargetData, :pointer], :ulong_long 197 | 198 | # Computes the ABI size of a type in bytes for a target. 199 | # See the method llvm::TargetData::getTypeAllocSize. 200 | # 201 | # @method abi_size_of_type(opaque_target_data, type_ref) 202 | # @param [OpaqueTargetData] opaque_target_data 203 | # @param [FFI::Pointer(TypeRef)] type_ref 204 | # @return [Integer] 205 | # @scope class 206 | attach_function :abi_size_of_type, :LLVMABISizeOfType, [OpaqueTargetData, :pointer], :ulong_long 207 | 208 | # Computes the ABI alignment of a type in bytes for a target. 209 | # See the method llvm::TargetData::getTypeABISize. 210 | # 211 | # @method abi_alignment_of_type(opaque_target_data, type_ref) 212 | # @param [OpaqueTargetData] opaque_target_data 213 | # @param [FFI::Pointer(TypeRef)] type_ref 214 | # @return [Integer] 215 | # @scope class 216 | attach_function :abi_alignment_of_type, :LLVMABIAlignmentOfType, [OpaqueTargetData, :pointer], :uint 217 | 218 | # Computes the call frame alignment of a type in bytes for a target. 219 | # See the method llvm::TargetData::getTypeABISize. 220 | # 221 | # @method call_frame_alignment_of_type(opaque_target_data, type_ref) 222 | # @param [OpaqueTargetData] opaque_target_data 223 | # @param [FFI::Pointer(TypeRef)] type_ref 224 | # @return [Integer] 225 | # @scope class 226 | attach_function :call_frame_alignment_of_type, :LLVMCallFrameAlignmentOfType, [OpaqueTargetData, :pointer], :uint 227 | 228 | # Computes the preferred alignment of a type in bytes for a target. 229 | # See the method llvm::TargetData::getTypeABISize. 230 | # 231 | # @method preferred_alignment_of_type(opaque_target_data, type_ref) 232 | # @param [OpaqueTargetData] opaque_target_data 233 | # @param [FFI::Pointer(TypeRef)] type_ref 234 | # @return [Integer] 235 | # @scope class 236 | attach_function :preferred_alignment_of_type, :LLVMPreferredAlignmentOfType, [OpaqueTargetData, :pointer], :uint 237 | 238 | # Computes the preferred alignment of a global variable in bytes for a target. 239 | # See the method llvm::TargetData::getPreferredAlignment. 240 | # 241 | # @method preferred_alignment_of_global(opaque_target_data, global_var) 242 | # @param [OpaqueTargetData] opaque_target_data 243 | # @param [FFI::Pointer(ValueRef)] global_var 244 | # @return [Integer] 245 | # @scope class 246 | attach_function :preferred_alignment_of_global, :LLVMPreferredAlignmentOfGlobal, [OpaqueTargetData, :pointer], :uint 247 | 248 | # Computes the structure element that contains the byte offset for a target. 249 | # See the method llvm::StructLayout::getElementContainingOffset. 250 | # 251 | # @method element_at_offset(opaque_target_data, struct_ty, offset) 252 | # @param [OpaqueTargetData] opaque_target_data 253 | # @param [FFI::Pointer(TypeRef)] struct_ty 254 | # @param [Integer] offset 255 | # @return [Integer] 256 | # @scope class 257 | attach_function :element_at_offset, :LLVMElementAtOffset, [OpaqueTargetData, :pointer, :ulong_long], :uint 258 | 259 | # Computes the byte offset of the indexed struct element for a target. 260 | # See the method llvm::StructLayout::getElementContainingOffset. 261 | # 262 | # @method offset_of_element(opaque_target_data, struct_ty, element) 263 | # @param [OpaqueTargetData] opaque_target_data 264 | # @param [FFI::Pointer(TypeRef)] struct_ty 265 | # @param [Integer] element 266 | # @return [Integer] 267 | # @scope class 268 | attach_function :offset_of_element, :LLVMOffsetOfElement, [OpaqueTargetData, :pointer, :uint], :ulong_long 269 | 270 | # Deallocates a TargetData. 271 | # See the destructor llvm::TargetData::~TargetData. 272 | # 273 | # @method dispose_target_data(opaque_target_data) 274 | # @param [OpaqueTargetData] opaque_target_data 275 | # @return [nil] 276 | # @scope class 277 | attach_function :dispose_target_data, :LLVMDisposeTargetData, [OpaqueTargetData], :void 278 | 279 | end 280 | -------------------------------------------------------------------------------- /lib/llvm/transforms/ipo.rb: -------------------------------------------------------------------------------- 1 | # Interprocedural optimization (IPO) 2 | require 'llvm' 3 | require 'llvm/core' 4 | require 'llvm/transforms/ipo_ffi' 5 | 6 | module LLVM 7 | class PassManager 8 | # @LLVMpass gdce 9 | def gdce! 10 | C.add_global_dce_pass(self) 11 | end 12 | 13 | # @LLVMpass inline 14 | def inline! 15 | C.add_function_inlining_pass(self) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/llvm/transforms/ipo_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # @method add_argument_promotion_pass(pm) 18 | # @param [FFI::Pointer(PassManagerRef)] pm 19 | # @return [nil] 20 | # @scope class 21 | attach_function :add_argument_promotion_pass, :LLVMAddArgumentPromotionPass, [:pointer], :void 22 | 23 | # See llvm::createConstantMergePass function. 24 | # 25 | # @method add_constant_merge_pass(pm) 26 | # @param [FFI::Pointer(PassManagerRef)] pm 27 | # @return [nil] 28 | # @scope class 29 | attach_function :add_constant_merge_pass, :LLVMAddConstantMergePass, [:pointer], :void 30 | 31 | # See llvm::createDeadArgEliminationPass function. 32 | # 33 | # @method add_dead_arg_elimination_pass(pm) 34 | # @param [FFI::Pointer(PassManagerRef)] pm 35 | # @return [nil] 36 | # @scope class 37 | attach_function :add_dead_arg_elimination_pass, :LLVMAddDeadArgEliminationPass, [:pointer], :void 38 | 39 | # See llvm::createFunctionAttrsPass function. 40 | # 41 | # @method add_function_attrs_pass(pm) 42 | # @param [FFI::Pointer(PassManagerRef)] pm 43 | # @return [nil] 44 | # @scope class 45 | attach_function :add_function_attrs_pass, :LLVMAddFunctionAttrsPass, [:pointer], :void 46 | 47 | # See llvm::createFunctionInliningPass function. 48 | # 49 | # @method add_function_inlining_pass(pm) 50 | # @param [FFI::Pointer(PassManagerRef)] pm 51 | # @return [nil] 52 | # @scope class 53 | attach_function :add_function_inlining_pass, :LLVMAddFunctionInliningPass, [:pointer], :void 54 | 55 | # See llvm::createAlwaysInlinerPass function. 56 | # 57 | # @method add_always_inliner_pass(pm) 58 | # @param [FFI::Pointer(PassManagerRef)] pm 59 | # @return [nil] 60 | # @scope class 61 | attach_function :add_always_inliner_pass, :LLVMAddAlwaysInlinerPass, [:pointer], :void 62 | 63 | # See llvm::createGlobalDCEPass function. 64 | # 65 | # @method add_global_dce_pass(pm) 66 | # @param [FFI::Pointer(PassManagerRef)] pm 67 | # @return [nil] 68 | # @scope class 69 | attach_function :add_global_dce_pass, :LLVMAddGlobalDCEPass, [:pointer], :void 70 | 71 | # See llvm::createGlobalOptimizerPass function. 72 | # 73 | # @method add_global_optimizer_pass(pm) 74 | # @param [FFI::Pointer(PassManagerRef)] pm 75 | # @return [nil] 76 | # @scope class 77 | attach_function :add_global_optimizer_pass, :LLVMAddGlobalOptimizerPass, [:pointer], :void 78 | 79 | # See llvm::createIPConstantPropagationPass function. 80 | # 81 | # @method add_ip_constant_propagation_pass(pm) 82 | # @param [FFI::Pointer(PassManagerRef)] pm 83 | # @return [nil] 84 | # @scope class 85 | attach_function :add_ip_constant_propagation_pass, :LLVMAddIPConstantPropagationPass, [:pointer], :void 86 | 87 | # See llvm::createPruneEHPass function. 88 | # 89 | # @method add_prune_eh_pass(pm) 90 | # @param [FFI::Pointer(PassManagerRef)] pm 91 | # @return [nil] 92 | # @scope class 93 | attach_function :add_prune_eh_pass, :LLVMAddPruneEHPass, [:pointer], :void 94 | 95 | # See llvm::createIPSCCPPass function. 96 | # 97 | # @method add_ipsccp_pass(pm) 98 | # @param [FFI::Pointer(PassManagerRef)] pm 99 | # @return [nil] 100 | # @scope class 101 | attach_function :add_ipsccp_pass, :LLVMAddIPSCCPPass, [:pointer], :void 102 | 103 | # See llvm::createInternalizePass function. 104 | # 105 | # @method add_internalize_pass(pass_manager_ref, all_but_main) 106 | # @param [FFI::Pointer(PassManagerRef)] pass_manager_ref 107 | # @param [Integer] all_but_main 108 | # @return [nil] 109 | # @scope class 110 | attach_function :add_internalize_pass, :LLVMAddInternalizePass, [:pointer, :uint], :void 111 | 112 | # See llvm::createStripDeadPrototypesPass function. 113 | # 114 | # @method add_strip_dead_prototypes_pass(pm) 115 | # @param [FFI::Pointer(PassManagerRef)] pm 116 | # @return [nil] 117 | # @scope class 118 | attach_function :add_strip_dead_prototypes_pass, :LLVMAddStripDeadPrototypesPass, [:pointer], :void 119 | 120 | # See llvm::createStripSymbolsPass function. 121 | # 122 | # @method add_strip_symbols_pass(pm) 123 | # @param [FFI::Pointer(PassManagerRef)] pm 124 | # @return [nil] 125 | # @scope class 126 | attach_function :add_strip_symbols_pass, :LLVMAddStripSymbolsPass, [:pointer], :void 127 | 128 | end 129 | -------------------------------------------------------------------------------- /lib/llvm/transforms/scalar.rb: -------------------------------------------------------------------------------- 1 | require 'llvm' 2 | require 'llvm/core' 3 | require 'llvm/transforms/scalar_ffi' 4 | 5 | module LLVM 6 | class PassManager 7 | # @LLVMpass adce 8 | def adce! 9 | C.add_aggressive_dce_pass(self) 10 | end 11 | 12 | # @LLVMpass simplifycfg 13 | def simplifycfg! 14 | C.add_cfg_simplification_pass(self) 15 | end 16 | 17 | # @LLVMpass dse 18 | def dse! 19 | C.add_dead_store_elimination_pass(self) 20 | end 21 | 22 | # @LLVMpass gvn 23 | def gvn! 24 | C.add_gvn_pass(self) 25 | end 26 | 27 | # @LLVMpass indvars 28 | def indvars! 29 | C.add_ind_var_simplify_pass(self) 30 | end 31 | 32 | # @LLVMpass instcombine 33 | def instcombine! 34 | C.add_instruction_combining_pass(self) 35 | end 36 | 37 | # @LLVMpass jump-threading 38 | def jump_threading! 39 | C.add_jump_threading_pass(self) 40 | end 41 | 42 | # @LLVMpass licm 43 | def licm! 44 | C.add_licm_pass(self) 45 | end 46 | 47 | # @LLVMpass loop-deletion 48 | def loop_deletion! 49 | C.add_loop_deletion_pass(self) 50 | end 51 | 52 | # @LLVMpass loop-rotate 53 | def loop_rotate! 54 | C.add_loop_rotate_pass(self) 55 | end 56 | 57 | # @LLVMpass loop-unroll 58 | def loop_unroll! 59 | C.add_loop_unroll_pass(self) 60 | end 61 | 62 | # @LLVMpass loop-unswitch 63 | def loop_unswitch! 64 | C.add_loop_unswitch_pass(self) 65 | end 66 | 67 | # @LLVMpass memcpyopt 68 | def memcpyopt! 69 | C.add_mem_cpy_opt_pass(self) 70 | end 71 | 72 | # @LLVMpass mem2reg 73 | def mem2reg! 74 | C.add_promote_memory_to_register_pass(self) 75 | end 76 | 77 | # @LLVMpass reassociate 78 | def reassociate! 79 | C.add_reassociate_pass(self) 80 | end 81 | 82 | # @LLVMpass sccp 83 | def sccp! 84 | C.add_sccp_pass(self) 85 | end 86 | 87 | # @LLVMpass scalarrepl 88 | def scalarrepl! 89 | C.add_scalar_repl_aggregates_pass(self) 90 | end 91 | 92 | # @LLVMpass simplify-libcalls 93 | def simplify_libcalls! 94 | C.add_simplify_lib_calls_pass(self) 95 | end 96 | 97 | # @LLVMpass tailcallelim 98 | def tailcallelim! 99 | C.add_tail_call_elimination_pass(self) 100 | end 101 | 102 | # @LLVMpass constprop 103 | def constprop! 104 | C.add_constant_propagation_pass(self) 105 | end 106 | 107 | # @LLVMpass reg2mem 108 | def reg2mem! 109 | C.add_demote_memory_to_register_pass(self) 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /lib/llvm/transforms/scalar_ffi.rb: -------------------------------------------------------------------------------- 1 | # Generated by ffi_gen. Please do not change this file by hand. 2 | 3 | require 'ffi' 4 | 5 | module LLVM::C 6 | extend FFI::Library 7 | ffi_lib 'LLVM-3.1' 8 | 9 | def self.attach_function(name, *_) 10 | begin; super; rescue FFI::NotFoundError => e 11 | (class << self; self; end).class_eval { define_method(name) { |*_| raise e } } 12 | end 13 | end 14 | 15 | # (Not documented) 16 | # 17 | # @method add_aggressive_dce_pass(pm) 18 | # @param [FFI::Pointer(PassManagerRef)] pm 19 | # @return [nil] 20 | # @scope class 21 | attach_function :add_aggressive_dce_pass, :LLVMAddAggressiveDCEPass, [:pointer], :void 22 | 23 | # See llvm::createCFGSimplificationPass function. 24 | # 25 | # @method add_cfg_simplification_pass(pm) 26 | # @param [FFI::Pointer(PassManagerRef)] pm 27 | # @return [nil] 28 | # @scope class 29 | attach_function :add_cfg_simplification_pass, :LLVMAddCFGSimplificationPass, [:pointer], :void 30 | 31 | # See llvm::createDeadStoreEliminationPass function. 32 | # 33 | # @method add_dead_store_elimination_pass(pm) 34 | # @param [FFI::Pointer(PassManagerRef)] pm 35 | # @return [nil] 36 | # @scope class 37 | attach_function :add_dead_store_elimination_pass, :LLVMAddDeadStoreEliminationPass, [:pointer], :void 38 | 39 | # See llvm::createGVNPass function. 40 | # 41 | # @method add_gvn_pass(pm) 42 | # @param [FFI::Pointer(PassManagerRef)] pm 43 | # @return [nil] 44 | # @scope class 45 | attach_function :add_gvn_pass, :LLVMAddGVNPass, [:pointer], :void 46 | 47 | # See llvm::createIndVarSimplifyPass function. 48 | # 49 | # @method add_ind_var_simplify_pass(pm) 50 | # @param [FFI::Pointer(PassManagerRef)] pm 51 | # @return [nil] 52 | # @scope class 53 | attach_function :add_ind_var_simplify_pass, :LLVMAddIndVarSimplifyPass, [:pointer], :void 54 | 55 | # See llvm::createInstructionCombiningPass function. 56 | # 57 | # @method add_instruction_combining_pass(pm) 58 | # @param [FFI::Pointer(PassManagerRef)] pm 59 | # @return [nil] 60 | # @scope class 61 | attach_function :add_instruction_combining_pass, :LLVMAddInstructionCombiningPass, [:pointer], :void 62 | 63 | # See llvm::createJumpThreadingPass function. 64 | # 65 | # @method add_jump_threading_pass(pm) 66 | # @param [FFI::Pointer(PassManagerRef)] pm 67 | # @return [nil] 68 | # @scope class 69 | attach_function :add_jump_threading_pass, :LLVMAddJumpThreadingPass, [:pointer], :void 70 | 71 | # See llvm::createLICMPass function. 72 | # 73 | # @method add_licm_pass(pm) 74 | # @param [FFI::Pointer(PassManagerRef)] pm 75 | # @return [nil] 76 | # @scope class 77 | attach_function :add_licm_pass, :LLVMAddLICMPass, [:pointer], :void 78 | 79 | # See llvm::createLoopDeletionPass function. 80 | # 81 | # @method add_loop_deletion_pass(pm) 82 | # @param [FFI::Pointer(PassManagerRef)] pm 83 | # @return [nil] 84 | # @scope class 85 | attach_function :add_loop_deletion_pass, :LLVMAddLoopDeletionPass, [:pointer], :void 86 | 87 | # See llvm::createLoopIdiomPass function 88 | # 89 | # @method add_loop_idiom_pass(pm) 90 | # @param [FFI::Pointer(PassManagerRef)] pm 91 | # @return [nil] 92 | # @scope class 93 | attach_function :add_loop_idiom_pass, :LLVMAddLoopIdiomPass, [:pointer], :void 94 | 95 | # See llvm::createLoopRotatePass function. 96 | # 97 | # @method add_loop_rotate_pass(pm) 98 | # @param [FFI::Pointer(PassManagerRef)] pm 99 | # @return [nil] 100 | # @scope class 101 | attach_function :add_loop_rotate_pass, :LLVMAddLoopRotatePass, [:pointer], :void 102 | 103 | # See llvm::createLoopUnrollPass function. 104 | # 105 | # @method add_loop_unroll_pass(pm) 106 | # @param [FFI::Pointer(PassManagerRef)] pm 107 | # @return [nil] 108 | # @scope class 109 | attach_function :add_loop_unroll_pass, :LLVMAddLoopUnrollPass, [:pointer], :void 110 | 111 | # See llvm::createLoopUnswitchPass function. 112 | # 113 | # @method add_loop_unswitch_pass(pm) 114 | # @param [FFI::Pointer(PassManagerRef)] pm 115 | # @return [nil] 116 | # @scope class 117 | attach_function :add_loop_unswitch_pass, :LLVMAddLoopUnswitchPass, [:pointer], :void 118 | 119 | # See llvm::createMemCpyOptPass function. 120 | # 121 | # @method add_mem_cpy_opt_pass(pm) 122 | # @param [FFI::Pointer(PassManagerRef)] pm 123 | # @return [nil] 124 | # @scope class 125 | attach_function :add_mem_cpy_opt_pass, :LLVMAddMemCpyOptPass, [:pointer], :void 126 | 127 | # See llvm::createPromoteMemoryToRegisterPass function. 128 | # 129 | # @method add_promote_memory_to_register_pass(pm) 130 | # @param [FFI::Pointer(PassManagerRef)] pm 131 | # @return [nil] 132 | # @scope class 133 | attach_function :add_promote_memory_to_register_pass, :LLVMAddPromoteMemoryToRegisterPass, [:pointer], :void 134 | 135 | # See llvm::createReassociatePass function. 136 | # 137 | # @method add_reassociate_pass(pm) 138 | # @param [FFI::Pointer(PassManagerRef)] pm 139 | # @return [nil] 140 | # @scope class 141 | attach_function :add_reassociate_pass, :LLVMAddReassociatePass, [:pointer], :void 142 | 143 | # See llvm::createSCCPPass function. 144 | # 145 | # @method add_sccp_pass(pm) 146 | # @param [FFI::Pointer(PassManagerRef)] pm 147 | # @return [nil] 148 | # @scope class 149 | attach_function :add_sccp_pass, :LLVMAddSCCPPass, [:pointer], :void 150 | 151 | # See llvm::createScalarReplAggregatesPass function. 152 | # 153 | # @method add_scalar_repl_aggregates_pass(pm) 154 | # @param [FFI::Pointer(PassManagerRef)] pm 155 | # @return [nil] 156 | # @scope class 157 | attach_function :add_scalar_repl_aggregates_pass, :LLVMAddScalarReplAggregatesPass, [:pointer], :void 158 | 159 | # See llvm::createScalarReplAggregatesPass function. 160 | # 161 | # @method add_scalar_repl_aggregates_pass_ssa(pm) 162 | # @param [FFI::Pointer(PassManagerRef)] pm 163 | # @return [nil] 164 | # @scope class 165 | attach_function :add_scalar_repl_aggregates_pass_ssa, :LLVMAddScalarReplAggregatesPassSSA, [:pointer], :void 166 | 167 | # See llvm::createScalarReplAggregatesPass function. 168 | # 169 | # @method add_scalar_repl_aggregates_pass_with_threshold(pm, threshold) 170 | # @param [FFI::Pointer(PassManagerRef)] pm 171 | # @param [Integer] threshold 172 | # @return [nil] 173 | # @scope class 174 | attach_function :add_scalar_repl_aggregates_pass_with_threshold, :LLVMAddScalarReplAggregatesPassWithThreshold, [:pointer, :int], :void 175 | 176 | # See llvm::createSimplifyLibCallsPass function. 177 | # 178 | # @method add_simplify_lib_calls_pass(pm) 179 | # @param [FFI::Pointer(PassManagerRef)] pm 180 | # @return [nil] 181 | # @scope class 182 | attach_function :add_simplify_lib_calls_pass, :LLVMAddSimplifyLibCallsPass, [:pointer], :void 183 | 184 | # See llvm::createTailCallEliminationPass function. 185 | # 186 | # @method add_tail_call_elimination_pass(pm) 187 | # @param [FFI::Pointer(PassManagerRef)] pm 188 | # @return [nil] 189 | # @scope class 190 | attach_function :add_tail_call_elimination_pass, :LLVMAddTailCallEliminationPass, [:pointer], :void 191 | 192 | # See llvm::createConstantPropagationPass function. 193 | # 194 | # @method add_constant_propagation_pass(pm) 195 | # @param [FFI::Pointer(PassManagerRef)] pm 196 | # @return [nil] 197 | # @scope class 198 | attach_function :add_constant_propagation_pass, :LLVMAddConstantPropagationPass, [:pointer], :void 199 | 200 | # See llvm::demotePromoteMemoryToRegisterPass function. 201 | # 202 | # @method add_demote_memory_to_register_pass(pm) 203 | # @param [FFI::Pointer(PassManagerRef)] pm 204 | # @return [nil] 205 | # @scope class 206 | attach_function :add_demote_memory_to_register_pass, :LLVMAddDemoteMemoryToRegisterPass, [:pointer], :void 207 | 208 | # See llvm::createVerifierPass function. 209 | # 210 | # @method add_verifier_pass(pm) 211 | # @param [FFI::Pointer(PassManagerRef)] pm 212 | # @return [nil] 213 | # @scope class 214 | attach_function :add_verifier_pass, :LLVMAddVerifierPass, [:pointer], :void 215 | 216 | # See llvm::createCorrelatedValuePropagationPass function 217 | # 218 | # @method add_correlated_value_propagation_pass(pm) 219 | # @param [FFI::Pointer(PassManagerRef)] pm 220 | # @return [nil] 221 | # @scope class 222 | attach_function :add_correlated_value_propagation_pass, :LLVMAddCorrelatedValuePropagationPass, [:pointer], :void 223 | 224 | # See llvm::createEarlyCSEPass function 225 | # 226 | # @method add_early_cse_pass(pm) 227 | # @param [FFI::Pointer(PassManagerRef)] pm 228 | # @return [nil] 229 | # @scope class 230 | attach_function :add_early_cse_pass, :LLVMAddEarlyCSEPass, [:pointer], :void 231 | 232 | # See llvm::createLowerExpectIntrinsicPass function 233 | # 234 | # @method add_lower_expect_intrinsic_pass(pm) 235 | # @param [FFI::Pointer(PassManagerRef)] pm 236 | # @return [nil] 237 | # @scope class 238 | attach_function :add_lower_expect_intrinsic_pass, :LLVMAddLowerExpectIntrinsicPass, [:pointer], :void 239 | 240 | # See llvm::createTypeBasedAliasAnalysisPass function 241 | # 242 | # @method add_type_based_alias_analysis_pass(pm) 243 | # @param [FFI::Pointer(PassManagerRef)] pm 244 | # @return [nil] 245 | # @scope class 246 | attach_function :add_type_based_alias_analysis_pass, :LLVMAddTypeBasedAliasAnalysisPass, [:pointer], :void 247 | 248 | # See llvm::createBasicAliasAnalysisPass function 249 | # 250 | # @method add_basic_alias_analysis_pass(pm) 251 | # @param [FFI::Pointer(PassManagerRef)] pm 252 | # @return [nil] 253 | # @scope class 254 | attach_function :add_basic_alias_analysis_pass, :LLVMAddBasicAliasAnalysisPass, [:pointer], :void 255 | 256 | end 257 | -------------------------------------------------------------------------------- /lib/llvm/version.rb: -------------------------------------------------------------------------------- 1 | module LLVM 2 | LLVM_VERSION = "3.1" 3 | RUBY_LLVM_VERSION = "3.1.0.beta.1" 4 | end 5 | -------------------------------------------------------------------------------- /ruby-llvm.gemspec: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(__FILE__), "lib/llvm/version") 2 | 3 | Gem::Specification.new do |s| 4 | s.platform = Gem::Platform::RUBY 5 | 6 | s.name = "ruby-llvm" 7 | s.version = LLVM::RUBY_LLVM_VERSION 8 | s.summary = "LLVM bindings for Ruby" 9 | s.description = "LLVM bindings for Ruby" 10 | s.author = "Jeremy Voorhis" 11 | s.email = "jvoorhis@gmail.com" 12 | s.homepage = "http://github.com/jvoorhis/ruby-llvm" 13 | 14 | s.add_dependency("ffi", ">= 1.0.0") 15 | s.add_development_dependency("ffi_gen", ">= 1.1.0") 16 | s.add_development_dependency("rake") 17 | s.add_development_dependency("rcov") 18 | s.add_development_dependency("yard") 19 | s.files = Dir["lib/**/*rb"] + Dir["ext/**/*"] 20 | s.require_path = "lib" 21 | s.extensions << "ext/ruby-llvm-support/Rakefile" 22 | 23 | s.test_files = Dir["test/**/*.rb"] 24 | 25 | s.has_rdoc = true 26 | s.extra_rdoc_files = "README.rdoc" 27 | end 28 | -------------------------------------------------------------------------------- /samples/factorial.rb: -------------------------------------------------------------------------------- 1 | require 'llvm/core' 2 | require 'llvm/execution_engine' 3 | require 'llvm/transforms/scalar' 4 | 5 | LLVM.init_x86 6 | 7 | mod = LLVM::Module.new("Factorial") 8 | 9 | mod.functions.add("fac", [LLVM::Int], LLVM::Int) do |fac, n| 10 | n.name = "n" 11 | entry = fac.basic_blocks.append("entry") 12 | recur = fac.basic_blocks.append("recur") 13 | result = fac.basic_blocks.append("result") 14 | n_fac_n_1 = nil # predeclare within function's scope 15 | 16 | entry.build do |b| 17 | test = b.icmp(:eq, n, LLVM::Int(1), "test") 18 | b.cond(test, result, recur) 19 | end 20 | 21 | recur.build do |b| 22 | n_1 = b.sub(n, LLVM::Int(1), "n-1") 23 | fac_n_1 = b.call(fac, n_1, "fac(n-1)") 24 | n_fac_n_1 = b.mul(n, fac_n_1, "n*fac(n-1)") 25 | b.br(result) 26 | end 27 | 28 | result.build do |b| 29 | fac = b.phi(LLVM::Int, 30 | { entry => LLVM::Int(1), 31 | recur => n_fac_n_1 }, 32 | "fac") 33 | b.ret(fac) 34 | end 35 | end 36 | 37 | mod.verify 38 | 39 | puts 40 | mod.dump 41 | 42 | engine = LLVM::JITCompiler.new(mod) 43 | 44 | arg = (ARGV[0] || 6).to_i 45 | value = engine.run_function(mod.functions["fac"], arg) 46 | 47 | printf("\nfac(%i) = %i\n\n", arg, value) 48 | 49 | -------------------------------------------------------------------------------- /samples/fp.rb: -------------------------------------------------------------------------------- 1 | require 'llvm/core' 2 | require 'llvm/execution_engine' 3 | require 'llvm/transforms/scalar' 4 | 5 | LLVM.init_x86 6 | 7 | mod = LLVM::Module.new("Function Pointers") 8 | 9 | F = LLVM::Function([LLVM::Int], LLVM::Int) 10 | FP = LLVM::Pointer(F) 11 | 12 | mod.functions.add("f", [LLVM::Int], LLVM::Int) do |f, n| 13 | f.basic_blocks.append("entry").build do |b| 14 | b.ret(b.add(LLVM::Int(1), n)) 15 | end 16 | end 17 | 18 | mod.functions.add("g", [FP, LLVM::Int], LLVM::Int) do |g, fp, n| 19 | g.basic_blocks.append("entry").build do |b| 20 | b.ret(b.call(fp, n)) 21 | end 22 | end 23 | 24 | mod.functions.add("test", [], LLVM::Int) do |test| 25 | test.basic_blocks.append("entry").build do |b| 26 | b.ret(b.call(mod.functions["g"], 27 | mod.functions["f"], 28 | LLVM::Int(41))) 29 | end 30 | end 31 | 32 | mod.verify 33 | mod.dump 34 | 35 | jit = LLVM::JITCompiler.new(mod) 36 | puts jit.run_function(mod.functions["test"]).to_i 37 | -------------------------------------------------------------------------------- /test/array_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ArrayTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_constant_array_from_size 10 | array = LLVM::ConstantArray.const(LLVM::Int, 2) { |i| LLVM::Int(i) } 11 | assert_instance_of LLVM::ConstantArray, array 12 | assert_equal 2, array.size 13 | end 14 | 15 | def test_constant_array_from_array 16 | array = LLVM::ConstantArray.const(LLVM::Int, [LLVM::Int(0), LLVM::Int(1)]) 17 | assert_instance_of LLVM::ConstantArray, array 18 | assert_equal 2, array.size 19 | end 20 | 21 | def test_array_values 22 | assert_equal 2 + 3, run_array_values(2, 3).to_i 23 | end 24 | 25 | def run_array_values(value1, value2) 26 | run_function([LLVM::Int, LLVM::Int], [value1, value2], LLVM::Int) do |builder, function, *arguments| 27 | entry = function.basic_blocks.append 28 | builder.position_at_end(entry) 29 | pointer = builder.alloca(LLVM::Array(LLVM::Int, 2)) 30 | array = builder.load(pointer) 31 | array = builder.insert_value(array, arguments.first, 0) 32 | array = builder.insert_value(array, arguments.last, 1) 33 | builder.ret(builder.add(builder.extract_value(array, 0), 34 | builder.extract_value(array, 1))) 35 | end 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /test/basic_block_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BasicBlockTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | @module = LLVM::Module.new("BasicBlockTestCase") 8 | end 9 | 10 | def test_basic_block_collection 11 | @module.functions.add("test_basic_block_collection", [], LLVM.Void) do |fn| 12 | coll = fn.basic_blocks 13 | 14 | block1 = coll.append 15 | assert_instance_of LLVM::BasicBlock, block1 16 | 17 | assert_equal 1, coll.size 18 | assert_equal coll.first, coll.last, 19 | 'Only one block exists in the function' 20 | assert_equal coll.first, coll.entry, 21 | 'The entry block for the function is always the first block' 22 | 23 | block2 = coll.append 24 | assert_equal 2, coll.size 25 | assert_equal block1, coll.first 26 | assert_equal block2, coll.last 27 | 28 | [ coll.each.to_a, coll.to_a ].each do |blocks| 29 | assert_equal 2, blocks.size 30 | assert_equal block1, blocks[0] 31 | assert_equal block2, blocks[1] 32 | end 33 | end 34 | end 35 | 36 | def test_basic_block 37 | @module.functions.add("test_basic_block", [], LLVM.Void) do |fn| 38 | coll = fn.basic_blocks 39 | 40 | block1 = coll.append 41 | block2 = coll.append 42 | 43 | assert_equal fn, block1.parent 44 | assert_equal fn, block2.parent 45 | 46 | assert_equal block2, block1.next 47 | assert_equal block1, block2.previous 48 | 49 | block1.build do |builder| 50 | builder.br(block2) 51 | end 52 | 53 | block2.build do |builder| 54 | builder.ret_void 55 | end 56 | 57 | assert_equal block1.first_instruction, 58 | block1.last_instruction 59 | assert_equal block2.first_instruction, 60 | block2.last_instruction 61 | end 62 | end 63 | 64 | def test_basic_block_enumerable 65 | @module.functions.add("test_basic_block_enumerable", [LLVM::Double], LLVM::Double) do |fn, arg| 66 | block1 = fn.basic_blocks.append 67 | 68 | [ block1.instructions.to_a, block1.instructions.each.to_a ].each do |insts| 69 | assert_equal 0, insts.size, 'Empty basic block' 70 | end 71 | 72 | block1.build do |builder| 73 | builder.ret(builder.fadd(arg, LLVM.Double(1.0))) 74 | end 75 | 76 | [ block1.instructions.to_a, block1.instructions.each.to_a ].each do |insts| 77 | assert_equal 2, insts.size 78 | assert_equal block1.first_instruction, insts[0] # deprecated 79 | assert_equal block1.last_instruction, insts[1] # deprecated 80 | assert_equal block1.instructions.first, insts[0] 81 | assert_equal block1.instructions.last, insts[1] 82 | end 83 | 84 | end 85 | end 86 | 87 | end 88 | 89 | -------------------------------------------------------------------------------- /test/basic_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BasicTestCase < Test::Unit::TestCase 4 | 5 | def test_llvm_initialization 6 | assert_nothing_raised do 7 | LLVM.init_x86 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/binary_operations_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BasicOperationsTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_integer_binary_operations 10 | integer_binary_operation_assertion(:add, 3, 2, 3 + 2) 11 | integer_binary_operation_assertion(:sub, 3, 2, 3 - 2) 12 | integer_binary_operation_assertion(:mul, 3, 2, 3 * 2) 13 | integer_binary_operation_assertion(:udiv, 10, 2, 10 / 2) 14 | integer_binary_operation_assertion(:sdiv, 10, 2, 10 / 2) 15 | integer_binary_operation_assertion(:urem, 10, 3, 10 % 3) 16 | integer_binary_operation_assertion(:srem, 10, 3, 10 % 3) 17 | end 18 | 19 | def test_integer_bitwise_binary_operations 20 | integer_binary_operation_assertion(:shl, 2, 3, 2 << 3) 21 | integer_binary_operation_assertion(:lshr, 16, 3, 16 >> 3) 22 | integer_binary_operation_assertion(:ashr, 16, 3, 16 >> 3) 23 | integer_binary_operation_assertion(:and, 2, 1, 2 & 1) 24 | integer_binary_operation_assertion(:or, 2, 1, 2 | 1) 25 | integer_binary_operation_assertion(:xor, 3, 2, 3 ^ 2) 26 | end 27 | 28 | def test_float_binary_operations 29 | float_binary_operation_assertion(:fadd, 3.1, 2.2, 3.1 + 2.2) 30 | float_binary_operation_assertion(:fsub, 3.1, 2.2, 3.1 - 2.2) 31 | float_binary_operation_assertion(:fmul, 3.1, 2.2, 3.1 * 2.2) 32 | float_binary_operation_assertion(:fdiv, 3.1, 2.2, 3.1 / 2.2) 33 | float_binary_operation_assertion(:frem, 3.1, 2.2, 3.1 % 2.2) 34 | end 35 | 36 | def integer_binary_operation_assertion(operation, operand1, operand2, expected_result) 37 | result = run_binary_operation(operation, 38 | LLVM::Int(operand1), LLVM::Int(operand2), 39 | LLVM::Int).to_i 40 | assert_equal expected_result, result 41 | end 42 | 43 | def float_binary_operation_assertion(operation, operand1, operand2, expected_result) 44 | result = run_binary_operation(operation, 45 | LLVM::Float(operand1), LLVM::Float(operand2), 46 | LLVM::Float).to_f 47 | assert_in_delta expected_result, result, 0.001 48 | end 49 | 50 | def run_binary_operation(operation, operand1, operand2, return_type) 51 | run_function([], [], return_type) do |builder, function, *arguments| 52 | entry = function.basic_blocks.append 53 | builder.position_at_end(entry) 54 | builder.ret(builder.send(operation, operand1, operand2)) 55 | end 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /test/bitcode_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | require "tempfile" 3 | 4 | class BitcodeTestCase < Test::Unit::TestCase 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_bitcode 10 | test_module = define_module("test_module") do |mod| 11 | define_function(mod, "test_function", [], LLVM::Int) do 12 | |builder, function, *arguments| 13 | entry = function.basic_blocks.append 14 | builder.position_at_end(entry) 15 | builder.ret(LLVM::Int(1)) 16 | end 17 | end 18 | Tempfile.open("bitcode") do |tmp| 19 | assert test_module.write_bitcode(tmp) 20 | new_module = LLVM::Module.parse_bitcode(tmp.path) 21 | result = run_function_on_module(new_module, "test_function").to_i 22 | assert_equal 1, result 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/branch_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BranchTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_branching 10 | assert_equal 0, direct_jump_function().to_i 11 | assert_equal 0, conditional_jump_function().to_i 12 | assert_equal 0, switched_jump_function().to_i 13 | end 14 | 15 | def direct_jump_function 16 | run_function([], [], LLVM::Int) do |builder, function, *arguments| 17 | entry = function.basic_blocks.append 18 | branch_1 = function.basic_blocks.append 19 | branch_2 = function.basic_blocks.append 20 | builder.position_at_end(entry) 21 | builder.br(branch_2) 22 | builder.position_at_end(branch_1) 23 | builder.ret(LLVM::Int(1)) 24 | builder.position_at_end(branch_2) 25 | builder.ret(LLVM::Int(0)) 26 | end 27 | end 28 | 29 | def conditional_jump_function 30 | run_function([], [], LLVM::Int) do |builder, function, *arguments| 31 | entry = function.basic_blocks.append 32 | branch_1 = function.basic_blocks.append 33 | branch_2 = function.basic_blocks.append 34 | builder.position_at_end(entry) 35 | builder.cond(builder.icmp(:eq, LLVM::Int(1), LLVM::Int(2)), branch_1, branch_2) 36 | builder.position_at_end(branch_1) 37 | builder.ret(LLVM::Int(1)) 38 | builder.position_at_end(branch_2) 39 | builder.ret(LLVM::Int(0)) 40 | end 41 | end 42 | 43 | def switched_jump_function 44 | run_function([], [], LLVM::Int) do |builder, function, *arguments| 45 | entry = function.basic_blocks.append 46 | branch_1 = function.basic_blocks.append 47 | branch_2 = function.basic_blocks.append 48 | builder.position_at_end(entry) 49 | switch = builder.switch(LLVM::Int(1), branch_1, LLVM::Int(1) => branch_2) 50 | builder.position_at_end(branch_1) 51 | builder.ret(LLVM::Int(1)) 52 | builder.position_at_end(branch_2) 53 | builder.ret(LLVM::Int(0)) 54 | end 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /test/call_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class CallTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_simple_call 10 | test_module = define_module("test_module") do |host_module| 11 | define_function(host_module, "test_function", [], LLVM::Int) do |builder, function, *arguments| 12 | entry = function.basic_blocks.append 13 | builder.position_at_end(entry) 14 | builder.ret(LLVM::Int(1)) 15 | end 16 | end 17 | assert_equal 1, run_function_on_module(test_module, "test_function").to_i 18 | end 19 | 20 | def test_nested_call 21 | test_module = define_module("test_module") do |host_module| 22 | function_1 = define_function(host_module, "test_function_1", [], LLVM::Int) do |builder, function, *arguments| 23 | entry = function.basic_blocks.append 24 | builder.position_at_end(entry) 25 | builder.ret(LLVM::Int(1)) 26 | end 27 | function_2 = define_function(host_module, "test_function_2", [], LLVM::Int) do |builder, function, *arguments| 28 | entry = function.basic_blocks.append 29 | builder.position_at_end(entry) 30 | builder.ret(builder.call(function_1)) 31 | end 32 | end 33 | assert_equal 1, run_function_on_module(test_module, "test_function_2").to_i 34 | end 35 | 36 | def test_recursive_call 37 | test_module = define_module("test_module") do |host_module| 38 | define_function(host_module, "test_function", [LLVM::Int], LLVM::Int) do |builder, function, *arguments| 39 | entry = function.basic_blocks.append 40 | recurse = function.basic_blocks.append 41 | exit = function.basic_blocks.append 42 | builder.position_at_end(entry) 43 | builder.cond(builder.icmp(:uge, arguments.first, LLVM::Int(5)), exit, recurse) 44 | builder.position_at_end(recurse) 45 | result = builder.call(function, builder.add(arguments.first, LLVM::Int(1))) 46 | builder.br(exit) 47 | builder.position_at_end(exit) 48 | builder.ret(builder.phi(LLVM::Int, entry => arguments.first, recurse => result)) 49 | end 50 | end 51 | assert_equal 5, run_function_on_module(test_module, "test_function", 1).to_i 52 | end 53 | 54 | def test_external 55 | test_module = define_module("test_module") do |host_module| 56 | external = host_module.functions.add("abs", [LLVM::Int], LLVM::Int) 57 | define_function(host_module, "test_function", [LLVM::Int], LLVM::Int) do |builder, function, *arguments| 58 | entry = function.basic_blocks.append 59 | builder.position_at_end(entry) 60 | builder.ret(builder.call(external, arguments.first)) 61 | end 62 | end 63 | assert_equal -10.abs, run_function_on_module(test_module, "test_function", -10).to_i 64 | end 65 | 66 | def test_external_string 67 | test_module = define_module("test_module") do |host_module| 68 | global = host_module.globals.add(LLVM::Array(LLVM::Int8, 5), "path") 69 | global.linkage = :internal 70 | global.initializer = LLVM::ConstantArray.string("PATH") 71 | external = host_module.functions.add("getenv", [LLVM::Pointer(LLVM::Int8)], LLVM::Pointer(LLVM::Int8)) 72 | define_function(host_module, "test_function", [], LLVM::Pointer(LLVM::Int8)) do |builder, function, *arguments| 73 | entry = function.basic_blocks.append 74 | builder.position_at_end(entry) 75 | parameter = builder.gep(global, [LLVM::Int(0), LLVM::Int(0)]) 76 | builder.ret(builder.call(external, parameter)) 77 | end 78 | end 79 | assert_equal ENV["PATH"], run_function_on_module(test_module, "test_function").to_ptr.read_pointer.read_string 80 | end 81 | 82 | end 83 | -------------------------------------------------------------------------------- /test/comparisons_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ComparisonsTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_integer_comparison 10 | integer_comparison_assertion(:eq, 1, 1, LLVM_SIGNED, LLVM_TRUE) 11 | integer_comparison_assertion(:ne, 1, 1, LLVM_SIGNED, LLVM_FALSE) 12 | integer_comparison_assertion(:ugt, 2, 2, LLVM_UNSIGNED, LLVM_FALSE) 13 | integer_comparison_assertion(:uge, 2, 1, LLVM_UNSIGNED, LLVM_TRUE) 14 | integer_comparison_assertion(:ult, 1, 1, LLVM_UNSIGNED, LLVM_FALSE) 15 | integer_comparison_assertion(:ule, 1, 2, LLVM_UNSIGNED, LLVM_TRUE) 16 | integer_comparison_assertion(:sgt, -2, 2, LLVM_SIGNED, LLVM_FALSE) 17 | integer_comparison_assertion(:sge, -2, 1, LLVM_SIGNED, LLVM_FALSE) 18 | integer_comparison_assertion(:slt, -1, 2, LLVM_SIGNED, LLVM_TRUE) 19 | integer_comparison_assertion(:sle, -1, 2, LLVM_SIGNED, LLVM_TRUE) 20 | end 21 | 22 | def test_float_comparison 23 | float_comparison_assertion(:oeq, 1.0, 1.0, LLVM_TRUE) 24 | float_comparison_assertion(:one, 1.0, 1.0, LLVM_FALSE) 25 | float_comparison_assertion(:ogt, 2.0, 2.0, LLVM_FALSE) 26 | float_comparison_assertion(:oge, 2.0, 1.0, LLVM_TRUE) 27 | float_comparison_assertion(:olt, 1.0, 1.0, LLVM_FALSE) 28 | float_comparison_assertion(:ole, 1.0, 2.0, LLVM_TRUE) 29 | float_comparison_assertion(:ord, 1.0, 2.0, LLVM_TRUE) 30 | float_comparison_assertion(:ueq, 1.0, 1.0, LLVM_TRUE) 31 | float_comparison_assertion(:une, 1.0, 1.0, LLVM_FALSE) 32 | float_comparison_assertion(:ugt, 2.0, 2.0, LLVM_FALSE) 33 | float_comparison_assertion(:uge, 2.0, 1.0, LLVM_TRUE) 34 | float_comparison_assertion(:ult, 1.0, 1.0, LLVM_FALSE) 35 | float_comparison_assertion(:ule, 1.0, 2.0, LLVM_TRUE) 36 | float_comparison_assertion(:uno, 1.0, 2.0, LLVM_FALSE) 37 | end 38 | 39 | def integer_comparison_assertion(operation, operand1, operand2, signed, expected_result) 40 | result = run_comparison_operation(:icmp, 41 | operation, 42 | LLVM::Int.from_i(operand1, signed), 43 | LLVM::Int.from_i(operand2, signed), 44 | LLVM::Int1).to_i(false) 45 | assert_equal expected_result, result 46 | end 47 | 48 | def float_comparison_assertion(operation, operand1, operand2, expected_result) 49 | result = run_comparison_operation(:fcmp, 50 | operation, 51 | LLVM::Float(operand1), 52 | LLVM::Float(operand2), 53 | LLVM::Int1).to_i(false) 54 | assert_equal expected_result, result 55 | end 56 | 57 | def run_comparison_operation(comparison_operation, comparison_operator, 58 | operand1, operand2, return_type) 59 | run_function([], [], return_type) do |builder, function, *arguments| 60 | entry = function.basic_blocks.append 61 | builder.position_at_end(entry) 62 | builder.ret(builder.send(comparison_operation, comparison_operator, operand1, operand2)) 63 | end 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /test/conversions_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ConversionsTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_trunc_to 10 | integer_conversion_assertion(:trunc, LLVM::Int32.from_i(257), LLVM::Int8, LLVM_UNSIGNED, 1) 11 | integer_conversion_assertion(:trunc, LLVM::Int32.from_i(123), LLVM::Int1, LLVM_UNSIGNED, 1) 12 | integer_conversion_assertion(:trunc, LLVM::Int32.from_i(122), LLVM::Int1, LLVM_UNSIGNED, 0) 13 | end 14 | 15 | def test_zext_to 16 | integer_conversion_assertion(:zext, LLVM::Int16.from_i(257), LLVM::Int32, LLVM_UNSIGNED, 257) 17 | end 18 | 19 | def test_sext_to 20 | integer_conversion_assertion(:sext, LLVM::Int1.from_i(1), LLVM::Int32, LLVM_SIGNED, -1) 21 | integer_conversion_assertion(:sext, LLVM::Int8.from_i(-1), LLVM::Int16, LLVM_UNSIGNED, 65535) 22 | end 23 | 24 | def test_fptrunc_to 25 | float_conversion_assertion(:fp_trunc, LLVM::Double(123.0), LLVM::Float, 123.0) 26 | end 27 | 28 | def test_fpext_to 29 | float_conversion_assertion(:fp_ext, LLVM::Float(123.0), LLVM::Double, 123.0) 30 | float_conversion_assertion(:fp_ext, LLVM::Float(123.0), LLVM::Float, 123.0) 31 | end 32 | 33 | def test_fptoui_to 34 | different_type_assertion(:fp2ui, LLVM::Double(123.3), LLVM::Int32, :integer, 123) 35 | different_type_assertion(:fp2ui, LLVM::Double(0.7), LLVM::Int32, :integer, 0) 36 | different_type_assertion(:fp2ui, LLVM::Double(1.7), LLVM::Int32, :integer, 1) 37 | end 38 | 39 | def test_fptosi_to 40 | different_type_assertion(:fp2si, LLVM::Double(-123.3), LLVM::Int32, :integer, -123) 41 | different_type_assertion(:fp2si, LLVM::Double(0.7), LLVM::Int32, :integer, 0) 42 | different_type_assertion(:fp2si, LLVM::Double(1.7), LLVM::Int32, :integer, 1) 43 | end 44 | 45 | def test_uitofp_to 46 | different_type_assertion(:ui2fp, LLVM::Int32.from_i(257), LLVM::Float, :float, 257.0) 47 | different_type_assertion(:ui2fp, LLVM::Int8.from_i(-1), LLVM::Double, :float, 255.0) 48 | end 49 | 50 | def test_sitofp_to 51 | different_type_assertion(:si2fp, LLVM::Int32.from_i(257), LLVM::Float, :float, 257.0) 52 | different_type_assertion(:si2fp, LLVM::Int8.from_i(-1), LLVM::Double, :float, -1.0) 53 | end 54 | 55 | def test_bitcast_to 56 | different_type_assertion(:bit_cast, LLVM::Int8.from_i(255), LLVM::Int8, :integer, -1) 57 | end 58 | 59 | def test_int64 60 | integer_conversion_assertion(:zext, LLVM::Int64.from_i(2**62 + 123), LLVM::Int64, LLVM_SIGNED, 2**62 + 123) 61 | integer_conversion_assertion(:zext, LLVM::Int64.from_i(-2**62 - 123), LLVM::Int64, LLVM_SIGNED, -2**62 - 123) 62 | integer_conversion_assertion(:zext, LLVM::Int64.from_i(2**63 + 123), LLVM::Int64, LLVM_UNSIGNED, 2**63 + 123) 63 | end 64 | 65 | def integer_conversion_assertion(operation, operand, return_type, signed, expected_result) 66 | result = run_conversion_operation(operation, operand, return_type) 67 | assert_equal expected_result, result.to_i(signed) 68 | end 69 | 70 | def float_conversion_assertion(operation, operand, return_type, expected_result) 71 | result = run_conversion_operation(operation, operand, return_type) 72 | assert_in_delta expected_result, result.to_f(return_type), 0.001 73 | end 74 | 75 | def different_type_assertion(operation, operand, return_type, assertion_type, expected_result) 76 | result = run_conversion_operation(operation, operand, return_type) 77 | if assertion_type == :integer 78 | assert_equal expected_result, result.to_i 79 | else 80 | assert_in_delta expected_result, result.to_f(return_type), 0.001 81 | end 82 | end 83 | 84 | def run_conversion_operation(operation, operand, return_type) 85 | run_function([], [], return_type) do |builder, function, *arguments| 86 | entry = function.basic_blocks.append 87 | builder.position_at_end(entry) 88 | builder.ret(builder.send(operation, operand, return_type)) 89 | end 90 | end 91 | 92 | end 93 | -------------------------------------------------------------------------------- /test/double_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class DoubleTestCase < Test::Unit::TestCase 4 | def setup 5 | LLVM.init_x86 6 | end 7 | 8 | def test_double 9 | mod = LLVM::Module.new("Double Test") 10 | mod.functions.add(:sin, [LLVM::Double], LLVM::Double) 11 | 12 | builder = LLVM::Builder.new 13 | 14 | mod.functions.add('test', [LLVM::Double], LLVM::Double) do |fun, p0| 15 | p0.name = 'x' 16 | 17 | bb = fun.basic_blocks.append 18 | builder.position_at_end(bb) 19 | 20 | builder.ret(builder.fadd(p0, LLVM::Double(1.0))) 21 | end 22 | 23 | engine = LLVM::JITCompiler.new(mod) 24 | 25 | arg = 5.0 26 | result = engine.run_function(mod.functions["test"], arg) 27 | assert_equal arg+1, result.to_f(LLVM::Double) 28 | 29 | assert_in_delta(Math.sin(1.0), 30 | engine.run_function(mod.functions["sin"], 1.0).to_f(LLVM::Double), 31 | 1e-10) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/equality_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | require "llvm/core" 3 | 4 | class EqualityTestCase < Test::Unit::TestCase 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | class MyModule < LLVM::Module; end 10 | class MyInt < LLVM::Int32; end 11 | class MyType < LLVM::Type; end 12 | class MyFunction < LLVM::Function; end 13 | 14 | def assert_equalities(options) 15 | map = { 16 | :equal => method(:assert_equal), 17 | :not_equal => method(:assert_not_equal), 18 | :same => method(:assert_same), 19 | :not_same => method(:assert_not_same), 20 | :eql => lambda {|n, m, name| assert n.eql?(m), name }, 21 | :not_eql => lambda {|n, m, name| assert !n.eql?(m), name }, 22 | } 23 | 24 | map.each do |name, callable| 25 | options[name].combination(2).each do |n, m| 26 | callable.call(n, m, name.to_s) 27 | end 28 | end 29 | 30 | end 31 | 32 | def test_int_value 33 | int1 = LLVM::Int32.from_i(1) 34 | int2 = LLVM::Int32.from_ptr(int1.to_ptr) 35 | int3 = LLVM::Int32.from_i(2) 36 | int4 = MyInt.from_ptr(int1.to_ptr) 37 | 38 | assert_equalities :equal => [int1, int2, int4], 39 | :not_equal => [int1, int3], 40 | :same => [int1, int1], 41 | :not_same => [int1, int2, int3, int4], 42 | :eql => [int1, int2], 43 | :not_eql => [int1, int3, int4] 44 | end 45 | 46 | def test_module 47 | mod1 = LLVM::Module.new('test') 48 | mod2 = LLVM::Module.from_ptr(mod1.to_ptr) 49 | mod3 = LLVM::Module.new('dummy') 50 | mod4 = MyModule.from_ptr(mod1.to_ptr) 51 | 52 | assert_equalities :equal => [mod1, mod2, mod4], 53 | :not_equal => [mod1, mod3], 54 | :same => [mod1, mod1], 55 | :not_same => [mod1, mod2, mod3, mod4], 56 | :eql => [mod1, mod2], 57 | :not_eql => [mod1, mod3, mod4] 58 | end 59 | 60 | def test_type 61 | type1 = LLVM::Float.type 62 | type2 = LLVM::Type.from_ptr(type1.to_ptr, nil) 63 | type3 = LLVM::Double.type 64 | type4 = MyType.from_ptr(type1.to_ptr, :mytype) 65 | 66 | assert_equalities :equal => [type1, type2, type4], 67 | :not_equal => [type1, type3], 68 | :same => [type1, type1], 69 | :not_same => [type1, type2, type3, type4], 70 | :eql => [type1, type2], 71 | :not_eql => [type1, type3, type4] 72 | end 73 | 74 | def test_function 75 | mod = LLVM::Module.new('test') 76 | 77 | fn1 = mod.functions.add('test1', [], LLVM.Void) 78 | fn2 = LLVM::Function.from_ptr(fn1.to_ptr) 79 | fn3 = mod.functions.add('test2', [], LLVM.Void) 80 | fn4 = MyFunction.from_ptr(fn1.to_ptr) 81 | 82 | assert_equalities :equal => [fn1, fn2, fn4], 83 | :not_equal => [fn1, fn3], 84 | :same => [fn1, fn1], 85 | :not_same => [fn1, fn2, fn3, fn4], 86 | :eql => [fn1, fn2], 87 | :not_eql => [fn1, fn3, fn4] 88 | end 89 | 90 | end 91 | 92 | -------------------------------------------------------------------------------- /test/generic_value_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class GenericValueTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_from_i 10 | assert_equal 2, LLVM::GenericValue.from_i(2).to_i 11 | assert_equal 2 ,LLVM::GenericValue.from_i(2.2).to_i 12 | end 13 | 14 | def test_from_float 15 | assert_in_delta 2.2, LLVM::GenericValue.from_f(2.2).to_f, 1e-6 16 | end 17 | 18 | def test_from_double 19 | assert_in_delta 2.2, LLVM::GenericValue.from_d(2.2).to_f(LLVM::Double), 1e-6 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /test/instruction_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class InstructionTestCase < Test::Unit::TestCase 4 | def setup 5 | LLVM.init_x86 6 | @module = LLVM::Module.new("InstructionTestCase") 7 | end 8 | 9 | def test_instruction 10 | fn = @module.functions.add("test_instruction", [LLVM::Double], LLVM::Double) do |fn, arg| 11 | fn.basic_blocks.append.build do |builder| 12 | builder.ret( 13 | builder.fadd(arg, LLVM.Double(3.0))) 14 | end 15 | end 16 | 17 | entry = fn.basic_blocks.entry 18 | 19 | inst1 = entry.instructions.first 20 | inst2 = entry.instructions.last 21 | 22 | assert_kind_of LLVM::Instruction, inst1 23 | assert_kind_of LLVM::Instruction, inst2 24 | 25 | assert_equal inst2, inst1.next 26 | assert_equal inst1, inst2.previous 27 | assert_equal entry, inst1.parent 28 | assert_equal entry, inst2.parent 29 | end 30 | end 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/ipo_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | require "llvm/core" 3 | require 'llvm/transforms/ipo' 4 | require 'llvm/core/pass_manager' 5 | 6 | class IPOTestCase < Test::Unit::TestCase 7 | 8 | def setup 9 | LLVM.init_x86 10 | end 11 | 12 | def test_gdce 13 | mod = LLVM::Module.new('test') 14 | 15 | fn1 = mod.functions.add("fn1", [], LLVM.Void) do |fn| 16 | fn.linkage = :internal 17 | fn.basic_blocks.append.build do |builder| 18 | builder.ret_void 19 | end 20 | end 21 | 22 | fn2 = mod.functions.add("fn2", [], LLVM.Void) do |fn| 23 | fn.linkage = :internal 24 | fn.basic_blocks.append.build do |builder| 25 | builder.ret_void 26 | end 27 | end 28 | 29 | main = mod.functions.add("main", [], LLVM.Void) do |fn| 30 | fn.basic_blocks.append.build do |builder| 31 | builder.call(fn1) 32 | builder.ret_void 33 | end 34 | end 35 | 36 | fns = mod.functions.to_a 37 | assert fns.include?(fn1) 38 | assert fns.include?(fn2) 39 | assert fns.include?(main) 40 | 41 | # optimize 42 | engine = LLVM::JITCompiler.new(mod) 43 | passm = LLVM::PassManager.new(engine) 44 | 45 | passm.gdce! 46 | passm.run(mod) 47 | 48 | fns = mod.functions.to_a 49 | assert fns.include?(fn1) 50 | assert !fns.include?(fn2), 'fn2 should be eliminated' 51 | assert fns.include?(main) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /test/memory_access_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class MemoryAccessTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_memory_access 10 | assert_equal 1 + 2, simple_memory_access_function(1, 2).to_i 11 | assert_equal 3 + 4, array_memory_access_function(3, 4).to_i 12 | end 13 | 14 | def simple_memory_access_function(value1, value2) 15 | run_function([LLVM::Int, LLVM::Int], [value1, value2], LLVM::Int) do |builder, function, *arguments| 16 | entry = function.basic_blocks.append 17 | builder.position_at_end(entry) 18 | pointer1 = builder.alloca(LLVM::Int) 19 | pointer2 = builder.alloca(LLVM::Int) 20 | builder.store(arguments.first, pointer1) 21 | builder.store(arguments.last, pointer2) 22 | builder.ret(builder.add(builder.load(pointer1), builder.load(pointer2))) 23 | end 24 | end 25 | 26 | def array_memory_access_function(value1, value2) 27 | run_function([LLVM::Int, LLVM::Int], [value1, value2], LLVM::Int) do |builder, function, *arguments| 28 | entry = function.basic_blocks.append 29 | builder.position_at_end(entry) 30 | pointer = builder.array_alloca(LLVM::Int, LLVM::Int(2)) 31 | builder.store(arguments.first, builder.gep(pointer, [LLVM::Int(0)])) 32 | builder.store(arguments.last, builder.gep(pointer, [LLVM::Int(1)])) 33 | builder.ret(builder.add(builder.load(builder.gep(pointer, [LLVM::Int(0)])), 34 | builder.load(builder.gep(pointer, [LLVM::Int(1)])))) 35 | end 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /test/module_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ModuleTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_simple_module 10 | assert_equal 1, simple_function().to_i 11 | end 12 | 13 | def simple_function 14 | run_function([], [], LLVM::Int) do |builder, function, *arguments| 15 | entry = function.basic_blocks.append 16 | builder.position_at_end(entry) 17 | builder.ret(LLVM::Int(1)) 18 | end 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /test/parameter_collection_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ParameterCollectionTestCase < Test::Unit::TestCase 4 | def setup 5 | @mod = LLVM::Module.new('test') 6 | @fun = @mod.functions.add('fun', [LLVM::Int, LLVM::Int], LLVM::Int) 7 | @fun.params[0].name = 'foo' 8 | @fun.params[1].name = 'bar' 9 | end 10 | 11 | def test_positive_index_in_range 12 | assert_equal 'foo', @fun.params[0].name 13 | assert_equal 'bar', @fun.params[1].name 14 | end 15 | 16 | def test_negative_index_in_range 17 | assert_equal 'foo', @fun.params[-2].name 18 | assert_equal 'bar', @fun.params[-1].name 19 | end 20 | 21 | def test_positive_index_out_of_range 22 | assert_nil @fun.params[2] 23 | end 24 | 25 | def test_negative_index_out_of_range 26 | assert_nil @fun.params[-3] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /test/phi_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class PhiTest < Test::Unit::TestCase 4 | def setup 5 | LLVM.init_x86 6 | end 7 | 8 | def test_phi 9 | assert_equal 1, run_phi_function(0).to_i 10 | assert_equal 0, run_phi_function(1).to_i 11 | end 12 | 13 | def run_phi_function(argument) 14 | run_function([LLVM::Int], argument, LLVM::Int) do |builder, function, *arguments| 15 | entry = function.basic_blocks.append 16 | block1 = function.basic_blocks.append 17 | block2 = function.basic_blocks.append 18 | exit = function.basic_blocks.append 19 | builder.position_at_end(entry) 20 | builder.cond(builder.icmp(:eq, arguments.first, LLVM::Int(0)), block1, block2) 21 | builder.position_at_end(block1) 22 | result1 = builder.add(arguments.first, LLVM::Int(1)) 23 | builder.br(exit) 24 | builder.position_at_end(block2) 25 | result2 = builder.sub(arguments.first, LLVM::Int(1)) 26 | builder.br(exit) 27 | builder.position_at_end(exit) 28 | builder.ret(builder.phi(LLVM::Int, 29 | block1 => result1, 30 | block2 => result2)) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/select_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class SelectTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_select 10 | assert_equal 0, select_function(1).to_i 11 | assert_equal 1, select_function(0).to_i 12 | end 13 | 14 | def select_function(value) 15 | run_function([LLVM::Int1], [value], LLVM::Int) do |builder, function, *arguments| 16 | entry = function.basic_blocks.append 17 | builder.position_at_end(entry) 18 | builder.ret(builder.select(arguments.first, LLVM::Int(0), LLVM::Int(1))) 19 | end 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /test/struct_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class StructTestCase < Test::Unit::TestCase 4 | 5 | LLVM_UNPACKED = false 6 | LLVM_PACKED = true 7 | 8 | def setup 9 | LLVM.init_x86 10 | end 11 | 12 | def test_simple_struct 13 | struct = LLVM::Struct(LLVM::Int, LLVM::Float) 14 | assert_instance_of LLVM::StructType, struct 15 | assert_equal 2, struct.element_types.size 16 | assert_equal LLVM::Int.type, struct.element_types[0] 17 | assert_equal LLVM::Float.type, struct.element_types[1] 18 | end 19 | 20 | def test_named_struct 21 | struct = LLVM::Struct(LLVM::Int, LLVM::Float, "struct100") 22 | assert_instance_of LLVM::StructType, struct 23 | assert_equal "struct100", struct.name 24 | end 25 | 26 | def test_deferred_element_type_setting 27 | struct = LLVM::Struct("struct200") 28 | struct.element_types = [LLVM::Int, LLVM::Float] 29 | assert_equal 2, struct.element_types.size 30 | end 31 | 32 | def test_unpacked_constant_struct_from_size 33 | struct = LLVM::ConstantStruct.const(2, LLVM_UNPACKED) { |i| LLVM::Int(i) } 34 | assert_instance_of LLVM::ConstantStruct, struct 35 | assert_equal 2, struct.operands.size 36 | end 37 | 38 | def test_unpacked_constant_struct_from_struct 39 | struct = LLVM::ConstantStruct.const([LLVM::Int(0), LLVM::Int(1)], LLVM_UNPACKED) 40 | assert_instance_of LLVM::ConstantStruct, struct 41 | assert_equal 2, struct.operands.size 42 | end 43 | 44 | def test_packed_constant_struct_from_size 45 | struct = LLVM::ConstantStruct.const(2, LLVM_PACKED) { |i| LLVM::Int(i) } 46 | assert_instance_of LLVM::ConstantStruct, struct 47 | assert_equal 2, struct.operands.size 48 | end 49 | 50 | def test_packed_constant_struct_from_struct 51 | struct = LLVM::ConstantStruct.const([LLVM::Int(0), LLVM::Int(1)], LLVM_PACKED) 52 | assert_instance_of LLVM::ConstantStruct, struct 53 | assert_equal 2, struct.operands.size 54 | end 55 | 56 | def test_struct_values 57 | assert_equal 2 + 3, run_struct_values(2, 3).to_i 58 | end 59 | 60 | def test_struct_access 61 | assert_in_delta 2 + 3.3, run_struct_access(LLVM::Float, 2, 3.3).to_f, 0.001 62 | end 63 | 64 | def run_struct_values(value1, value2) 65 | run_function([LLVM::Int, LLVM::Int], [value1, value2], LLVM::Int) do |builder, function, *arguments| 66 | entry = function.basic_blocks.append 67 | builder.position_at_end(entry) 68 | pointer = builder.alloca(LLVM::Struct(LLVM::Int, LLVM::Int)) 69 | struct = builder.load(pointer) 70 | struct = builder.insert_value(struct, arguments.first, 0) 71 | struct = builder.insert_value(struct, arguments.last, 1) 72 | builder.ret(builder.add(builder.extract_value(struct, 0), 73 | builder.extract_value(struct, 1))) 74 | end 75 | end 76 | 77 | def run_struct_access(return_type, value1, value2) 78 | run_function([LLVM::Int, LLVM::Float], [value1, value2], return_type) do |builder, function, *arguments| 79 | entry = function.basic_blocks.append 80 | builder.position_at_end(entry) 81 | pointer = builder.alloca(LLVM::Struct(LLVM::Float, LLVM::Struct(LLVM::Int, LLVM::Float), LLVM::Int)) 82 | builder.store(arguments.first, builder.gep(pointer, [LLVM::Int(0), LLVM::Int32.from_i(1), LLVM::Int32.from_i(0)])) 83 | builder.store(arguments.last, builder.gep(pointer, [LLVM::Int(0), LLVM::Int32.from_i(1), LLVM::Int32.from_i(1)])) 84 | address1 = builder.gep(pointer, [LLVM::Int(0), LLVM::Int32.from_i(1), LLVM::Int32.from_i(0)]) 85 | address2 = builder.gep(pointer, [LLVM::Int(0), LLVM::Int32.from_i(1), LLVM::Int32.from_i(1)]) 86 | builder.ret(builder.fadd(builder.ui2fp(builder.load(address1), LLVM::Float), builder.load(address2))) 87 | end 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib")) 2 | 3 | begin 4 | require "ruby-debug" 5 | rescue LoadError 6 | # Ignore ruby-debug is case it's not installed 7 | end 8 | 9 | require "test/unit" 10 | 11 | require "llvm/core" 12 | require "llvm/execution_engine" 13 | require "llvm/transforms/scalar" 14 | 15 | class Test::Unit::TestCase 16 | 17 | LLVM_SIGNED = true 18 | LLVM_UNSIGNED = false 19 | 20 | LLVM_FALSE = 0 21 | LLVM_TRUE = 1 22 | 23 | end 24 | 25 | def define_module(module_name) 26 | new_module = LLVM::Module.new(module_name) 27 | yield new_module 28 | new_module.verify 29 | new_module 30 | end 31 | 32 | def define_function(host_module, function_name, argument_types, return_type) 33 | host_module.functions.add(function_name, argument_types, return_type) do |function, *arguments| 34 | yield(LLVM::Builder.new, function, *arguments) 35 | end 36 | end 37 | 38 | def run_function_on_module(host_module, function_name, *argument_values) 39 | LLVM::JITCompiler.new(host_module). 40 | run_function(host_module.functions[function_name], *argument_values) 41 | end 42 | 43 | def run_function(argument_types, argument_values, return_type, &block) 44 | test_module = define_module("test_module") do |host_module| 45 | define_function(host_module, "test_function", argument_types, return_type, &block) 46 | end 47 | 48 | run_function_on_module(test_module, "test_function", *argument_values) 49 | end 50 | 51 | -------------------------------------------------------------------------------- /test/type_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class TypeTestCase < Test::Unit::TestCase 4 | 5 | def test_element_type 6 | pointer = LLVM.Pointer(LLVM::Int32.type) 7 | pointee = pointer.element_type 8 | 9 | assert_equal :pointer, pointer.kind 10 | assert_equal :integer, pointee.kind 11 | 12 | assert_nil pointee.element_type 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /test/vector_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class VectorTestCase < Test::Unit::TestCase 4 | 5 | def setup 6 | LLVM.init_x86 7 | end 8 | 9 | def test_all_ones_vector 10 | assert_raise(NotImplementedError) do 11 | LLVM::ConstantVector.all_ones 12 | end 13 | end 14 | 15 | def test_constant_vector_from_size 16 | vector = LLVM::ConstantVector.const(2) { |i| LLVM::Int(i) } 17 | assert_instance_of LLVM::ConstantVector, vector 18 | assert_equal 2, vector.size 19 | end 20 | 21 | def test_constant_vector_from_array 22 | vector = LLVM::ConstantVector.const([LLVM::Int(0), LLVM::Int(1)]) 23 | assert_instance_of LLVM::ConstantVector, vector 24 | assert_equal 2, vector.size 25 | end 26 | 27 | def test_vector_elements 28 | assert_equal 2 + 3, run_vector_elements(2, 3).to_i 29 | end 30 | 31 | def test_vector_shuffle 32 | assert_equal 1 + 4, run_vector_shuffle(1, 2, 3, 4).to_i 33 | end 34 | 35 | def run_vector_elements(value1, value2) 36 | run_function([LLVM::Int, LLVM::Int], [value1, value2], LLVM::Int) do |builder, function, *arguments| 37 | entry = function.basic_blocks.append 38 | builder.position_at_end(entry) 39 | pointer = builder.alloca(LLVM::Vector(LLVM::Int, 2)) 40 | vector = builder.load(pointer) 41 | vector = builder.insert_element(vector, arguments.first, LLVM::Int32.from_i(0)) 42 | vector = builder.insert_element(vector, arguments.last, LLVM::Int32.from_i(1)) 43 | builder.ret(builder.add(builder.extract_element(vector, LLVM::Int32.from_i(0)), 44 | builder.extract_element(vector, LLVM::Int32.from_i(1)))) 45 | end 46 | end 47 | 48 | def run_vector_shuffle(*values) 49 | run_function([LLVM::Int, LLVM::Int, LLVM::Int, LLVM::Int], values, LLVM::Int) do |builder, function, *arguments| 50 | entry = function.basic_blocks.append 51 | builder.position_at_end(entry) 52 | vector1 = builder.load(builder.alloca(LLVM::Vector(LLVM::Int, 2))) 53 | vector1 = builder.insert_element(vector1, arguments[0], LLVM::Int32.from_i(0)) 54 | vector1 = builder.insert_element(vector1, arguments[1], LLVM::Int32.from_i(1)) 55 | vector2 = builder.load(builder.alloca(LLVM::Vector(LLVM::Int, 2))) 56 | vector2 = builder.insert_element(vector2, arguments[2], LLVM::Int32.from_i(0)) 57 | vector2 = builder.insert_element(vector2, arguments[3], LLVM::Int32.from_i(1)) 58 | vector3 = builder.shuffle_vector(vector1, vector2, LLVM::ConstantVector.const([LLVM::Int(0), LLVM::Int(3)])) 59 | builder.ret(builder.add(builder.extract_element(vector3, LLVM::Int32.from_i(0)), 60 | builder.extract_element(vector3, LLVM::Int32.from_i(1)))) 61 | end 62 | end 63 | 64 | end 65 | -------------------------------------------------------------------------------- /yardlib/llvm.rb: -------------------------------------------------------------------------------- 1 | class LLVMTagFactory < YARD::Tags::DefaultFactory 2 | def parse_tag(name, text) 3 | case name 4 | when :LLVMinst then inst_tag(text) 5 | when :LLVMpass then pass_tag(text) 6 | else 7 | super 8 | end 9 | end 10 | 11 | private 12 | 13 | def inst_tag(text) 14 | url = "http://llvm.org/docs/LangRef.html#i_#{text}" 15 | markup = "LLVM Instruction: #{text}" 16 | YARD::Tags::Tag.new("see", markup) 17 | end 18 | 19 | def pass_tag(text) 20 | url = "http://llvm.org/docs/Passes.html##{text}" 21 | markup = "LLVM Pass: #{text}" 22 | YARD::Tags::Tag.new("see", markup) 23 | end 24 | end 25 | 26 | YARD::Tags::Library.define_tag "Instruction", :LLVMinst 27 | YARD::Tags::Library.define_tag "Pass", :LLVMpass 28 | YARD::Tags::Library.default_factory = LLVMTagFactory 29 | --------------------------------------------------------------------------------