Skip to content

Commit

Permalink
Start of new LLVM JIT
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Phoenix committed May 11, 2009
1 parent d32a63e commit a352624
Show file tree
Hide file tree
Showing 4,347 changed files with 890 additions and 694,668 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
4 changes: 4 additions & 0 deletions Rakefile
Expand Up @@ -5,6 +5,10 @@ $trace ||= false
$VERBOSE = true
$verbose = Rake.application.options.trace || ARGV.delete("-v")

if !$verbose and respond_to?(:verbose)
verbose(false) if verbose() == :default
end

$dlext = Config::CONFIG["DLEXT"]
$compiler = nil

Expand Down
2 changes: 1 addition & 1 deletion rakelib/extensions.rake
Expand Up @@ -15,7 +15,7 @@ task :extensions => %w[
# Ask the VM to build an extension from source.
#
def compile_extension(path, flags = "-p -I#{Dir.pwd}/vm/capi")
cflags = Object.const_get(:FLAGS).reject {|f| f =~ /-Wno-deprecated|-Weffc\+\+/ }
cflags = BASIC_FLAGS.reject {|f| f =~ /-Wno-deprecated|-Weffc\+\+/ }

cflags.each {|flag| flags << " -C,#{flag}" }

Expand Down
61 changes: 61 additions & 0 deletions rakelib/jit.rake
@@ -0,0 +1,61 @@
namespace :jit do
task :generate_header do
classes = %w!rubinius::ObjectHeader
rubinius::Object
rubinius::CallFrame
rubinius::UnwindInfo
rubinius::VariableScope
rubinius::CompiledMethod
rubinius::Executable
rubinius::Dispatch
rubinius::Arguments
rubinius::Tuple
rubinius::Array
rubinius::Class
rubinius::Module
rubinius::StaticScope
rubinius::InstructionSequence
jit_state!
require 'tempfile'

files = %w!vm/call_frame.hpp vm/arguments.hpp vm/dispatch.hpp!
path = "llvm-type-temp.cpp"

File.open(path, "w+") do |f|
files.each do |file|
f.puts "#include \"#{file}\""
end

i = 0
classes.each do |klass|
f.puts "void useme#{i}(#{klass}* thing);"
f.puts "void blah#{i}(#{klass}* thing) { useme#{i}(thing); }"
i += 1
end
end

str = `llvm-g++ -I. -Ivm -Ivm/external_libs/libtommath -emit-llvm -S -o - "#{path}"`

types = []

str.split("\n").each do |line|
classes.each do |klass|
if /%"?struct.#{klass}(::\$[^\s]+)?"? = type/.match(line)
types << line
end
end
end

opaque = %w!VM TypeInfo VMMethod Fixnum Symbol!

File.open("vm/gen/types.ll","w+") do |f|
opaque.each do |o|
f.puts "%\"struct.rubinius::#{o}\" = type opaque"
end
f.puts(*types)
end

`llvm-as < vm/gen/types.ll > vm/gen/types.bc`
`llc -march=cpp -cppgen=contents -f -o vm/gen/types.cpp vm/gen/types.bc`
end
end
29 changes: 14 additions & 15 deletions rakelib/vm.rake
Expand Up @@ -27,7 +27,7 @@ else
LLVM_STYLE = "Release"
end

LLVM_ENABLE = false
LLVM_ENABLE = true


ENV.delete 'CDPATH' # confuses llvm_config
Expand All @@ -43,7 +43,7 @@ end
# tests << 'vm/test/test_instructions.hpp'
tests.uniq!

subdirs = %w!builtin capi parser util instruments gc!
subdirs = %w!builtin capi parser util instruments gc llvm!

srcs = FileList["vm/*.{cpp,c}"]
subdirs.each do |dir|
Expand Down Expand Up @@ -173,17 +173,22 @@ INCLUDES = EX_INC + %w[/usr/local/include vm/test/cxxtest vm . vm/assembler
INCLUDES.map! { |f| "-I#{f}" }

# Default build options
FLAGS = %W[ -pipe -Wall -Wno-deprecated
BASIC_FLAGS = %W[ -pipe -Wall -Wno-deprecated
-DBASE_PATH=\\"#{RBX_BASE_PATH}\\"
-DRBA_PATH=\\"#{RBX_RBA_PATH}\\"
]

FLAGS = BASIC_FLAGS.dup

if RUBY_PLATFORM =~ /darwin/i && `sw_vers` =~ /10\.4/
FLAGS.concat %w(-DHAVE_STRLCAT -DHAVE_STRLCPY)
end

if LLVM_ENABLE
FLAGS << "-DENABLE_LLVM"
# FLAGS << "-DENABLE_LLVM"
llvm_flags = `#{LLVM_CONFIG} --cflags`.split(/\s+/)
llvm_flags.delete_if { |e| e.index("-O") == 0 }
FLAGS.concat llvm_flags
end

BUILD_PRETASKS = []
Expand All @@ -201,12 +206,6 @@ def compile_c(obj, src)
flags << "-emit-llvm"
end

if LLVM_ENABLE and !defined? $llvm_c then
$llvm_c = `#{LLVM_CONFIG} --cflags`.split(/\s+/)
$llvm_c.delete_if { |e| e.index("-O") == 0 }
flags.concat $llvm_c
end

# GROSS
if src == "vm/test/runner.cpp"
flags.delete_if { |f| /-O.*/.match(f) }
Expand Down Expand Up @@ -541,16 +540,16 @@ file "vm/instructions.o" => "vm/gen/instructions.cpp" do
compile_c "vm/instructions.o", "vm/gen/instructions.cpp"
end

file "vm/gen/instructions.cpp" => %w[vm/llvm/instructions.cpp vm/instructions.rb] + hdrs do
ruby "vm/codegen/rubypp.rb", "vm/llvm/instructions.cpp", "vm/gen/instructions.cpp"
file "vm/gen/instructions.cpp" => %w[vm/template/instructions.cpp vm/instructions.rb] + hdrs do
ruby "vm/codegen/rubypp.rb", "vm/template/instructions.cpp", "vm/gen/instructions.cpp"
end

#
#rubypp_task 'vm/instructions.o', 'vm/llvm/instructions.cpp', 'vm/instructions.rb', *hdrs do |path|
#rubypp_task 'vm/instructions.o', 'vm/template/instructions.cpp', 'vm/instructions.rb', *hdrs do |path|
# compile_c 'vm/instructions.o', path
#end

rubypp_task 'vm/instructions.bc', 'vm/llvm/instructions.cpp', *hdrs do |path|
rubypp_task 'vm/instructions.bc', 'vm/template/instructions.cpp', *hdrs do |path|
sh "llvm-g++ -emit-llvm -Ivm -Ivm/external_libs/libffi/include -c -o vm/instructions.bc #{path}"
end

Expand Down Expand Up @@ -582,7 +581,7 @@ namespace :vm do
puts "CC/LD vm/test/coverage/runner"
begin
path = "vm/gen/instructions.cpp"
ruby 'vm/codegen/rubypp.rb', "vm/llvm/instructions.cpp", path
ruby 'vm/codegen/rubypp.rb', "vm/template/instructions.cpp", path
sh "g++ -fprofile-arcs -ftest-coverage #{flags} -o vm/test/coverage/runner vm/test/runner.cpp vm/*.cpp vm/builtin/*.cpp #{path} #{$link_opts} #{(ex_libs + EXTERNALS).join(' ')}"

puts "RUN vm/test/coverage/runner"
Expand Down
20 changes: 20 additions & 0 deletions tools/llvm_type_extract.rb
@@ -0,0 +1,20 @@
file = ARGV.shift
klass = ARGV.shift

require 'tempfile'

path = "llvm-type-temp.cpp"

File.open(path, "w+") do |f|
f.puts "#include \"#{file}\""
f.puts "void useme(#{klass}* thing);"
f.puts "void blah(#{klass}* thing) { useme(thing); }"
end

str = `llvm-g++ -I. -I.. -Iexternal_libs/libtommath -emit-llvm -S -o - "#{path}"`

str.split("\n").each do |line|
if /%"?struct.#{klass}"? = type/.match(line)
puts line
end
end
4 changes: 1 addition & 3 deletions vm/builtin/compiledmethod.cpp
Expand Up @@ -165,9 +165,7 @@ namespace rubinius {
formalize(state, false);
}

JITCompiler jit;
jit.compile(state, backend_method_);
return MachineMethod::create(state, backend_method_, jit);
return MachineMethod::create(state, backend_method_);
}

bool CompiledMethod::is_rescue_target(STATE, int ip) {
Expand Down
45 changes: 35 additions & 10 deletions vm/builtin/machine_method.cpp
Expand Up @@ -8,6 +8,8 @@

#include "detection.hpp"

#include "llvm/jit.hpp"

// #define MM_DEBUG

namespace rubinius {
Expand Down Expand Up @@ -72,22 +74,45 @@ namespace rubinius {
return mm;
}

MachineMethod* MachineMethod::create(STATE, VMMethod* vmm) {
LLVMCompiler jit;
jit.compile(state, vmm);

MachineMethod* mm = state->new_struct<MachineMethod>(G(machine_method));

mm->vmmethod_ = vmm;
mm->code_size_ = 0;
mm->set_function(jit.function_pointer(state));
mm->relocations_ = 0;
mm->virtual2native_ = 0;
mm->comments_ = 0;

mm->jit_data_ = reinterpret_cast<void*>(jit.llvm_function(state));
return mm;
}

void* MachineMethod::resolve_virtual_ip(int ip) {
CodeMap::iterator i = virtual2native_->find(ip);
if(i == virtual2native_->end()) return NULL;
return i->second;
}

Object* MachineMethod::show() {
std::cout << "== stats ==\n";
std::cout << "number of bytecodes: " << vmmethod_->total << "\n";
std::cout << " bytes of assembley: " << code_size_ << "\n";
double ratio = (double)code_size_ / (double)vmmethod_->total;
std::cout << " direct ratio: " << ratio << "\n";
ratio = (double)code_size_ / ((double)vmmethod_->total * sizeof(rubinius::opcode));
std::cout << " memory ratio: " << ratio << "\n";
std::cout << "\n== x86 assembly ==\n";
assembler_x86::AssemblerX86::show_buffer(function(), code_size_, false, comments_);
Object* MachineMethod::show(STATE) {
if(code_size_ == 0) {
std::cout << "== llvm assembly ==\n";
LLVMCompiler::show_assembly(state, reinterpret_cast<llvm::Function*>(jit_data_));
} else {
std::cout << "== stats ==\n";
std::cout << "number of bytecodes: " << vmmethod_->total << "\n";
std::cout << " bytes of assembley: " << code_size_ << "\n";
double ratio = (double)code_size_ / (double)vmmethod_->total;
std::cout << " direct ratio: " << ratio << "\n";
ratio = (double)code_size_ / ((double)vmmethod_->total * sizeof(rubinius::opcode));
std::cout << " memory ratio: " << ratio << "\n";
std::cout << "\n== x86 assembly ==\n";
assembler_x86::AssemblerX86::show_buffer(function(), code_size_, false, comments_);
}

return Qnil;
}

Expand Down
6 changes: 4 additions & 2 deletions vm/builtin/machine_method.hpp
Expand Up @@ -20,10 +20,12 @@ namespace rubinius {
assembler::Relocation** relocations_;

void* function_;
void* jit_data_;

public:
static void init(STATE);
static MachineMethod* create(STATE, VMMethod* vmm, JITCompiler& jit);
static MachineMethod* create(STATE, VMMethod* vmm);

void* function() {
return reinterpret_cast<void*>(function_);
Expand All @@ -34,10 +36,10 @@ namespace rubinius {
}

// Used for debugging. Gives us a place to break on before entering jit'd code
static Object * run_code(STATE, VMMethod* const vmm, CallFrame* const call_frame);
static Object* run_code(STATE, VMMethod* const vmm, CallFrame* const call_frame);

// Ruby.primitive :machine_method_show
Object* show();
Object* show(STATE);

// Ruby.primitive :machine_method_activate
Object* activate();
Expand Down
14 changes: 14 additions & 0 deletions vm/codegen/instruction_macros.rb
@@ -0,0 +1,14 @@
require "#{File.dirname(__FILE__)}/../../kernel/compiler/iseq"

File.open "#{File.dirname(__FILE__)}/../gen/inst_list.hpp", "w" do |f|
InstructionSet::OpCodes.each do |ins|
case ins.arg_count
when 2
f.puts "HANDLE_INST2(#{ins.bytecode}, #{ins.opcode});"
when 1
f.puts "HANDLE_INST1(#{ins.bytecode}, #{ins.opcode});"
when 0
f.puts "HANDLE_INST0(#{ins.bytecode}, #{ins.opcode});"
end
end
end
45 changes: 45 additions & 0 deletions vm/codegen/transforms.rb
@@ -0,0 +1,45 @@
require "#{File.dirname(__FILE__)}/../../kernel/compiler/iseq"

puts "template <class SubClass>"
puts "void VisitInstructions::drive() {"
puts " switch(current_instruction()) {"

InstructionSet::OpCodes.each do |ins|
puts " case #{ins.bytecode}: // #{ins.opcode}"
case ins.arg_count
when 2
puts " SPECIFIC->visit_#{ins.opcode}(opcode_arg(0), opcode_arg(1));"
when 1
puts " SPECIFIC->visit_#{ins.opcode}(opcode_arg(0));"
when 0
puts " SPECIFIC->visit_#{ins.opcode}();"
else
raise "huh?"
end
puts " advance(#{ins.arg_count + 1});"
puts " return;"
end

puts " }"

puts "}"

InstructionSet::OpCodes.each do |ins|
puts "template <class SubClass>"
case ins.arg_count
when 2
puts "void VisitInstructions::visit_#{ins.opcode}(opcode arg1, opcode arg2)"
puts "{\n SPECIFIC->visit(#{ins.bytecode}, arg1, arg2);\n}"
when 1
puts "void VisitInstructions::visit_#{ins.opcode}(opcode arg1)"
puts "{\n SPECIFIC->visit(#{ins.bytecode}, arg1, -1);\n}"
when 0
puts "void VisitInstructions::visit_#{ins.opcode}()"
puts "{\n SPECIFIC->visit(#{ins.bytecode}, -1, -1);\n}"
else
raise "huh?"
end

puts

end

0 comments on commit a352624

Please sign in to comment.