What is the difference of `call_function` and `call_method`?

Crazyai: <p>From the FX documentation, I learned that there are several node types:</p>
<ul>
<li>placeholder</li>
<li>getattr</li>
<li>output</li>
<li>call_method</li>
<li>call_function</li>
<li>call_module</li>
</ul>
<p>I have difficulty to tell the last three concepts apart. Could someone explain them using more examples?</p>

Crazyai: <p>Here is an example:</p>
<pre><code class="lang-auto">import torch
import torch.fx as fx
import torch.nn as nn

def myadd(x, y):
    return x + y

class Adder(nn.Module):
    def forward(self, x, y):
        return x + y
    
class M(nn.Module):
    def __init__(self):
        super(M, self).__init__()
        self.adder = Adder()
    
    def forward(self, x, y):
        return x + y, myadd(x, y), torch.add(x, y), x.add(y), self.adder(x, y)

fx.symbolic_trace(M()).graph.print_tabular()

#### output
opcode         name    target                                               args                                  kwargs
-------------  ------  ---------------------------------------------------  ------------------------------------  --------
placeholder    x       x                                                    ()                                    {}
placeholder    y       y                                                    ()                                    {}
call_function  add     &lt;built-in function add&gt;                              (x, y)                                {}
call_function  add_1   &lt;built-in function add&gt;                              (x, y)                                {}
call_function  add_2   &lt;built-in method add of type object at 0x10310d390&gt;  (x, y)                                {}
call_method    add_3   add                                                  (x, y)                                {}
call_function  add_4   &lt;built-in function add&gt;                              (x, y)                                {}
output         output  output                                               ((add, add_1, add_2, add_3, add_4),)  {}

</code></pre>
<p>Why the <code>Adder</code> module not traced as <code>call_module</code>？</p>
<p>What is the difference between <code>Tensor.add</code> and <code>myadd</code>? Because <code>Tensor.add</code> is bound with a Tensor object and thus it is not free?</p>

jfix: <ul>
<li>
<code>call_function</code> is e.g. your <code>myadd</code>, but the FX symbolic tracer will trace through such user-defined functions unless you <a href="https://pytorch.org/docs/stable/fx.html#torch.fx.wrap" rel="noopener nofollow ugc">FX <code>wrap</code></a> them.</li>
<li>
<code>call_module</code> is e.g. your <code>Adder</code> module, but the FX symbolic tracer will trace through such modules unless you tell the symbolic tracer not to via <a href="https://pytorch.org/docs/stable/fx.html#torch.fx.Tracer.is_leaf_module" rel="noopener nofollow ugc">is_leaf_module</a>. See the default logic <a href="https://github.com/pytorch/pytorch/blob/17641fed2a7ed6d27e30d6b7f66c1077b4257f20/torch/fx/_symbolic_trace.py#L313" rel="noopener nofollow ugc">here</a> for <code>is_leaf_module</code>.</li>
<li>
<code>call_method</code> is when you have some method called on a Tensor, e.g. your example <code>x.add(y)</code>. The IR here is just representative of how the original python/pytorch program represented the add; you could likely simply replace all <code>call_method add</code> to <code>call_function torch.add</code> with no difference in output from execution of your module.</li>
</ul>