Compare commits
4 Commits
main
...
users/tbla
Author | SHA1 | Date | |
---|---|---|---|
![]() |
245ecd1984 | ||
![]() |
f84070b2b0 | ||
![]() |
16662ce212 | ||
![]() |
040a19d127 |
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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 &&
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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,
|
||||||
|
@ -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),
|
||||||
|
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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>;
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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()),
|
||||||
|
@ -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())
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -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
|
||||||
|
@ -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)">;
|
||||||
}
|
}
|
||||||
|
@ -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">>;
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -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"; }
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
@ -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; }
|
||||||
|
@ -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
|
||||||
|
@ -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.">;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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.
|
||||||
|
@ -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(),
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -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?");
|
||||||
|
@ -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
|
||||||
|
@ -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>();
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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 *
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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}}
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -732,8 +732,3 @@ namespace LocalVarForParmVarDecl {
|
|||||||
}
|
}
|
||||||
static_assert(foo(), "");
|
static_assert(foo(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PtrPtrCast {
|
|
||||||
void foo() { ; }
|
|
||||||
void bar(int *a) { a = (int *)(void *)(foo); }
|
|
||||||
}
|
|
||||||
|
@ -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}}
|
|
||||||
}
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
@ -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)
|
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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>} { }
|
|
@ -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>)
|
|
||||||
}
|
|
||||||
|
@ -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>}
|
|
@ -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>)
|
|
||||||
}
|
|
@ -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: }
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user