-
Notifications
You must be signed in to change notification settings - Fork 18.1k
[Clang] Forward incoming Indirect parameters across musttail calls #199351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
xroche
wants to merge
26
commits into
llvm:main
Choose a base branch
from
xroche:musttail-byval-temp-fix
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 16 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
cf30821
[Clang] Forward incoming Indirect parameters across musttail calls
xroche a1c3fd3
[Clang][NFC] Trim comments on musttail Indirect forwarding helper
xroche 11cdbbf
[Clang] Address review on musttail Indirect forwarding
xroche 4359083
[Clang] Extend musttail Indirect forwarding to C++ trivial-copy args
xroche 9b1aa8b
[Clang][test] Mirror C test cases in musttail-indirect-arg.cpp
xroche 99dfa79
[Clang] Switch musttail Indirect to a two-phase general algorithm
xroche 88607e8
[Clang][test] Strengthen P3 and P17 to catch in-place-write regression
xroche 2dd4ce8
Merge branch 'main' into musttail-byval-temp-fix
xroche a27213a
Merge branch 'main' into musttail-byval-temp-fix
xroche d12920e
[Clang] Diagnose musttail Indirect args with no addressable source
xroche 7231b68
Merge remote-tracking branch 'origin/main' into musttail-byval-temp-fix
xroche f008bf5
[Clang][test] Make musttail-indirect-arg scratch checks SROA-robust
xroche 1248313
Merge remote-tracking branch 'origin/main' into musttail-byval-temp-fix
xroche 40a7edf
Merge branch 'main' into musttail-byval-temp-fix
xroche 6964a03
Merge branch 'main' into musttail-byval-temp-fix
xroche 3a58836
[Clang][test] Pin slot operands and swap data-flow in musttail-indire…
xroche 6f56dba
[Clang] Drop redundant freeze of forwarded musttail Indirect pointer
xroche cb7efcb
[Clang] Forward trivially-copyable by-value args beyond musttail
xroche 3a8db70
[Clang][test] Cover musttail Indirect arg with no in-memory source
xroche 2a770e5
[Clang] Exclude CUDA surface/texture types from by-value arg forwarding
xroche 5be3d32
[Clang] Exclude ObjC GC object-member records from by-value arg forwa…
xroche 9905d11
Merge remote-tracking branch 'origin/main' into musttail-byval-temp-fix
xroche 8c5c3be
[Clang] Re-gate trivial-copy arg forwarding to musttail calls
xroche beda9ba
[Clang] Accept any same-type glvalue as musttail forwarding source
xroche d6fe44f
[Clang][test] Note the unsupported musttail Indirect case is liftable
xroche c3ba863
[Clang] Restrict musttail forwarding sources to pure lvalue chains
xroche File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // RUN: %clang_cc1 -triple=riscv64-linux-gnu %s -emit-llvm -O1 -o - | FileCheck %s --check-prefix=COMMON | ||
| // RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -O1 -o - | FileCheck %s --check-prefix=COMMON | ||
| // RUN: %clang_cc1 -triple=loongarch64-linux-gnu %s -emit-llvm -O1 -o - | FileCheck %s --check-prefix=COMMON | ||
| // RUN: %clang_cc1 -triple=s390x-linux-gnu %s -emit-llvm -O1 -o - | FileCheck %s --check-prefix=COMMON | ||
|
|
||
| // Musttail calls with struct-by-value args must route each value through the | ||
| // matching incoming Indirect parameter's storage, not a local alloca that | ||
| // dangles past the tail-call frame teardown. For each Indirect slot i: if | ||
| // the source IS the i-th incoming pointer, pass it; otherwise memcpy the | ||
| // source into the i-th incoming pointer and pass that. Each call slot ends | ||
| // up with a distinct pointer in the caller's caller's frame. | ||
|
|
||
| // Plain Indirect-ABI struct on the targets above. | ||
| struct Big { | ||
| unsigned long long a, b, c, d; | ||
| }; | ||
|
|
||
| // P1: simple forward. | ||
| struct Big C1(struct Big a); | ||
| struct Big P1(struct Big a) { | ||
| __attribute__((musttail)) return C1(a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P1( | ||
| // COMMON-NOT: = alloca {{.*}}struct.Big | ||
| // COMMON: musttail call {{.*}} @C1({{.*}}, ptr {{[^,]*}} %a) | ||
|
|
||
| // P2: two distinct incoming sources. | ||
| struct Big C2(struct Big a, struct Big b); | ||
| struct Big P2(struct Big a, struct Big b) { | ||
| __attribute__((musttail)) return C2(a, b); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P2( | ||
| // COMMON-NOT: = alloca {{.*}}struct.Big | ||
| // COMMON-NOT: llvm.memcpy | ||
| // COMMON: musttail call {{.*}} @C2({{.*}}, ptr {{[^,]*}} %a, ptr {{[^,]*}} %b) | ||
|
|
||
| // P3: swap. Pin the data flow: %a is captured before %b overwrites it, and | ||
| // the saved %a lands in %b. An in-place memmove(%a,%b);memmove(%b,%a) would | ||
| // drop orig_a, so both slots would read orig_b. | ||
| struct Big C3(struct Big x, struct Big y); | ||
| struct Big P3(struct Big a, struct Big b) { | ||
| __attribute__((musttail)) return C3(b, a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P3( | ||
| // COMMON: [[SAVED:%musttail.copy[0-9.a-z]*]] = load {{.*}}, ptr %a, | ||
| // COMMON: @llvm.mem{{(cpy|move)}}{{.*}}(ptr {{[^,]*}} %a, ptr {{[^,]*}} %b, | ||
| // COMMON: store {{.*}} [[SAVED]], ptr %b, | ||
| // COMMON: musttail call {{.*}} @C3({{.*}}, ptr {{[^,]*}} %a, ptr {{[^,]*}} %b) | ||
|
|
||
| // P5: caller mutates the parameter before the musttail. The mutation lands | ||
| // at the incoming pointer the callee receives. | ||
| struct Big C5(struct Big a); | ||
| struct Big P5(struct Big a) { | ||
| a.a += 1; | ||
| __attribute__((musttail)) return C5(a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P5( | ||
| // COMMON: musttail call {{.*}} @C5({{.*}}, ptr {{[^,]*}} %a) | ||
|
|
||
| // P6: musttail in a non-entry block. | ||
| struct Big C6(struct Big a, int cond); | ||
| struct Big P6(struct Big a, int cond) { | ||
| if (cond) | ||
| __attribute__((musttail)) return C6(a, cond); | ||
| return a; | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P6( | ||
| // COMMON: musttail call {{.*}} @C6({{.*}}, ptr {{[^,]*}} %a, | ||
|
|
||
| // P7: same arg to two slots. C ABI requires distinct storage per by-value | ||
| // param, so slot 1 cannot share %a's pointer. Slot 0 forwards %a; slot 1 | ||
| // memcpys *%a into the i=1 incoming pointer %b and forwards %b. | ||
| struct Big C7(struct Big x, struct Big y); | ||
| struct Big P7(struct Big a, struct Big b) { | ||
| __attribute__((musttail)) return C7(a, a); | ||
|
xroche marked this conversation as resolved.
|
||
| } | ||
| // COMMON-LABEL: define {{.*}} @P7( | ||
| // COMMON: llvm.mem{{(cpy|move)}}{{.*}}(ptr {{[^,]*}} %b, ptr {{[^,]*}} %a, | ||
| // COMMON: musttail call {{.*}} @C7({{.*}}, ptr {{[^,]*}} %a, ptr {{[^,]*}} %b) | ||
|
|
||
| // P8: local source. The local lives in our frame; copy it into %a, forward %a. | ||
| struct Big C8(struct Big a); | ||
| struct Big P8(struct Big a) { | ||
| struct Big local = {1, 2, 3, 4}; | ||
| __attribute__((musttail)) return C8(local); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P8( | ||
| // COMMON: llvm.mem{{(cpy|move)}}{{.*}}(ptr {{[^,]*}} %a, ptr {{.*}} | ||
| // COMMON: musttail call {{.*}} @C8({{.*}}, ptr {{[^,]*}} %a) | ||
|
|
||
| // P9: non-musttail tail call (existing path). | ||
| struct Big C9(struct Big a); | ||
| struct Big P9(struct Big a) { | ||
| return C9(a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P9( | ||
| // COMMON-NOT: musttail | ||
|
|
||
| // P10: mixed direct + indirect. | ||
| struct Big C10(int x1, struct Big s1, int x2, struct Big s2); | ||
| struct Big P10(int x1, struct Big s1, int x2, struct Big s2) { | ||
| __attribute__((musttail)) return C10(x1, s1, x2, s2); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P10( | ||
| // COMMON-NOT: = alloca {{.*}}struct.Big | ||
| // COMMON: musttail call {{.*}} @C10({{.*}}, i32 {{.*}} %x1, ptr {{[^,]*}} %s1, i32 {{.*}} %x2, ptr {{[^,]*}} %s2) | ||
|
|
||
| // P11: many args, including stack-spilled ones on the target ABIs above. | ||
| struct Big C11(struct Big s1, struct Big s2, struct Big s3, struct Big s4, | ||
| struct Big s5, struct Big s6, struct Big s7, struct Big s8, | ||
| struct Big s9, struct Big s10); | ||
| struct Big P11(struct Big a1, struct Big a2, struct Big a3, struct Big a4, | ||
| struct Big a5, struct Big a6, struct Big a7, struct Big a8, | ||
| struct Big a9, struct Big a10) { | ||
| __attribute__((musttail)) return C11(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P11( | ||
| // COMMON-NOT: = alloca {{.*}}struct.Big | ||
| // COMMON: musttail call {{.*}} @C11( | ||
| // COMMON-SAME: ptr {{[^,]*}} %a1, ptr {{[^,]*}} %a2, ptr {{[^,]*}} %a3, ptr {{[^,]*}} %a4 | ||
| // COMMON-SAME: ptr {{[^,]*}} %a5, ptr {{[^,]*}} %a6, ptr {{[^,]*}} %a7, ptr {{[^,]*}} %a8 | ||
| // COMMON-SAME: ptr {{[^,]*}} %a9, ptr {{[^,]*}} %a10 | ||
|
|
||
| // P12: over-aligned struct. | ||
| struct __attribute__((aligned(32))) AlignedBig { | ||
| unsigned long long a, b, c, d; | ||
| }; | ||
| struct AlignedBig C12(struct AlignedBig a); | ||
| struct AlignedBig P12(struct AlignedBig a) { | ||
| __attribute__((musttail)) return C12(a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P12( | ||
| // COMMON: musttail call {{.*}} @C12({{.*}}, ptr {{[^,]*}} %a) | ||
|
|
||
| // P13: mixed source kinds within Indirect slots. Slot 0's source is a local; | ||
| // slot 1's source is an incoming parameter. Both routes engage in the same | ||
| // call: local-source case (would have dangled under v1's byval-temp path) | ||
| // and forward case must coexist with two-phase ordering. | ||
| struct Big C13(struct Big x, struct Big y); | ||
| struct Big P13(struct Big a, struct Big b) { | ||
| struct Big local = {1, 2, 3, 4}; | ||
| __attribute__((musttail)) return C13(local, a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P13( | ||
| // COMMON-NOT: byval-temp | ||
| // COMMON: %musttail.copy{{[0-9.a-z]*}} = | ||
| // COMMON: musttail call {{.*}} @C13({{.*}}, ptr {{[^,]*}} %a, ptr {{[^,]*}} %b) | ||
|
|
||
| // P17: same arg to three slots (generalization of P7). | ||
| struct Big C17(struct Big x, struct Big y, struct Big z); | ||
| struct Big P17(struct Big a, struct Big b, struct Big c) { | ||
| __attribute__((musttail)) return C17(a, a, a); | ||
| } | ||
| // COMMON-LABEL: define {{.*}} @P17( | ||
| // Both copied slots take their value from %a: %b via the memmove, %c via the | ||
| // captured load. Neither sources from the other copied slot. | ||
| // COMMON: [[SAVED:%musttail.copy[0-9.a-z]*]] = load {{.*}}, ptr %a, | ||
| // COMMON: @llvm.mem{{(cpy|move)}}{{.*}}(ptr {{[^,]*}} %b, ptr {{[^,]*}} %a, | ||
| // COMMON: store {{.*}} [[SAVED]], ptr %c, | ||
| // COMMON: musttail call {{.*}} @C17({{.*}}, ptr {{[^,]*}} %a, ptr {{[^,]*}} %b, ptr {{[^,]*}} %c) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.