You can't say that one version is always better than the other. Sometimes it is better to pack parameters into a struct, and sometimes it is worse.
In the x86_64 ABI, there is a difference between passing 2x int and a single struct parameter.
- in the former case, each intis passed via a separate registeredi,esi
- in the latter case, the structmembers are packed into a single registerrdi
As a rule of thumb, a struct is better when we perform operations with the whole struct (like passing it to other functions), whereas separate parameters are better when using them in separate ways.
Positive Cost struct
struct point {
    int x;
    int y;
};
int sum(int x, int y) {
    return x + y;
}
int struct_sum(struct point p) {
    return p.x + p.y;
}
Which produces: (GCC 13 -O2)
sum:
        lea     eax, [rdi+rsi]
        ret
struct_sum:
        mov     rax, rdi
        shr     rax, 32
        add     eax, edi
        ret
You can see that sum simply computes the sum of rdi and rsi, whereas struct_sum first has to unpack the operands into separate registers, since they both start in rdi.
Negative Cost struct
struct point {
    int x;
    int y;
};
struct point lowest_bit(int x, int y) {
    return (struct point) {x & 1, y & 1};
}
struct point struct_lowest_bit(struct point p) {
    return (struct point) {p.x & 1, p.y & 1};
}
Which procudes: (clang trunk -O2)
lowest_bit:
        and     edi, 1
        and     esi, 1
        shl     rsi, 32
        lea     rax, [rdi + rsi]
        ret
struct_lowest_bit:
        movabs  rax, 4294967297
        and     rax, rdi
        ret
Note: GCC doesn't find this optimization for some reason.
In this case, it's better for both members to be packed into rdi, because performing & 1 with either one of them can be parallelized this way.
Also see: C++ Weekly - Ep 119 - Negative Cost Structs (C++ video, but equally applies to C due to similar ABI).