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 | : 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 | void computeInfo(CGFunctionInfo &FI) const override { |
38 | if (!getCXXABI().classifyReturnType(FI)) |
39 | FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType()); |
40 | for (auto &Arg : FI.arguments()) |
41 | Arg.info = classifyArgumentType(Ty: Arg.type); |
42 | } |
43 | |
44 | RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, |
45 | AggValueSlot Slot) const override; |
46 | }; |
47 | |
48 | class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { |
49 | public: |
50 | explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, |
51 | WebAssemblyABIKind K) |
52 | : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(args&: CGT, args&: K)) { |
53 | SwiftInfo = |
54 | std::make_unique<SwiftABIInfo>(args&: CGT, /*SwiftErrorInRegister=*/args: false); |
55 | } |
56 | |
57 | void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, |
58 | CodeGen::CodeGenModule &CGM) const override { |
59 | TargetCodeGenInfo::setTargetAttributes(D, GV, M&: CGM); |
60 | if (const auto *FD = dyn_cast_or_null<FunctionDecl>(Val: D)) { |
61 | if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) { |
62 | llvm::Function *Fn = cast<llvm::Function>(Val: GV); |
63 | llvm::AttrBuilder B(GV->getContext()); |
64 | B.addAttribute(A: "wasm-import-module" , V: Attr->getImportModule()); |
65 | Fn->addFnAttrs(Attrs: B); |
66 | } |
67 | if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) { |
68 | llvm::Function *Fn = cast<llvm::Function>(Val: GV); |
69 | llvm::AttrBuilder B(GV->getContext()); |
70 | B.addAttribute(A: "wasm-import-name" , V: Attr->getImportName()); |
71 | Fn->addFnAttrs(Attrs: B); |
72 | } |
73 | if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { |
74 | llvm::Function *Fn = cast<llvm::Function>(Val: GV); |
75 | llvm::AttrBuilder B(GV->getContext()); |
76 | B.addAttribute(A: "wasm-export-name" , V: Attr->getExportName()); |
77 | Fn->addFnAttrs(Attrs: B); |
78 | } |
79 | } |
80 | |
81 | if (auto *FD = dyn_cast_or_null<FunctionDecl>(Val: D)) { |
82 | llvm::Function *Fn = cast<llvm::Function>(Val: GV); |
83 | if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype()) |
84 | Fn->addFnAttr(Kind: "no-prototype" ); |
85 | } |
86 | } |
87 | |
88 | /// Return the WebAssembly externref reference type. |
89 | virtual llvm::Type *getWasmExternrefReferenceType() const override { |
90 | return llvm::Type::getWasm_ExternrefTy(C&: getABIInfo().getVMContext()); |
91 | } |
92 | /// Return the WebAssembly funcref reference type. |
93 | virtual llvm::Type *getWasmFuncrefReferenceType() const override { |
94 | return llvm::Type::getWasm_FuncrefTy(C&: getABIInfo().getVMContext()); |
95 | } |
96 | }; |
97 | |
98 | /// Classify argument of given type \p Ty. |
99 | ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { |
100 | Ty = useFirstFieldIfTransparentUnion(Ty); |
101 | |
102 | if (isAggregateTypeForABI(T: Ty)) { |
103 | // Records with non-trivial destructors/copy-constructors should not be |
104 | // passed by value. |
105 | if (auto RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI())) |
106 | return getNaturalAlignIndirect(Ty, ByVal: RAA == CGCXXABI::RAA_DirectInMemory); |
107 | // Ignore empty structs/unions. |
108 | if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true)) |
109 | 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 | if (const Type *SeltTy = isSingleElementStruct(T: Ty, Context&: getContext())) |
114 | return ABIArgInfo::getDirect(T: CGT.ConvertType(T: QualType(SeltTy, 0))); |
115 | // For the experimental multivalue ABI, fully expand all other aggregates |
116 | if (Kind == WebAssemblyABIKind::ExperimentalMV) { |
117 | const RecordType *RT = Ty->getAs<RecordType>(); |
118 | assert(RT); |
119 | bool HasBitField = false; |
120 | for (auto *Field : RT->getDecl()->fields()) { |
121 | if (Field->isBitField()) { |
122 | HasBitField = true; |
123 | break; |
124 | } |
125 | } |
126 | if (!HasBitField) |
127 | return ABIArgInfo::getExpand(); |
128 | } |
129 | } |
130 | |
131 | // Otherwise just do the default thing. |
132 | return defaultInfo.classifyArgumentType(RetTy: Ty); |
133 | } |
134 | |
135 | ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { |
136 | if (isAggregateTypeForABI(T: RetTy)) { |
137 | // Records with non-trivial destructors/copy-constructors should not be |
138 | // returned by value. |
139 | if (!getRecordArgABI(T: RetTy, CXXABI&: getCXXABI())) { |
140 | // Ignore empty structs/unions. |
141 | if (isEmptyRecord(Context&: getContext(), T: RetTy, AllowArrays: true)) |
142 | 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 | if (const Type *SeltTy = isSingleElementStruct(T: RetTy, Context&: getContext())) |
147 | return ABIArgInfo::getDirect(T: CGT.ConvertType(T: QualType(SeltTy, 0))); |
148 | // For the experimental multivalue ABI, return all other aggregates |
149 | if (Kind == WebAssemblyABIKind::ExperimentalMV) |
150 | return ABIArgInfo::getDirect(); |
151 | } |
152 | } |
153 | |
154 | // Otherwise just do the default thing. |
155 | return defaultInfo.classifyReturnType(RetTy); |
156 | } |
157 | |
158 | RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
159 | QualType Ty, AggValueSlot Slot) const { |
160 | bool IsIndirect = isAggregateTypeForABI(T: Ty) && |
161 | !isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true) && |
162 | !isSingleElementStruct(T: Ty, Context&: getContext()); |
163 | return emitVoidPtrVAArg(CGF, VAListAddr, ValueTy: Ty, IsIndirect, |
164 | ValueInfo: getContext().getTypeInfoInChars(T: Ty), |
165 | SlotSizeAndAlign: CharUnits::fromQuantity(Quantity: 4), |
166 | /*AllowHigherAlign=*/true, Slot); |
167 | } |
168 | |
169 | std::unique_ptr<TargetCodeGenInfo> |
170 | CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, |
171 | WebAssemblyABIKind K) { |
172 | return std::make_unique<WebAssemblyTargetCodeGenInfo>(args&: CGM.getTypes(), args&: K); |
173 | } |
174 | |