Compare commits
165 Commits
users/arse
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2a79ef66eb | ||
![]() |
b149fc7755 | ||
![]() |
7c1d2467f1 | ||
![]() |
15a192cde5 | ||
![]() |
2014890c09 | ||
![]() |
d8769bb5b7 | ||
![]() |
3292edb7b4 | ||
![]() |
d2b810e24f | ||
![]() |
a8aacb1b66 | ||
![]() |
d2dee948a4 | ||
![]() |
a6fcd1a663 | ||
![]() |
2975e674ec | ||
![]() |
ee5367bedb | ||
![]() |
d5af08a221 | ||
![]() |
d6fcaef281 | ||
![]() |
17dbb92612 | ||
![]() |
8439777131 | ||
![]() |
fda24dbc16 | ||
![]() |
7594b4b8d1 | ||
![]() |
bfc16510c7 | ||
![]() |
fd52f4d232 | ||
![]() |
8bc038daf2 | ||
![]() |
faca8c9ed4 | ||
![]() |
1b4fe26343 | ||
![]() |
00a405f666 | ||
![]() |
8bf105cb01 | ||
![]() |
2d3167f8d8 | ||
![]() |
4ff7ac2330 | ||
![]() |
8d7df8bba1 | ||
![]() |
4ab5efd48d | ||
![]() |
f1aee598e7 | ||
![]() |
2a59400003 | ||
![]() |
2b8e806942 | ||
![]() |
149d9a38e1 | ||
![]() |
6560adb584 | ||
![]() |
2b46f31ee3 | ||
![]() |
e0945dfa30 | ||
![]() |
cf5243619a | ||
![]() |
50f7c6a5b9 | ||
![]() |
945a186089 | ||
![]() |
06ab660911 | ||
![]() |
36dc6146b8 | ||
![]() |
5050da7ba1 | ||
![]() |
a2f542b7a5 | ||
![]() |
04a3dd5a19 | ||
![]() |
1def457228 | ||
![]() |
d3d5751a39 | ||
![]() |
595148ab76 | ||
![]() |
0fff460592 | ||
![]() |
b08b219650 | ||
![]() |
be179d0696 | ||
![]() |
dee25a8a8e | ||
![]() |
d6fae7f921 | ||
![]() |
630712f4c1 | ||
![]() |
b1b5102624 | ||
![]() |
c1625fad02 | ||
![]() |
c346f4079a | ||
![]() |
fc5fcc0c95 | ||
![]() |
01f785cac4 | ||
![]() |
6a7ade03d1 | ||
![]() |
586a7131d3 | ||
![]() |
49d4712129 | ||
![]() |
6df9a13e40 | ||
![]() |
d26ea02060 | ||
![]() |
f1f194bf10 | ||
![]() |
418fb50301 | ||
![]() |
273b6f2911 | ||
![]() |
4d323206ed | ||
![]() |
3ce25abd4a | ||
![]() |
783859b2a0 | ||
![]() |
9d2a66fb32 | ||
![]() |
0bc02096f6 | ||
![]() |
6167b1e6e9 | ||
![]() |
b3f04bf44c | ||
![]() |
4eeeb8a01e | ||
![]() |
c97c6869b6 | ||
![]() |
e6d095e89c | ||
![]() |
05b1ec3724 | ||
![]() |
ff85dbdf6b | ||
![]() |
f961b61f88 | ||
![]() |
c74afaac6c | ||
![]() |
a3ed96b899 | ||
![]() |
304373fb6d | ||
![]() |
36d07ad83b | ||
![]() |
33f6b10c17 | ||
![]() |
d4b9acad58 | ||
![]() |
7f0e70fd2d | ||
![]() |
22f8693248 | ||
![]() |
628280b597 | ||
![]() |
67e95c6f60 | ||
![]() |
4e98641451 | ||
![]() |
ec07d8e941 | ||
![]() |
f5f6613af6 | ||
![]() |
e45210afe2 | ||
![]() |
1d05d693a1 | ||
![]() |
fa67855c99 | ||
![]() |
2421929ca6 | ||
![]() |
d38a5afa5a | ||
![]() |
04a271adf8 | ||
![]() |
c704dabe88 | ||
![]() |
8fa55a023b | ||
![]() |
09612007f1 | ||
![]() |
300d2c6d20 | ||
![]() |
38f0b9e6d9 | ||
![]() |
9b24ccca73 | ||
![]() |
933d8723b0 | ||
![]() |
545cda649e | ||
![]() |
ba5d487ac4 | ||
![]() |
4a9d2187ee | ||
![]() |
76b8e19203 | ||
![]() |
a447fc63f9 | ||
![]() |
a64e6f4928 | ||
![]() |
de7bac6426 | ||
![]() |
344793e513 | ||
![]() |
b3baa4d063 | ||
![]() |
779bb04a9a | ||
![]() |
9b5282723b | ||
![]() |
4e7779c099 | ||
![]() |
8d69c83808 | ||
![]() |
7d1f15c985 | ||
![]() |
f66d7b50ff | ||
![]() |
0f33b90b61 | ||
![]() |
424521f599 | ||
![]() |
1b9e9e29e2 | ||
![]() |
c80b7822e3 | ||
![]() |
de64f85f5d | ||
![]() |
e42ef8083c | ||
![]() |
8b091961b1 | ||
![]() |
e41aaf5a64 | ||
![]() |
21cca5ea9d | ||
![]() |
11994e8da7 | ||
![]() |
c91f7dc7cd | ||
![]() |
1a09581aa1 | ||
![]() |
87a1d42bed | ||
![]() |
a9de1ab44d | ||
![]() |
0319a7970d | ||
![]() |
13eca5248c | ||
![]() |
bce9b6d177 | ||
![]() |
c5466c64d4 | ||
![]() |
761125f267 | ||
![]() |
436f391d1d | ||
![]() |
b5fc4fd009 | ||
![]() |
9576a100ae | ||
![]() |
eed5f06ae8 | ||
![]() |
e20fa4f412 | ||
![]() |
fc62990657 | ||
![]() |
3923adfa3f | ||
![]() |
dacabc1fee | ||
![]() |
86c9a7b0c1 | ||
![]() |
035dd1d854 | ||
![]() |
a96b78cf41 | ||
![]() |
5c36fb3303 | ||
![]() |
1b0b59ae43 | ||
![]() |
0594bad039 | ||
![]() |
68d6866428 | ||
![]() |
32a5adbd42 | ||
![]() |
a53e73e6ef | ||
![]() |
cfef05e69c | ||
![]() |
dbadab96eb | ||
![]() |
3f97736181 | ||
![]() |
17eb05ddd3 | ||
![]() |
3d41197d68 | ||
![]() |
5d4aa87ca5 | ||
![]() |
e21b0dd819 | ||
![]() |
42cf9c60d7 |
@ -60,7 +60,8 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \
|
||||
-D MLIR_ENABLE_BINDINGS_PYTHON=ON \
|
||||
-D LLDB_ENABLE_PYTHON=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"
|
||||
|
||||
|
@ -138,6 +138,12 @@
|
||||
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
|
||||
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 kernel exception table
|
||||
|
@ -15,6 +15,12 @@
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace bolt {
|
||||
class BinaryFunction;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
namespace opts {
|
||||
|
||||
enum HeatmapModeKind {
|
||||
@ -100,6 +106,9 @@ extern llvm::cl::opt<unsigned> Verbosity;
|
||||
/// Return true if we should process all functions in the binary.
|
||||
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 };
|
||||
|
||||
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
|
||||
|
@ -52,6 +52,7 @@ namespace opts {
|
||||
extern cl::opt<bool> PrintAll;
|
||||
extern cl::opt<bool> PrintDynoStats;
|
||||
extern cl::opt<bool> DumpDotAll;
|
||||
extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
|
||||
extern cl::opt<std::string> AsmDump;
|
||||
extern cl::opt<bolt::PLTCall::OptType> PLT;
|
||||
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
|
||||
@ -340,7 +341,7 @@ Error BinaryFunctionPassManager::runPasses() {
|
||||
|
||||
Function.print(BC.outs(), Message);
|
||||
|
||||
if (opts::DumpDotAll)
|
||||
if (opts::shouldDumpDot(Function))
|
||||
Function.dumpGraphForPass(PassIdName);
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,35 @@ cl::opt<bool> DumpDotAll(
|
||||
"enable '-print-loops' for color-coded blocks"),
|
||||
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>
|
||||
ForceFunctionNames("funcs",
|
||||
cl::CommaSeparated,
|
||||
@ -3569,7 +3598,7 @@ void RewriteInstance::postProcessFunctions() {
|
||||
if (opts::PrintAll || opts::PrintCFG)
|
||||
Function.print(BC->outs(), "after building cfg");
|
||||
|
||||
if (opts::DumpDotAll)
|
||||
if (opts::shouldDumpDot(Function))
|
||||
Function.dumpGraphForPass("00_build-cfg");
|
||||
|
||||
if (opts::PrintLoopInfo) {
|
||||
|
24
bolt/test/Inputs/multi-func.cpp
Normal file
24
bolt/test/Inputs/multi-func.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#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;
|
||||
}
|
52
bolt/test/dump-dot-func.test
Normal file
52
bolt/test/dump-dot-func.test
Normal file
@ -0,0 +1,52 @@
|
||||
# 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,6 +1575,10 @@ template <typename T, std::size_t N = SmallDataStructureSize>
|
||||
using ParamToSmallSetMap =
|
||||
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
|
||||
/// least one element in common.
|
||||
template <typename MapTy, typename ElemTy>
|
||||
@ -1699,7 +1703,7 @@ public:
|
||||
/// Implements the heuristic that marks two parameters related if the same
|
||||
/// member is accessed (referred to) inside the current function's body.
|
||||
class AccessedSameMemberOf {
|
||||
ParamToSmallSetMap<const Decl *> AccessedMembers;
|
||||
ParamToSmallPtrSetMap<const Decl *> AccessedMembers;
|
||||
|
||||
public:
|
||||
void setup(const FunctionDecl *FD) {
|
||||
|
@ -15,14 +15,12 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
|
||||
namespace {
|
||||
|
||||
// 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
|
||||
// or passed to a function or constructor.
|
||||
// For this use case compound assignments are not counted as a "store" (the 'E'
|
||||
// expression should have pointer type).
|
||||
bool isExprValueStored(const Expr *E, ASTContext &C) {
|
||||
static bool isExprValueStored(const Expr *E, ASTContext &C) {
|
||||
E = E->IgnoreParenCasts();
|
||||
// Get first non-paren, non-cast parent.
|
||||
ParentMapContext &PMap = C.getParentMapContext();
|
||||
@ -49,6 +47,8 @@ bool isExprValueStored(const Expr *E, ASTContext &C) {
|
||||
return isa<CallExpr, CXXConstructExpr>(ParentE);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
|
||||
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
|
||||
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
|
||||
|
@ -14,10 +14,8 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
||||
const StringLiteral *Lit) {
|
||||
static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
||||
const StringLiteral *Lit) {
|
||||
// String literals surrounded by parentheses are assumed to be on purpose.
|
||||
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
|
||||
|
||||
@ -58,6 +56,8 @@ bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
|
||||
MaxConcatenatedTokens) {
|
||||
return Node.getNumConcatenated() > 1 &&
|
||||
|
@ -46,7 +46,9 @@ enum class ConversionKind {
|
||||
ToLongDouble
|
||||
};
|
||||
|
||||
ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
||||
} // namespace
|
||||
|
||||
static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
||||
return llvm::StringSwitch<ConversionKind>(FD->getName())
|
||||
.Cases("atoi", "atol", ConversionKind::ToInt)
|
||||
.Case("atoll", ConversionKind::ToLongInt)
|
||||
@ -54,8 +56,8 @@ ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
||||
.Default(ConversionKind::None);
|
||||
}
|
||||
|
||||
ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
||||
const TargetInfo &TI) {
|
||||
static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
||||
const TargetInfo &TI) {
|
||||
// Scan the format string for the first problematic format specifier, then
|
||||
// report that as the conversion type. This will miss additional conversion
|
||||
// specifiers, but that is acceptable behavior.
|
||||
@ -128,7 +130,7 @@ ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
||||
return H.get();
|
||||
}
|
||||
|
||||
StringRef classifyConversionType(ConversionKind K) {
|
||||
static StringRef classifyConversionType(ConversionKind K) {
|
||||
switch (K) {
|
||||
case ConversionKind::None:
|
||||
llvm_unreachable("Unexpected conversion kind");
|
||||
@ -148,7 +150,7 @@ StringRef classifyConversionType(ConversionKind K) {
|
||||
llvm_unreachable("Unknown conversion kind");
|
||||
}
|
||||
|
||||
StringRef classifyReplacement(ConversionKind K) {
|
||||
static StringRef classifyReplacement(ConversionKind K) {
|
||||
switch (K) {
|
||||
case ConversionKind::None:
|
||||
llvm_unreachable("Unexpected conversion kind");
|
||||
@ -173,7 +175,6 @@ StringRef classifyReplacement(ConversionKind K) {
|
||||
}
|
||||
llvm_unreachable("Unknown conversion kind");
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
|
||||
|
@ -59,7 +59,9 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) {
|
||||
return true;
|
||||
}
|
||||
|
||||
OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
||||
} // namespace
|
||||
|
||||
static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
||||
switch (FD->getOverloadedOperator()) {
|
||||
default:
|
||||
break;
|
||||
@ -75,7 +77,7 @@ OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
||||
llvm_unreachable("Not an overloaded allocation operator");
|
||||
}
|
||||
|
||||
const char *getOperatorName(OverloadedOperatorKind K) {
|
||||
static const char *getOperatorName(OverloadedOperatorKind K) {
|
||||
switch (K) {
|
||||
default:
|
||||
break;
|
||||
@ -91,13 +93,14 @@ const char *getOperatorName(OverloadedOperatorKind K) {
|
||||
llvm_unreachable("Not an overloaded allocation operator");
|
||||
}
|
||||
|
||||
bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
||||
const FunctionDecl *RHS) {
|
||||
static bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
||||
const FunctionDecl *RHS) {
|
||||
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
|
||||
}
|
||||
|
||||
bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
||||
const CXXRecordDecl *RD = nullptr) {
|
||||
static bool
|
||||
hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
||||
const CXXRecordDecl *RD = nullptr) {
|
||||
if (RD) {
|
||||
// Check the methods in the given class and accessible to derived classes.
|
||||
for (const auto *BMD : RD->methods())
|
||||
@ -124,8 +127,6 @@ bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// Match all operator new and operator delete overloads (including the array
|
||||
// forms). Do not match implicit operators, placement operators, or
|
||||
|
@ -395,16 +395,12 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
|
||||
--CurrentFile->ConditionScopes;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <size_t N>
|
||||
bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
||||
static bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
||||
return StringRef{HayStack, N - 1} == Needle;
|
||||
}
|
||||
|
||||
template <size_t N> size_t len(const char (&)[N]) { return N - 1; }
|
||||
|
||||
} // namespace
|
||||
template <size_t N> static size_t len(const char (&)[N]) { return N - 1; }
|
||||
|
||||
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
|
||||
PragmaIntroducerKind Introducer) {
|
||||
|
@ -16,14 +16,13 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::modernize {
|
||||
|
||||
namespace {
|
||||
static constexpr char ConstructorCall[] = "constructorCall";
|
||||
static constexpr char ResetCall[] = "resetCall";
|
||||
static constexpr char NewExpression[] = "newExpression";
|
||||
|
||||
constexpr char ConstructorCall[] = "constructorCall";
|
||||
constexpr char ResetCall[] = "resetCall";
|
||||
constexpr char NewExpression[] = "newExpression";
|
||||
|
||||
std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
|
||||
const LangOptions &Lang) {
|
||||
static std::string getNewExprName(const CXXNewExpr *NewExpr,
|
||||
const SourceManager &SM,
|
||||
const LangOptions &Lang) {
|
||||
StringRef WrittenName = Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(
|
||||
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
|
||||
@ -34,8 +33,6 @@ std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
|
||||
return WrittenName.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
|
||||
|
||||
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
|
||||
|
@ -19,9 +19,7 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::modernize {
|
||||
|
||||
namespace {
|
||||
|
||||
bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
||||
static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
||||
size_t BackSlash = HayStack.find('\\');
|
||||
if (BackSlash == StringRef::npos)
|
||||
return false;
|
||||
@ -35,16 +33,16 @@ bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isRawStringLiteral(StringRef Text) {
|
||||
static bool isRawStringLiteral(StringRef Text) {
|
||||
// Already a raw string literal if R comes before ".
|
||||
const size_t QuotePos = Text.find('"');
|
||||
assert(QuotePos != StringRef::npos);
|
||||
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
|
||||
}
|
||||
|
||||
bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
||||
const StringLiteral *Literal,
|
||||
const CharsBitSet &DisallowedChars) {
|
||||
static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
||||
const StringLiteral *Literal,
|
||||
const CharsBitSet &DisallowedChars) {
|
||||
// FIXME: Handle L"", u8"", u"" and U"" literals.
|
||||
if (!Literal->isOrdinary())
|
||||
return false;
|
||||
@ -64,14 +62,12 @@ bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
||||
return containsEscapes(Text, R"('\"?x01)");
|
||||
}
|
||||
|
||||
bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
||||
static bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
||||
return Bytes.find(Delimiter.empty()
|
||||
? std::string(R"lit()")lit")
|
||||
: (")" + Delimiter + R"(")")) != StringRef::npos;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
|
||||
ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -29,12 +29,13 @@
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::objc {
|
||||
namespace {
|
||||
|
||||
static constexpr StringRef WeakText = "__weak";
|
||||
static constexpr StringRef StrongText = "__strong";
|
||||
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
|
||||
|
||||
namespace {
|
||||
|
||||
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
|
||||
/// Objective-C object (or block) variables or fields whose object lifetimes
|
||||
/// are not __unsafe_unretained.
|
||||
@ -49,6 +50,8 @@ AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime,
|
||||
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::optional<FixItHint>
|
||||
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
|
||||
StringRef Ownership) {
|
||||
@ -93,8 +96,6 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM,
|
||||
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(
|
||||
traverse(
|
||||
|
@ -27,11 +27,14 @@ enum NamingStyle {
|
||||
CategoryProperty = 2,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
||||
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
|
||||
/// come up with a proper name by their own.
|
||||
/// FIXME: provide fix for snake_case to snakeCase
|
||||
FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
|
||||
static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
|
||||
NamingStyle Style) {
|
||||
auto Name = Decl->getName();
|
||||
auto NewName = Decl->getName().str();
|
||||
size_t Index = 0;
|
||||
@ -50,7 +53,7 @@ FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string validPropertyNameRegex(bool UsedInMatcher) {
|
||||
static std::string validPropertyNameRegex(bool UsedInMatcher) {
|
||||
// Allow any of these names:
|
||||
// foo
|
||||
// fooBar
|
||||
@ -72,13 +75,13 @@ std::string validPropertyNameRegex(bool UsedInMatcher) {
|
||||
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
||||
}
|
||||
|
||||
bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
||||
static bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
||||
auto RegexExp =
|
||||
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
||||
return RegexExp.match(PropertyName);
|
||||
}
|
||||
|
||||
bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
||||
static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
||||
size_t Start = PropertyName.find_first_of('_');
|
||||
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
|
||||
auto Prefix = PropertyName.substr(0, Start);
|
||||
@ -88,7 +91,6 @@ bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
||||
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
|
||||
return RegexExp.match(PropertyName.substr(Start + 1));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(objcPropertyDecl(
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <optional>
|
||||
|
||||
namespace clang::tidy::performance {
|
||||
namespace {
|
||||
|
||||
using namespace ::clang::ast_matchers;
|
||||
using llvm::StringRef;
|
||||
@ -30,8 +29,8 @@ static constexpr StringRef MethodDeclId = "methodDecl";
|
||||
static constexpr StringRef FunctionDeclId = "functionDecl";
|
||||
static constexpr StringRef OldVarDeclId = "oldVarDecl";
|
||||
|
||||
void recordFixes(const VarDecl &Var, ASTContext &Context,
|
||||
DiagnosticBuilder &Diagnostic) {
|
||||
static void recordFixes(const VarDecl &Var, ASTContext &Context,
|
||||
DiagnosticBuilder &Diagnostic) {
|
||||
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
|
||||
if (!Var.getType().isLocalConstQualified()) {
|
||||
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
||||
@ -40,8 +39,8 @@ void recordFixes(const VarDecl &Var, ASTContext &Context,
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
||||
SourceManager &SM) {
|
||||
static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
||||
SourceManager &SM) {
|
||||
bool Invalid = false;
|
||||
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
|
||||
if (Invalid) {
|
||||
@ -51,8 +50,8 @@ std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
||||
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
|
||||
}
|
||||
|
||||
void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
||||
DiagnosticBuilder &Diagnostic) {
|
||||
static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
||||
DiagnosticBuilder &Diagnostic) {
|
||||
auto &SM = Context.getSourceManager();
|
||||
// Attempt to remove trailing comments as well.
|
||||
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
|
||||
@ -74,6 +73,8 @@ void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
AST_MATCHER_FUNCTION_P(StatementMatcher,
|
||||
isRefReturningMethodCallWithConstOverloads,
|
||||
std::vector<StringRef>, ExcludedContainerTypes) {
|
||||
@ -130,6 +131,8 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
|
||||
hasUnaryOperand(OldVarDeclRef)))));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// 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
|
||||
// the BlockStmt. It does this by checking the following:
|
||||
@ -180,13 +183,13 @@ static bool isInitializingVariableImmutable(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
||||
ASTContext &Context) {
|
||||
static bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
||||
ASTContext &Context) {
|
||||
return allDeclRefExprs(Var, BlockStmt, Context).empty();
|
||||
}
|
||||
|
||||
const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
|
||||
ASTContext &Context) {
|
||||
static const SubstTemplateTypeParmType *
|
||||
getSubstitutedType(const QualType &Type, ASTContext &Context) {
|
||||
auto Matches = match(
|
||||
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
|
||||
hasDescendant(substTemplateTypeParmType().bind("subst")))),
|
||||
@ -194,9 +197,9 @@ const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
|
||||
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
|
||||
}
|
||||
|
||||
bool differentReplacedTemplateParams(const QualType &VarType,
|
||||
const QualType &InitializerType,
|
||||
ASTContext &Context) {
|
||||
static bool differentReplacedTemplateParams(const QualType &VarType,
|
||||
const QualType &InitializerType,
|
||||
ASTContext &Context) {
|
||||
if (const SubstTemplateTypeParmType *VarTmplType =
|
||||
getSubstitutedType(VarType, Context)) {
|
||||
if (const SubstTemplateTypeParmType *InitializerTmplType =
|
||||
@ -212,8 +215,8 @@ bool differentReplacedTemplateParams(const QualType &VarType,
|
||||
return false;
|
||||
}
|
||||
|
||||
QualType constructorArgumentType(const VarDecl *OldVar,
|
||||
const BoundNodes &Nodes) {
|
||||
static QualType constructorArgumentType(const VarDecl *OldVar,
|
||||
const BoundNodes &Nodes) {
|
||||
if (OldVar) {
|
||||
return OldVar->getType();
|
||||
}
|
||||
@ -224,8 +227,6 @@ QualType constructorArgumentType(const VarDecl *OldVar,
|
||||
return MethodDecl->getReturnType();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -21,16 +21,14 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::performance {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
||||
static std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
||||
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
|
||||
: llvm::Twine('\'') + Name + llvm::Twine('\''))
|
||||
.str();
|
||||
}
|
||||
|
||||
bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
||||
ASTContext &Context) {
|
||||
static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
||||
ASTContext &Context) {
|
||||
auto Matches = match(
|
||||
traverse(TK_AsIs,
|
||||
decl(forEachDescendant(declRefExpr(
|
||||
@ -41,8 +39,6 @@ bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
||||
return Matches.empty();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -122,15 +122,15 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) {
|
||||
return !AllEnumeratorsArePowersOfTwo;
|
||||
}
|
||||
|
||||
std::string getName(const EnumDecl *Decl) {
|
||||
} // namespace
|
||||
|
||||
static std::string getName(const EnumDecl *Decl) {
|
||||
if (!Decl->getDeclName())
|
||||
return "<unnamed>";
|
||||
|
||||
return Decl->getQualifiedNameAsString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
|
||||
ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -144,6 +144,8 @@ struct CognitiveComplexity final {
|
||||
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// All the possible messages that can be output. The choice of the message
|
||||
// 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
|
||||
@ -163,23 +165,27 @@ static const std::array<const StringRef, 4> Msgs = {{
|
||||
}};
|
||||
|
||||
// Criteria is a bitset, thus a few helpers are needed.
|
||||
CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
static CognitiveComplexity::Criteria
|
||||
operator|(CognitiveComplexity::Criteria LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
|
||||
llvm::to_underlying(RHS));
|
||||
}
|
||||
CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
static CognitiveComplexity::Criteria
|
||||
operator&(CognitiveComplexity::Criteria LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
|
||||
llvm::to_underlying(RHS));
|
||||
}
|
||||
CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
static CognitiveComplexity::Criteria &
|
||||
operator|=(CognitiveComplexity::Criteria &LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
LHS = operator|(LHS, RHS);
|
||||
return LHS;
|
||||
}
|
||||
CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
static CognitiveComplexity::Criteria &
|
||||
operator&=(CognitiveComplexity::Criteria &LHS,
|
||||
CognitiveComplexity::Criteria RHS) {
|
||||
LHS = operator&(LHS, RHS);
|
||||
return LHS;
|
||||
}
|
||||
@ -199,6 +205,8 @@ void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
|
||||
Total += Increase;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class FunctionASTVisitor final
|
||||
: public RecursiveASTVisitor<FunctionASTVisitor> {
|
||||
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
||||
|
@ -41,9 +41,11 @@ AST_MATCHER(Stmt, isNULLMacroExpansion) {
|
||||
return isNULLMacroExpansion(&Node, Finder->getASTContext());
|
||||
}
|
||||
|
||||
StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
||||
QualType Type,
|
||||
ASTContext &Context) {
|
||||
} // namespace
|
||||
|
||||
static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
||||
QualType Type,
|
||||
ASTContext &Context) {
|
||||
switch (CastExprKind) {
|
||||
case CK_IntegralToBoolean:
|
||||
return Type->isUnsignedIntegerType() ? "0u" : "0";
|
||||
@ -62,15 +64,15 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
||||
}
|
||||
}
|
||||
|
||||
bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
||||
static bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
||||
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
|
||||
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
|
||||
}
|
||||
|
||||
void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
||||
const ImplicitCastExpr *Cast, const Stmt *Parent,
|
||||
ASTContext &Context,
|
||||
bool UseUpperCaseLiteralSuffix) {
|
||||
static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
||||
const ImplicitCastExpr *Cast,
|
||||
const Stmt *Parent, ASTContext &Context,
|
||||
bool UseUpperCaseLiteralSuffix) {
|
||||
// In case of expressions like (! integer), we should remove the redundant not
|
||||
// operator and use inverted comparison (integer == 0).
|
||||
bool InvertComparison =
|
||||
@ -133,8 +135,8 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
||||
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
|
||||
}
|
||||
|
||||
StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
||||
ASTContext &Context) {
|
||||
static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
||||
ASTContext &Context) {
|
||||
if (isNULLMacroExpansion(Expression, Context)) {
|
||||
return "false";
|
||||
}
|
||||
@ -161,7 +163,7 @@ StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
||||
return {};
|
||||
}
|
||||
|
||||
bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
||||
static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
||||
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
|
||||
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
|
||||
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
|
||||
@ -173,9 +175,10 @@ bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
||||
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
|
||||
}
|
||||
|
||||
void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
||||
const ImplicitCastExpr *Cast,
|
||||
ASTContext &Context, StringRef OtherType) {
|
||||
static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
||||
const ImplicitCastExpr *Cast,
|
||||
ASTContext &Context,
|
||||
StringRef OtherType) {
|
||||
if (!Context.getLangOpts().CPlusPlus) {
|
||||
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
|
||||
(Twine("(") + OtherType + ")").str());
|
||||
@ -200,8 +203,9 @@ void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
||||
}
|
||||
}
|
||||
|
||||
StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
||||
QualType DestType, ASTContext &Context) {
|
||||
static StringRef
|
||||
getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
||||
QualType DestType, ASTContext &Context) {
|
||||
// Prior to C++11, false literal could be implicitly converted to pointer.
|
||||
if (!Context.getLangOpts().CPlusPlus11 &&
|
||||
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
|
||||
@ -222,8 +226,8 @@ StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
||||
return BoolLiteral->getValue() ? "1" : "0";
|
||||
}
|
||||
|
||||
bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
||||
ASTContext &Context) {
|
||||
static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
||||
ASTContext &Context) {
|
||||
std::queue<const Stmt *> Q;
|
||||
Q.push(Cast);
|
||||
|
||||
@ -251,8 +255,6 @@ bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -28,8 +28,11 @@ AST_MATCHER_P(QualType, hasUnqualifiedType,
|
||||
|
||||
enum class Qualifier { Const, Volatile, Restrict };
|
||||
|
||||
std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
} // namespace
|
||||
|
||||
static std::optional<Token>
|
||||
findQualToken(const VarDecl *Decl, Qualifier Qual,
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
// 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
|
||||
// source file.
|
||||
@ -58,7 +61,7 @@ std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
|
||||
*Result.SourceManager);
|
||||
}
|
||||
|
||||
std::optional<SourceRange>
|
||||
static std::optional<SourceRange>
|
||||
getTypeSpecifierLocation(const VarDecl *Var,
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
SourceRange TypeSpecifier(
|
||||
@ -73,8 +76,8 @@ getTypeSpecifierLocation(const VarDecl *Var,
|
||||
return TypeSpecifier;
|
||||
}
|
||||
|
||||
std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
|
||||
const Token &ConstToken) {
|
||||
static std::optional<SourceRange>
|
||||
mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
|
||||
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
|
||||
TypeSpecifier.setBegin(ConstToken.getLocation());
|
||||
return std::nullopt;
|
||||
@ -86,21 +89,19 @@ std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
|
||||
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
|
||||
}
|
||||
|
||||
bool isPointerConst(QualType QType) {
|
||||
static bool isPointerConst(QualType QType) {
|
||||
QualType Pointee = QType->getPointeeType();
|
||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||
return Pointee.isConstQualified();
|
||||
}
|
||||
|
||||
bool isAutoPointerConst(QualType QType) {
|
||||
static bool isAutoPointerConst(QualType QType) {
|
||||
QualType Pointee =
|
||||
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
|
||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||
return Pointee.isConstQualified();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
|
||||
ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
|
@ -14,19 +14,18 @@ using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::readability {
|
||||
|
||||
namespace {
|
||||
static const char *const RedundantReturnDiag =
|
||||
"redundant return statement at the end "
|
||||
"of a function with a void return type";
|
||||
static const char *const RedundantContinueDiag =
|
||||
"redundant continue statement at the "
|
||||
"end of loop statement";
|
||||
|
||||
const char *const RedundantReturnDiag = "redundant return statement at the end "
|
||||
"of a function with a void return type";
|
||||
const char *const RedundantContinueDiag = "redundant continue statement at the "
|
||||
"end of loop statement";
|
||||
|
||||
bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) {
|
||||
static bool isLocationInMacroExpansion(const SourceManager &SM,
|
||||
SourceLocation Loc) {
|
||||
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(
|
||||
functionDecl(isDefinition(), returns(voidType()),
|
||||
|
@ -13,16 +13,14 @@
|
||||
|
||||
namespace clang::tidy::utils::type_traits {
|
||||
|
||||
namespace {
|
||||
|
||||
bool classHasTrivialCopyAndDestroy(QualType Type) {
|
||||
static bool classHasTrivialCopyAndDestroy(QualType Type) {
|
||||
auto *Record = Type->getAsCXXRecordDecl();
|
||||
return Record && Record->hasDefinition() &&
|
||||
!Record->hasNonTrivialCopyConstructor() &&
|
||||
!Record->hasNonTrivialDestructor();
|
||||
}
|
||||
|
||||
bool hasDeletedCopyConstructor(QualType Type) {
|
||||
static bool hasDeletedCopyConstructor(QualType Type) {
|
||||
auto *Record = Type->getAsCXXRecordDecl();
|
||||
if (!Record || !Record->hasDefinition())
|
||||
return false;
|
||||
@ -33,8 +31,6 @@ bool hasDeletedCopyConstructor(QualType Type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<bool> isExpensiveToCopy(QualType Type,
|
||||
const ASTContext &Context) {
|
||||
if (Type->isDependentType() || Type->isIncompleteType())
|
||||
|
@ -215,7 +215,8 @@ Changes in existing checks
|
||||
|
||||
- Improved :doc:`readability-identifier-naming
|
||||
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
|
||||
declarations in system headers.
|
||||
declarations in system headers. The documentation is also improved to
|
||||
differentiate the general options from the specific ones.
|
||||
|
||||
- Improved :doc:`readability-qualified-auto
|
||||
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
|
||||
|
@ -43,14 +43,21 @@ The options and their corresponding values are:
|
||||
- ``LowerCase`` - example: ``int i_Variable``
|
||||
- ``CamelCase`` - example: ``int IVariable``
|
||||
|
||||
Options
|
||||
-------
|
||||
Options summary
|
||||
---------------
|
||||
|
||||
The following options are described below:
|
||||
The available options are summarized below:
|
||||
|
||||
**General options**
|
||||
|
||||
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
||||
- :option:`AggressiveDependentMemberLookup`
|
||||
- :option:`CheckAnonFieldInParent`
|
||||
- :option:`GetConfigPerFile`
|
||||
- :option:`IgnoreMainLikeFunctions`
|
||||
|
||||
**Specific options**
|
||||
|
||||
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
||||
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
|
||||
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
|
||||
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
|
||||
@ -66,13 +73,11 @@ The following options are described below:
|
||||
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
|
||||
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
|
||||
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
|
||||
- :option:`GetConfigPerFile`
|
||||
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
|
||||
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
|
||||
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
|
||||
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
|
||||
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
|
||||
- :option:`IgnoreMainLikeFunctions`
|
||||
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
|
||||
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
|
||||
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
|
||||
@ -105,6 +110,12 @@ The following options are described below:
|
||||
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
|
||||
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
|
||||
|
||||
|
||||
Options description
|
||||
-------------------
|
||||
|
||||
A detailed description of each option is presented below:
|
||||
|
||||
.. option:: AbstractClassCase
|
||||
|
||||
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
|
||||
debugging them can still be challenging. This document guides you how to most
|
||||
debugging them can still be challenging. This document guides you on how to most
|
||||
efficiently debug coroutines and how to navigate existing shortcomings in
|
||||
debuggers and compilers.
|
||||
|
||||
Coroutines are generally used either as generators or for asynchronous
|
||||
programming. In this document, we will discuss both use cases. Even if you are
|
||||
using coroutines for asynchronous programming, you should still read the
|
||||
generators section, as it will introduce foundational debugging techniques also
|
||||
generators section, as it introduces foundational debugging techniques also
|
||||
applicable to the debugging of asynchronous programs.
|
||||
|
||||
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
|
||||
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
|
||||
implementation details of coroutines (such as their ABI). The further down in
|
||||
this document you go, the more low-level, technical the content will become. If
|
||||
implementation details of coroutines (such as their ABI). The further down you go in
|
||||
this document, 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
|
||||
earlier.
|
||||
|
||||
Debugging generators
|
||||
====================
|
||||
|
||||
One of the two major use cases for coroutines in C++ are generators, i.e.,
|
||||
One of the two major use cases for coroutines in C++ is generators, i.e.,
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
Stepping out of a coroutine
|
||||
@ -174,7 +174,7 @@ Inspecting a suspended coroutine
|
||||
--------------------------------
|
||||
|
||||
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.
|
||||
|
||||
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,
|
||||
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
|
||||
address (``0x555...`` in the screenshot) to directly jump to the function
|
||||
address (``0x555...`` in the screenshot) to jump directly to the function
|
||||
definition backing your coroutine handle.
|
||||
|
||||
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.
|
||||
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``
|
||||
type used below for asynchronous programming.
|
||||
|
||||
Alternatively, we can modify the C++ code to store the line number in the
|
||||
promise type. We can use a ``std::source_location`` to get the line number of
|
||||
promise type. We can use ``std::source_location`` to get the line number of
|
||||
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.
|
||||
|
||||
@ -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
|
||||
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
|
||||
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.
|
||||
@ -285,7 +285,7 @@ provide custom debugging support, so in addition to this guide, you might want
|
||||
to check out their documentation.
|
||||
|
||||
When using coroutines for asynchronous programming, your library usually
|
||||
provides you some ``task`` type. This type usually looks similar to this:
|
||||
provides you with some ``task`` type. This type usually looks similar to this:
|
||||
|
||||
.. 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
|
||||
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.
|
||||
|
||||
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
|
||||
approach described in the :ref:`devirtualization` section.
|
||||
|
||||
LLDB before 18.0 was hiding the ``__promise`` and ``__coro_frame``
|
||||
variable by default. The variables are still present, but they need to be
|
||||
LLDB before 18.0 hid the ``__promise`` and ``__coro_frame``
|
||||
variables by default. The variables are still present, but they need to be
|
||||
explicitly added to the "watch" pane in VS Code or requested via
|
||||
``print __promise`` and ``print __coro_frame`` from the debugger console.
|
||||
|
||||
@ -511,9 +511,9 @@ section.
|
||||
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,
|
||||
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
|
||||
----------------------------------
|
||||
@ -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
|
||||
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
|
||||
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 compiler. Semantic analysis is performed in Clang, and Coroutine
|
||||
construction and optimization takes place in the LLVM middle-end.
|
||||
the compiler. Semantic analysis is performed in Clang, and coroutine
|
||||
construction and optimization take place in the LLVM middle-end.
|
||||
|
||||
For each coroutine function, the frontend generates a single corresponding
|
||||
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
|
||||
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
|
||||
information.
|
||||
|
||||
@ -636,8 +636,8 @@ However, this is not possible for coroutine frames because the frames are
|
||||
constructed in the LLVM middle-end.
|
||||
|
||||
To mitigate this problem, the LLVM middle end attempts to generate some debug
|
||||
information, which is unfortunately incomplete, since much of the language
|
||||
specific information is missing in the middle end.
|
||||
information, which is unfortunately incomplete, since much of the
|
||||
language-specific information is missing in the middle end.
|
||||
|
||||
.. _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
|
||||
and coroutine frame.
|
||||
|
||||
In gdb, one can use the following approach to devirtualize coroutine type,
|
||||
In gdb, one can use the following approach to devirtualize a coroutine type,
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
*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
|
||||
state while the coroutine is suspended. As such, the variables inside the
|
||||
``__coro_frame`` variable might be outdated, in particular when optimizations
|
||||
``__coro_frame`` variable might be outdated, particularly when optimizations
|
||||
are enabled.
|
||||
|
||||
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
|
||||
that it can eliminate most of the load/store operations.
|
||||
The above code gets optimized to the equivalent of:
|
||||
The above code is optimized to the equivalent of:
|
||||
|
||||
.. 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/>`_
|
||||
|
||||
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
|
||||
more additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
||||
additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
||||
and printing async stack traces on crashes.
|
||||
|
@ -37,6 +37,22 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
|
||||
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
|
||||
-------------------------------------------
|
||||
|
||||
@ -229,7 +245,7 @@ Bug Fixes in This Version
|
||||
cast chain. (#GH149967).
|
||||
- Fixed a crash with incompatible pointer to integer conversions in designated
|
||||
initializers involving string literals. (#GH154046)
|
||||
- Clang's ``<stddef.h>`` now properly declares ``nullptr_t`` in C++ mode. (#GH154577).
|
||||
- Fixed scope of typedefs present inside a template class. (#GH91451)
|
||||
|
||||
Bug Fixes to Compiler Builtins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -293,6 +309,13 @@ NVPTX 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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -23,20 +23,20 @@
|
||||
#include "clang/Basic/DiagnosticInstallAPI.h"
|
||||
#include "clang/Basic/DiagnosticLex.h"
|
||||
#include "clang/Basic/DiagnosticParse.h"
|
||||
#include "clang/Basic/DiagnosticRefactoring.h"
|
||||
#include "clang/Basic/DiagnosticSema.h"
|
||||
#include "clang/Basic/DiagnosticSerialization.h"
|
||||
#include "clang/Basic/DiagnosticRefactoring.h"
|
||||
|
||||
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!");
|
||||
|
||||
public:
|
||||
enum { Size = SizeOfStr };
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
|
||||
fieldTy>::Size
|
||||
#define STR_SIZE(str, fieldTy) \
|
||||
clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size
|
||||
|
||||
#endif
|
||||
|
@ -627,11 +627,23 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
|
||||
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 pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||
}
|
||||
|
||||
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
||||
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 {
|
||||
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||
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 {
|
||||
@ -654,46 +666,6 @@ 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>)">;
|
||||
}
|
||||
|
||||
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 {
|
||||
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
|
||||
}
|
||||
|
@ -885,4 +885,9 @@ def warn_drv_openacc_without_cir
|
||||
: Warning<"OpenACC directives will result in no runtime behavior; use "
|
||||
"-fclangir to enable runtime effect">,
|
||||
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,76 +23,78 @@
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
class DiagnosticsEngine;
|
||||
class DiagnosticBuilder;
|
||||
class LangOptions;
|
||||
class SourceLocation;
|
||||
class DiagnosticsEngine;
|
||||
class DiagnosticBuilder;
|
||||
class LangOptions;
|
||||
class SourceLocation;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
enum class Group;
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
enum class Group;
|
||||
|
||||
// Size of each of the diagnostic categories.
|
||||
enum {
|
||||
DIAG_SIZE_COMMON = 300,
|
||||
DIAG_SIZE_DRIVER = 400,
|
||||
DIAG_SIZE_FRONTEND = 200,
|
||||
DIAG_SIZE_SERIALIZATION = 120,
|
||||
DIAG_SIZE_LEX = 500,
|
||||
DIAG_SIZE_PARSE = 800,
|
||||
DIAG_SIZE_AST = 300,
|
||||
DIAG_SIZE_COMMENT = 100,
|
||||
DIAG_SIZE_CROSSTU = 100,
|
||||
DIAG_SIZE_SEMA = 5000,
|
||||
DIAG_SIZE_ANALYSIS = 100,
|
||||
DIAG_SIZE_REFACTORING = 1000,
|
||||
DIAG_SIZE_INSTALLAPI = 100,
|
||||
};
|
||||
// Start position for diagnostics.
|
||||
enum {
|
||||
DIAG_START_COMMON = 0,
|
||||
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_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
||||
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
||||
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
||||
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
||||
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
||||
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
||||
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
||||
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_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
|
||||
};
|
||||
// Size of each of the diagnostic categories.
|
||||
enum {
|
||||
DIAG_SIZE_COMMON = 300,
|
||||
DIAG_SIZE_DRIVER = 400,
|
||||
DIAG_SIZE_FRONTEND = 200,
|
||||
DIAG_SIZE_SERIALIZATION = 120,
|
||||
DIAG_SIZE_LEX = 500,
|
||||
DIAG_SIZE_PARSE = 800,
|
||||
DIAG_SIZE_AST = 300,
|
||||
DIAG_SIZE_COMMENT = 100,
|
||||
DIAG_SIZE_CROSSTU = 100,
|
||||
DIAG_SIZE_SEMA = 5000,
|
||||
DIAG_SIZE_ANALYSIS = 100,
|
||||
DIAG_SIZE_REFACTORING = 1000,
|
||||
DIAG_SIZE_INSTALLAPI = 100,
|
||||
};
|
||||
// Start position for diagnostics.
|
||||
// clang-format off
|
||||
enum {
|
||||
DIAG_START_COMMON = 0,
|
||||
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_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
||||
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
||||
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
||||
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
||||
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
||||
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
||||
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
||||
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_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.
|
||||
typedef unsigned kind;
|
||||
/// All of the diagnostics that can be emitted by the frontend.
|
||||
typedef unsigned kind;
|
||||
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
||||
/// (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).
|
||||
enum class Severity : uint8_t {
|
||||
// NOTE: 0 means "uncomputed".
|
||||
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
||||
Remark = 2, ///< Present this diagnostic as a remark.
|
||||
Warning = 3, ///< Present this diagnostic as a warning.
|
||||
Error = 4, ///< Present this diagnostic as an error.
|
||||
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
||||
};
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
||||
/// (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).
|
||||
enum class Severity : uint8_t {
|
||||
// NOTE: 0 means "uncomputed".
|
||||
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
||||
Remark = 2, ///< Present this diagnostic as a remark.
|
||||
Warning = 3, ///< Present this diagnostic as a warning.
|
||||
Error = 4, ///< Present this diagnostic as an error.
|
||||
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
||||
};
|
||||
|
||||
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
||||
/// kind of diagnostic (for instance, for -W/-R flags).
|
||||
enum class Flavor {
|
||||
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
||||
///< problem. Can be made fatal by -Werror.
|
||||
Remark ///< A diagnostic that indicates normal progress through
|
||||
///< compilation.
|
||||
};
|
||||
} // end namespace diag
|
||||
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
||||
/// kind of diagnostic (for instance, for -W/-R flags).
|
||||
enum class Flavor {
|
||||
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
||||
///< problem. Can be made fatal by -Werror.
|
||||
Remark ///< A diagnostic that indicates normal progress through
|
||||
///< compilation.
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
// This has to be included *after* the DIAG_START_ enums above are defined.
|
||||
@ -173,7 +175,8 @@ public:
|
||||
|
||||
/// Used for handling and querying diagnostic IDs.
|
||||
///
|
||||
/// Can be used and shared by multiple Diagnostics for multiple translation units.
|
||||
/// Can be used and shared by multiple Diagnostics for multiple translation
|
||||
/// units.
|
||||
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
||||
public:
|
||||
/// The level of the diagnostic, after it has been through mapping.
|
||||
@ -498,6 +501,6 @@ private:
|
||||
friend class DiagnosticsEngine;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -50,6 +50,45 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -496,6 +535,72 @@ 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -35,6 +35,7 @@ def CIR_Dialect : Dialect {
|
||||
let hasConstantMaterializer = 1;
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
static llvm::StringRef getSourceLanguageAttrName() { return "cir.lang"; }
|
||||
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
|
||||
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
|
||||
static llvm::StringRef getCalleeAttrName() { return "callee"; }
|
||||
|
@ -26,6 +26,7 @@ std::unique_ptr<Pass> createCIRSimplifyPass();
|
||||
std::unique_ptr<Pass> createHoistAllocasPass();
|
||||
std::unique_ptr<Pass> createLoweringPreparePass();
|
||||
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
|
||||
std::unique_ptr<Pass> createGotoSolverPass();
|
||||
|
||||
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
|
||||
|
||||
|
@ -72,6 +72,16 @@ def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
|
||||
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"> {
|
||||
let summary = "Lower to more fine-grained CIR operations before lowering to "
|
||||
"other dialects";
|
||||
|
@ -264,6 +264,7 @@ struct MissingFeatures {
|
||||
static bool setNonGC() { return false; }
|
||||
static bool setObjCGCLValueClass() { return false; }
|
||||
static bool setTargetAttributes() { return false; }
|
||||
static bool sourceLanguageCases() { return false; }
|
||||
static bool stackBase() { return false; }
|
||||
static bool stackSaveOp() { return false; }
|
||||
static bool targetCIRGenInfoArch() { return false; }
|
||||
|
@ -32,6 +32,7 @@
|
||||
namespace llvm {
|
||||
class AttrBuilder;
|
||||
class Constant;
|
||||
class ConstantInt;
|
||||
class Function;
|
||||
class FunctionType;
|
||||
class Type;
|
||||
@ -126,6 +127,12 @@ uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD);
|
||||
uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
|
||||
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
|
||||
/// with, set the default LLVM IR attributes for a function definition.
|
||||
/// The attributes set here are mostly global target-configuration and
|
||||
|
@ -9468,8 +9468,12 @@ def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<dxc_Group>,
|
||||
def fspv_extension_EQ
|
||||
: Joined<["-"], "fspv-extension=">,
|
||||
Group<dxc_Group>,
|
||||
HelpText<"Specify the available SPIR-V extensions. If this option is not "
|
||||
"specified, then all extensions are available.">;
|
||||
HelpText<
|
||||
"Specify the available SPIR-V extensions. If this option is not "
|
||||
"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
|
||||
: DXCFlag<"fvk-use-dx-layout">,
|
||||
HelpText<"Use DirectX memory layout for Vulkan resources.">;
|
||||
|
@ -224,9 +224,6 @@ protected:
|
||||
static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
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,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
const Twine &Path);
|
||||
@ -246,6 +243,9 @@ protected:
|
||||
///@}
|
||||
|
||||
public:
|
||||
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
const Twine &Path);
|
||||
virtual ~ToolChain();
|
||||
|
||||
// Accessors
|
||||
|
@ -205,6 +205,8 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
|
||||
|
||||
if (A.isDummy() || B.isDummy())
|
||||
return false;
|
||||
if (!A.isBlockPointer() || !B.isBlockPointer())
|
||||
return false;
|
||||
|
||||
bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp ||
|
||||
ID == Builtin::BI__builtin_wcscmp ||
|
||||
@ -212,7 +214,10 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
|
||||
assert(A.getFieldDesc()->isPrimitiveArray());
|
||||
assert(B.getFieldDesc()->isPrimitiveArray());
|
||||
|
||||
assert(getElemType(A).getTypePtr() == getElemType(B).getTypePtr());
|
||||
// Different element types shouldn't happen, but with casts they can.
|
||||
if (!S.getASTContext().hasSameUnqualifiedType(getElemType(A), getElemType(B)))
|
||||
return false;
|
||||
|
||||
PrimType ElemT = *S.getContext().classify(getElemType(A));
|
||||
|
||||
auto returnResult = [&](int V) -> bool {
|
||||
@ -2778,6 +2783,40 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
|
||||
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,
|
||||
uint32_t BuiltinID) {
|
||||
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
|
||||
@ -3210,9 +3249,36 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
|
||||
case clang::X86::BI__builtin_ia32_pmuludq256:
|
||||
case clang::X86::BI__builtin_ia32_pmuludq512:
|
||||
return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID);
|
||||
|
||||
case Builtin::BI__builtin_elementwise_fma:
|
||||
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:
|
||||
S.FFDiag(S.Current->getLocation(OpPC),
|
||||
diag::note_invalid_subexpr_in_const_expr)
|
||||
|
@ -341,6 +341,8 @@ public:
|
||||
QualType getType() const {
|
||||
if (isTypeidPointer())
|
||||
return QualType(Typeid.TypeInfoType, 0);
|
||||
if (isFunctionPointer())
|
||||
return asFunctionPointer().getFunction()->getDecl()->getType();
|
||||
|
||||
if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
|
||||
// Unfortunately, complex and vector types are not array types in clang,
|
||||
|
@ -11669,13 +11669,24 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||
case clang::X86::BI__builtin_ia32_pmulhuw512:
|
||||
case clang::X86::BI__builtin_ia32_pmulhw128:
|
||||
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;
|
||||
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
|
||||
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
|
||||
return false;
|
||||
|
||||
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
|
||||
bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType();
|
||||
unsigned SourceLen = SourceLHS.getVectorLength();
|
||||
SmallVector<APValue, 4> ResultElements;
|
||||
ResultElements.reserve(SourceLen);
|
||||
@ -11687,12 +11698,12 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||
case Builtin::BI__builtin_elementwise_add_sat:
|
||||
ResultElements.push_back(APValue(
|
||||
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS),
|
||||
DestEltTy->isUnsignedIntegerOrEnumerationType())));
|
||||
DestUnsigned)));
|
||||
break;
|
||||
case Builtin::BI__builtin_elementwise_sub_sat:
|
||||
ResultElements.push_back(APValue(
|
||||
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS),
|
||||
DestEltTy->isUnsignedIntegerOrEnumerationType())));
|
||||
DestUnsigned)));
|
||||
break;
|
||||
case clang::X86::BI__builtin_ia32_pmulhuw128:
|
||||
case clang::X86::BI__builtin_ia32_pmulhuw256:
|
||||
@ -11706,6 +11717,40 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||
ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS),
|
||||
/*isUnsigned=*/false)));
|
||||
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,6 +174,9 @@ protected:
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
if (this->HasFloat128)
|
||||
Builder.defineMacro("__FLOAT128__");
|
||||
|
||||
if (Opts.C11)
|
||||
Builder.defineMacro("__STDC_NO_THREADS__");
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -73,21 +73,54 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr,
|
||||
|
||||
// Casts:
|
||||
if (auto const *ce = dyn_cast<CastExpr>(expr)) {
|
||||
if (isa<ExplicitCastExpr>(ce)) {
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
"emitPointerWithAlignment: explicit cast");
|
||||
return Address::invalid();
|
||||
}
|
||||
if (const auto *ece = dyn_cast<ExplicitCastExpr>(ce))
|
||||
cgm.emitExplicitCastExprType(ece);
|
||||
|
||||
switch (ce->getCastKind()) {
|
||||
// Non-converting casts (but not C's implicit conversion from void*).
|
||||
case CK_BitCast:
|
||||
case CK_NoOp:
|
||||
case CK_AddressSpaceConversion: {
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
"emitPointerWithAlignment: noop cast");
|
||||
return Address::invalid();
|
||||
} break;
|
||||
if (const auto *ptrTy =
|
||||
ce->getSubExpr()->getType()->getAs<PointerType>()) {
|
||||
if (ptrTy->getPointeeType()->isVoidType())
|
||||
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.
|
||||
case CK_ArrayToPointerDecay:
|
||||
@ -551,6 +584,37 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
|
||||
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) {
|
||||
const NamedDecl *nd = e->getDecl();
|
||||
QualType ty = e->getType();
|
||||
@ -607,6 +671,16 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
|
||||
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");
|
||||
return LValue();
|
||||
}
|
||||
@ -1401,11 +1475,6 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) {
|
||||
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
|
||||
// non-inline version. In that case we should pick the external one
|
||||
// everywhere. That's GCC behavior too.
|
||||
|
@ -1905,6 +1905,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
|
||||
cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
|
||||
Visit(subExpr));
|
||||
}
|
||||
case CK_FunctionToPointerDecay:
|
||||
return cgf.emitLValue(subExpr).getPointer();
|
||||
|
||||
default:
|
||||
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
|
||||
|
@ -103,6 +103,9 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
|
||||
PtrDiffTy =
|
||||
cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true);
|
||||
|
||||
theModule->setAttr(
|
||||
cir::CIRDialect::getSourceLanguageAttrName(),
|
||||
cir::SourceLanguageAttr::get(&mlirContext, getCIRSourceLanguage()));
|
||||
theModule->setAttr(cir::CIRDialect::getTripleAttrName(),
|
||||
builder.getStringAttr(getTriple().str()));
|
||||
|
||||
@ -510,6 +513,23 @@ void CIRGenModule::setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op) {
|
||||
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) {
|
||||
// Set linkage and visibility in case we never see a definition.
|
||||
LinkageInfo lv = nd->getLinkageAndVisibility();
|
||||
|
@ -461,6 +461,9 @@ private:
|
||||
void replacePointerTypeArgs(cir::FuncOp oldF, cir::FuncOp newF);
|
||||
|
||||
void setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op);
|
||||
|
||||
/// Map source language used to a CIR attribute.
|
||||
cir::SourceLanguage getCIRSourceLanguage() const;
|
||||
};
|
||||
} // namespace CIRGen
|
||||
|
||||
|
@ -424,6 +424,44 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -342,7 +342,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
|
||||
|
||||
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
|
||||
cir::ConstComplexAttr, cir::ConstRecordAttr,
|
||||
cir::GlobalViewAttr, cir::PoisonAttr>(attrType))
|
||||
cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>(
|
||||
attrType))
|
||||
return success();
|
||||
|
||||
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
|
||||
|
@ -4,6 +4,7 @@ add_clang_library(MLIRCIRTransforms
|
||||
FlattenCFG.cpp
|
||||
HoistAllocas.cpp
|
||||
LoweringPrepare.cpp
|
||||
GotoSolver.cpp
|
||||
|
||||
DEPENDS
|
||||
MLIRCIRPassIncGen
|
||||
|
57
clang/lib/CIR/Dialect/Transforms/GotoSolver.cpp
Normal file
57
clang/lib/CIR/Dialect/Transforms/GotoSolver.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//====- 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,6 +45,7 @@ namespace mlir {
|
||||
void populateCIRPreLoweringPasses(OpPassManager &pm) {
|
||||
pm.addPass(createHoistAllocasPass());
|
||||
pm.addPass(createCIRFlattenCFGPass());
|
||||
pm.addPass(createGotoSolverPass());
|
||||
}
|
||||
|
||||
} // namespace mlir
|
||||
|
@ -4184,7 +4184,14 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
|
||||
break;
|
||||
}
|
||||
|
||||
RegionMap[RD].reset(RealDecl);
|
||||
if (auto *CTSD =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(Ty->getOriginalDecl())) {
|
||||
CXXRecordDecl *TemplateDecl =
|
||||
CTSD->getSpecializedTemplate()->getTemplatedDecl();
|
||||
RegionMap[TemplateDecl].reset(RealDecl);
|
||||
} else {
|
||||
RegionMap[RD].reset(RealDecl);
|
||||
}
|
||||
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
|
||||
|
||||
if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
||||
|
@ -977,6 +977,8 @@ public:
|
||||
ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn);
|
||||
/// Restore everything back to the original state.
|
||||
~ApplyInlineDebugLocation();
|
||||
ApplyInlineDebugLocation(const ApplyInlineDebugLocation &) = delete;
|
||||
ApplyInlineDebugLocation &operator=(ApplyInlineDebugLocation &) = delete;
|
||||
};
|
||||
|
||||
class SanitizerDebugLocation {
|
||||
@ -988,6 +990,8 @@ public:
|
||||
ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
|
||||
SanitizerHandler Handler);
|
||||
~SanitizerDebugLocation();
|
||||
SanitizerDebugLocation(const SanitizerDebugLocation &) = delete;
|
||||
SanitizerDebugLocation &operator=(SanitizerDebugLocation &) = delete;
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
|
@ -466,6 +466,14 @@ llvm::Constant *CodeGenModule::getConstantSignedPointer(
|
||||
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
|
||||
/// functionType.
|
||||
llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
|
||||
|
@ -1409,13 +1409,6 @@ void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
|
||||
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"
|
||||
/// semantics to CC1 arguments.
|
||||
///
|
||||
@ -1438,6 +1431,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
|
||||
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.
|
||||
void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args,
|
||||
|
@ -534,7 +534,14 @@ void Flang::addTargetOptions(const ArgList &Args,
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -2123,10 +2123,11 @@ void Generic_GCC::GCCInstallationDetector::init(
|
||||
StringRef TripleText =
|
||||
llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
|
||||
|
||||
Version = GCCVersion::Parse(VersionText);
|
||||
GCCTriple.setTriple(TripleText);
|
||||
GCCInstallPath = std::string(InstallDir);
|
||||
GCCParentLibPath = GCCInstallPath + "/../../..";
|
||||
SelectedInstallation.Version = GCCVersion::Parse(VersionText);
|
||||
SelectedInstallation.GCCTriple.setTriple(TripleText);
|
||||
SelectedInstallation.GCCInstallPath = std::string(InstallDir);
|
||||
SelectedInstallation.GCCParentLibPath =
|
||||
SelectedInstallation.GCCInstallPath + "/../../..";
|
||||
IsValid = true;
|
||||
}
|
||||
return;
|
||||
@ -2186,7 +2187,7 @@ void Generic_GCC::GCCInstallationDetector::init(
|
||||
// Loop over the various components which exist and select the best GCC
|
||||
// installation available. GCC installs are ranked by version number.
|
||||
const GCCVersion VersionZero = GCCVersion::Parse("0.0.0");
|
||||
Version = VersionZero;
|
||||
SelectedInstallation.Version = VersionZero;
|
||||
for (const std::string &Prefix : Prefixes) {
|
||||
auto &VFS = D.getVFS();
|
||||
if (!VFS.exists(Prefix))
|
||||
@ -2214,7 +2215,7 @@ void Generic_GCC::GCCInstallationDetector::init(
|
||||
}
|
||||
|
||||
// Skip other prefixes once a GCC installation is found.
|
||||
if (Version > VersionZero)
|
||||
if (SelectedInstallation.Version > VersionZero)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2223,14 +2224,17 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
|
||||
for (const auto &InstallPath : CandidateGCCInstallPaths)
|
||||
OS << "Found candidate GCC installation: " << InstallPath << "\n";
|
||||
|
||||
if (!GCCInstallPath.empty())
|
||||
OS << "Selected GCC installation: " << GCCInstallPath << "\n";
|
||||
if (!SelectedInstallation.GCCInstallPath.empty())
|
||||
OS << "Selected GCC installation: " << SelectedInstallation.GCCInstallPath
|
||||
<< "\n";
|
||||
|
||||
for (const auto &Multilib : Multilibs)
|
||||
OS << "Candidate multilib: " << Multilib << "\n";
|
||||
|
||||
if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
|
||||
OS << "Selected multilib: " << SelectedMultilib << "\n";
|
||||
if (Multilibs.size() != 0 ||
|
||||
!SelectedInstallation.SelectedMultilib.isDefault())
|
||||
OS << "Selected multilib: " << SelectedInstallation.SelectedMultilib
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
|
||||
@ -2768,14 +2772,50 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
|
||||
}
|
||||
|
||||
Multilibs = Detected.Multilibs;
|
||||
SelectedMultilib = Detected.SelectedMultilibs.empty()
|
||||
? Multilib()
|
||||
: Detected.SelectedMultilibs.back();
|
||||
SelectedInstallation.SelectedMultilib =
|
||||
Detected.SelectedMultilibs.empty() ? Multilib()
|
||||
: Detected.SelectedMultilibs.back();
|
||||
BiarchSibling = Detected.BiarchSibling;
|
||||
|
||||
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(
|
||||
const llvm::Triple &TargetTriple, const ArgList &Args,
|
||||
const std::string &LibDir, StringRef CandidateTriple,
|
||||
@ -2805,6 +2845,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
||||
TargetTriple.getVendor() == llvm::Triple::Freescale ||
|
||||
TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}};
|
||||
|
||||
SmallVector<GCCInstallCandidate, 3> Installations;
|
||||
for (auto &Suffix : Suffixes) {
|
||||
if (!Suffix.Active)
|
||||
continue;
|
||||
@ -2822,23 +2863,31 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
||||
continue; // Saw this path before; no need to look at it again.
|
||||
if (CandidateVersion.isOlderThan(4, 1, 1))
|
||||
continue;
|
||||
if (CandidateVersion <= Version)
|
||||
if (CandidateVersion <= SelectedInstallation.Version && IsValid)
|
||||
continue;
|
||||
|
||||
if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(),
|
||||
NeedsBiarchSuffix))
|
||||
continue;
|
||||
|
||||
Version = CandidateVersion;
|
||||
GCCTriple.setTriple(CandidateTriple);
|
||||
GCCInstallCandidate Installation;
|
||||
Installation.Version = CandidateVersion;
|
||||
Installation.GCCTriple.setTriple(CandidateTriple);
|
||||
// FIXME: We hack together the directory name here instead of
|
||||
// using LI to ensure stable path separators across Windows and
|
||||
// Linux.
|
||||
GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str();
|
||||
GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str();
|
||||
IsValid = true;
|
||||
Installation.GCCInstallPath =
|
||||
(LibDir + "/" + LibSuffix + "/" + VersionText).str();
|
||||
Installation.GCCParentLibPath =
|
||||
(Installation.GCCInstallPath + "/../" + Suffix.ReversePath).str();
|
||||
Installation.SelectedMultilib = getMultilib();
|
||||
|
||||
Installations.push_back(Installation);
|
||||
}
|
||||
}
|
||||
|
||||
IsValid |=
|
||||
SelectGCCInstallationDirectory(Installations, Args, SelectedInstallation);
|
||||
}
|
||||
|
||||
bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
|
||||
@ -2916,10 +2965,12 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
|
||||
NeedsBiarchSuffix))
|
||||
continue;
|
||||
|
||||
Version = GCCVersion::Parse(ActiveVersion.second);
|
||||
GCCInstallPath = GentooPath;
|
||||
GCCParentLibPath = GentooPath + std::string("/../../..");
|
||||
GCCTriple.setTriple(ActiveVersion.first);
|
||||
SelectedInstallation.Version =
|
||||
GCCVersion::Parse(ActiveVersion.second);
|
||||
SelectedInstallation.GCCInstallPath = GentooPath;
|
||||
SelectedInstallation.GCCParentLibPath =
|
||||
GentooPath + std::string("/../../..");
|
||||
SelectedInstallation.GCCTriple.setTriple(ActiveVersion.first);
|
||||
IsValid = true;
|
||||
return true;
|
||||
}
|
||||
@ -3122,8 +3173,9 @@ void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs,
|
||||
// gcc TOOL_INCLUDE_DIR.
|
||||
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
|
||||
std::string LibPath(GCCInstallation.getParentLibPath());
|
||||
addSystemInclude(DriverArgs, CC1Args,
|
||||
Twine(LibPath) + "/../" + GCCTriple.str() + "/include");
|
||||
ToolChain::addSystemInclude(DriverArgs, CC1Args,
|
||||
Twine(LibPath) + "/../" + GCCTriple.str() +
|
||||
"/include");
|
||||
|
||||
const auto &Callback = Multilibs.includeDirsCallback();
|
||||
if (Callback) {
|
||||
@ -3210,12 +3262,14 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
return;
|
||||
}
|
||||
|
||||
bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||
Twine IncludeSuffix,
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
bool DetectDebian) const {
|
||||
if (!getVFS().exists(IncludeDir))
|
||||
static bool addLibStdCXXIncludePaths(llvm::vfs::FileSystem &vfs,
|
||||
Twine IncludeDir, StringRef Triple,
|
||||
Twine IncludeSuffix,
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
bool DetectDebian = false) {
|
||||
|
||||
if (!vfs.exists(IncludeDir))
|
||||
return false;
|
||||
|
||||
// Debian native gcc uses g++-multiarch-incdir.diff which uses
|
||||
@ -3227,39 +3281,48 @@ bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||
std::string Path =
|
||||
(Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix)
|
||||
.str();
|
||||
if (DetectDebian && !getVFS().exists(Path))
|
||||
if (DetectDebian && !vfs.exists(Path))
|
||||
return false;
|
||||
|
||||
// GPLUSPLUS_INCLUDE_DIR
|
||||
addSystemInclude(DriverArgs, CC1Args, IncludeDir);
|
||||
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir);
|
||||
// GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent
|
||||
// include directory.
|
||||
if (DetectDebian)
|
||||
addSystemInclude(DriverArgs, CC1Args, Path);
|
||||
ToolChain::addSystemInclude(DriverArgs, CC1Args, Path);
|
||||
else if (!Triple.empty())
|
||||
addSystemInclude(DriverArgs, CC1Args,
|
||||
IncludeDir + "/" + Triple + IncludeSuffix);
|
||||
ToolChain::addSystemInclude(DriverArgs, CC1Args,
|
||||
IncludeDir + "/" + Triple + IncludeSuffix);
|
||||
// GPLUSPLUS_BACKWARD_INCLUDE_DIR
|
||||
addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
|
||||
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
||||
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
|
||||
StringRef DebianMultiarch) const {
|
||||
assert(GCCInstallation.isValid());
|
||||
bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||
Twine IncludeSuffix,
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
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
|
||||
// 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.
|
||||
StringRef LibDir = GCCInstallation.getParentLibPath();
|
||||
StringRef InstallDir = GCCInstallation.getInstallPath();
|
||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
||||
const Multilib &Multilib = GCCInstallation.getMultilib();
|
||||
const GCCVersion &Version = GCCInstallation.getVersion();
|
||||
StringRef LibDir = getParentLibPath();
|
||||
StringRef InstallDir = getInstallPath();
|
||||
StringRef TripleStr = getTriple().str();
|
||||
const Multilib &Multilib = getMultilib();
|
||||
const GCCVersion &Version = getVersion();
|
||||
|
||||
// Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty).
|
||||
if (addLibStdCXXIncludePaths(
|
||||
if (::addLibStdCXXIncludePaths(
|
||||
vfs,
|
||||
LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text,
|
||||
TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args))
|
||||
return true;
|
||||
@ -3267,22 +3330,24 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
||||
// Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not
|
||||
// empty). Like above but for GCC built with
|
||||
// --enable-version-specific-runtime-libs.
|
||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" +
|
||||
Version.Text + "/include/c++/",
|
||||
TripleStr, Multilib.includeSuffix(), DriverArgs,
|
||||
CC1Args))
|
||||
if (::addLibStdCXXIncludePaths(vfs,
|
||||
LibDir.str() + "/gcc/" + TripleStr + "/" +
|
||||
Version.Text + "/include/c++/",
|
||||
TripleStr, Multilib.includeSuffix(),
|
||||
DriverArgs, CC1Args))
|
||||
return true;
|
||||
|
||||
// Detect Debian g++-multiarch-incdir.diff.
|
||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
|
||||
DebianMultiarch, Multilib.includeSuffix(),
|
||||
DriverArgs, CC1Args, /*Debian=*/true))
|
||||
if (::addLibStdCXXIncludePaths(
|
||||
vfs, LibDir.str() + "/../include/c++/" + Version.Text,
|
||||
DebianMultiarch, Multilib.includeSuffix(), DriverArgs, CC1Args,
|
||||
/*Debian=*/true))
|
||||
return true;
|
||||
|
||||
// Try /../include/c++/$version (gcc --print-multiarch is empty).
|
||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
|
||||
TripleStr, Multilib.includeSuffix(), DriverArgs,
|
||||
CC1Args))
|
||||
if (::addLibStdCXXIncludePaths(
|
||||
vfs, LibDir.str() + "/../include/c++/" + Version.Text, TripleStr,
|
||||
Multilib.includeSuffix(), DriverArgs, CC1Args))
|
||||
return true;
|
||||
|
||||
// Otherwise, fall back on a bunch of options which don't use multiarch
|
||||
@ -3297,20 +3362,50 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
||||
};
|
||||
|
||||
for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
|
||||
if (addLibStdCXXIncludePaths(IncludePath, TripleStr,
|
||||
Multilib.includeSuffix(), DriverArgs, CC1Args))
|
||||
if (::addLibStdCXXIncludePaths(vfs, IncludePath, TripleStr,
|
||||
Multilib.includeSuffix(), DriverArgs,
|
||||
CC1Args))
|
||||
return true;
|
||||
}
|
||||
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
|
||||
Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const {
|
||||
if (GCCInstallation.isValid()) {
|
||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
|
||||
GCCInstallation.getTriple().str());
|
||||
}
|
||||
if (!GCCInstallation.isValid())
|
||||
return;
|
||||
|
||||
GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths(
|
||||
getVFS(), DriverArgs, CC1Args, GCCInstallation.getTriple().str());
|
||||
}
|
||||
|
||||
llvm::opt::DerivedArgList *
|
||||
|
@ -184,46 +184,18 @@ public:
|
||||
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
struct GCCInstallCandidate {
|
||||
// FIXME: These might be better as path objects.
|
||||
std::string GCCInstallPath;
|
||||
std::string GCCParentLibPath;
|
||||
|
||||
llvm::Triple GCCTriple;
|
||||
|
||||
/// The primary multilib appropriate for the given flags.
|
||||
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;
|
||||
|
||||
// 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.
|
||||
const llvm::Triple &getTriple() const { return GCCTriple; }
|
||||
|
||||
@ -236,6 +208,88 @@ public:
|
||||
/// Get the detected Multilib
|
||||
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
|
||||
const MultilibSet &getMultilibs() const { return Multilibs; }
|
||||
|
||||
@ -244,7 +298,9 @@ public:
|
||||
bool getBiarchSibling(Multilib &M) const;
|
||||
|
||||
/// Get the detected GCC version string.
|
||||
const GCCVersion &getVersion() const { return Version; }
|
||||
const GCCVersion &getVersion() const {
|
||||
return SelectedInstallation.Version;
|
||||
}
|
||||
|
||||
/// Print information about the detected GCC installation.
|
||||
void print(raw_ostream &OS) const;
|
||||
@ -262,6 +318,19 @@ public:
|
||||
SmallVectorImpl<std::string> &Prefixes,
|
||||
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,
|
||||
const llvm::opt::ArgList &Args, StringRef Path,
|
||||
bool NeedsBiarchSuffix = false);
|
||||
@ -348,8 +417,7 @@ protected:
|
||||
llvm::opt::ArgStringList &CC1Args) const;
|
||||
|
||||
bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
StringRef DebianMultiarch) const;
|
||||
llvm::opt::ArgStringList &CC) const;
|
||||
|
||||
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||
Twine IncludeSuffix,
|
||||
|
@ -173,24 +173,72 @@ bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string getSpirvExtArg(ArrayRef<std::string> SpvExtensionArgs) {
|
||||
if (SpvExtensionArgs.empty()) {
|
||||
return "-spirv-ext=all";
|
||||
void getSpirvExtOperand(StringRef SpvExtensionArg, raw_ostream &out) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
std::string LlvmOption =
|
||||
(Twine("-spirv-ext=+") + SpvExtensionArgs.front()).str();
|
||||
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()) {
|
||||
return StringRef("-spirv-ext=all");
|
||||
}
|
||||
|
||||
llvm::SmallString<1024> LlvmOption;
|
||||
raw_svector_ostream out(LlvmOption);
|
||||
|
||||
out << "-spirv-ext=";
|
||||
getSpirvExtOperand(SpvExtensionArgs[0], out);
|
||||
|
||||
SpvExtensionArgs = SpvExtensionArgs.slice(1);
|
||||
for (auto Extension : SpvExtensionArgs) {
|
||||
if (Extension != "KHR")
|
||||
Extension = (Twine("+") + Extension).str();
|
||||
LlvmOption = (Twine(LlvmOption) + "," + Extension).str();
|
||||
for (StringRef Extension : SpvExtensionArgs) {
|
||||
out << ",";
|
||||
getSpirvExtOperand(Extension, out);
|
||||
}
|
||||
return LlvmOption;
|
||||
}
|
||||
|
||||
bool isValidSPIRVExtensionName(const std::string &str) {
|
||||
std::regex pattern("KHR|SPV_[a-zA-Z0-9_]+");
|
||||
std::regex pattern("dxc|DXC|khr|KHR|SPV_[a-zA-Z0-9_]+");
|
||||
return std::regex_match(str, pattern);
|
||||
}
|
||||
|
||||
@ -371,7 +419,7 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
|
||||
std::vector<std::string> SpvExtensionArgs =
|
||||
Args.getAllArgValues(options::OPT_fspv_extension_EQ);
|
||||
if (checkExtensionArgsAreValid(SpvExtensionArgs, getDriver())) {
|
||||
std::string LlvmOption = getSpirvExtArg(SpvExtensionArgs);
|
||||
SmallString<1024> LlvmOption = getSpirvExtArg(SpvExtensionArgs);
|
||||
DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_mllvm),
|
||||
LlvmOption);
|
||||
}
|
||||
|
@ -71,6 +71,13 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
|
||||
|
||||
Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &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);
|
||||
Multilibs = GCCInstallation.getMultilibs();
|
||||
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
||||
@ -207,12 +214,7 @@ void Hurd::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
if (!GCCInstallation.isValid())
|
||||
return;
|
||||
|
||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
||||
StringRef DebianMultiarch =
|
||||
GCCInstallation.getTriple().getArch() == llvm::Triple::x86 ? "i386-gnu"
|
||||
: TripleStr;
|
||||
|
||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, DebianMultiarch);
|
||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
|
||||
|
@ -211,6 +211,13 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
|
||||
|
||||
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &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);
|
||||
Multilibs = GCCInstallation.getMultilibs();
|
||||
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
||||
@ -693,22 +700,15 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
if (!GCCInstallation.isValid())
|
||||
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.
|
||||
if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
|
||||
DebianMultiarch))
|
||||
if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args))
|
||||
return;
|
||||
|
||||
StringRef LibDir = GCCInstallation.getParentLibPath();
|
||||
const Multilib &Multilib = GCCInstallation.getMultilib();
|
||||
const GCCVersion &Version = GCCInstallation.getVersion();
|
||||
|
||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
||||
const std::string LibStdCXXIncludePathCandidates[] = {
|
||||
// Android standalone toolchain has C++ headers in yet another place.
|
||||
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
|
||||
|
@ -193,10 +193,8 @@ void Managarm::addLibStdCxxIncludePaths(
|
||||
if (!GCCInstallation.isValid())
|
||||
return;
|
||||
|
||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
||||
|
||||
// Try generic GCC detection.
|
||||
Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, TripleStr);
|
||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
SanitizerMask Managarm::getSupportedSanitizers() const {
|
||||
|
@ -16,8 +16,7 @@
|
||||
#define _NULLPTR_T
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus >= 201103L || \
|
||||
(defined(_MSC_EXTENSIONS) && defined(_NATIVE_NULLPTR_SUPPORTED))
|
||||
#if defined(_MSC_EXTENSIONS) && defined(_NATIVE_NULLPTR_SUPPORTED)
|
||||
namespace std {
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
}
|
||||
|
@ -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
|
||||
/// bits).
|
||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||
_mm256_sllv_epi32(__m256i __X, __m256i __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
|
||||
/// bits).
|
||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||
_mm_sllv_epi32(__m128i __X, __m128i __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
|
||||
/// bits).
|
||||
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||
_mm256_sllv_epi64(__m256i __X, __m256i __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
|
||||
/// bits).
|
||||
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||
_mm_sllv_epi64(__m128i __X, __m128i __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
|
||||
/// bits).
|
||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||
_mm256_srav_epi32(__m256i __X, __m256i __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
|
||||
/// bits).
|
||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||
_mm_srav_epi32(__m128i __X, __m128i __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
|
||||
/// bits).
|
||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||
_mm256_srlv_epi32(__m256i __X, __m256i __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
|
||||
/// bits).
|
||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||
_mm_srlv_epi32(__m128i __X, __m128i __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
|
||||
/// bits).
|
||||
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||
_mm256_srlv_epi64(__m256i __X, __m256i __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
|
||||
/// bits).
|
||||
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||
_mm_srlv_epi64(__m128i __X, __m128i __Y)
|
||||
{
|
||||
return (__m128i)__builtin_ia32_psrlv2di((__v2di)__X, (__v2di)__Y);
|
||||
|
@ -5601,8 +5601,10 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
|
||||
TheCall->getArg(1)->getEndLoc()));
|
||||
} else if (numElements != numResElements) {
|
||||
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
|
||||
resType =
|
||||
Context.getVectorType(eltType, numResElements, VectorKind::Generic);
|
||||
resType = resType->isExtVectorType()
|
||||
? Context.getExtVectorType(eltType, numResElements)
|
||||
: Context.getVectorType(eltType, numResElements,
|
||||
VectorKind::Generic);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,3 +338,12 @@ 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,7 +15,6 @@ using FourFloatsExtVec __attribute__((ext_vector_type(4))) = float;
|
||||
using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double;
|
||||
using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128;
|
||||
|
||||
|
||||
// Next a series of tests to make sure these operations are usable in
|
||||
// constexpr functions. Template instantiations don't emit Winvalid-constexpr,
|
||||
// so we have to do these as macros.
|
||||
@ -875,3 +874,9 @@ void BoolVecUsage() {
|
||||
constexpr auto k = ~FourBoolsExtVec{true, false, true, false};
|
||||
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,3 +732,8 @@ namespace LocalVarForParmVarDecl {
|
||||
}
|
||||
static_assert(foo(), "");
|
||||
}
|
||||
|
||||
namespace PtrPtrCast {
|
||||
void foo() { ; }
|
||||
void bar(int *a) { a = (int *)(void *)(foo); }
|
||||
}
|
||||
|
47
clang/test/CIR/CodeGen/function-to-pointer-decay.c
Normal file
47
clang/test/CIR/CodeGen/function-to-pointer-decay.c
Normal file
@ -0,0 +1,47 @@
|
||||
// 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,5 +1,7 @@
|
||||
// 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: %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: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
|
||||
|
||||
@ -27,6 +29,24 @@ err:
|
||||
// CIR: cir.store [[MINUS]], [[RETVAL]] : !s32i, !cir.ptr<!s32i>
|
||||
// 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: if.then:
|
||||
// OGCG: br label %err
|
||||
@ -51,6 +71,17 @@ err:
|
||||
// CIR: ^bb1:
|
||||
// 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: if.then:
|
||||
// OGCG: br label %err
|
||||
@ -78,6 +109,15 @@ end2:
|
||||
// CIR: ^bb[[#BLK3]]:
|
||||
// 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: br label %end1
|
||||
// OGCG: end1:
|
||||
@ -99,6 +139,13 @@ end:
|
||||
// CIR: ^bb[[#BLK2:]]:
|
||||
// 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: br label %end
|
||||
// OGCG: end:
|
||||
@ -126,6 +173,14 @@ extern "C" void multiple_non_case(int v) {
|
||||
// CIR: cir.call @action2()
|
||||
// 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: sw.default:
|
||||
// OGCG: call void @action1()
|
||||
@ -158,6 +213,26 @@ extern "C" void case_follow_label(int v) {
|
||||
// CIR: cir.call @action2()
|
||||
// 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: sw.bb:
|
||||
// OGCG: br label %label
|
||||
@ -197,6 +272,26 @@ extern "C" void default_follow_label(int v) {
|
||||
// CIR: cir.call @action2()
|
||||
// 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: sw.bb:
|
||||
// OGCG: call void @action1()
|
||||
|
@ -1,5 +1,7 @@
|
||||
// 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: %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: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
|
||||
|
||||
@ -12,8 +14,8 @@ labelA:
|
||||
// CIR: cir.label "labelA"
|
||||
// CIR: cir.return
|
||||
|
||||
// Note: We are not lowering to LLVM IR via CIR at this stage because that
|
||||
// process depends on the GotoSolver.
|
||||
// LLVM:define dso_local void @label
|
||||
// LLVM: ret void
|
||||
|
||||
// OGCG: define dso_local void @label
|
||||
// OGCG: br label %labelA
|
||||
@ -33,6 +35,11 @@ labelC:
|
||||
// CIR: cir.label "labelC"
|
||||
// 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: br label %labelB
|
||||
// OGCG: labelB:
|
||||
@ -56,6 +63,22 @@ labelD:
|
||||
// CIR: }
|
||||
// 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: if.then:
|
||||
// OGCG: br label %labelD
|
||||
@ -80,6 +103,13 @@ void after_return() {
|
||||
// CIR: cir.label "label"
|
||||
// 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: br label %label
|
||||
// OGCG: label:
|
||||
@ -97,6 +127,11 @@ void after_unreachable() {
|
||||
// CIR: cir.label "label"
|
||||
// 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: unreachable
|
||||
// OGCG: label:
|
||||
@ -111,6 +146,9 @@ end:
|
||||
// CIR: cir.return
|
||||
// CIR: }
|
||||
|
||||
// LLVM: define dso_local void @labelWithoutMatch
|
||||
// LLVM: ret void
|
||||
|
||||
// OGCG: define dso_local void @labelWithoutMatch
|
||||
// OGCG: br label %end
|
||||
// OGCG: end:
|
||||
@ -132,6 +170,15 @@ void foo() {
|
||||
// CIR: cir.label "label"
|
||||
// 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: %agg.tmp = alloca %struct.S, align 1
|
||||
// OGCG: %undef.agg.tmp = alloca %struct.S, align 1
|
||||
|
11
clang/test/CIR/CodeGen/lang-c-cpp.cpp
Normal file
11
clang/test/CIR/CodeGen/lang-c-cpp.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
// 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;
|
||||
}
|
5
clang/test/CIR/IR/invalid-lang-attr.cir
Normal file
5
clang/test/CIR/IR/invalid-lang-attr.cir
Normal file
@ -0,0 +1,5 @@
|
||||
// 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
|
||||
// RUN: cir-opt %s -verify-diagnostics -split-input-file
|
||||
|
||||
!s8i = !cir.int<s, 8>
|
||||
!u32i = !cir.int<u, 32>
|
||||
@ -7,3 +7,67 @@ cir.func @reference_unknown_vtable() {
|
||||
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
|
||||
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>)
|
||||
}
|
||||
|
12
clang/test/CIR/IR/module.cir
Normal file
12
clang/test/CIR/IR/module.cir
Normal file
@ -0,0 +1,12 @@
|
||||
// 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>}
|
19
clang/test/CIR/IR/vtable-attr.cir
Normal file
19
clang/test/CIR/IR/vtable-attr.cir
Normal file
@ -0,0 +1,19 @@
|
||||
// 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>)
|
||||
}
|
52
clang/test/CIR/Lowering/goto.cir
Normal file
52
clang/test/CIR/Lowering/goto.cir
Normal file
@ -0,0 +1,52 @@
|
||||
// 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,7 +327,6 @@ __m256i test_mm256_cvtepi8_epi16(__m128i a) {
|
||||
// CHECK: sext <16 x i8> %{{.*}} to <16 x i16>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepi8_epi32(__m128i a) {
|
||||
@ -336,7 +335,6 @@ __m256i test_mm256_cvtepi8_epi32(__m128i a) {
|
||||
// CHECK: sext <8 x i8> %{{.*}} to <8 x i32>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepi8_epi64(__m128i a) {
|
||||
@ -345,7 +343,6 @@ __m256i test_mm256_cvtepi8_epi64(__m128i a) {
|
||||
// CHECK: sext <4 x i8> %{{.*}} to <4 x i64>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepi16_epi32(__m128i a) {
|
||||
@ -353,7 +350,6 @@ __m256i test_mm256_cvtepi16_epi32(__m128i a) {
|
||||
// CHECK: sext <8 x i16> %{{.*}} to <8 x i32>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepi16_epi64(__m128i a) {
|
||||
@ -362,7 +358,6 @@ __m256i test_mm256_cvtepi16_epi64(__m128i a) {
|
||||
// CHECK: sext <4 x i16> %{{.*}} to <4 x i64>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepi32_epi64(__m128i a) {
|
||||
@ -370,7 +365,6 @@ __m256i test_mm256_cvtepi32_epi64(__m128i a) {
|
||||
// CHECK: sext <4 x i32> %{{.*}} to <4 x i64>
|
||||
return _mm256_cvtepi32_epi64(a);
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -378,7 +372,6 @@ __m256i test_mm256_cvtepu8_epi16(__m128i a) {
|
||||
// CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepu8_epi32(__m128i a) {
|
||||
@ -387,7 +380,6 @@ __m256i test_mm256_cvtepu8_epi32(__m128i a) {
|
||||
// CHECK: zext <8 x i8> %{{.*}} to <8 x i32>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepu8_epi64(__m128i a) {
|
||||
@ -396,7 +388,6 @@ __m256i test_mm256_cvtepu8_epi64(__m128i a) {
|
||||
// CHECK: zext <4 x i8> %{{.*}} to <4 x i64>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepu16_epi32(__m128i a) {
|
||||
@ -404,7 +395,6 @@ __m256i test_mm256_cvtepu16_epi32(__m128i a) {
|
||||
// CHECK: zext <8 x i16> {{.*}} to <8 x i32>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepu16_epi64(__m128i a) {
|
||||
@ -413,7 +403,6 @@ __m256i test_mm256_cvtepu16_epi64(__m128i a) {
|
||||
// CHECK: zext <4 x i16> %{{.*}} to <4 x i64>
|
||||
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));
|
||||
|
||||
__m256i test_mm256_cvtepu32_epi64(__m128i a) {
|
||||
@ -421,7 +410,6 @@ __m256i test_mm256_cvtepu32_epi64(__m128i a) {
|
||||
// CHECK: zext <4 x i32> %{{.*}} to <4 x i64>
|
||||
return _mm256_cvtepu32_epi64(a);
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -1120,24 +1108,28 @@ __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> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_sllv_epi32
|
||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psllv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm_sllv_epi64
|
||||
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psllv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_sllv_epi64
|
||||
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psllv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_sra_epi16
|
||||
@ -1180,12 +1172,14 @@ __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> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_srav_epi32
|
||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psrav.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_srl_epi16
|
||||
@ -1252,24 +1246,28 @@ __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> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_srlv_epi32
|
||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psrlv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm_srlv_epi64
|
||||
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psrlv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_srlv_epi64
|
||||
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psrlv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
||||
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) {
|
||||
// CHECK-LABEL: test_mm256_stream_load_si256
|
||||
|
@ -3,6 +3,11 @@
|
||||
// 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 -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 "builtin_test_helpers.h"
|
||||
|
||||
|
12
clang/test/DebugInfo/CXX/dependent-template-type-scope.cpp
Normal file
12
clang/test/DebugInfo/CXX/dependent-template-type-scope.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=standalone -o - %s | FileCheck %s
|
||||
|
||||
template <typename T = int>
|
||||
struct Y {
|
||||
typedef int outside;
|
||||
outside o;
|
||||
};
|
||||
|
||||
Y<> y;
|
||||
|
||||
// CHECK: ![[Y:.*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y<int>", {{.*}}identifier: "_ZTS1YIiE")
|
||||
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "outside", scope: ![[Y]],
|
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