174 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ABIInfoImpl.h"10#include "TargetInfo.h"11 12using namespace clang;13using namespace clang::CodeGen;14 15//===----------------------------------------------------------------------===//16// WebAssembly ABI Implementation17//18// This is a very simple ABI that relies a lot on DefaultABIInfo.19//===----------------------------------------------------------------------===//20 21class WebAssemblyABIInfo final : public ABIInfo {22 DefaultABIInfo defaultInfo;23 WebAssemblyABIKind Kind;24 25public:26 explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT,27 WebAssemblyABIKind Kind)28 : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}29 30private:31 ABIArgInfo classifyReturnType(QualType RetTy) const;32 ABIArgInfo classifyArgumentType(QualType Ty) const;33 34 // DefaultABIInfo's classifyReturnType and classifyArgumentType are35 // non-virtual, but computeInfo and EmitVAArg are virtual, so we36 // 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 48class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {49public: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.99ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {100 Ty = useFirstFieldIfTransparentUnion(Ty);101 102 if (isAggregateTypeForABI(Ty)) {103 // Records with non-trivial destructors/copy-constructors should not be104 // 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: We112 // 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 aggregates117 if (Kind == WebAssemblyABIKind::ExperimentalMV) {118 const auto *RD = Ty->castAsRecordDecl();119 bool HasBitField = false;120 for (auto *Field : RD->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 135ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {136 if (isAggregateTypeForABI(RetTy)) {137 // Records with non-trivial destructors/copy-constructors should not be138 // 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: We144 // could do reasonable-size multiple-element structs too, using145 // 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 aggregates149 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 158RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,159 QualType Ty, AggValueSlot Slot) 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, Slot);167}168 169std::unique_ptr<TargetCodeGenInfo>170CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,171 WebAssemblyABIKind K) {172 return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);173}174