clang 23.0.0git
SemaWasm.cpp
Go to the documentation of this file.
1//===------ SemaWasm.cpp ---- WebAssembly target-specific routines --------===//
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// This file implements semantic analysis functions specific to WebAssembly.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Sema/SemaWasm.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/Type.h"
21#include "clang/Sema/Attr.h"
22#include "clang/Sema/Sema.h"
23
24namespace clang {
25
27
28/// Checks the argument at the given index is a WebAssembly table and if it
29/// is, sets ElTy to the element type.
30static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex,
31 QualType &ElTy) {
32 Expr *ArgExpr = E->getArg(ArgIndex);
33 const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType());
34 if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) {
35 return S.Diag(ArgExpr->getBeginLoc(),
36 diag::err_wasm_builtin_arg_must_be_table_type)
37 << ArgIndex + 1 << ArgExpr->getSourceRange();
38 }
39 ElTy = ATy->getElementType();
40 return false;
41}
42
43static bool CheckWasmTableElement(Sema &S, QualType &ElTy, CallExpr *E,
44 unsigned TableIndex, unsigned ArgIndex) {
45 Expr *NewElemArg = E->getArg(ArgIndex);
46 QualType QT = NewElemArg->getType();
47 // Compare the types after removing insignificant qualifiers
48 if (!S.getASTContext().hasSameType(ElTy.getTypePtr(), QT.getTypePtr())) {
49 return S.Diag(NewElemArg->getBeginLoc(),
50 diag::err_wasm_builtin_arg_must_match_table_element_type)
51 << (ArgIndex + 1) << (TableIndex + 1)
52 << NewElemArg->getSourceRange();
53 }
54 return false;
55}
56
57/// Checks the argument at the given index is an integer.
59 unsigned ArgIndex) {
60 Expr *ArgExpr = E->getArg(ArgIndex);
61 if (!ArgExpr->getType()->isIntegerType()) {
62 return S.Diag(ArgExpr->getBeginLoc(),
63 diag::err_wasm_builtin_arg_must_be_integer_type)
64 << ArgIndex + 1 << ArgExpr->getSourceRange();
65 }
66 return false;
67}
68
70 if (SemaRef.checkArgCount(TheCall, /*DesiredArgCount=*/0))
71 return true;
72 TheCall->setType(getASTContext().getWebAssemblyExternrefType());
73
74 return false;
75}
76
78 if (SemaRef.checkArgCount(TheCall, 1)) {
79 return true;
80 }
81
82 Expr *ArgExpr = TheCall->getArg(0);
83 if (!ArgExpr->getType().isWebAssemblyExternrefType()) {
84 SemaRef.Diag(ArgExpr->getBeginLoc(),
85 diag::err_wasm_builtin_arg_must_be_externref_type)
86 << 1 << ArgExpr->getSourceRange();
87 return true;
88 }
89
90 return false;
91}
92
94 ASTContext &Context = getASTContext();
95 if (SemaRef.checkArgCount(TheCall, /*DesiredArgCount=*/0))
96 return true;
97
98 // This custom type checking code ensures that the nodes are as expected
99 // in order to later on generate the necessary builtin.
100 QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {});
101 QualType Type = Context.getPointerType(Pointee);
102 Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref);
103 Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type,
104 Context.getPointerType(Pointee));
105 TheCall->setType(Type);
106
107 return false;
108}
109
110/// Check that the first argument is a WebAssembly table, and the second
111/// is an index to use as index into the table.
113 if (SemaRef.checkArgCount(TheCall, 2))
114 return true;
115
116 QualType ElTy;
117 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
118 return true;
119
120 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1))
121 return true;
122
123 // If all is well, we set the type of TheCall to be the type of the
124 // element of the table.
125 // i.e. a table.get on an externref table has type externref,
126 // or whatever the type of the table element is.
127 TheCall->setType(ElTy);
128
129 return false;
130}
131
132/// Check that the first argument is a WebAssembly table, the second is
133/// an index to use as index into the table and the third is the reference
134/// type to set into the table.
136 if (SemaRef.checkArgCount(TheCall, 3))
137 return true;
138
139 QualType ElTy;
140 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
141 return true;
142
143 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1))
144 return true;
145
146 if (CheckWasmTableElement(SemaRef, ElTy, TheCall, 0, 2))
147 return true;
148
149 return false;
150}
151
152/// Check that the argument is a WebAssembly table.
154 if (SemaRef.checkArgCount(TheCall, 1))
155 return true;
156
157 QualType ElTy;
158 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
159 return true;
160
161 return false;
162}
163
164/// Check that the first argument is a WebAssembly table, the second is the
165/// value to use for new elements (of a type matching the table type), the
166/// third value is an integer.
168 if (SemaRef.checkArgCount(TheCall, 3))
169 return true;
170
171 QualType ElTy;
172 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
173 return true;
174
175 if (CheckWasmTableElement(SemaRef, ElTy, TheCall, 0, 1))
176 return true;
177
178 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 2))
179 return true;
180
181 return false;
182}
183
184/// Check that the first argument is a WebAssembly table, the second is an
185/// integer, the third is the value to use to fill the table (of a type
186/// matching the table type), and the fourth is an integer.
188 if (SemaRef.checkArgCount(TheCall, 4))
189 return true;
190
191 QualType ElTy;
192 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
193 return true;
194
195 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1))
196 return true;
197
198 if (CheckWasmTableElement(SemaRef, ElTy, TheCall, 0, 2))
199 return true;
200
201 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 3))
202 return true;
203
204 return false;
205}
206
207/// Check that the first argument is a WebAssembly table, the second is also a
208/// WebAssembly table (of the same element type), and the third to fifth
209/// arguments are integers.
211 if (SemaRef.checkArgCount(TheCall, 5))
212 return true;
213
214 QualType XElTy;
215 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, XElTy))
216 return true;
217
218 QualType YElTy;
219 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 1, YElTy))
220 return true;
221
222 Expr *TableYArg = TheCall->getArg(1);
223 if (!getASTContext().hasSameType(XElTy.getTypePtr(), YElTy.getTypePtr())) {
224 return Diag(TableYArg->getBeginLoc(),
225 diag::err_wasm_builtin_arg_must_match_table_element_type)
226 << 2 << 1 << TableYArg->getSourceRange();
227 }
228
229 for (int I = 2; I <= 4; I++) {
230 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, I))
231 return true;
232 }
233
234 return false;
235}
236
238 CallExpr *TheCall) {
239 if (SemaRef.checkArgCount(TheCall, 1))
240 return true;
241
242 Expr *FuncPtrArg = TheCall->getArg(0);
243 QualType ArgType = FuncPtrArg->getType();
244
245 // Check that the argument is a function pointer
246 const PointerType *PtrTy = ArgType->getAs<PointerType>();
247 if (!PtrTy) {
248 return Diag(FuncPtrArg->getBeginLoc(),
249 diag::err_typecheck_expect_function_pointer)
250 << ArgType << FuncPtrArg->getSourceRange();
251 }
252
253 const FunctionProtoType *FuncTy =
255 if (!FuncTy) {
256 return Diag(FuncPtrArg->getBeginLoc(),
257 diag::err_typecheck_expect_function_pointer)
258 << ArgType << FuncPtrArg->getSourceRange();
259 }
260
261 if (TI.getABI() == "experimental-mv") {
262 auto isStructOrUnion = [](QualType T) {
263 return T->isUnionType() || T->isStructureType();
264 };
265 if (isStructOrUnion(FuncTy->getReturnType())) {
266 return Diag(
267 FuncPtrArg->getBeginLoc(),
268 diag::
269 err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
270 << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
271 }
272 auto NParams = FuncTy->getNumParams();
273 for (unsigned I = 0; I < NParams; I++) {
274 if (isStructOrUnion(FuncTy->getParamType(I))) {
275 return Diag(
276 FuncPtrArg->getBeginLoc(),
277 diag::
278 err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
279 << 1 << FuncPtrArg->getSourceRange();
280 }
281 }
282 }
283
284 // Set return type to int (the result of the test)
285 TheCall->setType(getASTContext().IntTy);
286 return false;
287}
288
290 unsigned BuiltinID,
291 CallExpr *TheCall) {
292 switch (BuiltinID) {
293 case WebAssembly::BI__builtin_wasm_ref_null_extern:
294 return BuiltinWasmRefNullExtern(TheCall);
295 case WebAssembly::BI__builtin_wasm_ref_null_func:
296 return BuiltinWasmRefNullFunc(TheCall);
297 case WebAssembly::BI__builtin_wasm_ref_is_null_extern:
298 return BuiltinWasmRefIsNullExtern(TheCall);
299 case WebAssembly::BI__builtin_wasm_table_get:
300 return BuiltinWasmTableGet(TheCall);
301 case WebAssembly::BI__builtin_wasm_table_set:
302 return BuiltinWasmTableSet(TheCall);
303 case WebAssembly::BI__builtin_wasm_table_size:
304 return BuiltinWasmTableSize(TheCall);
305 case WebAssembly::BI__builtin_wasm_table_grow:
306 return BuiltinWasmTableGrow(TheCall);
307 case WebAssembly::BI__builtin_wasm_table_fill:
308 return BuiltinWasmTableFill(TheCall);
309 case WebAssembly::BI__builtin_wasm_table_copy:
310 return BuiltinWasmTableCopy(TheCall);
311 case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
312 return BuiltinWasmTestFunctionPointerSignature(TI, TheCall);
313 }
314
315 return false;
316}
317
318WebAssemblyImportModuleAttr *
320 const WebAssemblyImportModuleAttr &AL) {
321 auto *FD = cast<FunctionDecl>(D);
322
323 if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
324 if (ExistingAttr->getImportModule() == AL.getImportModule())
325 return nullptr;
326 Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
327 << 0 << ExistingAttr->getImportModule() << AL.getImportModule();
328 Diag(AL.getLoc(), diag::note_previous_attribute);
329 return nullptr;
330 }
331 if (FD->hasBody()) {
332 Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
333 return nullptr;
334 }
335 return ::new (getASTContext())
336 WebAssemblyImportModuleAttr(getASTContext(), AL, AL.getImportModule());
337}
338
339WebAssemblyImportNameAttr *
340SemaWasm::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
341 auto *FD = cast<FunctionDecl>(D);
342
343 if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
344 if (ExistingAttr->getImportName() == AL.getImportName())
345 return nullptr;
346 Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
347 << 1 << ExistingAttr->getImportName() << AL.getImportName();
348 Diag(AL.getLoc(), diag::note_previous_attribute);
349 return nullptr;
350 }
351 if (FD->hasBody()) {
352 Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
353 return nullptr;
354 }
355 return ::new (getASTContext())
356 WebAssemblyImportNameAttr(getASTContext(), AL, AL.getImportName());
357}
358
360 const ParsedAttr &AL) {
361 auto *FD = cast<FunctionDecl>(D);
362
363 StringRef Str;
364 SourceLocation ArgLoc;
365 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
366 return;
367 if (FD->hasBody()) {
368 Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
369 return;
370 }
371
372 FD->addAttr(::new (getASTContext())
373 WebAssemblyImportModuleAttr(getASTContext(), AL, Str));
374}
375
377 auto *FD = cast<FunctionDecl>(D);
378
379 StringRef Str;
380 SourceLocation ArgLoc;
381 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
382 return;
383 if (FD->hasBody()) {
384 Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
385 return;
386 }
387
388 FD->addAttr(::new (getASTContext())
389 WebAssemblyImportNameAttr(getASTContext(), AL, Str));
390}
391
393 ASTContext &Context = getASTContext();
395 Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
397 return;
398 }
399
400 auto *FD = cast<FunctionDecl>(D);
401 if (FD->isThisDeclarationADefinition()) {
402 Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
403 return;
404 }
405
406 StringRef Str;
407 SourceLocation ArgLoc;
408 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
409 return;
410
411 D->addAttr(::new (Context) WebAssemblyExportNameAttr(Context, AL, Str));
412 D->addAttr(UsedAttr::CreateImplicit(Context));
413}
414
415} // namespace clang
Defines the clang::ASTContext interface.
Provides definitions for the various language-specific address spaces.
This file declares semantic analysis functions specific to Wasm.
Enumerates target-specific builtins in their own namespaces within namespace clang.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
SourceLocation getLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2946
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3150
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
void addAttr(Attr *A)
SourceLocation getLocation() const
Definition DeclBase.h:439
This represents one expression.
Definition Expr.h:112
void setType(QualType t)
Definition Expr.h:145
QualType getType() const
Definition Expr.h:144
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5315
unsigned getNumParams() const
Definition TypeBase.h:5593
QualType getParamType(unsigned i) const
Definition TypeBase.h:5595
QualType getReturnType() const
Definition TypeBase.h:4851
ParsedAttr - Represents a syntactic attribute.
Definition ParsedAttr.h:119
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3336
A (possibly-)qualified type.
Definition TypeBase.h:937
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8388
bool isWebAssemblyExternrefType() const
Returns true if it is a WebAssembly Externref Type.
Definition Type.cpp:2988
SemaBase(Sema &S)
Definition SemaBase.cpp:7
ASTContext & getASTContext() const
Definition SemaBase.cpp:9
Sema & SemaRef
Definition SemaBase.h:40
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition SemaBase.cpp:61
void handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL)
Definition SemaWasm.cpp:376
bool BuiltinWasmRefNullExtern(CallExpr *TheCall)
Definition SemaWasm.cpp:69
bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaWasm.cpp:289
bool BuiltinWasmTableGet(CallExpr *TheCall)
Check that the first argument is a WebAssembly table, and the second is an index to use as index into...
Definition SemaWasm.cpp:112
bool BuiltinWasmTableFill(CallExpr *TheCall)
Check that the first argument is a WebAssembly table, the second is an integer, the third is the valu...
Definition SemaWasm.cpp:187
bool BuiltinWasmTableSize(CallExpr *TheCall)
Check that the argument is a WebAssembly table.
Definition SemaWasm.cpp:153
void handleWebAssemblyImportModuleAttr(Decl *D, const ParsedAttr &AL)
Definition SemaWasm.cpp:359
bool BuiltinWasmRefNullFunc(CallExpr *TheCall)
Definition SemaWasm.cpp:93
bool BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI, CallExpr *TheCall)
Definition SemaWasm.cpp:237
bool BuiltinWasmTableSet(CallExpr *TheCall)
Check that the first argument is a WebAssembly table, the second is an index to use as index into the...
Definition SemaWasm.cpp:135
SemaWasm(Sema &S)
Definition SemaWasm.cpp:26
bool BuiltinWasmRefIsNullExtern(CallExpr *TheCall)
Definition SemaWasm.cpp:77
void handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL)
Definition SemaWasm.cpp:392
WebAssemblyImportNameAttr * mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL)
Definition SemaWasm.cpp:340
WebAssemblyImportModuleAttr * mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL)
Definition SemaWasm.cpp:319
bool BuiltinWasmTableGrow(CallExpr *TheCall)
Check that the first argument is a WebAssembly table, the second is the value to use for new elements...
Definition SemaWasm.cpp:167
bool BuiltinWasmTableCopy(CallExpr *TheCall)
Check that the first argument is a WebAssembly table, the second is also a WebAssembly table (of the ...
Definition SemaWasm.cpp:210
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:868
ASTContext & getASTContext() const
Definition Sema.h:939
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Exposes information about the current target.
Definition TargetInfo.h:226
virtual StringRef getABI() const
Get the ABI currently in use.
The base class of the type hierarchy.
Definition TypeBase.h:1839
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9035
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:753
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9218
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
@ ExpectedFunction
static bool CheckWasmTableElement(Sema &S, QualType &ElTy, CallExpr *E, unsigned TableIndex, unsigned ArgIndex)
Definition SemaWasm.cpp:43
static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, QualType &ElTy)
Checks the argument at the given index is a WebAssembly table and if it is, sets ElTy to the element ...
Definition SemaWasm.cpp:30
static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, unsigned ArgIndex)
Checks the argument at the given index is an integer.
Definition SemaWasm.cpp:58
bool isFuncOrMethodForAttrSubject(const Decl *D)
isFuncOrMethodForAttrSubject - Return true if the given decl has function type (function or function-...
Definition Attr.h:34
U cast(CodeGen::Address addr)
Definition Address.h:327