/src/llvm-project/clang/lib/CodeGen/Targets/WebAssembly.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- WebAssembly.cpp ----------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "ABIInfoImpl.h" |
10 | | #include "TargetInfo.h" |
11 | | |
12 | | using namespace clang; |
13 | | using namespace clang::CodeGen; |
14 | | |
15 | | //===----------------------------------------------------------------------===// |
16 | | // WebAssembly ABI Implementation |
17 | | // |
18 | | // This is a very simple ABI that relies a lot on DefaultABIInfo. |
19 | | //===----------------------------------------------------------------------===// |
20 | | |
21 | | class WebAssemblyABIInfo final : public ABIInfo { |
22 | | DefaultABIInfo defaultInfo; |
23 | | WebAssemblyABIKind Kind; |
24 | | |
25 | | public: |
26 | | explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT, |
27 | | WebAssemblyABIKind Kind) |
28 | 0 | : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {} |
29 | | |
30 | | private: |
31 | | ABIArgInfo classifyReturnType(QualType RetTy) const; |
32 | | ABIArgInfo classifyArgumentType(QualType Ty) const; |
33 | | |
34 | | // DefaultABIInfo's classifyReturnType and classifyArgumentType are |
35 | | // non-virtual, but computeInfo and EmitVAArg are virtual, so we |
36 | | // overload them. |
37 | 0 | void computeInfo(CGFunctionInfo &FI) const override { |
38 | 0 | if (!getCXXABI().classifyReturnType(FI)) |
39 | 0 | FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); |
40 | 0 | for (auto &Arg : FI.arguments()) |
41 | 0 | Arg.info = classifyArgumentType(Arg.type); |
42 | 0 | } |
43 | | |
44 | | Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
45 | | QualType Ty) const override; |
46 | | }; |
47 | | |
48 | | class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { |
49 | | public: |
50 | | explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, |
51 | | WebAssemblyABIKind K) |
52 | 0 | : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) { |
53 | 0 | SwiftInfo = |
54 | 0 | std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false); |
55 | 0 | } |
56 | | |
57 | | void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, |
58 | 0 | CodeGen::CodeGenModule &CGM) const override { |
59 | 0 | TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); |
60 | 0 | if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { |
61 | 0 | if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) { |
62 | 0 | llvm::Function *Fn = cast<llvm::Function>(GV); |
63 | 0 | llvm::AttrBuilder B(GV->getContext()); |
64 | 0 | B.addAttribute("wasm-import-module", Attr->getImportModule()); |
65 | 0 | Fn->addFnAttrs(B); |
66 | 0 | } |
67 | 0 | if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) { |
68 | 0 | llvm::Function *Fn = cast<llvm::Function>(GV); |
69 | 0 | llvm::AttrBuilder B(GV->getContext()); |
70 | 0 | B.addAttribute("wasm-import-name", Attr->getImportName()); |
71 | 0 | Fn->addFnAttrs(B); |
72 | 0 | } |
73 | 0 | if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { |
74 | 0 | llvm::Function *Fn = cast<llvm::Function>(GV); |
75 | 0 | llvm::AttrBuilder B(GV->getContext()); |
76 | 0 | B.addAttribute("wasm-export-name", Attr->getExportName()); |
77 | 0 | Fn->addFnAttrs(B); |
78 | 0 | } |
79 | 0 | } |
80 | |
|
81 | 0 | if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { |
82 | 0 | llvm::Function *Fn = cast<llvm::Function>(GV); |
83 | 0 | if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype()) |
84 | 0 | Fn->addFnAttr("no-prototype"); |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | /// Return the WebAssembly externref reference type. |
89 | 0 | virtual llvm::Type *getWasmExternrefReferenceType() const override { |
90 | 0 | return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext()); |
91 | 0 | } |
92 | | /// Return the WebAssembly funcref reference type. |
93 | 0 | virtual llvm::Type *getWasmFuncrefReferenceType() const override { |
94 | 0 | return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext()); |
95 | 0 | } |
96 | | }; |
97 | | |
98 | | /// Classify argument of given type \p Ty. |
99 | 0 | ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { |
100 | 0 | Ty = useFirstFieldIfTransparentUnion(Ty); |
101 | |
|
102 | 0 | if (isAggregateTypeForABI(Ty)) { |
103 | | // Records with non-trivial destructors/copy-constructors should not be |
104 | | // passed by value. |
105 | 0 | if (auto RAA = getRecordArgABI(Ty, getCXXABI())) |
106 | 0 | return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); |
107 | | // Ignore empty structs/unions. |
108 | 0 | if (isEmptyRecord(getContext(), Ty, true)) |
109 | 0 | return ABIArgInfo::getIgnore(); |
110 | | // Lower single-element structs to just pass a regular value. TODO: We |
111 | | // could do reasonable-size multiple-element structs too, using getExpand(), |
112 | | // though watch out for things like bitfields. |
113 | 0 | if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) |
114 | 0 | return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); |
115 | | // For the experimental multivalue ABI, fully expand all other aggregates |
116 | 0 | if (Kind == WebAssemblyABIKind::ExperimentalMV) { |
117 | 0 | const RecordType *RT = Ty->getAs<RecordType>(); |
118 | 0 | assert(RT); |
119 | 0 | bool HasBitField = false; |
120 | 0 | for (auto *Field : RT->getDecl()->fields()) { |
121 | 0 | if (Field->isBitField()) { |
122 | 0 | HasBitField = true; |
123 | 0 | break; |
124 | 0 | } |
125 | 0 | } |
126 | 0 | if (!HasBitField) |
127 | 0 | return ABIArgInfo::getExpand(); |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | | // Otherwise just do the default thing. |
132 | 0 | return defaultInfo.classifyArgumentType(Ty); |
133 | 0 | } |
134 | | |
135 | 0 | ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { |
136 | 0 | if (isAggregateTypeForABI(RetTy)) { |
137 | | // Records with non-trivial destructors/copy-constructors should not be |
138 | | // returned by value. |
139 | 0 | if (!getRecordArgABI(RetTy, getCXXABI())) { |
140 | | // Ignore empty structs/unions. |
141 | 0 | if (isEmptyRecord(getContext(), RetTy, true)) |
142 | 0 | return ABIArgInfo::getIgnore(); |
143 | | // Lower single-element structs to just return a regular value. TODO: We |
144 | | // could do reasonable-size multiple-element structs too, using |
145 | | // ABIArgInfo::getDirect(). |
146 | 0 | if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) |
147 | 0 | return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); |
148 | | // For the experimental multivalue ABI, return all other aggregates |
149 | 0 | if (Kind == WebAssemblyABIKind::ExperimentalMV) |
150 | 0 | return ABIArgInfo::getDirect(); |
151 | 0 | } |
152 | 0 | } |
153 | | |
154 | | // Otherwise just do the default thing. |
155 | 0 | return defaultInfo.classifyReturnType(RetTy); |
156 | 0 | } |
157 | | |
158 | | Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
159 | 0 | QualType Ty) const { |
160 | 0 | bool IsIndirect = isAggregateTypeForABI(Ty) && |
161 | 0 | !isEmptyRecord(getContext(), Ty, true) && |
162 | 0 | !isSingleElementStruct(Ty, getContext()); |
163 | 0 | return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, |
164 | 0 | getContext().getTypeInfoInChars(Ty), |
165 | 0 | CharUnits::fromQuantity(4), |
166 | 0 | /*AllowHigherAlign=*/true); |
167 | 0 | } |
168 | | |
169 | | std::unique_ptr<TargetCodeGenInfo> |
170 | | CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, |
171 | 0 | WebAssemblyABIKind K) { |
172 | 0 | return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K); |
173 | 0 | } |