kumi 0.0.23 → 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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +2 -2
  4. data/golden/array_element/expected/schema_ruby.rb +1 -1
  5. data/golden/array_index/expected/schema_ruby.rb +1 -1
  6. data/golden/array_operations/expected/schema_ruby.rb +1 -1
  7. data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
  8. data/golden/chained_fusion/expected/schema_ruby.rb +1 -1
  9. data/golden/element_arrays/expected/schema_ruby.rb +1 -1
  10. data/golden/empty_and_null_inputs/expected/schema_ruby.rb +1 -1
  11. data/golden/game_of_life/expected/lir_00_unoptimized.txt +33 -33
  12. data/golden/game_of_life/expected/lir_01_hoist_scalar_references.txt +33 -33
  13. data/golden/game_of_life/expected/lir_02_inlined.txt +296 -296
  14. data/golden/game_of_life/expected/lir_03_cse.txt +128 -128
  15. data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +128 -128
  16. data/golden/game_of_life/expected/lir_04_loop_invcm.txt +128 -128
  17. data/golden/game_of_life/expected/lir_06_const_prop.txt +128 -128
  18. data/golden/game_of_life/expected/schema_ruby.rb +1 -1
  19. data/golden/hash_keys/expected/schema_ruby.rb +1 -1
  20. data/golden/hash_keys/schema.kumi +4 -5
  21. data/golden/hash_value/expected/schema_ruby.rb +1 -1
  22. data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -1
  23. data/golden/inline_rename_scope_leak/expected/ast.txt +48 -0
  24. data/golden/inline_rename_scope_leak/expected/input_plan.txt +10 -0
  25. data/golden/inline_rename_scope_leak/expected/lir_00_unoptimized.txt +35 -0
  26. data/golden/inline_rename_scope_leak/expected/lir_01_hoist_scalar_references.txt +35 -0
  27. data/golden/inline_rename_scope_leak/expected/lir_02_inlined.txt +49 -0
  28. data/golden/inline_rename_scope_leak/expected/lir_03_cse.txt +49 -0
  29. data/golden/inline_rename_scope_leak/expected/lir_04_1_loop_fusion.txt +49 -0
  30. data/golden/inline_rename_scope_leak/expected/lir_04_loop_invcm.txt +49 -0
  31. data/golden/inline_rename_scope_leak/expected/lir_06_const_prop.txt +49 -0
  32. data/golden/inline_rename_scope_leak/expected/nast.txt +31 -0
  33. data/golden/inline_rename_scope_leak/expected/schema_javascript.mjs +51 -0
  34. data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +82 -0
  35. data/golden/inline_rename_scope_leak/expected/snast.txt +31 -0
  36. data/golden/inline_rename_scope_leak/expected.json +7 -0
  37. data/golden/inline_rename_scope_leak/input.json +4 -0
  38. data/golden/inline_rename_scope_leak/schema.kumi +24 -0
  39. data/golden/input_reference/expected/schema_ruby.rb +1 -1
  40. data/golden/interleaved_fusion/expected/schema_ruby.rb +1 -1
  41. data/golden/let_inline/expected/schema_ruby.rb +1 -1
  42. data/golden/loop_fusion/expected/schema_ruby.rb +1 -1
  43. data/golden/min_reduce_scope/expected/schema_ruby.rb +1 -1
  44. data/golden/mixed_dimensions/expected/schema_ruby.rb +1 -1
  45. data/golden/multirank_hoisting/expected/schema_ruby.rb +1 -1
  46. data/golden/nested_hash/expected/schema_ruby.rb +1 -1
  47. data/golden/reduction_broadcast/expected/schema_ruby.rb +1 -1
  48. data/golden/roll/expected/lir_00_unoptimized.txt +8 -8
  49. data/golden/roll/expected/lir_01_hoist_scalar_references.txt +8 -8
  50. data/golden/roll/expected/lir_02_inlined.txt +8 -8
  51. data/golden/roll/expected/lir_03_cse.txt +8 -8
  52. data/golden/roll/expected/lir_04_1_loop_fusion.txt +8 -8
  53. data/golden/roll/expected/lir_04_loop_invcm.txt +8 -8
  54. data/golden/roll/expected/lir_06_const_prop.txt +8 -8
  55. data/golden/roll/expected/schema_ruby.rb +1 -1
  56. data/golden/shift/expected/lir_00_unoptimized.txt +12 -12
  57. data/golden/shift/expected/lir_01_hoist_scalar_references.txt +12 -12
  58. data/golden/shift/expected/lir_02_inlined.txt +12 -12
  59. data/golden/shift/expected/lir_03_cse.txt +12 -12
  60. data/golden/shift/expected/lir_04_1_loop_fusion.txt +12 -12
  61. data/golden/shift/expected/lir_04_loop_invcm.txt +12 -12
  62. data/golden/shift/expected/lir_06_const_prop.txt +12 -12
  63. data/golden/shift/expected/schema_ruby.rb +1 -1
  64. data/golden/shift_2d/expected/lir_00_unoptimized.txt +48 -48
  65. data/golden/shift_2d/expected/lir_01_hoist_scalar_references.txt +48 -48
  66. data/golden/shift_2d/expected/lir_02_inlined.txt +48 -48
  67. data/golden/shift_2d/expected/lir_03_cse.txt +48 -48
  68. data/golden/shift_2d/expected/lir_04_1_loop_fusion.txt +48 -48
  69. data/golden/shift_2d/expected/lir_04_loop_invcm.txt +48 -48
  70. data/golden/shift_2d/expected/lir_06_const_prop.txt +48 -48
  71. data/golden/shift_2d/expected/schema_ruby.rb +1 -1
  72. data/golden/simple_math/expected/schema_ruby.rb +1 -1
  73. data/golden/streaming_basics/expected/schema_ruby.rb +1 -1
  74. data/golden/tuples/expected/lir_00_unoptimized.txt +4 -4
  75. data/golden/tuples/expected/lir_01_hoist_scalar_references.txt +4 -4
  76. data/golden/tuples/expected/lir_02_inlined.txt +4 -4
  77. data/golden/tuples/expected/lir_03_cse.txt +4 -4
  78. data/golden/tuples/expected/lir_04_1_loop_fusion.txt +4 -4
  79. data/golden/tuples/expected/lir_04_loop_invcm.txt +4 -4
  80. data/golden/tuples/expected/lir_06_const_prop.txt +4 -4
  81. data/golden/tuples/expected/schema_ruby.rb +1 -1
  82. data/golden/tuples_and_arrays/expected/lir_00_unoptimized.txt +1 -1
  83. data/golden/tuples_and_arrays/expected/lir_01_hoist_scalar_references.txt +1 -1
  84. data/golden/tuples_and_arrays/expected/lir_02_inlined.txt +2 -2
  85. data/golden/tuples_and_arrays/expected/lir_03_cse.txt +2 -2
  86. data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +2 -2
  87. data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +2 -2
  88. data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +2 -2
  89. data/golden/tuples_and_arrays/expected/schema_ruby.rb +1 -1
  90. data/golden/us_tax_2024/expected/ast.txt +865 -0
  91. data/golden/us_tax_2024/expected/input_plan.txt +61 -0
  92. data/golden/us_tax_2024/expected/lir_00_unoptimized.txt +901 -0
  93. data/golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt +901 -0
  94. data/golden/us_tax_2024/expected/lir_02_inlined.txt +5178 -0
  95. data/golden/us_tax_2024/expected/lir_03_cse.txt +2499 -0
  96. data/golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt +2519 -0
  97. data/golden/us_tax_2024/expected/lir_04_loop_invcm.txt +2439 -0
  98. data/golden/us_tax_2024/expected/lir_06_const_prop.txt +2439 -0
  99. data/golden/us_tax_2024/expected/nast.txt +976 -0
  100. data/golden/us_tax_2024/expected/schema_javascript.mjs +584 -0
  101. data/golden/us_tax_2024/expected/schema_ruby.rb +639 -0
  102. data/golden/us_tax_2024/expected/snast.txt +976 -0
  103. data/golden/us_tax_2024/expected.json +1 -0
  104. data/golden/us_tax_2024/input.json +168 -0
  105. data/golden/us_tax_2024/schema.kumi +203 -0
  106. data/golden/with_constants/expected/schema_ruby.rb +1 -1
  107. data/lib/kumi/core/analyzer/passes/lir/inline_declarations_pass.rb +181 -105
  108. data/lib/kumi/version.rb +1 -1
  109. 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).with(:lir_02_inlined_ops_by_decl, 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
- # Call the new top-level inliner
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 = Env.new
52
- reg_map = {}
45
+ env = Env.new
46
+ reg_map = {}
53
47
  rename_map = {}
54
- processed_ops, hoisted_ops = process_and_hoist_block(ops, env, reg_map, rename_map)
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
- processed_ops
51
+ processed
60
52
  end
61
53
 
62
- # --- NEW: The core recursive block processor ---
63
- # Returns two arrays: [ processed_instructions_for_this_block, instructions_to_hoist_up_one_level ]
54
+ # ---------------- core ----------------
55
+
56
+ # returns [processed_ops, hoisted_ops]
64
57
  def process_and_hoist_block(block_ops, env, reg_map, rename_map)
65
- out_ops = []
66
- hoisted_out_ops = [] # Operations to be returned to the parent scope
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 = find_matching_loop_end(block_ops, i)
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
- processed_body, hoisted_from_child = process_and_hoist_block(loop_body, env, reg_map, rename_map)
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
- # This is the crucial step: emit code hoisted from the child loop
81
- # BEFORE emitting the child loop itself.
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
- # Now, emit the reconstructed loop with its processed body
85
- out_ops << rewrite(ins, reg_map, rename_map)
86
- out_ops.concat(processed_body)
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 # Jump iterator past the entire loop block
81
+ i = end_idx
90
82
 
91
83
  when :LoadDeclaration
92
- # This helper now decides if ops go inline or get returned for hoisting
93
- inline_ops, hoist_ops = handle_load_declaration(ins, env, reg_map, rename_map)
94
- out_ops.concat(inline_ops)
95
- hoisted_out_ops.concat(hoist_ops)
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
- out_ops << rewrite(ins, reg_map, rename_map)
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
- # --- NEW: Helper to manage LoadDeclaration logic ---
107
- # Returns two arrays: [ instructions_to_add_inline, instructions_to_hoist ]
108
- def handle_load_declaration(ins, env, reg_map, rename_map)
109
- callee = ins.immediates.first.value.to_sym
110
- decl_axes = ins.attributes.fetch(:axes)
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, callee_regs = inline_callee_core(callee)
114
- remap = remap_axes(callee_regs, env)
115
- _acc, fresh_ops = freshen(body, reg_map, pre_map: remap)
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
- rename_yielded_register(ins, yield_reg, reg_map, remap, rename_map)
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
- [[], fresh_ops] # Return ops in the 'hoist' bucket
122
- # Case 2: In-place
138
+ [[], hoisted_inner + processed_inner] # hoist
123
139
  elsif decl_axes == site_axes
124
- [fresh_ops, []] # Return ops in the 'inline' bucket
125
- # Case 3: Cannot inline
140
+ [hoisted_inner + processed_inner, []] # inline in place
126
141
  else
127
- [[rewrite(ins, reg_map, rename_map)], []]
142
+ [[rewrite(call_ins, reg_map, outer_rename_map)], []] # cannot inline
128
143
  end
129
144
  end
130
145
 
131
- # --- UNCHANGED AND ORIGINAL HELPERS ---
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; (start_index + 1...ops.length).each do |i|
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]] = caller[: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 << { axis: loop_ins.attributes[:axis], el: loop_ins.attributes[:as_element], idx: loop_ins.attributes[:as_index] }
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
- def reg_for_axis(axis) = @frames.reverse.find { _1[:axis] == axis } || raise("no element for #{axis}")
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 << { axis: ins.attributes[:axis], el: ins.attributes[:as_element], idx: ins.attributes[:as_index] }
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 do |f|
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
- prologue = ops[0...first_loop_index]
204
- main_part = ops[first_loop_index...yield_index]
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
- kind_stack = []
208
- main_part.each do |ins|
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
- kind_stack << :gamma
263
+ stack << :gamma
213
264
  open_gamma += 1
214
265
  else
215
- kind_stack << :inner
266
+ stack << :inner
216
267
  inner_body << ins
217
268
  end
218
269
  when :LoopEnd
219
- kind = kind_stack.pop or raise "unbalanced loops in #{callee_name}"
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
- attrs = (ins.attributes || {}).dup
300
+
238
301
  case ins.opcode
239
302
  when :DeclareAccumulator
240
- original_acc = ins.result_register
241
- acc_map[original_acc] ||= @ids.generate_acc
242
- res = acc_map[original_acc]
303
+ orig = ins.result_register
304
+ acc_map[orig] ||= @ids.generate_acc
305
+ res = acc_map[orig]
243
306
  when :Accumulate
244
- original_acc = ins.result_register
245
- acc_map[original_acc] ||= @ids.generate_acc
246
- res = acc_map[original_acc]
307
+ orig = ins.result_register
308
+ acc_map[orig] ||= @ids.generate_acc
309
+ res = acc_map[orig]
247
310
  when :LoadAccumulator
248
- original_acc = ins.inputs.first
249
- acc_map[original_acc] ||= @ids.generate_acc
250
- new_inputs[0] = acc_map[original_acc]
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
- LIR::Instruction.new(opcode: ins.opcode, result_register: res ? reg_map.fetch(res, res) : nil, stamp: ins.stamp, inputs: new_inputs,
255
- immediates: ins.immediates, attributes: attrs, location: ins.location)
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 do |r|
262
- rename.fetch(r, r)
263
- end
264
- LIR::Instruction.new(opcode: ins.opcode, result_register: ins.result_register, stamp: ins.stamp, inputs: new_inputs,
265
- immediates: ins.immediates, attributes: ins.attributes, location: ins.location)
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) = pre.each_with_index.all? { |tok, i| full[i] == tok }
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
data/lib/kumi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kumi
4
- VERSION = "0.0.23"
4
+ VERSION = "0.0.24"
5
5
  end
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.23
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