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:
WebAssemblyABIInfo(CodeGen::CodeGenTypes & CGT,WebAssemblyABIKind Kind)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.
computeInfo(CGFunctionInfo & FI) const37 void computeInfo(CGFunctionInfo &FI) const override {
38 if (!getCXXABI().classifyReturnType(FI))
39 FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
40 for (auto &Arg : FI.arguments())
41 Arg.info = classifyArgumentType(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:
WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,WebAssemblyABIKind K)50 explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
51 WebAssemblyABIKind K)
52 : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
53 SwiftInfo =
54 std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
55 }
56
setTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const57 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
58 CodeGen::CodeGenModule &CGM) const override {
59 TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
60 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
61 if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
62 llvm::Function *Fn = cast<llvm::Function>(GV);
63 llvm::AttrBuilder B(GV->getContext());
64 B.addAttribute("wasm-import-module", Attr->getImportModule());
65 Fn->addFnAttrs(B);
66 }
67 if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
68 llvm::Function *Fn = cast<llvm::Function>(GV);
69 llvm::AttrBuilder B(GV->getContext());
70 B.addAttribute("wasm-import-name", Attr->getImportName());
71 Fn->addFnAttrs(B);
72 }
73 if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
74 llvm::Function *Fn = cast<llvm::Function>(GV);
75 llvm::AttrBuilder B(GV->getContext());
76 B.addAttribute("wasm-export-name", Attr->getExportName());
77 Fn->addFnAttrs(B);
78 }
79 }
80
81 if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
82 llvm::Function *Fn = cast<llvm::Function>(GV);
83 if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
84 Fn->addFnAttr("no-prototype");
85 }
86 }
87
88 /// Return the WebAssembly externref reference type.
getWasmExternrefReferenceType() const89 virtual llvm::Type *getWasmExternrefReferenceType() const override {
90 return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
91 }
92 /// Return the WebAssembly funcref reference type.
getWasmFuncrefReferenceType() const93 virtual llvm::Type *getWasmFuncrefReferenceType() const override {
94 return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
95 }
96 };
97
98 /// Classify argument of given type \p Ty.
classifyArgumentType(QualType Ty) const99 ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
100 Ty = useFirstFieldIfTransparentUnion(Ty);
101
102 if (isAggregateTypeForABI(Ty)) {
103 // Records with non-trivial destructors/copy-constructors should not be
104 // passed by value.
105 if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
106 return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
107 // Ignore empty structs/unions.
108 if (isEmptyRecord(getContext(), Ty, 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(Ty, getContext()))
114 return ABIArgInfo::getDirect(CGT.ConvertType(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(Ty);
133 }
134
classifyReturnType(QualType RetTy) const135 ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
136 if (isAggregateTypeForABI(RetTy)) {
137 // Records with non-trivial destructors/copy-constructors should not be
138 // returned by value.
139 if (!getRecordArgABI(RetTy, getCXXABI())) {
140 // Ignore empty structs/unions.
141 if (isEmptyRecord(getContext(), RetTy, 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(RetTy, getContext()))
147 return ABIArgInfo::getDirect(CGT.ConvertType(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
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const158 RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
159 QualType Ty, AggValueSlot Slot) const {
160 bool IsIndirect = isAggregateTypeForABI(Ty) &&
161 !isEmptyRecord(getContext(), Ty, true) &&
162 !isSingleElementStruct(Ty, getContext());
163 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
164 getContext().getTypeInfoInChars(Ty),
165 CharUnits::fromQuantity(4),
166 /*AllowHigherAlign=*/true, Slot);
167 }
168
169 std::unique_ptr<TargetCodeGenInfo>
createWebAssemblyTargetCodeGenInfo(CodeGenModule & CGM,WebAssemblyABIKind K)170 CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
171 WebAssemblyABIKind K) {
172 return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
173 }
174