clang 20.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"
20#include "clang/Sema/Attr.h"
21#include "clang/Sema/Sema.h"
22
23namespace clang {
24
26
27/// Checks the argument at the given index is a WebAssembly table and if it
28/// is, sets ElTy to the element type.
29static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex,
30 QualType &ElTy) {
31 Expr *ArgExpr = E->getArg(ArgIndex);
32 const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType());
33 if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) {
34 return S.Diag(ArgExpr->getBeginLoc(),
35 diag::err_wasm_builtin_arg_must_be_table_type)
36 << ArgIndex + 1 << ArgExpr->getSourceRange();
37 }
38 ElTy = ATy->getElementType();
39 return false;
40}
41
42/// Checks the argument at the given index is an integer.
44 unsigned ArgIndex) {
45 Expr *ArgExpr = E->getArg(ArgIndex);
46 if (!ArgExpr->getType()->isIntegerType()) {
47 return S.Diag(ArgExpr->getBeginLoc(),
48 diag::err_wasm_builtin_arg_must_be_integer_type)
49 << ArgIndex + 1 << ArgExpr->getSourceRange();
50 }
51 return false;
52}
53
55 if (TheCall->getNumArgs() != 0)
56 return true;
57
58 TheCall->setType(getASTContext().getWebAssemblyExternrefType());
59
60 return false;
61}
62
64 ASTContext &Context = getASTContext();
65 if (TheCall->getNumArgs() != 0) {
66 Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args)
67 << 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs()
68 << /*is non object*/ 0;
69 return true;
70 }
71
72 // This custom type checking code ensures that the nodes are as expected
73 // in order to later on generate the necessary builtin.
74 QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {});
75 QualType Type = Context.getPointerType(Pointee);
76 Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref);
77 Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type,
78 Context.getPointerType(Pointee));
79 TheCall->setType(Type);
80
81 return false;
82}
83
84/// Check that the first argument is a WebAssembly table, and the second
85/// is an index to use as index into the table.
87 if (SemaRef.checkArgCount(TheCall, 2))
88 return true;
89
90 QualType ElTy;
91 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
92 return true;
93
95 return true;
96
97 // If all is well, we set the type of TheCall to be the type of the
98 // element of the table.
99 // i.e. a table.get on an externref table has type externref,
100 // or whatever the type of the table element is.
101 TheCall->setType(ElTy);
102
103 return false;
104}
105
106/// Check that the first argumnet is a WebAssembly table, the second is
107/// an index to use as index into the table and the third is the reference
108/// type to set into the table.
110 if (SemaRef.checkArgCount(TheCall, 3))
111 return true;
112
113 QualType ElTy;
114 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
115 return true;
116
117 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1))
118 return true;
119
120 if (!getASTContext().hasSameType(ElTy, TheCall->getArg(2)->getType()))
121 return true;
122
123 return false;
124}
125
126/// Check that the argument is a WebAssembly table.
128 if (SemaRef.checkArgCount(TheCall, 1))
129 return true;
130
131 QualType ElTy;
132 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
133 return true;
134
135 return false;
136}
137
138/// Check that the first argument is a WebAssembly table, the second is the
139/// value to use for new elements (of a type matching the table type), the
140/// third value is an integer.
142 if (SemaRef.checkArgCount(TheCall, 3))
143 return true;
144
145 QualType ElTy;
146 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
147 return true;
148
149 Expr *NewElemArg = TheCall->getArg(1);
150 if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) {
151 return Diag(NewElemArg->getBeginLoc(),
152 diag::err_wasm_builtin_arg_must_match_table_element_type)
153 << 2 << 1 << NewElemArg->getSourceRange();
154 }
155
156 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 2))
157 return true;
158
159 return false;
160}
161
162/// Check that the first argument is a WebAssembly table, the second is an
163/// integer, the third is the value to use to fill the table (of a type
164/// matching the table type), and the fourth is an integer.
166 if (SemaRef.checkArgCount(TheCall, 4))
167 return true;
168
169 QualType ElTy;
170 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy))
171 return true;
172
173 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1))
174 return true;
175
176 Expr *NewElemArg = TheCall->getArg(2);
177 if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) {
178 return Diag(NewElemArg->getBeginLoc(),
179 diag::err_wasm_builtin_arg_must_match_table_element_type)
180 << 3 << 1 << NewElemArg->getSourceRange();
181 }
182
183 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 3))
184 return true;
185
186 return false;
187}
188
189/// Check that the first argument is a WebAssembly table, the second is also a
190/// WebAssembly table (of the same element type), and the third to fifth
191/// arguments are integers.
193 if (SemaRef.checkArgCount(TheCall, 5))
194 return true;
195
196 QualType XElTy;
197 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, XElTy))
198 return true;
199
200 QualType YElTy;
201 if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 1, YElTy))
202 return true;
203
204 Expr *TableYArg = TheCall->getArg(1);
205 if (!getASTContext().hasSameType(XElTy, YElTy)) {
206 return Diag(TableYArg->getBeginLoc(),
207 diag::err_wasm_builtin_arg_must_match_table_element_type)
208 << 2 << 1 << TableYArg->getSourceRange();
209 }
210
211 for (int I = 2; I <= 4; I++) {
212 if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, I))
213 return true;
214 }
215
216 return false;
217}
218
220 unsigned BuiltinID,
221 CallExpr *TheCall) {
222 switch (BuiltinID) {
223 case WebAssembly::BI__builtin_wasm_ref_null_extern:
224 return BuiltinWasmRefNullExtern(TheCall);
225 case WebAssembly::BI__builtin_wasm_ref_null_func:
226 return BuiltinWasmRefNullFunc(TheCall);
227 case WebAssembly::BI__builtin_wasm_table_get:
228 return BuiltinWasmTableGet(TheCall);
229 case WebAssembly::BI__builtin_wasm_table_set:
230 return BuiltinWasmTableSet(TheCall);
231 case WebAssembly::BI__builtin_wasm_table_size:
232 return BuiltinWasmTableSize(TheCall);
233 case WebAssembly::BI__builtin_wasm_table_grow:
234 return BuiltinWasmTableGrow(TheCall);
235 case WebAssembly::BI__builtin_wasm_table_fill:
236 return BuiltinWasmTableFill(TheCall);
237 case WebAssembly::BI__builtin_wasm_table_copy:
238 return BuiltinWasmTableCopy(TheCall);
239 }
240
241 return false;
242}
243
244WebAssemblyImportModuleAttr *
246 const WebAssemblyImportModuleAttr &AL) {
247 auto *FD = cast<FunctionDecl>(D);
248
249 if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
250 if (ExistingAttr->getImportModule() == AL.getImportModule())
251 return nullptr;
252 Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
253 << 0 << ExistingAttr->getImportModule() << AL.getImportModule();
254 Diag(AL.getLoc(), diag::note_previous_attribute);
255 return nullptr;
256 }
257 if (FD->hasBody()) {
258 Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
259 return nullptr;
260 }
261 return ::new (getASTContext())
262 WebAssemblyImportModuleAttr(getASTContext(), AL, AL.getImportModule());
263}
264
265WebAssemblyImportNameAttr *
266SemaWasm::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
267 auto *FD = cast<FunctionDecl>(D);
268
269 if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
270 if (ExistingAttr->getImportName() == AL.getImportName())
271 return nullptr;
272 Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import)
273 << 1 << ExistingAttr->getImportName() << AL.getImportName();
274 Diag(AL.getLoc(), diag::note_previous_attribute);
275 return nullptr;
276 }
277 if (FD->hasBody()) {
278 Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
279 return nullptr;
280 }
281 return ::new (getASTContext())
282 WebAssemblyImportNameAttr(getASTContext(), AL, AL.getImportName());
283}
284
286 const ParsedAttr &AL) {
287 auto *FD = cast<FunctionDecl>(D);
288
289 StringRef Str;
290 SourceLocation ArgLoc;
291 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
292 return;
293 if (FD->hasBody()) {
294 Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
295 return;
296 }
297
298 FD->addAttr(::new (getASTContext())
299 WebAssemblyImportModuleAttr(getASTContext(), AL, Str));
300}
301
303 auto *FD = cast<FunctionDecl>(D);
304
305 StringRef Str;
306 SourceLocation ArgLoc;
307 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
308 return;
309 if (FD->hasBody()) {
310 Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
311 return;
312 }
313
314 FD->addAttr(::new (getASTContext())
315 WebAssemblyImportNameAttr(getASTContext(), AL, Str));
316}
317
319 ASTContext &Context = getASTContext();
321 Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
323 return;
324 }
325
326 auto *FD = cast<FunctionDecl>(D);
327 if (FD->isThisDeclarationADefinition()) {
328 Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
329 return;
330 }
331
332 StringRef Str;
333 SourceLocation ArgLoc;
334 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
335 return;
336
337 D->addAttr(::new (Context) WebAssemblyExportNameAttr(Context, AL, Str));
338 D->addAttr(UsedAttr::CreateImplicit(Context));
339}
340
341} // namespace clang
Defines the clang::ASTContext interface.
Provides definitions for the various language-specific address spaces.
const Decl * D
Expr * E
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:187
SourceLocation getLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2830
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3021
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Expr.cpp:1638
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3008
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
void setType(QualType t)
Definition: Expr.h:143
QualType getType() const
Definition: Expr.h:142
ParsedAttr - Represents a syntactic attribute.
Definition: ParsedAttr.h:129
A (possibly-)qualified type.
Definition: Type.h:941
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: SemaBase.cpp:60
ASTContext & getASTContext() const
Definition: SemaBase.cpp:9
Sema & SemaRef
Definition: SemaBase.h:40
void handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaWasm.cpp:302
bool BuiltinWasmRefNullExtern(CallExpr *TheCall)
Definition: SemaWasm.cpp:54
bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition: SemaWasm.cpp:219
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:86
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:165
bool BuiltinWasmTableSize(CallExpr *TheCall)
Check that the argument is a WebAssembly table.
Definition: SemaWasm.cpp:127
void handleWebAssemblyImportModuleAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaWasm.cpp:285
bool BuiltinWasmRefNullFunc(CallExpr *TheCall)
Definition: SemaWasm.cpp:63
bool BuiltinWasmTableSet(CallExpr *TheCall)
Check that the first argumnet is a WebAssembly table, the second is an index to use as index into the...
Definition: SemaWasm.cpp:109
SemaWasm(Sema &S)
Definition: SemaWasm.cpp:25
void handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaWasm.cpp:318
WebAssemblyImportNameAttr * mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL)
Definition: SemaWasm.cpp:266
WebAssemblyImportModuleAttr * mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL)
Definition: SemaWasm.cpp:245
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:141
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:192
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:535
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
bool checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI, const Expr *E, StringRef &Str, SourceLocation *ArgLocation=nullptr)
Check if the argument E is a ASCII string literal.
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:326
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:338
Exposes information about the current target.
Definition: TargetInfo.h:218
The base class of the type hierarchy.
Definition: Type.h:1829
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8359
The JSON file list parser is used to communicate input to InstallAPI.
@ ExpectedFunction
Definition: ParsedAttr.h:1091
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:29
static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, unsigned ArgIndex)
Checks the argument at the given index is an integer.
Definition: SemaWasm.cpp:43
bool isFuncOrMethodForAttrSubject(const Decl *D)
isFuncOrMethodForAttrSubject - Return true if the given decl has function type (function or function-...
Definition: Attr.h:34