39 changes: 28 additions & 11 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,42 @@ enum class OpenACCAtomicKind {

/// Represents the kind of an OpenACC clause.
enum class OpenACCClauseKind {
// 'finalize' clause, allowed on 'exit data' directive.
/// 'finalize' clause, allowed on 'exit data' directive.
Finalize,
// 'if_present' clause, allowed on 'host_data' and 'update' directives.
/// 'if_present' clause, allowed on 'host_data' and 'update' directives.
IfPresent,
// 'seq' clause, allowed on 'loop' and 'routine' directives.
/// 'seq' clause, allowed on 'loop' and 'routine' directives.
Seq,
// 'independent' clause, allowed on 'loop' directives.
/// 'independent' clause, allowed on 'loop' directives.
Independent,
// 'auto' clause, allowed on 'loop' directives.
/// 'auto' clause, allowed on 'loop' directives.
Auto,
// 'worker' clause, allowed on 'loop' and 'routine' directives.
/// 'worker' clause, allowed on 'loop' and 'routine' directives.
Worker,
// 'vector' clause, allowed on 'loop' and 'routine' directives. Takes no
// arguments for 'routine', so the 'loop' version is not yet implemented
// completely.
/// 'vector' clause, allowed on 'loop' and 'routine' directives. Takes no
/// arguments for 'routine', so the 'loop' version is not yet implemented
/// completely.
Vector,
// 'nohost' clause, allowed on 'routine' directives.
/// 'nohost' clause, allowed on 'routine' directives.
NoHost,
// Represents an invalid clause, for the purposes of parsing.
/// 'default' clause, allowed on parallel, serial, kernel (and compound)
/// constructs.
Default,
/// 'if' clause, allowed on all the Compute Constructs, Data Constructs,
/// Executable Constructs, and Combined Constructs.
If,
/// 'self' clause, allowed on Compute and Combined Constructs, plus 'update'.
Self,
/// Represents an invalid clause, for the purposes of parsing.
Invalid,
};

enum class OpenACCDefaultClauseKind {
/// 'none' option.
None,
/// 'present' option.
Present,
/// Not a valid option.
Invalid,
};
} // namespace clang
Expand Down
137 changes: 66 additions & 71 deletions clang/include/clang/Basic/arm_sve.td

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clang/include/clang/Basic/arm_sve_sme_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ def IsPreservesZA : FlagType<0x10000000000>;
def IsReadZA : FlagType<0x20000000000>;
def IsWriteZA : FlagType<0x40000000000>;
def IsReductionQV : FlagType<0x80000000000>;
def IsStreamingOrSVE2p1 : FlagType<0x80000000000>; // Use for intrinsics that are common between sme/sme2 and sve2p1.

// These must be kept in sync with the flags in include/clang/Basic/TargetBuiltins.h
class ImmCheckType<int val> {
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/riscv_sifive_vector.td
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ multiclass RVVVQMACCDODBuiltinSet<list<list<string>> suffixes_prototypes> {
}

multiclass RVVVQMACCQOQBuiltinSet<list<list<string>> suffixes_prototypes> {
let OverloadedName = NAME,
Name = NAME,
HasMasked = false,
Log2LMUL = [-1, 0, 1, 2] in
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "s", suffixes_prototypes>;
let OverloadedName = NAME,
Name = NAME,
HasMasked = false,
Log2LMUL = [-1, 0, 1, 2] in
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "s", suffixes_prototypes>;
}

multiclass RVVVFNRCLIPBuiltinSet<string suffix, string prototype, string type_range> {
Expand Down
26 changes: 18 additions & 8 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,8 @@ def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">,
def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>,
HelpText<"Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Clang will use the GCC installation with the largest version">;
def gcc_triple_EQ : Joined<["--"], "gcc-triple=">,
HelpText<"Search for the GCC installation with the specified triple.">;
def CC : Flag<["-"], "CC">, Visibility<[ClangOption, CC1Option]>,
Group<Preprocessor_Group>,
HelpText<"Include comments from within macros in preprocessed output">,
Expand Down Expand Up @@ -1695,6 +1697,12 @@ defm coverage_mapping : BoolFOption<"coverage-mapping",
"Generate coverage mapping to enable code coverage analysis">,
NegFlag<SetFalse, [], [ClangOption], "Disable code coverage analysis">, BothFlags<
[], [ClangOption, CLOption]>>;
defm mcdc_coverage : BoolFOption<"coverage-mcdc",
CodeGenOpts<"MCDCCoverage">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Enable MC/DC criteria when generating code coverage">,
NegFlag<SetFalse, [], [ClangOption], "Disable MC/DC coverage criteria">,
BothFlags<[], [ClangOption, CLOption]>>;
def fprofile_generate : Flag<["-"], "fprofile-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
Expand Down Expand Up @@ -4577,11 +4585,13 @@ let Flags = [TargetSpecific] in {
def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>,
HelpText<"Enable use of experimental RISC-V extensions.">;
def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_Group>,
HelpText<"Specify the size in bits of an RVV vector register. Defaults to "
"the vector length agnostic value of \"scalable\". Accepts power of "
"2 values between 64 and 65536. Also accepts \"zvl\" "
"to use the value implied by -march/-mcpu. Value will be reflected "
"in __riscv_v_fixed_vlen preprocessor define (RISC-V only)">;
Visibility<[ClangOption, FlangOption]>,
HelpText<"Specify the size in bits of an RVV vector register">,
DocBrief<"Defaults to the vector length agnostic value of \"scalable\". "
"Accepts power of 2 values between 64 and 65536. Also accepts "
"\"zvl\" to use the value implied by -march/-mcpu. On Clang, value "
"will be reflected in __riscv_v_fixed_vlen preprocessor define "
"(RISC-V only)">;

def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64/LoongArch/RISC-V only)">;
Expand Down Expand Up @@ -5189,12 +5199,12 @@ def nohipwrapperinc : Flag<["-"], "nohipwrapperinc">, Group<IncludePath_Group>,
HelpText<"Do not include the default HIP wrapper headers and include paths">;
def : Flag<["-"], "nocudainc">, Alias<nogpuinc>;
def nogpulib : Flag<["-"], "nogpulib">, MarshallingInfoFlag<LangOpts<"NoGPULib">>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Do not link device library for CUDA/HIP device compilation">;
def : Flag<["-"], "nocudalib">, Alias<nogpulib>;
def gpulibc : Flag<["-"], "gpulibc">, Visibility<[ClangOption, CC1Option]>,
def gpulibc : Flag<["-"], "gpulibc">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Link the LLVM C Library for GPUs">;
def nogpulibc : Flag<["-"], "nogpulibc">, Visibility<[ClangOption, CC1Option]>;
def nogpulibc : Flag<["-"], "nogpulibc">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>;
def nodefaultlibs : Flag<["-"], "nodefaultlibs">;
def nodriverkitlib : Flag<["-"], "nodriverkitlib">;
def nofixprebinding : Flag<["-"], "nofixprebinding">;
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Format/.clang-format
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
BasedOnStyle: clang-format
BasedOnStyle: LLVM
InsertBraces: true
InsertNewlineAtEOF: true
LineEnding: LF
RemoveBracesLLVM: true
RemoveParentheses: ReturnStatement
24 changes: 22 additions & 2 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,26 @@ class Parser : public CodeCompletionHandler {
/// Parsing OpenACC directive mode.
bool OpenACCDirectiveParsing = false;

/// Currently parsing a situation where an OpenACC array section could be
/// legal, such as a 'var-list'.
bool AllowOpenACCArraySections = false;

/// RAII object to set reset OpenACC parsing a context where Array Sections
/// are allowed.
class OpenACCArraySectionRAII {
Parser &P;

public:
OpenACCArraySectionRAII(Parser &P) : P(P) {
assert(!P.AllowOpenACCArraySections);
P.AllowOpenACCArraySections = true;
}
~OpenACCArraySectionRAII() {
assert(P.AllowOpenACCArraySections);
P.AllowOpenACCArraySections = false;
}
};

/// When true, we are directly inside an Objective-C message
/// send expression.
///
Expand Down Expand Up @@ -3546,8 +3566,8 @@ class Parser : public CodeCompletionHandler {
ExprResult ParseOpenACCIDExpression();
/// Parses the variable list for the `cache` construct.
void ParseOpenACCCacheVarList();
/// Parses a single variable in a variable list for the 'cache' construct.
bool ParseOpenACCCacheVar();
/// Parses a single variable in a variable list for OpenACC.
bool ParseOpenACCVar();
bool ParseOpenACCWaitArgument();

private:
Expand Down
15 changes: 10 additions & 5 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10263,11 +10263,13 @@ class Sema final {
~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); }
};

// Unlike the above, this evaluates constraints, which should only happen at
// 'constraint checking' time.
// Must be used instead of SubstExpr at 'constraint checking' time.
ExprResult
SubstConstraintExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
// Unlike the above, this does not evaluates constraints.
ExprResult SubstConstraintExprWithoutSatisfaction(
Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs);

/// Substitute the given template arguments into a list of
/// expressions, expanding pack expansions if required.
Expand Down Expand Up @@ -11344,9 +11346,12 @@ class Sema final {
/// rigorous semantic checking in the new mapped directives.
bool mapLoopConstruct(llvm::SmallVector<OMPClause *> &ClausesWithoutBind,
ArrayRef<OMPClause *> Clauses,
OpenMPBindClauseKind BindKind,
OpenMPBindClauseKind &BindKind,
OpenMPDirectiveKind &Kind,
OpenMPDirectiveKind &PrevMappedDirective);
OpenMPDirectiveKind &PrevMappedDirective,
SourceLocation StartLoc, SourceLocation EndLoc,
const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion);

public:
/// The declarator \p D defines a function in the scope \p S which is nested
Expand Down Expand Up @@ -12967,7 +12972,7 @@ class Sema final {
QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc);

bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
bool DiagnoseConditionalForNull(const Expr *LHSExpr, const Expr *RHSExpr,
SourceLocation QuestionLoc);

void DiagnoseAlwaysNonNullPointer(Expr *E,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ enum class TemplateSubstitutionKind : char {
const MultiLevelTemplateArgumentList &TemplateArgs;
Sema::LateInstantiatedAttrVec* LateAttrs = nullptr;
LocalInstantiationScope *StartingScope = nullptr;
// Whether to evaluate the C++20 constraints or simply substitute into them.
bool EvaluateConstraints = true;

/// A list of out-of-line class template partial
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace clang {
namespace ento {
namespace categories {
extern const char *const AppleAPIMisuse;
extern const char *const CoreFoundationObjectiveC;
extern const char *const LogicError;
extern const char *const MemoryRefCount;
Expand Down
14 changes: 5 additions & 9 deletions clang/include/clang/StaticAnalyzer/Core/Checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,8 @@ class PostCall {

class Location {
template <typename CHECKER>
static void _checkLocation(void *checker,
const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &C) {
static void _checkLocation(void *checker, SVal location, bool isLoad,
const Stmt *S, CheckerContext &C) {
((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
}

Expand All @@ -209,8 +208,7 @@ class Location {

class Bind {
template <typename CHECKER>
static void _checkBind(void *checker,
const SVal &location, const SVal &val, const Stmt *S,
static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S,
CheckerContext &C) {
((const CHECKER *)checker)->checkBind(location, val, S, C);
}
Expand Down Expand Up @@ -456,10 +454,8 @@ namespace eval {

class Assume {
template <typename CHECKER>
static ProgramStateRef _evalAssume(void *checker,
ProgramStateRef state,
const SVal &cond,
bool assumption) {
static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state,
SVal cond, bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
}

Expand Down
11 changes: 4 additions & 7 deletions clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,13 +488,11 @@ class CheckerManager {
using CheckCallFunc =
CheckerFn<void (const CallEvent &, CheckerContext &)>;

using CheckLocationFunc =
CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &)>;
using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad,
const Stmt *S, CheckerContext &)>;

using CheckBindFunc =
CheckerFn<void (const SVal &location, const SVal &val, const Stmt *S,
CheckerContext &)>;
CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;

using CheckEndAnalysisFunc =
CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;
Expand Down Expand Up @@ -530,8 +528,7 @@ class CheckerManager {
RegionAndSymbolInvalidationTraits *ITraits)>;

using EvalAssumeFunc =
CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond,
bool assumption)>;
CheckerFn<ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)>;

using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>;

Expand Down
30 changes: 18 additions & 12 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,13 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping);
InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator);
}
// Placeholder type for OpenACC array sections.
if (LangOpts.OpenACC) {
// FIXME: Once we implement OpenACC array sections in Sema, this will either
// be combined with the OpenMP type, or given its own type. In the meantime,
// just use the OpenMP type so that parsing can work.
InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection);
}
if (LangOpts.MatrixTypes)
InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx);

Expand Down Expand Up @@ -2748,21 +2755,20 @@ bool ASTContext::hasUniqueObjectRepresentations(
QualType Ty, bool CheckIfTriviallyCopyable) const {
// C++17 [meta.unary.prop]:
// The predicate condition for a template specialization
// has_unique_object_representations<T> shall be
// satisfied if and only if:
// has_unique_object_representations<T> shall be satisfied if and only if:
// (9.1) - T is trivially copyable, and
// (9.2) - any two objects of type T with the same value have the same
// object representation, where two objects
// of array or non-union class type are considered to have the same value
// if their respective sequences of
// direct subobjects have the same values, and two objects of union type
// are considered to have the same
// value if they have the same active member and the corresponding members
// have the same value.
// object representation, where:
// - two objects of array or non-union class type are considered to have
// the same value if their respective sequences of direct subobjects
// have the same values, and
// - two objects of union type are considered to have the same value if
// they have the same active member and the corresponding members have
// the same value.
// The set of scalar types for which this condition holds is
// implementation-defined. [ Note: If a type has padding
// bits, the condition does not hold; otherwise, the condition holds true
// for unsigned integral types. -- end note ]
// implementation-defined. [ Note: If a type has padding bits, the condition
// does not hold; otherwise, the condition holds true for unsigned integral
// types. -- end note ]
assert(!Ty.isNull() && "Null QualType sent to unique object rep check");

// Arrays are unique only if their element type is unique.
Expand Down
39 changes: 23 additions & 16 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2034,23 +2034,25 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
return ToDCOrErr.takeError();
}

DeclContext *ToDC = *ToDCOrErr;
// Remove all declarations, which may be in wrong order in the
// lexical DeclContext and then add them in the proper order.
for (auto *D : FromDC->decls()) {
if (!MightNeedReordering(D))
continue;
if (const auto *FromRD = dyn_cast<RecordDecl>(FromDC)) {
DeclContext *ToDC = *ToDCOrErr;
// Remove all declarations, which may be in wrong order in the
// lexical DeclContext and then add them in the proper order.
for (auto *D : FromRD->decls()) {
if (!MightNeedReordering(D))
continue;

assert(D && "DC contains a null decl");
if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) {
// Remove only the decls which we successfully imported.
assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
// Remove the decl from its wrong place in the linked list.
ToDC->removeDecl(ToD);
// Add the decl to the end of the linked list.
// This time it will be at the proper place because the enclosing for
// loop iterates in the original (good) order of the decls.
ToDC->addDeclInternal(ToD);
assert(D && "DC contains a null decl");
if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) {
// Remove only the decls which we successfully imported.
assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
// Remove the decl from its wrong place in the linked list.
ToDC->removeDecl(ToD);
// Add the decl to the end of the linked list.
// This time it will be at the proper place because the enclosing for
// loop iterates in the original (good) order of the decls.
ToDC->addDeclInternal(ToD);
}
}
}

Expand Down Expand Up @@ -6141,6 +6143,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
InsertPos))
// Add this partial specialization to the class template.
ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos);
if (Expected<ClassTemplatePartialSpecializationDecl *> ToInstOrErr =
import(PartialSpec->getInstantiatedFromMember()))
PartSpec2->setInstantiatedFromMember(*ToInstOrErr);
else
return ToInstOrErr.takeError();

updateLookupTableForTemplateParameters(*ToTPList);
} else { // Not a partial specialization.
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1463,8 +1463,9 @@ IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
}

/// Determine if context of a class is equivalent.
static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1,
RecordDecl *D2) {
static bool
IsRecordContextStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
// The context should be completely equal, including anonymous and inline
// namespaces.
// We compare objects as part of full translation units, not subtrees of
Expand All @@ -1491,6 +1492,12 @@ static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1,
return false;
}

if (auto *D1Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
auto *D2Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
if (!IsStructurallyEquivalent(Context, D1Spec, D2Spec))
return false;
}

DC1 = DC1->getParent()->getNonTransparentContext();
DC2 = DC2->getParent()->getNonTransparentContext();
}
Expand Down Expand Up @@ -1544,7 +1551,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// If the records occur in different context (namespace), these should be
// different. This is specially important if the definition of one or both
// records is missing.
if (!IsRecordContextStructurallyEquivalent(D1, D2))
if (!IsRecordContextStructurallyEquivalent(Context, D1, D2))
return false;

// If both declarations are class template specializations, we know
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ ExprDependence clang::computeDependence(PredefinedExpr *E) {
ExprDependence clang::computeDependence(CallExpr *E,
llvm::ArrayRef<Expr *> PreArgs) {
auto D = E->getCallee()->getDependence();
if (E->getType()->isDependentType())
D |= ExprDependence::Type;
for (auto *A : llvm::ArrayRef(E->getArgs(), E->getNumArgs())) {
if (A)
D |= A->getDependence();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2835,7 +2835,7 @@ CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const {
if (!Ty || !Ty->getDecl()->hasFlexibleArrayMember())
return CharUnits::Zero();
auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens());
if (!List)
if (!List || List->getNumInits() == 0)
return CharUnits::Zero();
const Expr *FlexibleInit = List->getInit(List->getNumInits() - 1);
auto InitTy = Ctx.getAsConstantArrayType(FlexibleInit->getType());
Expand Down
50 changes: 16 additions & 34 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,39 +930,27 @@ const AttrVec &Decl::getAttrs() const {

Decl *Decl::castFromDeclContext (const DeclContext *D) {
Decl::Kind DK = D->getDeclKind();
switch(DK) {
#define DECL(NAME, BASE)
#define DECL_CONTEXT(NAME) \
case Decl::NAME: \
return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D));
#define DECL_CONTEXT_BASE(NAME)
#include "clang/AST/DeclNodes.inc"
default:
switch (DK) {
#define DECL(NAME, BASE)
#define DECL_CONTEXT_BASE(NAME) \
if (DK >= first##NAME && DK <= last##NAME) \
return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D));
#define DECL_CONTEXT(NAME) \
case Decl::NAME: \
return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D));
#include "clang/AST/DeclNodes.inc"
llvm_unreachable("a decl that inherits DeclContext isn't handled");
default:
llvm_unreachable("a decl that inherits DeclContext isn't handled");
}
}

DeclContext *Decl::castToDeclContext(const Decl *D) {
Decl::Kind DK = D->getKind();
switch(DK) {
#define DECL(NAME, BASE)
#define DECL_CONTEXT(NAME) \
case Decl::NAME: \
return static_cast<NAME##Decl *>(const_cast<Decl *>(D));
#define DECL_CONTEXT_BASE(NAME)
#define DECL_CONTEXT(NAME) \
case Decl::NAME: \
return static_cast<NAME##Decl *>(const_cast<Decl *>(D));
#include "clang/AST/DeclNodes.inc"
default:
#define DECL(NAME, BASE)
#define DECL_CONTEXT_BASE(NAME) \
if (DK >= first##NAME && DK <= last##NAME) \
return static_cast<NAME##Decl *>(const_cast<Decl *>(D));
#include "clang/AST/DeclNodes.inc"
llvm_unreachable("a decl that inherits DeclContext isn't handled");
default:
llvm_unreachable("a decl that inherits DeclContext isn't handled");
}
}

Expand Down Expand Up @@ -1129,20 +1117,14 @@ DeclContext::DeclContext(Decl::Kind K) {
}

bool DeclContext::classof(const Decl *D) {
switch (D->getKind()) {
Decl::Kind DK = D->getKind();
switch (DK) {
#define DECL(NAME, BASE)
#define DECL_CONTEXT(NAME) case Decl::NAME:
#define DECL_CONTEXT_BASE(NAME)
#include "clang/AST/DeclNodes.inc"
return true;
default:
#define DECL(NAME, BASE)
#define DECL_CONTEXT_BASE(NAME) \
if (D->getKind() >= Decl::first##NAME && \
D->getKind() <= Decl::last##NAME) \
return true;
#include "clang/AST/DeclNodes.inc"
return false;
return true;
default:
return false;
}
}

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,19 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
return true;
}

bool CXXRecordDecl::isTriviallyCopyConstructible() const {

// A trivially copy constructible class is a class that:
// -- has no non-trivial copy constructors,
if (hasNonTrivialCopyConstructor())
return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor())
return false;

return true;
}

void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/FormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,6 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return NoMatchPromotionTypeConfusion;
break;
case BuiltinType::Half:
case BuiltinType::Float16:
case BuiltinType::Float:
if (T == C.DoubleTy)
return MatchPromotion;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,17 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
}

case CK_FloatingCast: {
if (DiscardResult)
return this->discard(SubExpr);
if (!this->visit(SubExpr))
return false;
const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
return this->emitCastFP(TargetSemantics, getRoundingMode(CE), CE);
}

case CK_IntegralToFloating: {
if (DiscardResult)
return this->discard(SubExpr);
std::optional<PrimType> FromT = classify(SubExpr->getType());
if (!FromT)
return false;
Expand All @@ -135,6 +139,9 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {

case CK_FloatingToBoolean:
case CK_FloatingToIntegral: {
if (DiscardResult)
return this->discard(SubExpr);

std::optional<PrimType> ToT = classify(CE->getType());

if (!ToT)
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
}

/// Unknown-size arrays of composite elements.
Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
UnknownSize)
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem,
bool IsTemporary, UnknownSize)
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
Size(UnknownSizeMark), MDSize(0),
AllocSize(alignof(void *) + sizeof(InitMapPtr)), ElemDesc(Elem),
Expand All @@ -286,7 +286,7 @@ Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
}

/// Composite records.
Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD,
Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
bool IsConst, bool IsTemporary, bool IsMutable)
: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct Descriptor final {
static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);

/// Pointer to the record, if block contains records.
Record *const ElemRecord = nullptr;
const Record *const ElemRecord = nullptr;
/// Descriptor of the array element.
const Descriptor *const ElemDesc = nullptr;
/// Flag indicating if the block is mutable.
Expand Down Expand Up @@ -135,10 +135,11 @@ struct Descriptor final {
unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);

/// Allocates a descriptor for an array of composites of unknown size.
Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
Descriptor(const DeclTy &D, const Descriptor *Elem, bool IsTemporary,
UnknownSize);

/// Allocates a descriptor for a record.
Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst,
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);

Descriptor(const DeclTy &D, MetadataSize MD);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,10 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
}

bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckLive(S, OpPC, Ptr, AK_Read))
return false;
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Read))
Expand Down
7 changes: 0 additions & 7 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
namespace clang {
namespace interp {

using APInt = llvm::APInt;
using APSInt = llvm::APSInt;

/// Convert a value to an APValue.
Expand Down Expand Up @@ -1814,9 +1813,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (!CheckArray(S, OpPC, Ptr))
return false;

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

Expand Down Expand Up @@ -1844,9 +1840,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (!CheckArray(S, OpPC, Ptr))
return false;

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

Expand Down
16 changes: 8 additions & 8 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,14 +315,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
bool IsConst, bool IsTemporary,
bool IsMutable, const Expr *Init) {
// Classes and structures.
if (auto *RT = Ty->getAs<RecordType>()) {
if (auto *Record = getOrCreateRecord(RT->getDecl()))
if (const auto *RT = Ty->getAs<RecordType>()) {
if (const auto *Record = getOrCreateRecord(RT->getDecl()))
return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
IsMutable);
}

// Arrays.
if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
QualType ElemTy = ArrayType->getElementType();
// Array of well-known bounds.
if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
Expand All @@ -338,7 +338,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
} else {
// Arrays of composites. In this case, the array is a list of pointers,
// followed by the actual elements.
Descriptor *ElemDesc = createDescriptor(
const Descriptor *ElemDesc = createDescriptor(
D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
if (!ElemDesc)
return nullptr;
Expand All @@ -358,8 +358,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
return allocateDescriptor(D, *T, IsTemporary,
Descriptor::UnknownSize{});
} else {
Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize,
IsConst, IsTemporary);
const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(),
MDSize, IsConst, IsTemporary);
if (!Desc)
return nullptr;
return allocateDescriptor(D, Desc, IsTemporary,
Expand All @@ -369,14 +369,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
}

// Atomic types.
if (auto *AT = Ty->getAs<AtomicType>()) {
if (const auto *AT = Ty->getAs<AtomicType>()) {
const Type *InnerTy = AT->getValueType().getTypePtr();
return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
IsMutable);
}

// Complex types - represented as arrays of elements.
if (auto *CT = Ty->getAs<ComplexType>()) {
if (const auto *CT = Ty->getAs<ComplexType>()) {
PrimType ElemTy = *Ctx.classify(CT->getElementType());
return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
IsMutable);
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,16 @@ void clang::TextNodeDumper::VisitReturnStmt(const ReturnStmt *Node) {
}
}

void clang::TextNodeDumper::VisitCoawaitExpr(const CoawaitExpr *Node) {
if (Node->isImplicit())
OS << " implicit";
}

void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) {
if (Node->isImplicit())
OS << " implicit";
}

void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
if (Node->hasAPValueResult())
AddChild("value",
Expand Down
41 changes: 32 additions & 9 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,19 +2604,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
return false;
}

bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTriviallyCopyableType(Context);
static bool isTriviallyCopyableTypeImpl(const QualType &type,
const ASTContext &Context,
bool IsCopyConstructible) {
if (type->isArrayType())
return isTriviallyCopyableTypeImpl(Context.getBaseElementType(type),
Context, IsCopyConstructible);

if (hasNonTrivialObjCLifetime())
if (type.hasNonTrivialObjCLifetime())
return false;

// C++11 [basic.types]p9 - See Core 2094
// Scalar types, trivially copyable class types, arrays of such types, and
// cv-qualified versions of these types are collectively
// called trivially copyable types.
// called trivially copy constructible types.

QualType CanonicalType = getCanonicalType();
QualType CanonicalType = type.getCanonicalType();
if (CanonicalType->isDependentType())
return false;

Expand All @@ -2634,16 +2637,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {

if (const auto *RT = CanonicalType->getAs<RecordType>()) {
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
if (IsCopyConstructible) {
return ClassDecl->isTriviallyCopyConstructible();
} else {
return ClassDecl->isTriviallyCopyable();
}
}

return true;
}

// No other types can match.
return false;
}

bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
return isTriviallyCopyableTypeImpl(*this, Context,
/*IsCopyConstructible=*/false);
}

bool QualType::isTriviallyCopyConstructibleType(
const ASTContext &Context) const {
return isTriviallyCopyableTypeImpl(*this, Context,
/*IsCopyConstructible=*/true);
}

bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
QualType BaseElementType = Context.getBaseElementType(*this);

Expand Down Expand Up @@ -3414,6 +3430,13 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
llvm_unreachable("Invalid calling convention.");
}

void FunctionProtoType::ExceptionSpecInfo::instantiate() {
assert(Type == EST_Uninstantiated);
NoexceptExpr =
cast<FunctionProtoType>(SourceTemplate->getType())->getNoexceptExpr();
Type = EST_DependentNoexcept;
}

FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
QualType canonical,
const ExtProtoInfo &epi)
Expand Down
355 changes: 191 additions & 164 deletions clang/lib/Analysis/ExprMutationAnalyzer.cpp

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions clang/lib/Analysis/PathDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@
using namespace clang;
using namespace ento;

static StringRef StripTrailingDots(StringRef s) {
for (StringRef::size_type i = s.size(); i != 0; --i)
if (s[i - 1] != '.')
return s.substr(0, i);
return {};
}
static StringRef StripTrailingDots(StringRef s) { return s.rtrim('.'); }

PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
Kind k, DisplayHint hint)
Expand Down
38 changes: 34 additions & 4 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,34 @@ class UnsafeBufferUsageAttrGadget : public WarningGadget {
DeclUseList getClaimedVarUseSites() const override { return {}; }
};

// Warning gadget for unsafe invocation of span::data method.
// Triggers when the pointer returned by the invocation is immediately
// cast to a larger type.

class DataInvocationGadget : public WarningGadget {
constexpr static const char *const OpTag = "data_invocation_expr";
const ExplicitCastExpr *Op;

public:
DataInvocationGadget(const MatchFinder::MatchResult &Result)
: WarningGadget(Kind::DataInvocation),
Op(Result.Nodes.getNodeAs<ExplicitCastExpr>(OpTag)) {}

static bool classof(const Gadget *G) {
return G->getKind() == Kind::DataInvocation;
}

static Matcher matcher() {
return stmt(
explicitCastExpr(has(cxxMemberCallExpr(callee(cxxMethodDecl(
hasName("data"), ofClass(hasName("std::span")))))))
.bind(OpTag));
}
const Stmt *getBaseStmt() const override { return Op; }

DeclUseList getClaimedVarUseSites() const override { return {}; }
};

// Represents expressions of the form `DRE[*]` in the Unspecified Lvalue
// Context (see `isInUnspecifiedLvalueContext`).
// Note here `[]` is the built-in subscript operator.
Expand Down Expand Up @@ -2657,8 +2685,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
// every problematic operation and consider it done. No need to deal
// with fixable gadgets, no need to group operations by variable.
for (const auto &G : WarningGadgets) {
Handler.handleUnsafeOperation(G->getBaseStmt(),
/*IsRelatedToDecl=*/false);
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false,
D->getASTContext());
}

// This return guarantees that most of the machine doesn't run when
Expand Down Expand Up @@ -2893,7 +2921,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
Tracker, Handler, VarGrpMgr);

for (const auto &G : UnsafeOps.noVar) {
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false);
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false,
D->getASTContext());
}

for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
Expand All @@ -2904,7 +2933,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
: FixItList{},
D);
for (const auto &G : WarningGadgets) {
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true);
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true,
D->getASTContext());
}
}
}
64 changes: 64 additions & 0 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TargetParser/ARMTargetParser.h"

using namespace clang;
using namespace clang::targets;
Expand Down Expand Up @@ -837,6 +838,69 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.RWPI)
Builder.defineMacro("__ARM_RWPI", "1");

// Macros for enabling co-proc intrinsics
uint64_t FeatureCoprocBF = 0;
switch (ArchKind) {
default:
break;
case llvm::ARM::ArchKind::ARMV4:
case llvm::ARM::ArchKind::ARMV4T:
// Filter __arm_ldcl and __arm_stcl in acle.h
FeatureCoprocBF = isThumb() ? 0 : FEATURE_COPROC_B1;
break;
case llvm::ARM::ArchKind::ARMV5T:
FeatureCoprocBF = isThumb() ? 0 : FEATURE_COPROC_B1 | FEATURE_COPROC_B2;
break;
case llvm::ARM::ArchKind::ARMV5TE:
case llvm::ARM::ArchKind::ARMV5TEJ:
if (!isThumb())
FeatureCoprocBF =
FEATURE_COPROC_B1 | FEATURE_COPROC_B2 | FEATURE_COPROC_B3;
break;
case llvm::ARM::ArchKind::ARMV6:
case llvm::ARM::ArchKind::ARMV6K:
case llvm::ARM::ArchKind::ARMV6KZ:
case llvm::ARM::ArchKind::ARMV6T2:
if (!isThumb() || ArchKind == llvm::ARM::ArchKind::ARMV6T2)
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
case llvm::ARM::ArchKind::ARMV7A:
case llvm::ARM::ArchKind::ARMV7R:
case llvm::ARM::ArchKind::ARMV7M:
case llvm::ARM::ArchKind::ARMV7S:
case llvm::ARM::ArchKind::ARMV7EM:
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
case llvm::ARM::ArchKind::ARMV8A:
case llvm::ARM::ArchKind::ARMV8R:
case llvm::ARM::ArchKind::ARMV8_1A:
case llvm::ARM::ArchKind::ARMV8_2A:
case llvm::ARM::ArchKind::ARMV8_3A:
case llvm::ARM::ArchKind::ARMV8_4A:
case llvm::ARM::ArchKind::ARMV8_5A:
case llvm::ARM::ArchKind::ARMV8_6A:
case llvm::ARM::ArchKind::ARMV8_7A:
case llvm::ARM::ArchKind::ARMV8_8A:
case llvm::ARM::ArchKind::ARMV8_9A:
case llvm::ARM::ArchKind::ARMV9A:
case llvm::ARM::ArchKind::ARMV9_1A:
case llvm::ARM::ArchKind::ARMV9_2A:
case llvm::ARM::ArchKind::ARMV9_3A:
case llvm::ARM::ArchKind::ARMV9_4A:
// Filter __arm_cdp, __arm_ldcl, __arm_stcl in arm_acle.h
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B3;
break;
case llvm::ARM::ArchKind::ARMV8MMainline:
case llvm::ARM::ArchKind::ARMV8_1MMainline:
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
}
Builder.defineMacro("__ARM_FEATURE_COPROC",
"0x" + Twine::utohexstr(FeatureCoprocBF));

if (ArchKind == llvm::ARM::ArchKind::XSCALE)
Builder.defineMacro("__XSCALE__");

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
};
uint32_t HW_FP;

enum {
/// __arm_cdp __arm_ldc, __arm_ldcl, __arm_stc,
/// __arm_stcl, __arm_mcr and __arm_mrc
FEATURE_COPROC_B1 = (1 << 0),
/// __arm_cdp2, __arm_ldc2, __arm_stc2, __arm_ldc2l,
/// __arm_stc2l, __arm_mcr2 and __arm_mrc2
FEATURE_COPROC_B2 = (1 << 1),
/// __arm_mcrr, __arm_mrrc
FEATURE_COPROC_B3 = (1 << 2),
/// __arm_mcrr2, __arm_mrrc2
FEATURE_COPROC_B4 = (1 << 3),
};

void setABIAAPCS();
void setABIAPCS(bool IsAAPCS16);

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Basic/Targets/AVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo {
case 'R': // Integer constant (Range: -6 to 5)
Info.setRequiresImmediate(-6, 5);
return true;
case 'G': // Floating point constant
case 'G': // Floating point constant 0.0
Info.setRequiresImmediate(0);
return true;
case 'Q': // A memory address based on Y or Z pointer with displacement.
return true;
}
Expand Down
23 changes: 8 additions & 15 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,22 +237,15 @@ ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {

static std::vector<std::string>
collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) {
auto ParseResult =
llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesNeedOverride);

if (!ParseResult) {
consumeError(ParseResult.takeError());
return std::vector<std::string>();
}

std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();

std::vector<std::string> NonISAExtFeatureVec;

auto IsNonISAExtFeature = [](const std::string &Feature) {
assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
StringRef Ext = StringRef(Feature).drop_front(); // drop the +/-
return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
};
llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec),
[&](const std::string &Feat) {
return !llvm::is_contained(ImpliedFeatures, Feat);
});
IsNonISAExtFeature);

return NonISAExtFeatureVec;
}
Expand Down Expand Up @@ -303,7 +296,7 @@ bool RISCVTargetInfo::initFeatureMap(
}

// RISCVISAInfo makes implications for ISA features
std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatures();

// parseFeatures normalizes the feature set by dropping any explicit
// negatives, and non-extension features. We need to preserve the later
Expand Down Expand Up @@ -420,7 +413,7 @@ static void handleFullArchString(StringRef FullArchStr,
// Forward the invalid FullArchStr.
Features.push_back("+" + FullArchStr.str());
} else {
std::vector<std::string> FeatStrings = (*RII)->toFeatureVector();
std::vector<std::string> FeatStrings = (*RII)->toFeatures();
Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
}
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,13 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAVX512BF16 = true;
} else if (Feature == "+avx512er") {
HasAVX512ER = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+avx512fp16") {
HasAVX512FP16 = true;
HasLegalHalfType = true;
} else if (Feature == "+avx512pf") {
HasAVX512PF = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+avx512dq") {
HasAVX512DQ = true;
} else if (Feature == "+avx512bitalg") {
Expand Down Expand Up @@ -358,6 +360,7 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasPREFETCHI = true;
} else if (Feature == "+prefetchwt1") {
HasPREFETCHWT1 = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+clzero") {
HasCLZERO = true;
} else if (Feature == "+cldemote") {
Expand Down
24 changes: 22 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9681,8 +9681,8 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
bool IsQuadStore = false;

switch (IntrinsicID) {
case Intrinsic::aarch64_sve_st1uwq:
case Intrinsic::aarch64_sve_st1udq:
case Intrinsic::aarch64_sve_st1wq:
case Intrinsic::aarch64_sve_st1dq:
AddrMemoryTy = llvm::ScalableVectorType::get(MemEltTy, 1);
PredTy =
llvm::ScalableVectorType::get(IntegerType::get(getLLVMContext(), 1), 1);
Expand Down Expand Up @@ -10430,6 +10430,26 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}

if (BuiltinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
// Create call to __arm_sme_state and store the results to the two pointers.
CallInst *CI = EmitRuntimeCall(CGM.CreateRuntimeFunction(
llvm::FunctionType::get(StructType::get(CGM.Int64Ty, CGM.Int64Ty), {},
false),
"__arm_sme_state"));
auto Attrs =
AttributeList()
.addFnAttribute(getLLVMContext(), "aarch64_pstate_sm_compatible")
.addFnAttribute(getLLVMContext(), "aarch64_pstate_za_preserved");
CI->setAttributes(Attrs);
CI->setCallingConv(
llvm::CallingConv::
AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2);
Builder.CreateStore(Builder.CreateExtractValue(CI, 0),
EmitPointerWithAlignment(E->getArg(0)));
return Builder.CreateStore(Builder.CreateExtractValue(CI, 1),
EmitPointerWithAlignment(E->getArg(1)));
}

if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit) {
assert((getContext().getTypeSize(E->getType()) == 32) &&
"rbit of unusual size!");
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);

incrementProfileCounter(Body);
maybeCreateMCDCCondBitmap();

RunCleanupsScope RunCleanups(*this);

Expand Down Expand Up @@ -1444,8 +1445,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
}

Stmt *Body = Dtor->getBody();
if (Body)
if (Body) {
incrementProfileCounter(Body);
maybeCreateMCDCCondBitmap();
}

// The call to operator delete in a deleting destructor happens
// outside of the function-try-block, which means it's always
Expand Down Expand Up @@ -1548,6 +1551,7 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
LexicalScope Scope(*this, RootCS->getSourceRange());

incrementProfileCounter(RootCS);
maybeCreateMCDCCondBitmap();
AssignmentMemcpyizer AM(*this, AssignOp, Args);
for (auto *I : RootCS->body())
AM.emitAssignment(I);
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
case ObjCRuntime::WatchOS:
return EHPersonality::NeXT_ObjC;
case ObjCRuntime::GNUstep:
if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
if (T.isOSCygMing())
return EHPersonality::GNU_CPlusPlus_SEH;
else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
return EHPersonality::GNUstep_ObjC;
[[fallthrough]];
case ObjCRuntime::GCC:
Expand Down Expand Up @@ -210,7 +212,8 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
return getObjCPersonality(Target, L);

case ObjCRuntime::GNUstep:
return EHPersonality::GNU_ObjCXX;
return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH
: EHPersonality::GNU_ObjCXX;

// The GCC runtime's personality function inherently doesn't support
// mixed EH. Use the ObjC personality just to avoid returning null.
Expand Down
61 changes: 59 additions & 2 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4564,6 +4564,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
if (LHSCondVal) { // If we have 1 && X, just emit X.
CGF.incrementProfileCounter(E);

// If the top of the logical operator nest, reset the MCDC temp to 0.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeResetMCDCCondBitmap(E);

CGF.MCDCLogOpStack.push_back(E);

Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());

// If we're generating for profiling or coverage, generate a branch to a
Expand All @@ -4572,6 +4578,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// "FalseBlock" after the increment is done.
if (InstrumentRegions &&
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
llvm::BasicBlock *FBlock = CGF.createBasicBlock("land.end");
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
Builder.CreateCondBr(RHSCond, RHSBlockCnt, FBlock);
Expand All @@ -4581,6 +4588,11 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
CGF.EmitBlock(FBlock);
}

CGF.MCDCLogOpStack.pop_back();
// If the top of the logical operator nest, update the MCDC bitmap.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeUpdateMCDCTestVectorBitmap(E);

// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
}
Expand All @@ -4590,6 +4602,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
return llvm::Constant::getNullValue(ResTy);
}

// If the top of the logical operator nest, reset the MCDC temp to 0.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeResetMCDCCondBitmap(E);

CGF.MCDCLogOpStack.push_back(E);

llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs");

Expand Down Expand Up @@ -4622,6 +4640,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// condition coverage.
if (InstrumentRegions &&
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("land.rhscnt");
Builder.CreateCondBr(RHSCond, RHSBlockCnt, ContBlock);
CGF.EmitBlock(RHSBlockCnt);
Expand All @@ -4639,6 +4658,11 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// Insert an entry into the phi node for the edge with the value of RHSCond.
PN->addIncoming(RHSCond, RHSBlock);

CGF.MCDCLogOpStack.pop_back();
// If the top of the logical operator nest, update the MCDC bitmap.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeUpdateMCDCTestVectorBitmap(E);

// Artificial location to preserve the scope information
{
auto NL = ApplyDebugLocation::CreateArtificial(CGF);
Expand Down Expand Up @@ -4680,6 +4704,12 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
if (!LHSCondVal) { // If we have 0 || X, just emit X.
CGF.incrementProfileCounter(E);

// If the top of the logical operator nest, reset the MCDC temp to 0.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeResetMCDCCondBitmap(E);

CGF.MCDCLogOpStack.push_back(E);

Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());

// If we're generating for profiling or coverage, generate a branch to a
Expand All @@ -4688,6 +4718,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// "FalseBlock" after the increment is done.
if (InstrumentRegions &&
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
llvm::BasicBlock *FBlock = CGF.createBasicBlock("lor.end");
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
Builder.CreateCondBr(RHSCond, FBlock, RHSBlockCnt);
Expand All @@ -4697,6 +4728,11 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
CGF.EmitBlock(FBlock);
}

CGF.MCDCLogOpStack.pop_back();
// If the top of the logical operator nest, update the MCDC bitmap.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeUpdateMCDCTestVectorBitmap(E);

// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
}
Expand All @@ -4706,6 +4742,12 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
return llvm::ConstantInt::get(ResTy, 1);
}

// If the top of the logical operator nest, reset the MCDC temp to 0.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeResetMCDCCondBitmap(E);

CGF.MCDCLogOpStack.push_back(E);

llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs");

Expand Down Expand Up @@ -4742,6 +4784,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// condition coverage.
if (InstrumentRegions &&
CodeGenFunction::isInstrumentedCondition(E->getRHS())) {
CGF.maybeUpdateMCDCCondBitmap(E->getRHS(), RHSCond);
llvm::BasicBlock *RHSBlockCnt = CGF.createBasicBlock("lor.rhscnt");
Builder.CreateCondBr(RHSCond, ContBlock, RHSBlockCnt);
CGF.EmitBlock(RHSBlockCnt);
Expand All @@ -4755,6 +4798,11 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
CGF.EmitBlock(ContBlock);
PN->addIncoming(RHSCond, RHSBlock);

CGF.MCDCLogOpStack.pop_back();
// If the top of the logical operator nest, update the MCDC bitmap.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeUpdateMCDCTestVectorBitmap(E);

// ZExt result to int.
return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext");
}
Expand Down Expand Up @@ -4899,6 +4947,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return Builder.CreateSelect(CondV, LHS, RHS, "cond");
}

// If the top of the logical operator nest, reset the MCDC temp to 0.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeResetMCDCCondBitmap(condExpr);

llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
Expand Down Expand Up @@ -4934,6 +4986,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond");
PN->addIncoming(LHS, LHSBlock);
PN->addIncoming(RHS, RHSBlock);

// If the top of the logical operator nest, update the MCDC bitmap.
if (CGF.MCDCLogOpStack.empty())
CGF.maybeUpdateMCDCTestVectorBitmap(condExpr);

return PN;
}

Expand Down Expand Up @@ -5292,8 +5349,8 @@ static GEPOffsetAndOverflow EmitGEPOffsetInBytes(Value *BasePtr, Value *GEPVal,
} else {
// Otherwise this is array-like indexing. The local offset is the index
// multiplied by the element size.
auto *ElementSize = llvm::ConstantInt::get(
IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType()));
auto *ElementSize =
llvm::ConstantInt::get(IntPtrTy, GTI.getSequentialElementStride(DL));
auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, /*isSigned=*/true);
LocalOffset = eval(BO_Mul, ElementSize, IndexS);
}
Expand Down
37 changes: 25 additions & 12 deletions clang/lib/CodeGen/CGObjCGNU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class CGObjCGNU : public CGObjCRuntime {
/// Does the current target use SEH-based exceptions? False implies
/// Itanium-style DWARF unwinding.
bool usesSEHExceptions;
/// Does the current target uses C++-based exceptions?
bool usesCxxExceptions;

/// Helper to check if we are targeting a specific runtime version or later.
bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) {
Expand Down Expand Up @@ -819,12 +821,18 @@ class CGObjCGNUstep : public CGObjCGNU {
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
PtrToObjCSuperTy, SelectorTy);
// If we're in ObjC++ mode, then we want to make
if (usesSEHExceptions) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_rethrow(void)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
if (usesCxxExceptions) {
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
// void objc_exception_rethrow(void*)
ExceptionReThrowFn.init(&CGM, "__cxa_rethrow", PtrTy);
} else if (usesSEHExceptions) {
// void objc_exception_rethrow(void)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
} else if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
Expand All @@ -833,15 +841,13 @@ class CGObjCGNUstep : public CGObjCGNU {
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
PtrTy);
} else if (R.getVersion() >= VersionTuple(1, 7)) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// id objc_begin_catch(void *e)
EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy);
// void objc_end_catch(void)
ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy);
}
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
SelectorTy, IdTy, PtrDiffTy);
SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
Expand Down Expand Up @@ -1851,6 +1857,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
llvm::GlobalValue::HiddenVisibility :
llvm::GlobalValue::DefaultVisibility;
OffsetVar->setVisibility(ivarVisibility);
if (ivarVisibility != llvm::GlobalValue::HiddenVisibility)
CGM.setGVProperties(OffsetVar, OID->getClassInterface());
ivarBuilder.add(OffsetVar);
// Ivar size
ivarBuilder.addInt(Int32Ty,
Expand Down Expand Up @@ -2124,6 +2132,9 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
usesSEHExceptions =
cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment();
usesCxxExceptions =
cgm.getContext().getTargetInfo().getTriple().isOSCygMing() &&
isRuntime(ObjCRuntime::GNUstep, 2);

CodeGenTypes &Types = CGM.getTypes();
IntTy = cast<llvm::IntegerType>(
Expand Down Expand Up @@ -2210,7 +2221,10 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,

// void objc_exception_throw(id);
ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
ExceptionReThrowFn.init(&CGM,
usesCxxExceptions ? "objc_exception_rethrow"
: "objc_exception_throw",
VoidTy, IdTy);
// int objc_sync_enter(id);
SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
// int objc_sync_exit(id);
Expand Down Expand Up @@ -2387,7 +2401,7 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
if (usesSEHExceptions)
return CGM.getCXXABI().getAddrOfRTTIDescriptor(T);

if (!CGM.getLangOpts().CPlusPlus)
if (!CGM.getLangOpts().CPlusPlus && !usesCxxExceptions)
return CGObjCGNU::GetEHType(T);

// For Objective-C++, we want to provide the ability to catch both C++ and
Expand Down Expand Up @@ -3993,7 +4007,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
isRethrow = true;
}
if (isRethrow && usesSEHExceptions) {
if (isRethrow && (usesSEHExceptions || usesCxxExceptions)) {
// For SEH, ExceptionAsObject may be undef, because the catch handler is
// not passed it for catchalls and so it is not visible to the catch
// funclet. The real thrown object will still be live on the stack at this
Expand All @@ -4003,8 +4017,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
// argument.
llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn);
Throw->setDoesNotReturn();
}
else {
} else {
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallBase *Throw =
CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,19 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
if (!ThenCount && !getCurrentProfileCount() &&
CGM.getCodeGenOpts().OptimizationLevel)
LH = Stmt::getLikelihood(S.getThen(), S.getElse());
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);

// When measuring MC/DC, always fully evaluate the condition up front using
// EvaluateExprAsBool() so that the test vector bitmap can be updated prior to
// executing the body of the if.then or if.else. This is useful for when
// there is a 'return' within the body, but this is particularly beneficial
// when one if-stmt is nested within another if-stmt so that all of the MC/DC
// updates are kept linear and consistent.
if (!CGM.getCodeGenOpts().MCDCCoverage)
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);
else {
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock);
}

// Emit the 'then' code.
EmitBlock(ThenBlock);
Expand Down
61 changes: 40 additions & 21 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6406,13 +6406,11 @@ static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF,
}
}

static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
llvm::AtomicOrdering AO, const Expr *X,
const Expr *V, const Expr *R,
const Expr *E, const Expr *D,
const Expr *CE, bool IsXBinopExpr,
bool IsPostfixUpdate, bool IsFailOnly,
SourceLocation Loc) {
static void emitOMPAtomicCompareExpr(
CodeGenFunction &CGF, llvm::AtomicOrdering AO, llvm::AtomicOrdering FailAO,
const Expr *X, const Expr *V, const Expr *R, const Expr *E, const Expr *D,
const Expr *CE, bool IsXBinopExpr, bool IsPostfixUpdate, bool IsFailOnly,
SourceLocation Loc) {
llvm::OpenMPIRBuilder &OMPBuilder =
CGF.CGM.getOpenMPRuntime().getOMPBuilder();

Expand Down Expand Up @@ -6477,13 +6475,21 @@ static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
R->getType().isVolatileQualified()};
}

CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly));
if (FailAO == llvm::AtomicOrdering::NotAtomic) {
// fail clause was not mentionend on the
// "#pragma omp atomic compare" construct.
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly));
} else
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly, FailAO));
}

static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
llvm::AtomicOrdering AO, bool IsPostfixUpdate,
llvm::AtomicOrdering AO,
llvm::AtomicOrdering FailAO, bool IsPostfixUpdate,
const Expr *X, const Expr *V, const Expr *R,
const Expr *E, const Expr *UE, const Expr *D,
const Expr *CE, bool IsXLHSInRHSPart,
Expand All @@ -6504,12 +6510,8 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
IsXLHSInRHSPart, Loc);
break;
case OMPC_compare: {
emitOMPAtomicCompareExpr(CGF, AO, X, V, R, E, D, CE, IsXLHSInRHSPart,
IsPostfixUpdate, IsFailOnly, Loc);
break;
}
case OMPC_fail: {
//TODO
emitOMPAtomicCompareExpr(CGF, AO, FailAO, X, V, R, E, D, CE,
IsXLHSInRHSPart, IsPostfixUpdate, IsFailOnly, Loc);
break;
}
default:
Expand All @@ -6519,6 +6521,8 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,

void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
llvm::AtomicOrdering AO = llvm::AtomicOrdering::Monotonic;
// Fail Memory Clause Ordering.
llvm::AtomicOrdering FailAO = llvm::AtomicOrdering::NotAtomic;
bool MemOrderingSpecified = false;
if (S.getSingleClause<OMPSeqCstClause>()) {
AO = llvm::AtomicOrdering::SequentiallyConsistent;
Expand Down Expand Up @@ -6572,12 +6576,27 @@ void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
}
}

if (KindsEncountered.contains(OMPC_compare) &&
KindsEncountered.contains(OMPC_fail)) {
Kind = OMPC_compare;
const auto *FailClause = S.getSingleClause<OMPFailClause>();
if (FailClause) {
OpenMPClauseKind FailParameter = FailClause->getFailParameter();
if (FailParameter == llvm::omp::OMPC_relaxed)
FailAO = llvm::AtomicOrdering::Monotonic;
else if (FailParameter == llvm::omp::OMPC_acquire)
FailAO = llvm::AtomicOrdering::Acquire;
else if (FailParameter == llvm::omp::OMPC_seq_cst)
FailAO = llvm::AtomicOrdering::SequentiallyConsistent;
}
}

LexicalScope Scope(*this, S.getSourceRange());
EmitStopPoint(S.getAssociatedStmt());
emitOMPAtomicExpr(*this, Kind, AO, S.isPostfixUpdate(), S.getX(), S.getV(),
S.getR(), S.getExpr(), S.getUpdateExpr(), S.getD(),
S.getCondExpr(), S.isXLHSInRHSPart(), S.isFailOnly(),
S.getBeginLoc());
emitOMPAtomicExpr(*this, Kind, AO, FailAO, S.isPostfixUpdate(), S.getX(),
S.getV(), S.getR(), S.getExpr(), S.getUpdateExpr(),
S.getD(), S.getCondExpr(), S.isXLHSInRHSPart(),
S.isFailOnly(), S.getBeginLoc());
}

static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
Expand Down
98 changes: 71 additions & 27 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,

void CodeGenFunction::EmitFunctionBody(const Stmt *Body) {
incrementProfileCounter(Body);
maybeCreateMCDCCondBitmap();
if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
EmitCompoundStmtWithoutScope(*S);
else
Expand Down Expand Up @@ -1601,6 +1602,13 @@ bool CodeGenFunction::mightAddDeclToScope(const Stmt *S) {
bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
bool &ResultBool,
bool AllowLabels) {
// If MC/DC is enabled, disable folding so that we can instrument all
// conditions to yield complete test vectors. We still keep track of
// folded conditions during region mapping and visualization.
if (!AllowLabels && CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().MCDCCoverage)
return false;

llvm::APSInt ResultInt;
if (!ConstantFoldsToSimpleInteger(Cond, ResultInt, AllowLabels))
return false;
Expand Down Expand Up @@ -1629,16 +1637,20 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
return true;
}

/// Strip parentheses and simplistic logical-NOT operators.
const Expr *CodeGenFunction::stripCond(const Expr *C) {
while (const UnaryOperator *Op = dyn_cast<UnaryOperator>(C->IgnoreParens())) {
if (Op->getOpcode() != UO_LNot)
break;
C = Op->getSubExpr();
}
return C->IgnoreParens();
}

/// Determine whether the given condition is an instrumentable condition
/// (i.e. no "&&" or "||").
bool CodeGenFunction::isInstrumentedCondition(const Expr *C) {
// Bypass simplistic logical-NOT operator before determining whether the
// condition contains any other logical operator.
if (const UnaryOperator *UnOp = dyn_cast<UnaryOperator>(C->IgnoreParens()))
if (UnOp->getOpcode() == UO_LNot)
C = UnOp->getSubExpr();

const BinaryOperator *BOp = dyn_cast<BinaryOperator>(C->IgnoreParens());
const BinaryOperator *BOp = dyn_cast<BinaryOperator>(stripCond(C));
return (!BOp || !BOp->isLogicalOp());
}

Expand Down Expand Up @@ -1717,35 +1729,41 @@ void CodeGenFunction::EmitBranchToCounterBlock(
/// statement) to the specified blocks. Based on the condition, this might try
/// to simplify the codegen of the conditional based on the branch.
/// \param LH The value of the likelihood attribute on the True branch.
void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock,
uint64_t TrueCount,
Stmt::Likelihood LH) {
/// \param ConditionalOp Used by MC/DC code coverage to track the result of the
/// ConditionalOperator (ternary) through a recursive call for the operator's
/// LHS and RHS nodes.
void CodeGenFunction::EmitBranchOnBoolExpr(
const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock,
uint64_t TrueCount, Stmt::Likelihood LH, const Expr *ConditionalOp) {
Cond = Cond->IgnoreParens();

if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {

// Handle X && Y in a condition.
if (CondBOp->getOpcode() == BO_LAnd) {
MCDCLogOpStack.push_back(CondBOp);

// If we have "1 && X", simplify the code. "0 && X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
ConstantBool) {
// br(1 && X) -> br(X).
incrementProfileCounter(CondBOp);
return EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LAnd, TrueBlock,
FalseBlock, TrueCount, LH);
EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LAnd, TrueBlock,
FalseBlock, TrueCount, LH);
MCDCLogOpStack.pop_back();
return;
}

// If we have "X && 1", simplify the code to use an uncond branch.
// "X && 0" would have been constant folded to 0.
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
ConstantBool) {
// br(X && 1) -> br(X).
return EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LAnd, TrueBlock,
FalseBlock, TrueCount, LH, CondBOp);
EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LAnd, TrueBlock,
FalseBlock, TrueCount, LH, CondBOp);
MCDCLogOpStack.pop_back();
return;
}

// Emit the LHS as a conditional. If the LHS conditional is false, we
Expand Down Expand Up @@ -1774,31 +1792,36 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LAnd, TrueBlock,
FalseBlock, TrueCount, LH);
eval.end(*this);

MCDCLogOpStack.pop_back();
return;
}

if (CondBOp->getOpcode() == BO_LOr) {
MCDCLogOpStack.push_back(CondBOp);

// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
!ConstantBool) {
// br(0 || X) -> br(X).
incrementProfileCounter(CondBOp);
return EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LOr, TrueBlock,
FalseBlock, TrueCount, LH);
EmitBranchToCounterBlock(CondBOp->getRHS(), BO_LOr, TrueBlock,
FalseBlock, TrueCount, LH);
MCDCLogOpStack.pop_back();
return;
}

// If we have "X || 0", simplify the code to use an uncond branch.
// "X || 1" would have been constant folded to 1.
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
!ConstantBool) {
// br(X || 0) -> br(X).
return EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LOr, TrueBlock,
FalseBlock, TrueCount, LH, CondBOp);
EmitBranchToCounterBlock(CondBOp->getLHS(), BO_LOr, TrueBlock,
FalseBlock, TrueCount, LH, CondBOp);
MCDCLogOpStack.pop_back();
return;
}

// Emit the LHS as a conditional. If the LHS conditional is true, we
// want to jump to the TrueBlock.
llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false");
Expand Down Expand Up @@ -1829,14 +1852,20 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
RHSCount, LH);

eval.end(*this);

MCDCLogOpStack.pop_back();
return;
}
}

if (const UnaryOperator *CondUOp = dyn_cast<UnaryOperator>(Cond)) {
// br(!x, t, f) -> br(x, f, t)
if (CondUOp->getOpcode() == UO_LNot) {
// Avoid doing this optimization when instrumenting a condition for MC/DC.
// LNot is taken as part of the condition for simplicity, and changing its
// sense negatively impacts test vector tracking.
bool MCDCCondition = CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().MCDCCoverage &&
isInstrumentedCondition(Cond);
if (CondUOp->getOpcode() == UO_LNot && !MCDCCondition) {
// Negate the count.
uint64_t FalseCount = getCurrentProfileCount() - TrueCount;
// The values of the enum are chosen to make this negation possible.
Expand Down Expand Up @@ -1876,14 +1905,14 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
{
ApplyDebugLocation DL(*this, Cond);
EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock,
LHSScaledTrueCount, LH);
LHSScaledTrueCount, LH, CondOp);
}
cond.end(*this);

cond.begin(*this);
EmitBlock(RHSBlock);
EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock,
TrueCount - LHSScaledTrueCount, LH);
TrueCount - LHSScaledTrueCount, LH, CondOp);
cond.end(*this);

return;
Expand All @@ -1906,6 +1935,21 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
CondV = EvaluateExprAsBool(Cond);
}

// If not at the top of the logical operator nest, update MCDC temp with the
// boolean result of the evaluated condition.
if (!MCDCLogOpStack.empty()) {
const Expr *MCDCBaseExpr = Cond;
// When a nested ConditionalOperator (ternary) is encountered in a boolean
// expression, MC/DC tracks the result of the ternary, and this is tied to
// the ConditionalOperator expression and not the ternary's LHS or RHS. If
// this is the case, the ConditionalOperator expression is passed through
// the ConditionalOp parameter and then used as the MCDC base expression.
if (ConditionalOp)
MCDCBaseExpr = ConditionalOp;

maybeUpdateMCDCCondBitmap(MCDCBaseExpr, CondV);
}

llvm::MDNode *Weights = nullptr;
llvm::MDNode *Unpredictable = nullptr;

Expand Down
58 changes: 57 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ class CodeGenFunction : public CodeGenTypeCache {
/// nest would extend.
SmallVector<llvm::CanonicalLoopInfo *, 4> OMPLoopNestStack;

/// Stack to track the Logical Operator recursion nest for MC/DC.
SmallVector<const BinaryOperator *, 16> MCDCLogOpStack;

/// Number of nested loop to be consumed by the last surrounding
/// loop-associated directive.
int ExpectedOMPLoopDepth = 0;
Expand Down Expand Up @@ -1521,6 +1524,9 @@ class CodeGenFunction : public CodeGenTypeCache {

CodeGenPGO PGO;

/// Bitmap used by MC/DC to track condition outcomes of a boolean expression.
Address MCDCCondBitmapAddr = Address::invalid();

/// Calculate branch weights appropriate for PGO data
llvm::MDNode *createProfileWeights(uint64_t TrueCount,
uint64_t FalseCount) const;
Expand All @@ -1539,6 +1545,52 @@ class CodeGenFunction : public CodeGenTypeCache {
PGO.setCurrentStmt(S);
}

bool isMCDCCoverageEnabled() const {
return (CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().MCDCCoverage &&
!CurFn->hasFnAttribute(llvm::Attribute::NoProfile));
}

/// Allocate a temp value on the stack that MCDC can use to track condition
/// results.
void maybeCreateMCDCCondBitmap() {
if (isMCDCCoverageEnabled()) {
PGO.emitMCDCParameters(Builder);
MCDCCondBitmapAddr =
CreateIRTemp(getContext().UnsignedIntTy, "mcdc.addr");
}
}

bool isBinaryLogicalOp(const Expr *E) const {
const BinaryOperator *BOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
return (BOp && BOp->isLogicalOp());
}

/// Zero-init the MCDC temp value.
void maybeResetMCDCCondBitmap(const Expr *E) {
if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
PGO.emitMCDCCondBitmapReset(Builder, E, MCDCCondBitmapAddr);
PGO.setCurrentStmt(E);
}
}

/// Increment the profiler's counter for the given expression by \p StepV.
/// If \p StepV is null, the default increment is 1.
void maybeUpdateMCDCTestVectorBitmap(const Expr *E) {
if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr);
PGO.setCurrentStmt(E);
}
}

/// Update the MCDC temp value with the condition's evaluated result.
void maybeUpdateMCDCCondBitmap(const Expr *E, llvm::Value *Val) {
if (isMCDCCoverageEnabled()) {
PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val);
PGO.setCurrentStmt(E);
}
}

/// Get the profiler's count for the given statement.
uint64_t getProfileCount(const Stmt *S) {
return PGO.getStmtCount(S).value_or(0);
Expand Down Expand Up @@ -4626,6 +4678,9 @@ class CodeGenFunction : public CodeGenTypeCache {
bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &Result,
bool AllowLabels = false);

/// Ignore parentheses and logical-NOT to track conditions consistently.
static const Expr *stripCond(const Expr *C);

/// isInstrumentedCondition - Determine whether the given condition is an
/// instrumentable condition (i.e. no "&&" or "||").
static bool isInstrumentedCondition(const Expr *C);
Expand All @@ -4648,7 +4703,8 @@ class CodeGenFunction : public CodeGenTypeCache {
/// evaluate to true based on PGO data.
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock, uint64_t TrueCount,
Stmt::Likelihood LH = Stmt::LH_None);
Stmt::Likelihood LH = Stmt::LH_None,
const Expr *ConditionalOp = nullptr);

/// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is
/// nonnull, if \p LHS is marked _Nonnull.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4869,6 +4869,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
GV->setSection(".cp.rodata");

// Handle code model attribute
if (const auto *CMA = D->getAttr<CodeModelAttr>())
GV->setCodeModel(CMA->getModel());

// Check if we a have a const declaration with an initializer, we may be
// able to emit it as available_externally to expose it's value to the
// optimizer.
Expand Down
263 changes: 252 additions & 11 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,24 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
PGOHash Hash;
/// The map of statements to counters.
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
/// The next bitmap byte index to assign.
unsigned NextMCDCBitmapIdx;
/// The map of statements to MC/DC bitmap coverage objects.
llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
/// Maximum number of supported MC/DC conditions in a boolean expression.
unsigned MCDCMaxCond;
/// The profile version.
uint64_t ProfileVersion;
/// Diagnostics Engine used to report warnings.
DiagnosticsEngine &Diag;

MapRegionCounters(PGOHashVersion HashVersion, uint64_t ProfileVersion,
llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap,
unsigned MCDCMaxCond, DiagnosticsEngine &Diag)
: NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),
ProfileVersion(ProfileVersion) {}
NextMCDCBitmapIdx(0), MCDCBitmapMap(MCDCBitmapMap),
MCDCMaxCond(MCDCMaxCond), ProfileVersion(ProfileVersion), Diag(Diag) {}

// Blocks and lambdas are handled as separate functions, so we need not
// traverse them in the parent context.
Expand Down Expand Up @@ -207,15 +218,126 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
return Type;
}

/// The following stacks are used with dataTraverseStmtPre() and
/// dataTraverseStmtPost() to track the depth of nested logical operators in a
/// boolean expression in a function. The ultimate purpose is to keep track
/// of the number of leaf-level conditions in the boolean expression so that a
/// profile bitmap can be allocated based on that number.
///
/// The stacks are also used to find error cases and notify the user. A
/// standard logical operator nest for a boolean expression could be in a form
/// similar to this: "x = a && b && c && (d || f)"
unsigned NumCond = 0;
bool SplitNestedLogicalOp = false;
SmallVector<const Stmt *, 16> NonLogOpStack;
SmallVector<const BinaryOperator *, 16> LogOpStack;

// Hook: dataTraverseStmtPre() is invoked prior to visiting an AST Stmt node.
bool dataTraverseStmtPre(Stmt *S) {
/// If MC/DC is not enabled, MCDCMaxCond will be set to 0. Do nothing.
if (MCDCMaxCond == 0)
return true;

/// At the top of the logical operator nest, reset the number of conditions.
if (LogOpStack.empty())
NumCond = 0;

if (const Expr *E = dyn_cast<Expr>(S)) {
const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
if (BinOp && BinOp->isLogicalOp()) {
/// Check for "split-nested" logical operators. This happens when a new
/// boolean expression logical-op nest is encountered within an existing
/// boolean expression, separated by a non-logical operator. For
/// example, in "x = (a && b && c && foo(d && f))", the "d && f" case
/// starts a new boolean expression that is separated from the other
/// conditions by the operator foo(). Split-nested cases are not
/// supported by MC/DC.
SplitNestedLogicalOp = SplitNestedLogicalOp || !NonLogOpStack.empty();

LogOpStack.push_back(BinOp);
return true;
}
}

/// Keep track of non-logical operators. These are OK as long as we don't
/// encounter a new logical operator after seeing one.
if (!LogOpStack.empty())
NonLogOpStack.push_back(S);

return true;
}

// Hook: dataTraverseStmtPost() is invoked by the AST visitor after visiting
// an AST Stmt node. MC/DC will use it to to signal when the top of a
// logical operation (boolean expression) nest is encountered.
bool dataTraverseStmtPost(Stmt *S) {
/// If MC/DC is not enabled, MCDCMaxCond will be set to 0. Do nothing.
if (MCDCMaxCond == 0)
return true;

if (const Expr *E = dyn_cast<Expr>(S)) {
const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
if (BinOp && BinOp->isLogicalOp()) {
assert(LogOpStack.back() == BinOp);
LogOpStack.pop_back();

/// At the top of logical operator nest:
if (LogOpStack.empty()) {
/// Was the "split-nested" logical operator case encountered?
if (SplitNestedLogicalOp) {
unsigned DiagID = Diag.getCustomDiagID(
DiagnosticsEngine::Warning,
"unsupported MC/DC boolean expression; "
"contains an operation with a nested boolean expression. "
"Expression will not be covered");
Diag.Report(S->getBeginLoc(), DiagID);
return false;
}

/// Was the maximum number of conditions encountered?
if (NumCond > MCDCMaxCond) {
unsigned DiagID = Diag.getCustomDiagID(
DiagnosticsEngine::Warning,
"unsupported MC/DC boolean expression; "
"number of conditions (%0) exceeds max (%1). "
"Expression will not be covered");
Diag.Report(S->getBeginLoc(), DiagID) << NumCond << MCDCMaxCond;
return false;
}

// Otherwise, allocate the number of bytes required for the bitmap
// based on the number of conditions. Must be at least 1-byte long.
MCDCBitmapMap[BinOp] = NextMCDCBitmapIdx;
unsigned SizeInBits = std::max<unsigned>(1L << NumCond, CHAR_BIT);
NextMCDCBitmapIdx += SizeInBits / CHAR_BIT;
}
return true;
}
}

if (!LogOpStack.empty())
NonLogOpStack.pop_back();

return true;
}

/// The RHS of all logical operators gets a fresh counter in order to count
/// how many times the RHS evaluates to true or false, depending on the
/// semantics of the operator. This is only valid for ">= v7" of the profile
/// version so that we facilitate backward compatibility.
/// version so that we facilitate backward compatibility. In addition, in
/// order to use MC/DC, count the number of total LHS and RHS conditions.
bool VisitBinaryOperator(BinaryOperator *S) {
if (ProfileVersion >= llvm::IndexedInstrProf::Version7)
if (S->isLogicalOp() &&
CodeGenFunction::isInstrumentedCondition(S->getRHS()))
CounterMap[S->getRHS()] = NextCounter++;
if (S->isLogicalOp()) {
if (CodeGenFunction::isInstrumentedCondition(S->getLHS()))
NumCond++;

if (CodeGenFunction::isInstrumentedCondition(S->getRHS())) {
if (ProfileVersion >= llvm::IndexedInstrProf::Version7)
CounterMap[S->getRHS()] = NextCounter++;

NumCond++;
}
}
return Base::VisitBinaryOperator(S);
}

Expand Down Expand Up @@ -851,8 +973,22 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
ProfileVersion = PGOReader->getVersion();
}

// If MC/DC is enabled, set the MaxConditions to a preset value. Otherwise,
// set it to zero. This value impacts the number of conditions accepted in a
// given boolean expression, which impacts the size of the bitmap used to
// track test vector execution for that boolean expression. Because the
// bitmap scales exponentially (2^n) based on the number of conditions seen,
// the maximum value is hard-coded at 6 conditions, which is more than enough
// for most embedded applications. Setting a maximum value prevents the
// bitmap footprint from growing too large without the user's knowledge. In
// the future, this value could be adjusted with a command-line option.
unsigned MCDCMaxConditions = (CGM.getCodeGenOpts().MCDCCoverage) ? 6 : 0;

RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap);
RegionMCDCBitmapMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap,
*RegionMCDCBitmapMap, MCDCMaxConditions,
CGM.getDiags());
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
Expand All @@ -863,6 +999,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
NumRegionCounters = Walker.NextCounter;
MCDCBitmapBytes = Walker.NextMCDCBitmapIdx;
FunctionHash = Walker.Hash.finalize();
}

Expand Down Expand Up @@ -894,9 +1031,11 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {

std::string CoverageMapping;
llvm::raw_string_ostream OS(CoverageMapping);
CoverageMappingGen MappingGen(*CGM.getCoverageMapping(),
CGM.getContext().getSourceManager(),
CGM.getLangOpts(), RegionCounterMap.get());
RegionCondIDMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
CoverageMappingGen MappingGen(
*CGM.getCoverageMapping(), CGM.getContext().getSourceManager(),
CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCBitmapMap.get(),
RegionCondIDMap.get());
MappingGen.emitCounterMapping(D, OS);
OS.flush();

Expand Down Expand Up @@ -972,6 +1111,108 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
ArrayRef(Args));
}

bool CodeGenPGO::canEmitMCDCCoverage(const CGBuilderTy &Builder) {
return (CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().MCDCCoverage && Builder.GetInsertBlock());
}

void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
return;

auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

// Emit intrinsic representing MCDC bitmap parameters at function entry.
// This is used by the instrumentation pass, but it isn't actually lowered to
// anything.
llvm::Value *Args[3] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(MCDCBitmapBytes)};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_parameters), Args);
}

void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
const Expr *S,
Address MCDCCondBitmapAddr) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
return;

S = S->IgnoreParens();

auto ExprMCDCBitmapMapIterator = RegionMCDCBitmapMap->find(S);
if (ExprMCDCBitmapMapIterator == RegionMCDCBitmapMap->end())
return;

// Extract the ID of the global bitmap associated with this expression.
unsigned MCDCTestVectorBitmapID = ExprMCDCBitmapMapIterator->second;
auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

// Emit intrinsic responsible for updating the global bitmap corresponding to
// a boolean expression. The index being set is based on the value loaded
// from a pointer to a dedicated temporary value on the stack that is itself
// updated via emitMCDCCondBitmapReset() and emitMCDCCondBitmapUpdate(). The
// index represents an executed test vector.
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(MCDCBitmapBytes),
Builder.getInt32(MCDCTestVectorBitmapID),
MCDCCondBitmapAddr.getPointer()};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);
}

void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
return;

S = S->IgnoreParens();

if (RegionMCDCBitmapMap->find(S) == RegionMCDCBitmapMap->end())
return;

// Emit intrinsic that resets a dedicated temporary value on the stack to 0.
Builder.CreateStore(Builder.getInt32(0), MCDCCondBitmapAddr);
}

void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr,
llvm::Value *Val) {
if (!canEmitMCDCCoverage(Builder) || !RegionCondIDMap)
return;

// Even though, for simplicity, parentheses and unary logical-NOT operators
// are considered part of their underlying condition for both MC/DC and
// branch coverage, the condition IDs themselves are assigned and tracked
// using the underlying condition itself. This is done solely for
// consistency since parentheses and logical-NOTs are ignored when checking
// whether the condition is actually an instrumentable condition. This can
// also make debugging a bit easier.
S = CodeGenFunction::stripCond(S);

auto ExprMCDCConditionIDMapIterator = RegionCondIDMap->find(S);
if (ExprMCDCConditionIDMapIterator == RegionCondIDMap->end())
return;

// Extract the ID of the condition we are setting in the bitmap.
unsigned CondID = ExprMCDCConditionIDMapIterator->second;
assert(CondID > 0 && "Condition has no ID!");

auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

// Emit intrinsic that updates a dedicated temporary value on the stack after
// a condition is evaluated. After the set of conditions has been updated,
// the resulting value is used to update the boolean expression's bitmap.
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(CondID - 1),
MCDCCondBitmapAddr.getPointer(), Val};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update),
Args);
}

void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) {
if (CGM.getCodeGenOpts().hasProfileClangInstr())
M.addModuleFlag(llvm::Module::Warning, "EnableValueProfiling",
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/CodeGen/CodeGenPGO.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ class CodeGenPGO {

std::array <unsigned, llvm::IPVK_Last + 1> NumValueSites;
unsigned NumRegionCounters;
unsigned MCDCBitmapBytes;
uint64_t FunctionHash;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionMCDCBitmapMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCondIDMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
std::vector<uint64_t> RegionCounts;
Expand All @@ -43,7 +46,8 @@ class CodeGenPGO {
public:
CodeGenPGO(CodeGenModule &CGModule)
: CGM(CGModule), FuncNameVar(nullptr), NumValueSites({{0}}),
NumRegionCounters(0), FunctionHash(0), CurrentRegionCount(0) {}
NumRegionCounters(0), MCDCBitmapBytes(0), FunctionHash(0),
CurrentRegionCount(0) {}

/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
Expand Down Expand Up @@ -103,10 +107,18 @@ class CodeGenPGO {
bool IsInMainFile);
bool skipRegionMappingForDecl(const Decl *D);
void emitCounterRegionMapping(const Decl *D);
bool canEmitMCDCCoverage(const CGBuilderTy &Builder);

public:
void emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
llvm::Value *StepV);
void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr);
void emitMCDCParameters(CGBuilderTy &Builder);
void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr);
void emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr, llvm::Value *Val);

/// Return the region count for the counter at the given index.
uint64_t getRegionCount(const Stmt *S) {
Expand Down
Loading