1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/tool/ruby_vm/models/bare_instructions.rb
shyouhei 9a8b38cacf extensive use of instruction attributes
Instead of using magic numbers, let us define a series of attributes
and use them from the VM core.  Proper function declarations makes
these attributes inlined in most modern compilers.  On my machine
exact same binary is generated with or without this changeset.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62085 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-01-29 06:47:05 +00:00

166 lines
4.5 KiB
Ruby

#! /your/favourite/path/to/ruby
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level: 2 -*-
# -*- frozen_string_literal: true; -*-
# -*- warn_indent: true; -*-
#
# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
#
# This file is a part of the programming language Ruby. Permission is hereby
# granted, to either redistribute and/or modify this file, provided that the
# conditions mentioned in the file COPYING are met. Consult the file for
# details.
require_relative '../loaders/insns_def'
require_relative 'c_expr'
require_relative 'typemap'
require_relative 'attribute'
class RubyVM::BareInstructions
attr_reader :template, :name, :opes, :pops, :rets, :decls, :expr
def initialize opts = {}
@template = opts[:template]
@name = opts[:name]
@loc = opts[:location]
@sig = opts[:signature]
@expr = RubyVM::CExpr.new opts[:expr]
@opes = typesplit @sig[:ope]
@pops = typesplit @sig[:pop].reject {|i| i == '...' }
@rets = typesplit @sig[:ret].reject {|i| i == '...' }
@attrs = opts[:attributes].map {|i|
RubyVM::Attribute.new i.merge(:insn => self)
}.each_with_object({}) {|a, h|
h[a.key] = a
}
@attrs_orig = @attrs.dup
predefine_attributes
end
def pretty_name
n = @sig[:name]
o = @sig[:ope].map{|i| i[/\S+$/] }.join ', '
p = @sig[:pop].map{|i| i[/\S+$/] }.join ', '
r = @sig[:ret].map{|i| i[/\S+$/] }.join ', '
return sprintf "%s(%s)(%s)(%s)", n, o, p, r
end
def bin
return "BIN(#{name})"
end
def call_attribute name
return sprintf 'attr_%s_%s(%s)', name, @name, \
@opes.map {|i| i[:name] }.compact.join(', ')
end
def has_attribute? k
@attrs_orig.has_key? k
end
def attributes
return @attrs.values
end
def width
return 1 + opes.size
end
def declarations
return @variables \
. values \
. group_by {|h| h[:type] } \
. map {|t, v| [t, v.map {|i| i[:name] }.sort ] } \
. map {|t, v| sprintf("%s %s", t, v.join(', ')) } \
. sort
end
def preamble
# preamble makes sense for operand unifications
return []
end
def sc?
# sc stands for stack caching.
return false
end
def cast_to_VALUE var, expr = var[:name]
RubyVM::Typemap.typecast_to_VALUE var[:type], expr
end
def cast_from_VALUE var, expr = var[:name]
RubyVM::Typemap.typecast_from_VALUE var[:type], expr
end
def operands_info
opes.map {|o|
c, _ = RubyVM::Typemap.fetch o[:type]
next c
}.join
end
def handles_frame?
/\b(false|0)\b/ !~ @attrs['handles_frame'].expr.expr
end
def inspect
sprintf "#<%s %s@%s:%d>", self.class.name, @name, @loc[0], @loc[1]
end
private
def generate_attribute t, k, v
@attrs[k] ||= RubyVM::Attribute.new \
insn: self, \
name: k, \
type: t, \
location: [], \
expr: v.to_s + ';'
return @attrs[k] ||= attr
end
def predefine_attributes
generate_attribute 'const char*', 'name', "insn_name(#{bin})"
generate_attribute 'enum ruby_vminsn_type', 'bin', bin
generate_attribute 'rb_num_t', 'open', opes.size
generate_attribute 'rb_num_t', 'popn', pops.size
generate_attribute 'rb_num_t', 'retn', rets.size
generate_attribute 'rb_num_t', 'width', width
generate_attribute 'rb_num_t', 'sp_inc', rets.size - pops.size
generate_attribute 'bool', 'handles_frame', \
opes.any? {|o| /CALL_INFO/ =~ o[:type] }
end
def typesplit a
@variables ||= {}
a.map do |decl|
md = %r'
(?<comment> /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* / ){0}
(?<ws> \g<comment> | \s ){0}
(?<ident> [_a-zA-Z] [0-9_a-zA-Z]* ){0}
(?<type> (?: \g<ident> \g<ws>+ )* \g<ident> ){0}
(?<var> \g<ident> ){0}
\G \g<ws>* \g<type> \g<ws>+ \g<var>
'x.match(decl)
@variables[md['var']] ||= {
decl: decl,
type: md['type'],
name: md['var'],
}
end
end
@instances = RubyVM::InsnsDef.map {|h|
new h.merge(:template => h)
}
def self.fetch name
@instances.find do |insn|
insn.name == name
end or raise IndexError, "instruction not found: #{name}"
end
def self.to_a
@instances
end
end