aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp4
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp32
-rw-r--r--clang/lib/AST/ByteCode/Compiler.h1
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp82
-rw-r--r--clang/lib/AST/ByteCode/Interp.h63
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp71
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp2
-rw-r--r--clang/lib/AST/ByteCode/Opcodes.td4
-rw-r--r--clang/lib/AST/ByteCode/Pointer.cpp17
-rw-r--r--clang/lib/AST/ByteCode/Pointer.h25
-rw-r--r--clang/lib/AST/Expr.cpp6
-rw-r--r--clang/lib/AST/ExprCXX.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp15
-rw-r--r--clang/lib/AST/OpenACCClause.cpp75
-rw-r--r--clang/lib/AST/ParentMap.cpp33
-rw-r--r--clang/lib/AST/StmtOpenACC.cpp40
-rw-r--r--clang/lib/AST/StmtPrinter.cpp6
-rw-r--r--clang/lib/AST/StmtProfile.cpp27
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp25
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp3
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp3
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp57
-rw-r--r--clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp21
-rw-r--r--clang/lib/Basic/Builtins.cpp4
-rw-r--r--clang/lib/Basic/CodeGenOptions.cpp2
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp2
-rw-r--r--clang/lib/Basic/Targets/AArch64.h2
-rw-r--r--clang/lib/Basic/Targets/OSTargets.cpp3
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp4
-rw-r--r--clang/lib/Basic/Targets/RISCV.h2
-rw-r--r--clang/lib/Basic/Targets/SPIR.cpp13
-rw-r--r--clang/lib/Basic/Targets/SPIR.h2
-rw-r--r--clang/lib/Basic/Targets/X86.cpp16
-rw-r--r--clang/lib/Basic/Targets/X86.h2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp42
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRAttrs.cpp172
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRDialect.cpp107
-rw-r--r--clang/lib/CIR/Dialect/IR/CMakeLists.txt1
-rw-r--r--clang/lib/CIR/Interfaces/CMakeLists.txt1
-rw-r--r--clang/lib/CodeGen/BackendConsumer.h34
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp6
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp80
-rw-r--r--clang/lib/CodeGen/CGCall.cpp6
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp8
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h2
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp5
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.cpp2
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.h3
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp52
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp67
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h34
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp18
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.cpp23
-rw-r--r--clang/lib/CodeGen/SanitizerMetadata.cpp4
-rw-r--r--clang/lib/CodeGen/Targets/AArch64.cpp17
-rw-r--r--clang/lib/CodeGen/Targets/AMDGPU.cpp6
-rw-r--r--clang/lib/CodeGen/Targets/NVPTX.cpp39
-rw-r--r--clang/lib/CodeGen/Targets/SPIR.cpp37
-rw-r--r--clang/lib/Driver/Action.cpp8
-rw-r--r--clang/lib/Driver/CMakeLists.txt2
-rw-r--r--clang/lib/Driver/Compilation.cpp9
-rw-r--r--clang/lib/Driver/Driver.cpp141
-rw-r--r--clang/lib/Driver/ToolChain.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp87
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp13
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp121
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.h76
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp8
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.h5
-rw-r--r--clang/lib/Driver/ToolChains/Linux.cpp5
-rw-r--r--clang/lib/Driver/ToolChains/Linux.h2
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp7
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.h5
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/SPIRV.h2
-rw-r--r--clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp34
-rw-r--r--clang/lib/Driver/ToolChains/SPIRVOpenMP.h29
-rw-r--r--clang/lib/Driver/ToolChains/SYCL.cpp154
-rw-r--r--clang/lib/Driver/ToolChains/SYCL.h77
-rw-r--r--clang/lib/Format/AffectedRangeManager.cpp10
-rw-r--r--clang/lib/Format/AffectedRangeManager.h4
-rw-r--r--clang/lib/Format/Format.cpp27
-rw-r--r--clang/lib/Format/FormatToken.h3
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp9
-rw-r--r--clang/lib/Format/FormatTokenLexer.h3
-rw-r--r--clang/lib/Format/MatchFilePath.cpp38
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp63
-rw-r--r--clang/lib/Format/TokenAnnotator.h8
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp168
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp27
-rw-r--r--clang/lib/Format/UnwrappedLineParser.h2
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp21
-rw-r--r--clang/lib/Frontend/DependencyFile.cpp22
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp6
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp5
-rw-r--r--clang/lib/Lex/InitHeaderSearch.cpp2
-rw-r--r--clang/lib/Parse/ParseOpenACC.cpp12
-rw-r--r--clang/lib/Sema/CMakeLists.txt1
-rw-r--r--clang/lib/Sema/Sema.cpp2
-rw-r--r--clang/lib/Sema/SemaARM.cpp24
-rw-r--r--clang/lib/Sema/SemaAttr.cpp4
-rw-r--r--clang/lib/Sema/SemaChecking.cpp3
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp7
-rw-r--r--clang/lib/Sema/SemaInit.cpp9
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp163
-rw-r--r--clang/lib/Sema/SemaOverload.cpp23
-rw-r--r--clang/lib/Sema/SemaSPIRV.cpp57
-rw-r--r--clang/lib/Sema/SemaStmt.cpp46
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp19
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp5
-rw-r--r--clang/lib/Sema/TreeTransform.h126
-rw-r--r--clang/lib/Serialization/ASTReader.cpp22
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp3
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp20
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp28
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp5
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp12
-rw-r--r--clang/lib/Serialization/GeneratePCH.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/CoreEngine.cpp27
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp60
-rw-r--r--clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Core/SymbolManager.cpp25
-rw-r--r--clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp38
125 files changed, 2709 insertions, 691 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8b4ae58..b10513f 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6376,7 +6376,7 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
}
QualType ASTContext::getUnconstrainedType(QualType T) const {
- QualType CanonT = T.getCanonicalType();
+ QualType CanonT = T.getNonPackExpansionType().getCanonicalType();
// Remove a type-constraint from a top-level auto or decltype(auto).
if (auto *AT = CanonT->getAs<AutoType>()) {
@@ -14357,7 +14357,7 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
// corresponding backend features (which may contain duplicates).
static std::vector<std::string> getFMVBackendFeaturesFor(
const llvm::SmallVectorImpl<StringRef> &FMVFeatStrings) {
- std::vector<std::string> BackendFeats{{"+fmv"}};
+ std::vector<std::string> BackendFeats;
llvm::AArch64::ExtensionSet FeatureBits;
for (StringRef F : FMVFeatStrings)
if (auto FMVExt = llvm::AArch64::parseFMVExtension(F))
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 68c75b0..036f960 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3427,6 +3427,38 @@ bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) {
}
template <class Emitter>
+bool Compiler<Emitter>::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
+ const Type *TypeInfoType = E->getType().getTypePtr();
+
+ if (!E->isPotentiallyEvaluated()) {
+ if (DiscardResult)
+ return true;
+
+ if (E->isTypeOperand())
+ return this->emitGetTypeid(
+ E->getTypeOperand(Ctx.getASTContext()).getTypePtr(), TypeInfoType, E);
+ return this->emitGetTypeid(E->getExprOperand()->getType().getTypePtr(),
+ TypeInfoType, E);
+ }
+
+ // Otherwise, we need to evaluate the expression operand.
+ assert(E->getExprOperand());
+ assert(E->getExprOperand()->isLValue());
+
+ if (!Ctx.getLangOpts().CPlusPlus20 && !this->emitDiagTypeid(E))
+ return false;
+
+ if (!this->visit(E->getExprOperand()))
+ return false;
+
+ if (!this->emitGetTypeidPtr(TypeInfoType, E))
+ return false;
+ if (DiscardResult)
+ return this->emitPopPtr(E);
+ return true;
+}
+
+template <class Emitter>
bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
assert(Ctx.getLangOpts().CPlusPlus);
return this->emitConstBool(E->getValue(), E);
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 2a94f5e..71765b1 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -205,6 +205,7 @@ public:
bool VisitCXXNewExpr(const CXXNewExpr *E);
bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
bool VisitBlockExpr(const BlockExpr *E);
+ bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
// Statements.
bool visitCompoundStmt(const CompoundStmt *S);
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 7c77520..cb0ce886 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1154,6 +1154,53 @@ bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
return false;
}
+static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ uint32_t Off) {
+ if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
+ !CheckNull(S, OpPC, Ptr, CSK_Field))
+ return false;
+
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+ if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
+ return false;
+
+ if (Ptr.isIntegralPointer()) {
+ S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
+ return true;
+ }
+
+ if (!Ptr.isBlockPointer()) {
+ // FIXME: The only time we (seem to) get here is when trying to access a
+ // field of a typeid pointer. In that case, we're supposed to diagnose e.g.
+ // `typeid(int).name`, but we currently diagnose `&typeid(int)`.
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_access_unreadable_object)
+ << AK_Read << Ptr.toDiagnosticString(S.getASTContext());
+ return false;
+ }
+
+ if (Off > Ptr.block()->getSize())
+ return false;
+
+ S.Stk.push<Pointer>(Ptr.atField(Off));
+ return true;
+}
+
+bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const auto &Ptr = S.Stk.peek<Pointer>();
+ return getField(S, OpPC, Ptr, Off);
+}
+
+bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const auto &Ptr = S.Stk.pop<Pointer>();
+ return getField(S, OpPC, Ptr, Off);
+}
+
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
const Pointer &ThisPtr) {
assert(Func->isConstructor());
@@ -1595,6 +1642,41 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
return false;
}
+bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
+ const Type *TypeInfoType) {
+ S.Stk.push<Pointer>(TypePtr, TypeInfoType);
+ return true;
+}
+
+bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
+ const auto &P = S.Stk.pop<Pointer>();
+
+ if (!P.isBlockPointer())
+ return false;
+
+ if (P.isDummy()) {
+ QualType StarThisType =
+ S.getASTContext().getLValueReferenceType(P.getType());
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_polymorphic_unknown_dynamic_type)
+ << AK_TypeId
+ << P.toAPValue(S.getASTContext())
+ .getAsString(S.getASTContext(), StarThisType);
+ return false;
+ }
+
+ S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType);
+ return true;
+}
+
+bool DiagTypeid(InterpState &S, CodePtr OpPC) {
+ const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));
+ S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
+ return false;
+}
+
// https://github.com/llvm/llvm-project/issues/102513
#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 8461d1e..d2aec69 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1526,61 +1526,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
/// 1) Peeks a Pointer
/// 2) Pushes Pointer.atField(Off) on the stack
-inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
- const Pointer &Ptr = S.Stk.peek<Pointer>();
-
- if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
- !CheckNull(S, OpPC, Ptr, CSK_Field))
- return false;
-
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckRange(S, OpPC, Ptr, CSK_Field))
- return false;
- if (!CheckArray(S, OpPC, Ptr))
- return false;
- if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
- return false;
-
- if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
- return false;
-
- if (Ptr.isIntegralPointer()) {
- S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
- return true;
- }
-
- S.Stk.push<Pointer>(Ptr.atField(Off));
- return true;
-}
-
-inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
- const Pointer &Ptr = S.Stk.pop<Pointer>();
-
- if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
- !CheckNull(S, OpPC, Ptr, CSK_Field))
- return false;
-
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckRange(S, OpPC, Ptr, CSK_Field))
- return false;
- if (!CheckArray(S, OpPC, Ptr))
- return false;
- if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
- return false;
-
- if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
- return false;
-
- if (Ptr.isIntegralPointer()) {
- S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
- return true;
- }
-
- S.Stk.push<Pointer>(Ptr.atField(Off));
- return true;
-}
+bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
+bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
if (S.checkingPotentialConstantExpression())
@@ -3087,6 +3034,12 @@ inline bool BitCast(InterpState &S, CodePtr OpPC) {
return true;
}
+/// Typeid support.
+bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
+ const Type *TypeInfoType);
+bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
+bool DiagTypeid(InterpState &S, CodePtr OpPC);
+
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 2ae91fe..0d52083 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/SipHash.h"
namespace clang {
@@ -154,7 +155,7 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
if (S.getLangOpts().CPlusPlus11)
S.CCEDiag(Loc, diag::note_constexpr_invalid_function)
<< /*isConstexpr=*/0 << /*isConstructor=*/0
- << ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str();
+ << S.getASTContext().BuiltinInfo.getQuotedName(ID);
else
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
@@ -1543,9 +1544,10 @@ static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC,
if (Res.isInvalid()) {
C.cleanup();
Stk.clear();
+ return returnInt(false);
}
- if (!Res.isInvalid() && !Res.empty()) {
+ if (!Res.empty()) {
const APValue &LV = Res.toAPValue();
if (LV.isLValue()) {
APValue::LValueBase Base = LV.getLValueBase();
@@ -1837,6 +1839,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
Pointer DestPtr = getParam<Pointer>(Frame, 0);
+ const ASTContext &ASTCtx = S.getASTContext();
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
@@ -1857,34 +1860,63 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
- << DiagPtr.toDiagnosticString(S.getASTContext());
+ << DiagPtr.toDiagnosticString(ASTCtx);
return false;
}
- QualType ElemType;
- if (DestPtr.getFieldDesc()->isArray())
- ElemType = DestPtr.getFieldDesc()->getElemQualType();
- else
- ElemType = DestPtr.getType();
+ // Can't read from dummy pointers.
+ if (DestPtr.isDummy() || SrcPtr.isDummy())
+ return false;
- unsigned ElemSize =
- S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
- if (Size.urem(ElemSize) != 0) {
+ QualType DestElemType;
+ size_t RemainingDestElems;
+ if (DestPtr.getFieldDesc()->isArray()) {
+ DestElemType = DestPtr.getFieldDesc()->getElemQualType();
+ RemainingDestElems = DestPtr.isUnknownSizeArray()
+ ? 0
+ : (DestPtr.getNumElems() - DestPtr.getIndex());
+ } else {
+ DestElemType = DestPtr.getType();
+ RemainingDestElems = 1;
+ }
+ unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
+
+ if (Size.urem(DestElemSize) != 0) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_memcpy_unsupported)
- << Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize;
+ << Move << /*IsWchar=*/false << 0 << DestElemType << Size
+ << DestElemSize;
return false;
}
QualType SrcElemType;
- if (SrcPtr.getFieldDesc()->isArray())
+ size_t RemainingSrcElems;
+ if (SrcPtr.getFieldDesc()->isArray()) {
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
- else
+ RemainingSrcElems = SrcPtr.isUnknownSizeArray()
+ ? 0
+ : (SrcPtr.getNumElems() - SrcPtr.getIndex());
+ } else {
SrcElemType = SrcPtr.getType();
+ RemainingSrcElems = 1;
+ }
+ unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
- if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
+ if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
- << Move << SrcElemType << ElemType;
+ << Move << SrcElemType << DestElemType;
+ return false;
+ }
+
+ // Check if we have enough elements to read from and write to/
+ size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
+ size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
+ if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {
+ APInt N = Size.udiv(DestElemSize);
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_unsupported)
+ << Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
+ << DestElemType << toString(N, 10, /*Signed=*/false);
return false;
}
@@ -1902,10 +1934,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
}
}
- // As a last resort, reject dummy pointers.
- if (DestPtr.isDummy() || SrcPtr.isDummy())
- return false;
- assert(Size.getZExtValue() % ElemSize == 0);
+ assert(Size.getZExtValue() % DestElemSize == 0);
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
return false;
@@ -1948,7 +1977,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
!isOneByteCharacterType(PtrB.getType()))) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_memcmp_unsupported)
- << ("'" + ASTCtx.BuiltinInfo.getName(ID) + "'").str() << PtrA.getType()
+ << ASTCtx.BuiltinInfo.getQuotedName(ID) << PtrA.getType()
<< PtrB.getType();
return false;
}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 0fc94e1..57c1fab 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -110,7 +110,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
if (FieldDesc->isCompositeArray()) {
QualType ElemType = FieldDesc->getElemQualType();
Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
- for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
+ for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
Offset += ElemSize;
if (Offset >= BitsToRead)
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 123c21f..4b0c902 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -850,3 +850,7 @@ def BitCastPrim : Opcode {
}
def BitCast : Opcode;
+
+def GetTypeid : Opcode { let Args = [ArgTypePtr, ArgTypePtr]; }
+def GetTypeidPtr : Opcode { let Args = [ArgTypePtr]; }
+def DiagTypeid : Opcode;
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 01e6423..ec4756f 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -96,6 +96,8 @@ void Pointer::operator=(const Pointer &P) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
+ } else if (P.isTypeidPointer()) {
+ PointeeStorage.Typeid = P.PointeeStorage.Typeid;
} else {
assert(false && "Unhandled storage kind");
}
@@ -132,6 +134,8 @@ void Pointer::operator=(Pointer &&P) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
+ } else if (P.isTypeidPointer()) {
+ PointeeStorage.Typeid = P.PointeeStorage.Typeid;
} else {
assert(false && "Unhandled storage kind");
}
@@ -151,6 +155,14 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
if (isFunctionPointer())
return asFunctionPointer().toAPValue(ASTCtx);
+ if (isTypeidPointer()) {
+ TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
+ return APValue(
+ APValue::LValueBase::getTypeInfo(
+ TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
+ CharUnits::Zero(), APValue::NoLValuePath{});
+ }
+
// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
APValue::LValueBase Base;
@@ -304,6 +316,9 @@ void Pointer::print(llvm::raw_ostream &OS) const {
case Storage::Fn:
OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
<< " }";
+ break;
+ case Storage::Typeid:
+ OS << "(Typeid)";
}
}
@@ -450,6 +465,8 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
return true;
if (A.isFunctionPointer() && B.isFunctionPointer())
return true;
+ if (A.isTypeidPointer() && B.isTypeidPointer())
+ return true;
if (A.isIntegralPointer() || B.isIntegralPointer())
return A.getSource() == B.getSource();
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 0d467c2..ef03c12 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -49,7 +49,12 @@ struct IntPointer {
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;
};
-enum class Storage { Block, Int, Fn };
+struct TypeidPointer {
+ const Type *TypePtr;
+ const Type *TypeInfoType;
+};
+
+enum class Storage { Block, Int, Fn, Typeid };
/// A pointer to a memory block, live or dead.
///
@@ -107,6 +112,11 @@ public:
: Offset(Offset), StorageKind(Storage::Fn) {
PointeeStorage.Fn = FunctionPointer(F);
}
+ Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
+ : Offset(Offset), StorageKind(Storage::Typeid) {
+ PointeeStorage.Typeid.TypePtr = TypePtr;
+ PointeeStorage.Typeid.TypeInfoType = TypeInfoType;
+ }
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
~Pointer();
@@ -263,6 +273,8 @@ public:
return asBlockPointer().Pointee == nullptr;
if (isFunctionPointer())
return asFunctionPointer().isZero();
+ if (isTypeidPointer())
+ return false;
assert(isIntegralPointer());
return asIntPointer().Value == 0 && Offset == 0;
}
@@ -284,7 +296,7 @@ public:
const Descriptor *getDeclDesc() const {
if (isIntegralPointer())
return asIntPointer().Desc;
- if (isFunctionPointer())
+ if (isFunctionPointer() || isTypeidPointer())
return nullptr;
assert(isBlockPointer());
@@ -337,6 +349,9 @@ public:
/// Returns the type of the innermost field.
QualType getType() const {
+ if (isTypeidPointer())
+ return QualType(PointeeStorage.Typeid.TypeInfoType, 0);
+
if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
// Unfortunately, complex and vector types are not array types in clang,
// but they are for us.
@@ -437,7 +452,7 @@ public:
}
/// Pointer points directly to a block.
bool isRoot() const {
- if (isZero() || isIntegralPointer())
+ if (isZero() || !isBlockPointer())
return true;
return (asBlockPointer().Base ==
asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||
@@ -467,6 +482,7 @@ public:
bool isBlockPointer() const { return StorageKind == Storage::Block; }
bool isIntegralPointer() const { return StorageKind == Storage::Int; }
bool isFunctionPointer() const { return StorageKind == Storage::Fn; }
+ bool isTypeidPointer() const { return StorageKind == Storage::Typeid; }
/// Returns the record descriptor of a class.
const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
@@ -605,7 +621,7 @@ public:
/// Checks if the index is one past end.
bool isOnePastEnd() const {
- if (isIntegralPointer() || isFunctionPointer())
+ if (!isBlockPointer())
return false;
if (!asBlockPointer().Pointee)
@@ -746,6 +762,7 @@ private:
BlockPointer BS;
IntPointer Int;
FunctionPointer Fn;
+ TypeidPointer Typeid;
} PointeeStorage;
Storage StorageKind = Storage::Int;
};
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 8c8ccdb..ba66d36 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1618,9 +1618,9 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
std::pair<const NamedDecl *, const Attr *>
CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
// If the callee is marked nodiscard, return that attribute
- const Decl *D = getCalleeDecl();
- if (const auto *A = D->getAttr<WarnUnusedResultAttr>())
- return {nullptr, A};
+ if (const Decl *D = getCalleeDecl())
+ if (const auto *A = D->getAttr<WarnUnusedResultAttr>())
+ return {nullptr, A};
// If the return type is a struct, union, or enum that is marked nodiscard,
// then return the return type attribute.
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index fc09d24..5bf5d6a 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1722,7 +1722,7 @@ PackIndexingExpr *PackIndexingExpr::Create(
if (Index && FullySubstituted && !SubstitutedExprs.empty())
Type = SubstitutedExprs[*Index]->getType();
else
- Type = Context.DependentTy;
+ Type = PackIdExpr->getType();
void *Storage =
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index dd75dca..e220f69 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9858,7 +9858,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/ 0 << /*isConstructor*/ 0
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp);
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
[[fallthrough]];
@@ -9903,8 +9903,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// FIXME: We can compare the bytes in the correct order.
if (IsRawByte && !isOneByteCharacterType(CharTy)) {
Info.FFDiag(E, diag::note_constexpr_memchr_unsupported)
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
- << CharTy;
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp) << CharTy;
return false;
}
// Figure out what value we're actually looking for (after converting to
@@ -9966,7 +9965,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/ 0 << /*isConstructor*/ 0
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp);
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
[[fallthrough]];
@@ -13241,7 +13240,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/ 0 << /*isConstructor*/ 0
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp);
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
[[fallthrough]];
@@ -13266,7 +13265,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/ 0 << /*isConstructor*/ 0
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp);
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
[[fallthrough]];
@@ -13321,8 +13320,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
!(isOneByteCharacterType(CharTy1) && isOneByteCharacterType(CharTy2))) {
// FIXME: Consider using our bit_cast implementation to support this.
Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported)
- << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
- << CharTy1 << CharTy2;
+ << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp) << CharTy1
+ << CharTy2;
return false;
}
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index d69fab5..da63b47 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -20,7 +20,7 @@ using namespace clang;
bool OpenACCClauseWithParams::classof(const OpenACCClause *C) {
return OpenACCDeviceTypeClause::classof(C) ||
OpenACCClauseWithCondition::classof(C) ||
- OpenACCClauseWithExprs::classof(C);
+ OpenACCClauseWithExprs::classof(C) || OpenACCSelfClause::classof(C);
}
bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) {
return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) ||
@@ -41,12 +41,13 @@ bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) {
OpenACCReductionClause::classof(C) || OpenACCCreateClause::classof(C);
}
bool OpenACCClauseWithCondition::classof(const OpenACCClause *C) {
- return OpenACCIfClause::classof(C) || OpenACCSelfClause::classof(C);
+ return OpenACCIfClause::classof(C);
}
bool OpenACCClauseWithSingleIntExpr::classof(const OpenACCClause *C) {
return OpenACCNumWorkersClause::classof(C) ||
OpenACCVectorLengthClause::classof(C) ||
OpenACCDeviceNumClause::classof(C) ||
+ OpenACCDefaultAsyncClause::classof(C) ||
OpenACCVectorClause::classof(C) || OpenACCWorkerClause::classof(C) ||
OpenACCCollapseClause::classof(C) || OpenACCAsyncClause::classof(C);
}
@@ -86,19 +87,43 @@ OpenACCSelfClause *OpenACCSelfClause::Create(const ASTContext &C,
SourceLocation LParenLoc,
Expr *ConditionExpr,
SourceLocation EndLoc) {
- void *Mem = C.Allocate(sizeof(OpenACCIfClause), alignof(OpenACCIfClause));
+ void *Mem = C.Allocate(OpenACCSelfClause::totalSizeToAlloc<Expr *>(1));
return new (Mem)
OpenACCSelfClause(BeginLoc, LParenLoc, ConditionExpr, EndLoc);
}
+OpenACCSelfClause *OpenACCSelfClause::Create(const ASTContext &C,
+ SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ ArrayRef<Expr *> VarList,
+ SourceLocation EndLoc) {
+ void *Mem =
+ C.Allocate(OpenACCSelfClause::totalSizeToAlloc<Expr *>(VarList.size()));
+ return new (Mem) OpenACCSelfClause(BeginLoc, LParenLoc, VarList, EndLoc);
+}
+
+OpenACCSelfClause::OpenACCSelfClause(SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ llvm::ArrayRef<Expr *> VarList,
+ SourceLocation EndLoc)
+ : OpenACCClauseWithParams(OpenACCClauseKind::Self, BeginLoc, LParenLoc,
+ EndLoc),
+ HasConditionExpr(std::nullopt), NumExprs(VarList.size()) {
+ std::uninitialized_copy(VarList.begin(), VarList.end(),
+ getTrailingObjects<Expr *>());
+}
+
OpenACCSelfClause::OpenACCSelfClause(SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expr *ConditionExpr, SourceLocation EndLoc)
- : OpenACCClauseWithCondition(OpenACCClauseKind::Self, BeginLoc, LParenLoc,
- ConditionExpr, EndLoc) {
+ : OpenACCClauseWithParams(OpenACCClauseKind::Self, BeginLoc, LParenLoc,
+ EndLoc),
+ HasConditionExpr(ConditionExpr != nullptr), NumExprs(1) {
assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() ||
ConditionExpr->getType()->isScalarType()) &&
"Condition expression type not scalar/dependent");
+ std::uninitialized_copy(&ConditionExpr, &ConditionExpr + 1,
+ getTrailingObjects<Expr *>());
}
OpenACCClause::child_range OpenACCClause::children() {
@@ -239,6 +264,27 @@ OpenACCDeviceNumClause *OpenACCDeviceNumClause::Create(const ASTContext &C,
return new (Mem) OpenACCDeviceNumClause(BeginLoc, LParenLoc, IntExpr, EndLoc);
}
+OpenACCDefaultAsyncClause::OpenACCDefaultAsyncClause(SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ Expr *IntExpr,
+ SourceLocation EndLoc)
+ : OpenACCClauseWithSingleIntExpr(OpenACCClauseKind::DefaultAsync, BeginLoc,
+ LParenLoc, IntExpr, EndLoc) {
+ assert((IntExpr->isInstantiationDependent() ||
+ IntExpr->getType()->isIntegerType()) &&
+ "default_async expression type not scalar/dependent");
+}
+
+OpenACCDefaultAsyncClause *
+OpenACCDefaultAsyncClause::Create(const ASTContext &C, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, Expr *IntExpr,
+ SourceLocation EndLoc) {
+ void *Mem = C.Allocate(sizeof(OpenACCDefaultAsyncClause),
+ alignof(OpenACCDefaultAsyncClause));
+ return new (Mem)
+ OpenACCDefaultAsyncClause(BeginLoc, LParenLoc, IntExpr, EndLoc);
+}
+
OpenACCWaitClause *OpenACCWaitClause::Create(
const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
@@ -533,9 +579,17 @@ void OpenACCClausePrinter::VisitIfClause(const OpenACCIfClause &C) {
void OpenACCClausePrinter::VisitSelfClause(const OpenACCSelfClause &C) {
OS << "self";
- if (const Expr *CondExpr = C.getConditionExpr()) {
+
+ if (C.isConditionExprClause()) {
+ if (const Expr *CondExpr = C.getConditionExpr()) {
+ OS << "(";
+ printExpr(CondExpr);
+ OS << ")";
+ }
+ } else {
OS << "(";
- printExpr(CondExpr);
+ llvm::interleaveComma(C.getVarList(), OS,
+ [&](const Expr *E) { printExpr(E); });
OS << ")";
}
}
@@ -575,6 +629,13 @@ void OpenACCClausePrinter::VisitDeviceNumClause(
OS << ")";
}
+void OpenACCClausePrinter::VisitDefaultAsyncClause(
+ const OpenACCDefaultAsyncClause &C) {
+ OS << "default_async(";
+ printExpr(C.getIntExpr());
+ OS << ")";
+}
+
void OpenACCClausePrinter::VisitAsyncClause(const OpenACCAsyncClause &C) {
OS << "async";
if (C.hasIntExpr()) {
diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp
index fd749b0..e62e71b 100644
--- a/clang/lib/AST/ParentMap.cpp
+++ b/clang/lib/AST/ParentMap.cpp
@@ -33,17 +33,19 @@ static void BuildParentMap(MapTy& M, Stmt* S,
switch (S->getStmtClass()) {
case Stmt::PseudoObjectExprClass: {
PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
-
- if (OVMode == OV_Opaque && M[POE->getSyntacticForm()])
- break;
-
- // If we are rebuilding the map, clear out any existing state.
- if (M[POE->getSyntacticForm()])
+ Expr *SF = POE->getSyntacticForm();
+
+ auto [Iter, Inserted] = M.try_emplace(SF, S);
+ if (!Inserted) {
+ // Nothing more to do in opaque mode if we are updating an existing map.
+ if (OVMode == OV_Opaque)
+ break;
+ // Update the entry in transparent mode, and clear existing state.
+ Iter->second = S;
for (Stmt *SubStmt : S->children())
- M[SubStmt] = nullptr;
-
- M[POE->getSyntacticForm()] = S;
- BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
+ M.erase(SubStmt);
+ }
+ BuildParentMap(M, SF, OV_Transparent);
for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),
E = POE->semantics_end();
@@ -78,10 +80,15 @@ static void BuildParentMap(MapTy& M, Stmt* S,
// The right thing to do is to give the OpaqueValueExpr its syntactic
// parent, then not reassign that when traversing the semantic expressions.
OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
- if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) {
- M[OVE->getSourceExpr()] = S;
- BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
+ Expr *SrcExpr = OVE->getSourceExpr();
+ auto [Iter, Inserted] = M.try_emplace(SrcExpr, S);
+ // Force update in transparent mode.
+ if (!Inserted && OVMode == OV_Transparent) {
+ Iter->second = S;
+ Inserted = true;
}
+ if (Inserted)
+ BuildParentMap(M, SrcExpr, OV_Transparent);
break;
}
case Stmt::CapturedStmtClass:
diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp
index e6d76ea..2b0ac71 100644
--- a/clang/lib/AST/StmtOpenACC.cpp
+++ b/clang/lib/AST/StmtOpenACC.cpp
@@ -265,3 +265,43 @@ OpenACCShutdownConstruct *OpenACCShutdownConstruct::Create(
new (Mem) OpenACCShutdownConstruct(Start, DirectiveLoc, End, Clauses);
return Inst;
}
+
+OpenACCSetConstruct *OpenACCSetConstruct::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses) {
+ void *Mem = C.Allocate(
+ OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>(NumClauses));
+ auto *Inst = new (Mem) OpenACCSetConstruct(NumClauses);
+ return Inst;
+}
+
+OpenACCSetConstruct *
+OpenACCSetConstruct::Create(const ASTContext &C, SourceLocation Start,
+ SourceLocation DirectiveLoc, SourceLocation End,
+ ArrayRef<const OpenACCClause *> Clauses) {
+ void *Mem =
+ C.Allocate(OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>(
+ Clauses.size()));
+ auto *Inst = new (Mem) OpenACCSetConstruct(Start, DirectiveLoc, End, Clauses);
+ return Inst;
+}
+
+OpenACCUpdateConstruct *
+OpenACCUpdateConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) {
+ void *Mem = C.Allocate(
+ OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>(
+ NumClauses));
+ auto *Inst = new (Mem) OpenACCUpdateConstruct(NumClauses);
+ return Inst;
+}
+
+OpenACCUpdateConstruct *
+OpenACCUpdateConstruct::Create(const ASTContext &C, SourceLocation Start,
+ SourceLocation DirectiveLoc, SourceLocation End,
+ ArrayRef<const OpenACCClause *> Clauses) {
+ void *Mem = C.Allocate(
+ OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>(
+ Clauses.size()));
+ auto *Inst =
+ new (Mem) OpenACCUpdateConstruct(Start, DirectiveLoc, End, Clauses);
+ return Inst;
+}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index c5d19f7..52bcb51 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1204,6 +1204,12 @@ void StmtPrinter::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) {
void StmtPrinter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
PrintOpenACCConstruct(S);
}
+void StmtPrinter::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) {
+ PrintOpenACCConstruct(S);
+}
+void StmtPrinter::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) {
+ PrintOpenACCConstruct(S);
+}
void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) {
Indent() << "#pragma acc wait";
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 27313f9..cd91a79 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2555,8 +2555,13 @@ void OpenACCClauseProfiler::VisitCreateClause(
}
void OpenACCClauseProfiler::VisitSelfClause(const OpenACCSelfClause &Clause) {
- if (Clause.hasConditionExpr())
- Profiler.VisitStmt(Clause.getConditionExpr());
+ if (Clause.isConditionExprClause()) {
+ if (Clause.hasConditionExpr())
+ Profiler.VisitStmt(Clause.getConditionExpr());
+ } else {
+ for (auto *E : Clause.getVarList())
+ Profiler.VisitStmt(E);
+ }
}
void OpenACCClauseProfiler::VisitFinalizeClause(
@@ -2650,6 +2655,11 @@ void OpenACCClauseProfiler::VisitDeviceNumClause(
Profiler.VisitStmt(Clause.getIntExpr());
}
+void OpenACCClauseProfiler::VisitDefaultAsyncClause(
+ const OpenACCDefaultAsyncClause &Clause) {
+ Profiler.VisitStmt(Clause.getIntExpr());
+}
+
void OpenACCClauseProfiler::VisitWorkerClause(
const OpenACCWorkerClause &Clause) {
if (Clause.hasIntExpr())
@@ -2769,6 +2779,19 @@ void StmtProfiler::VisitOpenACCShutdownConstruct(
P.VisitOpenACCClauseList(S->clauses());
}
+void StmtProfiler::VisitOpenACCSetConstruct(const OpenACCSetConstruct *S) {
+ VisitStmt(S);
+ OpenACCClauseProfiler P{*this};
+ P.VisitOpenACCClauseList(S->clauses());
+}
+
+void StmtProfiler::VisitOpenACCUpdateConstruct(
+ const OpenACCUpdateConstruct *S) {
+ VisitStmt(S);
+ OpenACCClauseProfiler P{*this};
+ P.VisitOpenACCClauseList(S->clauses());
+}
+
void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) {
VisitStmt(S);
}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 018147e..eedd8fa 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -414,6 +414,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
case OpenACCClauseKind::Detach:
case OpenACCClauseKind::Delete:
case OpenACCClauseKind::DeviceNum:
+ case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::DevicePtr:
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::FirstPrivate:
@@ -2930,7 +2931,6 @@ void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) {
OS << " " << S->getDirectiveKind();
}
void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
-
if (S->isOrphanedLoopConstruct())
OS << " <orphan>";
else
@@ -2939,37 +2939,44 @@ void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
void TextNodeDumper::VisitOpenACCCombinedConstruct(
const OpenACCCombinedConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCDataConstruct(const OpenACCDataConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCEnterDataConstruct(
const OpenACCEnterDataConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCExitDataConstruct(
const OpenACCExitDataConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCHostDataConstruct(
const OpenACCHostDataConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitOpenACCShutdownConstruct(
const OpenACCShutdownConstruct *S) {
- OS << " " << S->getDirectiveKind();
+ VisitOpenACCConstructStmt(S);
+}
+void TextNodeDumper::VisitOpenACCSetConstruct(const OpenACCSetConstruct *S) {
+ VisitOpenACCConstructStmt(S);
+}
+void TextNodeDumper::VisitOpenACCUpdateConstruct(
+ const OpenACCUpdateConstruct *S) {
+ VisitOpenACCConstructStmt(S);
}
void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 8c744ee..9c7943a 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1108,6 +1108,9 @@ const AstTypeMatcher<SubstTemplateTypeParmType> substTemplateTypeParmType;
const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType;
const AstTypeMatcher<InjectedClassNameType> injectedClassNameType;
const AstTypeMatcher<DecayedType> decayedType;
+const AstTypeMatcher<DependentNameType> dependentNameType;
+const AstTypeMatcher<DependentTemplateSpecializationType>
+ dependentTemplateSpecializationType;
AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasElementType,
AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType,
ComplexType));
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 685d626d..336d3a1 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -222,7 +222,9 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(decompositionDecl);
REGISTER_MATCHER(declCountIs);
REGISTER_MATCHER(declRefExpr);
+ REGISTER_MATCHER(dependentNameType);
REGISTER_MATCHER(dependentScopeDeclRefExpr);
+ REGISTER_MATCHER(dependentTemplateSpecializationType);
REGISTER_MATCHER(declStmt);
REGISTER_MATCHER(declaratorDecl);
REGISTER_MATCHER(decltypeType);
@@ -312,6 +314,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasDeducedType);
REGISTER_MATCHER(hasDefaultArgument);
REGISTER_MATCHER(hasDefinition);
+ REGISTER_MATCHER(hasDependentName);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
REGISTER_MATCHER(hasDirectBase);
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index da5dda0..e1394e2 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -25,8 +25,10 @@
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/Formula.h"
#include "clang/Analysis/FlowSensitive/RecordOps.h"
+#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
@@ -555,24 +557,25 @@ void handleConstMemberCall(const CallExpr *CE,
LatticeTransferState &State) {
// If the const method returns an optional or reference to an optional.
if (RecordLoc != nullptr && isSupportedOptionalType(CE->getType())) {
- StorageLocation *Loc =
+ const FunctionDecl *DirectCallee = CE->getDirectCallee();
+ if (DirectCallee == nullptr)
+ return;
+ StorageLocation &Loc =
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
- *RecordLoc, CE, State.Env, [&](StorageLocation &Loc) {
+ *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
setHasValue(cast<RecordStorageLocation>(Loc),
State.Env.makeAtomicBoolValue(), State.Env);
});
- if (Loc == nullptr)
- return;
if (CE->isGLValue()) {
// If the call to the const method returns a reference to an optional,
// link the call expression to the cached StorageLocation.
- State.Env.setStorageLocation(*CE, *Loc);
+ State.Env.setStorageLocation(*CE, Loc);
} else {
// If the call to the const method returns an optional by value, we
// need to use CopyRecord to link the optional to the result object
// of the call expression.
auto &ResultLoc = State.Env.getResultObjectLocation(*CE);
- copyRecord(*cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
+ copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
}
return;
}
@@ -1031,6 +1034,48 @@ auto buildTransferMatchSwitch() {
transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
})
+ // Smart-pointer-like operator* and operator-> calls that may look like
+ // const accessors (below) but need special handling to allow mixing
+ // the accessor calls.
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isSmartPointerLikeOperatorStar(),
+ [](const CXXOperatorCallExpr *E,
+ const MatchFinder::MatchResult &Result,
+ LatticeTransferState &State) {
+ transferSmartPointerLikeCachedDeref(
+ E,
+ dyn_cast_or_null<RecordStorageLocation>(
+ getLocBehindPossiblePointer(*E->getArg(0), State.Env)),
+ State, [](StorageLocation &Loc) {});
+ })
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isSmartPointerLikeOperatorArrow(),
+ [](const CXXOperatorCallExpr *E,
+ const MatchFinder::MatchResult &Result,
+ LatticeTransferState &State) {
+ transferSmartPointerLikeCachedGet(
+ E,
+ dyn_cast_or_null<RecordStorageLocation>(
+ getLocBehindPossiblePointer(*E->getArg(0), State.Env)),
+ State, [](StorageLocation &Loc) {});
+ })
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
+ isSmartPointerLikeValueMethodCall(),
+ [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &Result,
+ LatticeTransferState &State) {
+ transferSmartPointerLikeCachedDeref(
+ E, getImplicitObjectLocation(*E, State.Env), State,
+ [](StorageLocation &Loc) {});
+ })
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
+ isSmartPointerLikeGetMethodCall(),
+ [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &Result,
+ LatticeTransferState &State) {
+ transferSmartPointerLikeCachedGet(
+ E, getImplicitObjectLocation(*E, State.Env), State,
+ [](StorageLocation &Loc) {});
+ })
+
// const accessor calls
.CaseOfCFGStmt<CXXMemberCallExpr>(isZeroParamConstMemberCall(),
transferValue_ConstMemberCall)
diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
index a0c81aa..c58bd30 100644
--- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
+++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
@@ -132,6 +132,7 @@ ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {
callee(cxxMethodDecl(parameterCountIs(0), returns(pointerType()),
ofClass(smartPointerClassWithGetOrValue()))));
}
+
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() {
return cxxMemberCallExpr(callee(
cxxMethodDecl(parameterCountIs(0), returns(referenceType()),
@@ -144,4 +145,24 @@ ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall() {
ofClass(smartPointerClassWithGet()))));
}
+const FunctionDecl *
+getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {
+ const FunctionDecl *CanonicalCallee = nullptr;
+ const CXXMethodDecl *Callee =
+ cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
+ if (Callee == nullptr)
+ return nullptr;
+ const CXXRecordDecl *RD = Callee->getParent();
+ if (RD == nullptr)
+ return nullptr;
+ for (const auto *MD : RD->methods()) {
+ if (MD->getOverloadedOperator() == OO_Star && MD->isConst() &&
+ MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) {
+ CanonicalCallee = MD;
+ break;
+ }
+ }
+ return CanonicalCallee;
+}
+
} // namespace clang::dataflow
diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
index 8dd1888..5881837 100644
--- a/clang/lib/Basic/Builtins.cpp
+++ b/clang/lib/Basic/Builtins.cpp
@@ -163,6 +163,10 @@ void Builtin::Context::initializeBuiltins(IdentifierTable &Table,
}
}
+std::string Builtin::Context::getQuotedName(unsigned ID) const {
+ return (llvm::Twine("'") + getName(ID) + "'").str();
+}
+
unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {
const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V');
if (!WidthPos)
diff --git a/clang/lib/Basic/CodeGenOptions.cpp b/clang/lib/Basic/CodeGenOptions.cpp
index 79d7153..95e65ba 100644
--- a/clang/lib/Basic/CodeGenOptions.cpp
+++ b/clang/lib/Basic/CodeGenOptions.cpp
@@ -17,7 +17,6 @@ CodeGenOptions::CodeGenOptions() {
#include "clang/Basic/CodeGenOptions.def"
RelocationModel = llvm::Reloc::PIC_;
- memcpy(CoverageVersion, "408*", 4);
}
void CodeGenOptions::resetNonModularOptions(StringRef ModuleFormat) {
@@ -54,7 +53,6 @@ void CodeGenOptions::resetNonModularOptions(StringRef ModuleFormat) {
}
RelocationModel = llvm::Reloc::PIC_;
- memcpy(CoverageVersion, "408*", 4);
}
} // end namespace clang
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 53e102b..2b4b954d 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -714,7 +714,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
return std::nullopt;
}
-unsigned AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
+uint64_t AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return llvm::AArch64::getFMVPriority(Features);
}
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 68a8b1e..4e927c0 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -137,7 +137,7 @@ public:
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;
- unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
+ uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
bool useFP16ConversionIntrinsics() const override {
return false;
diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp
index 88c0541..6f98353 100644
--- a/clang/lib/Basic/Targets/OSTargets.cpp
+++ b/clang/lib/Basic/Targets/OSTargets.cpp
@@ -114,9 +114,6 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
assert(OsVersion.getMinor().value_or(0) < 100 &&
OsVersion.getSubminor().value_or(0) < 100 && "Invalid version!");
Builder.defineMacro("__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__", Str);
-
- // Tell users about the kernel if there is one.
- Builder.defineMacro("__MACH__");
}
PlatformMinVersion = OsVersion;
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index a541dfed..db23b0c 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -489,7 +489,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
return Ret;
}
-unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
+uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
// Priority is explicitly specified on RISC-V unlike on other targets, where
// it is derived by all the features of a specific version. Therefore if a
// feature contains the priority string, then return it immediately.
@@ -501,7 +501,7 @@ unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
Feature = RHS;
else
continue;
- unsigned Priority;
+ uint64_t Priority;
if (!Feature.getAsInteger(0, Priority))
return Priority;
}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index 68f10e7..bb3f3a5 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -122,7 +122,7 @@ public:
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
- unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
+ uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp
index 0403039..f242fed 100644
--- a/clang/lib/Basic/Targets/SPIR.cpp
+++ b/clang/lib/Basic/Targets/SPIR.cpp
@@ -13,11 +13,24 @@
#include "SPIR.h"
#include "AMDGPU.h"
#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "llvm/TargetParser/TargetParser.h"
using namespace clang;
using namespace clang::targets;
+static constexpr Builtin::Info BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#include "clang/Basic/BuiltinsSPIRV.inc"
+};
+
+ArrayRef<Builtin::Info> SPIRVTargetInfo::getTargetBuiltins() const {
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin);
+}
+
void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "SPIR", Opts);
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 85e4bd9..5a328b9c 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -313,7 +313,7 @@ public:
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"
"v256:256-v512:512-v1024:1024-n8:16:32:64-G1");
}
-
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
};
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 1b16888..40ad8fd 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -30,14 +30,6 @@ static constexpr Builtin::Info BuiltinInfoX86[] = {
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
-#include "clang/Basic/BuiltinsX86.def"
-
-#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
-#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/BuiltinsX86.inc"
#define BUILTIN(ID, TYPE, ATTRS) \
@@ -46,7 +38,7 @@ static constexpr Builtin::Info BuiltinInfoX86[] = {
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
-#include "clang/Basic/BuiltinsX86_64.def"
+#include "clang/Basic/BuiltinsX86_64.inc"
};
static const char *const GCCRegNames[] = {
@@ -1365,8 +1357,8 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
// correct, so it asserts if the value is out of range.
}
-unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
- auto getPriority = [](StringRef Feature) -> unsigned {
+uint64_t X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
+ auto getPriority = [](StringRef Feature) -> uint64_t {
// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
@@ -1380,7 +1372,7 @@ unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return getFeaturePriority(getFeature(Feature)) << 1;
};
- unsigned Priority = 0;
+ uint64_t Priority = 0;
for (StringRef Feature : Features)
if (!Feature.empty())
Priority = std::max(Priority, getPriority(Feature));
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 553c452..35aceb1 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -384,7 +384,7 @@ public:
return CPU != llvm::X86::CK_None;
}
- unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
+ uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
bool setFPMath(StringRef Name) override;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 416d532..2615ae3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -115,6 +115,48 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
identifier->getName(), type);
+ // TODO(CIR): This code for processing initial values is a placeholder
+ // until class ConstantEmitter is upstreamed and the code for processing
+ // constant expressions is filled out. Only the most basic handling of
+ // certain constant expressions is implemented for now.
+ const VarDecl *initDecl;
+ const Expr *initExpr = vd->getAnyInitializer(initDecl);
+ if (initExpr) {
+ mlir::Attribute initializer;
+ if (APValue *value = initDecl->evaluateValue()) {
+ switch (value->getKind()) {
+ case APValue::Int: {
+ initializer = builder.getAttr<cir::IntAttr>(type, value->getInt());
+ break;
+ }
+ case APValue::Float: {
+ initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat());
+ break;
+ }
+ case APValue::LValue: {
+ if (value->getLValueBase()) {
+ errorNYI(initExpr->getSourceRange(),
+ "non-null pointer initialization");
+ } else {
+ if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) {
+ initializer = builder.getConstPtrAttr(
+ ptrType, value->getLValueOffset().getQuantity());
+ } else {
+ llvm_unreachable(
+ "non-pointer variable initialized with a pointer");
+ }
+ }
+ break;
+ }
+ default:
+ errorNYI(initExpr->getSourceRange(), "unsupported initializer kind");
+ break;
+ }
+ } else {
+ errorNYI(initExpr->getSourceRange(), "non-constant initializer");
+ }
+ varOp.setInitialValueAttr(initializer);
+ }
theModule.push_back(varOp);
} else {
errorNYI(vd->getSourceRange().getBegin(),
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 7d42da1..8e8f7d5 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -12,6 +12,24 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "mlir/IR/DialectImplementation.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
+ mlir::Type ty);
+static mlir::ParseResult
+parseFloatLiteral(mlir::AsmParser &parser,
+ mlir::FailureOr<llvm::APFloat> &value,
+ cir::CIRFPTypeInterface fpType);
+
+static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
+ mlir::IntegerAttr &value);
+
+static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value);
+
+#define GET_ATTRDEF_CLASSES
+#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
+
using namespace mlir;
using namespace cir;
@@ -21,12 +39,155 @@ using namespace cir;
Attribute CIRDialect::parseAttribute(DialectAsmParser &parser,
Type type) const {
- // No attributes yet to parse
- return Attribute{};
+ llvm::SMLoc typeLoc = parser.getCurrentLocation();
+ llvm::StringRef mnemonic;
+ Attribute genAttr;
+ OptionalParseResult parseResult =
+ generatedAttributeParser(parser, &mnemonic, type, genAttr);
+ if (parseResult.has_value())
+ return genAttr;
+ parser.emitError(typeLoc, "unknown attribute in CIR dialect");
+ return Attribute();
}
void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
- // No attributes yet to print
+ if (failed(generatedAttributePrinter(attr, os)))
+ llvm_unreachable("unexpected CIR type kind");
+}
+
+//===----------------------------------------------------------------------===//
+// ConstPtrAttr definitions
+//===----------------------------------------------------------------------===//
+
+// TODO(CIR): Consider encoding the null value differently and use conditional
+// assembly format instead of custom parsing/printing.
+static ParseResult parseConstPtr(AsmParser &parser, mlir::IntegerAttr &value) {
+
+ if (parser.parseOptionalKeyword("null").succeeded()) {
+ value = mlir::IntegerAttr::get(
+ mlir::IntegerType::get(parser.getContext(), 64), 0);
+ return success();
+ }
+
+ return parser.parseAttribute(value);
+}
+
+static void printConstPtr(AsmPrinter &p, mlir::IntegerAttr value) {
+ if (!value.getInt())
+ p << "null";
+ else
+ p << value;
+}
+
+//===----------------------------------------------------------------------===//
+// IntAttr definitions
+//===----------------------------------------------------------------------===//
+
+Attribute IntAttr::parse(AsmParser &parser, Type odsType) {
+ mlir::APInt apValue;
+
+ if (!mlir::isa<IntType>(odsType))
+ return {};
+ auto type = mlir::cast<IntType>(odsType);
+
+ // Consume the '<' symbol.
+ if (parser.parseLess())
+ return {};
+
+ // Fetch arbitrary precision integer value.
+ if (type.isSigned()) {
+ int64_t value = 0;
+ if (parser.parseInteger(value)) {
+ parser.emitError(parser.getCurrentLocation(), "expected integer value");
+ } else {
+ apValue = mlir::APInt(type.getWidth(), value, type.isSigned(),
+ /*implicitTrunc=*/true);
+ if (apValue.getSExtValue() != value)
+ parser.emitError(parser.getCurrentLocation(),
+ "integer value too large for the given type");
+ }
+ } else {
+ uint64_t value = 0;
+ if (parser.parseInteger(value)) {
+ parser.emitError(parser.getCurrentLocation(), "expected integer value");
+ } else {
+ apValue = mlir::APInt(type.getWidth(), value, type.isSigned(),
+ /*implicitTrunc=*/true);
+ if (apValue.getZExtValue() != value)
+ parser.emitError(parser.getCurrentLocation(),
+ "integer value too large for the given type");
+ }
+ }
+
+ // Consume the '>' symbol.
+ if (parser.parseGreater())
+ return {};
+
+ return IntAttr::get(type, apValue);
+}
+
+void IntAttr::print(AsmPrinter &printer) const {
+ auto type = mlir::cast<IntType>(getType());
+ printer << '<';
+ if (type.isSigned())
+ printer << getSInt();
+ else
+ printer << getUInt();
+ printer << '>';
+}
+
+LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ Type type, APInt value) {
+ if (!mlir::isa<IntType>(type)) {
+ emitError() << "expected 'simple.int' type";
+ return failure();
+ }
+
+ auto intType = mlir::cast<IntType>(type);
+ if (value.getBitWidth() != intType.getWidth()) {
+ emitError() << "type and value bitwidth mismatch: " << intType.getWidth()
+ << " != " << value.getBitWidth();
+ return failure();
+ }
+
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// FPAttr definitions
+//===----------------------------------------------------------------------===//
+
+static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) {
+ p << value;
+}
+
+static ParseResult parseFloatLiteral(AsmParser &parser,
+ FailureOr<APFloat> &value,
+ CIRFPTypeInterface fpType) {
+
+ APFloat parsedValue(0.0);
+ if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
+ return failure();
+
+ value.emplace(parsedValue);
+ return success();
+}
+
+FPAttr FPAttr::getZero(Type type) {
+ return get(type,
+ APFloat::getZero(
+ mlir::cast<CIRFPTypeInterface>(type).getFloatSemantics()));
+}
+
+LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ CIRFPTypeInterface fpType, APFloat value) {
+ if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
+ APFloat::SemanticsToEnum(value.getSemantics())) {
+ emitError() << "floating-point semantics mismatch";
+ return failure();
+ }
+
+ return success();
}
//===----------------------------------------------------------------------===//
@@ -34,5 +195,8 @@ void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
//===----------------------------------------------------------------------===//
void CIRDialect::registerAttributes() {
- // No attributes yet to register
+ addAttributes<
+#define GET_ATTRDEF_LIST
+#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
+ >();
}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index dbdca1f..f98d8b6 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -12,6 +12,8 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+
#include "mlir/Support/LogicalResult.h"
#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"
@@ -33,12 +35,72 @@ void cir::CIRDialect::initialize() {
}
//===----------------------------------------------------------------------===//
+// ConstantOp
+//===----------------------------------------------------------------------===//
+
+static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
+ mlir::Attribute attrType) {
+ if (isa<cir::ConstPtrAttr>(attrType)) {
+ if (!mlir::isa<cir::PointerType>(opType))
+ return op->emitOpError(
+ "pointer constant initializing a non-pointer type");
+ return success();
+ }
+
+ if (mlir::isa<cir::IntAttr, cir::FPAttr>(attrType)) {
+ auto at = cast<TypedAttr>(attrType);
+ if (at.getType() != opType) {
+ return op->emitOpError("result type (")
+ << opType << ") does not match value type (" << at.getType()
+ << ")";
+ }
+ return success();
+ }
+
+ assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
+ return op->emitOpError("global with type ")
+ << cast<TypedAttr>(attrType).getType() << " not yet supported";
+}
+
+LogicalResult cir::ConstantOp::verify() {
+ // ODS already generates checks to make sure the result type is valid. We just
+ // need to additionally check that the value's attribute type is consistent
+ // with the result type.
+ return checkConstantTypes(getOperation(), getType(), getValue());
+}
+
+OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) {
+ return getValue();
+}
+
+//===----------------------------------------------------------------------===//
// GlobalOp
//===----------------------------------------------------------------------===//
-// TODO(CIR): The properties of global variables that require verification
-// haven't been implemented yet.
-mlir::LogicalResult cir::GlobalOp::verify() { return success(); }
+static ParseResult parseConstantValue(OpAsmParser &parser,
+ mlir::Attribute &valueAttr) {
+ NamedAttrList attr;
+ return parser.parseAttribute(valueAttr, "value", attr);
+}
+
+static void printConstant(OpAsmPrinter &p, Attribute value) {
+ p.printAttribute(value);
+}
+
+mlir::LogicalResult cir::GlobalOp::verify() {
+ // Verify that the initial value, if present, is either a unit attribute or
+ // an attribute CIR supports.
+ if (getInitialValue().has_value()) {
+ if (checkConstantTypes(getOperation(), getSymType(), *getInitialValue())
+ .failed())
+ return failure();
+ }
+
+ // TODO(CIR): Many other checks for properties that haven't been upstreamed
+ // yet.
+
+ return success();
+}
void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
llvm::StringRef sym_name, mlir::Type sym_type) {
@@ -48,6 +110,45 @@ void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
mlir::TypeAttr::get(sym_type));
}
+static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op,
+ TypeAttr type,
+ Attribute initAttr) {
+ if (!op.isDeclaration()) {
+ p << "= ";
+ // This also prints the type...
+ if (initAttr)
+ printConstant(p, initAttr);
+ } else {
+ p << ": " << type;
+ }
+}
+
+static ParseResult
+parseGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr,
+ Attribute &initialValueAttr) {
+ mlir::Type opTy;
+ if (parser.parseOptionalEqual().failed()) {
+ // Absence of equal means a declaration, so we need to parse the type.
+ // cir.global @a : !cir.int<s, 32>
+ if (parser.parseColonType(opTy))
+ return failure();
+ } else {
+ // Parse constant with initializer, examples:
+ // cir.global @y = #cir.fp<1.250000e+00> : !cir.double
+ // cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>
+ if (parseConstantValue(parser, initialValueAttr).failed())
+ return failure();
+
+ assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&
+ "Non-typed attrs shouldn't appear here.");
+ auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);
+ opTy = typedAttr.getType();
+ }
+
+ typeAttr = TypeAttr::get(opTy);
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index df60f69..baf8bff 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -5,6 +5,7 @@ add_clang_library(MLIRCIR
DEPENDS
MLIRCIROpsIncGen
+ MLIRCIRAttrsEnumsGen
LINK_LIBS PUBLIC
MLIRIR
diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt
index fcd8b69..b826bf6 100644
--- a/clang/lib/CIR/Interfaces/CMakeLists.txt
+++ b/clang/lib/CIR/Interfaces/CMakeLists.txt
@@ -5,6 +5,7 @@ add_clang_library(MLIRCIRInterfaces
${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces
DEPENDS
+ MLIRCIRAttrsEnumsGen
MLIRCIRFPTypeInterfaceIncGen
LINK_LIBS
diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h
index a023d29..d932a78 100644
--- a/clang/lib/CodeGen/BackendConsumer.h
+++ b/clang/lib/CodeGen/BackendConsumer.h
@@ -29,17 +29,16 @@ class BackendConsumer : public ASTConsumer {
virtual void anchor();
DiagnosticsEngine &Diags;
- BackendAction Action;
const HeaderSearchOptions &HeaderSearchOpts;
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
std::unique_ptr<raw_pwrite_stream> AsmOutStream;
- ASTContext *Context;
+ ASTContext *Context = nullptr;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
llvm::Timer LLVMIRGeneration;
- unsigned LLVMIRGenerationRefCount;
+ unsigned LLVMIRGenerationRefCount = 0;
/// True if we've finished generating IR. This prevents us from generating
/// additional LLVM IR after emitting output in HandleTranslationUnit. This
@@ -48,6 +47,8 @@ class BackendConsumer : public ASTConsumer {
bool TimerIsEnabled = false;
+ BackendAction Action;
+
std::unique_ptr<CodeGenerator> Gen;
SmallVector<LinkModule, 4> LinkModules;
@@ -69,29 +70,12 @@ class BackendConsumer : public ASTConsumer {
llvm::Module *CurLinkModule = nullptr;
public:
- BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts,
- const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts, const LangOptions &LangOpts,
- const std::string &InFile,
- SmallVector<LinkModule, 4> LinkModules,
- std::unique_ptr<raw_pwrite_stream> OS, llvm::LLVMContext &C,
- CoverageSourceInfo *CoverageInfo = nullptr);
-
- // This constructor is used in installing an empty BackendConsumer
- // to use the clang diagnostic handler for IR input files. It avoids
- // initializing the OS field.
- BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
+ BackendConsumer(const CompilerInstance &CI, BackendAction Action,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts,
- const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts, const LangOptions &LangOpts,
- llvm::Module *Module, SmallVector<LinkModule, 4> LinkModules,
- llvm::LLVMContext &C,
- CoverageSourceInfo *CoverageInfo = nullptr);
+ llvm::LLVMContext &C, SmallVector<LinkModule, 4> LinkModules,
+ StringRef InFile, std::unique_ptr<raw_pwrite_stream> OS,
+ CoverageSourceInfo *CoverageInfo,
+ llvm::Module *CurLinkModule = nullptr);
llvm::Module *getModule() const;
std::unique_ptr<llvm::Module> takeModule();
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 04358cd..2dbab78 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -736,10 +736,8 @@ static void addSanitizers(const Triple &TargetTriple,
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
- if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
- MPM.addPass(ModuleTypeSanitizerPass());
- MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
- }
+ if (LangOpts.Sanitize.has(SanitizerKind::Type))
+ MPM.addPass(TypeSanitizerPass());
if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
MPM.addPass(NumericalStabilitySanitizerPass());
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4d4b742..573be93 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -835,6 +835,38 @@ static Value *emitFrexpBuiltin(CodeGenFunction &CGF, const CallExpr *E,
return CGF.Builder.CreateExtractValue(Call, 0);
}
+static void emitSincosBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+ llvm::Intrinsic::ID IntrinsicID) {
+ llvm::Value *Val = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *Dest0 = CGF.EmitScalarExpr(E->getArg(1));
+ llvm::Value *Dest1 = CGF.EmitScalarExpr(E->getArg(2));
+
+ llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID, {Val->getType()});
+ llvm::Value *Call = CGF.Builder.CreateCall(F, Val);
+
+ llvm::Value *SinResult = CGF.Builder.CreateExtractValue(Call, 0);
+ llvm::Value *CosResult = CGF.Builder.CreateExtractValue(Call, 1);
+
+ QualType DestPtrType = E->getArg(1)->getType()->getPointeeType();
+ LValue SinLV = CGF.MakeNaturalAlignAddrLValue(Dest0, DestPtrType);
+ LValue CosLV = CGF.MakeNaturalAlignAddrLValue(Dest1, DestPtrType);
+
+ llvm::StoreInst *StoreSin =
+ CGF.Builder.CreateStore(SinResult, SinLV.getAddress());
+ llvm::StoreInst *StoreCos =
+ CGF.Builder.CreateStore(CosResult, CosLV.getAddress());
+
+ // Mark the two stores as non-aliasing with each other. The order of stores
+ // emitted by this builtin is arbitrary, enforcing a particular order will
+ // prevent optimizations later on.
+ llvm::MDBuilder MDHelper(CGF.getLLVMContext());
+ MDNode *Domain = MDHelper.createAnonymousAliasScopeDomain();
+ MDNode *AliasScope = MDHelper.createAnonymousAliasScope(Domain);
+ MDNode *AliasScopeList = MDNode::get(Call->getContext(), AliasScope);
+ StoreSin->setMetadata(LLVMContext::MD_alias_scope, AliasScopeList);
+ StoreCos->setMetadata(LLVMContext::MD_noalias, AliasScopeList);
+}
+
/// EmitFAbs - Emit a call to @llvm.fabs().
static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) {
Function *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType());
@@ -3232,6 +3264,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
*this, E, Intrinsic::sinh, Intrinsic::experimental_constrained_sinh));
+ case Builtin::BI__builtin_sincos:
+ case Builtin::BI__builtin_sincosf:
+ case Builtin::BI__builtin_sincosf16:
+ case Builtin::BI__builtin_sincosl:
+ case Builtin::BI__builtin_sincosf128:
+ emitSincosBuiltin(*this, E, Intrinsic::sincos);
+ return RValue::get(nullptr);
+
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
case Builtin::BIsqrtl:
@@ -6757,6 +6797,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
+ case llvm::Triple::spirv:
+ return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E);
case llvm::Triple::spirv64:
if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
return nullptr;
@@ -11285,6 +11327,19 @@ Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID,
if (Builtin->LLVMIntrinsic == 0)
return nullptr;
+ if (BuiltinID == SME::BI__builtin_sme___arm_in_streaming_mode) {
+ // If we already know the streaming mode, don't bother with the intrinsic
+ // and emit a constant instead
+ const auto *FD = cast<FunctionDecl>(CurFuncDecl);
+ if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
+ unsigned SMEAttrs = FPT->getAArch64SMEAttributes();
+ if (!(SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)) {
+ bool IsStreaming = SMEAttrs & FunctionType::SME_PStateSMEnabledMask;
+ return ConstantInt::getBool(Builder.getContext(), IsStreaming);
+ }
+ }
+ }
+
// Predicates must match the main datatype.
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
if (auto PredTy = dyn_cast<llvm::VectorType>(Ops[i]->getType()))
@@ -19157,8 +19212,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
// TODO: Map to an hlsl_device address space.
llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext());
- return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
- ArrayRef<Value *>{HandleOp, IndexOp});
+ return Builder.CreateIntrinsic(
+ RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
+ ArrayRef<Value *>{HandleOp, IndexOp});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
@@ -20440,6 +20496,26 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
}
}
+Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ switch (BuiltinID) {
+ case SPIRV::BI__builtin_spirv_distance: {
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ E->getArg(1)->getType()->hasFloatingRepresentation() &&
+ "Distance operands must have a float representation");
+ assert(E->getArg(0)->getType()->isVectorType() &&
+ E->getArg(1)->getType()->isVectorType() &&
+ "Distance operands must be a vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
+ ArrayRef<Value *>{X, Y}, nullptr, "spv.distance");
+ }
+ }
+ return nullptr;
+}
+
/// Handle a SystemZ function in which the final argument is a pointer
/// to an int that receives the post-instruction CC value. At the LLVM level
/// this is represented as a function that returns a {result, cc} pair.
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index f139c30..7b0ef4b 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4871,7 +4871,7 @@ llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee,
call->setCallingConv(getRuntimeCC());
if (CGM.shouldEmitConvergenceTokens() && call->isConvergent())
- return addControlledConvergenceToken(call);
+ return cast<llvm::CallInst>(addConvergenceControlToken(call));
return call;
}
@@ -5787,7 +5787,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CI->setName("call");
if (CGM.shouldEmitConvergenceTokens() && CI->isConvergent())
- CI = addControlledConvergenceToken(CI);
+ CI = addConvergenceControlToken(CI);
// Update largest vector width from the return type.
LargestVectorWidth =
@@ -6090,6 +6090,8 @@ RValue CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr,
VAListAddr = VE->isMicrosoftABI() ? EmitMSVAListRef(VE->getSubExpr())
: EmitVAListRef(VE->getSubExpr());
QualType Ty = VE->getType();
+ if (Ty->isVariablyModifiedType())
+ EmitVariablyModifiedType(Ty);
if (VE->isMicrosoftABI())
return CGM.getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty, Slot);
return CGM.getABIInfo().EmitVAArg(*this, VAListAddr, Ty, Slot);
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index f29ddec..560d4ce 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3492,6 +3492,11 @@ llvm::DIType *CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) {
return getOrCreateType(Ty->getElementType(), U);
}
+llvm::DIType *CGDebugInfo::CreateType(const HLSLAttributedResourceType *Ty,
+ llvm::DIFile *U) {
+ return getOrCreateType(Ty->getWrappedType(), U);
+}
+
llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
const EnumDecl *ED = Ty->getDecl();
@@ -3834,12 +3839,13 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
+ case Type::HLSLAttributedResource:
+ return CreateType(cast<HLSLAttributedResourceType>(Ty), Unit);
case Type::CountAttributed:
case Type::Auto:
case Type::Attributed:
case Type::BTFTagAttributed:
- case Type::HLSLAttributedResource:
case Type::Adjusted:
case Type::Decayed:
case Type::DeducedTemplateSpecialization:
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 3fd0237..38f73ec 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -196,6 +196,8 @@ class CGDebugInfo {
llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F);
+ llvm::DIType *CreateType(const HLSLAttributedResourceType *Ty,
+ llvm::DIFile *F);
/// Get structure or union type.
llvm::DIType *CreateType(const RecordType *Tyg);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 4159cee..0f27bd0 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -5455,11 +5455,6 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
}
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
- QualType Ty = VE->getType();
-
- if (Ty->isVariablyModifiedType())
- CGF.EmitVariablyModifiedType(Ty);
-
Address ArgValue = Address::invalid();
RValue ArgPtr = CGF.EmitVAArg(VE, ArgValue);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index c354e58..5679bd7 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -395,7 +395,7 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
}
if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
- llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id);
+ llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic());
return buildVectorInput(B, GroupIDIntrinsic, Ty);
}
assert(false && "Unhandled parameter attribute");
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index edb87f9..46e472f 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -87,6 +87,7 @@ public:
GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id)
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)
@@ -103,6 +104,8 @@ public:
GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp)
GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
+ resource_getpointer)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter)
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 13223ec..c551506 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -480,6 +480,12 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OpenACCShutdownConstructClass:
EmitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*S));
break;
+ case Stmt::OpenACCSetConstructClass:
+ EmitOpenACCSetConstruct(cast<OpenACCSetConstruct>(*S));
+ break;
+ case Stmt::OpenACCUpdateConstructClass:
+ EmitOpenACCUpdateConstruct(cast<OpenACCUpdateConstruct>(*S));
+ break;
}
}
@@ -1026,8 +1032,8 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
EmitBlock(LoopHeader.getBlock());
if (CGM.shouldEmitConvergenceTokens())
- ConvergenceTokenStack.push_back(emitConvergenceLoopToken(
- LoopHeader.getBlock(), ConvergenceTokenStack.back()));
+ ConvergenceTokenStack.push_back(
+ emitConvergenceLoopToken(LoopHeader.getBlock()));
// Create an exit block for when the condition fails, which will
// also become the break target.
@@ -1141,8 +1147,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
EmitBlockWithFallThrough(LoopBody, &S);
if (CGM.shouldEmitConvergenceTokens())
- ConvergenceTokenStack.push_back(
- emitConvergenceLoopToken(LoopBody, ConvergenceTokenStack.back()));
+ ConvergenceTokenStack.push_back(emitConvergenceLoopToken(LoopBody));
{
RunCleanupsScope BodyScope(*this);
@@ -1221,8 +1226,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
EmitBlock(CondBlock);
if (CGM.shouldEmitConvergenceTokens())
- ConvergenceTokenStack.push_back(
- emitConvergenceLoopToken(CondBlock, ConvergenceTokenStack.back()));
+ ConvergenceTokenStack.push_back(emitConvergenceLoopToken(CondBlock));
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
@@ -1346,8 +1350,7 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
EmitBlock(CondBlock);
if (CGM.shouldEmitConvergenceTokens())
- ConvergenceTokenStack.push_back(
- emitConvergenceLoopToken(CondBlock, ConvergenceTokenStack.back()));
+ ConvergenceTokenStack.push_back(emitConvergenceLoopToken(CondBlock));
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
@@ -3216,35 +3219,32 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
return F;
}
-namespace {
// Returns the first convergence entry/loop/anchor instruction found in |BB|.
// std::nullptr otherwise.
-llvm::IntrinsicInst *getConvergenceToken(llvm::BasicBlock *BB) {
+static llvm::ConvergenceControlInst *getConvergenceToken(llvm::BasicBlock *BB) {
for (auto &I : *BB) {
- auto *II = dyn_cast<llvm::IntrinsicInst>(&I);
- if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID()))
- return II;
+ if (auto *CI = dyn_cast<llvm::ConvergenceControlInst>(&I))
+ return CI;
}
return nullptr;
}
-} // namespace
-
llvm::CallBase *
-CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input,
- llvm::Value *ParentToken) {
+CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input) {
+ llvm::ConvergenceControlInst *ParentToken = ConvergenceTokenStack.back();
+ assert(ParentToken);
+
llvm::Value *bundleArgs[] = {ParentToken};
llvm::OperandBundleDef OB("convergencectrl", bundleArgs);
- auto Output = llvm::CallBase::addOperandBundle(
+ auto *Output = llvm::CallBase::addOperandBundle(
Input, llvm::LLVMContext::OB_convergencectrl, OB, Input->getIterator());
Input->replaceAllUsesWith(Output);
Input->eraseFromParent();
return Output;
}
-llvm::IntrinsicInst *
-CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB,
- llvm::Value *ParentToken) {
+llvm::ConvergenceControlInst *
+CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB) {
CGBuilderTy::InsertPoint IP = Builder.saveIP();
if (BB->empty())
Builder.SetInsertPoint(BB);
@@ -3255,14 +3255,14 @@ CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB,
llvm::Intrinsic::experimental_convergence_loop, {}, {});
Builder.restoreIP(IP);
- llvm::CallBase *I = addConvergenceControlToken(CB, ParentToken);
- return cast<llvm::IntrinsicInst>(I);
+ CB = addConvergenceControlToken(CB);
+ return cast<llvm::ConvergenceControlInst>(CB);
}
-llvm::IntrinsicInst *
+llvm::ConvergenceControlInst *
CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) {
llvm::BasicBlock *BB = &F->getEntryBlock();
- llvm::IntrinsicInst *Token = getConvergenceToken(BB);
+ llvm::ConvergenceControlInst *Token = getConvergenceToken(BB);
if (Token)
return Token;
@@ -3277,5 +3277,5 @@ CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) {
assert(isa<llvm::IntrinsicInst>(I));
Builder.restoreIP(IP);
- return cast<llvm::IntrinsicInst>(I);
+ return cast<llvm::ConvergenceControlInst>(I);
}
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index cc927f4..f63cb9b 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -106,46 +106,19 @@ static void reportOptRecordError(Error E, DiagnosticsEngine &Diags,
}
BackendConsumer::BackendConsumer(
- BackendAction Action, DiagnosticsEngine &Diags,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts, const LangOptions &LangOpts,
- const std::string &InFile, SmallVector<LinkModule, 4> LinkModules,
- std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
- CoverageSourceInfo *CoverageInfo)
- : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
- CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
- AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS),
- LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
- LLVMIRGenerationRefCount(0),
- Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts,
- PPOpts, CodeGenOpts, C, CoverageInfo)),
- LinkModules(std::move(LinkModules)) {
- TimerIsEnabled = CodeGenOpts.TimePasses;
- llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
- llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
-}
-
-// This constructor is used in installing an empty BackendConsumer
-// to use the clang diagnostic handler for IR input files. It avoids
-// initializing the OS field.
-BackendConsumer::BackendConsumer(
- BackendAction Action, DiagnosticsEngine &Diags,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts, const LangOptions &LangOpts,
- llvm::Module *Module, SmallVector<LinkModule, 4> LinkModules,
- LLVMContext &C, CoverageSourceInfo *CoverageInfo)
- : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
- CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
- Context(nullptr), FS(VFS),
- LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
- LLVMIRGenerationRefCount(0),
- Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, PPOpts,
- CodeGenOpts, C, CoverageInfo)),
- LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
+ const CompilerInstance &CI, BackendAction Action,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, LLVMContext &C,
+ SmallVector<LinkModule, 4> LinkModules, StringRef InFile,
+ std::unique_ptr<raw_pwrite_stream> OS, CoverageSourceInfo *CoverageInfo,
+ llvm::Module *CurLinkModule)
+ : Diags(CI.getDiagnostics()), HeaderSearchOpts(CI.getHeaderSearchOpts()),
+ CodeGenOpts(CI.getCodeGenOpts()), TargetOpts(CI.getTargetOpts()),
+ LangOpts(CI.getLangOpts()), AsmOutStream(std::move(OS)), FS(VFS),
+ LLVMIRGeneration("irgen", "LLVM IR Generation Time"), Action(Action),
+ Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS),
+ CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
+ CI.getCodeGenOpts(), C, CoverageInfo)),
+ LinkModules(std::move(LinkModules)), CurLinkModule(CurLinkModule) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
@@ -1011,10 +984,8 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor());
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
- BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
- CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
- CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile),
- std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
+ CI, BA, &CI.getVirtualFileSystem(), *VMContext, std::move(LinkModules),
+ InFile, std::move(OS), CoverageInfo));
BEConsumer = Result.get();
// Enable generating macro debug info only when debug info is not disabled and
@@ -1182,11 +1153,9 @@ void CodeGenAction::ExecuteAction() {
// Set clang diagnostic handler. To do this we need to create a fake
// BackendConsumer.
- BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
- CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
- CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(), TheModule.get(),
- std::move(LinkModules), *VMContext, nullptr);
+ BackendConsumer Result(CI, BA, &CI.getVirtualFileSystem(), *VMContext,
+ std::move(LinkModules), "", nullptr, nullptr,
+ TheModule.get());
// Link in each pending link module.
if (!CodeGenOpts.LinkBitcodePostopt && Result.LinkInModules(&*TheModule))
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 6145c6a..cdeff1e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -315,7 +315,7 @@ public:
SmallVector<const BinaryOperator *, 16> MCDCLogOpStack;
/// Stack to track the controlled convergence tokens.
- SmallVector<llvm::IntrinsicInst *, 4> ConvergenceTokenStack;
+ SmallVector<llvm::ConvergenceControlInst *, 4> ConvergenceTokenStack;
/// Number of nested loop to be consumed by the last surrounding
/// loop-associated directive.
@@ -4157,6 +4157,16 @@ public:
// but in the future we will implement some sort of IR.
}
+ void EmitOpenACCSetConstruct(const OpenACCSetConstruct &S) {
+ // TODO OpenACC: Implement this. It is currently implemented as a 'no-op',
+ // but in the future we will implement some sort of IR.
+ }
+
+ void EmitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &S) {
+ // TODO OpenACC: Implement this. It is currently implemented as a 'no-op',
+ // but in the future we will implement some sort of IR.
+ }
+
//===--------------------------------------------------------------------===//
// LValue Expression Emission
//===--------------------------------------------------------------------===//
@@ -4780,6 +4790,7 @@ public:
llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);
+ llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
const CallExpr *E);
llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
@@ -5258,29 +5269,20 @@ public:
llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec,
unsigned NumElementsDst,
const llvm::Twine &Name = "");
- // Adds a convergence_ctrl token to |Input| and emits the required parent
- // convergence instructions.
- template <typename CallType>
- CallType *addControlledConvergenceToken(CallType *Input) {
- return cast<CallType>(
- addConvergenceControlToken(Input, ConvergenceTokenStack.back()));
- }
private:
// Emits a convergence_loop instruction for the given |BB|, with |ParentToken|
// as it's parent convergence instr.
- llvm::IntrinsicInst *emitConvergenceLoopToken(llvm::BasicBlock *BB,
- llvm::Value *ParentToken);
+ llvm::ConvergenceControlInst *emitConvergenceLoopToken(llvm::BasicBlock *BB);
+
// Adds a convergence_ctrl token with |ParentToken| as parent convergence
// instr to the call |Input|.
- llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input,
- llvm::Value *ParentToken);
+ llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input);
+
// Find the convergence_entry instruction |F|, or emits ones if none exists.
// Returns the convergence instruction.
- llvm::IntrinsicInst *getOrEmitConvergenceEntryToken(llvm::Function *F);
- // Find the convergence_loop instruction for the loop defined by |LI|, or
- // emits one if none exists. Returns the convergence instruction.
- llvm::IntrinsicInst *getOrEmitConvergenceLoopToken(const LoopInfo *LI);
+ llvm::ConvergenceControlInst *
+ getOrEmitConvergenceEntryToken(llvm::Function *F);
private:
llvm::MDNode *getRangeForLoadFromType(QualType Ty);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c49f763..7db1ed7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2748,7 +2748,21 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
Attrs.addAttribute("target-features", llvm::join(Features, ","));
AddedAttr = true;
}
-
+ if (getTarget().getTriple().isAArch64()) {
+ llvm::SmallVector<StringRef, 8> Feats;
+ if (TV)
+ TV->getFeatures(Feats);
+ else if (TC)
+ TC->getFeatures(Feats, GD.getMultiVersionIndex());
+ if (!Feats.empty()) {
+ llvm::sort(Feats);
+ std::string FMVFeatures;
+ for (StringRef F : Feats)
+ FMVFeatures.append(",+" + F.str());
+ Attrs.addAttribute("fmv-features", FMVFeatures.substr(1));
+ AddedAttr = true;
+ }
+ }
return AddedAttr;
}
@@ -4227,7 +4241,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *NewFn);
-static unsigned getFMVPriority(const TargetInfo &TI,
+static uint64_t getFMVPriority(const TargetInfo &TI,
const CodeGenFunction::FMVResolverOption &RO) {
llvm::SmallVector<StringRef, 8> Features{RO.Features};
if (RO.Architecture)
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 9c870c6..8fcfd8b 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -938,17 +938,34 @@ struct CounterCoverageMappingBuilder
}
struct BranchCounterPair {
- Counter Executed;
- Counter Skipped;
+ Counter Executed; ///< The Counter previously assigned.
+ Counter Skipped; ///< An expression (Parent-Executed), or equivalent to it.
};
+ /// Retrieve or assign the pair of Counter(s).
+ ///
+ /// This returns BranchCounterPair {Executed, Skipped}.
+ /// Executed is the Counter associated with S assigned by an earlier
+ /// CounterMapping pass.
+ /// Skipped may be an expression (Executed - ParentCnt) or newly
+ /// assigned Counter in EnableSingleByteCoverage, as subtract
+ /// expressions are not available in this mode.
+ ///
+ /// \param S Key to the CounterMap
+ /// \param ParentCnt The Counter representing how many times S is evaluated.
+ /// \param SkipCntForOld (To be removed later) Optional fake Counter
+ /// to override Skipped for adjustment of
+ /// expressions in the old behavior of
+ /// EnableSingleByteCoverage that is unaware of
+ /// Branch coverage.
BranchCounterPair
getBranchCounterPair(const Stmt *S, Counter ParentCnt,
std::optional<Counter> SkipCntForOld = std::nullopt) {
auto &TheMap = CounterMap[S];
auto ExecCnt = Counter::getCounter(TheMap.Executed);
- // The old behavior of SingleByte shouldn't emit Branches.
+ // The old behavior of SingleByte is unaware of Branches.
+ // Will be pruned after the migration of SingleByte.
if (llvm::EnableSingleByteCoverage && SkipCntForOld)
return {ExecCnt, *SkipCntForOld};
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index 61fdf33..b7b212b 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -145,7 +145,9 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
for (auto *Attr : D.specific_attrs<NoSanitizeAttr>())
NoSanitizeMask |= Attr->getMask();
- if (D.hasExternalStorage())
+ // External definitions and incomplete types get handled at the place they
+ // are defined.
+ if (D.hasExternalStorage() || D.getType()->isIncompleteType())
NoSanitizeMask |= SanitizerKind::Type;
return NoSanitizeMask;
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index ad7f405..7db67ec 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -662,7 +662,7 @@ bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate()
bool AArch64ABIInfo::passAsAggregateType(QualType Ty) const {
if (Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessBuiltinType()) {
- const auto *BT = Ty->getAs<BuiltinType>();
+ const auto *BT = Ty->castAs<BuiltinType>();
return !BT->isSVECount() &&
getContext().getBuiltinVectorTypeInfo(BT).NumVectors > 1;
}
@@ -1169,8 +1169,9 @@ void AArch64TargetCodeGenInfo::checkFunctionABI(
enum class ArmSMEInlinability : uint8_t {
Ok = 0,
ErrorCalleeRequiresNewZA = 1 << 0,
- WarnIncompatibleStreamingModes = 1 << 1,
- ErrorIncompatibleStreamingModes = 1 << 2,
+ ErrorCalleeRequiresNewZT0 = 1 << 1,
+ WarnIncompatibleStreamingModes = 1 << 2,
+ ErrorIncompatibleStreamingModes = 1 << 3,
IncompatibleStreamingModes =
WarnIncompatibleStreamingModes | ErrorIncompatibleStreamingModes,
@@ -1198,9 +1199,12 @@ static ArmSMEInlinability GetArmSMEInlinability(const FunctionDecl *Caller,
else
Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
}
- if (auto *NewAttr = Callee->getAttr<ArmNewAttr>())
+ if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) {
if (NewAttr->isNewZA())
Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
+ if (NewAttr->isNewZT0())
+ Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
+ }
return Inlinability;
}
@@ -1227,6 +1231,11 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming(
ArmSMEInlinability::ErrorCalleeRequiresNewZA)
CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za)
<< Callee->getDeclName();
+
+ if ((Inlinability & ArmSMEInlinability::ErrorCalleeRequiresNewZT0) ==
+ ArmSMEInlinability::ErrorCalleeRequiresNewZT0)
+ CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_zt0)
+ << Callee->getDeclName();
}
// If the target does not have floating-point registers, but we are using a
diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp
index 56ad050..fa07e68 100644
--- a/clang/lib/CodeGen/Targets/AMDGPU.cpp
+++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp
@@ -537,7 +537,11 @@ AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts,
break;
}
- if (Ordering != llvm::AtomicOrdering::SequentiallyConsistent) {
+ // OpenCL assumes by default that atomic scopes are per-address space for
+ // non-sequentially consistent operations.
+ if (Scope >= SyncScope::OpenCLWorkGroup &&
+ Scope <= SyncScope::OpenCLSubGroup &&
+ Ordering != llvm::AtomicOrdering::SequentiallyConsistent) {
if (!Name.empty())
Name = Twine(Twine(Name) + Twine("-")).str();
diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp
index 0431d2c..b82e4dd 100644
--- a/clang/lib/CodeGen/Targets/NVPTX.cpp
+++ b/clang/lib/CodeGen/Targets/NVPTX.cpp
@@ -9,6 +9,7 @@
#include "ABIInfoImpl.h"
#include "TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/CallingConv.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
using namespace clang;
@@ -79,13 +80,11 @@ public:
// Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the
// resulting MDNode to the nvvm.annotations MDNode.
static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
- int Operand,
- const SmallVectorImpl<int> &GridConstantArgs);
+ int Operand);
- static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
- int Operand) {
- addNVVMMetadata(GV, Name, Operand, SmallVector<int, 1>(0));
- }
+ static void
+ addGridConstantNVVMMetadata(llvm::GlobalValue *GV,
+ const SmallVectorImpl<int> &GridConstantArgs);
private:
static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst,
@@ -259,7 +258,7 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL __kernel functions get kernel metadata
// Create !{<func-ref>, metadata !"kernel", i32 1} node
- addNVVMMetadata(F, "kernel", 1);
+ F->setCallingConv(llvm::CallingConv::PTX_Kernel);
// And kernel functions are not subject to inlining
F->addFnAttr(llvm::Attribute::NoInline);
}
@@ -277,7 +276,8 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
// For some reason arg indices are 1-based in NVVM
GCI.push_back(IV.index() + 1);
// Create !{<func-ref>, metadata !"kernel", i32 1} node
- addNVVMMetadata(F, "kernel", 1, GCI);
+ F->setCallingConv(llvm::CallingConv::PTX_Kernel);
+ addGridConstantNVVMMetadata(F, GCI);
}
if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>())
M.handleCUDALaunchBoundsAttr(F, Attr);
@@ -285,13 +285,12 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
// Attach kernel metadata directly if compiling for NVPTX.
if (FD->hasAttr<NVPTXKernelAttr>()) {
- addNVVMMetadata(F, "kernel", 1);
+ F->setCallingConv(llvm::CallingConv::PTX_Kernel);
}
}
-void NVPTXTargetCodeGenInfo::addNVVMMetadata(
- llvm::GlobalValue *GV, StringRef Name, int Operand,
- const SmallVectorImpl<int> &GridConstantArgs) {
+void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
+ StringRef Name, int Operand) {
llvm::Module *M = GV->getParent();
llvm::LLVMContext &Ctx = M->getContext();
@@ -302,6 +301,21 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(
llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
+
+ // Append metadata to nvvm.annotations
+ MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
+}
+
+void NVPTXTargetCodeGenInfo::addGridConstantNVVMMetadata(
+ llvm::GlobalValue *GV, const SmallVectorImpl<int> &GridConstantArgs) {
+
+ llvm::Module *M = GV->getParent();
+ llvm::LLVMContext &Ctx = M->getContext();
+
+ // Get "nvvm.annotations" metadata node
+ llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
+
+ SmallVector<llvm::Metadata *, 5> MDVals = {llvm::ConstantAsMetadata::get(GV)};
if (!GridConstantArgs.empty()) {
SmallVector<llvm::Metadata *, 10> GCM;
for (int I : GridConstantArgs)
@@ -310,6 +324,7 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(
MDVals.append({llvm::MDString::get(Ctx, "grid_constant"),
llvm::MDNode::get(Ctx, GCM)});
}
+
// Append metadata to nvvm.annotations
MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
}
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index a48fe9d..5c75e98 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -64,6 +64,8 @@ public:
void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const override;
+ void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
llvm::SyncScope::ID getLLVMSyncScopeID(const LangOptions &LangOpts,
SyncScope Scope,
llvm::AtomicOrdering Ordering,
@@ -245,6 +247,41 @@ SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
return DefaultGlobalAS;
}
+void SPIRVTargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
+ if (!M.getLangOpts().HIP ||
+ M.getTarget().getTriple().getVendor() != llvm::Triple::AMD)
+ return;
+ if (GV->isDeclaration())
+ return;
+
+ auto F = dyn_cast<llvm::Function>(GV);
+ if (!F)
+ return;
+
+ auto FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (!FD)
+ return;
+ if (!FD->hasAttr<CUDAGlobalAttr>())
+ return;
+
+ unsigned N = M.getLangOpts().GPUMaxThreadsPerBlock;
+ if (auto FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>())
+ N = FlatWGS->getMax()->EvaluateKnownConstInt(M.getContext()).getExtValue();
+
+ // We encode the maximum flat WG size in the first component of the 3D
+ // max_work_group_size attribute, which will get reverse translated into the
+ // original AMDGPU attribute when targeting AMDGPU.
+ auto Int32Ty = llvm::IntegerType::getInt32Ty(M.getLLVMContext());
+ llvm::Metadata *AttrMDArgs[] = {
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, N)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1))};
+
+ F->setMetadata("max_work_group_size",
+ llvm::MDNode::get(M.getLLVMContext(), AttrMDArgs));
+}
+
llvm::SyncScope::ID
SPIRVTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &, SyncScope Scope,
llvm::AtomicOrdering,
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp
index 849bf60..23dbceb 100644
--- a/clang/lib/Driver/Action.cpp
+++ b/clang/lib/Driver/Action.cpp
@@ -111,6 +111,8 @@ std::string Action::getOffloadingKindPrefix() const {
return "device-openmp";
case OFK_HIP:
return "device-hip";
+ case OFK_SYCL:
+ return "device-sycl";
// TODO: Add other programming models here.
}
@@ -128,6 +130,8 @@ std::string Action::getOffloadingKindPrefix() const {
Res += "-hip";
if (ActiveOffloadKindMask & OFK_OpenMP)
Res += "-openmp";
+ if (ActiveOffloadKindMask & OFK_SYCL)
+ Res += "-sycl";
// TODO: Add other programming models here.
@@ -164,6 +168,8 @@ StringRef Action::GetOffloadKindName(OffloadKind Kind) {
return "openmp";
case OFK_HIP:
return "hip";
+ case OFK_SYCL:
+ return "sycl";
// TODO: Add other programming models here.
}
@@ -320,7 +326,7 @@ void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
DeviceBoundArchs.push_back(BoundArch);
// Add each active offloading kind from a mask.
- for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP})
+ for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP, OFK_SYCL})
if (OKind & OffloadKindMask)
DeviceOffloadKinds.push_back(OKind);
}
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 4fd10bf..5bdb661 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -77,6 +77,8 @@ add_clang_library(clangDriver
ToolChains/RISCVToolchain.cpp
ToolChains/Solaris.cpp
ToolChains/SPIRV.cpp
+ ToolChains/SPIRVOpenMP.cpp
+ ToolChains/SYCL.cpp
ToolChains/TCE.cpp
ToolChains/UEFI.cpp
ToolChains/VEToolchain.cpp
diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp
index 4d40805..a39952e 100644
--- a/clang/lib/Driver/Compilation.cpp
+++ b/clang/lib/Driver/Compilation.cpp
@@ -214,10 +214,11 @@ static bool ActionFailed(const Action *A,
if (FailingCommands.empty())
return false;
- // CUDA/HIP can have the same input source code compiled multiple times so do
- // not compiled again if there are already failures. It is OK to abort the
- // CUDA pipeline on errors.
- if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
+ // CUDA/HIP/SYCL can have the same input source code compiled multiple times
+ // so do not compile again if there are already failures. It is OK to abort
+ // the CUDA/HIP/SYCL pipeline on errors.
+ if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP) ||
+ A->isOffloading(Action::OFK_SYCL))
return true;
for (const auto &CI : FailingCommands)
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index dc84c1b..528b7d1 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -43,6 +43,8 @@
#include "ToolChains/PS4CPU.h"
#include "ToolChains/RISCVToolchain.h"
#include "ToolChains/SPIRV.h"
+#include "ToolChains/SPIRVOpenMP.h"
+#include "ToolChains/SYCL.h"
#include "ToolChains/Solaris.h"
#include "ToolChains/TCE.h"
#include "ToolChains/UEFI.h"
@@ -780,6 +782,35 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
return RT;
}
+static llvm::Triple getSYCLDeviceTriple(StringRef TargetArch) {
+ SmallVector<StringRef, 5> SYCLAlias = {"spir", "spir64", "spirv", "spirv32",
+ "spirv64"};
+ if (llvm::is_contained(SYCLAlias, TargetArch)) {
+ llvm::Triple TargetTriple;
+ TargetTriple.setArchName(TargetArch);
+ TargetTriple.setVendor(llvm::Triple::UnknownVendor);
+ TargetTriple.setOS(llvm::Triple::UnknownOS);
+ return TargetTriple;
+ }
+ return llvm::Triple(TargetArch);
+}
+
+static bool addSYCLDefaultTriple(Compilation &C,
+ SmallVectorImpl<llvm::Triple> &SYCLTriples) {
+ // Check current set of triples to see if the default has already been set.
+ for (const auto &SYCLTriple : SYCLTriples) {
+ if (SYCLTriple.getSubArch() == llvm::Triple::NoSubArch &&
+ SYCLTriple.isSPIROrSPIRV())
+ return false;
+ }
+ // Add the default triple as it was not found.
+ llvm::Triple DefaultTriple = getSYCLDeviceTriple(
+ C.getDefaultToolChain().getTriple().isArch32Bit() ? "spirv32"
+ : "spirv64");
+ SYCLTriples.insert(SYCLTriples.begin(), DefaultTriple);
+ return true;
+}
+
void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
InputList &Inputs) {
@@ -841,7 +872,6 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
return;
auto *HIPTC = &getOffloadingDeviceToolChain(C.getInputArgs(), *HIPTriple,
*HostTC, OFK);
- assert(HIPTC && "Could not create offloading device tool chain.");
C.addOffloadDeviceToolChain(HIPTC, OFK);
}
@@ -890,9 +920,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
HostTC->getTriple());
// Attempt to deduce the offloading triple from the set of architectures.
- // We can only correctly deduce NVPTX / AMDGPU triples currently. We need
- // to temporarily create these toolchains so that we can access tools for
- // inferring architectures.
+ // We can only correctly deduce NVPTX / AMDGPU triples currently.
+ // We need to temporarily create these toolchains so that we can access
+ // tools for inferring architectures.
llvm::DenseSet<StringRef> Archs;
if (NVPTXTriple) {
auto TempTC = std::make_unique<toolchains::CudaToolChain>(
@@ -962,7 +992,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
const ToolChain *TC;
// Device toolchains have to be selected differently. They pair host
// and device in their implementation.
- if (TT.isNVPTX() || TT.isAMDGCN()) {
+ if (TT.isNVPTX() || TT.isAMDGCN() || TT.isSPIRV()) {
const ToolChain *HostTC =
C.getSingleOffloadToolChain<Action::OFK_Host>();
assert(HostTC && "Host toolchain should be always defined.");
@@ -975,6 +1005,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
else if (TT.isAMDGCN())
DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
*this, TT, *HostTC, C.getInputArgs());
+ else if (TT.isSPIRV())
+ DeviceTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>(
+ *this, TT, *HostTC, C.getInputArgs());
else
assert(DeviceTC && "Device toolchain not defined.");
}
@@ -993,11 +1026,71 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
return;
}
+ // We need to generate a SYCL toolchain if the user specified -fsycl.
+ bool IsSYCL = C.getInputArgs().hasFlag(options::OPT_fsycl,
+ options::OPT_fno_sycl, false);
+
+ auto argSYCLIncompatible = [&](OptSpecifier OptId) {
+ if (!IsSYCL)
+ return;
+ if (Arg *IncompatArg = C.getInputArgs().getLastArg(OptId))
+ Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << IncompatArg->getSpelling() << "-fsycl";
+ };
+ // -static-libstdc++ is not compatible with -fsycl.
+ argSYCLIncompatible(options::OPT_static_libstdcxx);
+ // -ffreestanding cannot be used with -fsycl
+ argSYCLIncompatible(options::OPT_ffreestanding);
+
+ llvm::SmallVector<llvm::Triple, 4> UniqueSYCLTriplesVec;
+
+ if (IsSYCL) {
+ addSYCLDefaultTriple(C, UniqueSYCLTriplesVec);
+
+ // We'll need to use the SYCL and host triples as the key into
+ // getOffloadingDeviceToolChain, because the device toolchains we're
+ // going to create will depend on both.
+ const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>();
+ for (const auto &TargetTriple : UniqueSYCLTriplesVec) {
+ auto SYCLTC = &getOffloadingDeviceToolChain(
+ C.getInputArgs(), TargetTriple, *HostTC, Action::OFK_SYCL);
+ C.addOffloadDeviceToolChain(SYCLTC, Action::OFK_SYCL);
+ }
+ }
+
//
// TODO: Add support for other offloading programming models here.
//
}
+bool Driver::loadZOSCustomizationFile(llvm::cl::ExpansionContext &ExpCtx) {
+ if (IsCLMode() || IsDXCMode() || IsFlangMode())
+ return false;
+
+ SmallString<128> CustomizationFile;
+ StringRef PathLIBEnv = StringRef(getenv("CLANG_CONFIG_PATH")).trim();
+ // If the env var is a directory then append "/clang.cfg" and treat
+ // that as the config file. Otherwise treat the env var as the
+ // config file.
+ if (!PathLIBEnv.empty()) {
+ llvm::sys::path::append(CustomizationFile, PathLIBEnv);
+ if (llvm::sys::fs::is_directory(PathLIBEnv))
+ llvm::sys::path::append(CustomizationFile, "/clang.cfg");
+ if (llvm::sys::fs::is_regular_file(CustomizationFile))
+ return readConfigFile(CustomizationFile, ExpCtx);
+ Diag(diag::err_drv_config_file_not_found) << CustomizationFile;
+ return true;
+ }
+
+ SmallString<128> BaseDir(llvm::sys::path::parent_path(Dir));
+ llvm::sys::path::append(CustomizationFile, BaseDir + "/etc/clang.cfg");
+ if (llvm::sys::fs::is_regular_file(CustomizationFile))
+ return readConfigFile(CustomizationFile, ExpCtx);
+
+ // If no customization file, just return
+ return false;
+}
+
static void appendOneArg(InputArgList &Args, const Arg *Opt) {
// The args for config files or /clang: flags belong to different InputArgList
// objects than Args. This copies an Arg from one of those other InputArgLists
@@ -1219,11 +1312,18 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) {
}
// Otherwise, use the real triple as used by the driver.
+ llvm::Triple RealTriple =
+ computeTargetTriple(*this, TargetTriple, *CLOptions);
if (Triple.str().empty()) {
- Triple = computeTargetTriple(*this, TargetTriple, *CLOptions);
+ Triple = RealTriple;
assert(!Triple.str().empty());
}
+ // On z/OS, start by loading the customization file before loading
+ // the usual default config file(s).
+ if (RealTriple.isOSzOS() && loadZOSCustomizationFile(ExpCtx))
+ return true;
+
// Search for config files in the following order:
// 1. <triple>-<mode>.cfg using real driver mode
// (e.g. i386-pc-linux-gnu-clang++.cfg).
@@ -4230,6 +4330,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
bool UseNewOffloadingDriver =
C.isOffloadingHostKind(Action::OFK_OpenMP) ||
+ C.isOffloadingHostKind(Action::OFK_SYCL) ||
Args.hasFlag(options::OPT_foffload_via_llvm,
options::OPT_fno_offload_via_llvm, false) ||
Args.hasFlag(options::OPT_offload_new_driver,
@@ -4647,6 +4748,8 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
Archs.insert(OffloadArchToString(OffloadArch::HIPDefault));
else if (Kind == Action::OFK_OpenMP)
Archs.insert(StringRef());
+ else if (Kind == Action::OFK_SYCL)
+ Archs.insert(StringRef());
} else {
Args.ClaimAllArgs(options::OPT_offload_arch_EQ);
Args.ClaimAllArgs(options::OPT_no_offload_arch_EQ);
@@ -4671,7 +4774,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
OffloadAction::DeviceDependences DDeps;
const Action::OffloadKind OffloadKinds[] = {
- Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP};
+ Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP, Action::OFK_SYCL};
for (Action::OffloadKind Kind : OffloadKinds) {
SmallVector<const ToolChain *, 2> ToolChains;
@@ -4708,6 +4811,15 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
if (DeviceActions.empty())
return HostAction;
+ // FIXME: Do not collapse the host side for Darwin targets with SYCL offload
+ // compilations. The toolchain is not properly initialized for the target.
+ if (isa<CompileJobAction>(HostAction) && Kind == Action::OFK_SYCL &&
+ HostAction->getType() != types::TY_Nothing &&
+ C.getSingleOffloadToolChain<Action::OFK_Host>()
+ ->getTriple()
+ .isOSDarwin())
+ HostAction->setCannotBeCollapsedWithNextDependentAction();
+
auto PL = types::getCompilationPhases(*this, Args, InputType);
for (phases::ID Phase : PL) {
@@ -4716,6 +4828,11 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
break;
}
+ // Assemble actions are not used for the SYCL device side. Both compile
+ // and backend actions are used to generate IR and textual IR if needed.
+ if (Kind == Action::OFK_SYCL && Phase == phases::Assemble)
+ continue;
+
auto TCAndArch = TCAndArchs.begin();
for (Action *&A : DeviceActions) {
if (A->getType() == types::TY_Nothing)
@@ -4954,6 +5071,7 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm) ||
+ TargetDeviceOffloadKind == Action::OFK_SYCL ||
(((Input->getOffloadingToolChain() &&
Input->getOffloadingToolChain()->getTriple().isAMDGPU()) ||
TargetDeviceOffloadKind == Action::OFK_HIP) &&
@@ -6603,6 +6721,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
else if (Target.isOSBinFormatELF())
TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
+ else if (Target.isAppleMachO())
+ TC = std::make_unique<toolchains::AppleMachO>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
TC = std::make_unique<toolchains::MachO>(*this, Target, Args);
else
@@ -6640,11 +6760,16 @@ const ToolChain &Driver::getOffloadingDeviceToolChain(
HostTC, Args);
break;
}
+ case Action::OFK_SYCL:
+ if (Target.isSPIROrSPIRV())
+ TC = std::make_unique<toolchains::SYCLToolChain>(*this, Target, HostTC,
+ Args);
+ break;
default:
break;
}
}
-
+ assert(TC && "Could not create offloading device tool chain.");
return *TC;
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 9f174fb..2b4df64 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1485,6 +1485,9 @@ void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {}
+void ToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {}
+
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
ToolChain::getDeviceLibs(const ArgList &DriverArgs) const {
return {};
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a020e00..c4b5374 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -24,6 +24,7 @@
#include "Hexagon.h"
#include "MSP430.h"
#include "PS4CPU.h"
+#include "SYCL.h"
#include "clang/Basic/CLWarnings.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/CodeGenOptions.h"
@@ -122,6 +123,13 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
} else if (JA.isDeviceOffloading(Action::OFK_OpenMP))
Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+ if (JA.isHostOffloading(Action::OFK_SYCL)) {
+ auto TCs = C.getOffloadToolChains<Action::OFK_SYCL>();
+ for (auto II = TCs.first, IE = TCs.second; II != IE; ++II)
+ Work(*II->second);
+ } else if (JA.isDeviceOffloading(Action::OFK_SYCL))
+ Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+
//
// TODO: Add support for other offloading programming models here.
//
@@ -1070,14 +1078,16 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_MP);
Args.AddLastArg(CmdArgs, options::OPT_MV);
- // Add offload include arguments specific for CUDA/HIP. This must happen
+ // Add offload include arguments specific for CUDA/HIP/SYCL. This must happen
// before we -I or -include anything else, because we must pick up the
- // CUDA/HIP headers from the particular CUDA/ROCm installation, rather than
- // from e.g. /usr/local/include.
+ // CUDA/HIP/SYCL headers from the particular CUDA/ROCm/SYCL installation,
+ // rather than from e.g. /usr/local/include.
if (JA.isOffloading(Action::OFK_Cuda))
getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
if (JA.isOffloading(Action::OFK_HIP))
getToolChain().AddHIPIncludeArgs(Args, CmdArgs);
+ if (JA.isOffloading(Action::OFK_SYCL))
+ getToolChain().addSYCLIncludeArgs(Args, CmdArgs);
// If we are offloading to a target via OpenMP we need to include the
// openmp_wrappers folder which contains alternative system headers.
@@ -5037,17 +5047,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// second input. Module precompilation accepts a list of header files to
// include as part of the module. API extraction accepts a list of header
// files whose API information is emitted in the output. All other jobs are
- // expected to have exactly one input.
+ // expected to have exactly one input. SYCL compilation only expects a
+ // single input.
bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda);
bool IsHIP = JA.isOffloading(Action::OFK_HIP);
bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP);
+ bool IsSYCL = JA.isOffloading(Action::OFK_SYCL);
+ bool IsSYCLDevice = JA.isDeviceOffloading(Action::OFK_SYCL);
bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
bool IsExtractAPI = isa<ExtractAPIJobAction>(JA);
bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_Host));
bool IsHostOffloadingAction =
JA.isHostOffloading(Action::OFK_OpenMP) ||
+ JA.isHostOffloading(Action::OFK_SYCL) ||
(JA.isHostOffloading(C.getActiveOffloadKinds()) &&
Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false));
@@ -5095,12 +5109,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const llvm::Triple *AuxTriple =
(IsCuda || IsHIP) ? TC.getAuxTriple() : nullptr;
bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
+ bool IsUEFI = RawTriple.isUEFI();
bool IsIAMCU = RawTriple.isOSIAMCU();
- // Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in
+ // Adjust IsWindowsXYZ for CUDA/HIP/SYCL compilations. Even when compiling in
// device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not
// Windows), we need to pass Windows-specific flags to cc1.
- if (IsCuda || IsHIP)
+ if (IsCuda || IsHIP || IsSYCL)
IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();
// C++ is not supported for IAMCU.
@@ -5184,11 +5199,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *PF = Args.getLastArg(options::OPT_mprintf_kind_EQ))
PF->claim();
- if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) {
- CmdArgs.push_back("-fsycl-is-device");
+ if (IsSYCL) {
+ if (IsSYCLDevice) {
+ // Host triple is needed when doing SYCL device compilations.
+ llvm::Triple AuxT = C.getDefaultToolChain().getTriple();
+ std::string NormalizedTriple = AuxT.normalize();
+ CmdArgs.push_back("-aux-triple");
+ CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
- if (Arg *A = Args.getLastArg(options::OPT_sycl_std_EQ)) {
- A->render(Args, CmdArgs);
+ // We want to compile sycl kernels.
+ CmdArgs.push_back("-fsycl-is-device");
+
+ // Set O2 optimization level by default
+ if (!Args.getLastArg(options::OPT_O_Group))
+ CmdArgs.push_back("-O2");
+ } else {
+ // Add any options that are needed specific to SYCL offload while
+ // performing the host side compilation.
+
+ // Let the front-end host compilation flow know about SYCL offload
+ // compilation.
+ CmdArgs.push_back("-fsycl-is-host");
+ }
+
+ // Set options for both host and device.
+ Arg *SYCLStdArg = Args.getLastArg(options::OPT_sycl_std_EQ);
+ if (SYCLStdArg) {
+ SYCLStdArg->render(Args, CmdArgs);
} else {
// Ensure the default version in SYCL mode is 2020.
CmdArgs.push_back("-sycl-std=2020");
@@ -6135,7 +6172,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Prepare `-aux-target-cpu` and `-aux-target-feature` unless
// `--gpu-use-aux-triple-only` is specified.
if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) &&
- (IsCudaDevice || IsHIPDevice)) {
+ (IsCudaDevice || IsHIPDevice || IsSYCLDevice)) {
const ArgList &HostArgs =
C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None);
std::string HostCPU =
@@ -7216,7 +7253,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- IsWindowsMSVC))
+ IsWindowsMSVC || IsUEFI))
CmdArgs.push_back("-fms-extensions");
// -fms-compatibility=0 is default.
@@ -8010,15 +8047,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (Args.hasArg(options::OPT_forder_file_instrumentation)) {
- CmdArgs.push_back("-forder-file-instrumentation");
- // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is
- // on, we need to pass these flags as linker flags and that will be handled
- // outside of the compiler.
- if (!IsUsingLTO) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-order-file-instrumentation");
- }
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_forder_file_instrumentation)) {
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << A->getAsString(Args) << /*hasReplacement=*/true
+ << "-mllvm -pgo-temporal-instrumentation";
+ CmdArgs.push_back("-forder-file-instrumentation");
+ // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is
+ // on, we need to pass these flags as linker flags and that will be handled
+ // outside of the compiler.
+ if (!IsUsingLTO) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-order-file-instrumentation");
+ }
}
if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128,
@@ -9241,6 +9282,10 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue()));
+
+ if (Args.getLastArg(options::OPT_ftime_report))
+ CmdArgs.push_back("--device-compiler=-ftime-report");
+
if (Args.getLastArg(options::OPT_save_temps_EQ))
CmdArgs.push_back("--save-temps");
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 8b96390..f896789 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1209,6 +1209,10 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
if (ImplicitMapSyms)
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-implicit-mapsyms"));
+
+ if (Args.hasArg(options::OPT_ftime_report))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-time-passes"));
}
void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
@@ -2839,10 +2843,13 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
LibraryPaths.emplace_back(LibPath);
OptSpecifier LibomptargetBCPathOpt =
- Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
- : options::OPT_libomptarget_nvptx_bc_path_EQ;
+ Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
+ : Triple.isNVPTX() ? options::OPT_libomptarget_nvptx_bc_path_EQ
+ : options::OPT_libomptarget_spirv_bc_path_EQ;
- StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx";
+ StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu"
+ : Triple.isNVPTX() ? "nvptx"
+ : "spirv64";
std::string LibOmpTargetName = ("libomptarget-" + ArchPrefix + ".bc").str();
// First check whether user specifies bc library
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 4105d38..e5dffb1 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -966,10 +966,14 @@ MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
getProgramPaths().push_back(getDriver().Dir);
}
+AppleMachO::AppleMachO(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : MachO(D, Triple, Args), CudaInstallation(D, Triple, Args),
+ RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {}
+
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : MachO(D, Triple, Args), TargetInitialized(false),
- CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {}
+ : AppleMachO(D, Triple, Args), TargetInitialized(false) {}
types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
types::ID Ty = ToolChain::LookupTypeForExtension(Ext);
@@ -1018,16 +1022,21 @@ bool Darwin::hasBlocksRuntime() const {
}
}
-void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+void AppleMachO::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
}
-void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+void AppleMachO::AddHIPIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
+void AppleMachO::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);
+}
+
// This is just a MachO name translation routine and there's no
// way to join this into ARMTargetParser without breaking all
// other assumptions. Maybe MachO should consider standardising
@@ -1119,6 +1128,8 @@ VersionTuple MachO::getLinkerVersion(const llvm::opt::ArgList &Args) const {
Darwin::~Darwin() {}
+AppleMachO::~AppleMachO() {}
+
MachO::~MachO() {}
std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
@@ -2482,7 +2493,7 @@ static void AppendPlatformPrefix(SmallString<128> &Path,
// Returns the effective sysroot from either -isysroot or --sysroot, plus the
// platform prefix (if any).
llvm::SmallString<128>
-DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const {
+AppleMachO::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const {
llvm::SmallString<128> Path("/");
if (DriverArgs.hasArg(options::OPT_isysroot))
Path = DriverArgs.getLastArgValue(options::OPT_isysroot);
@@ -2495,8 +2506,9 @@ DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const {
return Path;
}
-void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
+void AppleMachO::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();
llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
@@ -2574,7 +2586,7 @@ bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverAr
return getVFS().exists(Base);
}
-void DarwinClang::AddClangCXXStdlibIncludeArgs(
+void AppleMachO::AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
// The implementation from a base class will pass through the -stdlib to
@@ -2631,55 +2643,60 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
}
case ToolChain::CST_Libstdcxx:
- llvm::SmallString<128> UsrIncludeCxx = Sysroot;
- llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++");
-
- llvm::Triple::ArchType arch = getTriple().getArch();
- bool IsBaseFound = true;
- switch (arch) {
- default: break;
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.2.1",
- "i686-apple-darwin10",
- arch == llvm::Triple::x86_64 ? "x86_64" : "");
- IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.0.0", "i686-apple-darwin8",
- "");
- break;
+ AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args);
+ break;
+ }
+}
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.2.1",
- "arm-apple-darwin10",
- "v7");
- IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.2.1",
- "arm-apple-darwin10",
- "v6");
- break;
+void AppleMachO::AddGnuCPlusPlusIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {}
- case llvm::Triple::aarch64:
- IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
- "4.2.1",
- "arm64-apple-darwin10",
- "");
- break;
- }
+void DarwinClang::AddGnuCPlusPlusIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ llvm::SmallString<128> UsrIncludeCxx = GetEffectiveSysroot(DriverArgs);
+ llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++");
- if (!IsBaseFound) {
- getDriver().Diag(diag::warn_drv_libstdcxx_not_found);
- }
+ llvm::Triple::ArchType arch = getTriple().getArch();
+ bool IsBaseFound = true;
+ switch (arch) {
+ default:
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ IsBaseFound = AddGnuCPlusPlusIncludePaths(
+ DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", "i686-apple-darwin10",
+ arch == llvm::Triple::x86_64 ? "x86_64" : "");
+ IsBaseFound |= AddGnuCPlusPlusIncludePaths(
+ DriverArgs, CC1Args, UsrIncludeCxx, "4.0.0", "i686-apple-darwin8", "");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ IsBaseFound =
+ AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1",
+ "arm-apple-darwin10", "v7");
+ IsBaseFound |=
+ AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1",
+ "arm-apple-darwin10", "v6");
+ break;
+
+ case llvm::Triple::aarch64:
+ IsBaseFound =
+ AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1",
+ "arm64-apple-darwin10", "");
break;
}
+
+ if (!IsBaseFound) {
+ getDriver().Diag(diag::warn_drv_libstdcxx_not_found);
+ }
}
-void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
switch (Type) {
@@ -3615,7 +3632,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
return Res;
}
-void Darwin::printVerboseInfo(raw_ostream &OS) const {
+void AppleMachO::printVerboseInfo(raw_ostream &OS) const {
CudaInstallation->print(OS);
RocmInstallation->print(OS);
}
diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h
index 2e55b496..c44780c 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -12,6 +12,7 @@
#include "Cuda.h"
#include "LazyDetector.h"
#include "ROCm.h"
+#include "SYCL.h"
#include "clang/Basic/DarwinSDKInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Driver/Tool.h"
@@ -290,8 +291,52 @@ public:
/// }
};
+/// Apple specific MachO extensions
+class LLVM_LIBRARY_VISIBILITY AppleMachO : public MachO {
+public:
+ AppleMachO(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~AppleMachO() override;
+
+ /// }
+ /// @name Apple Specific ToolChain Implementation
+ /// {
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void printVerboseInfo(raw_ostream &OS) const override;
+ /// }
+
+ LazyDetector<CudaInstallationDetector> CudaInstallation;
+ LazyDetector<RocmInstallationDetector> RocmInstallation;
+ LazyDetector<SYCLInstallationDetector> SYCLInstallation;
+
+protected:
+ llvm::SmallString<128>
+ GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const;
+
+private:
+ virtual void
+ AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+};
+
/// Darwin - The base Darwin tool chain.
-class LLVM_LIBRARY_VISIBILITY Darwin : public MachO {
+class LLVM_LIBRARY_VISIBILITY Darwin : public AppleMachO {
public:
/// Whether the information on the target has been initialized.
//
@@ -329,9 +374,6 @@ public:
/// The target variant triple that was specified (if any).
mutable std::optional<llvm::Triple> TargetVariantTriple;
- LazyDetector<CudaInstallationDetector> CudaInstallation;
- LazyDetector<RocmInstallationDetector> RocmInstallation;
-
private:
void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const;
@@ -343,7 +385,7 @@ public:
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const override;
- /// @name Apple Specific Toolchain Implementation
+ /// @name Darwin Specific Toolchain Implementation
/// {
void addMinVersionArgs(const llvm::opt::ArgList &Args,
@@ -559,11 +601,6 @@ public:
ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override;
bool hasBlocksRuntime() const override;
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
bool UseObjCMixedDispatch() const override {
// This is only used with the non-fragile ABI and non-legacy dispatch.
@@ -594,8 +631,6 @@ public:
bool SupportsEmbeddedBitcode() const override;
SanitizerMask getSupportedSanitizers() const override;
-
- void printVerboseInfo(raw_ostream &OS) const override;
};
/// DarwinClang - The Darwin toolchain used by Clang.
@@ -613,16 +648,6 @@ public:
llvm::opt::ArgStringList &CmdArgs,
bool ForceLinkBuiltinRT = false) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
@@ -647,15 +672,16 @@ private:
StringRef Sanitizer,
bool shared = true) const;
+ void
+ AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
bool AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
llvm::SmallString<128> Base,
llvm::StringRef Version,
llvm::StringRef ArchDir,
llvm::StringRef BitDir) const;
-
- llvm::SmallString<128>
- GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 7034e5b..75b10e8 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -57,7 +57,8 @@ void Flang::addFortranDialectOptions(const ArgList &Args,
options::OPT_fno_automatic,
options::OPT_fhermetic_module_files,
options::OPT_frealloc_lhs,
- options::OPT_fno_realloc_lhs});
+ options::OPT_fno_realloc_lhs,
+ options::OPT_fsave_main_program});
}
void Flang::addPreprocessingOptions(const ArgList &Args,
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 8397f11..e5db1b2 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -3058,7 +3058,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), GCCInstallation(D),
- CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {
+ CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args),
+ SYCLInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().Dir);
}
@@ -3274,6 +3275,11 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
}
}
+void Generic_GCC::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);
+}
+
void
Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h
index 0b664a1..3b8df71 100644
--- a/clang/lib/Driver/ToolChains/Gnu.h
+++ b/clang/lib/Driver/ToolChains/Gnu.h
@@ -12,6 +12,7 @@
#include "Cuda.h"
#include "LazyDetector.h"
#include "ROCm.h"
+#include "SYCL.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include <set>
@@ -288,6 +289,7 @@ protected:
GCCInstallationDetector GCCInstallation;
LazyDetector<CudaInstallationDetector> CudaInstallation;
LazyDetector<RocmInstallationDetector> RocmInstallation;
+ LazyDetector<SYCLInstallationDetector> SYCLInstallation;
public:
Generic_GCC(const Driver &D, const llvm::Triple &Triple,
@@ -336,6 +338,9 @@ protected:
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
virtual void
addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index c91b55b..1c56355 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -777,6 +777,11 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
}
}
+void Linux::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);
+}
+
bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const {
return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() ||
getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE();
diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h
index 2d9e674..2eb2d05 100644
--- a/clang/lib/Driver/ToolChains/Linux.h
+++ b/clang/lib/Driver/ToolChains/Linux.h
@@ -41,6 +41,8 @@ public:
llvm::opt::ArgStringList &CmdArgs) const override;
void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
unsigned GetDefaultDwarfVersion() const override;
CXXStdlibType GetDefaultCXXStdlibType() const override;
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 752c2e2..bae41fc 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -430,7 +430,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
- RocmInstallation(D, Triple, Args) {
+ RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().Dir);
std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
@@ -509,6 +509,11 @@ void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
}
+void MSVCToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);
+}
+
void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index 3950a8e..b35390c 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -12,6 +12,7 @@
#include "AMDGPU.h"
#include "Cuda.h"
#include "LazyDetector.h"
+#include "SYCL.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
@@ -100,6 +101,9 @@ public:
void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
bool getWindowsSDKLibraryPath(
const llvm::opt::ArgList &Args, std::string &path) const;
bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args,
@@ -138,6 +142,7 @@ private:
llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS;
LazyDetector<CudaInstallationDetector> CudaInstallation;
LazyDetector<RocmInstallationDetector> RocmInstallation;
+ LazyDetector<SYCLInstallationDetector> SYCLInstallation;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 963de81..9f0c616 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -138,6 +138,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("arm64pe");
break;
+ case llvm::Triple::mipsel:
+ CmdArgs.push_back("mipspe");
+ break;
default:
D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
}
diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h
index d59a8c7..415f639 100644
--- a/clang/lib/Driver/ToolChains/SPIRV.h
+++ b/clang/lib/Driver/ToolChains/SPIRV.h
@@ -52,7 +52,7 @@ public:
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY SPIRVToolChain final : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY SPIRVToolChain : public ToolChain {
mutable std::unique_ptr<Tool> Translator;
public:
diff --git a/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp b/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp
new file mode 100644
index 0000000..1f27245
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp
@@ -0,0 +1,34 @@
+//==- SPIRVOpenMP.cpp - SPIR-V OpenMP Tool Implementations --------*- C++ -*==//
+//
+// 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
+//
+//==------------------------------------------------------------------------==//
+#include "SPIRVOpenMP.h"
+#include "CommonArgs.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace llvm::opt;
+
+namespace clang::driver::toolchains {
+SPIRVOpenMPToolChain::SPIRVOpenMPToolChain(const Driver &D,
+ const llvm::Triple &Triple,
+ const ToolChain &HostToolchain,
+ const ArgList &Args)
+ : SPIRVToolChain(D, Triple, Args), HostTC(HostToolchain) {}
+
+void SPIRVOpenMPToolChain::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+
+ if (DeviceOffloadingKind != Action::OFK_OpenMP)
+ return;
+
+ if (DriverArgs.hasArg(options::OPT_nogpulib))
+ return;
+ addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, "", getTriple(), HostTC);
+}
+} // namespace clang::driver::toolchains
diff --git a/clang/lib/Driver/ToolChains/SPIRVOpenMP.h b/clang/lib/Driver/ToolChains/SPIRVOpenMP.h
new file mode 100644
index 0000000..64404e2
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/SPIRVOpenMP.h
@@ -0,0 +1,29 @@
+//===--- SPIRVOpenMP.h - SPIR-V OpenMP Tool Implementations ------*- C++-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H
+
+#include "SPIRV.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang::driver::toolchains {
+class LLVM_LIBRARY_VISIBILITY SPIRVOpenMPToolChain : public SPIRVToolChain {
+public:
+ SPIRVOpenMPToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args);
+
+ void addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const override;
+
+ const ToolChain &HostTC;
+};
+} // namespace clang::driver::toolchains
+#endif
diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp
new file mode 100644
index 0000000..a2b07ef
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/SYCL.cpp
@@ -0,0 +1,154 @@
+//===--- SYCL.cpp - SYCL Tool and ToolChain Implementations -----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#include "SYCL.h"
+#include "CommonArgs.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+SYCLInstallationDetector::SYCLInstallationDetector(
+ const Driver &D, const llvm::Triple &HostTriple,
+ const llvm::opt::ArgList &Args) {}
+
+void SYCLInstallationDetector::addSYCLIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nobuiltininc))
+ return;
+
+ // Add the SYCL header search locations in the specified order.
+ // FIXME: Add the header file locations once the SYCL library and headers
+ // are properly established within the build.
+}
+
+// Unsupported options for SYCL device compilation.
+static ArrayRef<options::ID> getUnsupportedOpts() {
+ static constexpr options::ID UnsupportedOpts[] = {
+ options::OPT_fsanitize_EQ, // -fsanitize
+ options::OPT_fcf_protection_EQ, // -fcf-protection
+ options::OPT_fprofile_generate,
+ options::OPT_fprofile_generate_EQ,
+ options::OPT_fno_profile_generate, // -f[no-]profile-generate
+ options::OPT_ftest_coverage,
+ options::OPT_fno_test_coverage, // -f[no-]test-coverage
+ options::OPT_fcoverage_mapping,
+ options::OPT_fno_coverage_mapping, // -f[no-]coverage-mapping
+ options::OPT_coverage, // --coverage
+ options::OPT_fprofile_instr_generate,
+ options::OPT_fprofile_instr_generate_EQ,
+ options::OPT_fno_profile_instr_generate, // -f[no-]profile-instr-generate
+ options::OPT_fprofile_arcs,
+ options::OPT_fno_profile_arcs, // -f[no-]profile-arcs
+ options::OPT_fcreate_profile, // -fcreate-profile
+ options::OPT_fprofile_instr_use,
+ options::OPT_fprofile_instr_use_EQ, // -fprofile-instr-use
+ options::OPT_forder_file_instrumentation, // -forder-file-instrumentation
+ options::OPT_fcs_profile_generate, // -fcs-profile-generate
+ options::OPT_fcs_profile_generate_EQ,
+ };
+ return UnsupportedOpts;
+}
+
+SYCLToolChain::SYCLToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const ArgList &Args)
+ : ToolChain(D, Triple, Args), HostTC(HostTC),
+ SYCLInstallation(D, Triple, Args) {
+ // Lookup binaries into the driver directory, this is used to discover any
+ // dependent SYCL offload compilation tools.
+ getProgramPaths().push_back(getDriver().Dir);
+
+ // Diagnose unsupported options only once.
+ for (OptSpecifier Opt : getUnsupportedOpts()) {
+ if (const Arg *A = Args.getLastArg(Opt)) {
+ D.Diag(clang::diag::warn_drv_unsupported_option_for_target)
+ << A->getAsString(Args) << getTriple().str();
+ }
+ }
+}
+
+void SYCLToolChain::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+ HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
+}
+
+llvm::opt::DerivedArgList *
+SYCLToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ DerivedArgList *DAL =
+ HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+
+ bool IsNewDAL = false;
+ if (!DAL) {
+ DAL = new DerivedArgList(Args.getBaseArgs());
+ IsNewDAL = true;
+ }
+
+ for (Arg *A : Args) {
+ // Filter out any options we do not want to pass along to the device
+ // compilation.
+ auto Opt(A->getOption());
+ bool Unsupported = false;
+ for (OptSpecifier UnsupportedOpt : getUnsupportedOpts()) {
+ if (Opt.matches(UnsupportedOpt)) {
+ if (Opt.getID() == options::OPT_fsanitize_EQ &&
+ A->getValues().size() == 1) {
+ std::string SanitizeVal = A->getValue();
+ if (SanitizeVal == "address") {
+ if (IsNewDAL)
+ DAL->append(A);
+ continue;
+ }
+ }
+ if (!IsNewDAL)
+ DAL->eraseArg(Opt.getID());
+ Unsupported = true;
+ }
+ }
+ if (Unsupported)
+ continue;
+ if (IsNewDAL)
+ DAL->append(A);
+ }
+
+ const OptTable &Opts = getDriver().getOpts();
+ if (!BoundArch.empty()) {
+ DAL->eraseArg(options::OPT_march_EQ);
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ BoundArch);
+ }
+ return DAL;
+}
+
+void SYCLToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
+ HostTC.addClangWarningOptions(CC1Args);
+}
+
+ToolChain::CXXStdlibType
+SYCLToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ return HostTC.GetCXXStdlibType(Args);
+}
+
+void SYCLToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ SYCLInstallation.addSYCLIncludeArgs(DriverArgs, CC1Args);
+}
+
+void SYCLToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
+}
+
+void SYCLToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
+ ArgStringList &CC1Args) const {
+ HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+}
diff --git a/clang/lib/Driver/ToolChains/SYCL.h b/clang/lib/Driver/ToolChains/SYCL.h
new file mode 100644
index 0000000..2a8b4ec
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/SYCL.h
@@ -0,0 +1,77 @@
+//===--- SYCL.h - SYCL ToolChain Implementations ----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SYCL_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SYCL_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+
+class SYCLInstallationDetector {
+public:
+ SYCLInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
+ const llvm::opt::ArgList &Args);
+
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+};
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY SYCLToolChain : public ToolChain {
+public:
+ SYCLToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args);
+
+ const llvm::Triple *getAuxTriple() const override {
+ return &HostTC.getTriple();
+ }
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ bool useIntegratedAs() const override { return true; }
+ bool isPICDefault() const override { return false; }
+ llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override {
+ return this->HostTC.getDefaultDebugFormat();
+ }
+ bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
+ return false;
+ }
+ bool isPICDefaultForced() const override { return false; }
+
+ void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+private:
+ const ToolChain &HostTC;
+ SYCLInstallationDetector SYCLInstallation;
+};
+
+} // end namespace toolchains
+
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SYCL_H
diff --git a/clang/lib/Format/AffectedRangeManager.cpp b/clang/lib/Format/AffectedRangeManager.cpp
index bf124d7..67108f3 100644
--- a/clang/lib/Format/AffectedRangeManager.cpp
+++ b/clang/lib/Format/AffectedRangeManager.cpp
@@ -21,8 +21,8 @@ namespace format {
bool AffectedRangeManager::computeAffectedLines(
SmallVectorImpl<AnnotatedLine *> &Lines) {
- SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
- SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
+ ArrayRef<AnnotatedLine *>::iterator I = Lines.begin();
+ ArrayRef<AnnotatedLine *>::iterator E = Lines.end();
bool SomeLineAffected = false;
const AnnotatedLine *PreviousLine = nullptr;
while (I != E) {
@@ -34,7 +34,7 @@ bool AffectedRangeManager::computeAffectedLines(
// if any token within the directive is affected.
if (Line->InPPDirective) {
FormatToken *Last = Line->Last;
- SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
+ const auto *PPEnd = I + 1;
while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
Last = (*PPEnd)->Last;
++PPEnd;
@@ -89,8 +89,8 @@ bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
}
void AffectedRangeManager::markAllAsAffected(
- SmallVectorImpl<AnnotatedLine *>::iterator I,
- SmallVectorImpl<AnnotatedLine *>::iterator E) {
+ ArrayRef<AnnotatedLine *>::iterator I,
+ ArrayRef<AnnotatedLine *>::iterator E) {
while (I != E) {
(*I)->Affected = true;
markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
diff --git a/clang/lib/Format/AffectedRangeManager.h b/clang/lib/Format/AffectedRangeManager.h
index add16bd..eef056f 100644
--- a/clang/lib/Format/AffectedRangeManager.h
+++ b/clang/lib/Format/AffectedRangeManager.h
@@ -47,8 +47,8 @@ private:
bool affectsLeadingEmptyLines(const FormatToken &Tok);
// Marks all lines between I and E as well as all their children as affected.
- void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I,
- SmallVectorImpl<AnnotatedLine *>::iterator E);
+ void markAllAsAffected(ArrayRef<AnnotatedLine *>::iterator I,
+ ArrayRef<AnnotatedLine *>::iterator E);
// Determines whether 'Line' is affected by the SourceRanges given as input.
// Returns \c true if line or one if its children is affected.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 95129a8..fc60c5e 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -839,6 +839,18 @@ template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
}
};
+template <>
+struct ScalarEnumerationTraits<
+ FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle> {
+ static void
+ enumeration(IO &IO,
+ FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::WNBWELS_Never);
+ IO.enumCase(Value, "Always", FormatStyle::WNBWELS_Always);
+ IO.enumCase(Value, "Leave", FormatStyle::WNBWELS_Leave);
+ }
+};
+
template <> struct MappingTraits<FormatStyle> {
static void mapping(IO &IO, FormatStyle &Style) {
// When reading, read the language first, we need it for getPredefinedStyle.
@@ -975,6 +987,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.AllowShortLambdasOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine);
+ IO.mapOptional("AllowShortNamespacesOnASingleLine",
+ Style.AllowShortNamespacesOnASingleLine);
IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
Style.AlwaysBreakAfterDefinitionReturnType);
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@@ -1164,10 +1178,13 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("TypeNames", Style.TypeNames);
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
IO.mapOptional("UseTab", Style.UseTab);
+ IO.mapOptional("VariableTemplates", Style.VariableTemplates);
IO.mapOptional("VerilogBreakBetweenInstancePorts",
Style.VerilogBreakBetweenInstancePorts);
IO.mapOptional("WhitespaceSensitiveMacros",
Style.WhitespaceSensitiveMacros);
+ IO.mapOptional("WrapNamespaceBodyWithEmptyLines",
+ Style.WrapNamespaceBodyWithEmptyLines);
// If AlwaysBreakAfterDefinitionReturnType was specified but
// BreakAfterReturnType was not, initialize the latter from the former for
@@ -1480,6 +1497,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
+ LLVMStyle.AllowShortNamespacesOnASingleLine = false;
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AttributeMacros.push_back("__capability");
@@ -1635,6 +1653,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
+ LLVMStyle.WrapNamespaceBodyWithEmptyLines = FormatStyle::WNBWELS_Leave;
LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
@@ -3066,8 +3085,8 @@ static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start,
// its current line.
// If `Cursor` is not on any #include, `Index` will be UINT_MAX.
static std::pair<unsigned, unsigned>
-FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
- const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) {
+FindCursorIndex(const ArrayRef<IncludeDirective> &Includes,
+ const ArrayRef<unsigned> &Indices, unsigned Cursor) {
unsigned CursorIndex = UINT_MAX;
unsigned OffsetToEOL = 0;
for (int i = 0, e = Includes.size(); i != e; ++i) {
@@ -3116,7 +3135,7 @@ std::string replaceCRLF(const std::string &Code) {
// provided and put on a deleted #include, it will be moved to the remaining
// #include in the duplicate #includes.
static void sortCppIncludes(const FormatStyle &Style,
- const SmallVectorImpl<IncludeDirective> &Includes,
+ const ArrayRef<IncludeDirective> &Includes,
ArrayRef<tooling::Range> Ranges, StringRef FileName,
StringRef Code, tooling::Replacements &Replaces,
unsigned *Cursor) {
@@ -3359,7 +3378,7 @@ static unsigned findJavaImportGroup(const FormatStyle &Style,
// import group, a newline is inserted, and within each import group, a
// lexicographic sort based on ASCII value is performed.
static void sortJavaImports(const FormatStyle &Style,
- const SmallVectorImpl<JavaImportDirective> &Imports,
+ const ArrayRef<JavaImportDirective> &Imports,
ArrayRef<tooling::Range> Ranges, StringRef FileName,
StringRef Code, tooling::Replacements &Replaces) {
unsigned ImportsBeginOffset = Imports.front().Offset;
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index f6bb860..d97b652 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -25,6 +25,7 @@ namespace clang {
namespace format {
#define LIST_TOKEN_TYPES \
+ TYPE(AfterPPDirective) \
TYPE(ArrayInitializerLSquare) \
TYPE(ArraySubscriptLSquare) \
TYPE(AttributeColon) \
@@ -44,6 +45,7 @@ namespace format {
TYPE(CastRParen) \
TYPE(ClassLBrace) \
TYPE(ClassRBrace) \
+ TYPE(CompoundRequirementLBrace) \
/* ternary ?: expression */ \
TYPE(ConditionalExpr) \
/* the condition in an if statement */ \
@@ -186,6 +188,7 @@ namespace format {
TYPE(UnionLBrace) \
TYPE(UnionRBrace) \
TYPE(UntouchableMacroFunc) \
+ TYPE(VariableTemplate) \
/* Like in 'assign x = 0, y = 1;' . */ \
TYPE(VerilogAssignComma) \
/* like in begin : block */ \
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 7a264bd..a1d7eea 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -76,6 +76,8 @@ FormatTokenLexer::FormatTokenLexer(
TemplateNames.insert(&IdentTable.get(TemplateName));
for (const auto &TypeName : Style.TypeNames)
TypeNames.insert(&IdentTable.get(TypeName));
+ for (const auto &VariableTemplate : Style.VariableTemplates)
+ VariableTemplates.insert(&IdentTable.get(VariableTemplate));
}
ArrayRef<FormatToken *> FormatTokenLexer::lex() {
@@ -562,8 +564,7 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
if (Tokens.size() < Kinds.size())
return false;
- SmallVectorImpl<FormatToken *>::const_iterator First =
- Tokens.end() - Kinds.size();
+ const auto *First = Tokens.end() - Kinds.size();
for (unsigned i = 0; i < Kinds.size(); ++i)
if (First[i]->isNot(Kinds[i]))
return false;
@@ -575,7 +576,7 @@ bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) {
if (Tokens.size() < Count)
return false;
- SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Count;
+ const auto *First = Tokens.end() - Count;
unsigned AddLength = 0;
for (size_t i = 1; i < Count; ++i) {
// If there is whitespace separating the token and the previous one,
@@ -1382,6 +1383,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
FormatTok->setFinalizedType(TT_TemplateName);
else if (TypeNames.contains(Identifier))
FormatTok->setFinalizedType(TT_TypeName);
+ else if (VariableTemplates.contains(Identifier))
+ FormatTok->setFinalizedType(TT_VariableTemplate);
}
}
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index 71389d2..61474a3 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -129,7 +129,8 @@ private:
llvm::SmallMapVector<IdentifierInfo *, TokenType, 8> Macros;
- llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames;
+ llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames,
+ VariableTemplates;
bool FormattingDisabled;
diff --git a/clang/lib/Format/MatchFilePath.cpp b/clang/lib/Format/MatchFilePath.cpp
index 062b334d..1f1e4bf 100644
--- a/clang/lib/Format/MatchFilePath.cpp
+++ b/clang/lib/Format/MatchFilePath.cpp
@@ -25,9 +25,11 @@ bool matchFilePath(StringRef Pattern, StringRef FilePath) {
assert(!Pattern.empty());
assert(!FilePath.empty());
+ const auto FilePathBack = FilePath.back();
+
// No match if `Pattern` ends with a non-meta character not equal to the last
// character of `FilePath`.
- if (const auto C = Pattern.back(); !strchr("?*]", C) && C != FilePath.back())
+ if (const auto C = Pattern.back(); !strchr("?*]", C) && C != FilePathBack)
return false;
constexpr auto Separator = '/';
@@ -49,25 +51,37 @@ bool matchFilePath(StringRef Pattern, StringRef FilePath) {
return false;
break;
case '*': {
- while (++I < EOP && Pattern[I] == '*') { // Skip consecutive stars.
+ bool Globstar = I == 0 || Pattern[I - 1] == Separator;
+ int StarCount = 1;
+ for (; ++I < EOP && Pattern[I] == '*'; ++StarCount) {
+ // Skip consecutive stars.
}
+ if (StarCount != 2)
+ Globstar = false;
const auto K = FilePath.find(Separator, J); // Index of next `Separator`.
const bool NoMoreSeparatorsInFilePath = K == StringRef::npos;
if (I == EOP) // `Pattern` ends with a star.
- return NoMoreSeparatorsInFilePath;
- // `Pattern` ends with a lone backslash.
- if (Pattern[I] == '\\' && ++I == EOP)
- return false;
+ return Globstar || NoMoreSeparatorsInFilePath;
+ if (Pattern[I] != Separator) {
+ // `Pattern` ends with a lone backslash.
+ if (Pattern[I] == '\\' && ++I == EOP)
+ return false;
+ Globstar = false;
+ }
// The star is followed by a (possibly escaped) `Separator`.
if (Pattern[I] == Separator) {
- if (NoMoreSeparatorsInFilePath)
- return false;
- J = K; // Skip to next `Separator` in `FilePath`.
- break;
+ if (!Globstar) {
+ if (NoMoreSeparatorsInFilePath)
+ return false;
+ J = K; // Skip to next `Separator` in `FilePath`.
+ break;
+ }
+ if (++I == EOP)
+ return FilePathBack == Separator;
}
// Recurse.
- for (auto Pat = Pattern.substr(I); J < End && FilePath[J] != Separator;
- ++J) {
+ for (auto Pat = Pattern.substr(I);
+ J < End && (Globstar || FilePath[J] != Separator); ++J) {
if (matchFilePath(Pat, FilePath.substr(J)))
return true;
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index f2cfa7f..bf5ee28 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -137,12 +137,12 @@ public:
private:
ScopeType getScopeType(const FormatToken &Token) const {
switch (Token.getType()) {
- case TT_LambdaLBrace:
- return ST_ChildBlock;
case TT_ClassLBrace:
case TT_StructLBrace:
case TT_UnionLBrace:
return ST_Class;
+ case TT_CompoundRequirementLBrace:
+ return ST_CompoundRequirement;
default:
return ST_Other;
}
@@ -1580,7 +1580,10 @@ private:
return false;
break;
case tok::l_brace:
- if (Style.Language == FormatStyle::LK_TextProto) {
+ if (IsCpp) {
+ if (Tok->is(TT_RequiresExpressionLBrace))
+ Line.Type = LT_RequiresExpression;
+ } else if (Style.Language == FormatStyle::LK_TextProto) {
FormatToken *Previous = Tok->getPreviousNonComment();
if (Previous && Previous->isNot(TT_DictLiteral))
Previous->setType(TT_SelectorName);
@@ -2022,8 +2025,11 @@ public:
if (!consumeToken())
return LT_Invalid;
}
- if (Line.Type == LT_AccessModifier)
- return LT_AccessModifier;
+ if (const auto Type = Line.Type; Type == LT_AccessModifier ||
+ Type == LT_RequiresExpression ||
+ Type == LT_SimpleRequirement) {
+ return Type;
+ }
if (KeywordVirtualFound)
return LT_VirtualFunctionDecl;
if (ImportStatement)
@@ -2076,7 +2082,7 @@ private:
TT_RecordLBrace, TT_StructLBrace, TT_UnionLBrace, TT_RequiresClause,
TT_RequiresClauseInARequiresExpression, TT_RequiresExpression,
TT_RequiresExpressionLParen, TT_RequiresExpressionLBrace,
- TT_BracedListLBrace)) {
+ TT_CompoundRequirementLBrace, TT_BracedListLBrace)) {
CurrentToken->setType(TT_Unknown);
}
CurrentToken->Role.reset();
@@ -2792,6 +2798,16 @@ private:
return true;
}
+ auto IsNonVariableTemplate = [](const FormatToken &Tok) {
+ if (Tok.isNot(TT_TemplateCloser))
+ return false;
+ const auto *Less = Tok.MatchingParen;
+ if (!Less)
+ return false;
+ const auto *BeforeLess = Less->getPreviousNonComment();
+ return BeforeLess && BeforeLess->isNot(TT_VariableTemplate);
+ };
+
// Heuristically try to determine whether the parentheses contain a type.
auto IsQualifiedPointerOrReference = [](const FormatToken *T,
const LangOptions &LangOpts) {
@@ -2825,10 +2841,11 @@ private:
}
return T && T->is(TT_PointerOrReference);
};
- bool ParensAreType =
- BeforeRParen->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
- BeforeRParen->isTypeName(LangOpts) ||
- IsQualifiedPointerOrReference(BeforeRParen, LangOpts);
+
+ bool ParensAreType = IsNonVariableTemplate(*BeforeRParen) ||
+ BeforeRParen->is(TT_TypeDeclarationParen) ||
+ BeforeRParen->isTypeName(LangOpts) ||
+ IsQualifiedPointerOrReference(BeforeRParen, LangOpts);
bool ParensCouldEndDecl =
AfterRParen->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
if (ParensAreType && !ParensCouldEndDecl)
@@ -3089,6 +3106,11 @@ private:
}
}
+ if (Line.Type == LT_SimpleRequirement ||
+ (!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)) {
+ return TT_BinaryOperator;
+ }
+
return TT_PointerOrReference;
}
@@ -3371,13 +3393,13 @@ private:
/// Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- llvm::SmallVector<FormatToken *, 2> Tokens;
+ SmallVector<FormatToken *, 2> Tokens;
while (Current && Current->is(TT_UnaryOperator)) {
Tokens.push_back(Current);
next();
}
parse(PrecedenceArrowAndPeriod);
- for (FormatToken *Token : llvm::reverse(Tokens)) {
+ for (FormatToken *Token : reverse(Tokens)) {
// The actual precedence doesn't matter.
addFakeParenthesis(Token, prec::Unknown);
}
@@ -3555,7 +3577,7 @@ private:
void TokenAnnotator::setCommentLineLevels(
SmallVectorImpl<AnnotatedLine *> &Lines) const {
const AnnotatedLine *NextNonCommentLine = nullptr;
- for (AnnotatedLine *Line : llvm::reverse(Lines)) {
+ for (AnnotatedLine *Line : reverse(Lines)) {
assert(Line->First);
// If the comment is currently aligned with the line immediately following
@@ -3676,9 +3698,16 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
Line.Type = Parser.parseLine();
if (!Line.Children.empty()) {
- ScopeStack.push_back(ST_ChildBlock);
- for (auto &Child : Line.Children)
+ ScopeStack.push_back(ST_Other);
+ const bool InRequiresExpression = Line.Type == LT_RequiresExpression;
+ for (auto &Child : Line.Children) {
+ if (InRequiresExpression &&
+ !Child->First->isOneOf(tok::kw_typename, tok::kw_requires,
+ TT_CompoundRequirementLBrace)) {
+ Child->Type = LT_SimpleRequirement;
+ }
annotate(*Child);
+ }
// ScopeStack can become empty if Child has an unmatched `}`.
if (!ScopeStack.empty())
ScopeStack.pop_back();
@@ -4930,6 +4959,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Right.is(TT_ModulePartitionColon)) {
return true;
}
+
+ if (Right.is(TT_AfterPPDirective))
+ return true;
+
// No space between import foo:bar but keep a space between import :bar;
if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon))
return false;
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index 9117ca3..16e920e 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -33,14 +33,16 @@ enum LineType {
LT_VirtualFunctionDecl,
LT_ArrayOfStructInitializer,
LT_CommentAbovePPDirective,
+ LT_RequiresExpression,
+ LT_SimpleRequirement,
};
enum ScopeType {
- // Contained in child block.
- ST_ChildBlock,
// Contained in class declaration/definition.
ST_Class,
- // Contained within other scope block (function, loop, if/else, etc).
+ // Contained in compound requirement.
+ ST_CompoundRequirement,
+ // Contained in other blocks (function, lambda, loop, if/else, child, etc).
ST_Other,
};
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 1804c14..ec65fea 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -183,9 +183,9 @@ private:
unsigned Indent = 0;
};
-const FormatToken *getMatchingNamespaceToken(
- const AnnotatedLine *Line,
- const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+const FormatToken *
+getMatchingNamespaceToken(const AnnotatedLine *Line,
+ const ArrayRef<AnnotatedLine *> &AnnotatedLines) {
if (!Line->startsWith(tok::r_brace))
return nullptr;
size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
@@ -200,9 +200,9 @@ StringRef getNamespaceTokenText(const AnnotatedLine *Line) {
return NamespaceToken ? NamespaceToken->TokenText : StringRef();
}
-StringRef getMatchingNamespaceTokenText(
- const AnnotatedLine *Line,
- const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+StringRef
+getMatchingNamespaceTokenText(const AnnotatedLine *Line,
+ const ArrayRef<AnnotatedLine *> &AnnotatedLines) {
const FormatToken *NamespaceToken =
getMatchingNamespaceToken(Line, AnnotatedLines);
return NamespaceToken ? NamespaceToken->TokenText : StringRef();
@@ -241,8 +241,8 @@ private:
/// Calculates how many lines can be merged into 1 starting at \p I.
unsigned
tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E) {
const unsigned Indent = IndentTracker.getIndent();
// Can't join the last line with anything.
@@ -361,9 +361,18 @@ private:
const auto *FirstNonComment = TheLine->getFirstNonComment();
if (!FirstNonComment)
return 0;
+
// FIXME: There are probably cases where we should use FirstNonComment
// instead of TheLine->First.
+ if (Style.AllowShortNamespacesOnASingleLine &&
+ TheLine->First->is(tok::kw_namespace) &&
+ TheLine->Last->is(tok::l_brace)) {
+ const auto result = tryMergeNamespace(I, E, Limit);
+ if (result > 0)
+ return result;
+ }
+
if (Style.CompactNamespaces) {
if (const auto *NSToken = TheLine->First->getNamespaceToken()) {
int J = 1;
@@ -373,7 +382,7 @@ private:
ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
I[J]->Last->TotalLength < Limit;
++J, --ClosingLineIndex) {
- Limit -= I[J]->Last->TotalLength;
+ Limit -= I[J]->Last->TotalLength + 1;
// Reduce indent level for bodies of namespaces which were compacted,
// but only if their content was indented in the first place.
@@ -420,6 +429,7 @@ private:
TheLine->First != LastNonComment) {
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
}
+
// Try to merge a control statement block with left brace unwrapped.
if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last &&
FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
@@ -525,7 +535,7 @@ private:
// Try to merge records.
if (TheLine->Last->is(TT_EnumLBrace)) {
ShouldMerge = Style.AllowShortEnumsOnASingleLine;
- } else if (TheLine->Last->is(TT_RequiresExpressionLBrace)) {
+ } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) {
ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine;
} else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) {
// NOTE: We use AfterClass (whereas AfterStruct exists) for both classes
@@ -604,8 +614,8 @@ private:
}
unsigned
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ tryMergeSimplePPDirective(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
if (Limit == 0)
return 0;
@@ -616,9 +626,76 @@ private:
return 1;
}
- unsigned tryMergeSimpleControlStatement(
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ unsigned tryMergeNamespace(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+
+ assert(I[1]);
+ const auto &L1 = *I[1];
+ if (L1.InPPDirective != (*I)->InPPDirective ||
+ (L1.InPPDirective && L1.First->HasUnescapedNewline)) {
+ return 0;
+ }
+
+ if (std::distance(I, E) <= 2)
+ return 0;
+
+ assert(I[2]);
+ const auto &L2 = *I[2];
+ if (L2.Type == LT_Invalid)
+ return 0;
+
+ Limit = limitConsideringMacros(I + 1, E, Limit);
+
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
+
+ // Check if it's a namespace inside a namespace, and call recursively if so.
+ // '3' is the sizes of the whitespace and closing brace for " _inner_ }".
+ if (L1.First->is(tok::kw_namespace)) {
+ if (L1.Last->is(tok::comment) || !Style.CompactNamespaces)
+ return 0;
+
+ assert(Limit >= L1.Last->TotalLength + 3);
+ const auto InnerLimit = Limit - L1.Last->TotalLength - 3;
+ const auto MergedLines = tryMergeNamespace(I + 1, E, InnerLimit);
+ if (MergedLines == 0)
+ return 0;
+ const auto N = MergedLines + 2;
+ // Check if there is even a line after the inner result.
+ if (std::distance(I, E) <= N)
+ return 0;
+ // Check that the line after the inner result starts with a closing brace
+ // which we are permitted to merge into one line.
+ if (I[N]->First->is(tok::r_brace) && !I[N]->First->MustBreakBefore &&
+ I[MergedLines + 1]->Last->isNot(tok::comment) &&
+ nextNLinesFitInto(I, I + N + 1, Limit)) {
+ return N;
+ }
+ return 0;
+ }
+
+ // There's no inner namespace, so we are considering to merge at most one
+ // line.
+
+ // The line which is in the namespace should end with semicolon.
+ if (L1.Last->isNot(tok::semi))
+ return 0;
+
+ // Last, check that the third line starts with a closing brace.
+ if (L2.First->isNot(tok::r_brace) || L2.First->MustBreakBefore)
+ return 0;
+
+ // If so, merge all three lines.
+ return 2;
+ }
+
+ unsigned
+ tryMergeSimpleControlStatement(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
if (Limit == 0)
return 0;
if (Style.BraceWrapping.AfterControlStatement ==
@@ -658,10 +735,9 @@ private:
return 1;
}
- unsigned
- tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
+ unsigned tryMergeShortCaseLabels(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
if (Limit == 0 || I + 1 == E ||
I[1]->First->isOneOf(tok::kw_case, tok::kw_default)) {
return 0;
@@ -692,7 +768,7 @@ private:
if (Line->First->is(tok::comment)) {
if (Level != Line->Level)
return 0;
- SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts;
+ const auto *J = I + 2 + NumStmts;
for (; J != E; ++J) {
Line = *J;
if (Line->InPPDirective != InPPDirective)
@@ -713,10 +789,9 @@ private:
return NumStmts;
}
- unsigned
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
+ unsigned tryMergeSimpleBlock(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
// Don't merge with a preprocessor directive.
if (I[1]->Type == LT_PreprocessorDirective)
return 0;
@@ -898,10 +973,9 @@ private:
/// Returns the modified column limit for \p I if it is inside a macro and
/// needs a trailing '\'.
- unsigned
- limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
+ unsigned limitConsideringMacros(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
if (I[0]->InPPDirective && I + 1 != E &&
!I[1]->First->HasUnescapedNewline && I[1]->First->isNot(tok::eof)) {
return Limit < 2 ? 0 : Limit - 2;
@@ -909,13 +983,28 @@ private:
return Limit;
}
- bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ bool nextTwoLinesFitInto(ArrayRef<AnnotatedLine *>::const_iterator I,
unsigned Limit) {
if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
return false;
return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
}
+ bool nextNLinesFitInto(ArrayRef<AnnotatedLine *>::const_iterator I,
+ ArrayRef<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ unsigned JoinedLength = 0;
+ for (const auto *J = I + 1; J != E; ++J) {
+ if ((*J)->First->MustBreakBefore)
+ return false;
+
+ JoinedLength += 1 + (*J)->Last->TotalLength;
+ if (JoinedLength > Limit)
+ return false;
+ }
+ return true;
+ }
+
bool containsMustBreak(const AnnotatedLine *Line) {
assert(Line->First);
// Ignore the first token, because in this situation, it applies more to the
@@ -943,9 +1032,9 @@ private:
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
- const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
+ const ArrayRef<AnnotatedLine *>::const_iterator End;
- SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
+ ArrayRef<AnnotatedLine *>::const_iterator Next;
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
};
@@ -1493,6 +1582,23 @@ static auto computeNewlines(const AnnotatedLine &Line,
Newlines = 1;
}
+ if (Style.WrapNamespaceBodyWithEmptyLines != FormatStyle::WNBWELS_Leave) {
+ // Modify empty lines after TT_NamespaceLBrace.
+ if (PreviousLine && PreviousLine->endsWith(TT_NamespaceLBrace)) {
+ if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never)
+ Newlines = 1;
+ else if (!Line.startsWithNamespace())
+ Newlines = std::max(Newlines, 2u);
+ }
+ // Modify empty lines before TT_NamespaceRBrace.
+ if (Line.startsWith(TT_NamespaceRBrace)) {
+ if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never)
+ Newlines = 1;
+ else if (!PreviousLine->startsWith(TT_NamespaceRBrace))
+ Newlines = std::max(Newlines, 2u);
+ }
+ }
+
// Insert or remove empty line before access specifiers.
if (PreviousLine && RootToken.isAccessSpecifier()) {
switch (Style.EmptyLineBeforeAccessModifier) {
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 654148a..3177172 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -51,9 +51,7 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line,
<< "T=" << (unsigned)I->Tok->getType()
<< ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText
<< "\"] ";
- for (SmallVectorImpl<UnwrappedLine>::const_iterator
- CI = I->Children.begin(),
- CE = I->Children.end();
+ for (const auto *CI = I->Children.begin(), *CE = I->Children.end();
CI != CE; ++CI) {
OS << "\n";
printLine(OS, *CI, (Prefix + " ").str());
@@ -394,7 +392,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
break;
case tok::l_brace:
if (InRequiresExpression) {
- FormatTok->setFinalizedType(TT_RequiresExpressionLBrace);
+ FormatTok->setFinalizedType(TT_CompoundRequirementLBrace);
} else if (FormatTok->Previous &&
FormatTok->Previous->ClosesRequiresClause) {
// We need the 'default' case here to correctly parse a function
@@ -1032,6 +1030,12 @@ void UnwrappedLineParser::parsePPDirective() {
case tok::pp_pragma:
parsePPPragma();
break;
+ case tok::pp_error:
+ case tok::pp_warning:
+ nextToken();
+ if (!eof() && Style.isCpp())
+ FormatTok->setFinalizedType(TT_AfterPPDirective);
+ [[fallthrough]];
default:
parsePPUnknown();
break;
@@ -1211,9 +1215,8 @@ void UnwrappedLineParser::parsePPPragma() {
}
void UnwrappedLineParser::parsePPUnknown() {
- do {
+ while (!eof())
nextToken();
- } while (!eof());
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
Line->Level += PPBranchLevel + 1;
addUnwrappedLine();
@@ -1702,7 +1705,8 @@ void UnwrappedLineParser::parseStructuralElement(
}
for (const bool InRequiresExpression =
- OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace);
+ OpeningBrace && OpeningBrace->isOneOf(TT_RequiresExpressionLBrace,
+ TT_CompoundRequirementLBrace);
!eof();) {
if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) {
if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true);
@@ -2041,7 +2045,9 @@ void UnwrappedLineParser::parseStructuralElement(
? FormatTok->NewlinesBefore > 0
: CommentsBeforeNextToken.front()->NewlinesBefore > 0;
- if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) &&
+ if (FollowedByNewline &&
+ (Text.size() >= 5 ||
+ (FunctionLike && FormatTok->isNot(tok::l_paren))) &&
tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) {
if (PreviousToken->isNot(TT_UntouchableMacroFunc))
PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro);
@@ -4788,8 +4794,7 @@ void UnwrappedLineParser::nextToken(int LevelDifference) {
}
void UnwrappedLineParser::distributeComments(
- const SmallVectorImpl<FormatToken *> &Comments,
- const FormatToken *NextTok) {
+ const ArrayRef<FormatToken *> &Comments, const FormatToken *NextTok) {
// Whether or not a line comment token continues a line is controlled by
// the method continuesLineCommentSection, with the following caveat:
//
@@ -5011,7 +5016,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
namespace {
template <typename Iterator>
void pushTokens(Iterator Begin, Iterator End,
- llvm::SmallVectorImpl<FormatToken *> &Into) {
+ SmallVectorImpl<FormatToken *> &Into) {
for (auto I = Begin; I != End; ++I) {
Into.push_back(I->Tok);
for (const auto &Child : I->Children)
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index b7daf8d..8160d5e 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -228,7 +228,7 @@ private:
// NextTok specifies the next token. A null pointer NextTok is supported, and
// signifies either the absence of a next token, or that the next token
// shouldn't be taken into account for the analysis.
- void distributeComments(const SmallVectorImpl<FormatToken *> &Comments,
+ void distributeComments(const ArrayRef<FormatToken *> &Comments,
const FormatToken *NextTok);
// Adds the comment preceding the next token to unwrapped lines.
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 348c56c..d711df0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1260,6 +1260,23 @@ static void initOption(AnalyzerOptions::ConfigTable &Config,
<< Name << "an unsigned";
}
+static void initOption(AnalyzerOptions::ConfigTable &Config,
+ DiagnosticsEngine *Diags,
+ PositiveAnalyzerOption &OptionField, StringRef Name,
+ unsigned DefaultVal) {
+ auto Parsed = PositiveAnalyzerOption::create(
+ getStringOption(Config, Name, std::to_string(DefaultVal)));
+ if (Parsed.has_value()) {
+ OptionField = Parsed.value();
+ return;
+ }
+ if (Diags && !Parsed.has_value())
+ Diags->Report(diag::err_analyzer_config_invalid_input)
+ << Name << "a positive";
+
+ OptionField = DefaultVal;
+}
+
static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
DiagnosticsEngine *Diags) {
// TODO: There's no need to store the entire configtable, it'd be plenty
@@ -1691,7 +1708,7 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
}
}
- if (memcmp(Opts.CoverageVersion, "408*", 4) != 0)
+ if (memcmp(Opts.CoverageVersion, "0000", 4))
GenerateArg(Consumer, OPT_coverage_version_EQ,
StringRef(Opts.CoverageVersion, 4));
@@ -2007,7 +2024,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
} else if (Args.hasArg(OPT_fmemory_profile))
Opts.MemoryProfileOutput = MemProfileBasename;
- memcpy(Opts.CoverageVersion, "408*", 4);
if (Opts.CoverageNotesFile.size() || Opts.CoverageDataFile.size()) {
if (Args.hasArg(OPT_coverage_version_EQ)) {
StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
@@ -4263,6 +4279,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (TT.getArch() == llvm::Triple::UnknownArch ||
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
+ TT.getArch() == llvm::Triple::spirv64 ||
TT.getArch() == llvm::Triple::systemz ||
TT.getArch() == llvm::Triple::loongarch64 ||
TT.getArch() == llvm::Triple::nvptx ||
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index 528eae2..8a36d83 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -10,11 +10,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PPCallbacks.h"
@@ -23,8 +23,10 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
+#include <system_error>
using namespace clang;
@@ -236,6 +238,7 @@ void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
PP.SetSuppressIncludeNotFoundError(true);
DependencyCollector::attachToPreprocessor(PP);
+ FS = PP.getFileManager().getVirtualFileSystemPtr();
}
bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
@@ -312,11 +315,22 @@ void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
/// for Windows file-naming info.
-static void PrintFilename(raw_ostream &OS, StringRef Filename,
+static void printFilename(raw_ostream &OS, llvm::vfs::FileSystem *FS,
+ StringRef Filename,
DependencyOutputFormat OutputFormat) {
// Convert filename to platform native path
llvm::SmallString<256> NativePath;
llvm::sys::path::native(Filename.str(), NativePath);
+ // Resolve absolute path. Make and Ninja canonicalize paths
+ // without checking for symbolic links in the path, for performance concerns.
+ // If there is something like `/bin/../lib64` -> `/usr/lib64`
+ // (where `/bin` links to `/usr/bin`), Make will see them as `/lib64`.
+ if (FS != nullptr && llvm::sys::path::is_absolute(NativePath)) {
+ llvm::SmallString<256> NativePathTmp = NativePath;
+ std::error_code EC = FS->getRealPath(NativePathTmp, NativePath);
+ if (EC)
+ NativePath = NativePathTmp;
+ }
if (OutputFormat == DependencyOutputFormat::NMake) {
// Add quotes if needed. These are the characters listed as "special" to
@@ -400,7 +414,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
Columns = 2;
}
OS << ' ';
- PrintFilename(OS, File, OutputFormat);
+ printFilename(OS, FS.get(), File, OutputFormat);
Columns += N + 1;
}
OS << '\n';
@@ -411,7 +425,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
if (Index++ == InputFileIndex)
continue;
- PrintFilename(OS, *I, OutputFormat);
+ printFilename(OS, FS.get(), *I, OutputFormat);
OS << ":\n";
}
}
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index e943f14..30dfa54 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -279,12 +279,14 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
Consumers.push_back(std::make_unique<ReducedBMIGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
- CI.getFrontendOpts().ModuleOutputPath));
+ CI.getFrontendOpts().ModuleOutputPath,
+ +CI.getFrontendOpts().AllowPCMWithCompilerErrors));
}
Consumers.push_back(std::make_unique<CXX20ModulesGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
- CI.getFrontendOpts().OutputFile));
+ CI.getFrontendOpts().OutputFile,
+ +CI.getFrontendOpts().AllowPCMWithCompilerErrors));
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 29723b5..8eba766 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1507,6 +1507,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// ELF targets define __ELF__
if (TI.getTriple().isOSBinFormatELF())
Builder.defineMacro("__ELF__");
+ else if (TI.getTriple().isAppleMachO())
+ // Apple MachO targets define __MACH__ even when not using DarwinTargetInfo.
+ // Hurd will also define this in some circumstances, but that's done in
+ // HurdTargetInfo. Windows targets don't define this.
+ Builder.defineMacro("__MACH__");
// Target OS macro definitions.
if (PPOpts.DefineTargetOSMacros) {
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index 67c9d92..bb2a213 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -313,7 +313,7 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
break;
case llvm::Triple::UnknownOS:
- if (triple.isWasm())
+ if (triple.isWasm() || triple.isAppleMachO())
return false;
break;
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index ede4090..c79ba97 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -1003,7 +1003,9 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
// the 'update' clause, so we have to handle it here. U se an assert to
// make sure we get the right differentiator.
assert(DirKind == OpenACCDirectiveKind::Update);
- [[fallthrough]];
+ ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind),
+ /*IsReadOnly=*/false, /*IsZero=*/false);
+ break;
case OpenACCClauseKind::Device:
case OpenACCClauseKind::DeviceResident:
case OpenACCClauseKind::Host:
@@ -1082,13 +1084,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCanContinue();
}
- // TODO OpenACC: as we implement the 'rest' of the above, this 'if' should
- // be removed leaving just the 'setIntExprDetails'.
- if (ClauseKind == OpenACCClauseKind::NumWorkers ||
- ClauseKind == OpenACCClauseKind::DeviceNum ||
- ClauseKind == OpenACCClauseKind::VectorLength)
- ParsedClause.setIntExprDetails(IntExpr.get());
-
+ ParsedClause.setIntExprDetails(IntExpr.get());
break;
}
case OpenACCClauseKind::DType:
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 719c3a9..3241cb5 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -79,6 +79,7 @@ add_clang_library(clangSema
SemaStmt.cpp
SemaStmtAsm.cpp
SemaStmtAttr.cpp
+ SemaSPIRV.cpp
SemaSYCL.cpp
SemaSwift.cpp
SemaSystemZ.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index d651751..abb46d3 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -61,6 +61,7 @@
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/SemaRISCV.h"
+#include "clang/Sema/SemaSPIRV.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaSystemZ.h"
@@ -239,6 +240,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
PPCPtr(std::make_unique<SemaPPC>(*this)),
PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)),
RISCVPtr(std::make_unique<SemaRISCV>(*this)),
+ SPIRVPtr(std::make_unique<SemaSPIRV>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
SwiftPtr(std::make_unique<SemaSwift>(*this)),
SystemZPtr(std::make_unique<SemaSystemZ>(*this)),
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 3e93b38..411baa0 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -372,7 +372,7 @@ enum ArmSMEState : unsigned {
bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
unsigned ArgIdx, unsigned EltBitWidth,
- unsigned VecBitWidth) {
+ unsigned ContainerBitWidth) {
// Function that checks whether the operand (ArgIdx) is an immediate
// that is one of a given set of values.
auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set,
@@ -445,17 +445,17 @@ bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
break;
case ImmCheckType::ImmCheckLaneIndex:
if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
- (VecBitWidth / EltBitWidth) - 1))
+ (ContainerBitWidth / EltBitWidth) - 1))
return true;
break;
case ImmCheckType::ImmCheckLaneIndexCompRotate:
- if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
- (VecBitWidth / (2 * EltBitWidth)) - 1))
+ if (SemaRef.BuiltinConstantArgRange(
+ TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1))
return true;
break;
case ImmCheckType::ImmCheckLaneIndexDot:
- if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
- (VecBitWidth / (4 * EltBitWidth)) - 1))
+ if (SemaRef.BuiltinConstantArgRange(
+ TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1))
return true;
break;
case ImmCheckType::ImmCheckComplexRot90_270:
@@ -515,13 +515,13 @@ bool SemaARM::PerformNeonImmChecks(
bool HasError = false;
for (const auto &I : ImmChecks) {
- auto [ArgIdx, CheckTy, ElementSizeInBits, VecSizeInBits] = I;
+ auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
if (OverloadType >= 0)
- ElementSizeInBits = NeonTypeFlags(OverloadType).getEltSizeInBits();
+ ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
- HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits,
- VecSizeInBits);
+ HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth,
+ VecBitWidth);
}
return HasError;
@@ -532,9 +532,9 @@ bool SemaARM::PerformSVEImmChecks(
bool HasError = false;
for (const auto &I : ImmChecks) {
- auto [ArgIdx, CheckTy, ElementSizeInBits] = I;
+ auto [ArgIdx, CheckTy, ElementBitWidth] = I;
HasError |=
- CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits, 128);
+ CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128);
}
return HasError;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 44485e7..42aa68d 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -307,8 +307,8 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
Annotate(MD);
return;
}
- static const llvm::StringSet<> CapturingMethods{"insert", "push",
- "push_front", "push_back"};
+ static const llvm::StringSet<> CapturingMethods{
+ "insert", "insert_or_assign", "push", "push_front", "push_back"};
if (!CapturingMethods.contains(MD->getName()))
return;
Annotate(MD);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ce846ae..28dcfaa 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -70,6 +70,7 @@
#include "clang/Sema/SemaOpenCL.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaRISCV.h"
+#include "clang/Sema/SemaSPIRV.h"
#include "clang/Sema/SemaSystemZ.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
@@ -1934,6 +1935,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::spirv:
+ return SPIRV().CheckSPIRVBuiltinFunctionCall(BuiltinID, TheCall);
case llvm::Triple::systemz:
return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall);
case llvm::Triple::x86:
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index ac36663..ac5d51a1 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1401,6 +1401,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OpenACCWaitConstructClass:
case Stmt::OpenACCInitConstructClass:
case Stmt::OpenACCShutdownConstructClass:
+ case Stmt::OpenACCSetConstructClass:
+ case Stmt::OpenACCUpdateConstructClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 562c98c..ae40895 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -16592,6 +16592,13 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
<< TInfo->getTypeLoc().getSourceRange();
}
+ if (TInfo->getType()->isArrayType()) {
+ DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E,
+ PDiag(diag::warn_second_parameter_to_va_arg_array)
+ << TInfo->getType()
+ << TInfo->getTypeLoc().getSourceRange());
+ }
+
// Check for va_arg where arguments of the given type will be promoted
// (i.e. this va_arg is guaranteed to have undefined behavior).
QualType PromoteType;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 5909457..0dd5f46 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2030,13 +2030,8 @@ canInitializeArrayWithEmbedDataString(ArrayRef<Expr *> ExprList,
if (InitType->isArrayType()) {
const ArrayType *InitArrayType = InitType->getAsArrayTypeUnsafe();
- QualType InitElementTy = InitArrayType->getElementType();
- QualType EmbedExprElementTy = EE->getDataStringLiteral()->getType();
- const bool TypesMatch =
- Context.typesAreCompatible(InitElementTy, EmbedExprElementTy) ||
- (InitElementTy->isCharType() && EmbedExprElementTy->isCharType());
- if (TypesMatch)
- return true;
+ StringLiteral *SL = EE->getDataStringLiteral();
+ return IsStringInit(SL, InitArrayType, Context) == SIF_None;
}
return false;
}
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 42bbdf1..51a95f9 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -463,6 +463,14 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
return false;
}
}
+ case OpenACCClauseKind::DefaultAsync: {
+ switch (DirectiveKind) {
+ case OpenACCDirectiveKind::Set:
+ return true;
+ default:
+ return false;
+ }
+ }
}
default:
@@ -490,12 +498,9 @@ bool checkAlreadyHasClauseOfKind(
bool checkValidAfterDeviceType(
SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause,
const SemaOpenACC::OpenACCParsedClause &NewClause) {
- // This is only a requirement on compute, combined, data and loop constructs
- // so far, so this is fine otherwise.
- if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) &&
- !isOpenACCCombinedDirectiveKind(NewClause.getDirectiveKind()) &&
- NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop &&
- NewClause.getDirectiveKind() != OpenACCDirectiveKind::Data)
+ // This is implemented for everything but 'routine', so treat as 'fine' for
+ // that.
+ if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Routine)
return false;
// OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are
@@ -570,6 +575,21 @@ bool checkValidAfterDeviceType(
default:
break;
}
+ } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Set ||
+ NewClause.getDirectiveKind() == OpenACCDirectiveKind::Init ||
+ NewClause.getDirectiveKind() == OpenACCDirectiveKind::Shutdown) {
+ // There are no restrictions on 'set', 'init', or 'shutdown'.
+ return false;
+ } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Update) {
+ // OpenACC3.3 section 2.14.4: Only the async and wait clauses may follow a
+ // device_type clause.
+ switch (NewClause.getClauseKind()) {
+ case OpenACCClauseKind::Async:
+ case OpenACCClauseKind::Wait:
+ return false;
+ default:
+ break;
+ }
}
S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type)
<< NewClause.getClauseKind() << DeviceTypeClause.getClauseKind()
@@ -587,7 +607,8 @@ bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) {
isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) ||
DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait ||
DK == OpenACCDirectiveKind::Init ||
- DK == OpenACCDirectiveKind::Shutdown;
+ DK == OpenACCDirectiveKind::Shutdown ||
+ DK == OpenACCDirectiveKind::Set;
}
class SemaOpenACCClauseVisitor {
@@ -700,18 +721,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- // Restrictions only properly implemented on 'compute'/'combined'/'data'
- // constructs, and 'compute'/'combined'/'data' constructs are the only
- // constructs that can do anything with this yet, so skip/treat as
- // unimplemented in this case.
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
- return isNotImplemented();
-
// There is no prose in the standard that says duplicates aren't allowed,
// but this diagnostic is present in other compilers, as well as makes
- // sense. Prose DOES exist for 'data' and 'host_data', 'enter data' and 'exit
- // data' both don't, but other implmementations do this. OpenACC issue 519
- // filed for the latter two.
+ // sense. Prose DOES exist for 'data' and 'host_data', 'set', 'enter data' and
+ // 'exit data' both don't, but other implmementations do this. OpenACC issue
+ // 519 filed for the latter two. Prose also exists for 'update'.
// GCC allows this on init/shutdown, presumably for good reason, so we do too.
if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Init &&
Clause.getDirectiveKind() != OpenACCDirectiveKind::Shutdown &&
@@ -722,14 +736,14 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
// isn't really much to do here.
// If the 'if' clause is true, it makes the 'self' clause have no effect,
- // diagnose that here.
- // TODO OpenACC: When we add these two to other constructs, we might not
- // want to warn on this (for example, 'update').
- const auto *Itr =
- llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>);
- if (Itr != ExistingClauses.end()) {
- SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
- SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+ // diagnose that here. This only applies on compute/combined constructs.
+ if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Update) {
+ const auto *Itr =
+ llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>);
+ if (Itr != ExistingClauses.end()) {
+ SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
+ SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+ }
}
return OpenACCIfClause::Create(Ctx, Clause.getBeginLoc(),
@@ -739,16 +753,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- // Restrictions only properly implemented on 'compute' constructs, and
- // 'compute' constructs are the only construct that can do anything with
- // this yet, so skip/treat as unimplemented in this case.
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
- return isNotImplemented();
-
- // TODO OpenACC: When we implement this for 'update', this takes a
- // 'var-list' instead of a condition expression, so semantics/handling has
- // to happen differently here.
-
// There is no prose in the standard that says duplicates aren't allowed,
// but this diagnostic is present in other compilers, as well as makes
// sense.
@@ -756,9 +760,12 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause(
return nullptr;
// If the 'if' clause is true, it makes the 'self' clause have no effect,
- // diagnose that here.
- // TODO OpenACC: When we add these two to other constructs, we might not
- // want to warn on this (for example, 'update').
+ // diagnose that here. This only applies on compute/combined constructs.
+ if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Update)
+ return OpenACCSelfClause::Create(Ctx, Clause.getBeginLoc(),
+ Clause.getLParenLoc(), Clause.getVarList(),
+ Clause.getEndLoc());
+
const auto *Itr =
llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCIfClause>);
if (Itr != ExistingClauses.end()) {
@@ -935,13 +942,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorLengthClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- // Restrictions only properly implemented on 'compute'/'combined'/'data'
- // constructs, and 'compute'/'combined'/'data' constructs are the only
- // construct that can do anything with this yet, so skip/treat as
- // unimplemented in this case.
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
- return isNotImplemented();
-
// There is no prose in the standard that says duplicates aren't allowed,
// but this diagnostic is present in other compilers, as well as makes
// sense.
@@ -963,6 +963,12 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause(
if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
return isNotImplemented();
+ // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the
+ // same directive.
+ if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Set &&
+ checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+ return nullptr;
+
assert(Clause.getNumIntExprs() == 1 &&
"Invalid number of expressions for device_num");
return OpenACCDeviceNumClause::Create(
@@ -970,6 +976,20 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause(
Clause.getEndLoc());
}
+OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultAsyncClause(
+ SemaOpenACC::OpenACCParsedClause &Clause) {
+ // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the
+ // same directive.
+ if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+ return nullptr;
+
+ assert(Clause.getNumIntExprs() == 1 &&
+ "Invalid number of expressions for default_async");
+ return OpenACCDefaultAsyncClause::Create(
+ Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0],
+ Clause.getEndLoc());
+}
+
OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// ActOnVar ensured that everything is a valid variable reference, so there
@@ -1156,13 +1176,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- // Restrictions only properly implemented on 'compute'/'combined'/'data'
- // constructs, and 'compute'/'combined'/'data' constructs are the only
- // construct that can do anything with this yet, so skip/treat as
- // unimplemented in this case.
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
- return isNotImplemented();
-
return OpenACCWaitClause::Create(
Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getDevNumExpr(),
Clause.getQueuesLoc(), Clause.getQueueIdExprs(), Clause.getEndLoc());
@@ -1170,13 +1183,16 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- // Restrictions only properly implemented on 'compute', 'combined', 'data' and
- // 'loop' constructs, and 'compute'/'combined'/'data'/'loop' constructs are
- // the only construct that can do anything with this yet, so skip/treat as
- // unimplemented in this case.
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
+ // Restrictions implemented properly on everything except 'routine'.
+ if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Routine)
return isNotImplemented();
+ // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the
+ // same directive.
+ if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Set &&
+ checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause))
+ return nullptr;
+
// TODO OpenACC: Once we get enough of the CodeGen implemented that we have
// a source for the list of valid architectures, we need to warn on unknown
// identifiers here.
@@ -1709,8 +1725,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause(
OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
- if (!isDirectiveKindImplemented(Clause.getDirectiveKind()))
- return isNotImplemented();
// There isn't anything to do here, this is only valid on one construct, and
// has no associated rules.
return OpenACCIfPresentClause::Create(Ctx, Clause.getBeginLoc(),
@@ -1900,6 +1914,8 @@ bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) {
case OpenACCDirectiveKind::Wait:
case OpenACCDirectiveKind::Init:
case OpenACCDirectiveKind::Shutdown:
+ case OpenACCDirectiveKind::Set:
+ case OpenACCDirectiveKind::Update:
llvm_unreachable("Doesn't have an associated stmt");
default:
case OpenACCDirectiveKind::Invalid:
@@ -2328,6 +2344,8 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
case OpenACCDirectiveKind::HostData:
case OpenACCDirectiveKind::Init:
case OpenACCDirectiveKind::Shutdown:
+ case OpenACCDirectiveKind::Set:
+ case OpenACCDirectiveKind::Update:
// Nothing to do here, there is no real legalization that needs to happen
// here as these constructs do not take any arguments.
break;
@@ -3661,6 +3679,24 @@ bool SemaOpenACC::ActOnStartStmtDirective(
return Diag(StartLoc, diag::err_acc_construct_one_clause_of)
<< K << GetListOfClauses({OpenACCClauseKind::UseDevice});
+ // OpenACC3.3 2.14.3: At least one default_async, device_num, or device_type
+ // clause must appear.
+ if (K == OpenACCDirectiveKind::Set &&
+ llvm::find_if(
+ Clauses,
+ llvm::IsaPred<OpenACCDefaultAsyncClause, OpenACCDeviceNumClause,
+ OpenACCDeviceTypeClause, OpenACCIfClause>) ==
+ Clauses.end())
+ return Diag(StartLoc, diag::err_acc_construct_one_clause_of)
+ << K
+ << GetListOfClauses({OpenACCClauseKind::DefaultAsync,
+ OpenACCClauseKind::DeviceNum,
+ OpenACCClauseKind::DeviceType,
+ OpenACCClauseKind::If});
+
+ // TODO: OpenACC: 'Update' construct needs to have one of 'self', 'host', or
+ // 'device'. Implement here.
+
return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
}
@@ -3724,6 +3760,14 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(
return OpenACCShutdownConstruct::Create(getASTContext(), StartLoc, DirLoc,
EndLoc, Clauses);
}
+ case OpenACCDirectiveKind::Set: {
+ return OpenACCSetConstruct::Create(getASTContext(), StartLoc, DirLoc,
+ EndLoc, Clauses);
+ }
+ case OpenACCDirectiveKind::Update: {
+ return OpenACCUpdateConstruct::Create(getASTContext(), StartLoc, DirLoc,
+ EndLoc, Clauses);
+ }
}
llvm_unreachable("Unhandled case in directive handling?");
}
@@ -3739,6 +3783,7 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(
case OpenACCDirectiveKind::Wait:
case OpenACCDirectiveKind::Init:
case OpenACCDirectiveKind::Shutdown:
+ case OpenACCDirectiveKind::Set:
llvm_unreachable(
"these don't have associated statements, so shouldn't get here");
case OpenACCDirectiveKind::Parallel:
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index fff49b7..7589701 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6977,11 +6977,26 @@ void Sema::AddOverloadCandidate(
/// have linkage. So that all entities of the same should share one
/// linkage. But in clang, different entities of the same could have
/// different linkage.
- NamedDecl *ND = Function;
- if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
+ const NamedDecl *ND = Function;
+ bool IsImplicitlyInstantiated = false;
+ if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) {
ND = SpecInfo->getTemplate();
-
- if (ND->getFormalLinkage() == Linkage::Internal) {
+ IsImplicitlyInstantiated = SpecInfo->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation;
+ }
+
+ /// Don't remove inline functions with internal linkage from the overload
+ /// set if they are declared in a GMF, in violation of C++ [basic.link]p17.
+ /// However:
+ /// - Inline functions with internal linkage are a common pattern in
+ /// headers to avoid ODR issues.
+ /// - The global module is meant to be a transition mechanism for C and C++
+ /// headers, and the current rules as written work against that goal.
+ const bool IsInlineFunctionInGMF =
+ Function->isFromGlobalModule() &&
+ (IsImplicitlyInstantiated || Function->isInlined());
+
+ if (ND->getFormalLinkage() == Linkage::Internal && !IsInlineFunctionInGMF) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_module_mismatched;
return;
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
new file mode 100644
index 0000000..d2de648
--- /dev/null
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -0,0 +1,57 @@
+//===- SemaSPIRV.cpp - Semantic Analysis for SPIRV constructs--------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for SPIRV constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaSPIRV.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+
+SemaSPIRV::SemaSPIRV(Sema &S) : SemaBase(S) {}
+
+bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ switch (BuiltinID) {
+ case SPIRV::BI__builtin_spirv_distance: {
+ if (SemaRef.checkArgCount(TheCall, 2))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTyA = ArgTyA->getAs<VectorType>();
+ if (VTyA == nullptr) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTyA
+ << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1
+ << 0 << 0;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ auto *VTyB = ArgTyB->getAs<VectorType>();
+ if (VTyB == nullptr) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTyB
+ << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1
+ << 0 << 0;
+ return true;
+ }
+
+ QualType RetTy = VTyA->getElementType();
+ TheCall->setType(RetTy);
+ break;
+ }
+ }
+ return false;
+}
+} // namespace clang
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d9149f7..25a07d0 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -625,6 +625,15 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
if (getCurScope()->isInOpenACCComputeConstructScope())
setFunctionHasBranchProtectedScope();
+ // OpenACC3.3 2.14.4:
+ // The update directive is executable. It must not appear in place of the
+ // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or
+ // C++.
+ if (isa<OpenACCUpdateConstruct>(SubStmt)) {
+ Diag(SubStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*Label*/ 4;
+ SubStmt = new (Context) NullStmt(SubStmt->getBeginLoc());
+ }
+
// Otherwise, things are good. Fill in the declaration and return it.
LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
TheDecl->setStmt(LS);
@@ -1019,6 +1028,15 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate;
}
+ // OpenACC3.3 2.14.4:
+ // The update directive is executable. It must not appear in place of the
+ // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or
+ // C++.
+ if (isa<OpenACCUpdateConstruct>(thenStmt)) {
+ Diag(thenStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*if*/ 0;
+ thenStmt = new (Context) NullStmt(thenStmt->getBeginLoc());
+ }
+
return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc,
thenStmt, ElseLoc, elseStmt);
}
@@ -1297,6 +1315,16 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
getCurFunction()->SwitchStack.pop_back();
if (!BodyStmt) return StmtError();
+
+ // OpenACC3.3 2.14.4:
+ // The update directive is executable. It must not appear in place of the
+ // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or
+ // C++.
+ if (isa<OpenACCUpdateConstruct>(BodyStmt)) {
+ Diag(BodyStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*switch*/ 3;
+ BodyStmt = new (Context) NullStmt(BodyStmt->getBeginLoc());
+ }
+
SS->setBody(BodyStmt, SwitchLoc);
Expr *CondExpr = SS->getCond();
@@ -1774,6 +1802,15 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc,
!Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc()))
CommaVisitor(*this).Visit(CondVal.second);
+ // OpenACC3.3 2.14.4:
+ // The update directive is executable. It must not appear in place of the
+ // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or
+ // C++.
+ if (isa<OpenACCUpdateConstruct>(Body)) {
+ Diag(Body->getBeginLoc(), diag::err_acc_update_as_body) << /*while*/ 1;
+ Body = new (Context) NullStmt(Body->getBeginLoc());
+ }
+
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
@@ -1803,6 +1840,15 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
!Diags.isIgnored(diag::warn_comma_operator, Cond->getExprLoc()))
CommaVisitor(*this).Visit(Cond);
+ // OpenACC3.3 2.14.4:
+ // The update directive is executable. It must not appear in place of the
+ // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or
+ // C++.
+ if (isa<OpenACCUpdateConstruct>(Body)) {
+ Diag(Body->getBeginLoc(), diag::err_acc_update_as_body) << /*do*/ 2;
+ Body = new (Context) NullStmt(Body->getBeginLoc());
+ }
+
return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen);
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5e7a3c8..ce672b0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1228,7 +1228,7 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL,
NonTypeTemplateParmDecl *NewConstrainedParm,
NonTypeTemplateParmDecl *OrigConstrainedParm,
SourceLocation EllipsisLoc) {
- if (NewConstrainedParm->getType() != TL.getType() ||
+ if (NewConstrainedParm->getType().getNonPackExpansionType() != TL.getType() ||
TL.getAutoKeyword() != AutoTypeKeyword::Auto) {
Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
diag::err_unsupported_placeholder_constraint)
@@ -1530,9 +1530,19 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Param->setAccess(AS_public);
if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc())
- if (TL.isConstrained())
- if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc()))
+ if (TL.isConstrained()) {
+ if (D.getEllipsisLoc().isInvalid() &&
+ T->containsUnexpandedParameterPack()) {
+ assert(TL.getConceptReference()->getTemplateArgsAsWritten());
+ for (auto &Loc :
+ TL.getConceptReference()->getTemplateArgsAsWritten()->arguments())
+ Invalid |= DiagnoseUnexpandedParameterPack(
+ Loc, UnexpandedParameterPackContext::UPPC_TypeConstraint);
+ }
+ if (!Invalid &&
+ AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc()))
Invalid = true;
+ }
if (Invalid)
Param->setInvalidDecl();
@@ -4547,6 +4557,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
+ if (NamedConcept->isInvalidDecl())
+ return ExprError();
+
llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
NamedConcept, ConceptNameInfo.getLoc(),
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index fad20b3..1c1f6e3 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -857,7 +857,10 @@ private:
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
TemplateParams->getParam(Index))) {
if (!NTTP->isExpandedParameterPack())
- if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType()))
+ // FIXME: CWG2982 suggests a type-constraint forms a non-deduced
+ // context, however it is not yet resolved.
+ if (auto *Expansion = dyn_cast<PackExpansionType>(
+ S.Context.getUnconstrainedType(NTTP->getType())))
ExtraDeductions.push_back(Expansion->getPattern());
}
// FIXME: Also collect the unexpanded packs in any type and template
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5d43d98..d00ad5a 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4169,6 +4169,24 @@ public:
SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
}
+ StmtResult RebuildOpenACCSetConstruct(SourceLocation BeginLoc,
+ SourceLocation DirLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OpenACCClause *> Clauses) {
+ return getSema().OpenACC().ActOnEndStmtDirective(
+ OpenACCDirectiveKind::Set, BeginLoc, DirLoc, SourceLocation{},
+ SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
+ }
+
+ StmtResult RebuildOpenACCUpdateConstruct(SourceLocation BeginLoc,
+ SourceLocation DirLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OpenACCClause *> Clauses) {
+ return getSema().OpenACC().ActOnEndStmtDirective(
+ OpenACCDirectiveKind::Update, BeginLoc, DirLoc, SourceLocation{},
+ SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {});
+ }
+
StmtResult RebuildOpenACCWaitConstruct(
SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
@@ -11629,22 +11647,48 @@ template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitSelfClause(
const OpenACCSelfClause &C) {
- if (C.hasConditionExpr()) {
- Expr *Cond = const_cast<Expr *>(C.getConditionExpr());
- Sema::ConditionResult Res =
- Self.TransformCondition(Cond->getExprLoc(), /*Var=*/nullptr, Cond,
- Sema::ConditionKind::Boolean);
+ // If this is an 'update' 'self' clause, this is actually a var list instead.
+ if (ParsedClause.getDirectiveKind() == OpenACCDirectiveKind::Update) {
+ llvm::SmallVector<Expr *> InstantiatedVarList;
+ for (Expr *CurVar : C.getVarList()) {
+ ExprResult Res = Self.TransformExpr(CurVar);
- if (Res.isInvalid() || !Res.get().second)
- return;
+ if (!Res.isUsable())
+ continue;
- ParsedClause.setConditionDetails(Res.get().second);
- }
+ Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getClauseKind(),
+ Res.get());
- NewClause = OpenACCSelfClause::Create(
- Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
- ParsedClause.getLParenLoc(), ParsedClause.getConditionExpr(),
- ParsedClause.getEndLoc());
+ if (Res.isUsable())
+ InstantiatedVarList.push_back(Res.get());
+ }
+
+ ParsedClause.setVarListDetails(InstantiatedVarList,
+ /*IsReadOnly=*/false, /*IsZero=*/false);
+
+ NewClause = OpenACCSelfClause::Create(
+ Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
+ ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
+ ParsedClause.getEndLoc());
+ } else {
+
+ if (C.hasConditionExpr()) {
+ Expr *Cond = const_cast<Expr *>(C.getConditionExpr());
+ Sema::ConditionResult Res =
+ Self.TransformCondition(Cond->getExprLoc(), /*Var=*/nullptr, Cond,
+ Sema::ConditionKind::Boolean);
+
+ if (Res.isInvalid() || !Res.get().second)
+ return;
+
+ ParsedClause.setConditionDetails(Res.get().second);
+ }
+
+ NewClause = OpenACCSelfClause::Create(
+ Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
+ ParsedClause.getLParenLoc(), ParsedClause.getConditionExpr(),
+ ParsedClause.getEndLoc());
+ }
}
template <typename Derived>
@@ -11901,6 +11945,29 @@ void OpenACCClauseTransform<Derived>::VisitDeviceNumClause (
}
template <typename Derived>
+void OpenACCClauseTransform<Derived>::VisitDefaultAsyncClause(
+ const OpenACCDefaultAsyncClause &C) {
+ Expr *IntExpr = const_cast<Expr *>(C.getIntExpr());
+ assert(IntExpr && "default_async clause constructed with invalid int expr");
+
+ ExprResult Res = Self.TransformExpr(IntExpr);
+ if (!Res.isUsable())
+ return;
+
+ Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
+ C.getClauseKind(),
+ C.getBeginLoc(), Res.get());
+ if (!Res.isUsable())
+ return;
+
+ ParsedClause.setIntExprDetails(Res.get());
+ NewClause = OpenACCDefaultAsyncClause::Create(
+ Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
+ ParsedClause.getLParenLoc(), ParsedClause.getIntExprs()[0],
+ ParsedClause.getEndLoc());
+}
+
+template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitVectorLengthClause(
const OpenACCVectorLengthClause &C) {
Expr *IntExpr = const_cast<Expr *>(C.getIntExpr());
@@ -12422,6 +12489,39 @@ StmtResult TreeTransform<Derived>::TransformOpenACCShutdownConstruct(
C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
TransformedClauses);
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOpenACCSetConstruct(OpenACCSetConstruct *C) {
+ getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
+
+ llvm::SmallVector<OpenACCClause *> TransformedClauses =
+ getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
+ C->clauses());
+ if (getSema().OpenACC().ActOnStartStmtDirective(
+ C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses))
+ return StmtError();
+
+ return getDerived().RebuildOpenACCSetConstruct(
+ C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
+ TransformedClauses);
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOpenACCUpdateConstruct(
+ OpenACCUpdateConstruct *C) {
+ getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
+
+ llvm::SmallVector<OpenACCClause *> TransformedClauses =
+ getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
+ C->clauses());
+ if (getSema().OpenACC().ActOnStartStmtDirective(
+ C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses))
+ return StmtError();
+
+ return getDerived().RebuildOpenACCUpdateConstruct(
+ C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
+ TransformedClauses);
+}
template <typename Derived>
StmtResult
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fccd79b..0368990 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -12387,9 +12387,18 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
}
case OpenACCClauseKind::Self: {
SourceLocation LParenLoc = readSourceLocation();
- Expr *CondExpr = readBool() ? readSubExpr() : nullptr;
- return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc,
- CondExpr, EndLoc);
+ bool isConditionExprClause = readBool();
+ if (isConditionExprClause) {
+ Expr *CondExpr = readBool() ? readSubExpr() : nullptr;
+ return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc,
+ CondExpr, EndLoc);
+ }
+ unsigned NumVars = readInt();
+ llvm::SmallVector<Expr *> VarList;
+ for (unsigned I = 0; I < NumVars; ++I)
+ VarList.push_back(readSubExpr());
+ return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc, VarList,
+ EndLoc);
}
case OpenACCClauseKind::NumGangs: {
SourceLocation LParenLoc = readSourceLocation();
@@ -12412,6 +12421,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCDeviceNumClause::Create(getContext(), BeginLoc, LParenLoc,
IntExpr, EndLoc);
}
+ case OpenACCClauseKind::DefaultAsync: {
+ SourceLocation LParenLoc = readSourceLocation();
+ Expr *IntExpr = readSubExpr();
+ return OpenACCDefaultAsyncClause::Create(getContext(), BeginLoc, LParenLoc,
+ IntExpr, EndLoc);
+ }
case OpenACCClauseKind::VectorLength: {
SourceLocation LParenLoc = readSourceLocation();
Expr *IntExpr = readSubExpr();
@@ -12601,7 +12616,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::Host:
case OpenACCClauseKind::Link:
case OpenACCClauseKind::Bind:
- case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 719bc0d..8c60e85 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2663,7 +2663,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
- if (D->hasTypeConstraint()) {
+ bool TypeConstraintInitialized = D->hasTypeConstraint() && Record.readBool();
+ if (TypeConstraintInitialized) {
ConceptReference *CR = nullptr;
if (Record.readBool())
CR = Record.readConceptReference();
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 9e8cf19..4766f34 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2875,6 +2875,16 @@ void ASTStmtReader::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
VisitOpenACCConstructStmt(S);
}
+void ASTStmtReader::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) {
+ VisitStmt(S);
+ VisitOpenACCConstructStmt(S);
+}
+
+void ASTStmtReader::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) {
+ VisitStmt(S);
+ VisitOpenACCConstructStmt(S);
+}
+
void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
VisitStmt(S);
VisitOpenACCAssociatedStmtConstruct(S);
@@ -4407,6 +4417,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = OpenACCShutdownConstruct::CreateEmpty(Context, NumClauses);
break;
}
+ case STMT_OPENACC_SET_CONSTRUCT: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ S = OpenACCSetConstruct::CreateEmpty(Context, NumClauses);
+ break;
+ }
+ case STMT_OPENACC_UPDATE_CONSTRUCT: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ S = OpenACCUpdateConstruct::CreateEmpty(Context, NumClauses);
+ break;
+ }
case EXPR_REQUIRES: {
unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields];
unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1];
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 4a60279..8d9396e 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7230,6 +7230,10 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
if (!D->isFromASTFile())
return; // Declaration not imported from PCH.
+ // The function definition may not have a body due to parsing errors.
+ if (!D->doesThisDeclarationHaveABody())
+ return;
+
// Implicit function decl from a PCH was defined.
DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
}
@@ -7249,6 +7253,10 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
if (!D->isFromASTFile())
return;
+ // The function definition may not have a body due to parsing errors.
+ if (!D->doesThisDeclarationHaveABody())
+ return;
+
DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
}
@@ -8313,9 +8321,16 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Self: {
const auto *SC = cast<OpenACCSelfClause>(C);
writeSourceLocation(SC->getLParenLoc());
- writeBool(SC->hasConditionExpr());
- if (SC->hasConditionExpr())
- AddStmt(const_cast<Expr*>(SC->getConditionExpr()));
+ writeBool(SC->isConditionExprClause());
+ if (SC->isConditionExprClause()) {
+ writeBool(SC->hasConditionExpr());
+ if (SC->hasConditionExpr())
+ AddStmt(const_cast<Expr *>(SC->getConditionExpr()));
+ } else {
+ writeUInt32(SC->getVarList().size());
+ for (Expr *E : SC->getVarList())
+ AddStmt(E);
+ }
return;
}
case OpenACCClauseKind::NumGangs: {
@@ -8332,6 +8347,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr*>(DNC->getIntExpr()));
return;
}
+ case OpenACCClauseKind::DefaultAsync: {
+ const auto *DAC = cast<OpenACCDefaultAsyncClause>(C);
+ writeSourceLocation(DAC->getLParenLoc());
+ AddStmt(const_cast<Expr *>(DAC->getIntExpr()));
+ return;
+ }
case OpenACCClauseKind::NumWorkers: {
const auto *NWC = cast<OpenACCNumWorkersClause>(C);
writeSourceLocation(NWC->getLParenLoc());
@@ -8528,7 +8549,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Host:
case OpenACCClauseKind::Link:
case OpenACCClauseKind::Bind:
- case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 75c1d9a..f8ed155 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1951,7 +1951,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
Record.push_back(D->wasDeclaredWithTypename());
const TypeConstraint *TC = D->getTypeConstraint();
- assert((bool)TC == D->hasTypeConstraint());
+ if (D->hasTypeConstraint())
+ Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr);
if (TC) {
auto *CR = TC->getConceptReference();
Record.push_back(CR != nullptr);
@@ -1969,7 +1970,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
if (OwnsDefaultArg)
Record.AddTemplateArgumentLoc(D->getDefaultArgument());
- if (!TC && !OwnsDefaultArg &&
+ if (!D->hasTypeConstraint() && !OwnsDefaultArg &&
D->getDeclContext() == D->getLexicalDeclContext() &&
!D->isInvalidDecl() && !D->hasAttrs() &&
!D->isTopLevelDeclInObjCContainer() && !D->isImplicit() &&
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 1d42b43..7eedf7d 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2957,6 +2957,18 @@ void ASTStmtWriter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) {
Code = serialization::STMT_OPENACC_SHUTDOWN_CONSTRUCT;
}
+void ASTStmtWriter::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) {
+ VisitStmt(S);
+ VisitOpenACCConstructStmt(S);
+ Code = serialization::STMT_OPENACC_SET_CONSTRUCT;
+}
+
+void ASTStmtWriter::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) {
+ VisitStmt(S);
+ VisitOpenACCConstructStmt(S);
+ Code = serialization::STMT_OPENACC_UPDATE_CONSTRUCT;
+}
+
void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) {
VisitStmt(S);
VisitOpenACCAssociatedStmtConstruct(S);
diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp
index 7a8a951..a3189bb 100644
--- a/clang/lib/Serialization/GeneratePCH.cpp
+++ b/clang/lib/Serialization/GeneratePCH.cpp
@@ -102,12 +102,13 @@ void PCHGenerator::anchor() {}
CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP,
InMemoryModuleCache &ModuleCache,
StringRef OutputFile,
- bool GeneratingReducedBMI)
+ bool GeneratingReducedBMI,
+ bool AllowASTWithErrors)
: PCHGenerator(
PP, ModuleCache, OutputFile, llvm::StringRef(),
std::make_shared<PCHBuffer>(),
/*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
- /*AllowASTWithErrors*/ false, /*IncludeTimestamps=*/false,
+ AllowASTWithErrors, /*IncludeTimestamps=*/false,
/*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false,
GeneratingReducedBMI) {}
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 67b7d30..775a22e1 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -444,7 +444,8 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
NodeBuilderContext Ctx(*this, B, Pred);
ExplodedNodeSet Dst;
ExprEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()),
- *(B->succ_begin() + 1));
+ *(B->succ_begin() + 1),
+ getCompletedIterationCount(B, Pred));
// Enqueue the new frontier onto the worklist.
enqueue(Dst);
}
@@ -591,6 +592,30 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N,
return isNew ? Node : nullptr;
}
+std::optional<unsigned>
+CoreEngine::getCompletedIterationCount(const CFGBlock *B,
+ ExplodedNode *Pred) const {
+ const LocationContext *LC = Pred->getLocationContext();
+ BlockCounter Counter = WList->getBlockCounter();
+ unsigned BlockCount =
+ Counter.getNumVisited(LC->getStackFrame(), B->getBlockID());
+
+ const Stmt *Term = B->getTerminatorStmt();
+ if (isa<ForStmt, WhileStmt, CXXForRangeStmt>(Term)) {
+ assert(BlockCount >= 1 &&
+ "Block count of currently analyzed block must be >= 1");
+ return BlockCount - 1;
+ }
+ if (isa<DoStmt>(Term)) {
+ // In a do-while loop one iteration happens before the first evaluation of
+ // the loop condition, so we don't subtract one.
+ return BlockCount;
+ }
+ // ObjCForCollectionStmt is skipped intentionally because the current
+ // application of the iteration counts is not relevant for it.
+ return std::nullopt;
+}
+
void CoreEngine::enqueue(ExplodedNodeSet &Set) {
for (const auto I : Set)
WList->enqueue(I);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index db385e8..ff8bdce 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1832,6 +1832,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OpenACCWaitConstructClass:
case Stmt::OpenACCInitConstructClass:
case Stmt::OpenACCShutdownConstructClass:
+ case Stmt::OpenACCSetConstructClass:
+ case Stmt::OpenACCUpdateConstructClass:
case Stmt::OMPUnrollDirectiveClass:
case Stmt::OMPMetaDirectiveClass:
case Stmt::HLSLOutArgExprClass: {
@@ -2760,12 +2762,10 @@ assumeCondition(const Stmt *Condition, ExplodedNode *N) {
return State->assume(V);
}
-void ExprEngine::processBranch(const Stmt *Condition,
- NodeBuilderContext& BldCtx,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst,
- const CFGBlock *DstT,
- const CFGBlock *DstF) {
+void ExprEngine::processBranch(
+ const Stmt *Condition, NodeBuilderContext &BldCtx, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF,
+ std::optional<unsigned> IterationsCompletedInLoop) {
assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
"CXXBindTemporaryExprs are handled by processBindTemporary.");
const LocationContext *LCtx = Pred->getLocationContext();
@@ -2808,8 +2808,35 @@ void ExprEngine::processBranch(const Stmt *Condition,
if (StTrue && StFalse)
assert(!isa<ObjCForCollectionStmt>(Condition));
- if (StTrue)
- Builder.generateNode(StTrue, true, PredN);
+ if (StTrue) {
+ // If we are processing a loop condition where two iterations have
+ // already been completed and the false branch is also feasible, then
+ // don't assume a third iteration because it is a redundant execution
+ // path (unlikely to be different from earlier loop exits) and can cause
+ // false positives if e.g. the loop iterates over a two-element structure
+ // with an opaque condition.
+ //
+ // The iteration count "2" is hardcoded because it's the natural limit:
+ // * the fact that the programmer wrote a loop (and not just an `if`)
+ // implies that they thought that the loop body might be executed twice;
+ // * however, there are situations where the programmer knows that there
+ // are at most two iterations but writes a loop that appears to be
+ // generic, because there is no special syntax for "loop with at most
+ // two iterations". (This pattern is common in FFMPEG and appears in
+ // many other projects as well.)
+ bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(0) >= 2;
+ bool FalseAlsoFeasible =
+ StFalse ||
+ didEagerlyAssumeBifurcateAt(PrevState, dyn_cast<Expr>(Condition));
+ bool SkipTrueBranch = CompletedTwoIterations && FalseAlsoFeasible;
+
+ // FIXME: This "don't assume third iteration" heuristic partially
+ // conflicts with the widen-loop analysis option (which is off by
+ // default). If we intend to support and stabilize the loop widening,
+ // we must ensure that it 'plays nicely' with this logic.
+ if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops)
+ Builder.generateNode(StTrue, true, PredN);
+ }
if (StFalse)
Builder.generateNode(StFalse, false, PredN);
@@ -3731,6 +3758,12 @@ ExprEngine::getEagerlyAssumeBifurcationTags() {
return std::make_pair(&TrueTag, &FalseTag);
}
+/// If the last EagerlyAssume attempt was successful (i.e. the true and false
+/// cases were both feasible), this state trait stores the expression where it
+/// happened; otherwise this holds nullptr.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(LastEagerlyAssumeExprIfSuccessful,
+ const Expr *)
+
void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
@@ -3746,6 +3779,7 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
}
ProgramStateRef State = Pred->getState();
+ State = State->set<LastEagerlyAssumeExprIfSuccessful>(nullptr);
SVal V = State->getSVal(Ex, Pred->getLocationContext());
std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
@@ -3753,6 +3787,11 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
auto [StateTrue, StateFalse] = State->assume(*SEV);
+ if (StateTrue && StateFalse) {
+ StateTrue = StateTrue->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
+ StateFalse = StateFalse->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
+ }
+
// First assume that the condition is true.
if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
@@ -3770,6 +3809,11 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
}
}
+bool ExprEngine::didEagerlyAssumeBifurcateAt(ProgramStateRef State,
+ const Expr *Ex) const {
+ return Ex && State->get<LastEagerlyAssumeExprIfSuccessful>() == Ex;
+}
+
void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index 96f5d7c..01d87b0 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -283,10 +283,10 @@ static bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
llvm::APInt InitNum =
Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue();
auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator");
- if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
- InitNum = InitNum.zext(BoundNum.getBitWidth());
- BoundNum = BoundNum.zext(InitNum.getBitWidth());
- }
+ unsigned MaxWidth = std::max(InitNum.getBitWidth(), BoundNum.getBitWidth());
+
+ InitNum = InitNum.zext(MaxWidth);
+ BoundNum = BoundNum.zext(MaxWidth);
if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index f21e5c3..738b6a1 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -170,9 +170,8 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = new (BPAlloc) SymbolRegionValue(SymbolCounter, R);
+ SD = Alloc.make<SymbolRegionValue>(R);
DataSet.InsertNode(SD, InsertPos);
- ++SymbolCounter;
}
return cast<SymbolRegionValue>(SD);
@@ -188,9 +187,8 @@ const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = new (BPAlloc) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
+ SD = Alloc.make<SymbolConjured>(E, LCtx, T, Count, SymbolTag);
DataSet.InsertNode(SD, InsertPos);
- ++SymbolCounter;
}
return cast<SymbolConjured>(SD);
@@ -204,9 +202,8 @@ SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = new (BPAlloc) SymbolDerived(SymbolCounter, parentSymbol, R);
+ SD = Alloc.make<SymbolDerived>(parentSymbol, R);
DataSet.InsertNode(SD, InsertPos);
- ++SymbolCounter;
}
return cast<SymbolDerived>(SD);
@@ -219,9 +216,8 @@ SymbolManager::getExtentSymbol(const SubRegion *R) {
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = new (BPAlloc) SymbolExtent(SymbolCounter, R);
+ SD = Alloc.make<SymbolExtent>(R);
DataSet.InsertNode(SD, InsertPos);
- ++SymbolCounter;
}
return cast<SymbolExtent>(SD);
@@ -236,9 +232,8 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = new (BPAlloc) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag);
+ SD = Alloc.make<SymbolMetadata>(R, S, T, LCtx, Count, SymbolTag);
DataSet.InsertNode(SD, InsertPos);
- ++SymbolCounter;
}
return cast<SymbolMetadata>(SD);
@@ -252,7 +247,7 @@ SymbolManager::getCastSymbol(const SymExpr *Op,
void *InsertPos;
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = new (BPAlloc) SymbolCast(Op, From, To);
+ data = Alloc.make<SymbolCast>(Op, From, To);
DataSet.InsertNode(data, InsertPos);
}
@@ -268,7 +263,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = new (BPAlloc) SymIntExpr(lhs, op, v, t);
+ data = Alloc.make<SymIntExpr>(lhs, op, v, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -284,7 +279,7 @@ const IntSymExpr *SymbolManager::getIntSymExpr(APSIntPtr lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = new (BPAlloc) IntSymExpr(lhs, op, rhs, t);
+ data = Alloc.make<IntSymExpr>(lhs, op, rhs, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -301,7 +296,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = new (BPAlloc) SymSymExpr(lhs, op, rhs, t);
+ data = Alloc.make<SymSymExpr>(lhs, op, rhs, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -316,7 +311,7 @@ const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand,
void *InsertPos;
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = new (BPAlloc) UnarySymExpr(Operand, Opc, T);
+ data = Alloc.make<UnarySymExpr>(Operand, Opc, T);
DataSet.InsertNode(data, InsertPos);
}
diff --git a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp
index 739db95..c4dd016 100644
--- a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp
@@ -21,6 +21,10 @@
#define DEBUG_TYPE "Z3CrosscheckOracle"
+// Queries attempted at most `Z3CrosscheckMaxAttemptsPerQuery` number of times.
+// Multiple `check()` calls might be called on the same query if previous
+// attempts of the same query resulted in UNSAT for any reason. Each query is
+// only counted once for these statistics, the retries are not accounted for.
STATISTIC(NumZ3QueriesDone, "Number of Z3 queries done");
STATISTIC(NumTimesZ3TimedOut, "Number of times Z3 query timed out");
STATISTIC(NumTimesZ3ExhaustedRLimit,
@@ -77,16 +81,32 @@ void Z3CrosscheckVisitor::finalizeVisitor(BugReporterContext &BRC,
RefutationSolver->addConstraint(SMTConstraints);
}
- // And check for satisfiability
- llvm::TimeRecord Start = llvm::TimeRecord::getCurrentTime(/*Start=*/true);
- std::optional<bool> IsSAT = RefutationSolver->check();
- llvm::TimeRecord Diff = llvm::TimeRecord::getCurrentTime(/*Start=*/false);
- Diff -= Start;
- Result = Z3Result{
- IsSAT,
- static_cast<unsigned>(Diff.getWallTime() * 1000),
- RefutationSolver->getStatistics()->getUnsigned("rlimit count"),
+ auto GetUsedRLimit = [](const llvm::SMTSolverRef &Solver) {
+ return Solver->getStatistics()->getUnsigned("rlimit count");
+ };
+
+ auto AttemptOnce = [&](const llvm::SMTSolverRef &Solver) -> Z3Result {
+ constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime;
+ unsigned InitialRLimit = GetUsedRLimit(Solver);
+ double Start = getCurrentTime(/*Start=*/true).getWallTime();
+ std::optional<bool> IsSAT = Solver->check();
+ double End = getCurrentTime(/*Start=*/false).getWallTime();
+ return {
+ IsSAT,
+ static_cast<unsigned>((End - Start) * 1000),
+ GetUsedRLimit(Solver) - InitialRLimit,
+ };
};
+
+ // And check for satisfiability
+ unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max();
+ for (unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) {
+ Result = AttemptOnce(RefutationSolver);
+ Result.Z3QueryTimeMilliseconds =
+ std::min(MinQueryTimeAcrossAttempts, Result.Z3QueryTimeMilliseconds);
+ if (Result.IsSAT.has_value())
+ return;
+ }
}
void Z3CrosscheckVisitor::addConstraints(