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