1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- 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 '../helpers/c_escape'
require_relative '../loaders/opt_operand_def'
require_relative 'bare_instructions'
class RubyVM::OperandsUnifications < RubyVM::BareInstructions
include RubyVM::CEscape
attr_reader :preamble, :original, :spec
def initialize opts = {}
name = opts[:signature][0]
@original = RubyVM::BareInstructions.fetch name
template = @original.template
parts = compose opts[:location], opts[:signature], template[:signature]
json = template.dup
json[:location] = opts[:location]
json[:signature] = parts[:signature]
json[:name] = parts[:name]
@preamble = parts[:preamble]
@spec = parts[:spec]
super json.merge(:template => template)
@konsts = parts[:vars]
@konsts.each do |v|
@variables[v[:name]] ||= v
end
end
def operand_shift_of var
before = @original.opes.find_index var
after = @opes.find_index var
raise "no #{var} for #{@name}" unless before and after
return before - after
end
def condition ptr
# :FIXME: I'm not sure if this method should be in model?
exprs = @spec.each_with_index.map do |(var, val), i|
case val when '*' then
next nil
else
type = @original.opes[i][:type]
expr = RubyVM::Typemap.typecast_to_VALUE type, val
next "#{ptr}[#{i}] == #{expr}"
end
end
exprs.compact!
if exprs.size == 1 then
return exprs[0]
else
exprs.map! {|i| "(#{i})" }
return exprs.join ' && '
end
end
def has_ope? var
super or @konsts.any? {|i| i[:name] == var[:name] }
end
private
def namegen signature
insn, argv = *signature
wcary = argv.map do |i|
case i when '*' then
'WC'
else
i
end
end
as_tr_cpp [insn, *wcary].join(', ')
end
def compose location, spec, template
name = namegen spec
*, argv = *spec
opes = @original.opes
if opes.size != argv.size
raise sprintf("operand size mismatch for %s (%s's: %d, given: %d)",
name, template[:name], opes.size, argv.size)
else
src = []
mod = []
spec = []
vars = []
argv.each_index do |i|
j = argv[i]
k = opes[i]
spec[i] = [k, j]
case j when '*' then
# operand is from iseq
mod << k[:decl]
else
# operand is inside C
vars << k
src << {
location: location,
expr: " const #{k[:decl]} = #{j};"
}
end
end
src.map! {|i| RubyVM::CExpr.new i }
return {
name: name,
signature: {
name: name,
ope: mod,
pop: template[:pop],
ret: template[:ret],
},
preamble: src,
vars: vars,
spec: spec
}
end
end
@instances = RubyVM::OptOperandDef.map do |h|
new h
end
def self.to_a
@instances
end
def self.each_group
to_a.group_by(&:original).each_pair do |k, v|
yield k, v
end
end
end
|