kumi 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +60 -116
- data/golden/array_element/expected/schema_ruby.rb +1 -1
- data/golden/array_index/expected/schema_ruby.rb +1 -1
- data/golden/array_operations/expected/schema_ruby.rb +1 -1
- data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
- data/golden/chained_fusion/expected/schema_ruby.rb +1 -1
- data/golden/element_arrays/expected/schema_ruby.rb +1 -1
- data/golden/empty_and_null_inputs/expected/schema_ruby.rb +1 -1
- data/golden/game_of_life/expected/lir_00_unoptimized.txt +33 -33
- data/golden/game_of_life/expected/lir_01_hoist_scalar_references.txt +33 -33
- data/golden/game_of_life/expected/lir_02_inlined.txt +296 -296
- data/golden/game_of_life/expected/lir_03_cse.txt +128 -128
- data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +128 -128
- data/golden/game_of_life/expected/lir_04_loop_invcm.txt +128 -128
- data/golden/game_of_life/expected/lir_06_const_prop.txt +128 -128
- data/golden/game_of_life/expected/schema_ruby.rb +1 -1
- data/golden/hash_keys/expected/schema_ruby.rb +1 -1
- data/golden/hash_keys/schema.kumi +4 -5
- data/golden/hash_value/expected/schema_ruby.rb +1 -1
- data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -1
- data/golden/inline_rename_scope_leak/expected/ast.txt +48 -0
- data/golden/inline_rename_scope_leak/expected/input_plan.txt +10 -0
- data/golden/inline_rename_scope_leak/expected/lir_00_unoptimized.txt +35 -0
- data/golden/inline_rename_scope_leak/expected/lir_01_hoist_scalar_references.txt +35 -0
- data/golden/inline_rename_scope_leak/expected/lir_02_inlined.txt +49 -0
- data/golden/inline_rename_scope_leak/expected/lir_03_cse.txt +49 -0
- data/golden/inline_rename_scope_leak/expected/lir_04_1_loop_fusion.txt +49 -0
- data/golden/inline_rename_scope_leak/expected/lir_04_loop_invcm.txt +49 -0
- data/golden/inline_rename_scope_leak/expected/lir_06_const_prop.txt +49 -0
- data/golden/inline_rename_scope_leak/expected/nast.txt +31 -0
- data/golden/inline_rename_scope_leak/expected/schema_javascript.mjs +51 -0
- data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +82 -0
- data/golden/inline_rename_scope_leak/expected/snast.txt +31 -0
- data/golden/inline_rename_scope_leak/expected.json +7 -0
- data/golden/inline_rename_scope_leak/input.json +4 -0
- data/golden/inline_rename_scope_leak/schema.kumi +24 -0
- data/golden/input_reference/expected/schema_ruby.rb +1 -1
- data/golden/interleaved_fusion/expected/schema_ruby.rb +1 -1
- data/golden/let_inline/expected/schema_ruby.rb +1 -1
- data/golden/loop_fusion/expected/schema_ruby.rb +1 -1
- data/golden/min_reduce_scope/expected/schema_ruby.rb +1 -1
- data/golden/mixed_dimensions/expected/schema_ruby.rb +1 -1
- data/golden/multirank_hoisting/expected/schema_ruby.rb +1 -1
- data/golden/nested_hash/expected/schema_ruby.rb +1 -1
- data/golden/reduction_broadcast/expected/schema_ruby.rb +1 -1
- data/golden/roll/expected/lir_00_unoptimized.txt +8 -8
- data/golden/roll/expected/lir_01_hoist_scalar_references.txt +8 -8
- data/golden/roll/expected/lir_02_inlined.txt +8 -8
- data/golden/roll/expected/lir_03_cse.txt +8 -8
- data/golden/roll/expected/lir_04_1_loop_fusion.txt +8 -8
- data/golden/roll/expected/lir_04_loop_invcm.txt +8 -8
- data/golden/roll/expected/lir_06_const_prop.txt +8 -8
- data/golden/roll/expected/schema_ruby.rb +1 -1
- data/golden/shift/expected/lir_00_unoptimized.txt +12 -12
- data/golden/shift/expected/lir_01_hoist_scalar_references.txt +12 -12
- data/golden/shift/expected/lir_02_inlined.txt +12 -12
- data/golden/shift/expected/lir_03_cse.txt +12 -12
- data/golden/shift/expected/lir_04_1_loop_fusion.txt +12 -12
- data/golden/shift/expected/lir_04_loop_invcm.txt +12 -12
- data/golden/shift/expected/lir_06_const_prop.txt +12 -12
- data/golden/shift/expected/schema_ruby.rb +1 -1
- data/golden/shift_2d/expected/lir_00_unoptimized.txt +48 -48
- data/golden/shift_2d/expected/lir_01_hoist_scalar_references.txt +48 -48
- data/golden/shift_2d/expected/lir_02_inlined.txt +48 -48
- data/golden/shift_2d/expected/lir_03_cse.txt +48 -48
- data/golden/shift_2d/expected/lir_04_1_loop_fusion.txt +48 -48
- data/golden/shift_2d/expected/lir_04_loop_invcm.txt +48 -48
- data/golden/shift_2d/expected/lir_06_const_prop.txt +48 -48
- data/golden/shift_2d/expected/schema_ruby.rb +1 -1
- data/golden/simple_math/expected/schema_ruby.rb +1 -1
- data/golden/streaming_basics/expected/schema_ruby.rb +1 -1
- data/golden/tuples/expected/lir_00_unoptimized.txt +4 -4
- data/golden/tuples/expected/lir_01_hoist_scalar_references.txt +4 -4
- data/golden/tuples/expected/lir_02_inlined.txt +4 -4
- data/golden/tuples/expected/lir_03_cse.txt +4 -4
- data/golden/tuples/expected/lir_04_1_loop_fusion.txt +4 -4
- data/golden/tuples/expected/lir_04_loop_invcm.txt +4 -4
- data/golden/tuples/expected/lir_06_const_prop.txt +4 -4
- data/golden/tuples/expected/schema_ruby.rb +1 -1
- data/golden/tuples_and_arrays/expected/lir_00_unoptimized.txt +1 -1
- data/golden/tuples_and_arrays/expected/lir_01_hoist_scalar_references.txt +1 -1
- data/golden/tuples_and_arrays/expected/lir_02_inlined.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_03_cse.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +2 -2
- data/golden/tuples_and_arrays/expected/schema_ruby.rb +1 -1
- data/golden/us_tax_2024/expected/ast.txt +865 -0
- data/golden/us_tax_2024/expected/input_plan.txt +61 -0
- data/golden/us_tax_2024/expected/lir_00_unoptimized.txt +901 -0
- data/golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt +901 -0
- data/golden/us_tax_2024/expected/lir_02_inlined.txt +5178 -0
- data/golden/us_tax_2024/expected/lir_03_cse.txt +2499 -0
- data/golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt +2519 -0
- data/golden/us_tax_2024/expected/lir_04_loop_invcm.txt +2439 -0
- data/golden/us_tax_2024/expected/lir_06_const_prop.txt +2439 -0
- data/golden/us_tax_2024/expected/nast.txt +976 -0
- data/golden/us_tax_2024/expected/schema_javascript.mjs +584 -0
- data/golden/us_tax_2024/expected/schema_ruby.rb +639 -0
- data/golden/us_tax_2024/expected/snast.txt +976 -0
- data/golden/us_tax_2024/expected.json +1 -0
- data/golden/us_tax_2024/input.json +168 -0
- data/golden/us_tax_2024/schema.kumi +203 -0
- data/golden/with_constants/expected/schema_ruby.rb +1 -1
- data/lib/kumi/core/analyzer/passes/lir/inline_declarations_pass.rb +181 -105
- data/lib/kumi/core/analyzer/passes/output_schema_pass.rb +6 -4
- data/lib/kumi/core/functions/function_spec.rb +14 -8
- data/lib/kumi/core/functions/loader.rb +1 -1
- data/lib/kumi/version.rb +1 -1
- metadata +33 -1
@@ -15,20 +15,18 @@ module Kumi
|
|
15
15
|
|
16
16
|
MAX_PASSES.times do
|
17
17
|
new_ops, changed = run_one_pass(current_ops)
|
18
|
-
|
19
18
|
unless changed
|
20
19
|
new_ops.freeze
|
21
|
-
return state.with(:lir_module, new_ops)
|
20
|
+
return state.with(:lir_module, new_ops)
|
21
|
+
.with(:lir_02_inlined_ops_by_decl, new_ops)
|
22
22
|
end
|
23
23
|
current_ops = new_ops
|
24
24
|
end
|
25
|
-
|
26
25
|
raise "LIR inlining did not converge after #{MAX_PASSES} passes."
|
27
26
|
end
|
28
27
|
|
29
28
|
private
|
30
29
|
|
31
|
-
# --- UNCHANGED: Top-level pass logic ---
|
32
30
|
def run_one_pass(ops_by_decl)
|
33
31
|
@ops_by_decl = ops_by_decl
|
34
32
|
@gamma = detect_all_gammas(@ops_by_decl)
|
@@ -36,102 +34,148 @@ module Kumi
|
|
36
34
|
fused = {}
|
37
35
|
@ops_by_decl.each do |name, payload|
|
38
36
|
original_ops = Array(payload[:operations])
|
39
|
-
|
40
|
-
|
41
|
-
inlined_ops = inline_top_level_decl(original_ops)
|
42
|
-
|
43
|
-
fused[name] = { operations: inlined_ops }
|
37
|
+
inlined_ops = inline_top_level_decl(original_ops)
|
38
|
+
fused[name] = { operations: inlined_ops }
|
44
39
|
changed ||= (inlined_ops != original_ops)
|
45
40
|
end
|
46
41
|
[fused, changed]
|
47
42
|
end
|
48
43
|
|
49
|
-
# --- NEW: Top-level entry point for the recursive processor ---
|
50
44
|
def inline_top_level_decl(ops)
|
51
|
-
env
|
52
|
-
reg_map
|
45
|
+
env = Env.new
|
46
|
+
reg_map = {}
|
53
47
|
rename_map = {}
|
54
|
-
|
55
|
-
|
56
|
-
# Hoisting is not allowed at the top level of a declaration
|
57
|
-
raise "Orphaned code was hoisted to top level" unless hoisted_ops.empty?
|
48
|
+
processed, hoisted = process_and_hoist_block(ops, env, reg_map, rename_map)
|
49
|
+
raise "Orphaned code was hoisted to top level" unless hoisted.empty?
|
58
50
|
|
59
|
-
|
51
|
+
processed
|
60
52
|
end
|
61
53
|
|
62
|
-
#
|
63
|
-
|
54
|
+
# ---------------- core ----------------
|
55
|
+
|
56
|
+
# returns [processed_ops, hoisted_ops]
|
64
57
|
def process_and_hoist_block(block_ops, env, reg_map, rename_map)
|
65
|
-
|
66
|
-
|
58
|
+
out = []
|
59
|
+
hoisted = []
|
67
60
|
i = 0
|
68
|
-
|
69
61
|
while i < block_ops.length
|
70
62
|
ins = block_ops[i]
|
71
63
|
case ins.opcode
|
72
64
|
when :LoopStart
|
73
|
-
end_idx
|
65
|
+
end_idx = find_matching_loop_end(block_ops, i)
|
74
66
|
loop_body = block_ops[(i + 1)...end_idx]
|
75
67
|
|
76
68
|
env.push(ins)
|
77
|
-
|
69
|
+
child_rename = {}
|
70
|
+
processed_body, hoisted_from_child =
|
71
|
+
process_and_hoist_block(loop_body, env, reg_map, child_rename)
|
78
72
|
env.pop
|
79
73
|
|
80
|
-
#
|
81
|
-
#
|
82
|
-
out_ops.concat(hoisted_from_child)
|
74
|
+
out.concat(hoisted_from_child) # emit hoists before loop
|
75
|
+
rename_map.merge!(child_rename) # make child renames visible
|
83
76
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
out_ops << rewrite(block_ops[end_idx], reg_map, rename_map)
|
77
|
+
out << rewrite(ins, reg_map, rename_map) # loop shell
|
78
|
+
out.concat(processed_body)
|
79
|
+
out << rewrite(block_ops[end_idx], reg_map, rename_map)
|
88
80
|
|
89
|
-
i = end_idx
|
81
|
+
i = end_idx
|
90
82
|
|
91
83
|
when :LoadDeclaration
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
84
|
+
inline_ops, hoist_ops =
|
85
|
+
handle_load_declaration(ins, env, reg_map, rename_map)
|
86
|
+
out.concat(inline_ops)
|
87
|
+
hoisted.concat(hoist_ops)
|
96
88
|
|
97
89
|
else
|
98
|
-
|
90
|
+
out << rewrite(ins, reg_map, rename_map)
|
99
91
|
end
|
100
92
|
i += 1
|
101
93
|
end
|
102
|
-
|
103
|
-
[out_ops, hoisted_out_ops]
|
94
|
+
[out, hoisted]
|
104
95
|
end
|
105
96
|
|
106
|
-
#
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
97
|
+
# returns [inline_ops, hoisted_ops]
|
98
|
+
def handle_load_declaration(call_ins, env, reg_map, outer_rename_map)
|
99
|
+
raise "LoadDeclaration missing callee" unless call_ins.immediates&.first&.respond_to?(:value)
|
100
|
+
|
101
|
+
callee = call_ins.immediates.first.value.to_sym
|
102
|
+
raise "LoadDeclaration callee #{callee} not found" unless @ops_by_decl.key?(callee)
|
103
|
+
|
104
|
+
decl_axes = fetch_decl_axes(callee, call_ins)
|
111
105
|
site_axes = env.axes
|
112
106
|
|
113
|
-
body, yield_reg,
|
114
|
-
|
115
|
-
|
107
|
+
body, yield_reg, callee_axis_regs = inline_callee_core(callee)
|
108
|
+
axis_map = remap_axes(callee_axis_regs, env)
|
109
|
+
|
110
|
+
local_reg_map = {}
|
111
|
+
_acc, fresh_ops = freshen(body, local_reg_map, pre_map: axis_map)
|
112
|
+
|
113
|
+
nested_rename = {}
|
114
|
+
processed_inner, hoisted_inner =
|
115
|
+
process_and_hoist_block(fresh_ops, env, {}, nested_rename)
|
116
|
+
|
117
|
+
prelim = local_reg_map[yield_reg] || axis_map[yield_reg] || yield_reg
|
118
|
+
mapped_yield = resolve_rename(prelim, nested_rename)
|
119
|
+
|
120
|
+
# def/dominance guard
|
121
|
+
defs_inline = defs_in(processed_inner)
|
122
|
+
defs_hoisted = defs_in(hoisted_inner)
|
123
|
+
unless defs_inline.include?(mapped_yield) || defs_hoisted.include?(mapped_yield)
|
124
|
+
msg = [
|
125
|
+
"inliner: mapped yield #{mapped_yield} has no def in emitted ops for #{callee}",
|
126
|
+
" original yield: #{yield_reg}",
|
127
|
+
" prelim mapping: #{prelim}",
|
128
|
+
" nested_rename keys: #{nested_rename.keys.inspect}",
|
129
|
+
" inline defs size: #{defs_inline.size}",
|
130
|
+
" hoisted defs size: #{defs_hoisted.size}"
|
131
|
+
].join("\n")
|
132
|
+
raise msg
|
133
|
+
end
|
116
134
|
|
117
|
-
|
135
|
+
outer_rename_map[call_ins.result_register] = mapped_yield if call_ins.result_register
|
118
136
|
|
119
|
-
# Case 1: Hoisting
|
120
137
|
if prefix?(decl_axes, site_axes) && decl_axes.length < site_axes.length
|
121
|
-
[[],
|
122
|
-
# Case 2: In-place
|
138
|
+
[[], hoisted_inner + processed_inner] # hoist
|
123
139
|
elsif decl_axes == site_axes
|
124
|
-
[
|
125
|
-
# Case 3: Cannot inline
|
140
|
+
[hoisted_inner + processed_inner, []] # inline in place
|
126
141
|
else
|
127
|
-
[[rewrite(
|
142
|
+
[[rewrite(call_ins, reg_map, outer_rename_map)], []] # cannot inline
|
128
143
|
end
|
129
144
|
end
|
130
145
|
|
131
|
-
#
|
146
|
+
# ---------------- helpers ----------------
|
147
|
+
|
148
|
+
def resolve_rename(reg, rename, limit: 64)
|
149
|
+
seen = {}
|
150
|
+
cur = reg
|
151
|
+
limit.times do
|
152
|
+
nxt = rename[cur]
|
153
|
+
break unless nxt
|
154
|
+
raise "inliner: rename cycle at #{cur}" if seen[nxt]
|
155
|
+
|
156
|
+
seen[nxt] = true
|
157
|
+
cur = nxt
|
158
|
+
end
|
159
|
+
cur
|
160
|
+
end
|
161
|
+
|
162
|
+
def defs_in(ops)
|
163
|
+
ops.each_with_object(Set.new) { |ins, s| s << ins.result_register if ins.result_register }
|
164
|
+
end
|
165
|
+
|
166
|
+
def fetch_decl_axes(callee, call_ins)
|
167
|
+
attr_axes = call_ins.attributes && call_ins.attributes[:axes]
|
168
|
+
gamma_axes = Array(@gamma.fetch(callee)&.axes || [])
|
169
|
+
ax = attr_axes.nil? ? gamma_axes : Array(attr_axes)
|
170
|
+
raise "LoadDeclaration missing :axes" if ax.nil?
|
171
|
+
raise "inliner: non-array axes for #{callee}: #{ax.inspect}" unless ax.is_a?(Array)
|
172
|
+
|
173
|
+
ax
|
174
|
+
end
|
132
175
|
|
133
176
|
def find_matching_loop_end(ops, start_index)
|
134
|
-
depth = 1
|
177
|
+
depth = 1
|
178
|
+
(start_index + 1...ops.length).each do |i|
|
135
179
|
op = ops[i].opcode
|
136
180
|
depth += 1 if op == :LoopStart
|
137
181
|
depth -= 1 if op == :LoopEnd
|
@@ -143,47 +187,52 @@ module Kumi
|
|
143
187
|
def remap_axes(callee_axis_regs, env)
|
144
188
|
callee_axis_regs.each_with_object({}) do |r, h|
|
145
189
|
caller = env.reg_for_axis(r[:axis])
|
146
|
-
h[r[:el]]
|
190
|
+
h[r[:el]] = caller[:el]
|
147
191
|
h[r[:idx]] = caller[:idx]
|
148
192
|
end
|
149
193
|
end
|
150
194
|
|
151
|
-
def rename_yielded_register(ins, yielded_reg, reg_map, axis_remap, rename)
|
152
|
-
return unless ins.result_register && yielded_reg
|
153
|
-
|
154
|
-
mapped = reg_map.fetch(yielded_reg, axis_remap.fetch(yielded_reg, yielded_reg))
|
155
|
-
rename[ins.result_register] = mapped
|
156
|
-
end
|
157
|
-
|
158
|
-
# (Your original `detect_all_gammas`, `detect_gamma`, `inline_callee_core`,
|
159
|
-
# `Env`, `freshen`, `rewrite`, and `prefix?` methods go here, unchanged)
|
160
195
|
class Env
|
161
196
|
def initialize = @frames = []
|
162
197
|
def axes = @frames.map { _1[:axis] }
|
163
198
|
|
164
199
|
def push(loop_ins)
|
165
|
-
@frames << {
|
200
|
+
@frames << {
|
201
|
+
axis: loop_ins.attributes[:axis],
|
202
|
+
el: loop_ins.attributes[:as_element],
|
203
|
+
idx: loop_ins.attributes[:as_index]
|
204
|
+
}
|
166
205
|
end
|
167
206
|
|
168
207
|
def pop = @frames.pop
|
169
|
-
|
208
|
+
|
209
|
+
def reg_for_axis(axis)
|
210
|
+
@frames.reverse.find { _1[:axis] == axis } ||
|
211
|
+
raise("no element for axis=#{axis.inspect}")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def detect_all_gammas(ops_by_decl)
|
216
|
+
ops_by_decl.transform_values { |p| detect_gamma(Array(p[:operations])) }
|
170
217
|
end
|
171
218
|
|
172
|
-
def detect_all_gammas(ops_by_decl) = ops_by_decl.transform_values { |p| detect_gamma(Array(p[:operations])) }
|
173
219
|
GammaInfo = Struct.new(:start_idx, :axes, :axis_regs, keyword_init: true)
|
220
|
+
|
174
221
|
def detect_gamma(ops)
|
175
222
|
frames = []
|
176
223
|
ops.each do |ins|
|
177
224
|
case ins.opcode
|
178
225
|
when :LoopStart
|
179
|
-
frames << {
|
226
|
+
frames << {
|
227
|
+
axis: ins.attributes[:axis],
|
228
|
+
el: ins.attributes[:as_element],
|
229
|
+
idx: ins.attributes[:as_index]
|
230
|
+
}
|
180
231
|
when :LoopEnd
|
181
232
|
frames.pop
|
182
233
|
when :Yield
|
183
234
|
axes = frames.map { _1[:axis] }
|
184
|
-
axis_regs = frames.map
|
185
|
-
{ axis: f[:axis], el: f[:el], idx: f[:idx] }
|
186
|
-
end
|
235
|
+
axis_regs = frames.map { |f| { axis: f[:axis], el: f[:el], idx: f[:idx] } }
|
187
236
|
return GammaInfo.new(start_idx: nil, axes: axes, axis_regs: axis_regs)
|
188
237
|
end
|
189
238
|
end
|
@@ -195,29 +244,30 @@ module Kumi
|
|
195
244
|
info = @gamma.fetch(callee_name)
|
196
245
|
axes = info.axes
|
197
246
|
k = axes.length
|
198
|
-
yield_index = ops.rindex { |ins| ins.opcode == :Yield } or raise "callee #{callee_name} has no Yield"
|
199
|
-
yielded_reg = Array(ops[yield_index].inputs).first
|
200
|
-
first_loop_index = ops.index { |ins| ins.opcode == :LoopStart }
|
201
|
-
return [ops[0...yield_index], yielded_reg, info.axis_regs] unless first_loop_index
|
202
247
|
|
203
|
-
|
204
|
-
|
248
|
+
yi = ops.rindex { |x| x.opcode == :Yield } or raise "callee #{callee_name} has no Yield"
|
249
|
+
yielded_reg = Array(ops[yi].inputs).first
|
250
|
+
|
251
|
+
first_loop = ops.index { |x| x.opcode == :LoopStart }
|
252
|
+
return [ops[0...yi], yielded_reg, info.axis_regs] unless first_loop
|
253
|
+
|
254
|
+
prologue = ops[0...first_loop]
|
255
|
+
main = ops[first_loop...yi]
|
205
256
|
inner_body = []
|
206
257
|
open_gamma = 0
|
207
|
-
|
208
|
-
|
258
|
+
stack = []
|
259
|
+
main.each do |ins|
|
209
260
|
case ins.opcode
|
210
261
|
when :LoopStart
|
211
262
|
if open_gamma < k && ins.attributes[:axis] == axes[open_gamma]
|
212
|
-
|
263
|
+
stack << :gamma
|
213
264
|
open_gamma += 1
|
214
265
|
else
|
215
|
-
|
266
|
+
stack << :inner
|
216
267
|
inner_body << ins
|
217
268
|
end
|
218
269
|
when :LoopEnd
|
219
|
-
|
220
|
-
inner_body << ins if kind == :inner
|
270
|
+
inner_body << ins if stack.pop == :inner
|
221
271
|
else
|
222
272
|
inner_body << ins
|
223
273
|
end
|
@@ -228,44 +278,70 @@ module Kumi
|
|
228
278
|
def freshen(block_ops, reg_map, pre_map: {})
|
229
279
|
acc_map = {}
|
230
280
|
new_ops = block_ops.map do |ins|
|
281
|
+
attrs = (ins.attributes || {}).dup
|
282
|
+
|
283
|
+
if ins.opcode == :LoopStart
|
284
|
+
attrs[:id] = @ids.generate_loop_id
|
285
|
+
new_el = @ids.generate_temp
|
286
|
+
new_idx = @ids.generate_temp
|
287
|
+
reg_map[attrs[:as_element]] = new_el
|
288
|
+
reg_map[attrs[:as_index]] = new_idx
|
289
|
+
attrs[:as_element] = new_el
|
290
|
+
attrs[:as_index] = new_idx
|
291
|
+
end
|
292
|
+
|
231
293
|
res = ins.result_register
|
232
294
|
reg_map[res] ||= @ids.generate_temp if res
|
295
|
+
|
233
296
|
new_inputs = Array(ins.inputs).map do |r|
|
234
297
|
r1 = pre_map.fetch(r, r)
|
235
298
|
reg_map.fetch(r1, r1)
|
236
299
|
end
|
237
|
-
|
300
|
+
|
238
301
|
case ins.opcode
|
239
302
|
when :DeclareAccumulator
|
240
|
-
|
241
|
-
acc_map[
|
242
|
-
res = acc_map[
|
303
|
+
orig = ins.result_register
|
304
|
+
acc_map[orig] ||= @ids.generate_acc
|
305
|
+
res = acc_map[orig]
|
243
306
|
when :Accumulate
|
244
|
-
|
245
|
-
acc_map[
|
246
|
-
res = acc_map[
|
307
|
+
orig = ins.result_register
|
308
|
+
acc_map[orig] ||= @ids.generate_acc
|
309
|
+
res = acc_map[orig]
|
247
310
|
when :LoadAccumulator
|
248
|
-
|
249
|
-
acc_map[
|
250
|
-
new_inputs[0] = acc_map[
|
251
|
-
when :LoopStart
|
252
|
-
attrs[:id] = @ids.generate_loop_id
|
311
|
+
orig = ins.inputs.first
|
312
|
+
acc_map[orig] ||= @ids.generate_acc
|
313
|
+
new_inputs[0] = acc_map[orig]
|
253
314
|
end
|
254
|
-
|
255
|
-
|
315
|
+
|
316
|
+
LIR::Instruction.new(
|
317
|
+
opcode: ins.opcode,
|
318
|
+
result_register: res ? reg_map.fetch(res, res) : nil,
|
319
|
+
stamp: ins.stamp,
|
320
|
+
inputs: new_inputs,
|
321
|
+
immediates: ins.immediates,
|
322
|
+
attributes: attrs,
|
323
|
+
location: ins.location
|
324
|
+
)
|
256
325
|
end
|
257
326
|
[acc_map, new_ops]
|
258
327
|
end
|
259
328
|
|
260
329
|
def rewrite(ins, _reg_map, rename)
|
261
|
-
new_inputs = Array(ins.inputs).map
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
330
|
+
new_inputs = Array(ins.inputs).map { |r| rename.fetch(r, r) }
|
331
|
+
LIR::Instruction.new(
|
332
|
+
opcode: ins.opcode,
|
333
|
+
result_register: ins.result_register,
|
334
|
+
stamp: ins.stamp,
|
335
|
+
inputs: new_inputs,
|
336
|
+
immediates: ins.immediates,
|
337
|
+
attributes: ins.attributes,
|
338
|
+
location: ins.location
|
339
|
+
)
|
266
340
|
end
|
267
341
|
|
268
|
-
def prefix?(pre, full)
|
342
|
+
def prefix?(pre, full)
|
343
|
+
pre.each_with_index.all? { |tok, i| full[i] == tok }
|
344
|
+
end
|
269
345
|
end
|
270
346
|
end
|
271
347
|
end
|
@@ -9,15 +9,17 @@ module Kumi
|
|
9
9
|
snast_module = get_state(:snast_module)
|
10
10
|
return state unless snast_module
|
11
11
|
|
12
|
-
|
12
|
+
hints = get_state(:hints)
|
13
|
+
output_schema = build_output_schema(snast_module, hints)
|
13
14
|
state.with(:output_schema, output_schema.freeze)
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
17
18
|
|
18
|
-
def build_output_schema(snast_module)
|
19
|
-
snast_module.decls.
|
20
|
-
|
19
|
+
def build_output_schema(snast_module, hints)
|
20
|
+
snast_module.decls.each_with_object({}) do |(name, decl), acc|
|
21
|
+
next if hints[name][:inline]
|
22
|
+
acc[name] = build_output_field(decl)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -1,10 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module Kumi
|
4
|
+
module Core
|
5
|
+
module Functions
|
6
|
+
# Minimal function specification for NAST dimensional analysis
|
7
|
+
FunctionSpec = Struct.new(
|
8
|
+
:id, # "core.add"
|
9
|
+
:kind, # :elementwise, :reduce, :constructor
|
10
|
+
:parameter_names, # [:left_operand, :right_operand]
|
11
|
+
:dtype_rule, # "promote(left_operand,right_operand)" or proc
|
12
|
+
keyword_init: true
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -34,7 +34,7 @@ module Kumi
|
|
34
34
|
parameter_names = (fn_hash["params"] || []).map { |p| p["name"].to_sym }
|
35
35
|
dtype_rule_fn = TypeRules.compile_dtype_rule(fn_hash.fetch("dtype"), parameter_names)
|
36
36
|
|
37
|
-
FunctionSpec.new(
|
37
|
+
Functions::FunctionSpec.new(
|
38
38
|
id: function_id,
|
39
39
|
kind: function_kind,
|
40
40
|
parameter_names: parameter_names,
|
data/lib/kumi/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kumi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- André Muta
|
@@ -265,6 +265,22 @@ files:
|
|
265
265
|
- golden/hierarchical_complex/expected/snast.txt
|
266
266
|
- golden/hierarchical_complex/input.json
|
267
267
|
- golden/hierarchical_complex/schema.kumi
|
268
|
+
- golden/inline_rename_scope_leak/expected.json
|
269
|
+
- golden/inline_rename_scope_leak/expected/ast.txt
|
270
|
+
- golden/inline_rename_scope_leak/expected/input_plan.txt
|
271
|
+
- golden/inline_rename_scope_leak/expected/lir_00_unoptimized.txt
|
272
|
+
- golden/inline_rename_scope_leak/expected/lir_01_hoist_scalar_references.txt
|
273
|
+
- golden/inline_rename_scope_leak/expected/lir_02_inlined.txt
|
274
|
+
- golden/inline_rename_scope_leak/expected/lir_03_cse.txt
|
275
|
+
- golden/inline_rename_scope_leak/expected/lir_04_1_loop_fusion.txt
|
276
|
+
- golden/inline_rename_scope_leak/expected/lir_04_loop_invcm.txt
|
277
|
+
- golden/inline_rename_scope_leak/expected/lir_06_const_prop.txt
|
278
|
+
- golden/inline_rename_scope_leak/expected/nast.txt
|
279
|
+
- golden/inline_rename_scope_leak/expected/schema_javascript.mjs
|
280
|
+
- golden/inline_rename_scope_leak/expected/schema_ruby.rb
|
281
|
+
- golden/inline_rename_scope_leak/expected/snast.txt
|
282
|
+
- golden/inline_rename_scope_leak/input.json
|
283
|
+
- golden/inline_rename_scope_leak/schema.kumi
|
268
284
|
- golden/input_reference/expected.json
|
269
285
|
- golden/input_reference/expected/ast.txt
|
270
286
|
- golden/input_reference/expected/input_plan.txt
|
@@ -521,6 +537,22 @@ files:
|
|
521
537
|
- golden/tuples_and_arrays/expected/snast.txt
|
522
538
|
- golden/tuples_and_arrays/input.json
|
523
539
|
- golden/tuples_and_arrays/schema.kumi
|
540
|
+
- golden/us_tax_2024/expected.json
|
541
|
+
- golden/us_tax_2024/expected/ast.txt
|
542
|
+
- golden/us_tax_2024/expected/input_plan.txt
|
543
|
+
- golden/us_tax_2024/expected/lir_00_unoptimized.txt
|
544
|
+
- golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt
|
545
|
+
- golden/us_tax_2024/expected/lir_02_inlined.txt
|
546
|
+
- golden/us_tax_2024/expected/lir_03_cse.txt
|
547
|
+
- golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt
|
548
|
+
- golden/us_tax_2024/expected/lir_04_loop_invcm.txt
|
549
|
+
- golden/us_tax_2024/expected/lir_06_const_prop.txt
|
550
|
+
- golden/us_tax_2024/expected/nast.txt
|
551
|
+
- golden/us_tax_2024/expected/schema_javascript.mjs
|
552
|
+
- golden/us_tax_2024/expected/schema_ruby.rb
|
553
|
+
- golden/us_tax_2024/expected/snast.txt
|
554
|
+
- golden/us_tax_2024/input.json
|
555
|
+
- golden/us_tax_2024/schema.kumi
|
524
556
|
- golden/with_constants/expected/ast.txt
|
525
557
|
- golden/with_constants/expected/input_plan.txt
|
526
558
|
- golden/with_constants/expected/lir_00_unoptimized.txt
|