llvm / llvm/llvm-project

Unnecessary copying of struct field when the same field is later overwritten

Open
#163,899 3 comments 1 reaction 0 assignees View on GitHub
backend:AArch64 backend:X86 missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

These functions should all produce the same assembly

https://godbolt.org/z/4c674fKxE

```c
typedef unsigned long u64;

typedef struct {
u64 x;
u64 y;
u64 z;
} Big;

// Not optimized

Big assign(Big b) {
b.x = 0;
return b;
}

Big copy_then_assign(Big b) {
Big c = b;
c.x = 0;
return c;
}

Big memcpy_then_assign(Big b) {
Big c;
__builtin_memcpy(&c, &b, sizeof(b));
c.x = 0;
return c;
}

// Optimized

Big c99_initializer(Big b) { return (Big){0, b.y, b.z}; }

Big c99_initializer2(Big b) {
Big c = {b.x, b.y, b.z};
c.x = 0;
return c;
}

Big copy_individually(Big b) {
Big c;
c.x = 0;
c.y = b.y;
c.z = b.z;
return c;
}

Big copy_individually_then_assign(Big b) {
Big c;
c.x = b.x;
c.y = b.y;
c.z = b.z;
c.x = 0;
return c;
}
```

Unoptimized assembly:
```asm
assign:
str xzr, [x0]
ldr x9, [x0, #16]
ldr q0, [x0]
str x9, [x8, #16]
str q0, [x8]
ret

```

Optimized assembly:
```asm
c99_initializer:
ldur q0, [x0, #8]
str xzr, [x8]
stur q0, [x8, #8]
ret
```

Contributor guide

Open the contributing guide

Research direction

Start with the C reproducer linked on Godbolt and compare the assembly for assign, copy_then_assign, and memcpy_then_assign with the optimized initializer examples. Trace the LLVM optimization path responsible for struct copies and verify the result by checking that the affected functions avoid copying fields later overwritten while preserving the returned values.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.