xref: /llvm-project/clang/lib/CodeGen/Targets/WebAssembly.cpp (revision 6d973b4548e281d0b8e75e85833804bb45b6a0e8)
1992cb984SSergei Barannikov //===- WebAssembly.cpp ----------------------------------------------------===//
2992cb984SSergei Barannikov //
3992cb984SSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4992cb984SSergei Barannikov // See https://llvm.org/LICENSE.txt for license information.
5992cb984SSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6992cb984SSergei Barannikov //
7992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
8992cb984SSergei Barannikov 
9992cb984SSergei Barannikov #include "ABIInfoImpl.h"
10992cb984SSergei Barannikov #include "TargetInfo.h"
11992cb984SSergei Barannikov 
12992cb984SSergei Barannikov using namespace clang;
13992cb984SSergei Barannikov using namespace clang::CodeGen;
14992cb984SSergei Barannikov 
15992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
16992cb984SSergei Barannikov // WebAssembly ABI Implementation
17992cb984SSergei Barannikov //
18992cb984SSergei Barannikov // This is a very simple ABI that relies a lot on DefaultABIInfo.
19992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
20992cb984SSergei Barannikov 
21992cb984SSergei Barannikov class WebAssemblyABIInfo final : public ABIInfo {
22992cb984SSergei Barannikov   DefaultABIInfo defaultInfo;
23992cb984SSergei Barannikov   WebAssemblyABIKind Kind;
24992cb984SSergei Barannikov 
25992cb984SSergei Barannikov public:
WebAssemblyABIInfo(CodeGen::CodeGenTypes & CGT,WebAssemblyABIKind Kind)26992cb984SSergei Barannikov   explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT,
27992cb984SSergei Barannikov                               WebAssemblyABIKind Kind)
28992cb984SSergei Barannikov       : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}
29992cb984SSergei Barannikov 
30992cb984SSergei Barannikov private:
31992cb984SSergei Barannikov   ABIArgInfo classifyReturnType(QualType RetTy) const;
32992cb984SSergei Barannikov   ABIArgInfo classifyArgumentType(QualType Ty) const;
33992cb984SSergei Barannikov 
34992cb984SSergei Barannikov   // DefaultABIInfo's classifyReturnType and classifyArgumentType are
35992cb984SSergei Barannikov   // non-virtual, but computeInfo and EmitVAArg are virtual, so we
36992cb984SSergei Barannikov   // overload them.
computeInfo(CGFunctionInfo & FI) const37992cb984SSergei Barannikov   void computeInfo(CGFunctionInfo &FI) const override {
38992cb984SSergei Barannikov     if (!getCXXABI().classifyReturnType(FI))
39992cb984SSergei Barannikov       FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
40992cb984SSergei Barannikov     for (auto &Arg : FI.arguments())
41992cb984SSergei Barannikov       Arg.info = classifyArgumentType(Arg.type);
42992cb984SSergei Barannikov   }
43992cb984SSergei Barannikov 
44*6d973b45SMariya Podchishchaeva   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
45*6d973b45SMariya Podchishchaeva                    AggValueSlot Slot) const override;
46992cb984SSergei Barannikov };
47992cb984SSergei Barannikov 
48992cb984SSergei Barannikov class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
49992cb984SSergei Barannikov public:
WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,WebAssemblyABIKind K)50992cb984SSergei Barannikov   explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
51992cb984SSergei Barannikov                                         WebAssemblyABIKind K)
52992cb984SSergei Barannikov       : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
53992cb984SSergei Barannikov     SwiftInfo =
54992cb984SSergei Barannikov         std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
55992cb984SSergei Barannikov   }
56992cb984SSergei Barannikov 
setTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const57992cb984SSergei Barannikov   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
58992cb984SSergei Barannikov                            CodeGen::CodeGenModule &CGM) const override {
59992cb984SSergei Barannikov     TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
60992cb984SSergei Barannikov     if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
61992cb984SSergei Barannikov       if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
62992cb984SSergei Barannikov         llvm::Function *Fn = cast<llvm::Function>(GV);
63992cb984SSergei Barannikov         llvm::AttrBuilder B(GV->getContext());
64992cb984SSergei Barannikov         B.addAttribute("wasm-import-module", Attr->getImportModule());
65992cb984SSergei Barannikov         Fn->addFnAttrs(B);
66992cb984SSergei Barannikov       }
67992cb984SSergei Barannikov       if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
68992cb984SSergei Barannikov         llvm::Function *Fn = cast<llvm::Function>(GV);
69992cb984SSergei Barannikov         llvm::AttrBuilder B(GV->getContext());
70992cb984SSergei Barannikov         B.addAttribute("wasm-import-name", Attr->getImportName());
71992cb984SSergei Barannikov         Fn->addFnAttrs(B);
72992cb984SSergei Barannikov       }
73992cb984SSergei Barannikov       if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
74992cb984SSergei Barannikov         llvm::Function *Fn = cast<llvm::Function>(GV);
75992cb984SSergei Barannikov         llvm::AttrBuilder B(GV->getContext());
76992cb984SSergei Barannikov         B.addAttribute("wasm-export-name", Attr->getExportName());
77992cb984SSergei Barannikov         Fn->addFnAttrs(B);
78992cb984SSergei Barannikov       }
79992cb984SSergei Barannikov     }
80992cb984SSergei Barannikov 
81992cb984SSergei Barannikov     if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
82992cb984SSergei Barannikov       llvm::Function *Fn = cast<llvm::Function>(GV);
83992cb984SSergei Barannikov       if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
84992cb984SSergei Barannikov         Fn->addFnAttr("no-prototype");
85992cb984SSergei Barannikov     }
86992cb984SSergei Barannikov   }
87992cb984SSergei Barannikov 
88992cb984SSergei Barannikov   /// Return the WebAssembly externref reference type.
getWasmExternrefReferenceType() const89992cb984SSergei Barannikov   virtual llvm::Type *getWasmExternrefReferenceType() const override {
90992cb984SSergei Barannikov     return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
91992cb984SSergei Barannikov   }
92992cb984SSergei Barannikov   /// Return the WebAssembly funcref reference type.
getWasmFuncrefReferenceType() const93992cb984SSergei Barannikov   virtual llvm::Type *getWasmFuncrefReferenceType() const override {
94992cb984SSergei Barannikov     return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
95992cb984SSergei Barannikov   }
96992cb984SSergei Barannikov };
97992cb984SSergei Barannikov 
98992cb984SSergei Barannikov /// Classify argument of given type \p Ty.
classifyArgumentType(QualType Ty) const99992cb984SSergei Barannikov ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
100992cb984SSergei Barannikov   Ty = useFirstFieldIfTransparentUnion(Ty);
101992cb984SSergei Barannikov 
102992cb984SSergei Barannikov   if (isAggregateTypeForABI(Ty)) {
103992cb984SSergei Barannikov     // Records with non-trivial destructors/copy-constructors should not be
104992cb984SSergei Barannikov     // passed by value.
105992cb984SSergei Barannikov     if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
106992cb984SSergei Barannikov       return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
107992cb984SSergei Barannikov     // Ignore empty structs/unions.
108992cb984SSergei Barannikov     if (isEmptyRecord(getContext(), Ty, true))
109992cb984SSergei Barannikov       return ABIArgInfo::getIgnore();
110992cb984SSergei Barannikov     // Lower single-element structs to just pass a regular value. TODO: We
111992cb984SSergei Barannikov     // could do reasonable-size multiple-element structs too, using getExpand(),
112992cb984SSergei Barannikov     // though watch out for things like bitfields.
113992cb984SSergei Barannikov     if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
114992cb984SSergei Barannikov       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
115992cb984SSergei Barannikov     // For the experimental multivalue ABI, fully expand all other aggregates
116992cb984SSergei Barannikov     if (Kind == WebAssemblyABIKind::ExperimentalMV) {
117992cb984SSergei Barannikov       const RecordType *RT = Ty->getAs<RecordType>();
118992cb984SSergei Barannikov       assert(RT);
119992cb984SSergei Barannikov       bool HasBitField = false;
120992cb984SSergei Barannikov       for (auto *Field : RT->getDecl()->fields()) {
121992cb984SSergei Barannikov         if (Field->isBitField()) {
122992cb984SSergei Barannikov           HasBitField = true;
123992cb984SSergei Barannikov           break;
124992cb984SSergei Barannikov         }
125992cb984SSergei Barannikov       }
126992cb984SSergei Barannikov       if (!HasBitField)
127992cb984SSergei Barannikov         return ABIArgInfo::getExpand();
128992cb984SSergei Barannikov     }
129992cb984SSergei Barannikov   }
130992cb984SSergei Barannikov 
131992cb984SSergei Barannikov   // Otherwise just do the default thing.
132992cb984SSergei Barannikov   return defaultInfo.classifyArgumentType(Ty);
133992cb984SSergei Barannikov }
134992cb984SSergei Barannikov 
classifyReturnType(QualType RetTy) const135992cb984SSergei Barannikov ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
136992cb984SSergei Barannikov   if (isAggregateTypeForABI(RetTy)) {
137992cb984SSergei Barannikov     // Records with non-trivial destructors/copy-constructors should not be
138992cb984SSergei Barannikov     // returned by value.
139992cb984SSergei Barannikov     if (!getRecordArgABI(RetTy, getCXXABI())) {
140992cb984SSergei Barannikov       // Ignore empty structs/unions.
141992cb984SSergei Barannikov       if (isEmptyRecord(getContext(), RetTy, true))
142992cb984SSergei Barannikov         return ABIArgInfo::getIgnore();
143992cb984SSergei Barannikov       // Lower single-element structs to just return a regular value. TODO: We
144992cb984SSergei Barannikov       // could do reasonable-size multiple-element structs too, using
145992cb984SSergei Barannikov       // ABIArgInfo::getDirect().
146992cb984SSergei Barannikov       if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
147992cb984SSergei Barannikov         return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
148992cb984SSergei Barannikov       // For the experimental multivalue ABI, return all other aggregates
149992cb984SSergei Barannikov       if (Kind == WebAssemblyABIKind::ExperimentalMV)
150992cb984SSergei Barannikov         return ABIArgInfo::getDirect();
151992cb984SSergei Barannikov     }
152992cb984SSergei Barannikov   }
153992cb984SSergei Barannikov 
154992cb984SSergei Barannikov   // Otherwise just do the default thing.
155992cb984SSergei Barannikov   return defaultInfo.classifyReturnType(RetTy);
156992cb984SSergei Barannikov }
157992cb984SSergei Barannikov 
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const158*6d973b45SMariya Podchishchaeva RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
159*6d973b45SMariya Podchishchaeva                                      QualType Ty, AggValueSlot Slot) const {
160992cb984SSergei Barannikov   bool IsIndirect = isAggregateTypeForABI(Ty) &&
161992cb984SSergei Barannikov                     !isEmptyRecord(getContext(), Ty, true) &&
162992cb984SSergei Barannikov                     !isSingleElementStruct(Ty, getContext());
163992cb984SSergei Barannikov   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
164992cb984SSergei Barannikov                           getContext().getTypeInfoInChars(Ty),
165992cb984SSergei Barannikov                           CharUnits::fromQuantity(4),
166*6d973b45SMariya Podchishchaeva                           /*AllowHigherAlign=*/true, Slot);
167992cb984SSergei Barannikov }
168992cb984SSergei Barannikov 
169992cb984SSergei Barannikov std::unique_ptr<TargetCodeGenInfo>
createWebAssemblyTargetCodeGenInfo(CodeGenModule & CGM,WebAssemblyABIKind K)170992cb984SSergei Barannikov CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
171992cb984SSergei Barannikov                                             WebAssemblyABIKind K) {
172992cb984SSergei Barannikov   return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
173992cb984SSergei Barannikov }
174