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(FI.getReturnType());
40     for (auto &Arg : FI.arguments())
41       Arg.info = classifyArgumentType(Arg.type);
42   }
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       : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
53     SwiftInfo =
54         std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
55   }
56 
57   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.
89   virtual llvm::Type *getWasmExternrefReferenceType() const override {
90     return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
91   }
92   /// Return the WebAssembly funcref reference type.
93   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.
99 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 
135 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 
158 Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
159                                       QualType Ty) 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);
167 }
168 
169 std::unique_ptr<TargetCodeGenInfo>
170 CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
171                                             WebAssemblyABIKind K) {
172   return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
173 }
174