//===- WebAssembly.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "ABIInfoImpl.h" #include "TargetInfo.h" using namespace clang; using namespace clang::CodeGen; //===----------------------------------------------------------------------===// // WebAssembly ABI Implementation // // This is a very simple ABI that relies a lot on DefaultABIInfo. //===----------------------------------------------------------------------===// class WebAssemblyABIInfo final : public ABIInfo { DefaultABIInfo defaultInfo; WebAssemblyABIKind Kind; public: explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT, WebAssemblyABIKind Kind) : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo and EmitVAArg are virtual, so we // overload them. void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); } RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; }; class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { public: explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, WebAssemblyABIKind K) : TargetCodeGenInfo(std::make_unique(CGT, K)) { SwiftInfo = std::make_unique(CGT, /*SwiftErrorInRegister=*/false); } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (const auto *FD = dyn_cast_or_null(D)) { if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-import-module", Attr->getImportModule()); Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-import-name", Attr->getImportName()); Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-export-name", Attr->getExportName()); Fn->addFnAttrs(B); } } if (auto *FD = dyn_cast_or_null(D)) { llvm::Function *Fn = cast(GV); if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype()) Fn->addFnAttr("no-prototype"); } } /// Return the WebAssembly externref reference type. virtual llvm::Type *getWasmExternrefReferenceType() const override { return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext()); } /// Return the WebAssembly funcref reference type. virtual llvm::Type *getWasmFuncrefReferenceType() const override { return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext()); } }; /// Classify argument of given type \p Ty. ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (auto RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just pass a regular value. TODO: We // could do reasonable-size multiple-element structs too, using getExpand(), // though watch out for things like bitfields. if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // For the experimental multivalue ABI, fully expand all other aggregates if (Kind == WebAssemblyABIKind::ExperimentalMV) { const RecordType *RT = Ty->getAs(); assert(RT); bool HasBitField = false; for (auto *Field : RT->getDecl()->fields()) { if (Field->isBitField()) { HasBitField = true; break; } } if (!HasBitField) return ABIArgInfo::getExpand(); } } // Otherwise just do the default thing. return defaultInfo.classifyArgumentType(Ty); } ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be // returned by value. if (!getRecordArgABI(RetTy, getCXXABI())) { // Ignore empty structs/unions. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just return a regular value. TODO: We // could do reasonable-size multiple-element structs too, using // ABIArgInfo::getDirect(). if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // For the experimental multivalue ABI, return all other aggregates if (Kind == WebAssemblyABIKind::ExperimentalMV) return ABIArgInfo::getDirect(); } } // Otherwise just do the default thing. return defaultInfo.classifyReturnType(RetTy); } RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const { bool IsIndirect = isAggregateTypeForABI(Ty) && !isEmptyRecord(getContext(), Ty, true) && !isSingleElementStruct(Ty, getContext()); return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(4), /*AllowHigherAlign=*/true, Slot); } std::unique_ptr CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, WebAssemblyABIKind K) { return std::make_unique(CGM.getTypes(), K); }