clang 24.0.0git
WebAssembly.cpp
Go to the documentation of this file.
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"
12
13using namespace clang;
14using namespace clang::CodeGen;
15
16//===----------------------------------------------------------------------===//
17// WebAssembly ABI Implementation
18//
19// This is a very simple ABI that relies a lot on DefaultABIInfo.
20//===----------------------------------------------------------------------===//
21
22class WebAssemblyABIInfo final : public ABIInfo {
23 DefaultABIInfo defaultInfo;
25
26public:
29 : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}
30
31private:
33 ABIArgInfo classifyArgumentType(QualType Ty) const;
34
35 // DefaultABIInfo's classifyReturnType and classifyArgumentType are
36 // non-virtual, but computeInfo and EmitVAArg are virtual, so we
37 // overload them.
38 void computeInfo(CGFunctionInfo &FI) const override {
41 for (auto &Arg : FI.arguments())
42 Arg.info = classifyArgumentType(Arg.type);
43 }
44
45 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
46 AggValueSlot Slot) const override;
47};
48
50public:
53 : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
54 SwiftInfo =
55 std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
56 }
57
58 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
59 CodeGen::CodeGenModule &CGM) const override {
61 if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
63 const auto *ModuleAttr = VD->getAttr<WebAssemblyImportModuleAttr>();
64 const auto *NameAttr = VD->getAttr<WebAssemblyImportNameAttr>();
65 if (ModuleAttr || NameAttr) {
66 if (VD->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) {
67 bool IsExplicit = (ModuleAttr && !ModuleAttr->isInherited()) ||
68 (NameAttr && !NameAttr->isInherited());
69 if (IsExplicit) {
70 auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation()
71 : NameAttr->getLocation();
72 CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
73 << "import attribute cannot be applied to a definition";
74 }
75 return;
76 }
77 if (Global->getAddressSpace() == 0) {
78 auto AttrLoc =
79 ModuleAttr ? ModuleAttr->getLocation() : NameAttr->getLocation();
80 CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
81 << "import attribute cannot be applied to a non-wasm-variable "
82 "global";
83 return;
84 }
85 if (ModuleAttr)
86 Global->addAttribute("wasm-import-module",
87 ModuleAttr->getImportModule());
88 if (NameAttr)
89 Global->addAttribute("wasm-import-name", NameAttr->getImportName());
90 }
91 if (const auto *Attr = VD->getAttr<WebAssemblyExportNameAttr>()) {
92 Global->addAttribute("wasm-export-name", Attr->getExportName());
93 }
94 } else if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
95 auto *Fn = cast<llvm::Function>(GV);
96 const auto *ModuleAttr = FD->getAttr<WebAssemblyImportModuleAttr>();
97 const auto *NameAttr = FD->getAttr<WebAssemblyImportNameAttr>();
98 if (ModuleAttr || NameAttr) {
99 if (FD->isThisDeclarationADefinition()) {
100 bool IsExplicit = (ModuleAttr && !ModuleAttr->isInherited()) ||
101 (NameAttr && !NameAttr->isInherited());
102 if (IsExplicit) {
103 auto AttrLoc = ModuleAttr ? ModuleAttr->getLocation()
104 : NameAttr->getLocation();
105 CGM.getDiags().Report(AttrLoc, diag::err_fe_backend_unsupported)
106 << "import attribute cannot be applied to a definition";
107 auto *NonConstFD = const_cast<FunctionDecl *>(FD);
108 NonConstFD->dropAttr<WebAssemblyImportModuleAttr>();
109 NonConstFD->dropAttr<WebAssemblyImportNameAttr>();
110 }
111 return;
112 }
113 if (ModuleAttr)
114 Fn->addFnAttr("wasm-import-module", ModuleAttr->getImportModule());
115 if (NameAttr)
116 Fn->addFnAttr("wasm-import-name", NameAttr->getImportName());
117 }
118 if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
119 Fn->addFnAttr("wasm-export-name", Attr->getExportName());
120 }
121
122 if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
123 Fn->addFnAttr("no-prototype");
124 }
125 }
126
127 /// Return the WebAssembly externref reference type.
128 virtual llvm::Type *getWasmExternrefReferenceType() const override {
129 return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
130 }
131 /// Return the WebAssembly funcref reference type.
132 virtual llvm::Type *getWasmFuncrefReferenceType() const override {
133 return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
134 }
135};
136
137/// Classify argument of given type \p Ty.
138ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
140
141 if (isAggregateTypeForABI(Ty)) {
142 // Records with non-trivial destructors/copy-constructors should not be
143 // passed by value.
144 if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
145 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
147 // Ignore empty structs/unions.
148 if (isEmptyRecord(getContext(), Ty, true))
149 return ABIArgInfo::getIgnore();
150 // Lower single-element structs to just pass a regular value. TODO: We
151 // could do reasonable-size multiple-element structs too, using getExpand(),
152 // though watch out for things like bitfields.
153 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
154 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
155 // For the experimental multivalue ABI, fully expand all other aggregates
156 if (Kind == WebAssemblyABIKind::ExperimentalMV) {
157 if (Ty->getAs<ComplexType>())
158 return ABIArgInfo::getDirect();
159 const auto *RD = Ty->getAsRecordDecl();
160 if (RD) {
161 bool HasBitField = false;
162 for (auto *Field : RD->fields()) {
163 if (Field->isBitField()) {
164 HasBitField = true;
165 break;
166 }
167 }
168 if (!HasBitField)
169 return ABIArgInfo::getExpand();
170 }
171 }
172 }
173
174 // Otherwise just do the default thing.
175 return defaultInfo.classifyArgumentType(Ty);
176}
177
178ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
179 if (isAggregateTypeForABI(RetTy)) {
180 // Records with non-trivial destructors/copy-constructors should not be
181 // returned by value.
182 if (!getRecordArgABI(RetTy, getCXXABI())) {
183 // Ignore empty structs/unions.
184 if (isEmptyRecord(getContext(), RetTy, true))
185 return ABIArgInfo::getIgnore();
186 // Lower single-element structs to just return a regular value. TODO: We
187 // could do reasonable-size multiple-element structs too, using
188 // ABIArgInfo::getDirect().
189 if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
190 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
191 // For the experimental multivalue ABI, return all other aggregates
192 if (Kind == WebAssemblyABIKind::ExperimentalMV)
193 return ABIArgInfo::getDirect();
194 }
195 }
196
197 // Otherwise just do the default thing.
198 return defaultInfo.classifyReturnType(RetTy);
199}
200
201RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
202 QualType Ty, AggValueSlot Slot) const {
203 bool IsIndirect = isAggregateTypeForABI(Ty) &&
204 !isEmptyRecord(getContext(), Ty, true) &&
206 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
207 getContext().getTypeInfoInChars(Ty),
209 /*AllowHigherAlign=*/true, Slot);
210}
211
212std::unique_ptr<TargetCodeGenInfo>
215 return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
216}
WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT, WebAssemblyABIKind Kind)
virtual llvm::Type * getWasmFuncrefReferenceType() const override
Return the WebAssembly funcref reference type.
virtual llvm::Type * getWasmExternrefReferenceType() const override
Return the WebAssembly externref reference type.
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override
setTargetAttributes - Provides a convenient hook to handle extra target-specific attributes for the g...
WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, WebAssemblyABIKind K)
Attr - This represents one attribute.
Definition Attr.h:46
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
ABIArgInfo - Helper class to encapsulate information about how a specific C type should be passed to ...
static ABIArgInfo getIgnore()
static ABIArgInfo getExpand()
static ABIArgInfo getDirect(llvm::Type *T=nullptr, unsigned Offset=0, llvm::Type *Padding=nullptr, bool CanBeFlattened=true, unsigned Align=0)
const llvm::DataLayout & getDataLayout() const
Definition ABIInfo.cpp:26
CodeGen::ABIArgInfo getNaturalAlignIndirect(QualType Ty, unsigned AddrSpace, bool ByVal=true, bool Realign=false, llvm::Type *Padding=nullptr) const
A convenience method to return an indirect ABIArgInfo with an expected alignment equal to the ABI ali...
Definition ABIInfo.cpp:178
ABIInfo(CodeGen::CodeGenTypes &cgt)
Definition ABIInfo.h:55
CodeGen::CodeGenTypes & CGT
Definition ABIInfo.h:51
CodeGen::CGCXXABI & getCXXABI() const
Definition ABIInfo.cpp:18
ASTContext & getContext() const
Definition ABIInfo.cpp:20
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
An aggregate value slot.
Definition CGValue.h:551
@ RAA_DirectInMemory
Pass it on the stack using its defined layout.
Definition CGCXXABI.h:158
CGFunctionInfo - Class to encapsulate the information about a function definition.
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
This class organizes the cross-function state that is used while generating LLVM code.
DiagnosticsEngine & getDiags() const
This class organizes the cross-module state that is used while lowering AST types to LLVM types.
DefaultABIInfo - The default implementation for ABI specific details.
Definition ABIInfoImpl.h:21
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Definition CGValue.h:42
std::unique_ptr< SwiftABIInfo > SwiftInfo
Definition TargetInfo.h:87
virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const
setTargetAttributes - Provides a convenient hook to handle extra target-specific attributes for the g...
Definition TargetInfo.h:113
TargetCodeGenInfo(std::unique_ptr< ABIInfo > Info)
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
void dropAttr()
Definition DeclBase.h:564
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Represents a function declaration or definition.
Definition Decl.h:2059
A (possibly-)qualified type.
Definition TypeBase.h:938
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9254
@ DeclarationOnly
This declaration is only a declaration.
Definition Decl.h:1319
CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI)
bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info)
std::unique_ptr< TargetCodeGenInfo > createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, WebAssemblyABIKind K)
RValue emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign, bool AllowHigherAlign, AggValueSlot Slot, bool ForceRightAdjust=false)
Emit va_arg for a platform using the common void* representation, where arguments are simply emitted ...
bool isAggregateTypeForABI(QualType T)
const Type * isSingleElementStruct(QualType T, ASTContext &Context)
isSingleElementStruct - Determine if a structure is a "singleelement struct", i.e.
QualType useFirstFieldIfTransparentUnion(QualType Ty)
Pass transparent unions as if they were the type of the first element.
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr=false)
isEmptyRecord - Return true iff a structure contains only empty fields.
Top level wrappers for InstallAPI frontend operations.
@ Type
The name was classified as a type.
Definition Sema.h:558
U cast(CodeGen::Address addr)
Definition Address.h:327