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 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 45 AggValueSlot Slot) 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, getDataLayout().getAllocaAddrSpace(), 107 RAA == CGCXXABI::RAA_DirectInMemory); 108 // Ignore empty structs/unions. 109 if (isEmptyRecord(getContext(), Ty, true)) 110 return ABIArgInfo::getIgnore(); 111 // Lower single-element structs to just pass a regular value. TODO: We 112 // could do reasonable-size multiple-element structs too, using getExpand(), 113 // though watch out for things like bitfields. 114 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) 115 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); 116 // For the experimental multivalue ABI, fully expand all other aggregates 117 if (Kind == WebAssemblyABIKind::ExperimentalMV) { 118 const RecordType *RT = Ty->getAs<RecordType>(); 119 assert(RT); 120 bool HasBitField = false; 121 for (auto *Field : RT->getDecl()->fields()) { 122 if (Field->isBitField()) { 123 HasBitField = true; 124 break; 125 } 126 } 127 if (!HasBitField) 128 return ABIArgInfo::getExpand(); 129 } 130 } 131 132 // Otherwise just do the default thing. 133 return defaultInfo.classifyArgumentType(Ty); 134 } 135 136 ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { 137 if (isAggregateTypeForABI(RetTy)) { 138 // Records with non-trivial destructors/copy-constructors should not be 139 // returned by value. 140 if (!getRecordArgABI(RetTy, getCXXABI())) { 141 // Ignore empty structs/unions. 142 if (isEmptyRecord(getContext(), RetTy, true)) 143 return ABIArgInfo::getIgnore(); 144 // Lower single-element structs to just return a regular value. TODO: We 145 // could do reasonable-size multiple-element structs too, using 146 // ABIArgInfo::getDirect(). 147 if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) 148 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); 149 // For the experimental multivalue ABI, return all other aggregates 150 if (Kind == WebAssemblyABIKind::ExperimentalMV) 151 return ABIArgInfo::getDirect(); 152 } 153 } 154 155 // Otherwise just do the default thing. 156 return defaultInfo.classifyReturnType(RetTy); 157 } 158 159 RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 160 QualType Ty, AggValueSlot Slot) const { 161 bool IsIndirect = isAggregateTypeForABI(Ty) && 162 !isEmptyRecord(getContext(), Ty, true) && 163 !isSingleElementStruct(Ty, getContext()); 164 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, 165 getContext().getTypeInfoInChars(Ty), 166 CharUnits::fromQuantity(4), 167 /*AllowHigherAlign=*/true, Slot); 168 } 169 170 std::unique_ptr<TargetCodeGenInfo> 171 CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM, 172 WebAssemblyABIKind K) { 173 return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K); 174 } 175