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" 11 12 using namespace clang; 13 using namespace clang::CodeGen; 14 15 //===----------------------------------------------------------------------===// 16 // WebAssembly ABI Implementation 17 // 18 // This is a very simple ABI that relies a lot on DefaultABIInfo. 19 //===----------------------------------------------------------------------===// 20 21 class WebAssemblyABIInfo final : public ABIInfo { 22 DefaultABIInfo defaultInfo; 23 WebAssemblyABIKind Kind; 24 25 public: 26 explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT, 27 WebAssemblyABIKind Kind) 28 : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {} 29 30 private: 31 ABIArgInfo classifyReturnType(QualType RetTy) const; 32 ABIArgInfo classifyArgumentType(QualType Ty) const; 33 34 // DefaultABIInfo's classifyReturnType and classifyArgumentType are 35 // non-virtual, but computeInfo and EmitVAArg are virtual, so we 36 // overload them. 37 void computeInfo(CGFunctionInfo &FI) const override { 38 if (!getCXXABI().classifyReturnType(FI)) 39 FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); 40 for (auto &Arg : FI.arguments()) 41 Arg.info = classifyArgumentType(Arg.type); 42 } 43 44 Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 45 QualType Ty) const override; 46 }; 47 48 class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { 49 public: 50 explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, 51 WebAssemblyABIKind K) 52 : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) { 53 SwiftInfo = 54 std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false); 55 } 56 57 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 58 CodeGen::CodeGenModule &CGM) const override { 59 TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); 60 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { 61 if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) { 62 llvm::Function *Fn = cast<llvm::Function>(GV); 63 llvm::AttrBuilder B(GV->getContext()); 64 B.addAttribute("wasm-import-module", Attr->getImportModule()); 65 Fn->addFnAttrs(B); 66 } 67 if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) { 68 llvm::Function *Fn = cast<llvm::Function>(GV); 69 llvm::AttrBuilder B(GV->getContext()); 70 B.addAttribute("wasm-import-name", Attr->getImportName()); 71 Fn->addFnAttrs(B); 72 } 73 if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { 74 llvm::Function *Fn = cast<llvm::Function>(GV); 75 llvm::AttrBuilder B(GV->getContext()); 76 B.addAttribute("wasm-export-name", Attr->getExportName()); 77 Fn->addFnAttrs(B); 78 } 79 } 80 81 if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { 82 llvm::Function *Fn = cast<llvm::Function>(GV); 83 if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype()) 84 Fn->addFnAttr("no-prototype"); 85 } 86 } 87 88 /// Return the WebAssembly externref reference type. 89 virtual llvm::Type *getWasmExternrefReferenceType() const override { 90 return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext()); 91 } 92 /// Return the WebAssembly funcref reference type. 93 virtual llvm::Type *getWasmFuncrefReferenceType() const override { 94 return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext()); 95 } 96 }; 97 98 /// Classify argument of given type \p Ty. 99 ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { 100 Ty = useFirstFieldIfTransparentUnion(Ty); 101 102 if (isAggregateTypeForABI(Ty)) { 103 // Records with non-trivial destructors/copy-constructors should not be 104 // passed by value. 105 if (auto RAA = getRecordArgABI(Ty, getCXXABI())) 106 return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); 107 // Ignore empty structs/unions. 108 if (isEmptyRecord(getContext(), Ty, true)) 109 return ABIArgInfo::getIgnore(); 110 // Lower single-element structs to just pass a regular value. TODO: We 111 // could do reasonable-size multiple-element structs too, using getExpand(), 112 // though watch out for things like bitfields. 113 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) 114 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); 115 // For the experimental multivalue ABI, fully expand all other aggregates 116 if (Kind == WebAssemblyABIKind::ExperimentalMV) { 117 const RecordType *RT = Ty->getAs<RecordType>(); 118 assert(RT); 119 bool HasBitField = false; 120 for (auto *Field : RT->getDecl()->fields()) { 121 if (Field->isBitField()) { 122 HasBitField = true; 123 break; 124 } 125 } 126 if (!HasBitField) 127 return ABIArgInfo::getExpand(); 128 } 129 } 130 131 // Otherwise just do the default thing. 132 return defaultInfo.classifyArgumentType(Ty); 133 } 134 135 ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { 136 if (isAggregateTypeForABI(RetTy)) { 137 // Records with non-trivial destructors/copy-constructors should not be 138 // returned by value. 139 if (!getRecordArgABI(RetTy, getCXXABI())) { 140 // Ignore empty structs/unions. 141 if (isEmptyRecord(getContext(), RetTy, true)) 142 return ABIArgInfo::getIgnore(); 143 // Lower single-element structs to just return a regular value. TODO: We 144 // could do reasonable-size multiple-element structs too, using 145 // ABIArgInfo::getDirect(). 146 if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) 147 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); 148 // For the experimental multivalue ABI, return all other aggregates 149 if (Kind == WebAssemblyABIKind::ExperimentalMV) 150 return ABIArgInfo::getDirect(); 151 } 152 } 153 154 // Otherwise just do the default thing. 155 return defaultInfo.classifyReturnType(RetTy); 156 } 157 158 Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 159 QualType Ty) const { 160 bool IsIndirect = isAggregateTypeForABI(Ty) && 161 !isEmptyRecord(getContext(), Ty, true) && 162 !isSingleElementStruct(Ty, getContext()); 163 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, 164 getContext().getTypeInfoInChars(Ty), 165 CharUnits::fromQuantity(4), 166 /*AllowHigherAlign=*/true); 167 } 168 169 std::unique_ptr<TargetCodeGenInfo> 170 CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, 171 WebAssemblyABIKind K) { 172 return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K); 173 } 174