Skip to content

Commit 4b0d43a

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 4b0d43a

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

clang/lib/CodeGen/Targets/WebAssembly.cpp

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

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

5779
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)