[mono][interp] Reduce redundant moves with calls (#79905)
authorVlad Brezae <brezaevlad@gmail.com>
Fri, 27 Jan 2023 14:26:56 +0000 (16:26 +0200)
committerGitHub <noreply@github.com>
Fri, 27 Jan 2023 14:26:56 +0000 (16:26 +0200)
We were marking INTERP_LOCAL_FLAG_NO_CALL_ARGS for source vars of non calls. With further optimizations, the var could end up being used only for the call but we never unset the flag. Reuse the ref count data, which is kept updated following optimizations, to achieve same thing. If cprop is not run then we always duplicate the args, but this is an unused scenario.

src/mono/mono/mini/interp/transform.c

index 0fda118..9f99a17 100644 (file)
@@ -9194,11 +9194,6 @@ retry:
                                        }
                                } else {
                                        cprop_sreg (td, ins, &sregs [i], local_defs);
-                                       // This var is used as a source to a normal instruction. In case this var will
-                                       // also be used as source to a call, make sure the offset allocator will create
-                                       // a new temporary call arg var and not use this one. Call arg vars have special
-                                       // semantics. They can be assigned only once and they die once the call is made.
-                                       td->locals [sregs [i]].flags |= INTERP_LOCAL_FLAG_NO_CALL_ARGS;
                                }
                        }
 
@@ -10389,9 +10384,12 @@ interp_alloc_offsets (TransformData *td)
 
                                        while (var != -1) {
                                                if (td->locals [var].flags & INTERP_LOCAL_FLAG_GLOBAL ||
+                                                               !td->local_ref_count || td->local_ref_count [var] > 1 ||
                                                                td->locals [var].flags & INTERP_LOCAL_FLAG_NO_CALL_ARGS) {
-                                                       // A global var is an argument to a call, which is not allowed. We need
-                                                       // to copy the global var into a local var
+                                                       // Some vars can't be allocated on the call args stack, since the constraint is that
+                                                       // call args vars die after the call. This isn't necessarily true for global vars or
+                                                       // vars that are used by other instructions aside from the call.
+                                                       // We need to copy the var into a new tmp var
                                                        int new_var = create_interp_local (td, td->locals [var].type);
                                                        td->locals [new_var].call = ins;
                                                        td->locals [new_var].flags |= INTERP_LOCAL_FLAG_CALL_ARGS;