173 lines
6.9 KiB
C++
173 lines
6.9 KiB
C++
//===- 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);
|
|
}
|
|
|
|
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
QualType Ty) const override;
|
|
};
|
|
|
|
class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
|
|
public:
|
|
explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
|
|
WebAssemblyABIKind K)
|
|
: TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
|
|
SwiftInfo =
|
|
std::make_unique<SwiftABIInfo>(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<FunctionDecl>(D)) {
|
|
if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
|
|
llvm::Function *Fn = cast<llvm::Function>(GV);
|
|
llvm::AttrBuilder B(GV->getContext());
|
|
B.addAttribute("wasm-import-module", Attr->getImportModule());
|
|
Fn->addFnAttrs(B);
|
|
}
|
|
if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
|
|
llvm::Function *Fn = cast<llvm::Function>(GV);
|
|
llvm::AttrBuilder B(GV->getContext());
|
|
B.addAttribute("wasm-import-name", Attr->getImportName());
|
|
Fn->addFnAttrs(B);
|
|
}
|
|
if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
|
|
llvm::Function *Fn = cast<llvm::Function>(GV);
|
|
llvm::AttrBuilder B(GV->getContext());
|
|
B.addAttribute("wasm-export-name", Attr->getExportName());
|
|
Fn->addFnAttrs(B);
|
|
}
|
|
}
|
|
|
|
if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
|
llvm::Function *Fn = cast<llvm::Function>(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<RecordType>();
|
|
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);
|
|
}
|
|
|
|
Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
QualType Ty) 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);
|
|
}
|
|
|
|
std::unique_ptr<TargetCodeGenInfo>
|
|
CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
|
|
WebAssemblyABIKind K) {
|
|
return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
|
|
}
|