Skip to content

Commit aa3319f

Browse files
author
z1_cciauto
authored
merge main into amd-staging (llvm#3305)
2 parents 76a47eb + 03ef1cb commit aa3319f

File tree

137 files changed

+7516
-3702
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+7516
-3702
lines changed

clang/docs/OpenMPSupport.rst

Lines changed: 506 additions & 500 deletions
Large diffs are not rendered by default.

clang/include/clang/Basic/BuiltinsWebAssembly.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ TARGET_BUILTIN(__builtin_wasm_ref_is_null_extern, "ii", "nct", "reference-types"
199199
// return type.
200200
TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
201201

202+
// Check if the runtime type of a function pointer matches its static type. Used
203+
// to avoid "function signature mismatch" traps. Takes a function pointer, uses
204+
// table.get to look up the pointer in __indirect_function_table and then
205+
// ref.test to test the type.
206+
TARGET_BUILTIN(__builtin_wasm_test_function_pointer_signature, "i.", "nct", "gc")
207+
202208
// Table builtins
203209
TARGET_BUILTIN(__builtin_wasm_table_set, "viii", "t", "reference-types")
204210
TARGET_BUILTIN(__builtin_wasm_table_get, "iii", "t", "reference-types")

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7571,6 +7571,8 @@ def err_typecheck_illegal_increment_decrement : Error<
75717571
"cannot %select{decrement|increment}1 value of type %0">;
75727572
def err_typecheck_expect_int : Error<
75737573
"used type %0 where integer is required">;
7574+
def err_typecheck_expect_function_pointer
7575+
: Error<"used type %0 where function pointer is required">;
75747576
def err_typecheck_expect_hlsl_resource : Error<
75757577
"used type %0 where __hlsl_resource_t is required">;
75767578
def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
@@ -13202,6 +13204,10 @@ def err_wasm_builtin_arg_must_match_table_element_type : Error <
1320213204
"%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
1320313205
def err_wasm_builtin_arg_must_be_integer_type : Error <
1320413206
"%ordinal0 argument must be an integer">;
13207+
def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
13208+
: Error<"not supported for "
13209+
"function pointers with a reference type %select{return "
13210+
"value|parameter}0">;
1320513211

1320613212
// OpenACC diagnostics.
1320713213
def warn_acc_routine_unimplemented

clang/include/clang/Sema/SemaWasm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class SemaWasm : public SemaBase {
3737
bool BuiltinWasmTableGrow(CallExpr *TheCall);
3838
bool BuiltinWasmTableFill(CallExpr *TheCall);
3939
bool BuiltinWasmTableCopy(CallExpr *TheCall);
40+
bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall);
4041

4142
WebAssemblyImportNameAttr *
4243
mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);

clang/lib/Basic/Targets/WebAssembly.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
6464
.Case("mutable-globals", HasMutableGlobals)
6565
.Case("nontrapping-fptoint", HasNontrappingFPToInt)
6666
.Case("reference-types", HasReferenceTypes)
67+
.Case("gc", HasGC)
6768
.Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
6869
.Case("sign-ext", HasSignExt)
6970
.Case("simd128", SIMDLevel >= SIMD128)
@@ -106,6 +107,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
106107
Builder.defineMacro("__wasm_nontrapping_fptoint__");
107108
if (HasReferenceTypes)
108109
Builder.defineMacro("__wasm_reference_types__");
110+
if (HasGC)
111+
Builder.defineMacro("__wasm_gc__");
109112
if (SIMDLevel >= RelaxedSIMD)
110113
Builder.defineMacro("__wasm_relaxed_simd__");
111114
if (HasSignExt)
@@ -307,6 +310,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
307310
HasReferenceTypes = false;
308311
continue;
309312
}
313+
if (Feature == "+gc") {
314+
HasGC = true;
315+
continue;
316+
}
317+
if (Feature == "-gc") {
318+
HasGC = false;
319+
continue;
320+
}
310321
if (Feature == "+relaxed-simd") {
311322
SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
312323
continue;
@@ -353,6 +364,11 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
353364
return false;
354365
}
355366

367+
// gc implies reference-types
368+
if (HasGC) {
369+
HasReferenceTypes = true;
370+
}
371+
356372
// bulk-memory-opt is a subset of bulk-memory.
357373
if (HasBulkMemory) {
358374
HasBulkMemoryOpt = true;

clang/lib/Basic/Targets/WebAssembly.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
6969
bool HasMutableGlobals = false;
7070
bool HasNontrappingFPToInt = false;
7171
bool HasReferenceTypes = false;
72+
bool HasGC = false;
7273
bool HasSignExt = false;
7374
bool HasTailCall = false;
7475
bool HasWideArithmetic = false;

clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,98 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr(
357357
emitArrayInit(dest.getAddress(), arrayTy, e->getType(), e, args,
358358
arrayFiller);
359359
return;
360+
} else if (e->getType()->isVariableArrayType()) {
361+
cgf.cgm.errorNYI(e->getSourceRange(),
362+
"visitCXXParenListOrInitListExpr variable array type");
363+
return;
364+
}
365+
366+
if (e->getType()->isArrayType()) {
367+
cgf.cgm.errorNYI(e->getSourceRange(),
368+
"visitCXXParenListOrInitListExpr array type");
369+
return;
370+
}
371+
372+
assert(e->getType()->isRecordType() && "Only support structs/unions here!");
373+
374+
// Do struct initialization; this code just sets each individual member
375+
// to the approprate value. This makes bitfield support automatic;
376+
// the disadvantage is that the generated code is more difficult for
377+
// the optimizer, especially with bitfields.
378+
unsigned numInitElements = args.size();
379+
RecordDecl *record = e->getType()->castAs<RecordType>()->getDecl();
380+
381+
// We'll need to enter cleanup scopes in case any of the element
382+
// initializers throws an exception.
383+
assert(!cir::MissingFeatures::requiresCleanups());
384+
385+
unsigned curInitIndex = 0;
386+
387+
// Emit initialization of base classes.
388+
if (auto *cxxrd = dyn_cast<CXXRecordDecl>(record)) {
389+
assert(numInitElements >= cxxrd->getNumBases() &&
390+
"missing initializer for base class");
391+
if (cxxrd->getNumBases() > 0) {
392+
cgf.cgm.errorNYI(e->getSourceRange(),
393+
"visitCXXParenListOrInitListExpr base class init");
394+
return;
395+
}
396+
}
397+
398+
LValue destLV = cgf.makeAddrLValue(dest.getAddress(), e->getType());
399+
400+
if (record->isUnion()) {
401+
cgf.cgm.errorNYI(e->getSourceRange(),
402+
"visitCXXParenListOrInitListExpr union type");
403+
return;
360404
}
361405

362-
cgf.cgm.errorNYI(
363-
"visitCXXParenListOrInitListExpr Record or VariableSizeArray type");
406+
// Here we iterate over the fields; this makes it simpler to both
407+
// default-initialize fields and skip over unnamed fields.
408+
for (const FieldDecl *field : record->fields()) {
409+
// We're done once we hit the flexible array member.
410+
if (field->getType()->isIncompleteArrayType())
411+
break;
412+
413+
// Always skip anonymous bitfields.
414+
if (field->isUnnamedBitField())
415+
continue;
416+
417+
// We're done if we reach the end of the explicit initializers, we
418+
// have a zeroed object, and the rest of the fields are
419+
// zero-initializable.
420+
if (curInitIndex == numInitElements && dest.isZeroed() &&
421+
cgf.getTypes().isZeroInitializable(e->getType()))
422+
break;
423+
LValue lv =
424+
cgf.emitLValueForFieldInitialization(destLV, field, field->getName());
425+
// We never generate write-barriers for initialized fields.
426+
assert(!cir::MissingFeatures::setNonGC());
427+
428+
if (curInitIndex < numInitElements) {
429+
// Store the initializer into the field.
430+
CIRGenFunction::SourceLocRAIIObject loc{
431+
cgf, cgf.getLoc(record->getSourceRange())};
432+
emitInitializationToLValue(args[curInitIndex++], lv);
433+
} else {
434+
// We're out of initializers; default-initialize to null
435+
emitNullInitializationToLValue(cgf.getLoc(e->getSourceRange()), lv);
436+
}
437+
438+
// Push a destructor if necessary.
439+
// FIXME: if we have an array of structures, all explicitly
440+
// initialized, we can end up pushing a linear number of cleanups.
441+
if (QualType::DestructionKind dtorKind =
442+
field->getType().isDestructedType()) {
443+
cgf.cgm.errorNYI(e->getSourceRange(),
444+
"visitCXXParenListOrInitListExpr destructor");
445+
return;
446+
}
447+
448+
// From classic codegen, maybe not useful for CIR:
449+
// If the GEP didn't get used because of a dead zero init or something
450+
// else, clean it up for -O0 builds and general tidiness.
451+
}
364452
}
365453

366454
// TODO(cir): This could be shared with classic codegen.

clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212

1313
#include "CGBuiltin.h"
1414
#include "clang/Basic/TargetBuiltins.h"
15+
#include "llvm/ADT/APInt.h"
16+
#include "llvm/IR/Constants.h"
1517
#include "llvm/IR/IntrinsicsWebAssembly.h"
18+
#include "llvm/Support/ErrorHandling.h"
1619

1720
using namespace clang;
1821
using namespace CodeGen;
@@ -218,6 +221,64 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
218221
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
219222
return Builder.CreateCall(Callee);
220223
}
224+
case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: {
225+
Value *FuncRef = EmitScalarExpr(E->getArg(0));
226+
227+
// Get the function type from the argument's static type
228+
QualType ArgType = E->getArg(0)->getType();
229+
const PointerType *PtrTy = ArgType->getAs<PointerType>();
230+
assert(PtrTy && "Sema should have ensured this is a function pointer");
231+
232+
const FunctionType *FuncTy = PtrTy->getPointeeType()->getAs<FunctionType>();
233+
assert(FuncTy && "Sema should have ensured this is a function pointer");
234+
235+
// In the llvm IR, we won't have access any more to the type of the function
236+
// pointer so we need to insert this type information somehow. The
237+
// @llvm.wasm.ref.test.func takes varargs arguments whose values are unused
238+
// to indicate the type of the function to test for. See the test here:
239+
// llvm/test/CodeGen/WebAssembly/ref-test-func.ll
240+
//
241+
// The format is: first we include the return types (since this is a C
242+
// function pointer, there will be 0 or one of these) then a token type to
243+
// indicate the boundary between return types and param types, then the
244+
// param types.
245+
246+
llvm::FunctionType *LLVMFuncTy =
247+
cast<llvm::FunctionType>(ConvertType(QualType(FuncTy, 0)));
248+
249+
unsigned NParams = LLVMFuncTy->getNumParams();
250+
std::vector<Value *> Args;
251+
Args.reserve(NParams + 3);
252+
// The only real argument is the FuncRef
253+
Args.push_back(FuncRef);
254+
255+
// Add the type information
256+
auto addType = [this, &Args](llvm::Type *T) {
257+
if (T->isVoidTy()) {
258+
// Do nothing
259+
} else if (T->isFloatingPointTy()) {
260+
Args.push_back(ConstantFP::get(T, 0));
261+
} else if (T->isIntegerTy()) {
262+
Args.push_back(ConstantInt::get(T, 0));
263+
} else if (T->isPointerTy()) {
264+
Args.push_back(ConstantPointerNull::get(llvm::PointerType::get(
265+
getLLVMContext(), T->getPointerAddressSpace())));
266+
} else {
267+
// TODO: Handle reference types. For now, we reject them in Sema.
268+
llvm_unreachable("Unhandled type");
269+
}
270+
};
271+
272+
addType(LLVMFuncTy->getReturnType());
273+
// The token type indicates the boundary between return types and param
274+
// types.
275+
Args.push_back(PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext())));
276+
for (unsigned i = 0; i < NParams; i++) {
277+
addType(LLVMFuncTy->getParamType(i));
278+
}
279+
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func);
280+
return Builder.CreateCall(Callee, Args);
281+
}
221282
case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
222283
Value *Src = EmitScalarExpr(E->getArg(0));
223284
Value *Indices = EmitScalarExpr(E->getArg(1));

clang/lib/Sema/SemaWasm.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,53 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
227227
return false;
228228
}
229229

230+
bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
231+
if (SemaRef.checkArgCount(TheCall, 1))
232+
return true;
233+
234+
Expr *FuncPtrArg = TheCall->getArg(0);
235+
QualType ArgType = FuncPtrArg->getType();
236+
237+
// Check that the argument is a function pointer
238+
const PointerType *PtrTy = ArgType->getAs<PointerType>();
239+
if (!PtrTy) {
240+
return Diag(FuncPtrArg->getBeginLoc(),
241+
diag::err_typecheck_expect_function_pointer)
242+
<< ArgType << FuncPtrArg->getSourceRange();
243+
}
244+
245+
const FunctionProtoType *FuncTy =
246+
PtrTy->getPointeeType()->getAs<FunctionProtoType>();
247+
if (!FuncTy) {
248+
return Diag(FuncPtrArg->getBeginLoc(),
249+
diag::err_typecheck_expect_function_pointer)
250+
<< ArgType << FuncPtrArg->getSourceRange();
251+
}
252+
253+
// Check that the function pointer doesn't use reference types
254+
if (FuncTy->getReturnType().isWebAssemblyReferenceType()) {
255+
return Diag(
256+
FuncPtrArg->getBeginLoc(),
257+
diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
258+
<< 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
259+
}
260+
auto NParams = FuncTy->getNumParams();
261+
for (unsigned I = 0; I < NParams; I++) {
262+
if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) {
263+
return Diag(
264+
FuncPtrArg->getBeginLoc(),
265+
diag::
266+
err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
267+
<< 1 << FuncPtrArg->getSourceRange();
268+
}
269+
}
270+
271+
// Set return type to int (the result of the test)
272+
TheCall->setType(getASTContext().IntTy);
273+
274+
return false;
275+
}
276+
230277
bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
231278
unsigned BuiltinID,
232279
CallExpr *TheCall) {
@@ -249,6 +296,8 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
249296
return BuiltinWasmTableFill(TheCall);
250297
case WebAssembly::BI__builtin_wasm_table_copy:
251298
return BuiltinWasmTableCopy(TheCall);
299+
case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
300+
return BuiltinWasmTestFunctionPointerSignature(TheCall);
252301
}
253302

254303
return false;

0 commit comments

Comments
 (0)