Compare commits

..

4 Commits

Author SHA1 Message Date
Tom Eccles
245ecd1984 Fix typo 2025-08-21 15:51:10 +00:00
Tom Eccles
f84070b2b0 [flang][OpenMP] move omp end sections validation to semantics
See #90452. The old parse tree errors exploded to thousands of unhelpful
lines when there were multiple missing end directives.

Instead, allow a missing end directive in the parse tree then validate
that it is present during semantics (where the error messages are a lot
easier to control).
2025-08-21 15:51:10 +00:00
Tom Eccles
16662ce212 Check for loosely-strictured block instead of maintaining a flag 2025-08-21 15:46:19 +00:00
Tom Eccles
040a19d127 [flang][OpenMP] move omp end directive validation to semantics
The old parse tree errors quckly exploded to thousands of unhelpful
lines when there were multiple missing end directives (e.g. #90452).

Instead I've added a flag to the parse tree indicating when a missing
end directive needs to be diagnosed, and moved the error messages to
semantics (where they are a lot easier to control).

This has the disadvantage of not displaying the error if there were
other parse errors, but there is a precedent for this approach (e.g.
parsing atomic constructs).
2025-08-21 11:18:53 +00:00
820 changed files with 21085 additions and 75855 deletions

View File

@ -60,8 +60,7 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \
-D MLIR_ENABLE_BINDINGS_PYTHON=ON \ -D MLIR_ENABLE_BINDINGS_PYTHON=ON \
-D LLDB_ENABLE_PYTHON=ON \ -D LLDB_ENABLE_PYTHON=ON \
-D LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS=ON \ -D LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS=ON \
-D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}"
-D CMAKE_EXE_LINKER_FLAGS="-no-pie"
start-group "ninja" start-group "ninja"

View File

@ -138,12 +138,6 @@
Dump function CFGs to graphviz format after each stage;enable '-print-loops' Dump function CFGs to graphviz format after each stage;enable '-print-loops'
for color-coded blocks for color-coded blocks
- `--dump-dot-func=<func1,func2,func3...>`
Dump function CFGs to graphviz format for specified functions only;
takes function name patterns (regex supported). Note: C++ function names
must be passed using their mangled names
- `--dump-linux-exceptions` - `--dump-linux-exceptions`
Dump Linux kernel exception table Dump Linux kernel exception table

View File

@ -15,12 +15,6 @@
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
namespace llvm {
namespace bolt {
class BinaryFunction;
}
} // namespace llvm
namespace opts { namespace opts {
enum HeatmapModeKind { enum HeatmapModeKind {
@ -106,9 +100,6 @@ extern llvm::cl::opt<unsigned> Verbosity;
/// Return true if we should process all functions in the binary. /// Return true if we should process all functions in the binary.
bool processAllFunctions(); bool processAllFunctions();
/// Return true if we should dump dot graphs for the given function.
bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL }; enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun; extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;

View File

@ -52,7 +52,6 @@ namespace opts {
extern cl::opt<bool> PrintAll; extern cl::opt<bool> PrintAll;
extern cl::opt<bool> PrintDynoStats; extern cl::opt<bool> PrintDynoStats;
extern cl::opt<bool> DumpDotAll; extern cl::opt<bool> DumpDotAll;
extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
extern cl::opt<std::string> AsmDump; extern cl::opt<std::string> AsmDump;
extern cl::opt<bolt::PLTCall::OptType> PLT; extern cl::opt<bolt::PLTCall::OptType> PLT;
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false, extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
@ -341,7 +340,7 @@ Error BinaryFunctionPassManager::runPasses() {
Function.print(BC.outs(), Message); Function.print(BC.outs(), Message);
if (opts::shouldDumpDot(Function)) if (opts::DumpDotAll)
Function.dumpGraphForPass(PassIdName); Function.dumpGraphForPass(PassIdName);
} }
} }

View File

@ -115,35 +115,6 @@ cl::opt<bool> DumpDotAll(
"enable '-print-loops' for color-coded blocks"), "enable '-print-loops' for color-coded blocks"),
cl::Hidden, cl::cat(BoltCategory)); cl::Hidden, cl::cat(BoltCategory));
cl::list<std::string> DumpDotFunc(
"dump-dot-func", cl::CommaSeparated,
cl::desc(
"dump function CFGs to graphviz format for specified functions only;"
"takes function name patterns (regex supported)"),
cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
bool shouldDumpDot(const bolt::BinaryFunction &Function) {
// If dump-dot-all is enabled, dump all functions
if (DumpDotAll)
return !Function.isIgnored();
// If no specific functions specified in dump-dot-func, don't dump any
if (DumpDotFunc.empty())
return false;
if (Function.isIgnored())
return false;
// Check if function matches any of the specified patterns
for (const std::string &Name : DumpDotFunc) {
if (Function.hasNameRegex(Name)) {
return true;
}
}
return false;
}
static cl::list<std::string> static cl::list<std::string>
ForceFunctionNames("funcs", ForceFunctionNames("funcs",
cl::CommaSeparated, cl::CommaSeparated,
@ -3598,7 +3569,7 @@ void RewriteInstance::postProcessFunctions() {
if (opts::PrintAll || opts::PrintCFG) if (opts::PrintAll || opts::PrintCFG)
Function.print(BC->outs(), "after building cfg"); Function.print(BC->outs(), "after building cfg");
if (opts::shouldDumpDot(Function)) if (opts::DumpDotAll)
Function.dumpGraphForPass("00_build-cfg"); Function.dumpGraphForPass("00_build-cfg");
if (opts::PrintLoopInfo) { if (opts::PrintLoopInfo) {

View File

@ -1,24 +0,0 @@
#include <iostream>
// Multiple functions to test selective dumping
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main_helper() {
std::cout << "Helper function" << std::endl;
return 42;
}
int main_secondary() { return add(5, 3); }
void other_function() { std::cout << "Other function" << std::endl; }
int main() {
int result = add(10, 20);
result = multiply(result, 2);
main_helper();
main_secondary();
other_function();
return result;
}

View File

@ -1,52 +0,0 @@
# Test the --dump-dot-func option with multiple functions
# (includes tests for both mangled/unmangled names)
RUN: %clang++ %p/Inputs/multi-func.cpp -o %t.exe -Wl,-q
# Test 1: --dump-dot-func with specific function name (mangled)
RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=_Z3addii -v=1 2>&1 | FileCheck %s --check-prefix=ADD
# Test 2: --dump-dot-func with regex pattern (main.*)
RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX
# Test 3: --dump-dot-func with multiple specific functions (mangled names)
RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=_Z3addii,_Z8multiplyii -v=1 2>&1 | FileCheck %s --check-prefix=MULTI
# Test 4: No option specified should create no dot files
RUN: llvm-bolt %t.exe -o %t.bolt4 2>&1 | FileCheck %s --check-prefix=NONE
# Test 5: --dump-dot-func with non-existent function
RUN: llvm-bolt %t.exe -o %t.bolt5 --dump-dot-func=nonexistent -v=1 2>&1 | FileCheck %s --check-prefix=NONEXISTENT
# Test 6: Backward compatibility - --dump-dot-all should still work
RUN: llvm-bolt %t.exe -o %t.bolt6 --dump-dot-all -v=1 2>&1 | FileCheck %s --check-prefix=ALL
# Test 7: Test with unmangled function name (main function)
RUN: llvm-bolt %t.exe -o %t.bolt7 --dump-dot-func=main -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-UNMANGLED
# Check that specific functions are dumped
ADD: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
ADD-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
ADD-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
ADD-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
MULTI-DAG: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
MULTI-DAG: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
MULTI-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
MULTI-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
# Should be no dumping messages when no option is specified
NONE-NOT: BOLT-INFO: dumping CFG
# Should be no dumping messages for non-existent function
NONEXISTENT-NOT: BOLT-INFO: dumping CFG
ALL: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
MAIN-UNMANGLED: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot

View File

@ -1575,10 +1575,6 @@ template <typename T, std::size_t N = SmallDataStructureSize>
using ParamToSmallSetMap = using ParamToSmallSetMap =
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>; llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
template <typename T, std::size_t N = SmallDataStructureSize>
using ParamToSmallPtrSetMap =
llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
/// Returns whether the sets mapped to the two elements in the map have at /// Returns whether the sets mapped to the two elements in the map have at
/// least one element in common. /// least one element in common.
template <typename MapTy, typename ElemTy> template <typename MapTy, typename ElemTy>
@ -1703,7 +1699,7 @@ public:
/// Implements the heuristic that marks two parameters related if the same /// Implements the heuristic that marks two parameters related if the same
/// member is accessed (referred to) inside the current function's body. /// member is accessed (referred to) inside the current function's body.
class AccessedSameMemberOf { class AccessedSameMemberOf {
ParamToSmallPtrSetMap<const Decl *> AccessedMembers; ParamToSmallSetMap<const Decl *> AccessedMembers;
public: public:
void setup(const FunctionDecl *FD) { void setup(const FunctionDecl *FD) {

View File

@ -15,12 +15,14 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone { namespace clang::tidy::bugprone {
namespace {
// Determine if the result of an expression is "stored" in some way. // Determine if the result of an expression is "stored" in some way.
// It is true if the value is stored into a variable or used as initialization // It is true if the value is stored into a variable or used as initialization
// or passed to a function or constructor. // or passed to a function or constructor.
// For this use case compound assignments are not counted as a "store" (the 'E' // For this use case compound assignments are not counted as a "store" (the 'E'
// expression should have pointer type). // expression should have pointer type).
static bool isExprValueStored(const Expr *E, ASTContext &C) { bool isExprValueStored(const Expr *E, ASTContext &C) {
E = E->IgnoreParenCasts(); E = E->IgnoreParenCasts();
// Get first non-paren, non-cast parent. // Get first non-paren, non-cast parent.
ParentMapContext &PMap = C.getParentMapContext(); ParentMapContext &PMap = C.getParentMapContext();
@ -47,8 +49,6 @@ static bool isExprValueStored(const Expr *E, ASTContext &C) {
return isa<CallExpr, CXXConstructExpr>(ParentE); return isa<CallExpr, CXXConstructExpr>(ParentE);
} }
namespace {
AST_MATCHER_P(CXXTryStmt, hasHandlerFor, AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
ast_matchers::internal::Matcher<QualType>, InnerMatcher) { ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) { for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {

View File

@ -14,7 +14,9 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone { namespace clang::tidy::bugprone {
static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx, namespace {
bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
const StringLiteral *Lit) { const StringLiteral *Lit) {
// String literals surrounded by parentheses are assumed to be on purpose. // String literals surrounded by parentheses are assumed to be on purpose.
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] }; // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
@ -56,8 +58,6 @@ static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
return false; return false;
} }
namespace {
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned, AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
MaxConcatenatedTokens) { MaxConcatenatedTokens) {
return Node.getNumConcatenated() > 1 && return Node.getNumConcatenated() > 1 &&

View File

@ -46,9 +46,7 @@ enum class ConversionKind {
ToLongDouble ToLongDouble
}; };
} // namespace ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
return llvm::StringSwitch<ConversionKind>(FD->getName()) return llvm::StringSwitch<ConversionKind>(FD->getName())
.Cases("atoi", "atol", ConversionKind::ToInt) .Cases("atoi", "atol", ConversionKind::ToInt)
.Case("atoll", ConversionKind::ToLongInt) .Case("atoll", ConversionKind::ToLongInt)
@ -56,7 +54,7 @@ static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
.Default(ConversionKind::None); .Default(ConversionKind::None);
} }
static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO, ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
const TargetInfo &TI) { const TargetInfo &TI) {
// Scan the format string for the first problematic format specifier, then // Scan the format string for the first problematic format specifier, then
// report that as the conversion type. This will miss additional conversion // report that as the conversion type. This will miss additional conversion
@ -130,7 +128,7 @@ static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
return H.get(); return H.get();
} }
static StringRef classifyConversionType(ConversionKind K) { StringRef classifyConversionType(ConversionKind K) {
switch (K) { switch (K) {
case ConversionKind::None: case ConversionKind::None:
llvm_unreachable("Unexpected conversion kind"); llvm_unreachable("Unexpected conversion kind");
@ -150,7 +148,7 @@ static StringRef classifyConversionType(ConversionKind K) {
llvm_unreachable("Unknown conversion kind"); llvm_unreachable("Unknown conversion kind");
} }
static StringRef classifyReplacement(ConversionKind K) { StringRef classifyReplacement(ConversionKind K) {
switch (K) { switch (K) {
case ConversionKind::None: case ConversionKind::None:
llvm_unreachable("Unexpected conversion kind"); llvm_unreachable("Unexpected conversion kind");
@ -175,6 +173,7 @@ static StringRef classifyReplacement(ConversionKind K) {
} }
llvm_unreachable("Unknown conversion kind"); llvm_unreachable("Unknown conversion kind");
} }
} // unnamed namespace
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) { void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr"); const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");

View File

@ -59,9 +59,7 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) {
return true; return true;
} }
} // namespace OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
switch (FD->getOverloadedOperator()) { switch (FD->getOverloadedOperator()) {
default: default:
break; break;
@ -77,7 +75,7 @@ static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
llvm_unreachable("Not an overloaded allocation operator"); llvm_unreachable("Not an overloaded allocation operator");
} }
static const char *getOperatorName(OverloadedOperatorKind K) { const char *getOperatorName(OverloadedOperatorKind K) {
switch (K) { switch (K) {
default: default:
break; break;
@ -93,13 +91,12 @@ static const char *getOperatorName(OverloadedOperatorKind K) {
llvm_unreachable("Not an overloaded allocation operator"); llvm_unreachable("Not an overloaded allocation operator");
} }
static bool areCorrespondingOverloads(const FunctionDecl *LHS, bool areCorrespondingOverloads(const FunctionDecl *LHS,
const FunctionDecl *RHS) { const FunctionDecl *RHS) {
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS); return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
} }
static bool bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
const CXXRecordDecl *RD = nullptr) { const CXXRecordDecl *RD = nullptr) {
if (RD) { if (RD) {
// Check the methods in the given class and accessible to derived classes. // Check the methods in the given class and accessible to derived classes.
@ -127,6 +124,8 @@ hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
return false; return false;
} }
} // anonymous namespace
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) { void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
// Match all operator new and operator delete overloads (including the array // Match all operator new and operator delete overloads (including the array
// forms). Do not match implicit operators, placement operators, or // forms). Do not match implicit operators, placement operators, or

View File

@ -395,12 +395,16 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
--CurrentFile->ConditionScopes; --CurrentFile->ConditionScopes;
} }
namespace {
template <size_t N> template <size_t N>
static bool textEquals(const char (&Needle)[N], const char *HayStack) { bool textEquals(const char (&Needle)[N], const char *HayStack) {
return StringRef{HayStack, N - 1} == Needle; return StringRef{HayStack, N - 1} == Needle;
} }
template <size_t N> static size_t len(const char (&)[N]) { return N - 1; } template <size_t N> size_t len(const char (&)[N]) { return N - 1; }
} // namespace
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc, void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
PragmaIntroducerKind Introducer) { PragmaIntroducerKind Introducer) {

View File

@ -16,12 +16,13 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize { namespace clang::tidy::modernize {
static constexpr char ConstructorCall[] = "constructorCall"; namespace {
static constexpr char ResetCall[] = "resetCall";
static constexpr char NewExpression[] = "newExpression";
static std::string getNewExprName(const CXXNewExpr *NewExpr, constexpr char ConstructorCall[] = "constructorCall";
const SourceManager &SM, constexpr char ResetCall[] = "resetCall";
constexpr char NewExpression[] = "newExpression";
std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
const LangOptions &Lang) { const LangOptions &Lang) {
StringRef WrittenName = Lexer::getSourceText( StringRef WrittenName = Lexer::getSourceText(
CharSourceRange::getTokenRange( CharSourceRange::getTokenRange(
@ -33,6 +34,8 @@ static std::string getNewExprName(const CXXNewExpr *NewExpr,
return WrittenName.str(); return WrittenName.str();
} }
} // namespace
const char MakeSmartPtrCheck::PointerType[] = "pointerType"; const char MakeSmartPtrCheck::PointerType[] = "pointerType";
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,

View File

@ -19,7 +19,9 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize { namespace clang::tidy::modernize {
static bool containsEscapes(StringRef HayStack, StringRef Escapes) { namespace {
bool containsEscapes(StringRef HayStack, StringRef Escapes) {
size_t BackSlash = HayStack.find('\\'); size_t BackSlash = HayStack.find('\\');
if (BackSlash == StringRef::npos) if (BackSlash == StringRef::npos)
return false; return false;
@ -33,14 +35,14 @@ static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
return true; return true;
} }
static bool isRawStringLiteral(StringRef Text) { bool isRawStringLiteral(StringRef Text) {
// Already a raw string literal if R comes before ". // Already a raw string literal if R comes before ".
const size_t QuotePos = Text.find('"'); const size_t QuotePos = Text.find('"');
assert(QuotePos != StringRef::npos); assert(QuotePos != StringRef::npos);
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R'); return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
} }
static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result, bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
const StringLiteral *Literal, const StringLiteral *Literal,
const CharsBitSet &DisallowedChars) { const CharsBitSet &DisallowedChars) {
// FIXME: Handle L"", u8"", u"" and U"" literals. // FIXME: Handle L"", u8"", u"" and U"" literals.
@ -62,12 +64,14 @@ static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
return containsEscapes(Text, R"('\"?x01)"); return containsEscapes(Text, R"('\"?x01)");
} }
static bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) { bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
return Bytes.find(Delimiter.empty() return Bytes.find(Delimiter.empty()
? std::string(R"lit()")lit") ? std::string(R"lit()")lit")
: (")" + Delimiter + R"(")")) != StringRef::npos; : (")" + Delimiter + R"(")")) != StringRef::npos;
} }
} // namespace
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name, RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
ClangTidyContext *Context) ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -29,13 +29,12 @@
using namespace clang::ast_matchers; using namespace clang::ast_matchers;
namespace clang::tidy::objc { namespace clang::tidy::objc {
namespace {
static constexpr StringRef WeakText = "__weak"; static constexpr StringRef WeakText = "__weak";
static constexpr StringRef StrongText = "__strong"; static constexpr StringRef StrongText = "__strong";
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained"; static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
namespace {
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference /// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
/// Objective-C object (or block) variables or fields whose object lifetimes /// Objective-C object (or block) variables or fields whose object lifetimes
/// are not __unsafe_unretained. /// are not __unsafe_unretained.
@ -50,8 +49,6 @@ AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime,
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone; QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
} }
} // namespace
static std::optional<FixItHint> static std::optional<FixItHint>
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range, fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
StringRef Ownership) { StringRef Ownership) {
@ -96,6 +93,8 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM,
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained "); return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
} }
} // namespace
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) { void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher( Finder->addMatcher(
traverse( traverse(

View File

@ -27,14 +27,11 @@ enum NamingStyle {
CategoryProperty = 2, CategoryProperty = 2,
}; };
} // namespace
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to /// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to /// 'camelCase' or 'abc_camelCase'. For other cases the users need to
/// come up with a proper name by their own. /// come up with a proper name by their own.
/// FIXME: provide fix for snake_case to snakeCase /// FIXME: provide fix for snake_case to snakeCase
static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
NamingStyle Style) {
auto Name = Decl->getName(); auto Name = Decl->getName();
auto NewName = Decl->getName().str(); auto NewName = Decl->getName().str();
size_t Index = 0; size_t Index = 0;
@ -53,7 +50,7 @@ static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
return {}; return {};
} }
static std::string validPropertyNameRegex(bool UsedInMatcher) { std::string validPropertyNameRegex(bool UsedInMatcher) {
// Allow any of these names: // Allow any of these names:
// foo // foo
// fooBar // fooBar
@ -75,13 +72,13 @@ static std::string validPropertyNameRegex(bool UsedInMatcher) {
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$"; return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
} }
static bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) { bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
auto RegexExp = auto RegexExp =
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$"); llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
return RegexExp.match(PropertyName); return RegexExp.match(PropertyName);
} }
static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) { bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
size_t Start = PropertyName.find_first_of('_'); size_t Start = PropertyName.find_first_of('_');
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size()); assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
auto Prefix = PropertyName.substr(0, Start); auto Prefix = PropertyName.substr(0, Start);
@ -91,6 +88,7 @@ static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false))); auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
return RegexExp.match(PropertyName.substr(Start + 1)); return RegexExp.match(PropertyName.substr(Start + 1));
} }
} // namespace
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) { void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(objcPropertyDecl( Finder->addMatcher(objcPropertyDecl(

View File

@ -17,6 +17,7 @@
#include <optional> #include <optional>
namespace clang::tidy::performance { namespace clang::tidy::performance {
namespace {
using namespace ::clang::ast_matchers; using namespace ::clang::ast_matchers;
using llvm::StringRef; using llvm::StringRef;
@ -29,7 +30,7 @@ static constexpr StringRef MethodDeclId = "methodDecl";
static constexpr StringRef FunctionDeclId = "functionDecl"; static constexpr StringRef FunctionDeclId = "functionDecl";
static constexpr StringRef OldVarDeclId = "oldVarDecl"; static constexpr StringRef OldVarDeclId = "oldVarDecl";
static void recordFixes(const VarDecl &Var, ASTContext &Context, void recordFixes(const VarDecl &Var, ASTContext &Context,
DiagnosticBuilder &Diagnostic) { DiagnosticBuilder &Diagnostic) {
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
if (!Var.getType().isLocalConstQualified()) { if (!Var.getType().isLocalConstQualified()) {
@ -39,7 +40,7 @@ static void recordFixes(const VarDecl &Var, ASTContext &Context,
} }
} }
static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc, std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
SourceManager &SM) { SourceManager &SM) {
bool Invalid = false; bool Invalid = false;
const char *TextAfter = SM.getCharacterData(Loc, &Invalid); const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
@ -50,7 +51,7 @@ static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1); return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
} }
static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context, void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
DiagnosticBuilder &Diagnostic) { DiagnosticBuilder &Diagnostic) {
auto &SM = Context.getSourceManager(); auto &SM = Context.getSourceManager();
// Attempt to remove trailing comments as well. // Attempt to remove trailing comments as well.
@ -73,8 +74,6 @@ static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
} }
} }
namespace {
AST_MATCHER_FUNCTION_P(StatementMatcher, AST_MATCHER_FUNCTION_P(StatementMatcher,
isRefReturningMethodCallWithConstOverloads, isRefReturningMethodCallWithConstOverloads,
std::vector<StringRef>, ExcludedContainerTypes) { std::vector<StringRef>, ExcludedContainerTypes) {
@ -131,8 +130,6 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
hasUnaryOperand(OldVarDeclRef))))); hasUnaryOperand(OldVarDeclRef)))));
} }
} // namespace
// This checks that the variable itself is only used as const, and also makes // This checks that the variable itself is only used as const, and also makes
// sure that it does not reference another variable that could be modified in // sure that it does not reference another variable that could be modified in
// the BlockStmt. It does this by checking the following: // the BlockStmt. It does this by checking the following:
@ -183,13 +180,13 @@ static bool isInitializingVariableImmutable(
return false; return false;
} }
static bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt, bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
ASTContext &Context) { ASTContext &Context) {
return allDeclRefExprs(Var, BlockStmt, Context).empty(); return allDeclRefExprs(Var, BlockStmt, Context).empty();
} }
static const SubstTemplateTypeParmType * const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
getSubstitutedType(const QualType &Type, ASTContext &Context) { ASTContext &Context) {
auto Matches = match( auto Matches = match(
qualType(anyOf(substTemplateTypeParmType().bind("subst"), qualType(anyOf(substTemplateTypeParmType().bind("subst"),
hasDescendant(substTemplateTypeParmType().bind("subst")))), hasDescendant(substTemplateTypeParmType().bind("subst")))),
@ -197,7 +194,7 @@ getSubstitutedType(const QualType &Type, ASTContext &Context) {
return selectFirst<SubstTemplateTypeParmType>("subst", Matches); return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
} }
static bool differentReplacedTemplateParams(const QualType &VarType, bool differentReplacedTemplateParams(const QualType &VarType,
const QualType &InitializerType, const QualType &InitializerType,
ASTContext &Context) { ASTContext &Context) {
if (const SubstTemplateTypeParmType *VarTmplType = if (const SubstTemplateTypeParmType *VarTmplType =
@ -215,7 +212,7 @@ static bool differentReplacedTemplateParams(const QualType &VarType,
return false; return false;
} }
static QualType constructorArgumentType(const VarDecl *OldVar, QualType constructorArgumentType(const VarDecl *OldVar,
const BoundNodes &Nodes) { const BoundNodes &Nodes) {
if (OldVar) { if (OldVar) {
return OldVar->getType(); return OldVar->getType();
@ -227,6 +224,8 @@ static QualType constructorArgumentType(const VarDecl *OldVar,
return MethodDecl->getReturnType(); return MethodDecl->getReturnType();
} }
} // namespace
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization( UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
StringRef Name, ClangTidyContext *Context) StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -21,13 +21,15 @@ using namespace clang::ast_matchers;
namespace clang::tidy::performance { namespace clang::tidy::performance {
static std::string paramNameOrIndex(StringRef Name, size_t Index) { namespace {
std::string paramNameOrIndex(StringRef Name, size_t Index) {
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1) return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
: llvm::Twine('\'') + Name + llvm::Twine('\'')) : llvm::Twine('\'') + Name + llvm::Twine('\''))
.str(); .str();
} }
static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl, bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
ASTContext &Context) { ASTContext &Context) {
auto Matches = match( auto Matches = match(
traverse(TK_AsIs, traverse(TK_AsIs,
@ -39,6 +41,8 @@ static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
return Matches.empty(); return Matches.empty();
} }
} // namespace
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
StringRef Name, ClangTidyContext *Context) StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -122,15 +122,15 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) {
return !AllEnumeratorsArePowersOfTwo; return !AllEnumeratorsArePowersOfTwo;
} }
} // namespace std::string getName(const EnumDecl *Decl) {
static std::string getName(const EnumDecl *Decl) {
if (!Decl->getDeclName()) if (!Decl->getDeclName())
return "<unnamed>"; return "<unnamed>";
return Decl->getQualifiedNameAsString(); return Decl->getQualifiedNameAsString();
} }
} // namespace
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name, EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
ClangTidyContext *Context) ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -144,8 +144,6 @@ struct CognitiveComplexity final {
void account(SourceLocation Loc, unsigned short Nesting, Criteria C); void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
}; };
} // namespace
// All the possible messages that can be output. The choice of the message // All the possible messages that can be output. The choice of the message
// to use is based of the combination of the CognitiveComplexity::Criteria. // to use is based of the combination of the CognitiveComplexity::Criteria.
// It would be nice to have it in CognitiveComplexity struct, but then it is // It would be nice to have it in CognitiveComplexity struct, but then it is
@ -165,26 +163,22 @@ static const std::array<const StringRef, 4> Msgs = {{
}}; }};
// Criteria is a bitset, thus a few helpers are needed. // Criteria is a bitset, thus a few helpers are needed.
static CognitiveComplexity::Criteria CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
operator|(CognitiveComplexity::Criteria LHS,
CognitiveComplexity::Criteria RHS) { CognitiveComplexity::Criteria RHS) {
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) | return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
llvm::to_underlying(RHS)); llvm::to_underlying(RHS));
} }
static CognitiveComplexity::Criteria CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
operator&(CognitiveComplexity::Criteria LHS,
CognitiveComplexity::Criteria RHS) { CognitiveComplexity::Criteria RHS) {
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) & return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
llvm::to_underlying(RHS)); llvm::to_underlying(RHS));
} }
static CognitiveComplexity::Criteria & CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
operator|=(CognitiveComplexity::Criteria &LHS,
CognitiveComplexity::Criteria RHS) { CognitiveComplexity::Criteria RHS) {
LHS = operator|(LHS, RHS); LHS = operator|(LHS, RHS);
return LHS; return LHS;
} }
static CognitiveComplexity::Criteria & CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
operator&=(CognitiveComplexity::Criteria &LHS,
CognitiveComplexity::Criteria RHS) { CognitiveComplexity::Criteria RHS) {
LHS = operator&(LHS, RHS); LHS = operator&(LHS, RHS);
return LHS; return LHS;
@ -205,8 +199,6 @@ void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
Total += Increase; Total += Increase;
} }
namespace {
class FunctionASTVisitor final class FunctionASTVisitor final
: public RecursiveASTVisitor<FunctionASTVisitor> { : public RecursiveASTVisitor<FunctionASTVisitor> {
using Base = RecursiveASTVisitor<FunctionASTVisitor>; using Base = RecursiveASTVisitor<FunctionASTVisitor>;

View File

@ -41,9 +41,7 @@ AST_MATCHER(Stmt, isNULLMacroExpansion) {
return isNULLMacroExpansion(&Node, Finder->getASTContext()); return isNULLMacroExpansion(&Node, Finder->getASTContext());
} }
} // namespace StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
QualType Type, QualType Type,
ASTContext &Context) { ASTContext &Context) {
switch (CastExprKind) { switch (CastExprKind) {
@ -64,14 +62,14 @@ static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
} }
} }
static bool isUnaryLogicalNotOperator(const Stmt *Statement) { bool isUnaryLogicalNotOperator(const Stmt *Statement) {
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement); const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot; return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
} }
static void fixGenericExprCastToBool(DiagnosticBuilder &Diag, void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
const ImplicitCastExpr *Cast, const ImplicitCastExpr *Cast, const Stmt *Parent,
const Stmt *Parent, ASTContext &Context, ASTContext &Context,
bool UseUpperCaseLiteralSuffix) { bool UseUpperCaseLiteralSuffix) {
// In case of expressions like (! integer), we should remove the redundant not // In case of expressions like (! integer), we should remove the redundant not
// operator and use inverted comparison (integer == 0). // operator and use inverted comparison (integer == 0).
@ -135,7 +133,7 @@ static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion); Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
} }
static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression, StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
ASTContext &Context) { ASTContext &Context) {
if (isNULLMacroExpansion(Expression, Context)) { if (isNULLMacroExpansion(Expression, Context)) {
return "false"; return "false";
@ -163,7 +161,7 @@ static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
return {}; return {};
} }
static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) { bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc); SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
StringRef SpaceBeforeStmtStr = Lexer::getSourceText( StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(), CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
@ -175,10 +173,9 @@ static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back()); return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
} }
static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag, void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
const ImplicitCastExpr *Cast, const ImplicitCastExpr *Cast,
ASTContext &Context, ASTContext &Context, StringRef OtherType) {
StringRef OtherType) {
if (!Context.getLangOpts().CPlusPlus) { if (!Context.getLangOpts().CPlusPlus) {
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(), Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
(Twine("(") + OtherType + ")").str()); (Twine("(") + OtherType + ")").str());
@ -203,8 +200,7 @@ static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
} }
} }
static StringRef StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
QualType DestType, ASTContext &Context) { QualType DestType, ASTContext &Context) {
// Prior to C++11, false literal could be implicitly converted to pointer. // Prior to C++11, false literal could be implicitly converted to pointer.
if (!Context.getLangOpts().CPlusPlus11 && if (!Context.getLangOpts().CPlusPlus11 &&
@ -226,7 +222,7 @@ getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
return BoolLiteral->getValue() ? "1" : "0"; return BoolLiteral->getValue() ? "1" : "0";
} }
static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast, bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
ASTContext &Context) { ASTContext &Context) {
std::queue<const Stmt *> Q; std::queue<const Stmt *> Q;
Q.push(Cast); Q.push(Cast);
@ -255,6 +251,8 @@ static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
return false; return false;
} }
} // anonymous namespace
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck( ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
StringRef Name, ClangTidyContext *Context) StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -28,10 +28,7 @@ AST_MATCHER_P(QualType, hasUnqualifiedType,
enum class Qualifier { Const, Volatile, Restrict }; enum class Qualifier { Const, Volatile, Restrict };
} // namespace std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
static std::optional<Token>
findQualToken(const VarDecl *Decl, Qualifier Qual,
const MatchFinder::MatchResult &Result) { const MatchFinder::MatchResult &Result) {
// Since either of the locs can be in a macro, use `makeFileCharRange` to be // Since either of the locs can be in a macro, use `makeFileCharRange` to be
// sure that we have a consistent `CharSourceRange`, located entirely in the // sure that we have a consistent `CharSourceRange`, located entirely in the
@ -61,7 +58,7 @@ findQualToken(const VarDecl *Decl, Qualifier Qual,
*Result.SourceManager); *Result.SourceManager);
} }
static std::optional<SourceRange> std::optional<SourceRange>
getTypeSpecifierLocation(const VarDecl *Var, getTypeSpecifierLocation(const VarDecl *Var,
const MatchFinder::MatchResult &Result) { const MatchFinder::MatchResult &Result) {
SourceRange TypeSpecifier( SourceRange TypeSpecifier(
@ -76,8 +73,8 @@ getTypeSpecifierLocation(const VarDecl *Var,
return TypeSpecifier; return TypeSpecifier;
} }
static std::optional<SourceRange> std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) { const Token &ConstToken) {
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) { if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
TypeSpecifier.setBegin(ConstToken.getLocation()); TypeSpecifier.setBegin(ConstToken.getLocation());
return std::nullopt; return std::nullopt;
@ -89,19 +86,21 @@ mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc()); return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
} }
static bool isPointerConst(QualType QType) { bool isPointerConst(QualType QType) {
QualType Pointee = QType->getPointeeType(); QualType Pointee = QType->getPointeeType();
assert(!Pointee.isNull() && "can't have a null Pointee"); assert(!Pointee.isNull() && "can't have a null Pointee");
return Pointee.isConstQualified(); return Pointee.isConstQualified();
} }
static bool isAutoPointerConst(QualType QType) { bool isAutoPointerConst(QualType QType) {
QualType Pointee = QualType Pointee =
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar(); cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
assert(!Pointee.isNull() && "can't have a null Pointee"); assert(!Pointee.isNull() && "can't have a null Pointee");
return Pointee.isConstQualified(); return Pointee.isConstQualified();
} }
} // namespace
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name, QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
ClangTidyContext *Context) ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),

View File

@ -14,18 +14,19 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability { namespace clang::tidy::readability {
static const char *const RedundantReturnDiag = namespace {
"redundant return statement at the end "
const char *const RedundantReturnDiag = "redundant return statement at the end "
"of a function with a void return type"; "of a function with a void return type";
static const char *const RedundantContinueDiag = const char *const RedundantContinueDiag = "redundant continue statement at the "
"redundant continue statement at the "
"end of loop statement"; "end of loop statement";
static bool isLocationInMacroExpansion(const SourceManager &SM, bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) {
SourceLocation Loc) {
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc); return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
} }
} // namespace
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) { void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher( Finder->addMatcher(
functionDecl(isDefinition(), returns(voidType()), functionDecl(isDefinition(), returns(voidType()),

View File

@ -13,14 +13,16 @@
namespace clang::tidy::utils::type_traits { namespace clang::tidy::utils::type_traits {
static bool classHasTrivialCopyAndDestroy(QualType Type) { namespace {
bool classHasTrivialCopyAndDestroy(QualType Type) {
auto *Record = Type->getAsCXXRecordDecl(); auto *Record = Type->getAsCXXRecordDecl();
return Record && Record->hasDefinition() && return Record && Record->hasDefinition() &&
!Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialCopyConstructor() &&
!Record->hasNonTrivialDestructor(); !Record->hasNonTrivialDestructor();
} }
static bool hasDeletedCopyConstructor(QualType Type) { bool hasDeletedCopyConstructor(QualType Type) {
auto *Record = Type->getAsCXXRecordDecl(); auto *Record = Type->getAsCXXRecordDecl();
if (!Record || !Record->hasDefinition()) if (!Record || !Record->hasDefinition())
return false; return false;
@ -31,6 +33,8 @@ static bool hasDeletedCopyConstructor(QualType Type) {
return false; return false;
} }
} // namespace
std::optional<bool> isExpensiveToCopy(QualType Type, std::optional<bool> isExpensiveToCopy(QualType Type,
const ASTContext &Context) { const ASTContext &Context) {
if (Type->isDependentType() || Type->isIncompleteType()) if (Type->isDependentType() || Type->isIncompleteType())

View File

@ -22,6 +22,10 @@ FeatureModule::Facilities &FeatureModule::facilities() {
return *Fac; return *Fac;
} }
void FeatureModuleSet::add(std::unique_ptr<FeatureModule> M) {
Modules.push_back(std::move(M));
}
bool FeatureModuleSet::addImpl(void *Key, std::unique_ptr<FeatureModule> M, bool FeatureModuleSet::addImpl(void *Key, std::unique_ptr<FeatureModule> M,
const char *Source) { const char *Source) {
if (!Map.try_emplace(Key, M.get()).second) { if (!Map.try_emplace(Key, M.get()).second) {
@ -35,3 +39,5 @@ bool FeatureModuleSet::addImpl(void *Key, std::unique_ptr<FeatureModule> M,
} // namespace clangd } // namespace clangd
} // namespace clang } // namespace clang
LLVM_INSTANTIATE_REGISTRY(clang::clangd::FeatureModuleRegistry)

View File

@ -15,6 +15,7 @@
#include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include "llvm/Support/JSON.h" #include "llvm/Support/JSON.h"
#include "llvm/Support/Registry.h"
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <type_traits> #include <type_traits>
@ -143,9 +144,14 @@ private:
/// A FeatureModuleSet is a collection of feature modules installed in clangd. /// A FeatureModuleSet is a collection of feature modules installed in clangd.
/// ///
/// Modules can be looked up by type, or used via the FeatureModule interface. /// Modules added with explicit type specification can be looked up by type, or
/// This allows individual modules to expose a public API. /// used via the FeatureModule interface. This allows individual modules to
/// For this reason, there can be only one feature module of each type. /// expose a public API. For this reason, there can be only one feature module
/// of each type.
///
/// Modules added using a base class pointer can be used only via the
/// FeatureModule interface and can't be looked up by type, thus custom public
/// API (if provided by the module) can't be used.
/// ///
/// The set owns the modules. It is itself owned by main, not ClangdServer. /// The set owns the modules. It is itself owned by main, not ClangdServer.
class FeatureModuleSet { class FeatureModuleSet {
@ -172,6 +178,7 @@ public:
const_iterator begin() const { return const_iterator(Modules.begin()); } const_iterator begin() const { return const_iterator(Modules.begin()); }
const_iterator end() const { return const_iterator(Modules.end()); } const_iterator end() const { return const_iterator(Modules.end()); }
void add(std::unique_ptr<FeatureModule> M);
template <typename Mod> bool add(std::unique_ptr<Mod> M) { template <typename Mod> bool add(std::unique_ptr<Mod> M) {
return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION); return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
} }
@ -185,6 +192,8 @@ public:
template <typename Mod> int FeatureModuleSet::ID<Mod>::Key; template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
} // namespace clangd } // namespace clangd
} // namespace clang } // namespace clang
#endif #endif

View File

@ -1017,6 +1017,14 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
: static_cast<int>(ErrorResultCode::CheckFailed); : static_cast<int>(ErrorResultCode::CheckFailed);
} }
FeatureModuleSet ModuleSet;
for (FeatureModuleRegistry::entry E : FeatureModuleRegistry::entries()) {
vlog("Adding feature module '{0}' ({1})", E.getName(), E.getDesc());
ModuleSet.add(E.instantiate());
}
if (ModuleSet.begin() != ModuleSet.end())
Opts.FeatureModules = &ModuleSet;
// Initialize and run ClangdLSPServer. // Initialize and run ClangdLSPServer.
// Change stdin to binary to not lose \r\n on windows. // Change stdin to binary to not lose \r\n on windows.
llvm::sys::ChangeStdinToBinary(); llvm::sys::ChangeStdinToBinary();

View File

@ -215,8 +215,7 @@ Changes in existing checks
- Improved :doc:`readability-identifier-naming - Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check by ignoring <clang-tidy/checks/readability/identifier-naming>` check by ignoring
declarations in system headers. The documentation is also improved to declarations in system headers.
differentiate the general options from the specific ones.
- Improved :doc:`readability-qualified-auto - Improved :doc:`readability-qualified-auto
<clang-tidy/checks/readability/qualified-auto>` check by adding the option <clang-tidy/checks/readability/qualified-auto>` check by adding the option

View File

@ -43,21 +43,14 @@ The options and their corresponding values are:
- ``LowerCase`` - example: ``int i_Variable`` - ``LowerCase`` - example: ``int i_Variable``
- ``CamelCase`` - example: ``int IVariable`` - ``CamelCase`` - example: ``int IVariable``
Options summary Options
--------------- -------
The available options are summarized below: The following options are described below:
**General options**
- :option:`AggressiveDependentMemberLookup`
- :option:`CheckAnonFieldInParent`
- :option:`GetConfigPerFile`
- :option:`IgnoreMainLikeFunctions`
**Specific options**
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix` - :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
- :option:`AggressiveDependentMemberLookup`
- :option:`CheckAnonFieldInParent`
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix` - :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix` - :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix` - :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
@ -73,11 +66,13 @@ The available options are summarized below:
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp` - :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix` - :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp` - :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
- :option:`GetConfigPerFile`
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix` - :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix` - :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp` - :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix` - :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix` - :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
- :option:`IgnoreMainLikeFunctions`
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp` - :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix` - :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix` - :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
@ -110,12 +105,6 @@ The available options are summarized below:
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix` - :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp` - :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
Options description
-------------------
A detailed description of each option is presented below:
.. option:: AbstractClassCase .. option:: AbstractClassCase
When defined, the check will ensure abstract class names conform to the When defined, the check will ensure abstract class names conform to the

View File

@ -9,14 +9,14 @@ Introduction
============ ============
Coroutines in C++ were introduced in C++20, and the user experience for Coroutines in C++ were introduced in C++20, and the user experience for
debugging them can still be challenging. This document guides you on how to most debugging them can still be challenging. This document guides you how to most
efficiently debug coroutines and how to navigate existing shortcomings in efficiently debug coroutines and how to navigate existing shortcomings in
debuggers and compilers. debuggers and compilers.
Coroutines are generally used either as generators or for asynchronous Coroutines are generally used either as generators or for asynchronous
programming. In this document, we will discuss both use cases. Even if you are programming. In this document, we will discuss both use cases. Even if you are
using coroutines for asynchronous programming, you should still read the using coroutines for asynchronous programming, you should still read the
generators section, as it introduces foundational debugging techniques also generators section, as it will introduce foundational debugging techniques also
applicable to the debugging of asynchronous programs. applicable to the debugging of asynchronous programs.
Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are
@ -34,15 +34,15 @@ scripting. This guide comes with a basic GDB script for coroutine debugging.
This guide will first showcase the more polished, bleeding-edge experience, but This guide will first showcase the more polished, bleeding-edge experience, but
will also show you how to debug coroutines with older toolchains. In general, will also show you how to debug coroutines with older toolchains. In general,
the older your toolchain, the deeper you will have to dive into the the older your toolchain, the deeper you will have to dive into the
implementation details of coroutines (such as their ABI). The further down you go in implementation details of coroutines (such as their ABI). The further down in
this document, the more low-level, technical the content will become. If this document you go, the more low-level, technical the content will become. If
you are on an up-to-date toolchain, you will hopefully be able to stop reading you are on an up-to-date toolchain, you will hopefully be able to stop reading
earlier. earlier.
Debugging generators Debugging generators
==================== ====================
One of the two major use cases for coroutines in C++ is generators, i.e., One of the two major use cases for coroutines in C++ are generators, i.e.,
functions which can produce values via ``co_yield``. Values are produced functions which can produce values via ``co_yield``. Values are produced
lazily, on-demand. For this purpose, every time a new value is requested, the lazily, on-demand. For this purpose, every time a new value is requested, the
coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby
@ -141,7 +141,7 @@ a regular function.
Note the two additional variables ``__promise`` and ``__coro_frame``. Those Note the two additional variables ``__promise`` and ``__coro_frame``. Those
show the internal state of the coroutine. They are not relevant for our show the internal state of the coroutine. They are not relevant for our
generator example but will be relevant for asynchronous programming described generator example, but will be relevant for asynchronous programming described
in the next section. in the next section.
Stepping out of a coroutine Stepping out of a coroutine
@ -174,7 +174,7 @@ Inspecting a suspended coroutine
-------------------------------- --------------------------------
The ``print10Elements`` function receives an opaque ``generator`` type. Let's The ``print10Elements`` function receives an opaque ``generator`` type. Let's
assume we are suspended at the ``++gen;`` line and want to inspect the assume we are suspended at the ``++gen;`` line, and want to inspect the
generator and its internal state. generator and its internal state.
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
@ -188,7 +188,7 @@ We can see two function pointers ``resume`` and ``destroy``. These pointers
point to the resume / destroy functions. By inspecting those function pointers, point to the resume / destroy functions. By inspecting those function pointers,
we can see that our ``generator`` is actually backed by our ``fibonacci`` we can see that our ``generator`` is actually backed by our ``fibonacci``
coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function
address (``0x555...`` in the screenshot) to jump directly to the function address (``0x555...`` in the screenshot) to directly jump to the function
definition backing your coroutine handle. definition backing your coroutine handle.
Next, we see the ``promise``. In our case, this reveals the current value of Next, we see the ``promise``. In our case, this reveals the current value of
@ -247,12 +247,12 @@ the line number of the current suspension point in the promise:
}; };
This stores the return address of ``await_suspend`` within the promise. This stores the return address of ``await_suspend`` within the promise.
Thereby, we can read it back from the promise of a suspended coroutine and map Thereby, we can read it back from the promise of a suspended coroutine, and map
it to an exact source code location. For a complete example, see the ``task`` it to an exact source code location. For a complete example, see the ``task``
type used below for asynchronous programming. type used below for asynchronous programming.
Alternatively, we can modify the C++ code to store the line number in the Alternatively, we can modify the C++ code to store the line number in the
promise type. We can use ``std::source_location`` to get the line number of promise type. We can use a ``std::source_location`` to get the line number of
the await and store it inside the ``promise_type``. In the debugger, we can the await and store it inside the ``promise_type``. In the debugger, we can
then read the line number from the promise of the suspended coroutine. then read the line number from the promise of the suspended coroutine.
@ -270,7 +270,7 @@ then read the line number from the promise of the suspended coroutine.
}; };
The downside of both approaches is that they come at the price of additional The downside of both approaches is that they come at the price of additional
runtime cost. In particular, the second approach increases binary size, since it runtime cost. In particular the second approach increases binary size, since it
requires additional ``std::source_location`` objects, and those source requires additional ``std::source_location`` objects, and those source
locations are not stripped by split-dwarf. Whether the first approach is worth locations are not stripped by split-dwarf. Whether the first approach is worth
the additional runtime cost is a trade-off you need to make yourself. the additional runtime cost is a trade-off you need to make yourself.
@ -285,7 +285,7 @@ provide custom debugging support, so in addition to this guide, you might want
to check out their documentation. to check out their documentation.
When using coroutines for asynchronous programming, your library usually When using coroutines for asynchronous programming, your library usually
provides you with some ``task`` type. This type usually looks similar to this: provides you some ``task`` type. This type usually looks similar to this:
.. code-block:: c++ .. code-block:: c++
@ -479,7 +479,7 @@ One such solution is to store the list of in-flight coroutines in a collection:
}; };
With this in place, it is possible to inspect ``inflight_coroutines`` from the With this in place, it is possible to inspect ``inflight_coroutines`` from the
debugger and rely on LLDB's ``std::coroutine_handle`` pretty-printer to debugger, and rely on LLDB's ``std::coroutine_handle`` pretty-printer to
inspect the coroutines. inspect the coroutines.
This technique will track *all* coroutines, also the ones which are currently This technique will track *all* coroutines, also the ones which are currently
@ -498,8 +498,8 @@ LLDB before 21.0 did not yet show the ``__coro_frame`` inside
``coroutine_handle``. To inspect the coroutine frame, you had to use the ``coroutine_handle``. To inspect the coroutine frame, you had to use the
approach described in the :ref:`devirtualization` section. approach described in the :ref:`devirtualization` section.
LLDB before 18.0 hid the ``__promise`` and ``__coro_frame`` LLDB before 18.0 was hiding the ``__promise`` and ``__coro_frame``
variables by default. The variables are still present, but they need to be variable by default. The variables are still present, but they need to be
explicitly added to the "watch" pane in VS Code or requested via explicitly added to the "watch" pane in VS Code or requested via
``print __promise`` and ``print __coro_frame`` from the debugger console. ``print __promise`` and ``print __coro_frame`` from the debugger console.
@ -511,9 +511,9 @@ section.
Toolchain Implementation Details Toolchain Implementation Details
================================ ================================
This section covers the ABI as well as additional compiler-specific behavior. This section covers the ABI, as well as additional compiler-specific behavior.
The ABI is followed by all compilers, on all major systems, including Windows, The ABI is followed by all compilers, on all major systems, including Windows,
Linux, and macOS. Different compilers emit different debug information, though. Linux and macOS. Different compilers emit different debug information, though.
Ramp, resume and destroy functions Ramp, resume and destroy functions
---------------------------------- ----------------------------------
@ -595,7 +595,7 @@ functions as their first two members. As such, we can read the function
pointers from the coroutine frame and then obtain the function's name from its pointers from the coroutine frame and then obtain the function's name from its
address. address.
The promise is guaranteed to be at a 16-byte offset from the coroutine frame. The promise is guaranteed to be at a 16 byte offset from the coroutine frame.
If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast
the promise as follows: the promise as follows:
@ -607,8 +607,8 @@ Implementation in clang / LLVM
------------------------------ ------------------------------
The C++ Coroutines feature in the Clang compiler is implemented in two parts of The C++ Coroutines feature in the Clang compiler is implemented in two parts of
the compiler. Semantic analysis is performed in Clang, and coroutine the compiler. Semantic analysis is performed in Clang, and Coroutine
construction and optimization take place in the LLVM middle-end. construction and optimization takes place in the LLVM middle-end.
For each coroutine function, the frontend generates a single corresponding For each coroutine function, the frontend generates a single corresponding
LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics
@ -622,7 +622,7 @@ points into the coroutine frame. Most of the heavy lifting to preserve debugging
information is done in this pass. This pass needs to rewrite all variable information is done in this pass. This pass needs to rewrite all variable
locations to point into the coroutine frame. locations to point into the coroutine frame.
Afterwards, a couple of additional optimizations are applied before code Afterwards, a couple of additional optimizations are applied, before code
gets emitted, but none of them are really interesting regarding debugging gets emitted, but none of them are really interesting regarding debugging
information. information.
@ -636,8 +636,8 @@ However, this is not possible for coroutine frames because the frames are
constructed in the LLVM middle-end. constructed in the LLVM middle-end.
To mitigate this problem, the LLVM middle end attempts to generate some debug To mitigate this problem, the LLVM middle end attempts to generate some debug
information, which is unfortunately incomplete, since much of the information, which is unfortunately incomplete, since much of the language
language-specific information is missing in the middle end. specific information is missing in the middle end.
.. _devirtualization: .. _devirtualization:
@ -655,7 +655,7 @@ There are two possible approaches to do so:
We can lookup their types and thereby get the types of promise We can lookup their types and thereby get the types of promise
and coroutine frame. and coroutine frame.
In gdb, one can use the following approach to devirtualize a coroutine type, In gdb, one can use the following approach to devirtualize coroutine type,
assuming we have a ``std::coroutine_handle`` is at address 0x418eb0: assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
:: ::
@ -679,7 +679,7 @@ LLDB comes with devirtualization support out of the box, as part of the
pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
uses the second approach. We look up the types in the destroy function and not uses the second approach. We look up the types in the destroy function and not
the resume function because the resume function pointer will be set to a the resume function because the resume function pointer will be set to a
``nullptr`` as soon as a coroutine reaches its final suspension point. If we used nullptr as soon as a coroutine reaches its final suspension point. If we used
the resume function, devirtualization would hence fail for all coroutines that the resume function, devirtualization would hence fail for all coroutines that
have reached their final suspension point. have reached their final suspension point.
@ -687,10 +687,10 @@ Interpreting the coroutine frame in optimized builds
---------------------------------------------------- ----------------------------------------------------
The ``__coro_frame`` variable usually refers to the coroutine frame of an The ``__coro_frame`` variable usually refers to the coroutine frame of an
*in-flight* coroutine. This means the coroutine is currently executing. *in-flight* coroutine. This means, the coroutine is currently executing.
However, the compiler only guarantees the coroutine frame to be in a consistent However, the compiler only guarantees the coroutine frame to be in a consistent
state while the coroutine is suspended. As such, the variables inside the state while the coroutine is suspended. As such, the variables inside the
``__coro_frame`` variable might be outdated, particularly when optimizations ``__coro_frame`` variable might be outdated, in particular when optimizations
are enabled. are enabled.
Furthermore, when optimizations are enabled, the compiler will layout the Furthermore, when optimizations are enabled, the compiler will layout the
@ -731,7 +731,7 @@ despite ``a`` being frequently incremented.
While this might be surprising, this is a result of the optimizer recognizing While this might be surprising, this is a result of the optimizer recognizing
that it can eliminate most of the load/store operations. that it can eliminate most of the load/store operations.
The above code is optimized to the equivalent of: The above code gets optimized to the equivalent of:
.. code-block:: c++ .. code-block:: c++
@ -1180,5 +1180,5 @@ The authors of the Folly libraries wrote a blog post series on how they debug co
* `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_ * `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
additional topics, such as capturing async stack traces in performance profiles via eBPF filters more additional topics, such as capturing async stack traces in performance profiles via eBPF filters
and printing async stack traces on crashes. and printing async stack traces on crashes.

View File

@ -1763,7 +1763,6 @@ Hexadecimal floating constants (N308) C
Compound literals (N716) C99 C89, C++ Compound literals (N716) C99 C89, C++
``//`` comments (N644) C99 C89 ``//`` comments (N644) C99 C89
Mixed declarations and code (N740) C99 C89 Mixed declarations and code (N740) C99 C89
init-statement in for (N740) C99 C89
Variadic macros (N707) C99 C89 Variadic macros (N707) C99 C89
Empty macro arguments (N570) C99 C89 Empty macro arguments (N570) C99 C89
Trailing comma in enum declaration C99 C89 Trailing comma in enum declaration C99 C89

View File

@ -37,22 +37,6 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
Potentially Breaking Changes Potentially Breaking Changes
============================ ============================
- Clang will now emit a warning if the auto-detected GCC installation
directory (i.e. the one with the largest version number) does not
contain libstdc++ include directories although a "complete" GCC
installation directory containing the include directories is
available. It is planned to change the auto-detection to prefer the
"complete" directory in the future. The warning will disappear if
the libstdc++ include directories are either installed or removed
for all GCC installation directories considered by the
auto-detection; see the output of ``clang -v`` for a list of those
directories. If the GCC installations cannot be modified and
maintaining the current choice of the auto-detection is desired, the
GCC installation directory can be selected explicitly using the
``--gcc-install-dir`` command line argument. This will silence the
warning. It can also be disabled using the
``-Wno-gcc-install-dir-libstdcxx`` command line flag.
C/C++ Language Potentially Breaking Changes C/C++ Language Potentially Breaking Changes
------------------------------------------- -------------------------------------------
@ -245,7 +229,6 @@ Bug Fixes in This Version
cast chain. (#GH149967). cast chain. (#GH149967).
- Fixed a crash with incompatible pointer to integer conversions in designated - Fixed a crash with incompatible pointer to integer conversions in designated
initializers involving string literals. (#GH154046) initializers involving string literals. (#GH154046)
- Fixed scope of typedefs present inside a template class. (#GH91451)
Bug Fixes to Compiler Builtins Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -309,13 +292,6 @@ NVPTX Support
X86 Support X86 Support
^^^^^^^^^^^ ^^^^^^^^^^^
- More SSE, AVX and AVX512 intrinsics, including initializers and general
arithmetic can now be used in C++ constant expressions.
- Some SSE, AVX and AVX512 intrinsics have been converted to wrap
generic __builtin intrinsics.
- NOTE: Please avoid use of the __builtin_ia32_* intrinsics - these are not
guaranteed to exist in future releases, or match behaviour with previous
releases of clang or other compilers.
Arm and AArch64 Support Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -23,20 +23,20 @@
#include "clang/Basic/DiagnosticInstallAPI.h" #include "clang/Basic/DiagnosticInstallAPI.h"
#include "clang/Basic/DiagnosticLex.h" #include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticRefactoring.h"
#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/DiagnosticSerialization.h" #include "clang/Basic/DiagnosticSerialization.h"
#include "clang/Basic/DiagnosticRefactoring.h"
namespace clang { namespace clang {
template <size_t SizeOfStr, typename FieldType> class StringSizerHelper { template <size_t SizeOfStr, typename FieldType>
class StringSizerHelper {
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!"); static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
public: public:
enum { Size = SizeOfStr }; enum { Size = SizeOfStr };
}; };
} // end namespace clang } // end namespace clang
#define STR_SIZE(str, fieldTy) \ #define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size fieldTy>::Size
#endif #endif

View File

@ -627,23 +627,11 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
} }
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
} }
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
@ -666,6 +654,46 @@ let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">; def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
} }
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
}
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
}
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">; def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
} }

View File

@ -885,9 +885,4 @@ def warn_drv_openacc_without_cir
: Warning<"OpenACC directives will result in no runtime behavior; use " : Warning<"OpenACC directives will result in no runtime behavior; use "
"-fclangir to enable runtime effect">, "-fclangir to enable runtime effect">,
InGroup<SourceUsesOpenACC>; InGroup<SourceUsesOpenACC>;
def warn_drv_gcc_install_dir_libstdcxx : Warning<
"future releases of the clang compiler will prefer GCC installations "
"containing libstdc++ include directories; '%0' would be chosen over '%1'">,
InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
} }

View File

@ -23,17 +23,17 @@
#include <vector> #include <vector>
namespace clang { namespace clang {
class DiagnosticsEngine; class DiagnosticsEngine;
class DiagnosticBuilder; class DiagnosticBuilder;
class LangOptions; class LangOptions;
class SourceLocation; class SourceLocation;
// Import the diagnostic enums themselves. // Import the diagnostic enums themselves.
namespace diag { namespace diag {
enum class Group; enum class Group;
// Size of each of the diagnostic categories. // Size of each of the diagnostic categories.
enum { enum {
DIAG_SIZE_COMMON = 300, DIAG_SIZE_COMMON = 300,
DIAG_SIZE_DRIVER = 400, DIAG_SIZE_DRIVER = 400,
DIAG_SIZE_FRONTEND = 200, DIAG_SIZE_FRONTEND = 200,
@ -47,10 +47,9 @@ enum {
DIAG_SIZE_ANALYSIS = 100, DIAG_SIZE_ANALYSIS = 100,
DIAG_SIZE_REFACTORING = 1000, DIAG_SIZE_REFACTORING = 1000,
DIAG_SIZE_INSTALLAPI = 100, DIAG_SIZE_INSTALLAPI = 100,
}; };
// Start position for diagnostics. // Start position for diagnostics.
// clang-format off enum {
enum {
DIAG_START_COMMON = 0, DIAG_START_COMMON = 0,
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON), DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER), DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
@ -65,36 +64,35 @@ enum {
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS), DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING), DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI) DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
}; };
// clang-format on
class CustomDiagInfo; class CustomDiagInfo;
/// All of the diagnostics that can be emitted by the frontend. /// All of the diagnostics that can be emitted by the frontend.
typedef unsigned kind; typedef unsigned kind;
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
/// to either Ignore (nothing), Remark (emit a remark), Warning /// to either Ignore (nothing), Remark (emit a remark), Warning
/// (emit a warning) or Error (emit as an error). It allows clients to /// (emit a warning) or Error (emit as an error). It allows clients to
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one). /// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
enum class Severity : uint8_t { enum class Severity : uint8_t {
// NOTE: 0 means "uncomputed". // NOTE: 0 means "uncomputed".
Ignored = 1, ///< Do not present this diagnostic, ignore it. Ignored = 1, ///< Do not present this diagnostic, ignore it.
Remark = 2, ///< Present this diagnostic as a remark. Remark = 2, ///< Present this diagnostic as a remark.
Warning = 3, ///< Present this diagnostic as a warning. Warning = 3, ///< Present this diagnostic as a warning.
Error = 4, ///< Present this diagnostic as an error. Error = 4, ///< Present this diagnostic as an error.
Fatal = 5 ///< Present this diagnostic as a fatal error. Fatal = 5 ///< Present this diagnostic as a fatal error.
}; };
/// Flavors of diagnostics we can emit. Used to filter for a particular /// Flavors of diagnostics we can emit. Used to filter for a particular
/// kind of diagnostic (for instance, for -W/-R flags). /// kind of diagnostic (for instance, for -W/-R flags).
enum class Flavor { enum class Flavor {
WarningOrError, ///< A diagnostic that indicates a problem or potential WarningOrError, ///< A diagnostic that indicates a problem or potential
///< problem. Can be made fatal by -Werror. ///< problem. Can be made fatal by -Werror.
Remark ///< A diagnostic that indicates normal progress through Remark ///< A diagnostic that indicates normal progress through
///< compilation. ///< compilation.
}; };
} // end namespace diag } // end namespace diag
} // end namespace clang } // end namespace clang
// This has to be included *after* the DIAG_START_ enums above are defined. // This has to be included *after* the DIAG_START_ enums above are defined.
@ -175,8 +173,7 @@ public:
/// Used for handling and querying diagnostic IDs. /// Used for handling and querying diagnostic IDs.
/// ///
/// Can be used and shared by multiple Diagnostics for multiple translation /// Can be used and shared by multiple Diagnostics for multiple translation units.
/// units.
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public: public:
/// The level of the diagnostic, after it has been through mapping. /// The level of the diagnostic, after it has been through mapping.

View File

@ -50,45 +50,6 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
let isOptional = 1; let isOptional = 1;
} }
//===----------------------------------------------------------------------===//
// SourceLanguageAttr
//===----------------------------------------------------------------------===//
// TODO: Add cases for other languages that Clang supports.
def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [
I32EnumAttrCase<"C", 1, "c">,
I32EnumAttrCase<"CXX", 2, "cxx">
]> {
// The enum attr class is defined in `CIR_SourceLanguageAttr` below,
// so that it can define extra class methods.
let genSpecializedAttr = 0;
}
def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> {
let summary = "Module source language";
let description = [{
Represents the source language used to generate the module.
Example:
```
// Module compiled from C.
module attributes {cir.lang = cir.lang<c>} {}
// Module compiled from C++.
module attributes {cir.lang = cir.lang<cxx>} {}
```
Module source language attribute name is `cir.lang` is defined by
`getSourceLanguageAttrName` method in CIRDialect class.
}];
let extraClassDeclaration = [{
bool isC() const { return getValue() == SourceLanguage::C; }
bool isCXX() const { return getValue() == SourceLanguage::CXX; }
}];
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// OptInfoAttr // OptInfoAttr
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -535,72 +496,6 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
}]; }];
} }
//===----------------------------------------------------------------------===//
// VTableAttr
//===----------------------------------------------------------------------===//
def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
let summary = "Represents a C++ vtable";
let description = [{
Wraps a #cir.const_record containing one or more vtable arrays.
In most cases, the anonymous record type wrapped by this attribute will
contain a single array corresponding to the vtable for one class. However,
in the case of multiple inheritence, the anonymous structure may contain
multiple arrays, each of which is a vtable.
Example 1 (single vtable):
```mlir
cir.global linkonce_odr @_ZTV6Mother =
#cir.vtable<{
#cir.const_array<[
#cir.ptr<null> : !cir.ptr<!u8i>,
#cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>,
#cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>,
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
]> : !cir.array<!cir.ptr<!u8i> x 4>
}> : !rec_anon_struct1
```
Example 2 (multiple vtables):
```mlir
cir.global linkonce_odr @_ZTV5Child =
#cir.vtable<{
#cir.const_array<[
#cir.ptr<null> : !cir.ptr<!u8i>,
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
#cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>,
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
]> : !cir.array<!cir.ptr<!u8i> x 4>,
#cir.const_array<[
#cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
#cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i>
]> : !cir.array<!cir.ptr<!u8i> x 3>
}> : !rec_anon_struct2
```
}];
// `data` is a const record with one element, containing an array of
// vtable information.
let parameters = (ins
AttributeSelfTypeParameter<"">:$type,
"mlir::ArrayAttr":$data
);
let builders = [
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
"mlir::ArrayAttr":$data), [{
return $_get(type.getContext(), type, data);
}]>
];
let genVerifyDecl = 1;
let assemblyFormat = [{
`<` custom<RecordMembers>($data) `>`
}];
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ConstComplexAttr // ConstComplexAttr
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -35,7 +35,6 @@ def CIR_Dialect : Dialect {
let hasConstantMaterializer = 1; let hasConstantMaterializer = 1;
let extraClassDeclaration = [{ let extraClassDeclaration = [{
static llvm::StringRef getSourceLanguageAttrName() { return "cir.lang"; }
static llvm::StringRef getTripleAttrName() { return "cir.triple"; } static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; } static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
static llvm::StringRef getCalleeAttrName() { return "callee"; } static llvm::StringRef getCalleeAttrName() { return "callee"; }

View File

@ -26,7 +26,6 @@ std::unique_ptr<Pass> createCIRSimplifyPass();
std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createHoistAllocasPass();
std::unique_ptr<Pass> createLoweringPreparePass(); std::unique_ptr<Pass> createLoweringPreparePass();
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx); std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
std::unique_ptr<Pass> createGotoSolverPass();
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);

View File

@ -72,16 +72,6 @@ def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
let dependentDialects = ["cir::CIRDialect"]; let dependentDialects = ["cir::CIRDialect"];
} }
def GotoSolver : Pass<"cir-goto-solver"> {
let summary = "Replaces goto operations with branches";
let description = [{
This pass transforms CIR and replaces goto-s with branch
operations to the proper blocks.
}];
let constructor = "mlir::createGotoSolverPass()";
let dependentDialects = ["cir::CIRDialect"];
}
def LoweringPrepare : Pass<"cir-lowering-prepare"> { def LoweringPrepare : Pass<"cir-lowering-prepare"> {
let summary = "Lower to more fine-grained CIR operations before lowering to " let summary = "Lower to more fine-grained CIR operations before lowering to "
"other dialects"; "other dialects";

View File

@ -264,7 +264,6 @@ struct MissingFeatures {
static bool setNonGC() { return false; } static bool setNonGC() { return false; }
static bool setObjCGCLValueClass() { return false; } static bool setObjCGCLValueClass() { return false; }
static bool setTargetAttributes() { return false; } static bool setTargetAttributes() { return false; }
static bool sourceLanguageCases() { return false; }
static bool stackBase() { return false; } static bool stackBase() { return false; }
static bool stackSaveOp() { return false; } static bool stackSaveOp() { return false; }
static bool targetCIRGenInfoArch() { return false; } static bool targetCIRGenInfoArch() { return false; }

View File

@ -32,7 +32,6 @@
namespace llvm { namespace llvm {
class AttrBuilder; class AttrBuilder;
class Constant; class Constant;
class ConstantInt;
class Function; class Function;
class FunctionType; class FunctionType;
class Type; class Type;
@ -127,12 +126,6 @@ uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD);
uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM, uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
QualType FunctionType); QualType FunctionType);
/// Return a signed constant pointer.
llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
llvm::Constant *Pointer, unsigned Key,
llvm::Constant *StorageAddress,
llvm::ConstantInt *OtherDiscriminator);
/// Given the language and code-generation options that Clang was configured /// Given the language and code-generation options that Clang was configured
/// with, set the default LLVM IR attributes for a function definition. /// with, set the default LLVM IR attributes for a function definition.
/// The attributes set here are mostly global target-configuration and /// The attributes set here are mostly global target-configuration and

View File

@ -9468,12 +9468,8 @@ def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<dxc_Group>,
def fspv_extension_EQ def fspv_extension_EQ
: Joined<["-"], "fspv-extension=">, : Joined<["-"], "fspv-extension=">,
Group<dxc_Group>, Group<dxc_Group>,
HelpText< HelpText<"Specify the available SPIR-V extensions. If this option is not "
"Specify the available SPIR-V extensions. If this option is not " "specified, then all extensions are available.">;
"specified, then all extensions are available. If KHR is specified, "
"then all KHR extensions will be available. If DXC is specifided, "
"then all extensions implemented by the DirectX Shader compiler will "
"be available. This option is useful for moving from DXC to Clang.">;
def fvk_use_dx_layout def fvk_use_dx_layout
: DXCFlag<"fvk-use-dx-layout">, : DXCFlag<"fvk-use-dx-layout">,
HelpText<"Use DirectX memory layout for Vulkan resources.">; HelpText<"Use DirectX memory layout for Vulkan resources.">;

View File

@ -224,6 +224,9 @@ protected:
static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args, llvm::opt::ArgStringList &CC1Args,
const Twine &Path); const Twine &Path);
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs, static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args, llvm::opt::ArgStringList &CC1Args,
const Twine &Path); const Twine &Path);
@ -243,9 +246,6 @@ protected:
///@} ///@}
public: public:
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
virtual ~ToolChain(); virtual ~ToolChain();
// Accessors // Accessors

View File

@ -1640,9 +1640,6 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Stk.peek<Pointer>(); const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckRange(S, OpPC, Ptr, CSK_Field)) if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false; return false;
if (!CheckArray(S, OpPC, Ptr))
return false;
const Pointer &Field = Ptr.atField(I); const Pointer &Field = Ptr.atField(I);
Field.deref<T>() = Value; Field.deref<T>() = Value;
Field.initialize(); Field.initialize();
@ -1655,9 +1652,6 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Stk.peek<Pointer>(); const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckRange(S, OpPC, Ptr, CSK_Field)) if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false; return false;
if (!CheckArray(S, OpPC, Ptr))
return false;
const Pointer &Field = Ptr.atField(I); const Pointer &Field = Ptr.atField(I);
Field.deref<T>() = Value; Field.deref<T>() = Value;
Field.activate(); Field.activate();
@ -1669,13 +1663,7 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
assert(F->isBitField()); assert(F->isBitField());
const T &Value = S.Stk.pop<T>(); const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>(); const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
if (!CheckArray(S, OpPC, Ptr))
return false;
const Pointer &Field = Ptr.atField(F->Offset);
if constexpr (needsAlloc<T>()) { if constexpr (needsAlloc<T>()) {
T Result = S.allocAP<T>(Value.bitWidth()); T Result = S.allocAP<T>(Value.bitWidth());
@ -1701,13 +1689,7 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
const Record::Field *F) { const Record::Field *F) {
assert(F->isBitField()); assert(F->isBitField());
const T &Value = S.Stk.pop<T>(); const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>(); const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
if (!CheckArray(S, OpPC, Ptr))
return false;
const Pointer &Field = Ptr.atField(F->Offset);
if constexpr (needsAlloc<T>()) { if constexpr (needsAlloc<T>()) {
T Result = S.allocAP<T>(Value.bitWidth()); T Result = S.allocAP<T>(Value.bitWidth());
@ -1806,8 +1788,6 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false; return false;
if (!Ptr.isBlockPointer()) { if (!Ptr.isBlockPointer()) {
if (!Ptr.isIntegralPointer())
return false;
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
return true; return true;
} }
@ -1829,8 +1809,6 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
return false; return false;
if (!Ptr.isBlockPointer()) { if (!Ptr.isBlockPointer()) {
if (!Ptr.isIntegralPointer())
return false;
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
return true; return true;
} }
@ -2459,17 +2437,9 @@ inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset); const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);
if (Ptr.getLifetime() == Lifetime::Ended) { if (Ptr.getLifetime() == Lifetime::Ended) {
// Try to use the declaration for better diagnostics auto *D = cast<NamedDecl>(Ptr.getFieldDesc()->asDecl());
if (const Decl *D = Ptr.getDeclDesc()->asDecl()) { S.FFDiag(D->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
auto *ND = cast<NamedDecl>(D); << D->getNameAsString();
S.FFDiag(ND->getLocation(),
diag::note_constexpr_destroy_out_of_lifetime)
<< ND->getNameAsString();
} else {
S.FFDiag(Ptr.getDeclDesc()->getLocation(),
diag::note_constexpr_destroy_out_of_lifetime)
<< Ptr.toDiagnosticString(S.getASTContext());
}
return false; return false;
} }
} }

View File

@ -205,8 +205,6 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
if (A.isDummy() || B.isDummy()) if (A.isDummy() || B.isDummy())
return false; return false;
if (!A.isBlockPointer() || !B.isBlockPointer())
return false;
bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp || bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp ||
ID == Builtin::BI__builtin_wcscmp || ID == Builtin::BI__builtin_wcscmp ||
@ -214,10 +212,7 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
assert(A.getFieldDesc()->isPrimitiveArray()); assert(A.getFieldDesc()->isPrimitiveArray());
assert(B.getFieldDesc()->isPrimitiveArray()); assert(B.getFieldDesc()->isPrimitiveArray());
// Different element types shouldn't happen, but with casts they can. assert(getElemType(A).getTypePtr() == getElemType(B).getTypePtr());
if (!S.getASTContext().hasSameUnqualifiedType(getElemType(A), getElemType(B)))
return false;
PrimType ElemT = *S.getContext().classify(getElemType(A)); PrimType ElemT = *S.getContext().classify(getElemType(A));
auto returnResult = [&](int V) -> bool { auto returnResult = [&](int V) -> bool {
@ -2688,10 +2683,9 @@ static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC,
const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>(); const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
PrimType ElemT = *S.getContext().classify(VT->getElementType()); PrimType ElemT = *S.getContext().classify(VT->getElementType());
unsigned SourceLen = VT->getNumElements(); unsigned SourceLen = VT->getNumElements();
SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen / 2);
PrimType DstElemT = *S.getContext().classify(
Call->getType()->castAs<VectorType>()->getElementType());
unsigned DstElem = 0;
for (unsigned I = 0; I != SourceLen; I += 2) { for (unsigned I = 0; I != SourceLen; I += 2) {
APSInt Elem1; APSInt Elem1;
APSInt Elem2; APSInt Elem2;
@ -2705,19 +2699,16 @@ static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC,
case clang::X86::BI__builtin_ia32_pmuludq128: case clang::X86::BI__builtin_ia32_pmuludq128:
case clang::X86::BI__builtin_ia32_pmuludq256: case clang::X86::BI__builtin_ia32_pmuludq256:
case clang::X86::BI__builtin_ia32_pmuludq512: case clang::X86::BI__builtin_ia32_pmuludq512:
Result = APSInt(llvm::APIntOps::muluExtended(Elem1, Elem2), Result = APSInt(llvm::APIntOps::muluExtended(Elem1, Elem2), true);
/*IsUnsigned=*/true);
break; break;
case clang::X86::BI__builtin_ia32_pmuldq128: case clang::X86::BI__builtin_ia32_pmuldq128:
case clang::X86::BI__builtin_ia32_pmuldq256: case clang::X86::BI__builtin_ia32_pmuldq256:
case clang::X86::BI__builtin_ia32_pmuldq512: case clang::X86::BI__builtin_ia32_pmuldq512:
Result = APSInt(llvm::APIntOps::mulsExtended(Elem1, Elem2), Result = APSInt(llvm::APIntOps::mulsExtended(Elem1, Elem2), false);
/*IsUnsigned=*/false);
break; break;
} }
INT_TYPE_SWITCH_NO_BOOL(DstElemT, INT_TYPE_SWITCH_NO_BOOL(ElemT,
{ Dst.elem<T>(DstElem) = static_cast<T>(Result); }); { Dst.elem<T>(I) = static_cast<T>(Result); });
++DstElem;
} }
Dst.initializeAllElements(); Dst.initializeAllElements();
@ -2783,40 +2774,6 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
return true; return true;
} }
/// AVX512 predicated move: "Result = Mask[] ? LHS[] : RHS[]".
static bool interp__builtin_select(InterpState &S, CodePtr OpPC,
const CallExpr *Call) {
const Pointer &RHS = S.Stk.pop<Pointer>();
const Pointer &LHS = S.Stk.pop<Pointer>();
PrimType MaskT = *S.getContext().classify(Call->getArg(0));
APSInt Mask = popToAPSInt(S.Stk, MaskT);
const Pointer &Dst = S.Stk.peek<Pointer>();
assert(LHS.getNumElems() == RHS.getNumElems());
assert(LHS.getNumElems() == Dst.getNumElems());
unsigned NumElems = LHS.getNumElems();
PrimType ElemT = LHS.getFieldDesc()->getPrimType();
PrimType DstElemT = Dst.getFieldDesc()->getPrimType();
for (unsigned I = 0; I != NumElems; ++I) {
if (ElemT == PT_Float) {
assert(DstElemT == PT_Float);
Dst.elem<Floating>(I) =
Mask[I] ? LHS.elem<Floating>(I) : RHS.elem<Floating>(I);
} else {
APSInt Elem;
INT_TYPE_SWITCH(ElemT, {
Elem = Mask[I] ? LHS.elem<T>(I).toAPSInt() : RHS.elem<T>(I).toAPSInt();
});
INT_TYPE_SWITCH_NO_BOOL(DstElemT,
{ Dst.elem<T>(I) = static_cast<T>(Elem); });
}
}
Dst.initializeAllElements();
return true;
}
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) { uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID)) if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@ -3247,38 +3204,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case clang::X86::BI__builtin_ia32_pmuldq512: case clang::X86::BI__builtin_ia32_pmuldq512:
case clang::X86::BI__builtin_ia32_pmuludq128: case clang::X86::BI__builtin_ia32_pmuludq128:
case clang::X86::BI__builtin_ia32_pmuludq256: case clang::X86::BI__builtin_ia32_pmuludq256:
case clang::X86::BI__builtin_ia32_pmuludq512:
return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID); return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID);
case Builtin::BI__builtin_elementwise_fma: case Builtin::BI__builtin_elementwise_fma:
return interp__builtin_elementwise_fma(S, OpPC, Call); return interp__builtin_elementwise_fma(S, OpPC, Call);
case X86::BI__builtin_ia32_selectb_128:
case X86::BI__builtin_ia32_selectb_256:
case X86::BI__builtin_ia32_selectb_512:
case X86::BI__builtin_ia32_selectw_128:
case X86::BI__builtin_ia32_selectw_256:
case X86::BI__builtin_ia32_selectw_512:
case X86::BI__builtin_ia32_selectd_128:
case X86::BI__builtin_ia32_selectd_256:
case X86::BI__builtin_ia32_selectd_512:
case X86::BI__builtin_ia32_selectq_128:
case X86::BI__builtin_ia32_selectq_256:
case X86::BI__builtin_ia32_selectq_512:
case X86::BI__builtin_ia32_selectph_128:
case X86::BI__builtin_ia32_selectph_256:
case X86::BI__builtin_ia32_selectph_512:
case X86::BI__builtin_ia32_selectpbf_128:
case X86::BI__builtin_ia32_selectpbf_256:
case X86::BI__builtin_ia32_selectpbf_512:
case X86::BI__builtin_ia32_selectps_128:
case X86::BI__builtin_ia32_selectps_256:
case X86::BI__builtin_ia32_selectps_512:
case X86::BI__builtin_ia32_selectpd_128:
case X86::BI__builtin_ia32_selectpd_256:
case X86::BI__builtin_ia32_selectpd_512:
return interp__builtin_select(S, OpPC, Call);
default: default:
S.FFDiag(S.Current->getLocation(OpPC), S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr) diag::note_invalid_subexpr_in_const_expr)

View File

@ -341,8 +341,6 @@ public:
QualType getType() const { QualType getType() const {
if (isTypeidPointer()) if (isTypeidPointer())
return QualType(Typeid.TypeInfoType, 0); return QualType(Typeid.TypeInfoType, 0);
if (isFunctionPointer())
return asFunctionPointer().getFunction()->getDecl()->getType();
if (inPrimitiveArray() && Offset != asBlockPointer().Base) { if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
// Unfortunately, complex and vector types are not array types in clang, // Unfortunately, complex and vector types are not array types in clang,

View File

@ -11669,24 +11669,13 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
case clang::X86::BI__builtin_ia32_pmulhuw512: case clang::X86::BI__builtin_ia32_pmulhuw512:
case clang::X86::BI__builtin_ia32_pmulhw128: case clang::X86::BI__builtin_ia32_pmulhw128:
case clang::X86::BI__builtin_ia32_pmulhw256: case clang::X86::BI__builtin_ia32_pmulhw256:
case clang::X86::BI__builtin_ia32_pmulhw512: case clang::X86::BI__builtin_ia32_pmulhw512: {
case clang::X86::BI__builtin_ia32_psllv2di:
case clang::X86::BI__builtin_ia32_psllv4di:
case clang::X86::BI__builtin_ia32_psllv4si:
case clang::X86::BI__builtin_ia32_psllv8si:
case clang::X86::BI__builtin_ia32_psrav4si:
case clang::X86::BI__builtin_ia32_psrav8si:
case clang::X86::BI__builtin_ia32_psrlv2di:
case clang::X86::BI__builtin_ia32_psrlv4di:
case clang::X86::BI__builtin_ia32_psrlv4si:
case clang::X86::BI__builtin_ia32_psrlv8si:{
APValue SourceLHS, SourceRHS; APValue SourceLHS, SourceRHS;
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) !EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
return false; return false;
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType();
unsigned SourceLen = SourceLHS.getVectorLength(); unsigned SourceLen = SourceLHS.getVectorLength();
SmallVector<APValue, 4> ResultElements; SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen); ResultElements.reserve(SourceLen);
@ -11698,12 +11687,12 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_elementwise_add_sat: case Builtin::BI__builtin_elementwise_add_sat:
ResultElements.push_back(APValue( ResultElements.push_back(APValue(
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS), APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS),
DestUnsigned))); DestEltTy->isUnsignedIntegerOrEnumerationType())));
break; break;
case Builtin::BI__builtin_elementwise_sub_sat: case Builtin::BI__builtin_elementwise_sub_sat:
ResultElements.push_back(APValue( ResultElements.push_back(APValue(
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS), APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS),
DestUnsigned))); DestEltTy->isUnsignedIntegerOrEnumerationType())));
break; break;
case clang::X86::BI__builtin_ia32_pmulhuw128: case clang::X86::BI__builtin_ia32_pmulhuw128:
case clang::X86::BI__builtin_ia32_pmulhuw256: case clang::X86::BI__builtin_ia32_pmulhuw256:
@ -11717,40 +11706,6 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS), ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS),
/*isUnsigned=*/false))); /*isUnsigned=*/false)));
break; break;
case clang::X86::BI__builtin_ia32_psllv2di:
case clang::X86::BI__builtin_ia32_psllv4di:
case clang::X86::BI__builtin_ia32_psllv4si:
case clang::X86::BI__builtin_ia32_psllv8si:
if (RHS.uge(RHS.getBitWidth())) {
ResultElements.push_back(
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
break;
}
ResultElements.push_back(
APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned)));
break;
case clang::X86::BI__builtin_ia32_psrav4si:
case clang::X86::BI__builtin_ia32_psrav8si:
if (RHS.uge(RHS.getBitWidth())) {
ResultElements.push_back(
APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned)));
break;
}
ResultElements.push_back(
APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned)));
break;
case clang::X86::BI__builtin_ia32_psrlv2di:
case clang::X86::BI__builtin_ia32_psrlv4di:
case clang::X86::BI__builtin_ia32_psrlv4si:
case clang::X86::BI__builtin_ia32_psrlv8si:
if (RHS.uge(RHS.getBitWidth())) {
ResultElements.push_back(
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
break;
}
ResultElements.push_back(
APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned)));
break;
} }
} }

View File

@ -174,9 +174,6 @@ protected:
DefineStd(Builder, "unix", Opts); DefineStd(Builder, "unix", Opts);
if (this->HasFloat128) if (this->HasFloat128)
Builder.defineMacro("__FLOAT128__"); Builder.defineMacro("__FLOAT128__");
if (Opts.C11)
Builder.defineMacro("__STDC_NO_THREADS__");
} }
public: public:

View File

@ -73,54 +73,21 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr,
// Casts: // Casts:
if (auto const *ce = dyn_cast<CastExpr>(expr)) { if (auto const *ce = dyn_cast<CastExpr>(expr)) {
if (const auto *ece = dyn_cast<ExplicitCastExpr>(ce)) if (isa<ExplicitCastExpr>(ce)) {
cgm.emitExplicitCastExprType(ece); cgm.errorNYI(expr->getSourceRange(),
"emitPointerWithAlignment: explicit cast");
return Address::invalid();
}
switch (ce->getCastKind()) { switch (ce->getCastKind()) {
// Non-converting casts (but not C's implicit conversion from void*). // Non-converting casts (but not C's implicit conversion from void*).
case CK_BitCast: case CK_BitCast:
case CK_NoOp: case CK_NoOp:
case CK_AddressSpaceConversion: { case CK_AddressSpaceConversion: {
if (const auto *ptrTy = cgm.errorNYI(expr->getSourceRange(),
ce->getSubExpr()->getType()->getAs<PointerType>()) { "emitPointerWithAlignment: noop cast");
if (ptrTy->getPointeeType()->isVoidType()) return Address::invalid();
break; } break;
LValueBaseInfo innerBaseInfo;
assert(!cir::MissingFeatures::opTBAA());
Address addr =
emitPointerWithAlignment(ce->getSubExpr(), &innerBaseInfo);
if (baseInfo)
*baseInfo = innerBaseInfo;
if (isa<ExplicitCastExpr>(ce)) {
LValueBaseInfo targetTypeBaseInfo;
const QualType pointeeType = expr->getType()->getPointeeType();
const CharUnits align =
cgm.getNaturalTypeAlignment(pointeeType, &targetTypeBaseInfo);
// If the source l-value is opaque, honor the alignment of the
// casted-to type.
if (innerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) {
if (baseInfo)
baseInfo->mergeForCast(targetTypeBaseInfo);
addr = Address(addr.getPointer(), addr.getElementType(), align);
}
}
assert(!cir::MissingFeatures::sanitizers());
const mlir::Type eltTy =
convertTypeForMem(expr->getType()->getPointeeType());
addr = getBuilder().createElementBitCast(getLoc(expr->getSourceRange()),
addr, eltTy);
assert(!cir::MissingFeatures::addressSpace());
return addr;
}
break;
}
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo. // Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
case CK_ArrayToPointerDecay: case CK_ArrayToPointerDecay:
@ -584,37 +551,6 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
return RValue::get(nullptr); return RValue::get(nullptr);
} }
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
assert(!cir::MissingFeatures::weakRefReference());
return cgm.getAddrOfFunction(gd);
}
static LValue emitFunctionDeclLValue(CIRGenFunction &cgf, const Expr *e,
GlobalDecl gd) {
const FunctionDecl *fd = cast<FunctionDecl>(gd.getDecl());
cir::FuncOp funcOp = emitFunctionDeclPointer(cgf.cgm, gd);
mlir::Location loc = cgf.getLoc(e->getSourceRange());
CharUnits align = cgf.getContext().getDeclAlign(fd);
assert(!cir::MissingFeatures::sanitizers());
mlir::Type fnTy = funcOp.getFunctionType();
mlir::Type ptrTy = cir::PointerType::get(fnTy);
mlir::Value addr = cgf.getBuilder().create<cir::GetGlobalOp>(
loc, ptrTy, funcOp.getSymName());
if (funcOp.getFunctionType() != cgf.convertType(fd->getType())) {
fnTy = cgf.convertType(fd->getType());
ptrTy = cir::PointerType::get(fnTy);
addr = cir::CastOp::create(cgf.getBuilder(), addr.getLoc(), ptrTy,
cir::CastKind::bitcast, addr);
}
return cgf.makeAddrLValue(Address(addr, fnTy, align), e->getType(),
AlignmentSource::Decl);
}
LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
const NamedDecl *nd = e->getDecl(); const NamedDecl *nd = e->getDecl();
QualType ty = e->getType(); QualType ty = e->getType();
@ -671,16 +607,6 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
return emitLValue(bd->getBinding()); return emitLValue(bd->getBinding());
} }
if (const auto *fd = dyn_cast<FunctionDecl>(nd)) {
LValue lv = emitFunctionDeclLValue(*this, e, fd);
// Emit debuginfo for the function declaration if the target wants to.
if (getContext().getTargetInfo().allowDebugInfoForExternalRef())
assert(!cir::MissingFeatures::generateDebugInfo());
return lv;
}
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type"); cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
return LValue(); return LValue();
} }
@ -1475,6 +1401,11 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) {
llvm_unreachable("bad evaluation kind"); llvm_unreachable("bad evaluation kind");
} }
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
assert(!cir::MissingFeatures::weakRefReference());
return cgm.getAddrOfFunction(gd);
}
// Detect the unusual situation where an inline version is shadowed by a // Detect the unusual situation where an inline version is shadowed by a
// non-inline version. In that case we should pick the external one // non-inline version. In that case we should pick the external one
// everywhere. That's GCC behavior too. // everywhere. That's GCC behavior too.

View File

@ -1905,8 +1905,6 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy), cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
Visit(subExpr)); Visit(subExpr));
} }
case CK_FunctionToPointerDecay:
return cgf.emitLValue(subExpr).getPointer();
default: default:
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(), cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),

View File

@ -103,9 +103,6 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
PtrDiffTy = PtrDiffTy =
cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true); cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true);
theModule->setAttr(
cir::CIRDialect::getSourceLanguageAttrName(),
cir::SourceLanguageAttr::get(&mlirContext, getCIRSourceLanguage()));
theModule->setAttr(cir::CIRDialect::getTripleAttrName(), theModule->setAttr(cir::CIRDialect::getTripleAttrName(),
builder.getStringAttr(getTriple().str())); builder.getStringAttr(getTriple().str()));
@ -513,23 +510,6 @@ void CIRGenModule::setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op) {
assert(!cir::MissingFeatures::setTargetAttributes()); assert(!cir::MissingFeatures::setTargetAttributes());
} }
cir::SourceLanguage CIRGenModule::getCIRSourceLanguage() const {
using ClangStd = clang::LangStandard;
using CIRLang = cir::SourceLanguage;
auto opts = getLangOpts();
if (opts.CPlusPlus)
return CIRLang::CXX;
if (opts.C99 || opts.C11 || opts.C17 || opts.C23 || opts.C2y ||
opts.LangStd == ClangStd::lang_c89 ||
opts.LangStd == ClangStd::lang_gnu89)
return CIRLang::C;
// TODO(cir): support remaining source languages.
assert(!cir::MissingFeatures::sourceLanguageCases());
errorNYI("CIR does not yet support the given source language");
}
static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) { static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) {
// Set linkage and visibility in case we never see a definition. // Set linkage and visibility in case we never see a definition.
LinkageInfo lv = nd->getLinkageAndVisibility(); LinkageInfo lv = nd->getLinkageAndVisibility();

View File

@ -461,9 +461,6 @@ private:
void replacePointerTypeArgs(cir::FuncOp oldF, cir::FuncOp newF); void replacePointerTypeArgs(cir::FuncOp oldF, cir::FuncOp newF);
void setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op); void setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op);
/// Map source language used to a CIR attribute.
cir::SourceLanguage getCIRSourceLanguage() const;
}; };
} // namespace CIRGen } // namespace CIRGen

View File

@ -424,44 +424,6 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return elementTypeCheck; return elementTypeCheck;
} }
//===----------------------------------------------------------------------===//
// CIR VTableAttr
//===----------------------------------------------------------------------===//
LogicalResult cir::VTableAttr::verify(
llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
mlir::ArrayAttr data) {
auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
if (!sTy)
return emitError() << "expected !cir.record type result";
if (sTy.getMembers().empty() || data.empty())
return emitError() << "expected record type with one or more subtype";
if (cir::ConstRecordAttr::verify(emitError, type, data).failed())
return failure();
for (const auto &element : data.getAsRange<mlir::Attribute>()) {
const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(element);
if (!constArrayAttr)
return emitError() << "expected constant array subtype";
LogicalResult eltTypeCheck = success();
auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
arrayElts.walkImmediateSubElements(
[&](mlir::Attribute attr) {
if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
return;
eltTypeCheck = emitError()
<< "expected GlobalViewAttr or ConstPtrAttr";
},
[&](mlir::Type type) {});
if (eltTypeCheck.failed())
return eltTypeCheck;
}
return success();
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// CIR Dialect // CIR Dialect
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -342,8 +342,7 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr, if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstComplexAttr, cir::ConstRecordAttr, cir::ConstComplexAttr, cir::ConstRecordAttr,
cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>( cir::GlobalViewAttr, cir::PoisonAttr>(attrType))
attrType))
return success(); return success();
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?"); assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");

View File

@ -4,7 +4,6 @@ add_clang_library(MLIRCIRTransforms
FlattenCFG.cpp FlattenCFG.cpp
HoistAllocas.cpp HoistAllocas.cpp
LoweringPrepare.cpp LoweringPrepare.cpp
GotoSolver.cpp
DEPENDS DEPENDS
MLIRCIRPassIncGen MLIRCIRPassIncGen

View File

@ -1,57 +0,0 @@
//====- GotoSolver.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "PassDetail.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/Passes.h"
#include "llvm/Support/TimeProfiler.h"
#include <memory>
using namespace mlir;
using namespace cir;
namespace {
struct GotoSolverPass : public GotoSolverBase<GotoSolverPass> {
GotoSolverPass() = default;
void runOnOperation() override;
};
static void process(cir::FuncOp func) {
mlir::OpBuilder rewriter(func.getContext());
llvm::StringMap<Block *> labels;
llvm::SmallVector<cir::GotoOp, 4> gotos;
func.getBody().walk([&](mlir::Operation *op) {
if (auto lab = dyn_cast<cir::LabelOp>(op)) {
// Will construct a string copy inplace. Safely erase the label
labels.try_emplace(lab.getLabel(), lab->getBlock());
lab.erase();
} else if (auto goTo = dyn_cast<cir::GotoOp>(op)) {
gotos.push_back(goTo);
}
});
for (auto goTo : gotos) {
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPoint(goTo);
Block *dest = labels[goTo.getLabel()];
cir::BrOp::create(rewriter, goTo.getLoc(), dest);
goTo.erase();
}
}
void GotoSolverPass::runOnOperation() {
llvm::TimeTraceScope scope("Goto Solver");
getOperation()->walk(&process);
}
} // namespace
std::unique_ptr<Pass> mlir::createGotoSolverPass() {
return std::make_unique<GotoSolverPass>();
}

View File

@ -45,7 +45,6 @@ namespace mlir {
void populateCIRPreLoweringPasses(OpPassManager &pm) { void populateCIRPreLoweringPasses(OpPassManager &pm) {
pm.addPass(createHoistAllocasPass()); pm.addPass(createHoistAllocasPass());
pm.addPass(createCIRFlattenCFGPass()); pm.addPass(createCIRFlattenCFGPass());
pm.addPass(createGotoSolverPass());
} }
} // namespace mlir } // namespace mlir

View File

@ -4184,14 +4184,7 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
break; break;
} }
if (auto *CTSD =
dyn_cast<ClassTemplateSpecializationDecl>(Ty->getOriginalDecl())) {
CXXRecordDecl *TemplateDecl =
CTSD->getSpecializedTemplate()->getTemplatedDecl();
RegionMap[TemplateDecl].reset(RealDecl);
} else {
RegionMap[RD].reset(RealDecl); RegionMap[RD].reset(RealDecl);
}
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl); TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))

View File

@ -977,8 +977,6 @@ public:
ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn); ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn);
/// Restore everything back to the original state. /// Restore everything back to the original state.
~ApplyInlineDebugLocation(); ~ApplyInlineDebugLocation();
ApplyInlineDebugLocation(const ApplyInlineDebugLocation &) = delete;
ApplyInlineDebugLocation &operator=(ApplyInlineDebugLocation &) = delete;
}; };
class SanitizerDebugLocation { class SanitizerDebugLocation {
@ -990,8 +988,6 @@ public:
ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals, ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
SanitizerHandler Handler); SanitizerHandler Handler);
~SanitizerDebugLocation(); ~SanitizerDebugLocation();
SanitizerDebugLocation(const SanitizerDebugLocation &) = delete;
SanitizerDebugLocation &operator=(SanitizerDebugLocation &) = delete;
}; };
} // namespace CodeGen } // namespace CodeGen

View File

@ -466,14 +466,6 @@ llvm::Constant *CodeGenModule::getConstantSignedPointer(
OtherDiscriminator); OtherDiscriminator);
} }
llvm::Constant *
CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,
unsigned Key, llvm::Constant *StorageAddress,
llvm::ConstantInt *OtherDiscriminator) {
return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,
OtherDiscriminator);
}
/// If applicable, sign a given constant function pointer with the ABI rules for /// If applicable, sign a given constant function pointer with the ABI rules for
/// functionType. /// functionType.
llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,

View File

@ -1409,6 +1409,13 @@ void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
CC1Args.push_back(DriverArgs.MakeArgString(Path)); CC1Args.push_back(DriverArgs.MakeArgString(Path));
} }
/// Utility function to add a system include directory to CC1 arguments.
void ToolChain::addSystemInclude(const ArgList &DriverArgs,
ArgStringList &CC1Args, const Twine &Path) {
CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
/// Utility function to add a system include directory with extern "C" /// Utility function to add a system include directory with extern "C"
/// semantics to CC1 arguments. /// semantics to CC1 arguments.
/// ///
@ -1431,14 +1438,6 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, Path); addExternCSystemInclude(DriverArgs, CC1Args, Path);
} }
/// Utility function to add a system include directory to CC1 arguments.
/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs,
ArgStringList &CC1Args,
const Twine &Path) {
CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
/// Utility function to add a list of system framework directories to CC1. /// Utility function to add a list of system framework directories to CC1.
void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs, void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs,
ArgStringList &CC1Args, ArgStringList &CC1Args,

View File

@ -534,14 +534,7 @@ void Flang::addTargetOptions(const ArgList &Args,
} }
Args.addAllArgs(CmdArgs, Args.addAllArgs(CmdArgs,
{options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, {options::OPT_fverbose_asm, options::OPT_fno_verbose_asm});
options::OPT_fatomic_ignore_denormal_mode,
options::OPT_fno_atomic_ignore_denormal_mode,
options::OPT_fatomic_fine_grained_memory,
options::OPT_fno_atomic_fine_grained_memory,
options::OPT_fatomic_remote_memory,
options::OPT_fno_atomic_remote_memory,
options::OPT_munsafe_fp_atomics});
} }
void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,

View File

@ -2123,11 +2123,10 @@ void Generic_GCC::GCCInstallationDetector::init(
StringRef TripleText = StringRef TripleText =
llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir)); llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
SelectedInstallation.Version = GCCVersion::Parse(VersionText); Version = GCCVersion::Parse(VersionText);
SelectedInstallation.GCCTriple.setTriple(TripleText); GCCTriple.setTriple(TripleText);
SelectedInstallation.GCCInstallPath = std::string(InstallDir); GCCInstallPath = std::string(InstallDir);
SelectedInstallation.GCCParentLibPath = GCCParentLibPath = GCCInstallPath + "/../../..";
SelectedInstallation.GCCInstallPath + "/../../..";
IsValid = true; IsValid = true;
} }
return; return;
@ -2187,7 +2186,7 @@ void Generic_GCC::GCCInstallationDetector::init(
// Loop over the various components which exist and select the best GCC // Loop over the various components which exist and select the best GCC
// installation available. GCC installs are ranked by version number. // installation available. GCC installs are ranked by version number.
const GCCVersion VersionZero = GCCVersion::Parse("0.0.0"); const GCCVersion VersionZero = GCCVersion::Parse("0.0.0");
SelectedInstallation.Version = VersionZero; Version = VersionZero;
for (const std::string &Prefix : Prefixes) { for (const std::string &Prefix : Prefixes) {
auto &VFS = D.getVFS(); auto &VFS = D.getVFS();
if (!VFS.exists(Prefix)) if (!VFS.exists(Prefix))
@ -2215,7 +2214,7 @@ void Generic_GCC::GCCInstallationDetector::init(
} }
// Skip other prefixes once a GCC installation is found. // Skip other prefixes once a GCC installation is found.
if (SelectedInstallation.Version > VersionZero) if (Version > VersionZero)
break; break;
} }
} }
@ -2224,17 +2223,14 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
for (const auto &InstallPath : CandidateGCCInstallPaths) for (const auto &InstallPath : CandidateGCCInstallPaths)
OS << "Found candidate GCC installation: " << InstallPath << "\n"; OS << "Found candidate GCC installation: " << InstallPath << "\n";
if (!SelectedInstallation.GCCInstallPath.empty()) if (!GCCInstallPath.empty())
OS << "Selected GCC installation: " << SelectedInstallation.GCCInstallPath OS << "Selected GCC installation: " << GCCInstallPath << "\n";
<< "\n";
for (const auto &Multilib : Multilibs) for (const auto &Multilib : Multilibs)
OS << "Candidate multilib: " << Multilib << "\n"; OS << "Candidate multilib: " << Multilib << "\n";
if (Multilibs.size() != 0 || if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
!SelectedInstallation.SelectedMultilib.isDefault()) OS << "Selected multilib: " << SelectedMultilib << "\n";
OS << "Selected multilib: " << SelectedInstallation.SelectedMultilib
<< "\n";
} }
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
@ -2772,50 +2768,14 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
} }
Multilibs = Detected.Multilibs; Multilibs = Detected.Multilibs;
SelectedInstallation.SelectedMultilib = SelectedMultilib = Detected.SelectedMultilibs.empty()
Detected.SelectedMultilibs.empty() ? Multilib() ? Multilib()
: Detected.SelectedMultilibs.back(); : Detected.SelectedMultilibs.back();
BiarchSibling = Detected.BiarchSibling; BiarchSibling = Detected.BiarchSibling;
return true; return true;
} }
bool Generic_GCC::GCCInstallationDetector::SelectGCCInstallationDirectory(
const SmallVector<Generic_GCC::GCCInstallCandidate, 3> &Installations,
const ArgList &Args,
Generic_GCC::GCCInstallCandidate &SelectedInstallation) const {
if (Installations.empty())
return false;
SelectedInstallation =
*max_element(Installations, [](const auto &Max, const auto &I) {
return I.Version > Max.Version;
});
// FIXME Start selecting installation with libstdc++ in clang 22,
// using the current way of selecting the installation as a fallback
// only. For now, warn if the installation with libstdc++ differs
// from SelectedInstallation.
const GCCInstallCandidate *InstallWithIncludes = nullptr;
for (const auto &I : Installations) {
if ((!InstallWithIncludes || I.Version > InstallWithIncludes->Version) &&
GCCInstallationHasLibStdcxxIncludePaths(I, Args))
InstallWithIncludes = &I;
}
if (InstallWithIncludes && SelectedInstallation.GCCInstallPath !=
InstallWithIncludes->GCCInstallPath)
D.Diag(diag::warn_drv_gcc_install_dir_libstdcxx)
<< InstallWithIncludes->GCCInstallPath
<< SelectedInstallation.GCCInstallPath;
// TODO Warn if SelectedInstallation does not contain libstdc++ includes
// although compiler flags indicate that it is required (C++ compilation,
// libstdc++ not explicitly disabled).
return true;
}
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
const llvm::Triple &TargetTriple, const ArgList &Args, const llvm::Triple &TargetTriple, const ArgList &Args,
const std::string &LibDir, StringRef CandidateTriple, const std::string &LibDir, StringRef CandidateTriple,
@ -2845,7 +2805,6 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
TargetTriple.getVendor() == llvm::Triple::Freescale || TargetTriple.getVendor() == llvm::Triple::Freescale ||
TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}}; TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}};
SmallVector<GCCInstallCandidate, 3> Installations;
for (auto &Suffix : Suffixes) { for (auto &Suffix : Suffixes) {
if (!Suffix.Active) if (!Suffix.Active)
continue; continue;
@ -2863,31 +2822,23 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
continue; // Saw this path before; no need to look at it again. continue; // Saw this path before; no need to look at it again.
if (CandidateVersion.isOlderThan(4, 1, 1)) if (CandidateVersion.isOlderThan(4, 1, 1))
continue; continue;
if (CandidateVersion <= SelectedInstallation.Version && IsValid) if (CandidateVersion <= Version)
continue; continue;
if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(),
NeedsBiarchSuffix)) NeedsBiarchSuffix))
continue; continue;
GCCInstallCandidate Installation; Version = CandidateVersion;
Installation.Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple);
Installation.GCCTriple.setTriple(CandidateTriple);
// FIXME: We hack together the directory name here instead of // FIXME: We hack together the directory name here instead of
// using LI to ensure stable path separators across Windows and // using LI to ensure stable path separators across Windows and
// Linux. // Linux.
Installation.GCCInstallPath = GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str();
(LibDir + "/" + LibSuffix + "/" + VersionText).str(); GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str();
Installation.GCCParentLibPath = IsValid = true;
(Installation.GCCInstallPath + "/../" + Suffix.ReversePath).str();
Installation.SelectedMultilib = getMultilib();
Installations.push_back(Installation);
} }
} }
IsValid |=
SelectGCCInstallationDirectory(Installations, Args, SelectedInstallation);
} }
bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
@ -2965,12 +2916,10 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
NeedsBiarchSuffix)) NeedsBiarchSuffix))
continue; continue;
SelectedInstallation.Version = Version = GCCVersion::Parse(ActiveVersion.second);
GCCVersion::Parse(ActiveVersion.second); GCCInstallPath = GentooPath;
SelectedInstallation.GCCInstallPath = GentooPath; GCCParentLibPath = GentooPath + std::string("/../../..");
SelectedInstallation.GCCParentLibPath = GCCTriple.setTriple(ActiveVersion.first);
GentooPath + std::string("/../../..");
SelectedInstallation.GCCTriple.setTriple(ActiveVersion.first);
IsValid = true; IsValid = true;
return true; return true;
} }
@ -3173,9 +3122,8 @@ void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs,
// gcc TOOL_INCLUDE_DIR. // gcc TOOL_INCLUDE_DIR.
const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
std::string LibPath(GCCInstallation.getParentLibPath()); std::string LibPath(GCCInstallation.getParentLibPath());
ToolChain::addSystemInclude(DriverArgs, CC1Args, addSystemInclude(DriverArgs, CC1Args,
Twine(LibPath) + "/../" + GCCTriple.str() + Twine(LibPath) + "/../" + GCCTriple.str() + "/include");
"/include");
const auto &Callback = Multilibs.includeDirsCallback(); const auto &Callback = Multilibs.includeDirsCallback();
if (Callback) { if (Callback) {
@ -3262,14 +3210,12 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
return; return;
} }
static bool addLibStdCXXIncludePaths(llvm::vfs::FileSystem &vfs, bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
Twine IncludeDir, StringRef Triple,
Twine IncludeSuffix, Twine IncludeSuffix,
const llvm::opt::ArgList &DriverArgs, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args, llvm::opt::ArgStringList &CC1Args,
bool DetectDebian = false) { bool DetectDebian) const {
if (!getVFS().exists(IncludeDir))
if (!vfs.exists(IncludeDir))
return false; return false;
// Debian native gcc uses g++-multiarch-incdir.diff which uses // Debian native gcc uses g++-multiarch-incdir.diff which uses
@ -3281,48 +3227,39 @@ static bool addLibStdCXXIncludePaths(llvm::vfs::FileSystem &vfs,
std::string Path = std::string Path =
(Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix) (Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix)
.str(); .str();
if (DetectDebian && !vfs.exists(Path)) if (DetectDebian && !getVFS().exists(Path))
return false; return false;
// GPLUSPLUS_INCLUDE_DIR // GPLUSPLUS_INCLUDE_DIR
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir); addSystemInclude(DriverArgs, CC1Args, IncludeDir);
// GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent // GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent
// include directory. // include directory.
if (DetectDebian) if (DetectDebian)
ToolChain::addSystemInclude(DriverArgs, CC1Args, Path); addSystemInclude(DriverArgs, CC1Args, Path);
else if (!Triple.empty()) else if (!Triple.empty())
ToolChain::addSystemInclude(DriverArgs, CC1Args, addSystemInclude(DriverArgs, CC1Args,
IncludeDir + "/" + Triple + IncludeSuffix); IncludeDir + "/" + Triple + IncludeSuffix);
// GPLUSPLUS_BACKWARD_INCLUDE_DIR // GPLUSPLUS_BACKWARD_INCLUDE_DIR
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward"); addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
return true; return true;
} }
bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, bool Generic_GCC::addGCCLibStdCxxIncludePaths(
Twine IncludeSuffix, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
const llvm::opt::ArgList &DriverArgs, StringRef DebianMultiarch) const {
llvm::opt::ArgStringList &CC1Args, assert(GCCInstallation.isValid());
bool DetectDebian) const {
return ::addLibStdCXXIncludePaths(getVFS(), IncludeDir, Triple, IncludeSuffix,
DriverArgs, CC1Args, DetectDebian);
}
bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths(
llvm::vfs::FileSystem &vfs, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args, StringRef DebianMultiarch) const {
// By default, look for the C++ headers in an include directory adjacent to // By default, look for the C++ headers in an include directory adjacent to
// the lib directory of the GCC installation. Note that this is expect to be // the lib directory of the GCC installation. Note that this is expect to be
// equivalent to '/usr/include/c++/X.Y' in almost all cases. // equivalent to '/usr/include/c++/X.Y' in almost all cases.
StringRef LibDir = getParentLibPath(); StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = getInstallPath(); StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef TripleStr = getTriple().str(); StringRef TripleStr = GCCInstallation.getTriple().str();
const Multilib &Multilib = getMultilib(); const Multilib &Multilib = GCCInstallation.getMultilib();
const GCCVersion &Version = getVersion(); const GCCVersion &Version = GCCInstallation.getVersion();
// Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty). // Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty).
if (::addLibStdCXXIncludePaths( if (addLibStdCXXIncludePaths(
vfs,
LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text, LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text,
TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args)) TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args))
return true; return true;
@ -3330,24 +3267,22 @@ bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths(
// Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not // Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not
// empty). Like above but for GCC built with // empty). Like above but for GCC built with
// --enable-version-specific-runtime-libs. // --enable-version-specific-runtime-libs.
if (::addLibStdCXXIncludePaths(vfs, if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" +
LibDir.str() + "/gcc/" + TripleStr + "/" +
Version.Text + "/include/c++/", Version.Text + "/include/c++/",
TripleStr, Multilib.includeSuffix(), TripleStr, Multilib.includeSuffix(), DriverArgs,
DriverArgs, CC1Args)) CC1Args))
return true; return true;
// Detect Debian g++-multiarch-incdir.diff. // Detect Debian g++-multiarch-incdir.diff.
if (::addLibStdCXXIncludePaths( if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
vfs, LibDir.str() + "/../include/c++/" + Version.Text, DebianMultiarch, Multilib.includeSuffix(),
DebianMultiarch, Multilib.includeSuffix(), DriverArgs, CC1Args, DriverArgs, CC1Args, /*Debian=*/true))
/*Debian=*/true))
return true; return true;
// Try /../include/c++/$version (gcc --print-multiarch is empty). // Try /../include/c++/$version (gcc --print-multiarch is empty).
if (::addLibStdCXXIncludePaths( if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
vfs, LibDir.str() + "/../include/c++/" + Version.Text, TripleStr, TripleStr, Multilib.includeSuffix(), DriverArgs,
Multilib.includeSuffix(), DriverArgs, CC1Args)) CC1Args))
return true; return true;
// Otherwise, fall back on a bunch of options which don't use multiarch // Otherwise, fall back on a bunch of options which don't use multiarch
@ -3362,50 +3297,20 @@ bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths(
}; };
for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
if (::addLibStdCXXIncludePaths(vfs, IncludePath, TripleStr, if (addLibStdCXXIncludePaths(IncludePath, TripleStr,
Multilib.includeSuffix(), DriverArgs, Multilib.includeSuffix(), DriverArgs, CC1Args))
CC1Args))
return true; return true;
} }
return false; return false;
} }
bool Generic_GCC::GCCInstallationDetector::
GCCInstallationHasLibStdcxxIncludePaths(
const GCCInstallCandidate &GCCInstallation,
const llvm::opt::ArgList &DriverArgs) const {
StringRef DebianMultiarch =
TripleToDebianMultiarch(GCCInstallation.getTriple());
// The following function checks for libstdc++ include paths and
// adds them to the provided argument list. Here we just need the
// check.
llvm::opt::ArgStringList dummyCC1Args;
return GCCInstallation.addGCCLibStdCxxIncludePaths(
D.getVFS(), DriverArgs, dummyCC1Args, DebianMultiarch);
}
bool Generic_GCC::addGCCLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
assert(GCCInstallation.isValid());
// Detect Debian g++-multiarch-incdir.diff.
StringRef DebianMultiarch =
GCCInstallation.TripleToDebianMultiarch(GCCInstallation.getTriple());
return GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths(
getVFS(), DriverArgs, CC1Args, DebianMultiarch);
}
void void
Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const { llvm::opt::ArgStringList &CC1Args) const {
if (!GCCInstallation.isValid()) if (GCCInstallation.isValid()) {
return; addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
GCCInstallation.getTriple().str());
GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths( }
getVFS(), DriverArgs, CC1Args, GCCInstallation.getTriple().str());
} }
llvm::opt::DerivedArgList * llvm::opt::DerivedArgList *

View File

@ -184,18 +184,46 @@ public:
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
}; };
struct GCCInstallCandidate { /// This is a class to find a viable GCC installation for Clang to
/// use.
///
/// This class tries to find a GCC installation on the system, and report
/// information about it. It starts from the host information provided to the
/// Driver, and has logic for fuzzing that where appropriate.
class GCCInstallationDetector {
bool IsValid;
llvm::Triple GCCTriple;
const Driver &D;
// FIXME: These might be better as path objects. // FIXME: These might be better as path objects.
std::string GCCInstallPath; std::string GCCInstallPath;
std::string GCCParentLibPath; std::string GCCParentLibPath;
llvm::Triple GCCTriple;
/// The primary multilib appropriate for the given flags. /// The primary multilib appropriate for the given flags.
Multilib SelectedMultilib; Multilib SelectedMultilib;
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
std::optional<Multilib> BiarchSibling;
GCCVersion Version; GCCVersion Version;
// We retain the list of install paths that were considered and rejected in
// order to print out detailed information in verbose mode.
std::set<std::string> CandidateGCCInstallPaths;
/// The set of multilibs that the detected installation supports.
MultilibSet Multilibs;
// Gentoo-specific toolchain configurations are stored here.
const std::string GentooConfigDir = "/etc/env.d/gcc";
public:
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
/// Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
/// Get the GCC triple for the detected install. /// Get the GCC triple for the detected install.
const llvm::Triple &getTriple() const { return GCCTriple; } const llvm::Triple &getTriple() const { return GCCTriple; }
@ -208,88 +236,6 @@ public:
/// Get the detected Multilib /// Get the detected Multilib
const Multilib &getMultilib() const { return SelectedMultilib; } const Multilib &getMultilib() const { return SelectedMultilib; }
/// Get the detected GCC version string.
const GCCVersion &getVersion() const { return Version; }
bool addGCCLibStdCxxIncludePaths(llvm::vfs::FileSystem &vfs,
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
StringRef DebianMultiarch) const;
};
/// This is a class to find a viable GCC installation for Clang to
/// use.
///
/// This class tries to find a GCC installation on the system, and report
/// information about it. It starts from the host information provided to the
/// Driver, and has logic for fuzzing that where appropriate.
class GCCInstallationDetector {
bool IsValid;
const Driver &D;
GCCInstallCandidate SelectedInstallation;
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
std::optional<Multilib> BiarchSibling;
// We retain the list of install paths that were considered and rejected in
// order to print out detailed information in verbose mode.
std::set<std::string> CandidateGCCInstallPaths;
/// The set of multilibs that the detected installation supports.
MultilibSet Multilibs;
// Gentoo-specific toolchain configurations are stored here.
const std::string GentooConfigDir = "/etc/env.d/gcc";
public:
/// Function for converting a triple to a Debian multiarch. The
/// toolchains use this to adjust the target specific component of
/// include paths for Debian.
std::function<StringRef(const llvm::Triple &)> TripleToDebianMultiarch =
[](const llvm::Triple &T) {
StringRef S = T.str();
return S;
};
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
// TODO Replace isValid by changing SelectedInstallation into
// std::optional<SelectedInstallation>
// and move all accessors for fields of GCCInstallCandidate into
// that struct.
/// Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
const GCCInstallCandidate &getSelectedInstallation() const {
return SelectedInstallation;
}
/// Get the GCC triple for the detected install.
const llvm::Triple &getTriple() const {
return SelectedInstallation.GCCTriple;
}
/// Get the detected GCC installation path.
StringRef getInstallPath() const {
return SelectedInstallation.GCCInstallPath;
}
/// Get the detected GCC parent lib path.
StringRef getParentLibPath() const {
return SelectedInstallation.GCCParentLibPath;
}
/// Get the detected Multilib
const Multilib &getMultilib() const {
return SelectedInstallation.SelectedMultilib;
}
/// Get the whole MultilibSet /// Get the whole MultilibSet
const MultilibSet &getMultilibs() const { return Multilibs; } const MultilibSet &getMultilibs() const { return Multilibs; }
@ -298,9 +244,7 @@ public:
bool getBiarchSibling(Multilib &M) const; bool getBiarchSibling(Multilib &M) const;
/// Get the detected GCC version string. /// Get the detected GCC version string.
const GCCVersion &getVersion() const { const GCCVersion &getVersion() const { return Version; }
return SelectedInstallation.Version;
}
/// Print information about the detected GCC installation. /// Print information about the detected GCC installation.
void print(raw_ostream &OS) const; void print(raw_ostream &OS) const;
@ -318,19 +262,6 @@ public:
SmallVectorImpl<std::string> &Prefixes, SmallVectorImpl<std::string> &Prefixes,
StringRef SysRoot); StringRef SysRoot);
/// Checks if the \p GCCInstallation has libstdc++ include
/// directories.
bool GCCInstallationHasLibStdcxxIncludePaths(
const GCCInstallCandidate &GCCInstallation,
const llvm::opt::ArgList &DriverArgs) const;
/// Select a GCC installation directory from \p Installations and
/// set \p SelectedInstallation accordingly.
bool SelectGCCInstallationDirectory(
const SmallVector<GCCInstallCandidate, 3> &Installations,
const llvm::opt::ArgList &Args,
GCCInstallCandidate &SelectedInstallation) const;
bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple,
const llvm::opt::ArgList &Args, StringRef Path, const llvm::opt::ArgList &Args, StringRef Path,
bool NeedsBiarchSuffix = false); bool NeedsBiarchSuffix = false);
@ -417,7 +348,8 @@ protected:
llvm::opt::ArgStringList &CC1Args) const; llvm::opt::ArgStringList &CC1Args) const;
bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC) const; llvm::opt::ArgStringList &CC1Args,
StringRef DebianMultiarch) const;
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
Twine IncludeSuffix, Twine IncludeSuffix,

View File

@ -173,72 +173,24 @@ bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
return true; return true;
} }
void getSpirvExtOperand(StringRef SpvExtensionArg, raw_ostream &out) { std::string getSpirvExtArg(ArrayRef<std::string> SpvExtensionArgs) {
// The extensions that are commented out are supported in DXC, but the SPIR-V
// backend does not know about them yet.
static const std::vector<StringRef> DxcSupportedExtensions = {
"SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_fragment_shading_rate", "SPV_KHR_multiview",
"SPV_KHR_post_depth_coverage", "SPV_KHR_non_semantic_info",
"SPV_KHR_shader_draw_parameters", "SPV_KHR_ray_tracing",
"SPV_KHR_shader_clock", "SPV_EXT_demote_to_helper_invocation",
"SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered",
"SPV_EXT_fragment_invocation_density",
"SPV_EXT_fragment_shader_interlock", "SPV_EXT_mesh_shader",
"SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer",
// "SPV_AMD_shader_early_and_late_fragment_tests",
"SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type",
"SPV_KHR_ray_query", "SPV_EXT_shader_image_int64",
"SPV_KHR_fragment_shader_barycentric", "SPV_KHR_physical_storage_buffer",
"SPV_KHR_vulkan_memory_model",
// "SPV_KHR_compute_shader_derivatives",
// "SPV_KHR_maximal_reconvergence",
"SPV_KHR_float_controls", "SPV_NV_shader_subgroup_partitioned",
// "SPV_KHR_quad_control"
};
if (SpvExtensionArg.starts_with("SPV_")) {
out << "+" << SpvExtensionArg;
return;
}
if (SpvExtensionArg.compare_insensitive("DXC") == 0) {
bool first = true;
std::string Operand;
for (StringRef E : DxcSupportedExtensions) {
if (!first)
out << ",";
else
first = false;
out << "+" << E;
}
return;
}
out << SpvExtensionArg;
return;
}
SmallString<1024> getSpirvExtArg(ArrayRef<std::string> SpvExtensionArgs) {
if (SpvExtensionArgs.empty()) { if (SpvExtensionArgs.empty()) {
return StringRef("-spirv-ext=all"); return "-spirv-ext=all";
} }
llvm::SmallString<1024> LlvmOption; std::string LlvmOption =
raw_svector_ostream out(LlvmOption); (Twine("-spirv-ext=+") + SpvExtensionArgs.front()).str();
out << "-spirv-ext=";
getSpirvExtOperand(SpvExtensionArgs[0], out);
SpvExtensionArgs = SpvExtensionArgs.slice(1); SpvExtensionArgs = SpvExtensionArgs.slice(1);
for (StringRef Extension : SpvExtensionArgs) { for (auto Extension : SpvExtensionArgs) {
out << ","; if (Extension != "KHR")
getSpirvExtOperand(Extension, out); Extension = (Twine("+") + Extension).str();
LlvmOption = (Twine(LlvmOption) + "," + Extension).str();
} }
return LlvmOption; return LlvmOption;
} }
bool isValidSPIRVExtensionName(const std::string &str) { bool isValidSPIRVExtensionName(const std::string &str) {
std::regex pattern("dxc|DXC|khr|KHR|SPV_[a-zA-Z0-9_]+"); std::regex pattern("KHR|SPV_[a-zA-Z0-9_]+");
return std::regex_match(str, pattern); return std::regex_match(str, pattern);
} }
@ -419,7 +371,7 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
std::vector<std::string> SpvExtensionArgs = std::vector<std::string> SpvExtensionArgs =
Args.getAllArgValues(options::OPT_fspv_extension_EQ); Args.getAllArgValues(options::OPT_fspv_extension_EQ);
if (checkExtensionArgsAreValid(SpvExtensionArgs, getDriver())) { if (checkExtensionArgsAreValid(SpvExtensionArgs, getDriver())) {
SmallString<1024> LlvmOption = getSpirvExtArg(SpvExtensionArgs); std::string LlvmOption = getSpirvExtArg(SpvExtensionArgs);
DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_mllvm), DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_mllvm),
LlvmOption); LlvmOption);
} }

View File

@ -71,13 +71,6 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) { : Generic_ELF(D, Triple, Args) {
GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) {
StringRef TripleStr = T.str();
StringRef DebianMultiarch =
T.getArch() == llvm::Triple::x86 ? "i386-gnu" : TripleStr;
return DebianMultiarch;
};
GCCInstallation.init(Triple, Args); GCCInstallation.init(Triple, Args);
Multilibs = GCCInstallation.getMultilibs(); Multilibs = GCCInstallation.getMultilibs();
SelectedMultilibs.assign({GCCInstallation.getMultilib()}); SelectedMultilibs.assign({GCCInstallation.getMultilib()});
@ -214,7 +207,12 @@ void Hurd::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
if (!GCCInstallation.isValid()) if (!GCCInstallation.isValid())
return; return;
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); StringRef TripleStr = GCCInstallation.getTriple().str();
StringRef DebianMultiarch =
GCCInstallation.getTriple().getArch() == llvm::Triple::x86 ? "i386-gnu"
: TripleStr;
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, DebianMultiarch);
} }
void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {

View File

@ -211,13 +211,6 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) { : Generic_ELF(D, Triple, Args) {
GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) {
StringRef TripleStr = T.str();
StringRef DebianMultiarch =
T.getArch() == llvm::Triple::x86 ? "i386-linux-gnu" : TripleStr;
return DebianMultiarch;
};
GCCInstallation.init(Triple, Args); GCCInstallation.init(Triple, Args);
Multilibs = GCCInstallation.getMultilibs(); Multilibs = GCCInstallation.getMultilibs();
SelectedMultilibs.assign({GCCInstallation.getMultilib()}); SelectedMultilibs.assign({GCCInstallation.getMultilib()});
@ -700,15 +693,22 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
if (!GCCInstallation.isValid()) if (!GCCInstallation.isValid())
return; return;
// Detect Debian g++-multiarch-incdir.diff.
StringRef TripleStr = GCCInstallation.getTriple().str();
StringRef DebianMultiarch =
GCCInstallation.getTriple().getArch() == llvm::Triple::x86
? "i386-linux-gnu"
: TripleStr;
// Try generic GCC detection first. // Try generic GCC detection first.
if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args)) if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
DebianMultiarch))
return; return;
StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef LibDir = GCCInstallation.getParentLibPath();
const Multilib &Multilib = GCCInstallation.getMultilib(); const Multilib &Multilib = GCCInstallation.getMultilib();
const GCCVersion &Version = GCCInstallation.getVersion(); const GCCVersion &Version = GCCInstallation.getVersion();
StringRef TripleStr = GCCInstallation.getTriple().str();
const std::string LibStdCXXIncludePathCandidates[] = { const std::string LibStdCXXIncludePathCandidates[] = {
// Android standalone toolchain has C++ headers in yet another place. // Android standalone toolchain has C++ headers in yet another place.
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,

View File

@ -193,8 +193,10 @@ void Managarm::addLibStdCxxIncludePaths(
if (!GCCInstallation.isValid()) if (!GCCInstallation.isValid())
return; return;
StringRef TripleStr = GCCInstallation.getTriple().str();
// Try generic GCC detection. // Try generic GCC detection.
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, TripleStr);
} }
SanitizerMask Managarm::getSupportedSanitizers() const { SanitizerMask Managarm::getSupportedSanitizers() const {

View File

@ -3721,7 +3721,7 @@ _mm_maskstore_epi64(long long *__X, __m128i __M, __m128i __Y)
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in /// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 256-bit vector of [8 x i32] containing the result. /// \returns A 256-bit vector of [8 x i32] containing the result.
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_sllv_epi32(__m256i __X, __m256i __Y) _mm256_sllv_epi32(__m256i __X, __m256i __Y)
{ {
return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y); return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y);
@ -3743,7 +3743,7 @@ _mm256_sllv_epi32(__m256i __X, __m256i __Y)
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in /// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 128-bit vector of [4 x i32] containing the result. /// \returns A 128-bit vector of [4 x i32] containing the result.
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_sllv_epi32(__m128i __X, __m128i __Y) _mm_sllv_epi32(__m128i __X, __m128i __Y)
{ {
return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y); return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y);
@ -3765,7 +3765,7 @@ _mm_sllv_epi32(__m128i __X, __m128i __Y)
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in /// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 256-bit vector of [4 x i64] containing the result. /// \returns A 256-bit vector of [4 x i64] containing the result.
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_sllv_epi64(__m256i __X, __m256i __Y) _mm256_sllv_epi64(__m256i __X, __m256i __Y)
{ {
return (__m256i)__builtin_ia32_psllv4di((__v4di)__X, (__v4di)__Y); return (__m256i)__builtin_ia32_psllv4di((__v4di)__X, (__v4di)__Y);
@ -3787,7 +3787,7 @@ _mm256_sllv_epi64(__m256i __X, __m256i __Y)
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in /// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 128-bit vector of [2 x i64] containing the result. /// \returns A 128-bit vector of [2 x i64] containing the result.
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_sllv_epi64(__m128i __X, __m128i __Y) _mm_sllv_epi64(__m128i __X, __m128i __Y)
{ {
return (__m128i)__builtin_ia32_psllv2di((__v2di)__X, (__v2di)__Y); return (__m128i)__builtin_ia32_psllv2di((__v2di)__X, (__v2di)__Y);
@ -3810,7 +3810,7 @@ _mm_sllv_epi64(__m128i __X, __m128i __Y)
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in /// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 256-bit vector of [8 x i32] containing the result. /// \returns A 256-bit vector of [8 x i32] containing the result.
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_srav_epi32(__m256i __X, __m256i __Y) _mm256_srav_epi32(__m256i __X, __m256i __Y)
{ {
return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y); return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y);
@ -3833,7 +3833,7 @@ _mm256_srav_epi32(__m256i __X, __m256i __Y)
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in /// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 128-bit vector of [4 x i32] containing the result. /// \returns A 128-bit vector of [4 x i32] containing the result.
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_srav_epi32(__m128i __X, __m128i __Y) _mm_srav_epi32(__m128i __X, __m128i __Y)
{ {
return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y); return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y);
@ -3855,7 +3855,7 @@ _mm_srav_epi32(__m128i __X, __m128i __Y)
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in /// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 256-bit vector of [8 x i32] containing the result. /// \returns A 256-bit vector of [8 x i32] containing the result.
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_srlv_epi32(__m256i __X, __m256i __Y) _mm256_srlv_epi32(__m256i __X, __m256i __Y)
{ {
return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y); return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y);
@ -3877,7 +3877,7 @@ _mm256_srlv_epi32(__m256i __X, __m256i __Y)
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in /// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 128-bit vector of [4 x i32] containing the result. /// \returns A 128-bit vector of [4 x i32] containing the result.
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_srlv_epi32(__m128i __X, __m128i __Y) _mm_srlv_epi32(__m128i __X, __m128i __Y)
{ {
return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y); return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y);
@ -3899,7 +3899,7 @@ _mm_srlv_epi32(__m128i __X, __m128i __Y)
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in /// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 256-bit vector of [4 x i64] containing the result. /// \returns A 256-bit vector of [4 x i64] containing the result.
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_srlv_epi64(__m256i __X, __m256i __Y) _mm256_srlv_epi64(__m256i __X, __m256i __Y)
{ {
return (__m256i)__builtin_ia32_psrlv4di((__v4di)__X, (__v4di)__Y); return (__m256i)__builtin_ia32_psrlv4di((__v4di)__X, (__v4di)__Y);
@ -3921,7 +3921,7 @@ _mm256_srlv_epi64(__m256i __X, __m256i __Y)
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in /// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
/// bits). /// bits).
/// \returns A 128-bit vector of [2 x i64] containing the result. /// \returns A 128-bit vector of [2 x i64] containing the result.
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_srlv_epi64(__m128i __X, __m128i __Y) _mm_srlv_epi64(__m128i __X, __m128i __Y)
{ {
return (__m128i)__builtin_ia32_psrlv2di((__v2di)__X, (__v2di)__Y); return (__m128i)__builtin_ia32_psrlv2di((__v2di)__X, (__v2di)__Y);

View File

@ -5601,10 +5601,8 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getArg(1)->getEndLoc())); TheCall->getArg(1)->getEndLoc()));
} else if (numElements != numResElements) { } else if (numElements != numResElements) {
QualType eltType = LHSType->castAs<VectorType>()->getElementType(); QualType eltType = LHSType->castAs<VectorType>()->getElementType();
resType = resType->isExtVectorType() resType =
? Context.getExtVectorType(eltType, numResElements) Context.getVectorType(eltType, numResElements, VectorKind::Generic);
: Context.getVectorType(eltType, numResElements,
VectorKind::Generic);
} }
} }

View File

@ -800,23 +800,3 @@ namespace ZeroSizeArrayRead {
static_assert(s[0] == '0', ""); // both-error {{not an integral constant expression}} \ static_assert(s[0] == '0', ""); // both-error {{not an integral constant expression}} \
// both-note {{read of dereferenced one-past-the-end pointer}} // both-note {{read of dereferenced one-past-the-end pointer}}
} }
namespace FAM {
char *strchr(const char *, int);
struct A {
char n, a[2];
};
struct B {
int n;
struct A a[]; // both-note {{here}}
};
const struct B b = {0, {{1, {2, 3}}, {4, {5, 6}}}};
void foo(void) { int sch = 0 != strchr(b.a[1].a, '\0'); }
int foo2() {
struct B b = {0, {{1, {2, 3}}, {4, {5, 6}}}}; // both-error {{initialization of flexible array member is not allowed}}
return 1;
}
}

View File

@ -338,12 +338,3 @@ static void *FooTable[1] = {
} }
}; };
int strcmp(const char *, const char *); // all-note {{passing argument to parameter here}}
#define S "\x01\x02\x03\x04\x05\x06\x07\x08"
const char _str[] = {S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7]};
const unsigned char _str2[] = {S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7]};
const int compared = strcmp(_str, (const char *)_str2); // all-error {{initializer element is not a compile-time constant}}
const int compared2 = strcmp(strcmp, _str); // all-warning {{incompatible pointer types}} \
// all-error {{initializer element is not a compile-time constant}}

View File

@ -15,6 +15,7 @@ using FourFloatsExtVec __attribute__((ext_vector_type(4))) = float;
using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double; using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double;
using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128; using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128;
// Next a series of tests to make sure these operations are usable in // Next a series of tests to make sure these operations are usable in
// constexpr functions. Template instantiations don't emit Winvalid-constexpr, // constexpr functions. Template instantiations don't emit Winvalid-constexpr,
// so we have to do these as macros. // so we have to do these as macros.
@ -874,9 +875,3 @@ void BoolVecUsage() {
constexpr auto k = ~FourBoolsExtVec{true, false, true, false}; constexpr auto k = ~FourBoolsExtVec{true, false, true, false};
static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, ""); static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, "");
} }
using EightBoolsExtVec __attribute__((ext_vector_type(8))) = bool;
void BoolVecShuffle() {
constexpr EightBoolsExtVec a = __builtin_shufflevector(
FourBoolsExtVec{}, FourBoolsExtVec{}, 0, 1, 2, 3, 4, 5, 6, 7);
}

View File

@ -732,8 +732,3 @@ namespace LocalVarForParmVarDecl {
} }
static_assert(foo(), ""); static_assert(foo(), "");
} }
namespace PtrPtrCast {
void foo() { ; }
void bar(int *a) { a = (int *)(void *)(foo); }
}

View File

@ -104,15 +104,3 @@ namespace CallScope {
// expected-note {{member call on variable whose lifetime has ended}} \ // expected-note {{member call on variable whose lifetime has ended}} \
// ref-note {{member call on object outside its lifetime}} // ref-note {{member call on object outside its lifetime}}
} }
namespace ExprDoubleDestroy {
template <typename T>
constexpr bool test() {
T{}.~T(); // both-note {{lifetime has already ended}}
return true;
}
struct S { int x; };
constexpr bool t = test<S>(); // both-error {{must be initialized by a constant expression}} \
// both-note {{in call to}}
}

View File

@ -13,12 +13,7 @@ struct __type_info_implementations {
typedef __unique_impl __impl; typedef __unique_impl __impl;
}; };
class __pointer_type_info { class type_info {
public:
int __flags = 0;
};
class type_info : public __pointer_type_info {
protected: protected:
typedef __type_info_implementations::__impl __impl; typedef __type_info_implementations::__impl __impl;
__impl::__type_name_t __type_name; __impl::__type_name_t __type_name;
@ -45,10 +40,3 @@ constexpr bool test() {
return true; return true;
} }
static_assert(test()); static_assert(test());
int dontcrash() {
auto& pti = static_cast<const std::__pointer_type_info&>(
typeid(int)
);
return pti.__flags == 0 ? 1 : 0;
}

View File

@ -1,47 +0,0 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
void f(void);
void f1() {
(void (*)())f;
}
void f2() {
(*(void (*)(void))f)();
}
void test_lvalue_cast() {
(*(void (*)(int))f)(42);
}
// CIR-LABEL: cir.func{{.*}} @f()
// CIR: cir.func{{.*}} @f1()
// CIR: cir.return{{.*}}
// CIR-LABEL: cir.func{{.*}} @f2()
// CIR: cir.call @f() : () -> ()
// CIR-LABEL: cir.func{{.*}} @test_lvalue_cast()
// CIR: %[[S0:.+]] = {{.*}}@f : !cir.ptr<!cir.func<()>>{{.*}}
// CIR: %[[S1:.+]] = cir.cast{{.*}}%[[S0]] : !cir.ptr<!cir.func<()>>{{.*}}
// CIR: %[[S2:.+]] = cir.const #cir.int<42> : !s32i
// CIR: cir.call %[[S1]](%[[S2]]) : (!cir.ptr<!cir.func<(!s32i)>>, !s32i) -> ()
// LLVM-LABEL: define{{.*}} void @f1()
// LLVM: ret void
// LLVM: define{{.*}} void @f2()
// LLVM: call void @f()
// LLVM: define{{.*}} void @test_lvalue_cast()
// LLVM: call void @f(i32 42)
// OGCG-LABEL: define{{.*}} void @f1()
// OGCG: ret void
// OGCG: define{{.*}} void @f2()
// OGCG: call void @f()
// OGCG: define{{.*}} void @test_lvalue_cast()
// OGCG: call void @f(i32 noundef 42)

View File

@ -1,7 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
@ -29,24 +27,6 @@ err:
// CIR: cir.store [[MINUS]], [[RETVAL]] : !s32i, !cir.ptr<!s32i> // CIR: cir.store [[MINUS]], [[RETVAL]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.br ^bb1 // CIR: cir.br ^bb1
// LLVM: define dso_local i32 @_Z21shouldNotGenBranchReti
// LLVM: [[COND:%.*]] = load i32, ptr {{.*}}, align 4
// LLVM: [[CMP:%.*]] = icmp sgt i32 [[COND]], 5
// LLVM: br i1 [[CMP]], label %[[IFTHEN:.*]], label %[[IFEND:.*]]
// LLVM: [[IFTHEN]]:
// LLVM: br label %[[ERR:.*]]
// LLVM: [[IFEND]]:
// LLVM: br label %[[BB9:.*]]
// LLVM: [[BB9]]:
// LLVM: store i32 0, ptr %[[RETVAL:.*]], align 4
// LLVM: br label %[[BBRET:.*]]
// LLVM: [[BBRET]]:
// LLVM: [[RET:%.*]] = load i32, ptr %[[RETVAL]], align 4
// LLVM: ret i32 [[RET]]
// LLVM: [[ERR]]:
// LLVM: store i32 -1, ptr %[[RETVAL]], align 4
// LLVM: br label %10
// OGCG: define dso_local noundef i32 @_Z21shouldNotGenBranchReti // OGCG: define dso_local noundef i32 @_Z21shouldNotGenBranchReti
// OGCG: if.then: // OGCG: if.then:
// OGCG: br label %err // OGCG: br label %err
@ -71,17 +51,6 @@ err:
// CIR: ^bb1: // CIR: ^bb1:
// CIR: cir.label "err" // CIR: cir.label "err"
// LLVM: define dso_local i32 @_Z15shouldGenBranchi
// LLVM: br i1 [[CMP:%.*]], label %[[IFTHEN:.*]], label %[[IFEND:.*]]
// LLVM: [[IFTHEN]]:
// LLVM: br label %[[ERR:.*]]
// LLVM: [[IFEND]]:
// LLVM: br label %[[BB9:.*]]
// LLVM: [[BB9]]:
// LLVM: br label %[[ERR]]
// LLVM: [[ERR]]:
// LLVM: ret i32 [[RET:%.*]]
// OGCG: define dso_local noundef i32 @_Z15shouldGenBranchi // OGCG: define dso_local noundef i32 @_Z15shouldGenBranchi
// OGCG: if.then: // OGCG: if.then:
// OGCG: br label %err // OGCG: br label %err
@ -109,15 +78,6 @@ end2:
// CIR: ^bb[[#BLK3]]: // CIR: ^bb[[#BLK3]]:
// CIR: cir.label "end2" // CIR: cir.label "end2"
// LLVM: define dso_local void @_Z19severalLabelsInARowi
// LLVM: br label %[[END1:.*]]
// LLVM: [[UNRE:.*]]: ; No predecessors!
// LLVM: br label %[[END2:.*]]
// LLVM: [[END1]]:
// LLVM: br label %[[END2]]
// LLVM: [[END2]]:
// LLVM: ret
// OGCG: define dso_local void @_Z19severalLabelsInARowi // OGCG: define dso_local void @_Z19severalLabelsInARowi
// OGCG: br label %end1 // OGCG: br label %end1
// OGCG: end1: // OGCG: end1:
@ -139,13 +99,6 @@ end:
// CIR: ^bb[[#BLK2:]]: // CIR: ^bb[[#BLK2:]]:
// CIR: cir.label "end" // CIR: cir.label "end"
// LLVM: define dso_local void @_Z18severalGotosInARowi
// LLVM: br label %[[END:.*]]
// LLVM: [[UNRE:.*]]: ; No predecessors!
// LLVM: br label %[[END]]
// LLVM: [[END]]:
// LLVM: ret void
// OGCG: define dso_local void @_Z18severalGotosInARowi(i32 noundef %a) #0 { // OGCG: define dso_local void @_Z18severalGotosInARowi(i32 noundef %a) #0 {
// OGCG: br label %end // OGCG: br label %end
// OGCG: end: // OGCG: end:
@ -173,14 +126,6 @@ extern "C" void multiple_non_case(int v) {
// CIR: cir.call @action2() // CIR: cir.call @action2()
// CIR: cir.break // CIR: cir.break
// LLVM: define dso_local void @multiple_non_case
// LLVM: [[SWDEFAULT:.*]]:
// LLVM: call void @action1()
// LLVM: br label %[[L2:.*]]
// LLVM: [[L2]]:
// LLVM: call void @action2()
// LLVM: br label %[[BREAK:.*]]
// OGCG: define dso_local void @multiple_non_case // OGCG: define dso_local void @multiple_non_case
// OGCG: sw.default: // OGCG: sw.default:
// OGCG: call void @action1() // OGCG: call void @action1()
@ -213,26 +158,6 @@ extern "C" void case_follow_label(int v) {
// CIR: cir.call @action2() // CIR: cir.call @action2()
// CIR: cir.goto "label" // CIR: cir.goto "label"
// LLVM: define dso_local void @case_follow_label
// LLVM: switch i32 {{.*}}, label %[[SWDEFAULT:.*]] [
// LLVM: i32 1, label %[[LABEL:.*]]
// LLVM: i32 2, label %[[CASE2:.*]]
// LLVM: ]
// LLVM: [[LABEL]]:
// LLVM: br label %[[CASE2]]
// LLVM: [[CASE2]]:
// LLVM: call void @action1()
// LLVM: br label %[[BREAK:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[END:.*]]
// LLVM: [[SWDEFAULT]]:
// LLVM: call void @action2()
// LLVM: br label %[[LABEL]]
// LLVM: [[END]]:
// LLVM: br label %[[RET:.*]]
// LLVM: [[RET]]:
// LLVM: ret void
// OGCG: define dso_local void @case_follow_label // OGCG: define dso_local void @case_follow_label
// OGCG: sw.bb: // OGCG: sw.bb:
// OGCG: br label %label // OGCG: br label %label
@ -272,26 +197,6 @@ extern "C" void default_follow_label(int v) {
// CIR: cir.call @action2() // CIR: cir.call @action2()
// CIR: cir.goto "label" // CIR: cir.goto "label"
// LLVM: define dso_local void @default_follow_label
// LLVM: [[CASE1:.*]]:
// LLVM: br label %[[BB8:.*]]
// LLVM: [[BB8]]:
// LLVM: br label %[[CASE2:.*]]
// LLVM: [[CASE2]]:
// LLVM: call void @action1()
// LLVM: br label %[[BREAK:.*]]
// LLVM: [[LABEL:.*]]:
// LLVM: br label %[[SWDEFAULT:.*]]
// LLVM: [[SWDEFAULT]]:
// LLVM: call void @action2()
// LLVM: br label %[[BB9:.*]]
// LLVM: [[BB9]]:
// LLVM: br label %[[LABEL]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[RET:.*]]
// LLVM: [[RET]]:
// LLVM: ret void
// OGCG: define dso_local void @default_follow_label // OGCG: define dso_local void @default_follow_label
// OGCG: sw.bb: // OGCG: sw.bb:
// OGCG: call void @action1() // OGCG: call void @action1()

View File

@ -1,7 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR // RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
@ -14,8 +12,8 @@ labelA:
// CIR: cir.label "labelA" // CIR: cir.label "labelA"
// CIR: cir.return // CIR: cir.return
// LLVM:define dso_local void @label // Note: We are not lowering to LLVM IR via CIR at this stage because that
// LLVM: ret void // process depends on the GotoSolver.
// OGCG: define dso_local void @label // OGCG: define dso_local void @label
// OGCG: br label %labelA // OGCG: br label %labelA
@ -35,11 +33,6 @@ labelC:
// CIR: cir.label "labelC" // CIR: cir.label "labelC"
// CIR: cir.return // CIR: cir.return
// LLVM: define dso_local void @multiple_labels()
// LLVM: br label %1
// LLVM: 1:
// LLVM: ret void
// OGCG: define dso_local void @multiple_labels // OGCG: define dso_local void @multiple_labels
// OGCG: br label %labelB // OGCG: br label %labelB
// OGCG: labelB: // OGCG: labelB:
@ -63,22 +56,6 @@ labelD:
// CIR: } // CIR: }
// CIR: cir.return // CIR: cir.return
// LLVM: define dso_local void @label_in_if
// LLVM: br label %3
// LLVM: 3:
// LLVM: [[LOAD:%.*]] = load i32, ptr [[COND:%.*]], align 4
// LLVM: [[CMP:%.*]] = icmp ne i32 [[LOAD]], 0
// LLVM: br i1 [[CMP]], label %6, label %9
// LLVM: 6:
// LLVM: [[LOAD2:%.*]] = load i32, ptr [[COND]], align 4
// LLVM: [[ADD1:%.*]] = add nsw i32 [[LOAD2]], 1
// LLVM: store i32 [[ADD1]], ptr [[COND]], align 4
// LLVM: br label %9
// LLVM: 9:
// LLVM: br label %10
// LLVM: 10:
// LLVM: ret void
// OGCG: define dso_local void @label_in_if // OGCG: define dso_local void @label_in_if
// OGCG: if.then: // OGCG: if.then:
// OGCG: br label %labelD // OGCG: br label %labelD
@ -103,13 +80,6 @@ void after_return() {
// CIR: cir.label "label" // CIR: cir.label "label"
// CIR: cir.br ^bb1 // CIR: cir.br ^bb1
// LLVM: define dso_local void @after_return
// LLVM: br label %1
// LLVM: 1:
// LLVM: ret void
// LLVM: 2:
// LLVM: br label %1
// OGCG: define dso_local void @after_return // OGCG: define dso_local void @after_return
// OGCG: br label %label // OGCG: br label %label
// OGCG: label: // OGCG: label:
@ -127,11 +97,6 @@ void after_unreachable() {
// CIR: cir.label "label" // CIR: cir.label "label"
// CIR: cir.return // CIR: cir.return
// LLVM: define dso_local void @after_unreachable
// LLVM: unreachable
// LLVM: 1:
// LLVM: ret void
// OGCG: define dso_local void @after_unreachable // OGCG: define dso_local void @after_unreachable
// OGCG: unreachable // OGCG: unreachable
// OGCG: label: // OGCG: label:
@ -146,9 +111,6 @@ end:
// CIR: cir.return // CIR: cir.return
// CIR: } // CIR: }
// LLVM: define dso_local void @labelWithoutMatch
// LLVM: ret void
// OGCG: define dso_local void @labelWithoutMatch // OGCG: define dso_local void @labelWithoutMatch
// OGCG: br label %end // OGCG: br label %end
// OGCG: end: // OGCG: end:
@ -170,15 +132,6 @@ void foo() {
// CIR: cir.label "label" // CIR: cir.label "label"
// CIR: %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["agg.tmp0"] // CIR: %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["agg.tmp0"]
// LLVM:define dso_local void @foo() {
// LLVM: [[ALLOC:%.*]] = alloca %struct.S, i64 1, align 1
// LLVM: br label %2
// LLVM:2:
// LLVM: [[CALL:%.*]] = call %struct.S @get()
// LLVM: store %struct.S [[CALL]], ptr [[ALLOC]], align 1
// LLVM: [[LOAD:%.*]] = load %struct.S, ptr [[ALLOC]], align 1
// LLVM: call void @bar(%struct.S [[LOAD]])
// OGCG: define dso_local void @foo() // OGCG: define dso_local void @foo()
// OGCG: %agg.tmp = alloca %struct.S, align 1 // OGCG: %agg.tmp = alloca %struct.S, align 1
// OGCG: %undef.agg.tmp = alloca %struct.S, align 1 // OGCG: %undef.agg.tmp = alloca %struct.S, align 1

View File

@ -1,11 +0,0 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cpp.cir
// RUN: FileCheck --check-prefix=CIR-CPP --input-file=%t.cpp.cir %s
// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.c.cir
// RUN: FileCheck --check-prefix=CIR-C --input-file=%t.c.cir %s
// CIR-CPP: module attributes {{{.*}}cir.lang = #cir.lang<cxx>{{.*}}}
// CIR-C: module attributes {{{.*}}cir.lang = #cir.lang<c>{{.*}}}
int main() {
return 0;
}

View File

@ -1,5 +0,0 @@
// RUN: cir-opt %s -verify-diagnostics
// expected-error@below {{expected ::cir::SourceLanguage to be one of}}
// expected-error@below {{failed to parse CIR_SourceLanguageAttr parameter 'value'}}
module attributes {cir.lang = #cir.lang<dummy>} { }

View File

@ -1,4 +1,4 @@
// RUN: cir-opt %s -verify-diagnostics -split-input-file // RUN: cir-opt %s -verify-diagnostics
!s8i = !cir.int<s, 8> !s8i = !cir.int<s, 8>
!u32i = !cir.int<u, 32> !u32i = !cir.int<u, 32>
@ -7,67 +7,3 @@ cir.func @reference_unknown_vtable() {
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr %0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
cir.return cir.return
} }
// -----
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
module {
// expected-error @below {{expected !cir.record type result}}
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !cir.ptr<!rec_anon_struct>
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
}
// -----
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {}>
module {
// expected-error @below {{expected record type with one or more subtype}}
cir.global external @_ZTV1S = #cir.vtable<{}> : !rec_anon_struct {alignment = 8 : i64}
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
}
// -----
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>}>
module {
// expected-error @below {{expected constant array subtype}}
cir.global external @_ZTV1S = #cir.vtable<{#cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
}
// -----
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!u64i = !cir.int<u, 64>
!rec_anon_struct = !cir.record<struct {!cir.array<!u64i x 4>}>
module {
// expected-error @below {{expected GlobalViewAttr or ConstPtrAttr}}
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.int<1> : !u64i, #cir.int<1> : !u64i, #cir.int<3> : !u64i, #cir.int<4> : !u64i]> : !cir.array<!u64i x 4>}> : !rec_anon_struct {alignment = 8 : i64}
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
}
// -----
!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.ptr<!u8i>}>
module {
// expected-error @below {{expected constant array subtype}}
cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
}

View File

@ -1,12 +0,0 @@
// RUN: cir-opt %s -split-input-file -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s
// Should parse and print C source language attribute.
module attributes {cir.lang = #cir.lang<c>} { }
// CHECK: module attributes {cir.lang = #cir.lang<c>}
// -----
// Should parse and print C++ source language attribute.
module attributes {cir.lang = #cir.lang<cxx>} { }
// CHECK: module attributes {cir.lang = #cir.lang<cxx>}

View File

@ -1,19 +0,0 @@
// RUN: cir-opt %s | FileCheck %s
!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
!rec_S = !cir.record<struct "S" {!cir.vptr}>
!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
!rec_anon_struct1 = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 3>}>
module {
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
// CHECK: cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
// CHECK: cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
}

View File

@ -1,52 +0,0 @@
// RUN: cir-opt %s --pass-pipeline='builtin.module(cir-to-llvm,canonicalize{region-simplify=disabled})' -o - | FileCheck %s -check-prefix=MLIR
!s32i = !cir.int<s, 32>
module {
cir.func @gotoFromIf(%arg0: !s32i) -> !s32i {
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
%1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
cir.scope {
%6 = cir.load %0 : !cir.ptr<!s32i>, !s32i
%7 = cir.const #cir.int<5> : !s32i
%8 = cir.cmp(gt, %6, %7) : !s32i, !cir.bool
cir.if %8 {
cir.goto "err"
}
}
%2 = cir.const #cir.int<0> : !s32i
cir.store %2, %1 : !s32i, !cir.ptr<!s32i>
cir.br ^bb1
^bb1:
%3 = cir.load %1 : !cir.ptr<!s32i>, !s32i
cir.return %3 : !s32i
^bb2:
cir.label "err"
%4 = cir.const #cir.int<1> : !s32i
%5 = cir.unary(minus, %4) : !s32i, !s32i
cir.store %5, %1 : !s32i, !cir.ptr<!s32i>
cir.br ^bb1
}
// MLIR: llvm.func @gotoFromIf
// MLIR: %[[#One:]] = llvm.mlir.constant(1 : i32) : i32
// MLIR: %[[#Zero:]] = llvm.mlir.constant(0 : i32) : i32
// MLIR: llvm.cond_br {{.*}}, ^bb[[#COND_YES:]], ^bb[[#COND_NO:]]
// MLIR: ^bb[[#COND_YES]]:
// MLIR: llvm.br ^bb[[#GOTO_BLK:]]
// MLIR: ^bb[[#COND_NO]]:
// MLIR: llvm.br ^bb[[#BLK:]]
// MLIR: ^bb[[#BLK]]:
// MLIR: llvm.store %[[#Zero]], %[[#Ret_val_addr:]] {{.*}}: i32, !llvm.ptr
// MLIR: llvm.br ^bb[[#RETURN:]]
// MLIR: ^bb[[#RETURN]]:
// MLIR: %[[#Ret_val:]] = llvm.load %[[#Ret_val_addr]] {alignment = 4 : i64} : !llvm.ptr -> i32
// MLIR: llvm.return %[[#Ret_val]] : i32
// MLIR: ^bb[[#GOTO_BLK]]:
// MLIR: %[[#Neg_one:]] = llvm.sub %[[#Zero]], %[[#One]] : i32
// MLIR: llvm.store %[[#Neg_one]], %[[#Ret_val_addr]] {{.*}}: i32, !llvm.ptr
// MLIR: llvm.br ^bb[[#RETURN]]
// MLIR: }
}

View File

@ -327,6 +327,7 @@ __m256i test_mm256_cvtepi8_epi16(__m128i a) {
// CHECK: sext <16 x i8> %{{.*}} to <16 x i16> // CHECK: sext <16 x i8> %{{.*}} to <16 x i16>
return _mm256_cvtepi8_epi16(a); return _mm256_cvtepi8_epi16(a);
} }
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepi8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)); TEST_CONSTEXPR(match_v16hi(_mm256_cvtepi8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12));
__m256i test_mm256_cvtepi8_epi32(__m128i a) { __m256i test_mm256_cvtepi8_epi32(__m128i a) {
@ -335,6 +336,7 @@ __m256i test_mm256_cvtepi8_epi32(__m128i a) {
// CHECK: sext <8 x i8> %{{.*}} to <8 x i32> // CHECK: sext <8 x i8> %{{.*}} to <8 x i32>
return _mm256_cvtepi8_epi32(a); return _mm256_cvtepi8_epi32(a);
} }
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4)); TEST_CONSTEXPR(match_v8si(_mm256_cvtepi8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4));
__m256i test_mm256_cvtepi8_epi64(__m128i a) { __m256i test_mm256_cvtepi8_epi64(__m128i a) {
@ -343,6 +345,7 @@ __m256i test_mm256_cvtepi8_epi64(__m128i a) {
// CHECK: sext <4 x i8> %{{.*}} to <4 x i64> // CHECK: sext <4 x i8> %{{.*}} to <4 x i64>
return _mm256_cvtepi8_epi64(a); return _mm256_cvtepi8_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepi8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0));
__m256i test_mm256_cvtepi16_epi32(__m128i a) { __m256i test_mm256_cvtepi16_epi32(__m128i a) {
@ -350,6 +353,7 @@ __m256i test_mm256_cvtepi16_epi32(__m128i a) {
// CHECK: sext <8 x i16> %{{.*}} to <8 x i32> // CHECK: sext <8 x i16> %{{.*}} to <8 x i32>
return _mm256_cvtepi16_epi32(a); return _mm256_cvtepi16_epi32(a);
} }
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0, 1, -2, 3, -4)); TEST_CONSTEXPR(match_v8si(_mm256_cvtepi16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0, 1, -2, 3, -4));
__m256i test_mm256_cvtepi16_epi64(__m128i a) { __m256i test_mm256_cvtepi16_epi64(__m128i a) {
@ -358,6 +362,7 @@ __m256i test_mm256_cvtepi16_epi64(__m128i a) {
// CHECK: sext <4 x i16> %{{.*}} to <4 x i64> // CHECK: sext <4 x i16> %{{.*}} to <4 x i64>
return _mm256_cvtepi16_epi64(a); return _mm256_cvtepi16_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepi16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0));
__m256i test_mm256_cvtepi32_epi64(__m128i a) { __m256i test_mm256_cvtepi32_epi64(__m128i a) {
@ -365,6 +370,7 @@ __m256i test_mm256_cvtepi32_epi64(__m128i a) {
// CHECK: sext <4 x i32> %{{.*}} to <4 x i64> // CHECK: sext <4 x i32> %{{.*}} to <4 x i64>
return _mm256_cvtepi32_epi64(a); return _mm256_cvtepi32_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), -70000, 2, -1, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepi32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), -70000, 2, -1, 0));
__m256i test_mm256_cvtepu8_epi16(__m128i a) { __m256i test_mm256_cvtepu8_epi16(__m128i a) {
@ -372,6 +378,7 @@ __m256i test_mm256_cvtepu8_epi16(__m128i a) {
// CHECK: zext <16 x i8> %{{.*}} to <16 x i16> // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
return _mm256_cvtepu8_epi16(a); return _mm256_cvtepu8_epi16(a);
} }
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepu8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252, 5, 250, 7, 248, 9, 246, 11, 244)); TEST_CONSTEXPR(match_v16hi(_mm256_cvtepu8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252, 5, 250, 7, 248, 9, 246, 11, 244));
__m256i test_mm256_cvtepu8_epi32(__m128i a) { __m256i test_mm256_cvtepu8_epi32(__m128i a) {
@ -380,6 +387,7 @@ __m256i test_mm256_cvtepu8_epi32(__m128i a) {
// CHECK: zext <8 x i8> %{{.*}} to <8 x i32> // CHECK: zext <8 x i8> %{{.*}} to <8 x i32>
return _mm256_cvtepu8_epi32(a); return _mm256_cvtepu8_epi32(a);
} }
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252)); TEST_CONSTEXPR(match_v8si(_mm256_cvtepu8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252));
__m256i test_mm256_cvtepu8_epi64(__m128i a) { __m256i test_mm256_cvtepu8_epi64(__m128i a) {
@ -388,6 +396,7 @@ __m256i test_mm256_cvtepu8_epi64(__m128i a) {
// CHECK: zext <4 x i8> %{{.*}} to <4 x i64> // CHECK: zext <4 x i8> %{{.*}} to <4 x i64>
return _mm256_cvtepu8_epi64(a); return _mm256_cvtepu8_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepu8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0));
__m256i test_mm256_cvtepu16_epi32(__m128i a) { __m256i test_mm256_cvtepu16_epi32(__m128i a) {
@ -395,6 +404,7 @@ __m256i test_mm256_cvtepu16_epi32(__m128i a) {
// CHECK: zext <8 x i16> {{.*}} to <8 x i32> // CHECK: zext <8 x i16> {{.*}} to <8 x i32>
return _mm256_cvtepu16_epi32(a); return _mm256_cvtepu16_epi32(a);
} }
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0, 1, 65534, 3, 65532)); TEST_CONSTEXPR(match_v8si(_mm256_cvtepu16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0, 1, 65534, 3, 65532));
__m256i test_mm256_cvtepu16_epi64(__m128i a) { __m256i test_mm256_cvtepu16_epi64(__m128i a) {
@ -403,6 +413,7 @@ __m256i test_mm256_cvtepu16_epi64(__m128i a) {
// CHECK: zext <4 x i16> %{{.*}} to <4 x i64> // CHECK: zext <4 x i16> %{{.*}} to <4 x i64>
return _mm256_cvtepu16_epi64(a); return _mm256_cvtepu16_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepu16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0));
__m256i test_mm256_cvtepu32_epi64(__m128i a) { __m256i test_mm256_cvtepu32_epi64(__m128i a) {
@ -410,6 +421,7 @@ __m256i test_mm256_cvtepu32_epi64(__m128i a) {
// CHECK: zext <4 x i32> %{{.*}} to <4 x i64> // CHECK: zext <4 x i32> %{{.*}} to <4 x i64>
return _mm256_cvtepu32_epi64(a); return _mm256_cvtepu32_epi64(a);
} }
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), 4294897296, 2, 4294967295, 0)); TEST_CONSTEXPR(match_v4di(_mm256_cvtepu32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), 4294897296, 2, 4294967295, 0));
__m128i test0_mm256_extracti128_si256_0(__m256i a) { __m128i test0_mm256_extracti128_si256_0(__m256i a) {
@ -1108,28 +1120,24 @@ __m128i test_mm_sllv_epi32(__m128i a, __m128i b) {
// CHECK: call <4 x i32> @llvm.x86.avx2.psllv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}) // CHECK: call <4 x i32> @llvm.x86.avx2.psllv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
return _mm_sllv_epi32(a, b); return _mm_sllv_epi32(a, b);
} }
TEST_CONSTEXPR(match_v4si(_mm_sllv_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 2, -8, 24, 0));
__m256i test_mm256_sllv_epi32(__m256i a, __m256i b) { __m256i test_mm256_sllv_epi32(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_sllv_epi32 // CHECK-LABEL: test_mm256_sllv_epi32
// CHECK: call <8 x i32> @llvm.x86.avx2.psllv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}}) // CHECK: call <8 x i32> @llvm.x86.avx2.psllv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
return _mm256_sllv_epi32(a, b); return _mm256_sllv_epi32(a, b);
} }
TEST_CONSTEXPR(match_v8si(_mm256_sllv_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 2, -8, 24, -64, 0, 0, 0, 0));
__m128i test_mm_sllv_epi64(__m128i a, __m128i b) { __m128i test_mm_sllv_epi64(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_sllv_epi64 // CHECK-LABEL: test_mm_sllv_epi64
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psllv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}) // CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psllv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
return _mm_sllv_epi64(a, b); return _mm_sllv_epi64(a, b);
} }
TEST_CONSTEXPR(match_m128i(_mm_sllv_epi64((__m128i)(__v2di){1, -3}, (__m128i)(__v2di){8, 63}), 256, 0x8000000000000000ULL));
__m256i test_mm256_sllv_epi64(__m256i a, __m256i b) { __m256i test_mm256_sllv_epi64(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_sllv_epi64 // CHECK-LABEL: test_mm256_sllv_epi64
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psllv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}}) // CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psllv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
return _mm256_sllv_epi64(a, b); return _mm256_sllv_epi64(a, b);
} }
TEST_CONSTEXPR(match_m256i(_mm256_sllv_epi64((__m256i)(__v4di){1, -2, 3, -4}, (__m256i)(__v4di){1, 2, 3, -4}), 2, -8, 24, 0));
__m256i test_mm256_sra_epi16(__m256i a, __m128i b) { __m256i test_mm256_sra_epi16(__m256i a, __m128i b) {
// CHECK-LABEL: test_mm256_sra_epi16 // CHECK-LABEL: test_mm256_sra_epi16
@ -1172,14 +1180,12 @@ __m128i test_mm_srav_epi32(__m128i a, __m128i b) {
// CHECK: call <4 x i32> @llvm.x86.avx2.psrav.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}) // CHECK: call <4 x i32> @llvm.x86.avx2.psrav.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
return _mm_srav_epi32(a, b); return _mm_srav_epi32(a, b);
} }
TEST_CONSTEXPR(match_v4si(_mm_srav_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 0, -1, 0, -1));
__m256i test_mm256_srav_epi32(__m256i a, __m256i b) { __m256i test_mm256_srav_epi32(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_srav_epi32 // CHECK-LABEL: test_mm256_srav_epi32
// CHECK: call <8 x i32> @llvm.x86.avx2.psrav.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}}) // CHECK: call <8 x i32> @llvm.x86.avx2.psrav.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
return _mm256_srav_epi32(a, b); return _mm256_srav_epi32(a, b);
} }
TEST_CONSTEXPR(match_v8si(_mm256_srav_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 0, -1, 0, -1, 0, -1, 0, -1));
__m256i test_mm256_srl_epi16(__m256i a, __m128i b) { __m256i test_mm256_srl_epi16(__m256i a, __m128i b) {
// CHECK-LABEL: test_mm256_srl_epi16 // CHECK-LABEL: test_mm256_srl_epi16
@ -1246,28 +1252,24 @@ __m128i test_mm_srlv_epi32(__m128i a, __m128i b) {
// CHECK: call <4 x i32> @llvm.x86.avx2.psrlv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}) // CHECK: call <4 x i32> @llvm.x86.avx2.psrlv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
return _mm_srlv_epi32(a, b); return _mm_srlv_epi32(a, b);
} }
TEST_CONSTEXPR(match_v4si(_mm_srlv_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 0, 1073741823, 0, 0));
__m256i test_mm256_srlv_epi32(__m256i a, __m256i b) { __m256i test_mm256_srlv_epi32(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_srlv_epi32 // CHECK-LABEL: test_mm256_srlv_epi32
// CHECK: call <8 x i32> @llvm.x86.avx2.psrlv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}}) // CHECK: call <8 x i32> @llvm.x86.avx2.psrlv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
return _mm256_srlv_epi32(a, b); return _mm256_srlv_epi32(a, b);
} }
TEST_CONSTEXPR(match_v8si(_mm256_srlv_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 0, 1073741823, 0, 268435455, 0, 1, 0, 7));
__m128i test_mm_srlv_epi64(__m128i a, __m128i b) { __m128i test_mm_srlv_epi64(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_srlv_epi64 // CHECK-LABEL: test_mm_srlv_epi64
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psrlv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}) // CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psrlv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
return _mm_srlv_epi64(a, b); return _mm_srlv_epi64(a, b);
} }
TEST_CONSTEXPR(match_m128i(_mm_srlv_epi64((__m128i)(__v2di){1, -3}, (__m128i)(__v2di){8, 63}), 0, 1));
__m256i test_mm256_srlv_epi64(__m256i a, __m256i b) { __m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_srlv_epi64 // CHECK-LABEL: test_mm256_srlv_epi64
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psrlv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}}) // CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psrlv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
return _mm256_srlv_epi64(a, b); return _mm256_srlv_epi64(a, b);
} }
TEST_CONSTEXPR(match_m256i(_mm256_srlv_epi64((__m256i)(__v4di){1, -2, 3, -4}, (__m256i)(__v4di){1, 2, 3, -4}), 0, 0x3FFFFFFFFFFFFFFFULL, 0, 0));
__m256i test_mm256_stream_load_si256(__m256i const *a) { __m256i test_mm256_stream_load_si256(__m256i const *a) {
// CHECK-LABEL: test_mm256_stream_load_si256 // CHECK-LABEL: test_mm256_stream_load_si256

View File

@ -3,11 +3,6 @@
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion | FileCheck %s // RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion | FileCheck %s
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -fms-extensions -fms-compatibility -ffreestanding %s -triple=x86_64-windows-msvc -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion | FileCheck %s // RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -fms-extensions -fms-compatibility -ffreestanding %s -triple=x86_64-windows-msvc -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion | FileCheck %s
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion -fexperimental-new-constant-interpreter | FileCheck %s
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -fms-extensions -fms-compatibility -ffreestanding %s -triple=x86_64-windows-msvc -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion -fexperimental-new-constant-interpreter | FileCheck %s
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion -fexperimental-new-constant-interpreter | FileCheck %s
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -fms-extensions -fms-compatibility -ffreestanding %s -triple=x86_64-windows-msvc -target-feature +avx512f -emit-llvm -o - -Wall -Werror -Wsign-conversion -fexperimental-new-constant-interpreter | FileCheck %s
#include <immintrin.h> #include <immintrin.h>
#include "builtin_test_helpers.h" #include "builtin_test_helpers.h"

Some files were not shown because too many files have changed in this diff Show More