xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/WebAssembly.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- WebAssembly.cpp ----------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "ABIInfoImpl.h"
1006c3fb27SDimitry Andric #include "TargetInfo.h"
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric using namespace clang;
1306c3fb27SDimitry Andric using namespace clang::CodeGen;
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1606c3fb27SDimitry Andric // WebAssembly ABI Implementation
1706c3fb27SDimitry Andric //
1806c3fb27SDimitry Andric // This is a very simple ABI that relies a lot on DefaultABIInfo.
1906c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
2006c3fb27SDimitry Andric 
2106c3fb27SDimitry Andric class WebAssemblyABIInfo final : public ABIInfo {
2206c3fb27SDimitry Andric   DefaultABIInfo defaultInfo;
2306c3fb27SDimitry Andric   WebAssemblyABIKind Kind;
2406c3fb27SDimitry Andric 
2506c3fb27SDimitry Andric public:
2606c3fb27SDimitry Andric   explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT,
2706c3fb27SDimitry Andric                               WebAssemblyABIKind Kind)
2806c3fb27SDimitry Andric       : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric private:
3106c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
3206c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty) const;
3306c3fb27SDimitry Andric 
3406c3fb27SDimitry Andric   // DefaultABIInfo's classifyReturnType and classifyArgumentType are
3506c3fb27SDimitry Andric   // non-virtual, but computeInfo and EmitVAArg are virtual, so we
3606c3fb27SDimitry Andric   // overload them.
3706c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override {
3806c3fb27SDimitry Andric     if (!getCXXABI().classifyReturnType(FI))
3906c3fb27SDimitry Andric       FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
4006c3fb27SDimitry Andric     for (auto &Arg : FI.arguments())
4106c3fb27SDimitry Andric       Arg.info = classifyArgumentType(Arg.type);
4206c3fb27SDimitry Andric   }
4306c3fb27SDimitry Andric 
44*0fca6ea1SDimitry Andric   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
45*0fca6ea1SDimitry Andric                    AggValueSlot Slot) const override;
4606c3fb27SDimitry Andric };
4706c3fb27SDimitry Andric 
4806c3fb27SDimitry Andric class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
4906c3fb27SDimitry Andric public:
5006c3fb27SDimitry Andric   explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
5106c3fb27SDimitry Andric                                         WebAssemblyABIKind K)
5206c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
5306c3fb27SDimitry Andric     SwiftInfo =
5406c3fb27SDimitry Andric         std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
5506c3fb27SDimitry Andric   }
5606c3fb27SDimitry Andric 
5706c3fb27SDimitry Andric   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
5806c3fb27SDimitry Andric                            CodeGen::CodeGenModule &CGM) const override {
5906c3fb27SDimitry Andric     TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
6006c3fb27SDimitry Andric     if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
6106c3fb27SDimitry Andric       if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
6206c3fb27SDimitry Andric         llvm::Function *Fn = cast<llvm::Function>(GV);
6306c3fb27SDimitry Andric         llvm::AttrBuilder B(GV->getContext());
6406c3fb27SDimitry Andric         B.addAttribute("wasm-import-module", Attr->getImportModule());
6506c3fb27SDimitry Andric         Fn->addFnAttrs(B);
6606c3fb27SDimitry Andric       }
6706c3fb27SDimitry Andric       if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
6806c3fb27SDimitry Andric         llvm::Function *Fn = cast<llvm::Function>(GV);
6906c3fb27SDimitry Andric         llvm::AttrBuilder B(GV->getContext());
7006c3fb27SDimitry Andric         B.addAttribute("wasm-import-name", Attr->getImportName());
7106c3fb27SDimitry Andric         Fn->addFnAttrs(B);
7206c3fb27SDimitry Andric       }
7306c3fb27SDimitry Andric       if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
7406c3fb27SDimitry Andric         llvm::Function *Fn = cast<llvm::Function>(GV);
7506c3fb27SDimitry Andric         llvm::AttrBuilder B(GV->getContext());
7606c3fb27SDimitry Andric         B.addAttribute("wasm-export-name", Attr->getExportName());
7706c3fb27SDimitry Andric         Fn->addFnAttrs(B);
7806c3fb27SDimitry Andric       }
7906c3fb27SDimitry Andric     }
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric     if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
8206c3fb27SDimitry Andric       llvm::Function *Fn = cast<llvm::Function>(GV);
8306c3fb27SDimitry Andric       if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
8406c3fb27SDimitry Andric         Fn->addFnAttr("no-prototype");
8506c3fb27SDimitry Andric     }
8606c3fb27SDimitry Andric   }
8706c3fb27SDimitry Andric 
8806c3fb27SDimitry Andric   /// Return the WebAssembly externref reference type.
8906c3fb27SDimitry Andric   virtual llvm::Type *getWasmExternrefReferenceType() const override {
9006c3fb27SDimitry Andric     return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
9106c3fb27SDimitry Andric   }
9206c3fb27SDimitry Andric   /// Return the WebAssembly funcref reference type.
9306c3fb27SDimitry Andric   virtual llvm::Type *getWasmFuncrefReferenceType() const override {
9406c3fb27SDimitry Andric     return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
9506c3fb27SDimitry Andric   }
9606c3fb27SDimitry Andric };
9706c3fb27SDimitry Andric 
9806c3fb27SDimitry Andric /// Classify argument of given type \p Ty.
9906c3fb27SDimitry Andric ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
10006c3fb27SDimitry Andric   Ty = useFirstFieldIfTransparentUnion(Ty);
10106c3fb27SDimitry Andric 
10206c3fb27SDimitry Andric   if (isAggregateTypeForABI(Ty)) {
10306c3fb27SDimitry Andric     // Records with non-trivial destructors/copy-constructors should not be
10406c3fb27SDimitry Andric     // passed by value.
10506c3fb27SDimitry Andric     if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
10606c3fb27SDimitry Andric       return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
10706c3fb27SDimitry Andric     // Ignore empty structs/unions.
10806c3fb27SDimitry Andric     if (isEmptyRecord(getContext(), Ty, true))
10906c3fb27SDimitry Andric       return ABIArgInfo::getIgnore();
11006c3fb27SDimitry Andric     // Lower single-element structs to just pass a regular value. TODO: We
11106c3fb27SDimitry Andric     // could do reasonable-size multiple-element structs too, using getExpand(),
11206c3fb27SDimitry Andric     // though watch out for things like bitfields.
11306c3fb27SDimitry Andric     if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
11406c3fb27SDimitry Andric       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
11506c3fb27SDimitry Andric     // For the experimental multivalue ABI, fully expand all other aggregates
11606c3fb27SDimitry Andric     if (Kind == WebAssemblyABIKind::ExperimentalMV) {
11706c3fb27SDimitry Andric       const RecordType *RT = Ty->getAs<RecordType>();
11806c3fb27SDimitry Andric       assert(RT);
11906c3fb27SDimitry Andric       bool HasBitField = false;
12006c3fb27SDimitry Andric       for (auto *Field : RT->getDecl()->fields()) {
12106c3fb27SDimitry Andric         if (Field->isBitField()) {
12206c3fb27SDimitry Andric           HasBitField = true;
12306c3fb27SDimitry Andric           break;
12406c3fb27SDimitry Andric         }
12506c3fb27SDimitry Andric       }
12606c3fb27SDimitry Andric       if (!HasBitField)
12706c3fb27SDimitry Andric         return ABIArgInfo::getExpand();
12806c3fb27SDimitry Andric     }
12906c3fb27SDimitry Andric   }
13006c3fb27SDimitry Andric 
13106c3fb27SDimitry Andric   // Otherwise just do the default thing.
13206c3fb27SDimitry Andric   return defaultInfo.classifyArgumentType(Ty);
13306c3fb27SDimitry Andric }
13406c3fb27SDimitry Andric 
13506c3fb27SDimitry Andric ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
13606c3fb27SDimitry Andric   if (isAggregateTypeForABI(RetTy)) {
13706c3fb27SDimitry Andric     // Records with non-trivial destructors/copy-constructors should not be
13806c3fb27SDimitry Andric     // returned by value.
13906c3fb27SDimitry Andric     if (!getRecordArgABI(RetTy, getCXXABI())) {
14006c3fb27SDimitry Andric       // Ignore empty structs/unions.
14106c3fb27SDimitry Andric       if (isEmptyRecord(getContext(), RetTy, true))
14206c3fb27SDimitry Andric         return ABIArgInfo::getIgnore();
14306c3fb27SDimitry Andric       // Lower single-element structs to just return a regular value. TODO: We
14406c3fb27SDimitry Andric       // could do reasonable-size multiple-element structs too, using
14506c3fb27SDimitry Andric       // ABIArgInfo::getDirect().
14606c3fb27SDimitry Andric       if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
14706c3fb27SDimitry Andric         return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
14806c3fb27SDimitry Andric       // For the experimental multivalue ABI, return all other aggregates
14906c3fb27SDimitry Andric       if (Kind == WebAssemblyABIKind::ExperimentalMV)
15006c3fb27SDimitry Andric         return ABIArgInfo::getDirect();
15106c3fb27SDimitry Andric     }
15206c3fb27SDimitry Andric   }
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric   // Otherwise just do the default thing.
15506c3fb27SDimitry Andric   return defaultInfo.classifyReturnType(RetTy);
15606c3fb27SDimitry Andric }
15706c3fb27SDimitry Andric 
158*0fca6ea1SDimitry Andric RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
159*0fca6ea1SDimitry Andric                                      QualType Ty, AggValueSlot Slot) const {
16006c3fb27SDimitry Andric   bool IsIndirect = isAggregateTypeForABI(Ty) &&
16106c3fb27SDimitry Andric                     !isEmptyRecord(getContext(), Ty, true) &&
16206c3fb27SDimitry Andric                     !isSingleElementStruct(Ty, getContext());
16306c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
16406c3fb27SDimitry Andric                           getContext().getTypeInfoInChars(Ty),
16506c3fb27SDimitry Andric                           CharUnits::fromQuantity(4),
166*0fca6ea1SDimitry Andric                           /*AllowHigherAlign=*/true, Slot);
16706c3fb27SDimitry Andric }
16806c3fb27SDimitry Andric 
16906c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
17006c3fb27SDimitry Andric CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
17106c3fb27SDimitry Andric                                             WebAssemblyABIKind K) {
17206c3fb27SDimitry Andric   return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
17306c3fb27SDimitry Andric }
174