aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ByteCode/DynamicAllocator.cpp4
-rw-r--r--clang/lib/AST/ByteCode/DynamicAllocator.h5
-rw-r--r--clang/lib/AST/ByteCode/EvalEmitter.cpp2
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp157
-rw-r--r--clang/lib/AST/ByteCode/Interp.h49
-rw-r--r--clang/lib/AST/ByteCode/InterpBlock.h4
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp4
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.cpp4
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.h1
-rw-r--r--clang/lib/AST/ByteCode/InterpState.cpp14
-rw-r--r--clang/lib/AST/ByteCode/MemberPointer.h6
-rw-r--r--clang/lib/AST/Type.cpp9
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCleanup.cpp71
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCleanup.h43
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenDecl.cpp6
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp8
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.cpp8
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp18
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.h2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenStmt.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/EHScopeStack.h101
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRDialect.cpp21
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp5
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.cpp9
-rw-r--r--clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp29
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp85
-rw-r--r--clang/lib/Headers/avx512fintrin.h101
-rw-r--r--clang/lib/Headers/avxintrin.h60
-rw-r--r--clang/lib/Headers/cpuid.h5
-rw-r--r--clang/lib/Interpreter/RemoteJITUtils.cpp31
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp20
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp2
-rw-r--r--clang/lib/Sema/SemaWasm.cpp36
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp74
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h54
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp83
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h59
38 files changed, 701 insertions, 503 deletions
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index 9b8b664..bbef941 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -128,7 +128,7 @@ bool DynamicAllocator::deallocate(const Expr *Source,
return false;
auto &Site = It->second;
- assert(Site.size() > 0);
+ assert(!Site.empty());
// Find the Block to delete.
auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
@@ -144,7 +144,7 @@ bool DynamicAllocator::deallocate(const Expr *Source,
S.deallocate(B);
Site.Allocations.erase(AllocIt);
- if (Site.size() == 0)
+ if (Site.empty())
AllocationSites.erase(It);
return true;
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h
index cff09bf..cba5e34 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.h
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.h
@@ -55,6 +55,7 @@ private:
}
size_t size() const { return Allocations.size(); }
+ bool empty() const { return Allocations.empty(); }
};
public:
@@ -65,8 +66,6 @@ public:
void cleanup();
- unsigned getNumAllocations() const { return AllocationSites.size(); }
-
/// Allocate ONE element of the given descriptor.
Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm);
/// Allocate \p NumElements primitive elements of the given type.
@@ -96,6 +95,8 @@ public:
return llvm::make_range(AllocationSites.begin(), AllocationSites.end());
}
+ bool hasAllocations() const { return !AllocationSites.empty(); }
+
private:
llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 976b7c0..9ed61c7 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -292,7 +292,7 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
Block *B = getLocal(I);
- if (!CheckLocalLoad(S, OpPC, Pointer(B)))
+ if (!CheckLocalLoad(S, OpPC, B))
return false;
S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index eb4e480..bc14bd3d 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -211,25 +211,26 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
S.Note(VD->getLocation(), diag::note_declared_at);
}
-static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
AccessKinds AK) {
- if (auto ID = Ptr.getDeclID()) {
- if (!Ptr.isStaticTemporary())
+ if (B->getDeclID()) {
+ if (!(B->isStatic() && B->isTemporary()))
return true;
const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
- Ptr.getDeclDesc()->asExpr());
+ B->getDescriptor()->asExpr());
if (!MTE)
return true;
// FIXME(perf): Since we do this check on every Load from a static
// temporary, it might make sense to cache the value of the
// isUsableInConstantExpressions call.
- if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&
- Ptr.block()->getEvalID() != S.Ctx.getEvalID()) {
+ if (B->getEvalID() != S.Ctx.getEvalID() &&
+ !MTE->isUsableInConstantExpressions(S.getASTContext())) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
- S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ S.Note(B->getDescriptor()->getLocation(),
+ diag::note_constexpr_temporary_here);
return false;
}
}
@@ -658,17 +659,19 @@ static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK) {
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
assert(Ptr.isLive());
+ assert(!Ptr.isInitialized());
+ return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.getDeclDesc(), AK);
+}
- if (Ptr.isInitialized())
- return true;
-
- if (Ptr.isExtern() && S.checkingPotentialConstantExpression())
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
+ const Descriptor *Desc, AccessKinds AK) {
+ if (Extern && S.checkingPotentialConstantExpression())
return false;
- if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
+ if (const auto *VD = Desc->asVarDecl();
VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
if (VD == S.EvaluatingDecl &&
@@ -703,9 +706,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,
AccessKinds AK) {
- if (Ptr.getLifetime() == Lifetime::Started)
+ if (LT == Lifetime::Started)
return true;
if (!S.checkingPotentialConstantExpression()) {
@@ -715,11 +718,11 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!Ptr.isWeak())
+static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {
+ if (!B->isWeak())
return true;
- const auto *VD = Ptr.getDeclDesc()->asVarDecl();
+ const auto *VD = B->getDescriptor()->asVarDecl();
assert(VD);
S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
<< VD;
@@ -732,32 +735,56 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
// ones removed that are impossible on primitive global values.
// For example, since those can't be members of structs, they also can't
// be mutable.
-bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckConstant(S, OpPC, Ptr))
+bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
+ const auto &Desc =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());
+ if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
+ if (!CheckConstant(S, OpPC, B->getDescriptor()))
return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
+ if (!CheckDummy(S, OpPC, B, AK_Read))
return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
+ if (Desc.InitState != GlobalInitState::Initialized)
+ return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
+ AK_Read);
+ if (!CheckTemporary(S, OpPC, B, AK_Read))
return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (!CheckWeak(S, OpPC, B))
return false;
- if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
+ if (B->getDescriptor()->IsVolatile) {
+ if (!S.getLangOpts().CPlusPlus)
+ return Invalid(S, OpPC);
+
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
+ S.FFDiag(S.Current->getLocation(OpPC),
+ diag::note_constexpr_access_volatile_obj, 1)
+ << AK_Read << 1 << D;
+ S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
return false;
+ }
return true;
}
// Similarly, for local loads.
-bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
+bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
+ assert(!B->isExtern());
+ const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());
+ if (!CheckLifetime(S, OpPC, Desc.LifeState, AK_Read))
+ return false;
+ if (!Desc.IsInitialized)
+ return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B->getDescriptor(),
+ AK_Read);
+ if (B->getDescriptor()->IsVolatile) {
+ if (!S.getLangOpts().CPlusPlus)
+ return Invalid(S, OpPC);
+
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
+ S.FFDiag(S.Current->getLocation(OpPC),
+ diag::note_constexpr_access_volatile_obj, 1)
+ << AK_Read << 1 << D;
+ S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
return false;
+ }
return true;
}
@@ -769,19 +796,19 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK))
return false;
if (!CheckRange(S, OpPC, Ptr, AK))
return false;
if (!CheckActive(S, OpPC, Ptr, AK))
return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK))
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK))
return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK))
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK);
+ if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK))
return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK))
- return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block()))
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
@@ -798,7 +825,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Read))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
@@ -806,13 +833,13 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return false;
if (!CheckActive(S, OpPC, Ptr, AK_Read))
return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read))
return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read);
+ if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK_Read))
return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block()))
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
@@ -822,9 +849,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Assign))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Assign))
return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK_Assign))
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
@@ -1098,12 +1125,11 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
return diagnoseUnknownDecl(S, OpPC, D);
}
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK) {
- if (!Ptr.isDummy())
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
+ const Descriptor *Desc = B->getDescriptor();
+ if (!Desc->isDummy())
return true;
- const Descriptor *Desc = Ptr.getDeclDesc();
const ValueDecl *D = Desc->asValueDecl();
if (!D)
return false;
@@ -1426,7 +1452,7 @@ static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
return false;
@@ -1620,8 +1646,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
- const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
- DynamicDecl, StaticDecl, InitialFunction);
+ const CXXMethodDecl *Overrider;
+
+ if (StaticDecl != DynamicDecl) {
+ if (!DynamicDecl->isDerivedFrom(StaticDecl))
+ return false;
+ Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
+ InitialFunction);
+
+ } else {
+ Overrider = InitialFunction;
+ }
if (Overrider != InitialFunction) {
// DR1872: An instantiated virtual constexpr function can't be called in a
@@ -1749,7 +1784,7 @@ static void startLifetimeRecurse(const Pointer &Ptr) {
bool StartLifetime(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.peek<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
startLifetimeRecurse(Ptr.narrow());
return true;
@@ -1780,7 +1815,7 @@ static void endLifetimeRecurse(const Pointer &Ptr) {
/// Ends the lifetime of the peek'd pointer.
bool EndLifetime(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.peek<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
endLifetimeRecurse(Ptr.narrow());
return true;
@@ -1789,7 +1824,7 @@ bool EndLifetime(InterpState &S, CodePtr OpPC) {
/// Ends the lifetime of the pop'd pointer.
bool EndLifetimePop(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.pop<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
endLifetimeRecurse(Ptr.narrow());
return true;
@@ -1804,16 +1839,16 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
// Similar to CheckStore(), but with the additional CheckTemporary() call and
// the AccessKinds are different.
- if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
return false;
if (!CheckLive(S, OpPC, Ptr, AK_Construct))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Construct))
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK_Construct))
return false;
// CheckLifetime for this and all base pointers.
for (Pointer P = Ptr;;) {
- if (!CheckLifetime(S, OpPC, P, AK_Construct))
+ if (!CheckLifetime(S, OpPC, P.getLifetime(), AK_Construct))
return false;
if (P.isRoot())
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 8a28106..0d3f492 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -51,8 +51,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK);
/// Checks if a pointer is a dummy pointer.
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
/// Checks if a pointer is null.
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
@@ -89,11 +88,14 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK = AK_Read);
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
+ const Descriptor *Desc, AccessKinds AK);
+
/// Checks a direct load of a primitive value from a global or local variable.
-bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
+bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);
/// Checks if a value can be stored in a block.
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
@@ -1351,10 +1353,10 @@ inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.Current->getLocalPointer(I);
- if (!CheckLocalLoad(S, OpPC, Ptr))
+ const Block *B = S.Current->getLocalBlock(I);
+ if (!CheckLocalLoad(S, OpPC, B))
return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ S.Stk.push<T>(B->deref<T>());
return true;
}
@@ -1465,22 +1467,26 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.P.getPtrGlobal(I);
+ const Block *B = S.P.getGlobal(I);
- if (!CheckGlobalLoad(S, OpPC, Ptr))
+ if (!CheckGlobalLoad(S, OpPC, B))
return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ S.Stk.push<T>(B->deref<T>());
return true;
}
/// Same as GetGlobal, but without the checks.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.P.getPtrGlobal(I);
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ const Block *B = S.P.getGlobal(I);
+ const auto &Desc =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());
+ if (Desc.InitState != GlobalInitState::Initialized)
+ return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
+ AK_Read);
+
+ S.Stk.push<T>(B->deref<T>());
return true;
}
@@ -2351,8 +2357,8 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
- return false;
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment);
return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
}
@@ -2360,8 +2366,8 @@ static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
- return false;
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement);
return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
}
@@ -3195,6 +3201,9 @@ inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
const auto &MP = S.Stk.pop<MemberPointer>();
+ if (!MP.isBaseCastPossible())
+ return false;
+
S.Stk.push<Pointer>(MP.getBase());
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h
index 5162223..07194d6 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -103,6 +103,10 @@ public:
return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
}
+ template <typename T> T deref() const {
+ return *reinterpret_cast<const T *>(data());
+ }
+
/// Invokes the constructor.
void invokeCtor() {
assert(!IsInitialized);
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index f908d02..c835bd4 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -276,7 +276,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
if (!CheckLive(S, OpPC, StrPtr, AK_Read))
return false;
- if (!CheckDummy(S, OpPC, StrPtr, AK_Read))
+ if (!CheckDummy(S, OpPC, StrPtr.block(), AK_Read))
return false;
assert(StrPtr.getFieldDesc()->isPrimitiveArray());
@@ -2232,7 +2232,7 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
return false;
}
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 9342192..f2eac86 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -231,6 +231,10 @@ Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
return Pointer(localBlock(Offset));
}
+Block *InterpFrame::getLocalBlock(unsigned Offset) const {
+ return localBlock(Offset);
+}
+
Pointer InterpFrame::getParamPointer(unsigned Off) {
// Return the block if it was created previously.
if (auto Pt = Params.find(Off); Pt != Params.end())
diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h
index cfebe93..4be5391 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -86,6 +86,7 @@ public:
/// Returns a pointer to a local variables.
Pointer getLocalPointer(unsigned Offset) const;
+ Block *getLocalBlock(unsigned Offset) const;
/// Returns the value of an argument.
template <typename T> const T &getParam(unsigned Offset) const {
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index a06b125..49c9b54 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -76,9 +76,6 @@ bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
void InterpState::deallocate(Block *B) {
assert(B);
- const Descriptor *Desc = B->getDescriptor();
- assert(Desc);
-
// The block might have a pointer saved in a field in its data
// that points to the block itself. We call the dtor first,
// which will destroy all the data but leave InlineDescriptors
@@ -95,7 +92,7 @@ void InterpState::deallocate(Block *B) {
auto *D = new (Memory) DeadBlock(DeadBlocks, B);
// Since the block doesn't hold any actual data anymore, we can just
// memcpy() everything over.
- std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize());
+ std::memcpy(D->rawData(), B->rawData(), B->getSize());
D->B.IsInitialized = B->IsInitialized;
// We moved the contents over to the DeadBlock.
@@ -104,15 +101,14 @@ void InterpState::deallocate(Block *B) {
}
bool InterpState::maybeDiagnoseDanglingAllocations() {
- bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0);
+ bool NoAllocationsLeft = !Alloc.hasAllocations();
if (!checkingPotentialConstantExpression()) {
- for (const auto &It : Alloc.allocation_sites()) {
- assert(It.second.size() > 0);
+ for (const auto &[Source, Site] : Alloc.allocation_sites()) {
+ assert(!Site.empty());
- const Expr *Source = It.first;
CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
- << (It.second.size() - 1) << Source->getSourceRange();
+ << (Site.size() - 1) << Source->getSourceRange();
}
}
// Keep evaluating before C++20, since the CXXNewExpr wasn't valid there
diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h
index b17ce25..8dd75ca 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -51,6 +51,12 @@ public:
FunctionPointer toFunctionPointer(const Context &Ctx) const;
+ bool isBaseCastPossible() const {
+ if (PtrOffset < 0)
+ return true;
+ return static_cast<uint64_t>(PtrOffset) <= Base.getByteOffset();
+ }
+
Pointer getBase() const {
if (PtrOffset < 0)
return Base.atField(-PtrOffset);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 141edc8..03d7413 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5246,6 +5246,15 @@ bool Type::isHLSLResourceRecord() const {
return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr;
}
+bool Type::isHLSLResourceRecordArray() const {
+ const Type *Ty = getUnqualifiedDesugaredType();
+ if (!Ty->isArrayType())
+ return false;
+ while (isa<ConstantArrayType>(Ty))
+ Ty = Ty->getArrayElementTypeNoTypeQual();
+ return Ty->isHLSLResourceRecord();
+}
+
bool Type::isHLSLIntangibleType() const {
const Type *Ty = getUnqualifiedDesugaredType();
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index be21ce9..b8663eb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -16,6 +16,7 @@
//
//===----------------------------------------------------------------------===//
+#include "CIRGenCleanup.h"
#include "CIRGenFunction.h"
#include "clang/CIR/MissingFeatures.h"
@@ -33,6 +34,52 @@ using namespace clang::CIRGen;
void EHScopeStack::Cleanup::anchor() {}
+/// Push an entry of the given size onto this protected-scope stack.
+char *EHScopeStack::allocate(size_t size) {
+ size = llvm::alignTo(size, ScopeStackAlignment);
+ if (!startOfBuffer) {
+ unsigned capacity = llvm::PowerOf2Ceil(std::max(size, 1024ul));
+ startOfBuffer = std::make_unique<char[]>(capacity);
+ startOfData = endOfBuffer = startOfBuffer.get() + capacity;
+ } else if (static_cast<size_t>(startOfData - startOfBuffer.get()) < size) {
+ unsigned currentCapacity = endOfBuffer - startOfBuffer.get();
+ unsigned usedCapacity =
+ currentCapacity - (startOfData - startOfBuffer.get());
+ unsigned requiredCapacity = usedCapacity + size;
+ // We know from the 'else if' condition that requiredCapacity is greater
+ // than currentCapacity.
+ unsigned newCapacity = llvm::PowerOf2Ceil(requiredCapacity);
+
+ std::unique_ptr<char[]> newStartOfBuffer =
+ std::make_unique<char[]>(newCapacity);
+ char *newEndOfBuffer = newStartOfBuffer.get() + newCapacity;
+ char *newStartOfData = newEndOfBuffer - usedCapacity;
+ memcpy(newStartOfData, startOfData, usedCapacity);
+ startOfBuffer.swap(newStartOfBuffer);
+ endOfBuffer = newEndOfBuffer;
+ startOfData = newStartOfData;
+ }
+
+ assert(startOfBuffer.get() + size <= startOfData);
+ startOfData -= size;
+ return startOfData;
+}
+
+void EHScopeStack::deallocate(size_t size) {
+ startOfData += llvm::alignTo(size, ScopeStackAlignment);
+}
+
+void *EHScopeStack::pushCleanup(CleanupKind kind, size_t size) {
+ char *buffer = allocate(size);
+
+ // When the full implementation is upstreamed, this will allocate
+ // extra memory for and construct a wrapper object that is used to
+ // manage the cleanup generation.
+ assert(!cir::MissingFeatures::ehCleanupScope());
+
+ return buffer;
+}
+
static mlir::Block *getCurCleanupBlock(CIRGenFunction &cgf) {
mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder());
mlir::Block *cleanup =
@@ -44,26 +91,34 @@ static mlir::Block *getCurCleanupBlock(CIRGenFunction &cgf) {
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
void CIRGenFunction::popCleanupBlock() {
- assert(!ehStack.cleanupStack.empty() && "cleanup stack is empty!");
+ assert(!ehStack.empty() && "cleanup stack is empty!");
+
+ // The memory for the cleanup continues to be owned by the EHScopeStack
+ // allocator, so we just destroy the object rather than attempting to
+ // free it.
+ EHScopeStack::Cleanup &cleanup = *ehStack.begin();
+
+ // The eventual implementation here will use the EHCleanupScope helper class.
+ assert(!cir::MissingFeatures::ehCleanupScope());
+
mlir::OpBuilder::InsertionGuard guard(builder);
- std::unique_ptr<EHScopeStack::Cleanup> cleanup =
- ehStack.cleanupStack.pop_back_val();
assert(!cir::MissingFeatures::ehCleanupFlags());
mlir::Block *cleanupEntry = getCurCleanupBlock(*this);
builder.setInsertionPointToEnd(cleanupEntry);
- cleanup->emit(*this);
+ cleanup.emit(*this);
+
+ ehStack.deallocate(cleanup.getSize());
}
/// Pops cleanup blocks until the given savepoint is reached.
-void CIRGenFunction::popCleanupBlocks(size_t oldCleanupStackDepth) {
+void CIRGenFunction::popCleanupBlocks(
+ EHScopeStack::stable_iterator oldCleanupStackDepth) {
assert(!cir::MissingFeatures::ehstackBranches());
- assert(ehStack.getStackDepth() >= oldCleanupStackDepth);
-
// Pop cleanup blocks until we reach the base stack depth for the
// current scope.
- while (ehStack.getStackDepth() > oldCleanupStackDepth) {
+ while (ehStack.stable_begin() != oldCleanupStackDepth) {
popCleanupBlock();
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
new file mode 100644
index 0000000..7361c8c
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes support the generation of CIR for cleanups, initially based
+// on LLVM IR cleanup handling, but ought to change as CIR evolves.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
+#define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
+
+#include "EHScopeStack.h"
+
+namespace clang::CIRGen {
+
+/// A non-stable pointer into the scope stack.
+class EHScopeStack::iterator {
+ char *ptr = nullptr;
+
+ friend class EHScopeStack;
+ explicit iterator(char *ptr) : ptr(ptr) {}
+
+public:
+ iterator() = default;
+
+ EHScopeStack::Cleanup *get() const {
+ return reinterpret_cast<EHScopeStack::Cleanup *>(ptr);
+ }
+
+ EHScopeStack::Cleanup &operator*() const { return *get(); }
+};
+
+inline EHScopeStack::iterator EHScopeStack::begin() const {
+ return iterator(startOfData);
+}
+
+} // namespace clang::CIRGen
+#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 78d375c..715d101 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -667,6 +667,12 @@ struct DestroyObject final : EHScopeStack::Cleanup {
void emit(CIRGenFunction &cgf) override {
cgf.emitDestroy(addr, type, destroyer);
}
+
+ // This is a placeholder until EHCleanupScope is implemented.
+ size_t getSize() const override {
+ assert(!cir::MissingFeatures::ehCleanupScope());
+ return sizeof(DestroyObject);
+ }
};
} // namespace
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index c22cf60..cba06a1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -171,6 +171,10 @@ public:
mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) {
return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub);
}
+
+ mlir::Value VisitBinMulAssign(const CompoundAssignOperator *e) {
+ return emitCompoundAssign(e, &ComplexExprEmitter::emitBinMul);
+ }
};
} // namespace
@@ -776,7 +780,7 @@ getComplexRangeAttr(LangOptions::ComplexRangeKind range) {
case LangOptions::CX_Basic:
return cir::ComplexRangeKind::Basic;
case LangOptions::CX_None:
- // The default value for ComplexRangeKind is Full is no option is selected
+ // The default value for ComplexRangeKind is Full if no option is selected
return cir::ComplexRangeKind::Full;
}
}
@@ -813,7 +817,7 @@ using CompoundFunc =
static CompoundFunc getComplexOp(BinaryOperatorKind op) {
switch (op) {
case BO_MulAssign:
- llvm_unreachable("getComplexOp: BO_MulAssign");
+ return &ComplexExprEmitter::emitBinMul;
case BO_DivAssign:
llvm_unreachable("getComplexOp: BO_DivAssign");
case BO_SubAssign:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index e93dc0b..dedd01c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -28,8 +28,6 @@ CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,
bool suppressNewContext)
: CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {
ehStack.setCGF(this);
- currentCleanupStackDepth = 0;
- assert(ehStack.getStackDepth() == 0);
}
CIRGenFunction::~CIRGenFunction() {}
@@ -409,6 +407,8 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
curFuncDecl = d->getNonClosureContext();
+ prologueCleanupDepth = ehStack.stable_begin();
+
mlir::Block *entryBB = &fn.getBlocks().front();
builder.setInsertionPointToStart(entryBB);
@@ -475,11 +475,11 @@ void CIRGenFunction::finishFunction(SourceLocation endLoc) {
// important to do this before we enter the return block or return
// edges will be *really* confused.
// TODO(cir): Use prologueCleanupDepth here.
- bool hasCleanups = ehStack.getStackDepth() != currentCleanupStackDepth;
+ bool hasCleanups = ehStack.stable_begin() != prologueCleanupDepth;
if (hasCleanups) {
assert(!cir::MissingFeatures::generateDebugInfo());
// FIXME(cir): should we clearInsertionPoint? breaks many testcases
- popCleanupBlocks(currentCleanupStackDepth);
+ popCleanupBlocks(prologueCleanupDepth);
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 2e60cfc..bdbc77c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -601,9 +601,13 @@ public:
FunctionArgList args, clang::SourceLocation loc,
clang::SourceLocation startLoc);
+ /// The cleanup depth enclosing all the cleanups associated with the
+ /// parameters.
+ EHScopeStack::stable_iterator prologueCleanupDepth;
+
/// Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added.
- void popCleanupBlocks(size_t oldCleanupStackDepth);
+ void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth);
void popCleanupBlock();
/// Push a cleanup to be run at the end of the current full-expression. Safe
@@ -622,7 +626,7 @@ public:
/// Enters a new scope for capturing cleanups, all of which
/// will be executed once the scope is exited.
class RunCleanupsScope {
- size_t cleanupStackDepth, oldCleanupStackDepth;
+ EHScopeStack::stable_iterator cleanupStackDepth, oldCleanupStackDepth;
protected:
bool performCleanup;
@@ -638,7 +642,7 @@ public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CIRGenFunction &cgf)
: performCleanup(true), cgf(cgf) {
- cleanupStackDepth = cgf.ehStack.getStackDepth();
+ cleanupStackDepth = cgf.ehStack.stable_begin();
oldCleanupStackDepth = cgf.currentCleanupStackDepth;
cgf.currentCleanupStackDepth = cleanupStackDepth;
}
@@ -663,7 +667,7 @@ public:
};
// Cleanup stack depth of the RunCleanupsScope that was pushed most recently.
- size_t currentCleanupStackDepth;
+ EHScopeStack::stable_iterator currentCleanupStackDepth = ehStack.stable_end();
public:
/// Represents a scope, including function bodies, compound statements, and
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 425250d..ff6d293 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1365,6 +1365,21 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
assert(!cir::MissingFeatures::generateDebugInfo());
assert(!cir::MissingFeatures::cxxRecordStaticMembers());
break;
+
+ case Decl::FileScopeAsm:
+ // File-scope asm is ignored during device-side CUDA compilation.
+ if (langOpts.CUDA && langOpts.CUDAIsDevice)
+ break;
+ // File-scope asm is ignored during device-side OpenMP compilation.
+ if (langOpts.OpenMPIsTargetDevice)
+ break;
+ // File-scope asm is ignored during device-side SYCL compilation.
+ if (langOpts.SYCLIsDevice)
+ break;
+ auto *file_asm = cast<FileScopeAsmDecl>(decl);
+ std::string line = file_asm->getAsmString();
+ globalScopeAsm.push_back(builder.getStringAttr(line));
+ break;
}
}
@@ -1978,6 +1993,9 @@ void CIRGenModule::release() {
emitDeferred();
applyReplacements();
+ theModule->setAttr(cir::CIRDialect::getModuleLevelAsmAttrName(),
+ builder.getArrayAttr(globalScopeAsm));
+
// There's a lot of code that is not implemented yet.
assert(!cir::MissingFeatures::cgmRelease());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 5d07d38..163a0fc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -90,6 +90,8 @@ private:
/// for FunctionDecls's.
CIRGenFunction *curCGF = nullptr;
+ llvm::SmallVector<mlir::Attribute> globalScopeAsm;
+
public:
mlir::ModuleOp getModule() const { return theModule; }
CIRGenBuilderTy &getBuilder() { return builder; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 50642e7..332babd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -412,7 +412,7 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
// This should emit a branch through the cleanup block if one exists.
builder.create<cir::BrOp>(loc, retBlock);
- if (ehStack.getStackDepth() != currentCleanupStackDepth)
+ if (ehStack.stable_begin() != currentCleanupStackDepth)
cgm.errorNYI(s.getSourceRange(), "return with cleanup stack");
builder.createBlock(builder.getBlock()->getParent());
diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h b/clang/lib/CIR/CodeGen/EHScopeStack.h
index 22750ac..47478f6 100644
--- a/clang/lib/CIR/CodeGen/EHScopeStack.h
+++ b/clang/lib/CIR/CodeGen/EHScopeStack.h
@@ -42,7 +42,47 @@ enum CleanupKind : unsigned {
/// A stack of scopes which respond to exceptions, including cleanups
/// and catch blocks.
class EHScopeStack {
+ friend class CIRGenFunction;
+
public:
+ // TODO(ogcg): Switch to alignof(uint64_t) instead of 8
+ enum { ScopeStackAlignment = 8 };
+
+ /// A saved depth on the scope stack. This is necessary because
+ /// pushing scopes onto the stack invalidates iterators.
+ class stable_iterator {
+ friend class EHScopeStack;
+
+ /// Offset from startOfData to endOfBuffer.
+ ptrdiff_t size = -1;
+
+ explicit stable_iterator(ptrdiff_t size) : size(size) {}
+
+ public:
+ static stable_iterator invalid() { return stable_iterator(-1); }
+ stable_iterator() = default;
+
+ bool isValid() const { return size >= 0; }
+
+ /// Returns true if this scope encloses I.
+ /// Returns false if I is invalid.
+ /// This scope must be valid.
+ bool encloses(stable_iterator other) const { return size <= other.size; }
+
+ /// Returns true if this scope strictly encloses I: that is,
+ /// if it encloses I and is not I.
+ /// Returns false is I is invalid.
+ /// This scope must be valid.
+ bool strictlyEncloses(stable_iterator I) const { return size < I.size; }
+
+ friend bool operator==(stable_iterator A, stable_iterator B) {
+ return A.size == B.size;
+ }
+ friend bool operator!=(stable_iterator A, stable_iterator B) {
+ return A.size != B.size;
+ }
+ };
+
/// Information for lazily generating a cleanup. Subclasses must be
/// POD-like: cleanups will not be destructed, and they will be
/// allocated on the cleanup stack and freely copied and moved
@@ -68,30 +108,75 @@ public:
///
// \param flags cleanup kind.
virtual void emit(CIRGenFunction &cgf) = 0;
- };
- // Classic codegen has a finely tuned custom allocator and a complex stack
- // management scheme. We'll probably eventually want to find a way to share
- // that implementation. For now, we will use a very simplified implementation
- // to get cleanups working.
- llvm::SmallVector<std::unique_ptr<Cleanup>, 8> cleanupStack;
+ // This is a placeholder until EHScope is implemented.
+ virtual size_t getSize() const = 0;
+ };
private:
+ // The implementation for this class is in CIRGenCleanup.h and
+ // CIRGenCleanup.cpp; the definition is here because it's used as a
+ // member of CIRGenFunction.
+
+ /// The start of the scope-stack buffer, i.e. the allocated pointer
+ /// for the buffer. All of these pointers are either simultaneously
+ /// null or simultaneously valid.
+ std::unique_ptr<char[]> startOfBuffer;
+
+ /// The end of the buffer.
+ char *endOfBuffer = nullptr;
+
+ /// The first valid entry in the buffer.
+ char *startOfData = nullptr;
+
/// The CGF this Stack belong to
CIRGenFunction *cgf = nullptr;
+ // This class uses a custom allocator for maximum efficiency because cleanups
+ // are allocated and freed very frequently. It's basically a bump pointer
+ // allocator, but we can't use LLVM's BumpPtrAllocator because we use offsets
+ // into the buffer as stable iterators.
+ char *allocate(size_t size);
+ void deallocate(size_t size);
+
+ void *pushCleanup(CleanupKind kind, size_t dataSize);
+
public:
EHScopeStack() = default;
~EHScopeStack() = default;
/// Push a lazily-created cleanup on the stack.
template <class T, class... As> void pushCleanup(CleanupKind kind, As... a) {
- cleanupStack.push_back(std::make_unique<T>(a...));
+ static_assert(alignof(T) <= ScopeStackAlignment,
+ "Cleanup's alignment is too large.");
+ void *buffer = pushCleanup(kind, sizeof(T));
+ [[maybe_unused]] Cleanup *obj = new (buffer) T(a...);
}
void setCGF(CIRGenFunction *inCGF) { cgf = inCGF; }
- size_t getStackDepth() const { return cleanupStack.size(); }
+ /// Pops a cleanup scope off the stack. This is private to CIRGenCleanup.cpp.
+ void popCleanup();
+
+ /// Determines whether the exception-scopes stack is empty.
+ bool empty() const { return startOfData == endOfBuffer; }
+
+ /// An unstable reference to a scope-stack depth. Invalidated by
+ /// pushes but not pops.
+ class iterator;
+
+ /// Returns an iterator pointing to the innermost EH scope.
+ iterator begin() const;
+
+ /// Create a stable reference to the top of the EH stack. The
+ /// returned reference is valid until that scope is popped off the
+ /// stack.
+ stable_iterator stable_begin() const {
+ return stable_iterator(endOfBuffer - startOfData);
+ }
+
+ /// Create a stable reference to the bottom of the EH stack.
+ static stable_iterator stable_end() { return stable_iterator(0); }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d3fcac1..53ab04e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1444,6 +1444,27 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
}
//===----------------------------------------------------------------------===//
+// VTableAddrPointOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+ StringRef name = getName();
+
+ // Verify that the result type underlying pointer type matches the type of
+ // the referenced cir.global or cir.func op.
+ auto op = symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
+ if (!op)
+ return emitOpError("'")
+ << name << "' does not reference a valid cir.global";
+ std::optional<mlir::Attribute> init = op.getInitialValue();
+ if (!init)
+ return success();
+ assert(!cir::MissingFeatures::vtableInitializer());
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7e1c9fb..43a1b51 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2143,6 +2143,11 @@ void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
module->getAttr(cir::CIRDialect::getTripleAttrName()))
module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
tripleAttr);
+
+ if (mlir::Attribute asmAttr =
+ module->getAttr(cir::CIRDialect::getModuleLevelAsmAttrName()))
+ module->setAttr(mlir::LLVM::LLVMDialect::getModuleLevelAsmAttrName(),
+ asmAttr);
}
void ConvertCIRToLLVMPass::runOnOperation() {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f64ac20..918cb3e 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -103,13 +103,6 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() {
return CGM.getTarget().getTriple().getArch();
}
-// Returns true if the type is an HLSL resource class or an array of them
-static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
- while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
- Ty = CAT->getArrayElementTypeNoTypeQual();
- return Ty->isHLSLResourceRecord();
-}
-
// Emits constant global variables for buffer constants declarations
// and creates metadata linking the constant globals with the buffer global.
void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
@@ -146,7 +139,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
if (VD->getStorageClass() == SC_Static ||
VDTy.getAddressSpace() == LangAS::hlsl_groupshared ||
- isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+ VDTy->isHLSLResourceRecord() || VDTy->isHLSLResourceRecordArray()) {
// Emit static and groupshared variables and resource classes inside
// cbuffer as regular globals
CGM.EmitGlobal(VD);
diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index 33a8d8f..1a1889a 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -246,35 +246,26 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
llvm::FunctionType *LLVMFuncTy =
cast<llvm::FunctionType>(ConvertType(QualType(FuncTy, 0)));
+ bool VarArg = LLVMFuncTy->isVarArg();
unsigned NParams = LLVMFuncTy->getNumParams();
std::vector<Value *> Args;
- Args.reserve(NParams + 3);
+ Args.reserve(NParams + 3 + VarArg);
// The only real argument is the FuncRef
Args.push_back(FuncRef);
// Add the type information
- auto addType = [this, &Args](llvm::Type *T) {
- if (T->isVoidTy()) {
- // Do nothing
- } else if (T->isFloatingPointTy()) {
- Args.push_back(ConstantFP::get(T, 0));
- } else if (T->isIntegerTy()) {
- Args.push_back(ConstantInt::get(T, 0));
- } else if (T->isPointerTy()) {
- Args.push_back(ConstantPointerNull::get(llvm::PointerType::get(
- getLLVMContext(), T->getPointerAddressSpace())));
- } else {
- // TODO: Handle reference types. For now, we reject them in Sema.
- llvm_unreachable("Unhandled type");
- }
- };
-
- addType(LLVMFuncTy->getReturnType());
+ llvm::Type *RetType = LLVMFuncTy->getReturnType();
+ if (!RetType->isVoidTy()) {
+ Args.push_back(PoisonValue::get(RetType));
+ }
// The token type indicates the boundary between return types and param
// types.
Args.push_back(PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext())));
for (unsigned i = 0; i < NParams; i++) {
- addType(LLVMFuncTy->getParamType(i));
+ Args.push_back(PoisonValue::get(LLVMFuncTy->getParamType(i)));
+ }
+ if (VarArg) {
+ Args.push_back(PoisonValue::get(Builder.getPtrTy()));
}
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func);
return Builder.CreateCall(Callee, Args);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 9f77e62..ccc3154 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3936,47 +3936,18 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fsanitize_ignorelist_EQ, F);
switch (Opts.getClangABICompat()) {
- case LangOptions::ClangABI::Ver3_8:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "3.8");
+#define ABI_VER_MAJOR_MINOR(Major, Minor) \
+ case LangOptions::ClangABI::Ver##Major##_##Minor: \
+ GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, #Major "." #Minor); \
break;
- case LangOptions::ClangABI::Ver4:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "4.0");
+#define ABI_VER_MAJOR(Major) \
+ case LangOptions::ClangABI::Ver##Major: \
+ GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, #Major ".0"); \
break;
- case LangOptions::ClangABI::Ver6:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "6.0");
- break;
- case LangOptions::ClangABI::Ver7:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "7.0");
- break;
- case LangOptions::ClangABI::Ver9:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "9.0");
- break;
- case LangOptions::ClangABI::Ver11:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "11.0");
- break;
- case LangOptions::ClangABI::Ver12:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "12.0");
- break;
- case LangOptions::ClangABI::Ver14:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "14.0");
- break;
- case LangOptions::ClangABI::Ver15:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "15.0");
- break;
- case LangOptions::ClangABI::Ver17:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
- break;
- case LangOptions::ClangABI::Ver18:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
- break;
- case LangOptions::ClangABI::Ver19:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "19.0");
- break;
- case LangOptions::ClangABI::Ver20:
- GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "20.0");
- break;
- case LangOptions::ClangABI::Latest:
+#define ABI_VER_LATEST(Latest) \
+ case LangOptions::ClangABI::Latest: \
break;
+#include "clang/Basic/ABIVersions.def"
}
if (Opts.getSignReturnAddressScope() ==
@@ -4482,32 +4453,18 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
!VerParts.second.getAsInteger(10, Minor)
: VerParts.first.size() == Ver.size() || VerParts.second == "0")) {
// Got a valid version number.
- if (Major == 3 && Minor <= 8)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
- else if (Major <= 4)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
- else if (Major <= 6)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver6);
- else if (Major <= 7)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver7);
- else if (Major <= 9)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver9);
- else if (Major <= 11)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver11);
- else if (Major <= 12)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver12);
- else if (Major <= 14)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver14);
- else if (Major <= 15)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
- else if (Major <= 17)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
- else if (Major <= 18)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
- else if (Major <= 19)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver19);
- else if (Major <= 20)
- Opts.setClangABICompat(LangOptions::ClangABI::Ver20);
+#define ABI_VER_MAJOR_MINOR(Major_, Minor_) \
+ if (std::tie(Major, Minor) <= std::tuple(Major_, Minor_)) \
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver##Major_##_##Minor_); \
+ else
+#define ABI_VER_MAJOR(Major_) \
+ if (Major <= Major_) \
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver##Major_); \
+ else
+#define ABI_VER_LATEST(Latest) \
+ { /* Equivalent to latest version - do nothing */ \
+ }
+#include "clang/Basic/ABIVersions.def"
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h
index 440552c..74343c3 100644
--- a/clang/lib/Headers/avx512fintrin.h
+++ b/clang/lib/Headers/avx512fintrin.h
@@ -835,45 +835,38 @@ _mm512_xor_si512(__m512i __a, __m512i __b)
/* Arithmetic */
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_add_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_add_pd(__m512d __a, __m512d __b) {
return (__m512d)((__v8df)__a + (__v8df)__b);
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_add_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_add_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a + (__v16sf)__b);
}
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_mul_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_mul_pd(__m512d __a, __m512d __b) {
return (__m512d)((__v8df)__a * (__v8df)__b);
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_mul_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_mul_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a * (__v16sf)__b);
}
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_sub_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_sub_pd(__m512d __a, __m512d __b) {
return (__m512d)((__v8df)__a - (__v8df)__b);
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_sub_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_sub_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a - (__v16sf)__b);
}
-static __inline__ __m512i __DEFAULT_FN_ATTRS512
-_mm512_add_epi64 (__m512i __A, __m512i __B)
-{
+static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_add_epi64(__m512i __A, __m512i __B) {
return (__m512i) ((__v8du) __A + (__v8du) __B);
}
@@ -2315,9 +2308,8 @@ _mm_maskz_div_sd(__mmask8 __U,__m128d __A, __m128d __B) {
(__v2df)_mm_setzero_pd(), \
(__mmask8)(U), (int)(R)))
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_div_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d
+ __DEFAULT_FN_ATTRS512_CONSTEXPR _mm512_div_pd(__m512d __a, __m512d __b) {
return (__m512d)((__v8df)__a/(__v8df)__b);
}
@@ -2335,9 +2327,8 @@ _mm512_maskz_div_pd(__mmask8 __U, __m512d __A, __m512d __B) {
(__v8df)_mm512_setzero_pd());
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_div_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_div_ps(__m512 __a, __m512 __b) {
return (__m512)((__v16sf)__a/(__v16sf)__b);
}
@@ -4123,9 +4114,8 @@ _mm512_cvtss_f32(__m512 __a)
/* Unpack and Interleave */
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_unpackhi_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_unpackhi_pd(__m512d __a, __m512d __b) {
return (__m512d)__builtin_shufflevector((__v8df)__a, (__v8df)__b,
1, 9, 1+2, 9+2, 1+4, 9+4, 1+6, 9+6);
}
@@ -4146,9 +4136,8 @@ _mm512_maskz_unpackhi_pd(__mmask8 __U, __m512d __A, __m512d __B)
(__v8df)_mm512_setzero_pd());
}
-static __inline __m512d __DEFAULT_FN_ATTRS512
-_mm512_unpacklo_pd(__m512d __a, __m512d __b)
-{
+static __inline __m512d __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_unpacklo_pd(__m512d __a, __m512d __b) {
return (__m512d)__builtin_shufflevector((__v8df)__a, (__v8df)__b,
0, 8, 0+2, 8+2, 0+4, 8+4, 0+6, 8+6);
}
@@ -4169,9 +4158,8 @@ _mm512_maskz_unpacklo_pd (__mmask8 __U, __m512d __A, __m512d __B)
(__v8df)_mm512_setzero_pd());
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_unpackhi_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_unpackhi_ps(__m512 __a, __m512 __b) {
return (__m512)__builtin_shufflevector((__v16sf)__a, (__v16sf)__b,
2, 18, 3, 19,
2+4, 18+4, 3+4, 19+4,
@@ -4195,9 +4183,8 @@ _mm512_maskz_unpackhi_ps (__mmask16 __U, __m512 __A, __m512 __B)
(__v16sf)_mm512_setzero_ps());
}
-static __inline __m512 __DEFAULT_FN_ATTRS512
-_mm512_unpacklo_ps(__m512 __a, __m512 __b)
-{
+static __inline __m512 __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_unpacklo_ps(__m512 __a, __m512 __b) {
return (__m512)__builtin_shufflevector((__v16sf)__a, (__v16sf)__b,
0, 16, 1, 17,
0+4, 16+4, 1+4, 17+4,
@@ -9337,19 +9324,23 @@ _mm512_mask_abs_pd(__m512d __W, __mmask8 __K, __m512d __A)
* This takes log2(n) steps where n is the number of elements in the vector.
*/
-static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_add_epi64(__m512i __W) {
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_reduce_add_epi64(__m512i __W) {
return __builtin_reduce_add((__v8di)__W);
}
-static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_mul_epi64(__m512i __W) {
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_reduce_mul_epi64(__m512i __W) {
return __builtin_reduce_mul((__v8di)__W);
}
-static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_and_epi64(__m512i __W) {
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_reduce_and_epi64(__m512i __W) {
return __builtin_reduce_and((__v8di)__W);
}
-static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_or_epi64(__m512i __W) {
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
+_mm512_reduce_or_epi64(__m512i __W) {
return __builtin_reduce_or((__v8di)__W);
}
@@ -9400,22 +9391,22 @@ _mm512_mask_reduce_mul_pd(__mmask8 __M, __m512d __W) {
return __builtin_ia32_reduce_fmul_pd512(1.0, __W);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_add_epi32(__m512i __W) {
return __builtin_reduce_add((__v16si)__W);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_mul_epi32(__m512i __W) {
return __builtin_reduce_mul((__v16si)__W);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_and_epi32(__m512i __W) {
return __builtin_reduce_and((__v16si)__W);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_or_epi32(__m512i __W) {
return __builtin_reduce_or((__v16si)__W);
}
@@ -9466,22 +9457,22 @@ _mm512_mask_reduce_mul_ps(__mmask16 __M, __m512 __W) {
return __builtin_ia32_reduce_fmul_ps512(1.0f, __W);
}
-static __inline__ long long __DEFAULT_FN_ATTRS512
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_max_epi64(__m512i __V) {
return __builtin_reduce_max((__v8di)__V);
}
-static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
+static __inline__ unsigned long long __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_max_epu64(__m512i __V) {
return __builtin_reduce_max((__v8du)__V);
}
-static __inline__ long long __DEFAULT_FN_ATTRS512
+static __inline__ long long __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_min_epi64(__m512i __V) {
return __builtin_reduce_min((__v8di)__V);
}
-static __inline__ unsigned long long __DEFAULT_FN_ATTRS512
+static __inline__ unsigned long long __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_min_epu64(__m512i __V) {
return __builtin_reduce_min((__v8du)__V);
}
@@ -9509,22 +9500,22 @@ _mm512_mask_reduce_min_epu64(__mmask8 __M, __m512i __V) {
__V = _mm512_mask_mov_epi64(_mm512_set1_epi64(-1LL), __M, __V);
return __builtin_reduce_min((__v8du)__V);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_max_epi32(__m512i __V) {
return __builtin_reduce_max((__v16si)__V);
}
-static __inline__ unsigned int __DEFAULT_FN_ATTRS512
+static __inline__ unsigned int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_max_epu32(__m512i __V) {
return __builtin_reduce_max((__v16su)__V);
}
-static __inline__ int __DEFAULT_FN_ATTRS512
+static __inline__ int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_min_epi32(__m512i __V) {
return __builtin_reduce_min((__v16si)__V);
}
-static __inline__ unsigned int __DEFAULT_FN_ATTRS512
+static __inline__ unsigned int __DEFAULT_FN_ATTRS512_CONSTEXPR
_mm512_reduce_min_epu32(__m512i __V) {
return __builtin_reduce_min((__v16su)__V);
}
diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h
index 1da50f0..2be4f68 100644
--- a/clang/lib/Headers/avxintrin.h
+++ b/clang/lib/Headers/avxintrin.h
@@ -87,9 +87,8 @@ typedef __bf16 __m256bh __attribute__((__vector_size__(32), __aligned__(32)));
/// A 256-bit vector of [4 x double] containing one of the source operands.
/// \returns A 256-bit vector of [4 x double] containing the sums of both
/// operands.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_add_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_add_pd(__m256d __a, __m256d __b) {
return (__m256d)((__v4df)__a+(__v4df)__b);
}
@@ -105,9 +104,8 @@ _mm256_add_pd(__m256d __a, __m256d __b)
/// A 256-bit vector of [8 x float] containing one of the source operands.
/// \returns A 256-bit vector of [8 x float] containing the sums of both
/// operands.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_add_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR _mm256_add_ps(__m256 __a,
+ __m256 __b) {
return (__m256)((__v8sf)__a+(__v8sf)__b);
}
@@ -123,9 +121,8 @@ _mm256_add_ps(__m256 __a, __m256 __b)
/// A 256-bit vector of [4 x double] containing the subtrahend.
/// \returns A 256-bit vector of [4 x double] containing the differences between
/// both operands.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_sub_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_sub_pd(__m256d __a, __m256d __b) {
return (__m256d)((__v4df)__a-(__v4df)__b);
}
@@ -141,9 +138,8 @@ _mm256_sub_pd(__m256d __a, __m256d __b)
/// A 256-bit vector of [8 x float] containing the subtrahend.
/// \returns A 256-bit vector of [8 x float] containing the differences between
/// both operands.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_sub_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR _mm256_sub_ps(__m256 __a,
+ __m256 __b) {
return (__m256)((__v8sf)__a-(__v8sf)__b);
}
@@ -197,9 +193,8 @@ _mm256_addsub_ps(__m256 __a, __m256 __b)
/// A 256-bit vector of [4 x double] containing the divisor.
/// \returns A 256-bit vector of [4 x double] containing the quotients of both
/// operands.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_div_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_div_pd(__m256d __a, __m256d __b) {
return (__m256d)((__v4df)__a/(__v4df)__b);
}
@@ -215,9 +210,8 @@ _mm256_div_pd(__m256d __a, __m256d __b)
/// A 256-bit vector of [8 x float] containing the divisor.
/// \returns A 256-bit vector of [8 x float] containing the quotients of both
/// operands.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_div_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR _mm256_div_ps(__m256 __a,
+ __m256 __b) {
return (__m256)((__v8sf)__a/(__v8sf)__b);
}
@@ -317,9 +311,8 @@ _mm256_min_ps(__m256 __a, __m256 __b)
/// A 256-bit vector of [4 x double] containing one of the operands.
/// \returns A 256-bit vector of [4 x double] containing the products of both
/// operands.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_mul_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_mul_pd(__m256d __a, __m256d __b) {
return (__m256d)((__v4df)__a * (__v4df)__b);
}
@@ -335,9 +328,8 @@ _mm256_mul_pd(__m256d __a, __m256d __b)
/// A 256-bit vector of [8 x float] containing one of the operands.
/// \returns A 256-bit vector of [8 x float] containing the products of both
/// operands.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_mul_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR _mm256_mul_ps(__m256 __a,
+ __m256 __b) {
return (__m256)((__v8sf)__a * (__v8sf)__b);
}
@@ -2462,9 +2454,8 @@ _mm256_movedup_pd(__m256d __a)
/// Bits [127:64] are written to bits [127:64] of the return value. \n
/// Bits [255:192] are written to bits [255:192] of the return value. \n
/// \returns A 256-bit vector of [4 x double] containing the interleaved values.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_unpackhi_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_unpackhi_pd(__m256d __a, __m256d __b) {
return __builtin_shufflevector((__v4df)__a, (__v4df)__b, 1, 5, 1+2, 5+2);
}
@@ -2484,9 +2475,8 @@ _mm256_unpackhi_pd(__m256d __a, __m256d __b)
/// Bits [63:0] are written to bits [127:64] of the return value. \n
/// Bits [191:128] are written to bits [255:192] of the return value. \n
/// \returns A 256-bit vector of [4 x double] containing the interleaved values.
-static __inline __m256d __DEFAULT_FN_ATTRS
-_mm256_unpacklo_pd(__m256d __a, __m256d __b)
-{
+static __inline __m256d __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_unpacklo_pd(__m256d __a, __m256d __b) {
return __builtin_shufflevector((__v4df)__a, (__v4df)__b, 0, 4, 0+2, 4+2);
}
@@ -2511,9 +2501,8 @@ _mm256_unpacklo_pd(__m256d __a, __m256d __b)
/// Bits [223:192] are written to bits [191:160] of the return value. \n
/// Bits [255:224] are written to bits [255:224] of the return value.
/// \returns A 256-bit vector of [8 x float] containing the interleaved values.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_unpackhi_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_unpackhi_ps(__m256 __a, __m256 __b) {
return __builtin_shufflevector((__v8sf)__a, (__v8sf)__b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1);
}
@@ -2538,9 +2527,8 @@ _mm256_unpackhi_ps(__m256 __a, __m256 __b)
/// Bits [159:128] are written to bits [191:160] of the return value. \n
/// Bits [191:160] are written to bits [255:224] of the return value.
/// \returns A 256-bit vector of [8 x float] containing the interleaved values.
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_unpacklo_ps(__m256 __a, __m256 __b)
-{
+static __inline __m256 __DEFAULT_FN_ATTRS_CONSTEXPR
+_mm256_unpacklo_ps(__m256 __a, __m256 __b) {
return __builtin_shufflevector((__v8sf)__a, (__v8sf)__b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1);
}
diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h
index 52addb7..ce8c79e 100644
--- a/clang/lib/Headers/cpuid.h
+++ b/clang/lib/Headers/cpuid.h
@@ -345,10 +345,15 @@ static __inline int __get_cpuid_count (unsigned int __leaf,
// In some configurations, __cpuidex is defined as a builtin (primarily
// -fms-extensions) which will conflict with the __cpuidex definition below.
#if !(__has_builtin(__cpuidex))
+// In some cases, offloading will set the host as the aux triple and define the
+// builtin. Given __has_builtin does not detect builtins on aux triples, we need
+// to explicitly check for some offloading cases.
+#ifndef __NVPTX__
static __inline void __cpuidex(int __cpu_info[4], int __leaf, int __subleaf) {
__cpuid_count(__leaf, __subleaf, __cpu_info[0], __cpu_info[1], __cpu_info[2],
__cpu_info[3]);
}
#endif
+#endif
#endif /* __CPUID_H */
diff --git a/clang/lib/Interpreter/RemoteJITUtils.cpp b/clang/lib/Interpreter/RemoteJITUtils.cpp
index c0e663b..c100f46 100644
--- a/clang/lib/Interpreter/RemoteJITUtils.cpp
+++ b/clang/lib/Interpreter/RemoteJITUtils.cpp
@@ -33,6 +33,10 @@
using namespace llvm;
using namespace llvm::orc;
+#if LLVM_ON_UNIX
+static std::vector<pid_t> LaunchedExecutorPID;
+#endif
+
Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
SizeString = SizeString.trim();
@@ -89,9 +93,14 @@ createSharedMemoryManager(SimpleRemoteEPC &SREPC,
SlabSize, SREPC, SAs);
}
+// Launches an out-of-process executor for remote JIT. The calling program can
+// provide a CustomizeFork callback, which allows it to run custom code in the
+// child process before exec. This enables sending custom setup or code to be
+// executed in the child (out-of-process) executor.
Expected<std::unique_ptr<SimpleRemoteEPC>>
launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
- llvm::StringRef SlabAllocateSizeString) {
+ llvm::StringRef SlabAllocateSizeString,
+ std::function<void()> CustomizeFork) {
#ifndef LLVM_ON_UNIX
// FIXME: Add support for Windows.
return make_error<StringError>("-" + ExecutablePath +
@@ -134,6 +143,9 @@ launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
close(ToExecutor[WriteEnd]);
close(FromExecutor[ReadEnd]);
+ if (CustomizeFork)
+ CustomizeFork();
+
// Execute the child process.
std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
{
@@ -158,6 +170,8 @@ launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
}
// else we're the parent...
+ LaunchedExecutorPID.push_back(ChildPID);
+
// Close the child ends of the pipes
close(ToExecutor[ReadEnd]);
close(FromExecutor[WriteEnd]);
@@ -265,3 +279,18 @@ connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,
std::move(S), *SockFD, *SockFD);
#endif
}
+
+#if LLVM_ON_UNIX
+
+pid_t getLastLaunchedExecutorPID() {
+ if (!LaunchedExecutorPID.size())
+ return -1;
+ return LaunchedExecutorPID.back();
+}
+
+pid_t getNthLaunchedExecutorPID(int n) {
+ if (n - 1 < 0 || n - 1 >= static_cast<int>(LaunchedExecutorPID.size()))
+ return -1;
+ return LaunchedExecutorPID.at(n - 1);
+}
+#endif \ No newline at end of file
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8536e04..17f17f8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -337,16 +337,9 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
return CAT != nullptr;
}
-// Returns true if the record type is an HLSL resource class or an array of
-// resource classes
-static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
- while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
- Ty = CAT->getArrayElementTypeNoTypeQual();
- return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
-}
-
static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
- return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr());
+ const Type *Ty = VD->getType().getTypePtr();
+ return Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray();
}
// Returns true if the type is a leaf element type that is not valid to be
@@ -355,7 +348,7 @@ static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
// type or if it is a record type that needs to be inspected further.
static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
Ty = Ty->getUnqualifiedDesugaredType();
- if (isResourceRecordTypeOrArrayOf(Ty))
+ if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray())
return true;
if (Ty->isRecordType())
return Ty->getAsCXXRecordDecl()->isEmpty();
@@ -3597,7 +3590,7 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
return;
// Resource handles.
- if (isResourceRecordTypeOrArrayOf(Type->getUnqualifiedDesugaredType()))
+ if (Type->isHLSLResourceRecord() || Type->isHLSLResourceRecordArray())
return;
// Only static globals belong to the Private address space.
@@ -3637,10 +3630,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
if (VD->getType()->isHLSLIntangibleType())
collectResourceBindingsOnVarDecl(VD);
- const Type *VarType = VD->getType().getTypePtr();
- while (VarType->isArrayType())
- VarType = VarType->getArrayElementTypeNoTypeQual();
- if (VarType->isHLSLResourceRecord() ||
+ if (isResourceRecordTypeOrArrayOf(VD) ||
VD->hasAttr<HLSLVkConstantIdAttr>()) {
// Make the variable for resources static. The global externally visible
// storage is accessed through the handle, which is a member. The variable
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b6b8932..2d8fdb5 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -367,7 +367,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
// The code is missing a 'template' keyword prior to the dependent template
// name.
- NestedNameSpecifier *Qualifier = (NestedNameSpecifier *)SS->getScopeRep();
+ NestedNameSpecifier *Qualifier = SS->getScopeRep();
SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(
{Qualifier, &II, /*HasTemplateKeyword=*/false}));
Diag(IILoc, diag::err_template_kw_missing)
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 8998492..e773113 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/Sema.h"
@@ -227,7 +228,8 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
return false;
}
-bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
+bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI,
+ CallExpr *TheCall) {
if (SemaRef.checkArgCount(TheCall, 1))
return true;
@@ -250,27 +252,31 @@ bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
<< ArgType << FuncPtrArg->getSourceRange();
}
- // Check that the function pointer doesn't use reference types
- if (FuncTy->getReturnType().isWebAssemblyReferenceType()) {
- return Diag(
- FuncPtrArg->getBeginLoc(),
- diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
- << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
- }
- auto NParams = FuncTy->getNumParams();
- for (unsigned I = 0; I < NParams; I++) {
- if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) {
+ if (TI.getABI() == "experimental-mv") {
+ auto isStructOrUnion = [](QualType T) {
+ return T->isUnionType() || T->isStructureType();
+ };
+ if (isStructOrUnion(FuncTy->getReturnType())) {
return Diag(
FuncPtrArg->getBeginLoc(),
diag::
- err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
- << 1 << FuncPtrArg->getSourceRange();
+ err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
+ << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
+ }
+ auto NParams = FuncTy->getNumParams();
+ for (unsigned I = 0; I < NParams; I++) {
+ if (isStructOrUnion(FuncTy->getParamType(I))) {
+ return Diag(
+ FuncPtrArg->getBeginLoc(),
+ diag::
+ err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
+ << 1 << FuncPtrArg->getSourceRange();
+ }
}
}
// Set return type to int (the result of the test)
TheCall->setType(getASTContext().IntTy);
-
return false;
}
@@ -297,7 +303,7 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
case WebAssembly::BI__builtin_wasm_table_copy:
return BuiltinWasmTableCopy(TheCall);
case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
- return BuiltinWasmTestFunctionPointerSignature(TheCall);
+ return BuiltinWasmTestFunctionPointerSignature(TI, TheCall);
}
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 62bc321..65ff902 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -840,20 +840,27 @@ ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
const RefCountBug &
RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
SymbolRef Sym) const {
+ const RefCountFrontend &FE = getPreferredFrontend();
+
switch (ErrorKind) {
case RefVal::ErrorUseAfterRelease:
- return *UseAfterRelease;
+ return FE.UseAfterRelease;
case RefVal::ErrorReleaseNotOwned:
- return *ReleaseNotOwned;
+ return FE.ReleaseNotOwned;
case RefVal::ErrorDeallocNotOwned:
if (Sym->getType()->getPointeeCXXRecordDecl())
- return *FreeNotOwned;
- return *DeallocNotOwned;
+ return FE.FreeNotOwned;
+ return FE.DeallocNotOwned;
default:
llvm_unreachable("Unhandled error.");
}
}
+bool RetainCountChecker::isReleaseUnownedError(RefVal::Kind ErrorKind) const {
+ return ErrorKind == RefVal::ErrorReleaseNotOwned ||
+ ErrorKind == RefVal::ErrorDeallocNotOwned;
+}
+
void RetainCountChecker::processNonLeakError(ProgramStateRef St,
SourceRange ErrorRange,
RefVal::Kind ErrorKind,
@@ -874,8 +881,8 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
return;
auto report = std::make_unique<RefCountReport>(
- errorKindToBugKind(ErrorKind, Sym),
- C.getASTContext().getLangOpts(), N, Sym);
+ errorKindToBugKind(ErrorKind, Sym), C.getASTContext().getLangOpts(), N,
+ Sym, /*isLeak=*/false, isReleaseUnownedError(ErrorKind));
report->addRange(ErrorRange);
C.emitReport(std::move(report));
}
@@ -1090,8 +1097,8 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
ExplodedNode *N = C.addTransition(state, Pred);
if (N) {
const LangOptions &LOpts = C.getASTContext().getLangOpts();
- auto R =
- std::make_unique<RefLeakReport>(*LeakAtReturn, LOpts, N, Sym, C);
+ auto R = std::make_unique<RefLeakReport>(
+ getPreferredFrontend().LeakAtReturn, LOpts, N, Sym, C);
C.emitReport(std::move(R));
}
return N;
@@ -1113,7 +1120,8 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
ExplodedNode *N = C.addTransition(state, Pred);
if (N) {
auto R = std::make_unique<RefCountReport>(
- *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
+ getPreferredFrontend().ReturnNotOwnedForOwned,
+ C.getASTContext().getLangOpts(), N, Sym);
C.emitReport(std::move(R));
}
return N;
@@ -1261,8 +1269,8 @@ ProgramStateRef RetainCountChecker::handleAutoreleaseCounts(
os << "has a +" << V.getCount() << " retain count";
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
- auto R = std::make_unique<RefCountReport>(*OverAutorelease, LOpts, N, Sym,
- os.str());
+ auto R = std::make_unique<RefCountReport>(
+ getPreferredFrontend().OverAutorelease, LOpts, N, Sym, os.str());
Ctx.emitReport(std::move(R));
}
@@ -1307,8 +1315,10 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
if (N) {
+ const RefCountFrontend &FE = getPreferredFrontend();
+ const RefCountBug &BT = Pred ? FE.LeakWithinFunction : FE.LeakAtReturn;
+
for (SymbolRef L : Leaked) {
- const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn;
Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
}
}
@@ -1463,44 +1473,31 @@ std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::DeallocSentTag;
std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::CastFailTag;
void ento::registerRetainCountBase(CheckerManager &Mgr) {
- auto *Chk = Mgr.registerChecker<RetainCountChecker>();
+ auto *Chk = Mgr.getChecker<RetainCountChecker>();
Chk->DeallocSentTag = std::make_unique<SimpleProgramPointTag>(
"RetainCountChecker", "DeallocSent");
Chk->CastFailTag = std::make_unique<SimpleProgramPointTag>(
"RetainCountChecker", "DynamicCastFail");
}
-bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) {
+bool ento::shouldRegisterRetainCountBase(const CheckerManager &) {
return true;
}
+
void ento::registerRetainCountChecker(CheckerManager &Mgr) {
auto *Chk = Mgr.getChecker<RetainCountChecker>();
- Chk->TrackObjCAndCFObjects = true;
+ Chk->RetainCount.enable(Mgr);
Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
-
-#define INIT_BUGTYPE(KIND) \
- Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
- RefCountBug::KIND);
- // TODO: Ideally, we should have a checker for each of these bug types.
- INIT_BUGTYPE(UseAfterRelease)
- INIT_BUGTYPE(ReleaseNotOwned)
- INIT_BUGTYPE(DeallocNotOwned)
- INIT_BUGTYPE(FreeNotOwned)
- INIT_BUGTYPE(OverAutorelease)
- INIT_BUGTYPE(ReturnNotOwnedForOwned)
- INIT_BUGTYPE(LeakWithinFunction)
- INIT_BUGTYPE(LeakAtReturn)
-#undef INIT_BUGTYPE
}
-bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) {
+bool ento::shouldRegisterRetainCountChecker(const CheckerManager &) {
return true;
}
void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
auto *Chk = Mgr.getChecker<RetainCountChecker>();
- Chk->TrackOSObjects = true;
+ Chk->OSObjectRetainCount.enable(Mgr);
// FIXME: We want bug reports to always have the same checker name associated
// with them, yet here, if RetainCountChecker is disabled but
@@ -1511,21 +1508,8 @@ void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
// diagnostics, and **hidden checker options** with the fine-tuning of
// modeling. Following this logic, OSObjectRetainCountChecker should be the
// latter, but we can't just remove it for backward compatibility reasons.
-#define LAZY_INIT_BUGTYPE(KIND) \
- if (!Chk->KIND) \
- Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \
- RefCountBug::KIND);
- LAZY_INIT_BUGTYPE(UseAfterRelease)
- LAZY_INIT_BUGTYPE(ReleaseNotOwned)
- LAZY_INIT_BUGTYPE(DeallocNotOwned)
- LAZY_INIT_BUGTYPE(FreeNotOwned)
- LAZY_INIT_BUGTYPE(OverAutorelease)
- LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned)
- LAZY_INIT_BUGTYPE(LeakWithinFunction)
- LAZY_INIT_BUGTYPE(LeakAtReturn)
-#undef LAZY_INIT_BUGTYPE
}
-bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) {
+bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &) {
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
index 0e81143..8854e10 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
@@ -235,51 +235,32 @@ public:
};
class RetainCountChecker
- : public Checker< check::Bind,
- check::DeadSymbols,
- check::BeginFunction,
- check::EndFunction,
- check::PostStmt<BlockExpr>,
- check::PostStmt<CastExpr>,
- check::PostStmt<ObjCArrayLiteral>,
- check::PostStmt<ObjCDictionaryLiteral>,
- check::PostStmt<ObjCBoxedExpr>,
- check::PostStmt<ObjCIvarRefExpr>,
- check::PostCall,
- check::RegionChanges,
- eval::Assume,
- eval::Call > {
+ : public CheckerFamily<
+ check::Bind, check::DeadSymbols, check::BeginFunction,
+ check::EndFunction, check::PostStmt<BlockExpr>,
+ check::PostStmt<CastExpr>, check::PostStmt<ObjCArrayLiteral>,
+ check::PostStmt<ObjCDictionaryLiteral>,
+ check::PostStmt<ObjCBoxedExpr>, check::PostStmt<ObjCIvarRefExpr>,
+ check::PostCall, check::RegionChanges, eval::Assume, eval::Call> {
public:
- std::unique_ptr<RefCountBug> UseAfterRelease;
- std::unique_ptr<RefCountBug> ReleaseNotOwned;
- std::unique_ptr<RefCountBug> DeallocNotOwned;
- std::unique_ptr<RefCountBug> FreeNotOwned;
- std::unique_ptr<RefCountBug> OverAutorelease;
- std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned;
- std::unique_ptr<RefCountBug> LeakWithinFunction;
- std::unique_ptr<RefCountBug> LeakAtReturn;
+ RefCountFrontend RetainCount;
+ RefCountFrontend OSObjectRetainCount;
mutable std::unique_ptr<RetainSummaryManager> Summaries;
static std::unique_ptr<SimpleProgramPointTag> DeallocSentTag;
static std::unique_ptr<SimpleProgramPointTag> CastFailTag;
- /// Track Objective-C and CoreFoundation objects.
- bool TrackObjCAndCFObjects = false;
-
- /// Track sublcasses of OSObject.
- bool TrackOSObjects = false;
-
/// Track initial parameters (for the entry point) for NS/CF objects.
bool TrackNSCFStartParam = false;
- RetainCountChecker() {};
+ StringRef getDebugTag() const override { return "RetainCountChecker"; }
RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
if (!Summaries)
- Summaries.reset(
- new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects));
+ Summaries = std::make_unique<RetainSummaryManager>(
+ Ctx, RetainCount.isEnabled(), OSObjectRetainCount.isEnabled());
return *Summaries;
}
@@ -287,6 +268,15 @@ public:
return getSummaryManager(C.getASTContext());
}
+ const RefCountFrontend &getPreferredFrontend() const {
+ // FIXME: The two frontends of this checker family are in an unusual
+ // relationship: if they are both enabled, then all bug reports are
+ // reported by RetainCount (i.e. `osx.cocoa.RetainCount`), even the bugs
+ // that "belong to" OSObjectRetainCount (i.e. `osx.OSObjectRetainCount`).
+ // This is counter-intuitive and should be fixed to avoid confusion.
+ return RetainCount.isEnabled() ? RetainCount : OSObjectRetainCount;
+ }
+
void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const override;
@@ -337,6 +327,8 @@ public:
const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
SymbolRef Sym) const;
+ bool isReleaseUnownedError(RefVal::Kind ErrorKind) const;
+
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym,
CheckerContext &C) const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index c9f5dc9..cad2c72 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -21,57 +21,6 @@ using namespace clang;
using namespace ento;
using namespace retaincountchecker;
-StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugKind BT) {
- switch (BT) {
- case UseAfterRelease:
- return "Use-after-release";
- case ReleaseNotOwned:
- return "Bad release";
- case DeallocNotOwned:
- return "-dealloc sent to non-exclusively owned object";
- case FreeNotOwned:
- return "freeing non-exclusively owned object";
- case OverAutorelease:
- return "Object autoreleased too many times";
- case ReturnNotOwnedForOwned:
- return "Method should return an owned object";
- case LeakWithinFunction:
- return "Leak";
- case LeakAtReturn:
- return "Leak of returned object";
- }
- llvm_unreachable("Unknown RefCountBugKind");
-}
-
-StringRef RefCountBug::getDescription() const {
- switch (BT) {
- case UseAfterRelease:
- return "Reference-counted object is used after it is released";
- case ReleaseNotOwned:
- return "Incorrect decrement of the reference count of an object that is "
- "not owned at this point by the caller";
- case DeallocNotOwned:
- return "-dealloc sent to object that may be referenced elsewhere";
- case FreeNotOwned:
- return "'free' called on an object that may be referenced elsewhere";
- case OverAutorelease:
- return "Object autoreleased too many times";
- case ReturnNotOwnedForOwned:
- return "Object with a +0 retain count returned to caller where a +1 "
- "(owning) retain count is expected";
- case LeakWithinFunction:
- case LeakAtReturn:
- return "";
- }
- llvm_unreachable("Unknown RefCountBugKind");
-}
-
-RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT)
- : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount,
- /*SuppressOnSink=*/BT == LeakWithinFunction ||
- BT == LeakAtReturn),
- BT(BT) {}
-
static bool isNumericLiteralExpression(const Expr *E) {
// FIXME: This set of cases was copied from SemaExprObjC.
return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral,
@@ -312,9 +261,11 @@ namespace retaincountchecker {
class RefCountReportVisitor : public BugReporterVisitor {
protected:
SymbolRef Sym;
+ bool IsReleaseUnowned;
public:
- RefCountReportVisitor(SymbolRef sym) : Sym(sym) {}
+ RefCountReportVisitor(SymbolRef S, bool IRU)
+ : Sym(S), IsReleaseUnowned(IRU) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
@@ -334,7 +285,8 @@ public:
class RefLeakReportVisitor : public RefCountReportVisitor {
public:
RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding)
- : RefCountReportVisitor(Sym), LastBinding(LastBinding) {}
+ : RefCountReportVisitor(Sym, /*IsReleaseUnowned=*/false),
+ LastBinding(LastBinding) {}
PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
@@ -452,12 +404,6 @@ annotateStartParameter(const ExplodedNode *N, SymbolRef Sym,
PathDiagnosticPieceRef
RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
-
- const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
-
- bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned ||
- BT.getBugType() == RefCountBug::DeallocNotOwned;
-
const SourceManager &SM = BRC.getSourceManager();
CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
if (auto CE = N->getLocationAs<CallExitBegin>())
@@ -490,7 +436,7 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- if (PrevT && IsFreeUnowned && CurrV.isNotOwned() && PrevT->isOwned()) {
+ if (PrevT && IsReleaseUnowned && CurrV.isNotOwned() && PrevT->isOwned()) {
os << "Object is now not exclusively owned";
auto Pos = PathDiagnosticLocation::create(N->getLocation(), SM);
return std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
@@ -815,10 +761,8 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
if (K == ObjKind::ObjC || K == ObjKind::CF) {
os << "whose name ('" << *FD
<< "') does not contain 'Copy' or 'Create'. This violates the "
- "naming"
- " convention rules given in the Memory Management Guide for "
- "Core"
- " Foundation";
+ "naming convention rules given in the Memory Management Guide "
+ "for Core Foundation";
} else if (RV->getObjKind() == ObjKind::OS) {
std::string FuncName = FD->getNameAsString();
os << "whose name ('" << FuncName << "') starts with '"
@@ -836,19 +780,20 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
- ExplodedNode *n, SymbolRef sym, bool isLeak)
- : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym),
+ ExplodedNode *n, SymbolRef sym, bool isLeak,
+ bool IsReleaseUnowned)
+ : PathSensitiveBugReport(D, D.getReportMessage(), n), Sym(sym),
isLeak(isLeak) {
if (!isLeak)
- addVisitor<RefCountReportVisitor>(sym);
+ addVisitor<RefCountReportVisitor>(sym, IsReleaseUnowned);
}
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
ExplodedNode *n, SymbolRef sym,
StringRef endText)
- : PathSensitiveBugReport(D, D.getDescription(), endText, n) {
+ : PathSensitiveBugReport(D, D.getReportMessage(), endText, n) {
- addVisitor<RefCountReportVisitor>(sym);
+ addVisitor<RefCountReportVisitor>(sym, /*IsReleaseUnowned=*/false);
}
void RefLeakReport::deriveParamLocation(CheckerContext &Ctx) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
index d059008..6ceb86f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
@@ -25,25 +25,44 @@ namespace ento {
namespace retaincountchecker {
class RefCountBug : public BugType {
+ StringRef ReportMessage;
+
public:
- enum RefCountBugKind {
- UseAfterRelease,
- ReleaseNotOwned,
- DeallocNotOwned,
- FreeNotOwned,
- OverAutorelease,
- ReturnNotOwnedForOwned,
- LeakWithinFunction,
- LeakAtReturn,
- };
- RefCountBug(CheckerNameRef Checker, RefCountBugKind BT);
- StringRef getDescription() const;
-
- RefCountBugKind getBugType() const { return BT; }
-
-private:
- RefCountBugKind BT;
- static StringRef bugTypeToName(RefCountBugKind BT);
+ RefCountBug(const CheckerFrontend *CF, StringRef Desc, StringRef ReportMsg,
+ bool SuppressOnSink = false)
+ : BugType(CF, Desc, categories::MemoryRefCount, SuppressOnSink),
+ ReportMessage(ReportMsg) {}
+ StringRef getReportMessage() const { return ReportMessage; }
+};
+
+class RefCountFrontend : public CheckerFrontend {
+public:
+ const RefCountBug UseAfterRelease{
+ this, "Use-after-release",
+ "Reference-counted object is used after it is released"};
+ const RefCountBug ReleaseNotOwned{
+ this, "Bad release",
+ "Incorrect decrement of the reference count of an object that is not "
+ "owned at this point by the caller"};
+ const RefCountBug DeallocNotOwned{
+ this, "-dealloc sent to non-exclusively owned object",
+ "-dealloc sent to object that may be referenced elsewhere"};
+ const RefCountBug FreeNotOwned{
+ this, "freeing non-exclusively owned object",
+ "'free' called on an object that may be referenced elsewhere"};
+ const RefCountBug OverAutorelease{this, "Object autoreleased too many times",
+ "Object autoreleased too many times"};
+ const RefCountBug ReturnNotOwnedForOwned{
+ this, "Method should return an owned object",
+ "Object with a +0 retain count returned to caller where a +1 (owning) "
+ "retain count is expected"};
+ // For these two bug types the report message will be generated dynamically
+ // by `RefLeakReport::createDescription` so the empty string taken from the
+ // BugType will be ignored (overwritten).
+ const RefCountBug LeakWithinFunction{this, "Leak", /*ReportMsg=*/"",
+ /*SuppressOnSink=*/true};
+ const RefCountBug LeakAtReturn{this, "Leak of returned object",
+ /*ReportMsg=*/"", /*SuppressOnSink=*/true};
};
class RefCountReport : public PathSensitiveBugReport {
@@ -53,8 +72,8 @@ protected:
public:
RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
- ExplodedNode *n, SymbolRef sym,
- bool isLeak=false);
+ ExplodedNode *n, SymbolRef sym, bool isLeak = false,
+ bool IsReleaseUnowned = false);
RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
ExplodedNode *n, SymbolRef sym,