Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/CodeGen/Targets/WebAssembly.cpp
Line
Count
Source (jump to first uncovered line)
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
0
      : 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
0
  void computeInfo(CGFunctionInfo &FI) const override {
38
0
    if (!getCXXABI().classifyReturnType(FI))
39
0
      FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
40
0
    for (auto &Arg : FI.arguments())
41
0
      Arg.info = classifyArgumentType(Arg.type);
42
0
  }
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
0
      : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
53
0
    SwiftInfo =
54
0
        std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
55
0
  }
56
57
  void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
58
0
                           CodeGen::CodeGenModule &CGM) const override {
59
0
    TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
60
0
    if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
61
0
      if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
62
0
        llvm::Function *Fn = cast<llvm::Function>(GV);
63
0
        llvm::AttrBuilder B(GV->getContext());
64
0
        B.addAttribute("wasm-import-module", Attr->getImportModule());
65
0
        Fn->addFnAttrs(B);
66
0
      }
67
0
      if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
68
0
        llvm::Function *Fn = cast<llvm::Function>(GV);
69
0
        llvm::AttrBuilder B(GV->getContext());
70
0
        B.addAttribute("wasm-import-name", Attr->getImportName());
71
0
        Fn->addFnAttrs(B);
72
0
      }
73
0
      if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) {
74
0
        llvm::Function *Fn = cast<llvm::Function>(GV);
75
0
        llvm::AttrBuilder B(GV->getContext());
76
0
        B.addAttribute("wasm-export-name", Attr->getExportName());
77
0
        Fn->addFnAttrs(B);
78
0
      }
79
0
    }
80
81
0
    if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
82
0
      llvm::Function *Fn = cast<llvm::Function>(GV);
83
0
      if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype())
84
0
        Fn->addFnAttr("no-prototype");
85
0
    }
86
0
  }
87
88
  /// Return the WebAssembly externref reference type.
89
0
  virtual llvm::Type *getWasmExternrefReferenceType() const override {
90
0
    return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
91
0
  }
92
  /// Return the WebAssembly funcref reference type.
93
0
  virtual llvm::Type *getWasmFuncrefReferenceType() const override {
94
0
    return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
95
0
  }
96
};
97
98
/// Classify argument of given type \p Ty.
99
0
ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
100
0
  Ty = useFirstFieldIfTransparentUnion(Ty);
101
102
0
  if (isAggregateTypeForABI(Ty)) {
103
    // Records with non-trivial destructors/copy-constructors should not be
104
    // passed by value.
105
0
    if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
106
0
      return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
107
    // Ignore empty structs/unions.
108
0
    if (isEmptyRecord(getContext(), Ty, true))
109
0
      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
0
    if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
114
0
      return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
115
    // For the experimental multivalue ABI, fully expand all other aggregates
116
0
    if (Kind == WebAssemblyABIKind::ExperimentalMV) {
117
0
      const RecordType *RT = Ty->getAs<RecordType>();
118
0
      assert(RT);
119
0
      bool HasBitField = false;
120
0
      for (auto *Field : RT->getDecl()->fields()) {
121
0
        if (Field->isBitField()) {
122
0
          HasBitField = true;
123
0
          break;
124
0
        }
125
0
      }
126
0
      if (!HasBitField)
127
0
        return ABIArgInfo::getExpand();
128
0
    }
129
0
  }
130
131
  // Otherwise just do the default thing.
132
0
  return defaultInfo.classifyArgumentType(Ty);
133
0
}
134
135
0
ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
136
0
  if (isAggregateTypeForABI(RetTy)) {
137
    // Records with non-trivial destructors/copy-constructors should not be
138
    // returned by value.
139
0
    if (!getRecordArgABI(RetTy, getCXXABI())) {
140
      // Ignore empty structs/unions.
141
0
      if (isEmptyRecord(getContext(), RetTy, true))
142
0
        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
0
      if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
147
0
        return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
148
      // For the experimental multivalue ABI, return all other aggregates
149
0
      if (Kind == WebAssemblyABIKind::ExperimentalMV)
150
0
        return ABIArgInfo::getDirect();
151
0
    }
152
0
  }
153
154
  // Otherwise just do the default thing.
155
0
  return defaultInfo.classifyReturnType(RetTy);
156
0
}
157
158
Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
159
0
                                      QualType Ty) const {
160
0
  bool IsIndirect = isAggregateTypeForABI(Ty) &&
161
0
                    !isEmptyRecord(getContext(), Ty, true) &&
162
0
                    !isSingleElementStruct(Ty, getContext());
163
0
  return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
164
0
                          getContext().getTypeInfoInChars(Ty),
165
0
                          CharUnits::fromQuantity(4),
166
0
                          /*AllowHigherAlign=*/true);
167
0
}
168
169
std::unique_ptr<TargetCodeGenInfo>
170
CodeGen::createWebAssemblyTargetCodeGenInfo(CodeGenModule &CGM,
171
0
                                            WebAssemblyABIKind K) {
172
0
  return std::make_unique<WebAssemblyTargetCodeGenInfo>(CGM.getTypes(), K);
173
0
}