@@ -91,16 +91,33 @@ let rec analyze_usage = instrs => {
9191 };
9292 };
9393
94+ let process_tail_call_arg = imm => {
95+ switch (imm. immediate_desc) {
96+ | MImmBinding (binding ) =>
97+ switch (BindMap . find(binding, usage_map^ )) {
98+ | Some (imm ) => imm. immediate_analyses. last_usage = TailCallLast
99+ | None => ()
100+ }
101+ | MImmConst (_ )
102+ | MImmTrap
103+ | MIncRef (_ ) => ()
104+ };
105+ };
106+
94107 let rec process_instr = instr => {
95108 switch (instr. instr_desc) {
96109 | MImmediate (imm ) => process_imm(imm)
97110 | MCallRaw ({args}) => List . iter(process_imm, args)
98111 | MCallKnown ({closure: func , args})
112+ | MCallIndirect ({func, args}) =>
113+ process_imm(func);
114+ List . iter(process_imm, args);
99115 | MReturnCallKnown ({closure: func , args})
100- | MCallIndirect ({func, args})
101116 | MReturnCallIndirect ({func, args}) =>
102117 process_imm(func);
103118 List . iter(process_imm, args);
119+ process_tail_call_arg(func);
120+ List . iter(process_tail_call_arg, args);
104121 | MError (e , args ) => List . iter(process_imm, args)
105122 | MAllocate (alloc ) =>
106123 switch (alloc) {
@@ -211,6 +228,12 @@ let is_last_usage = imm =>
211228 | _ => false
212229 };
213230
231+ let is_last_tail_call_usage = imm =>
232+ switch (imm. immediate_analyses. last_usage) {
233+ | TailCallLast => true
234+ | _ => false
235+ };
236+
214237type bind_state =
215238 | Alive
216239 | Dead ;
@@ -275,7 +298,8 @@ let rec apply_gc = (~level, ~loop_context, ~implicit_return=false, instrs) => {
275298 },
276299 };
277300
278- let handle_imm = (~non_gc_instr= false , ~is_return= false , imm) => {
301+ let handle_imm =
302+ (~non_gc_instr= false , ~is_return= false , ~is_tail= false , imm) => {
279303 switch (imm. immediate_desc) {
280304 | MImmBinding ((MArgBind (_ ) | MLocalBind (_ ) | MClosureBind (_ )) as binding ) =>
281305 let alloc =
@@ -314,10 +338,12 @@ let rec apply_gc = (~level, ~loop_context, ~implicit_return=false, instrs) => {
314338 );
315339 switch (alloc) {
316340 | Unmanaged (_ ) => imm
317- | Managed when non_gc_instr || is_return => imm
341+ | Managed when non_gc_instr || is_return || is_tail => imm
318342 | Managed => incref(imm)
319343 };
320344 };
345+ } else if (is_last_tail_call_usage(imm)) {
346+ imm;
321347 } else {
322348 switch (alloc) {
323349 | Managed when non_gc_instr || is_return => imm
@@ -352,8 +378,8 @@ let rec apply_gc = (~level, ~loop_context, ~implicit_return=false, instrs) => {
352378 // tail calls will use arguments directly without the need to incref
353379 MReturnCallKnown ({
354380 ... data,
355- closure: handle_imm(~is_return = true , closure),
356- args: List . map(handle_imm(~is_return = true ), args),
381+ closure: handle_imm(~is_tail = true , closure),
382+ args: List . map(handle_imm(~is_tail = true ), args),
357383 })
358384 | MCallIndirect ({func, args} as data ) =>
359385 MCallIndirect ({
@@ -365,8 +391,8 @@ let rec apply_gc = (~level, ~loop_context, ~implicit_return=false, instrs) => {
365391 // tail calls will use arguments directly without the need to incref
366392 MReturnCallIndirect ({
367393 ... data,
368- func: handle_imm(~is_return = true , func),
369- args: List . map(handle_imm(~is_return = true ), args),
394+ func: handle_imm(~is_tail = true , func),
395+ args: List . map(handle_imm(~is_tail = true ), args),
370396 })
371397 | MError (e , args ) => MError (e, List . map(handle_imm, args))
372398 | MAllocate (alloc ) =>
0 commit comments