Skip to content

Commit 3621fbe

Browse files
[clang][WebAssembly] Return aggregate values indirectly in swiftcc
The Swift calling convention on Wasm has historically returned aggregate values directly at the LLVM IR level due to the use of the generic `SwiftABIInfo` implementation. The direct return at LLVM IR level will cause unnecessary stack allocation and memory copies for each aggregate return value.
1 parent d8e7cc7 commit 3621fbe

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

clang/lib/CodeGen/Targets/WebAssembly.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,33 @@ class WebAssemblyABIInfo final : public ABIInfo {
4545
AggValueSlot Slot) const override;
4646
};
4747

48+
class WebAssemblySwiftABIInfo final : public SwiftABIInfo {
49+
WebAssemblyABIKind K;
50+
public:
51+
explicit WebAssemblySwiftABIInfo(CodeGen::CodeGenTypes &CGT, WebAssemblyABIKind K)
52+
: SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/false), K(K) {}
53+
54+
bool shouldPassIndirectly(ArrayRef<llvm::Type *> ComponentTys, bool AsReturnValue) const override {
55+
if (AsReturnValue) {
56+
if (K == WebAssemblyABIKind::ExperimentalMV) {
57+
// If the MV ABI is enabled, return all values directly.
58+
return false;
59+
}
60+
// Otherwise, check if the value occupies more than 1 scalar slot.
61+
return SwiftABIInfo::occupiesMoreThan(ComponentTys, /*total=*/1);
62+
}
63+
// For arguments, just follow the default implementation.
64+
return SwiftABIInfo::shouldPassIndirectly(ComponentTys, AsReturnValue);
65+
}
66+
};
67+
4868
class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
4969
public:
5070
explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
5171
WebAssemblyABIKind K)
5272
: TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
5373
SwiftInfo =
54-
std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
74+
std::make_unique<WebAssemblySwiftABIInfo>(CGT, K);
5575
}
5676

5777
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -emit-llvm -o - | FileCheck %s
2+
3+
typedef struct {
4+
int aa;
5+
int bb;
6+
} s1;
7+
8+
// Multiple-element structs should be returned through sret.
9+
// CHECK: define swiftcc void @return_s1(ptr dead_on_unwind noalias writable sret(%struct.s1) align 4 %agg.result)
10+
__attribute__((swiftcall))
11+
s1 return_s1(void) {
12+
s1 foo;
13+
return foo;
14+
}
15+
16+
typedef struct {
17+
int cc;
18+
} s2;
19+
20+
// Single-element structs should be returned directly.
21+
// CHECK: define swiftcc i32 @return_s2()
22+
__attribute__((swiftcall))
23+
s2 return_s2(void) {
24+
s2 foo;
25+
return foo;
26+
}
27+
28+
typedef struct {
29+
char c1[4];
30+
} s3;
31+
32+
// CHECK: define swiftcc i32 @return_s3()
33+
__attribute__((swiftcall))
34+
s3 return_s3(void) {
35+
s3 foo;
36+
return foo;
37+
}
38+
39+
typedef struct {
40+
int bf1 : 4;
41+
int bf2 : 3;
42+
int bf3 : 8;
43+
} s4;
44+
45+
// CHECK: define swiftcc i16 @return_s4()
46+
__attribute__((swiftcall))
47+
s4 return_s4(void) {
48+
s4 foo;
49+
return foo;
50+
}

0 commit comments

Comments
 (0)