%# -*- C -*-
%# 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.
%#
%
% stack_increase = proc do |i|
%   if i.has_attribute?('sp_inc')
%     '-127'
%   else
%     sprintf("%4d", i.rets.size - i.pops.size)
%   end
% end
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
PUREFUNC(MAYBE_UNUSED(static int comptime_insn_stack_increase(int depth, int insn, const VALUE *opes)));
PUREFUNC(static rb_snum_t comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes));

rb_snum_t
comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes)
{
    static const signed char t[] = {
% insns.each_slice(8) do |row|
        <%= row.map(&stack_increase).join(', ') -%>,
% end
#if USE_ZJIT
% zjit_insns.each_slice(8) do |row|
        <%= row.map(&stack_increase).join(', ') -%>,
% end
#endif
    };
    signed char c = t[insn];

    ASSERT_VM_INSTRUCTION_SIZE(t);
    if (c != -127) {
        return c;
    }
    else switch(insn) {
    default:
        UNREACHABLE;
% RubyVM::Instructions.each do |i|
%   next unless i.has_attribute?('sp_inc')
%   attr_function =
%     if i.has_attribute?('comptime_sp_inc')
%       "attr_comptime_sp_inc_#{i.name}"
%     else
%       "attr_sp_inc_#{i.name}"
%     end
    case <%= i.bin %>:
        return <%= attr_function %>(<%=
          i.operands.map.with_index do |v, j|
            if v[:type] == 'CALL_DATA' && i.has_attribute?('comptime_sp_inc')
              v = v.dup
              v[:type] = 'CALL_INFO'
            end
            i.cast_from_VALUE v, "opes[#{j}]"
          end.join(", ")
        %>);
% end
    }
}

int
comptime_insn_stack_increase(int depth, int insn, const VALUE *opes)
{
    enum ruby_vminsn_type itype = (enum ruby_vminsn_type)insn;
    return depth + (int)comptime_insn_stack_increase_dispatch(itype, opes);
}
