<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/74740>74740</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [Attributor] Questions on the precision of the Attributor's call graph
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          thomasfaingnaert
      </td>
    </tr>
</table>

<pre>
    Given the following C++ input file:

```cpp
#include <iostream>

struct A { virtual void f() = 0; };
struct A1 : public A { virtual void f() { std::cout << "A1::f()\n"; } };
struct A2 : public A { virtual void f() { std::cout << "A2::f()\n"; } };
struct A3 : public A { virtual void f() { std::cout << "A3::f()\n"; } };

struct B { virtual void f() = 0; };
struct B1 : public B { virtual void f() { std::cout << "B1::f()\n"; } };
struct B2 : public B { virtual void f() { std::cout << "B2::f()\n"; } };
struct B3 : public B { virtual void f() { std::cout << "B3::f()\n"; } };

struct C { virtual void f(int) = 0; };
struct C1 : public C { virtual void f(int) { std::cout << "C1::f(int)\n"; } };

void Af(A *a) { a->f(); }
void Bf(B *b) { b->f(); }
void Cf(C *c) { c->f(0); }

int main() {

    Af(new A1());
    Af(new A2());

    Bf(new B1());
    Bf(new B2());

    Cf(new C1());

    return 0;
}
```

And using the Attributor to generate a callgraph:
```bash
clang++ example.cpp -c -o outputs/example.ll -flto -fvisibility=hidden -fwhole-program-vtables -fsanitize=cfi-icall -O0 -Xclang -disable-O0-optnone
opt outputs/example.ll -passes=attributor --attributor-assume-closed-world --attributor-print-call-graph -disable-output | c++filt | awk 'BEGIN{FS=OFS="\042"} { for (i=2; i<=NF; i+=2) { gsub(/</, "\\\&lt;", $i); gsub(/>/, "\\\&gt;", $i); }} 1' >outputs/example.callgraph.dot
dot outputs/example.callgraph.dot -Tsvg -o outputs/example.callgraph.svg
```

I get the following output:
![example1](https://github.com/llvm/llvm-project/assets/10748726/a72c9965-2c19-4a65-a183-2ba817e7572a)

i.e. `Af(A*)` is assumed to call (a.o.) `A1::f()`, `A2::f()`, `B1::f()`, `B2::f()`, and `C1::f(int)`.

This can be made more precise in (at least) two ways:

1. Calling a function through a pointer of an incompatible type is UB in at least C and C++.
C standard 6.3.2.3 paragraph 8:
> A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

C++ standard 7.6.1.3 paragraph 5
> Calling a function through an expression whose function type E is different from the function type F of the called function’s definition results in undefined behavior unless the type “pointer to F” can be converted to the type “pointer to E” via a function pointer conversion (7.3.14).

Hence, `C1::f(int)` can be removed from the list of possible callees.

2. Using the vtable information encoded in the [Type Metadata](https://llvm.org/docs/TypeMetadata.html) (e.g., emitted through the use of `-flto -fvisibility=hidden -fwhole-program-vtables -fsanitize=cfi-icall`) to restrict the set to `A1::f()` and `A2::f()` only.

It seems that WPD uses some of this information: e.g., the call `c->f(0)` in `Cf` is converted to a direct call to `C1::f(int)`, as that is the only possible callee, but the Attributor does not.

>From what I can tell from https://github.com/llvm/llvm-project/blob/db3bc494875626c6b8e7392f08c631489b056702/llvm/lib/Transforms/IPO/Attributor.cpp#L1072-L1079 and https://github.com/llvm/llvm-project/blob/db3bc494875626c6b8e7392f08c631489b056702/llvm/lib/Transforms/IPO/AttributorAttributes.cpp#L12227-L12232, the Attributor (in closed world module mode) assumes that any function of which the address is taken is a potential callee, which is overly conservative.
Are there any plans/interest for contributions to make use of the function signature and Type Metadata in the Attributor call graph as well?
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMWF1v47rR_jXMzUCCRNmSfZELy47PG-Dt2VN0D9pbShrZ7NKkSlL2SX99MZRk2VlvtnuwFwUCJRbn45mZhzMTC-fkQSM-s2XJlrsn0fujsc_-aE7CtULqgxZo_VNlmrfnX-QZNfgjQmuUMhepD7BlvGS8BKm73kMrFbJsw5IdS6Znngw_ddeNb3gmda36BoFlW2mctyhOLHu5VXPe9rWHDbCihLO0vhcKzkY20DK-YnwNLNtBwrISWLFjWXmvlgLLNtD1lZL1h0aKEpxvCHO2qU3vCRLLtsA436TD61GWLbeacT56fOiV_wyv_Ee9Zj_Da_bfer3zXf658pR35fnIyAeQyx8tT8l_htcfLU-Z_Qyvf64828fepPbfq9D2rkLfsfMB8O1NkQbx72IP5oPCBhjfiMmFiFj2MiVgRD0rlHRSkkI1KVQfKmzphDBu6kmhnhSS9xrDU2oPJyH1XLDbUwAYYGu8wCYd_QZDjwT41wKzWDmJld-wMwt8aGc7iW0f2JnFLPre6kCG8ega-NS9b1U2uoHeUfenWbDx3sqq98aCN3BAjVZ4BAG1UOpgRXecJ8JkrRLuOLyqldCHcYbgH-LUKYzrroOohsiA6X3Xe8f4fjpTCqJWeQNRe5ZOVlJJ_8ay3VE2DWqI2svRKIw6aw5WnKKzF5VCB1HrhJZe_htZtqtbGUlCB9GnBKJ_BAwQNdKRcPQpiUzntdE4QDSd_waQTjiHjmU7MecgiuYPkXCuP2FUK-OwiS7GquZeoLNS-4iwRCFVM4rBI7BiC_WQn1aq4bO4fAHGi_Lll9dfWVHu_8ay3afwpIu13CYLTn-E21VCayzQ7WPZLtw6GW7n7tf98IGX4WC8AgfXV4Epe5Lie8bDNWbL7fjDc-WJJpwPRws53pVbzZfHmofHmkS2Ygcp4wWw7OXrVF-JFDfGDzVpzKOa3AlC9NmdD49ZNAu68-EDpr_CAf27jWewNnOap2xZjoZTttwxvjp63zmSoDTsD9If-yquzYnxvVLn6ReR9J9Ye8b3xKMAME2KxargOb0reL1e58uI1-k6Woh8GYl0lUW8Equ0wGJZcOqNdw0qxhhYngzdk_ENnecJSAcDExu6ooH5jK9EbOJQ9zx5v-rkSahRnrzfRq4H76fvfPBQQ-iGDh-MgzyJb0P4fJQOaqGhQjiJBuFkLEJnsZYOQeoA3INC4cLw8RcDF_Hm3m2daQxboRTVS0Db69pLQ6urNf3hCAI6I7VHC6YFoUHq2pw64WWlEPxbh5Sx32mphckXDDGM6-4IeQvOC90I20AeZzGPM-iEFcNNXs2QshfYXF16cwvJtGD06PQk3ijs2ugzWj8US3xbT2jjj3RAugSuEvUXEAeaUFkZWGvR9cqDO1LJQ4wWAf9FU9ybIGGsPEgt1OQmhteWevcVw-ReOujdDYFusFyOxs1508bDTTov0h9HLC1a1DXZeOuQWEGvKzyKszSDA91gKzU2d5SY_sW45rqI8zi9y_VyTvRHZdeAf3QWnZtRz0IE_4VQNLINSD201pyG238ntafs02tKBDbXU_bC2Sph67WDEIcMKkMNHJHpGt8cda8VOhesBduTje1N2ffTy910M-4o8qHuy6x7luI2K5PQYCukhPFVEWdxumB8fVeC_6O6jRf84R2egFk8mTOlZMqcks5TujrjXOBDyBm6O_M8ht-v-8QwskHq1tiTCFBR16bBhlJIEmxZfqZ4_4JeNMKLR02XGmxs7IHxfWNqaq2kMmnER39SoffxFcaHmELDk_QhoyNbyFPvkMCzPPl5S0foiGuqjUXnrayHAeNo0JjHzXhqn193YzBavd3l8tWDQzwRpYSHv_-2oyAcOHPCgbbS3eaWtvwpAxOlydX9LkwzRIfit-M8edekGmmx9oP2EMVDmoRRMEKTA-spgPfsILGq9-_Xy8ZgaC938e6JaRcy-BpI6FGpgX4_PIUrZSriS5VV9WK9WBXLnOd1Xq2wyNa8TVZ1nqWL1bpKlnmR8Bs7kvQ-W6EdJZbY9vrbJ8b3M3haahnP_j9NCh7Rcx2K-j-FcfoL3RUt57yI6FfGJ4bcFCSUFobtFobt9mSaXtHUbpBYPqwdY8WFfrsbYJejrId7JpqG2nLghPiCOmws0BmP2kuhbmgx6EgH5oxWvREPHdqz8PKMIy82FsmoxeCwU0JTsKHZofNhH66NHoKQRjsi7El8ud72u4bv5EEL39thwt61nakd3SQk8H8YScLBBZVi2f6pec6adbYWT_icFkm6LpJ8kT4dn5eYLJpmURRZWqwXuF6iqKpFnlR1sU5Wef4kn3nCs5QnRVpkBU9j0ebNqsrqVd1ysWwytkjwJKSKp3b3JJ3r8blYFIvkSYkKlQtf7XFO_wWGw7CU757sc2BW1R8cWyTUpt1sxUuvwneCc2xsuYO_9uiGlJkh9GEvG8t5nwvGC3eTj6fequcfZnsATNULAf0nAAD__zkvL6k">