Compare commits
20 Commits
main
...
users/myst
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9265309f0c | ||
![]() |
b7f8a9c8b4 | ||
![]() |
68761d9bf3 | ||
![]() |
d11cfe5d18 | ||
![]() |
435ba3597b | ||
![]() |
dff521f73d | ||
![]() |
40bafe2ceb | ||
![]() |
341dd6a3ca | ||
![]() |
75c4d315dc | ||
![]() |
904c996355 | ||
![]() |
a6220fef9b | ||
![]() |
20f2ad062c | ||
![]() |
6fc858761e | ||
![]() |
57ba236e87 | ||
![]() |
07ccb63a1b | ||
![]() |
dd58f21c9e | ||
![]() |
bd4dd9ca02 | ||
![]() |
5a056672cb | ||
![]() |
0e830ad120 | ||
![]() |
f3fdeff3e3 |
@ -49,7 +49,8 @@ DEPENDENTS_TO_TEST = {
|
|||||||
"flang",
|
"flang",
|
||||||
},
|
},
|
||||||
"lld": {"bolt", "cross-project-tests"},
|
"lld": {"bolt", "cross-project-tests"},
|
||||||
"clang": {"clang-tools-extra", "cross-project-tests", "lldb"},
|
# TODO(issues/132795): LLDB should be enabled on clang changes.
|
||||||
|
"clang": {"clang-tools-extra", "cross-project-tests"},
|
||||||
"mlir": {"flang"},
|
"mlir": {"flang"},
|
||||||
# Test everything if ci scripts are changed.
|
# Test everything if ci scripts are changed.
|
||||||
".ci": {
|
".ci": {
|
||||||
|
@ -83,11 +83,11 @@ class TestComputeProjects(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["projects_to_build"],
|
env_variables["projects_to_build"],
|
||||||
"clang;clang-tools-extra;lld;lldb;llvm",
|
"clang;clang-tools-extra;lld;llvm",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["project_check_targets"],
|
env_variables["project_check_targets"],
|
||||||
"check-clang check-clang-tools check-lldb",
|
"check-clang check-clang-tools",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"
|
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"
|
||||||
@ -158,11 +158,11 @@ class TestComputeProjects(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["projects_to_build"],
|
env_variables["projects_to_build"],
|
||||||
"clang;clang-tools-extra;lld;lldb;llvm;mlir",
|
"clang;clang-tools-extra;lld;llvm;mlir",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["project_check_targets"],
|
env_variables["project_check_targets"],
|
||||||
"check-clang check-clang-cir check-clang-tools check-lldb",
|
"check-clang check-clang-cir check-clang-tools",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"
|
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"
|
||||||
|
@ -60,8 +60,7 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \
|
|||||||
-D MLIR_ENABLE_BINDINGS_PYTHON=ON \
|
-D MLIR_ENABLE_BINDINGS_PYTHON=ON \
|
||||||
-D LLDB_ENABLE_PYTHON=ON \
|
-D LLDB_ENABLE_PYTHON=ON \
|
||||||
-D LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS=ON \
|
-D LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS=ON \
|
||||||
-D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
|
-D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}"
|
||||||
-D CMAKE_EXE_LINKER_FLAGS="-no-pie"
|
|
||||||
|
|
||||||
start-group "ninja"
|
start-group "ninja"
|
||||||
|
|
||||||
|
2
.github/workflows/pr-code-format.yml
vendored
2
.github/workflows/pr-code-format.yml
vendored
@ -70,6 +70,8 @@ jobs:
|
|||||||
- name: Run code formatter
|
- name: Run code formatter
|
||||||
env:
|
env:
|
||||||
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
START_REV: ${{ github.event.pull_request.base.sha }}
|
||||||
|
END_REV: ${{ github.event.pull_request.head.sha }}
|
||||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
# Create an empty comments file so the pr-write job doesn't fail.
|
# Create an empty comments file so the pr-write job doesn't fail.
|
||||||
run: |
|
run: |
|
||||||
|
10
.github/workflows/premerge.yaml
vendored
10
.github/workflows/premerge.yaml
vendored
@ -69,11 +69,6 @@ jobs:
|
|||||||
|
|
||||||
./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" "${runtimes_check_targets_needs_reconfig}" "${enable_cir}"
|
./.ci/monolithic-linux.sh "${projects_to_build}" "${project_check_targets}" "${runtimes_to_build}" "${runtimes_check_targets}" "${runtimes_check_targets_needs_reconfig}" "${enable_cir}"
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
# In some cases, Github will fail to upload the artifact. We want to
|
|
||||||
# continue anyways as a failed artifact upload is an infra failure, not
|
|
||||||
# a checks failure.
|
|
||||||
# https://github.com/actions/upload-artifact/issues/569
|
|
||||||
continue-on-error: true
|
|
||||||
if: '!cancelled()'
|
if: '!cancelled()'
|
||||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||||
with:
|
with:
|
||||||
@ -119,11 +114,6 @@ jobs:
|
|||||||
# these environment variables.
|
# these environment variables.
|
||||||
bash -c "export SCCACHE_GCS_BUCKET=$CACHE_GCS_BUCKET; export SCCACHE_GCS_RW_MODE=READ_WRITE; export SCCACHE_IDLE_TIMEOUT=0; sccache --start-server; .ci/monolithic-windows.sh \"${{ steps.vars.outputs.windows-projects }}\" \"${{ steps.vars.outputs.windows-check-targets }}\""
|
bash -c "export SCCACHE_GCS_BUCKET=$CACHE_GCS_BUCKET; export SCCACHE_GCS_RW_MODE=READ_WRITE; export SCCACHE_IDLE_TIMEOUT=0; sccache --start-server; .ci/monolithic-windows.sh \"${{ steps.vars.outputs.windows-projects }}\" \"${{ steps.vars.outputs.windows-check-targets }}\""
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
# In some cases, Github will fail to upload the artifact. We want to
|
|
||||||
# continue anyways as a failed artifact upload is an infra failure, not
|
|
||||||
# a checks failure.
|
|
||||||
# https://github.com/actions/upload-artifact/issues/569
|
|
||||||
continue-on-error: true
|
|
||||||
if: '!cancelled()'
|
if: '!cancelled()'
|
||||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||||
with:
|
with:
|
||||||
|
@ -138,12 +138,6 @@
|
|||||||
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
|
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
|
||||||
for color-coded blocks
|
for color-coded blocks
|
||||||
|
|
||||||
- `--dump-dot-func=<func1,func2,func3...>`
|
|
||||||
|
|
||||||
Dump function CFGs to graphviz format for specified functions only;
|
|
||||||
takes function name patterns (regex supported). Note: C++ function names
|
|
||||||
must be passed using their mangled names
|
|
||||||
|
|
||||||
- `--dump-linux-exceptions`
|
- `--dump-linux-exceptions`
|
||||||
|
|
||||||
Dump Linux kernel exception table
|
Dump Linux kernel exception table
|
||||||
|
@ -1196,6 +1196,11 @@ public:
|
|||||||
return getSecondaryEntryPointSymbol(BB.getLabel());
|
return getSecondaryEntryPointSymbol(BB.getLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove a label from the secondary entry point map.
|
||||||
|
void removeSymbolFromSecondaryEntryPointMap(const MCSymbol *Label) {
|
||||||
|
SecondaryEntryPoints.erase(Label);
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if the basic block is an entry point into the function
|
/// Return true if the basic block is an entry point into the function
|
||||||
/// (either primary or secondary).
|
/// (either primary or secondary).
|
||||||
bool isEntryPoint(const BinaryBasicBlock &BB) const {
|
bool isEntryPoint(const BinaryBasicBlock &BB) const {
|
||||||
|
@ -241,7 +241,7 @@ private:
|
|||||||
|
|
||||||
/// Adjust function sizes and set proper maximum size values after the whole
|
/// Adjust function sizes and set proper maximum size values after the whole
|
||||||
/// symbol table has been processed.
|
/// symbol table has been processed.
|
||||||
void adjustFunctionBoundaries(DenseMap<uint64_t, MarkerSymType> &MarkerSyms);
|
void adjustFunctionBoundaries();
|
||||||
|
|
||||||
/// Make .eh_frame section relocatable.
|
/// Make .eh_frame section relocatable.
|
||||||
void relocateEHFrameSection();
|
void relocateEHFrameSection();
|
||||||
|
@ -15,12 +15,6 @@
|
|||||||
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
namespace bolt {
|
|
||||||
class BinaryFunction;
|
|
||||||
}
|
|
||||||
} // namespace llvm
|
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
|
||||||
enum HeatmapModeKind {
|
enum HeatmapModeKind {
|
||||||
@ -106,9 +100,6 @@ extern llvm::cl::opt<unsigned> Verbosity;
|
|||||||
/// Return true if we should process all functions in the binary.
|
/// Return true if we should process all functions in the binary.
|
||||||
bool processAllFunctions();
|
bool processAllFunctions();
|
||||||
|
|
||||||
/// Return true if we should dump dot graphs for the given function.
|
|
||||||
bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
|
|
||||||
|
|
||||||
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
|
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
|
||||||
|
|
||||||
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
|
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
|
||||||
|
@ -1915,9 +1915,13 @@ void BinaryFunction::postProcessEntryPoints() {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If we have grabbed a wrong code label which actually points to some
|
// If we have grabbed a wrong code label which actually points to some
|
||||||
// constant island inside the function, ignore this label.
|
// constant island inside the function, ignore this label and remove it
|
||||||
if (isStartOfConstantIsland(Offset))
|
// from the secondary entry point map.
|
||||||
|
if (isStartOfConstantIsland(Offset)) {
|
||||||
|
BC.SymbolToFunctionMap.erase(Label);
|
||||||
|
removeSymbolFromSecondaryEntryPointMap(Label);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BC.errs() << "BOLT-WARNING: reference in the middle of instruction "
|
BC.errs() << "BOLT-WARNING: reference in the middle of instruction "
|
||||||
"detected in function "
|
"detected in function "
|
||||||
|
@ -30,11 +30,6 @@ using namespace bolt;
|
|||||||
using namespace MCPlus;
|
using namespace MCPlus;
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
cl::opt<bool>
|
|
||||||
TerminalHLT("terminal-x86-hlt",
|
|
||||||
cl::desc("Assume that execution stops at x86 HLT instruction"),
|
|
||||||
cl::init(true), cl::Hidden, cl::cat(BoltCategory));
|
|
||||||
|
|
||||||
cl::opt<bool>
|
cl::opt<bool>
|
||||||
TerminalTrap("terminal-trap",
|
TerminalTrap("terminal-trap",
|
||||||
cl::desc("Assume that execution stops at trap instruction"),
|
cl::desc("Assume that execution stops at trap instruction"),
|
||||||
@ -137,13 +132,10 @@ bool MCPlusBuilder::equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
|
bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
|
||||||
if (isX86HLT(Inst))
|
return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) ||
|
||||||
return opts::TerminalHLT;
|
Analysis->isTerminator(Inst)
|
||||||
|
? !isX86HLT(Inst)
|
||||||
if (Info->get(Inst.getOpcode()).isTrap())
|
: false;
|
||||||
return opts::TerminalTrap;
|
|
||||||
|
|
||||||
return Analysis->isTerminator(Inst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCPlusBuilder::setTailCall(MCInst &Inst) const {
|
void MCPlusBuilder::setTailCall(MCInst &Inst) const {
|
||||||
|
@ -52,7 +52,6 @@ namespace opts {
|
|||||||
extern cl::opt<bool> PrintAll;
|
extern cl::opt<bool> PrintAll;
|
||||||
extern cl::opt<bool> PrintDynoStats;
|
extern cl::opt<bool> PrintDynoStats;
|
||||||
extern cl::opt<bool> DumpDotAll;
|
extern cl::opt<bool> DumpDotAll;
|
||||||
extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
|
|
||||||
extern cl::opt<std::string> AsmDump;
|
extern cl::opt<std::string> AsmDump;
|
||||||
extern cl::opt<bolt::PLTCall::OptType> PLT;
|
extern cl::opt<bolt::PLTCall::OptType> PLT;
|
||||||
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
|
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
|
||||||
@ -341,7 +340,7 @@ Error BinaryFunctionPassManager::runPasses() {
|
|||||||
|
|
||||||
Function.print(BC.outs(), Message);
|
Function.print(BC.outs(), Message);
|
||||||
|
|
||||||
if (opts::shouldDumpDot(Function))
|
if (opts::DumpDotAll)
|
||||||
Function.dumpGraphForPass(PassIdName);
|
Function.dumpGraphForPass(PassIdName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,6 @@ extern cl::opt<bool> KeepNops;
|
|||||||
extern cl::opt<bool> Lite;
|
extern cl::opt<bool> Lite;
|
||||||
extern cl::list<std::string> ReorderData;
|
extern cl::list<std::string> ReorderData;
|
||||||
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
|
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
|
||||||
extern cl::opt<bool> TerminalHLT;
|
|
||||||
extern cl::opt<bool> TerminalTrap;
|
extern cl::opt<bool> TerminalTrap;
|
||||||
extern cl::opt<bool> TimeBuild;
|
extern cl::opt<bool> TimeBuild;
|
||||||
extern cl::opt<bool> TimeRewrite;
|
extern cl::opt<bool> TimeRewrite;
|
||||||
@ -115,35 +114,6 @@ cl::opt<bool> DumpDotAll(
|
|||||||
"enable '-print-loops' for color-coded blocks"),
|
"enable '-print-loops' for color-coded blocks"),
|
||||||
cl::Hidden, cl::cat(BoltCategory));
|
cl::Hidden, cl::cat(BoltCategory));
|
||||||
|
|
||||||
cl::list<std::string> DumpDotFunc(
|
|
||||||
"dump-dot-func", cl::CommaSeparated,
|
|
||||||
cl::desc(
|
|
||||||
"dump function CFGs to graphviz format for specified functions only;"
|
|
||||||
"takes function name patterns (regex supported)"),
|
|
||||||
cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
|
|
||||||
|
|
||||||
bool shouldDumpDot(const bolt::BinaryFunction &Function) {
|
|
||||||
// If dump-dot-all is enabled, dump all functions
|
|
||||||
if (DumpDotAll)
|
|
||||||
return !Function.isIgnored();
|
|
||||||
|
|
||||||
// If no specific functions specified in dump-dot-func, don't dump any
|
|
||||||
if (DumpDotFunc.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Function.isIgnored())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if function matches any of the specified patterns
|
|
||||||
for (const std::string &Name : DumpDotFunc) {
|
|
||||||
if (Function.hasNameRegex(Name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl::list<std::string>
|
static cl::list<std::string>
|
||||||
ForceFunctionNames("funcs",
|
ForceFunctionNames("funcs",
|
||||||
cl::CommaSeparated,
|
cl::CommaSeparated,
|
||||||
@ -910,9 +880,14 @@ void RewriteInstance::discoverFileObjects() {
|
|||||||
// code section (see IHI0056B). $d identifies data contents.
|
// code section (see IHI0056B). $d identifies data contents.
|
||||||
// Compilers usually merge multiple data objects in a single $d-$x interval,
|
// Compilers usually merge multiple data objects in a single $d-$x interval,
|
||||||
// but we need every data object to be marked with $d. Because of that we
|
// but we need every data object to be marked with $d. Because of that we
|
||||||
// keep track of marker symbols with all locations of data objects.
|
// create a vector of MarkerSyms with all locations of data objects.
|
||||||
|
|
||||||
DenseMap<uint64_t, MarkerSymType> MarkerSymbols;
|
struct MarkerSym {
|
||||||
|
uint64_t Address;
|
||||||
|
MarkerSymType Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<MarkerSym> SortedMarkerSymbols;
|
||||||
auto addExtraDataMarkerPerSymbol = [&]() {
|
auto addExtraDataMarkerPerSymbol = [&]() {
|
||||||
bool IsData = false;
|
bool IsData = false;
|
||||||
uint64_t LastAddr = 0;
|
uint64_t LastAddr = 0;
|
||||||
@ -936,14 +911,14 @@ void RewriteInstance::discoverFileObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (MarkerType != MarkerSymType::NONE) {
|
if (MarkerType != MarkerSymType::NONE) {
|
||||||
MarkerSymbols[SymInfo.Address] = MarkerType;
|
SortedMarkerSymbols.push_back(MarkerSym{SymInfo.Address, MarkerType});
|
||||||
LastAddr = SymInfo.Address;
|
LastAddr = SymInfo.Address;
|
||||||
IsData = MarkerType == MarkerSymType::DATA;
|
IsData = MarkerType == MarkerSymType::DATA;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsData) {
|
if (IsData) {
|
||||||
MarkerSymbols[SymInfo.Address] = MarkerSymType::DATA;
|
SortedMarkerSymbols.push_back({SymInfo.Address, MarkerSymType::DATA});
|
||||||
LastAddr = SymInfo.Address;
|
LastAddr = SymInfo.Address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1308,24 +1283,27 @@ void RewriteInstance::discoverFileObjects() {
|
|||||||
BC->setHasSymbolsWithFileName(FileSymbols.size());
|
BC->setHasSymbolsWithFileName(FileSymbols.size());
|
||||||
|
|
||||||
// Now that all the functions were created - adjust their boundaries.
|
// Now that all the functions were created - adjust their boundaries.
|
||||||
adjustFunctionBoundaries(MarkerSymbols);
|
adjustFunctionBoundaries();
|
||||||
|
|
||||||
// Annotate functions with code/data markers in AArch64
|
// Annotate functions with code/data markers in AArch64
|
||||||
for (auto &[Address, Type] : MarkerSymbols) {
|
for (auto ISym = SortedMarkerSymbols.begin();
|
||||||
auto *BF = BC->getBinaryFunctionContainingAddress(Address, true, true);
|
ISym != SortedMarkerSymbols.end(); ++ISym) {
|
||||||
|
|
||||||
|
auto *BF =
|
||||||
|
BC->getBinaryFunctionContainingAddress(ISym->Address, true, true);
|
||||||
|
|
||||||
if (!BF) {
|
if (!BF) {
|
||||||
// Stray marker
|
// Stray marker
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto EntryOffset = Address - BF->getAddress();
|
const auto EntryOffset = ISym->Address - BF->getAddress();
|
||||||
if (Type == MarkerSymType::CODE) {
|
if (ISym->Type == MarkerSymType::CODE) {
|
||||||
BF->markCodeAtOffset(EntryOffset);
|
BF->markCodeAtOffset(EntryOffset);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Type == MarkerSymType::DATA) {
|
if (ISym->Type == MarkerSymType::DATA) {
|
||||||
BF->markDataAtOffset(EntryOffset);
|
BF->markDataAtOffset(EntryOffset);
|
||||||
BC->AddressToConstantIslandMap[Address] = BF;
|
BC->AddressToConstantIslandMap[ISym->Address] = BF;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unknown marker");
|
llvm_unreachable("Unknown marker");
|
||||||
@ -1854,8 +1832,7 @@ void RewriteInstance::disassemblePLT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewriteInstance::adjustFunctionBoundaries(
|
void RewriteInstance::adjustFunctionBoundaries() {
|
||||||
DenseMap<uint64_t, MarkerSymType> &MarkerSyms) {
|
|
||||||
for (auto BFI = BC->getBinaryFunctions().begin(),
|
for (auto BFI = BC->getBinaryFunctions().begin(),
|
||||||
BFE = BC->getBinaryFunctions().end();
|
BFE = BC->getBinaryFunctions().end();
|
||||||
BFI != BFE; ++BFI) {
|
BFI != BFE; ++BFI) {
|
||||||
@ -1893,15 +1870,12 @@ void RewriteInstance::adjustFunctionBoundaries(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto It = MarkerSyms.find(NextSymRefI->first);
|
// This is potentially another entry point into the function.
|
||||||
if (It == MarkerSyms.end() || It->second != MarkerSymType::DATA) {
|
uint64_t EntryOffset = NextSymRefI->first - Function.getAddress();
|
||||||
// This is potentially another entry point into the function.
|
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding entry point to function "
|
||||||
uint64_t EntryOffset = NextSymRefI->first - Function.getAddress();
|
<< Function << " at offset 0x"
|
||||||
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding entry point to function "
|
<< Twine::utohexstr(EntryOffset) << '\n');
|
||||||
<< Function << " at offset 0x"
|
Function.addEntryPointAtOffset(EntryOffset);
|
||||||
<< Twine::utohexstr(EntryOffset) << '\n');
|
|
||||||
Function.addEntryPointAtOffset(EntryOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
++NextSymRefI;
|
++NextSymRefI;
|
||||||
}
|
}
|
||||||
@ -2203,9 +2177,7 @@ void RewriteInstance::adjustCommandLineOptions() {
|
|||||||
if (!opts::KeepNops.getNumOccurrences())
|
if (!opts::KeepNops.getNumOccurrences())
|
||||||
opts::KeepNops = true;
|
opts::KeepNops = true;
|
||||||
|
|
||||||
// Linux kernel may resume execution after a trap or x86 HLT instruction.
|
// Linux kernel may resume execution after a trap instruction in some cases.
|
||||||
if (!opts::TerminalHLT.getNumOccurrences())
|
|
||||||
opts::TerminalHLT = false;
|
|
||||||
if (!opts::TerminalTrap.getNumOccurrences())
|
if (!opts::TerminalTrap.getNumOccurrences())
|
||||||
opts::TerminalTrap = false;
|
opts::TerminalTrap = false;
|
||||||
}
|
}
|
||||||
@ -3598,7 +3570,7 @@ void RewriteInstance::postProcessFunctions() {
|
|||||||
if (opts::PrintAll || opts::PrintCFG)
|
if (opts::PrintAll || opts::PrintCFG)
|
||||||
Function.print(BC->outs(), "after building cfg");
|
Function.print(BC->outs(), "after building cfg");
|
||||||
|
|
||||||
if (opts::shouldDumpDot(Function))
|
if (opts::DumpDotAll)
|
||||||
Function.dumpGraphForPass("00_build-cfg");
|
Function.dumpGraphForPass("00_build-cfg");
|
||||||
|
|
||||||
if (opts::PrintLoopInfo) {
|
if (opts::PrintLoopInfo) {
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
# This test is to ensure that we query data marker symbols to avoid
|
|
||||||
# misidentifying constant data island symbol as extra entry point.
|
|
||||||
|
|
||||||
# RUN: %clang %cflags %s -o %t.so -Wl,-q -Wl,--init=_bar -Wl,--fini=_bar
|
|
||||||
# RUN: llvm-bolt %t.so -o %t.instr.so
|
|
||||||
|
|
||||||
.text
|
|
||||||
.global _start
|
|
||||||
.type _start, %function
|
|
||||||
_start:
|
|
||||||
ret
|
|
||||||
|
|
||||||
.text
|
|
||||||
.global _foo
|
|
||||||
.type _foo, %function
|
|
||||||
_foo:
|
|
||||||
cbz x1, _foo_2
|
|
||||||
_foo_1:
|
|
||||||
add x1, x2, x0
|
|
||||||
b _foo
|
|
||||||
_foo_2:
|
|
||||||
ret
|
|
||||||
|
|
||||||
# None of these constant island symbols should be identified as extra entry
|
|
||||||
# point for function `_foo'.
|
|
||||||
.align 4
|
|
||||||
_const1: .short 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80
|
|
||||||
_const2: .short 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0
|
|
||||||
_const3: .short 0x04, 0x08, 0x0c, 0x20, 0x60, 0x80, 0xa0, 0xc0
|
|
||||||
|
|
||||||
.text
|
|
||||||
.global _bar
|
|
||||||
.type _bar, %function
|
|
||||||
_bar:
|
|
||||||
ret
|
|
||||||
|
|
||||||
# Dummy relocation to force relocation mode
|
|
||||||
.reloc 0, R_AARCH64_NONE
|
|
@ -1,24 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
// Multiple functions to test selective dumping
|
|
||||||
int add(int a, int b) { return a + b; }
|
|
||||||
|
|
||||||
int multiply(int a, int b) { return a * b; }
|
|
||||||
|
|
||||||
int main_helper() {
|
|
||||||
std::cout << "Helper function" << std::endl;
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main_secondary() { return add(5, 3); }
|
|
||||||
|
|
||||||
void other_function() { std::cout << "Other function" << std::endl; }
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int result = add(10, 20);
|
|
||||||
result = multiply(result, 2);
|
|
||||||
main_helper();
|
|
||||||
main_secondary();
|
|
||||||
other_function();
|
|
||||||
return result;
|
|
||||||
}
|
|
17
bolt/test/X86/cfg_build_hlt.s
Normal file
17
bolt/test/X86/cfg_build_hlt.s
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
## Check CFG for halt instruction
|
||||||
|
|
||||||
|
# RUN: %clang %cflags %s -static -o %t.exe -nostdlib
|
||||||
|
# RUN: llvm-bolt %t.exe --print-cfg --print-only=main -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-CFG
|
||||||
|
# RUN: llvm-objdump -d %t --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN
|
||||||
|
|
||||||
|
# CHECK-CFG: BB Count : 1
|
||||||
|
# CHECK-BIN: <main>:
|
||||||
|
# CHECK-BIN-NEXT: f4 hlt
|
||||||
|
# CHECK-BIN-NEXT: c3 retq
|
||||||
|
|
||||||
|
.global main
|
||||||
|
.type main, %function
|
||||||
|
main:
|
||||||
|
hlt
|
||||||
|
retq
|
||||||
|
.size main, .-main
|
@ -1,24 +0,0 @@
|
|||||||
## Check that HLT instruction is handled differently depending on the flags.
|
|
||||||
## It's a terminator in the user-level code, but the execution can resume in
|
|
||||||
## ring 0.
|
|
||||||
|
|
||||||
# RUN: %clang %cflags %s -static -o %t.exe -nostdlib
|
|
||||||
# RUN: llvm-bolt %t.exe --print-cfg --print-only=main --terminal-x86-hlt=0 \
|
|
||||||
# RUN: -o %t.ring0 2>&1 | FileCheck %s --check-prefix=CHECK-RING0
|
|
||||||
# RUN: llvm-bolt %t.exe --print-cfg --print-only=main \
|
|
||||||
# RUN: -o %t.ring3 2>&1 | FileCheck %s --check-prefix=CHECK-RING3
|
|
||||||
# RUN: llvm-objdump -d %t.ring0 --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN
|
|
||||||
|
|
||||||
# CHECK-RING0: BB Count : 1
|
|
||||||
# CHECK-RING3: BB Count : 2
|
|
||||||
|
|
||||||
# CHECK-BIN: <main>:
|
|
||||||
# CHECK-BIN-NEXT: f4 hlt
|
|
||||||
# CHECK-BIN-NEXT: c3 retq
|
|
||||||
|
|
||||||
.global main
|
|
||||||
.type main, %function
|
|
||||||
main:
|
|
||||||
hlt
|
|
||||||
retq
|
|
||||||
.size main, .-main
|
|
@ -1,52 +0,0 @@
|
|||||||
# Test the --dump-dot-func option with multiple functions
|
|
||||||
# (includes tests for both mangled/unmangled names)
|
|
||||||
|
|
||||||
RUN: %clang++ %p/Inputs/multi-func.cpp -o %t.exe -Wl,-q
|
|
||||||
|
|
||||||
# Test 1: --dump-dot-func with specific function name (mangled)
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=_Z3addii -v=1 2>&1 | FileCheck %s --check-prefix=ADD
|
|
||||||
|
|
||||||
# Test 2: --dump-dot-func with regex pattern (main.*)
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX
|
|
||||||
|
|
||||||
# Test 3: --dump-dot-func with multiple specific functions (mangled names)
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=_Z3addii,_Z8multiplyii -v=1 2>&1 | FileCheck %s --check-prefix=MULTI
|
|
||||||
|
|
||||||
# Test 4: No option specified should create no dot files
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt4 2>&1 | FileCheck %s --check-prefix=NONE
|
|
||||||
|
|
||||||
# Test 5: --dump-dot-func with non-existent function
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt5 --dump-dot-func=nonexistent -v=1 2>&1 | FileCheck %s --check-prefix=NONEXISTENT
|
|
||||||
|
|
||||||
# Test 6: Backward compatibility - --dump-dot-all should still work
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt6 --dump-dot-all -v=1 2>&1 | FileCheck %s --check-prefix=ALL
|
|
||||||
|
|
||||||
# Test 7: Test with unmangled function name (main function)
|
|
||||||
RUN: llvm-bolt %t.exe -o %t.bolt7 --dump-dot-func=main -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-UNMANGLED
|
|
||||||
|
|
||||||
# Check that specific functions are dumped
|
|
||||||
ADD: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
|
||||||
ADD-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
|
||||||
ADD-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
|
||||||
ADD-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
|
|
||||||
|
|
||||||
MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
|
||||||
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
|
||||||
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
|
||||||
|
|
||||||
MULTI-DAG: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
|
||||||
MULTI-DAG: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
|
||||||
MULTI-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
|
||||||
MULTI-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
|
|
||||||
|
|
||||||
# Should be no dumping messages when no option is specified
|
|
||||||
NONE-NOT: BOLT-INFO: dumping CFG
|
|
||||||
|
|
||||||
# Should be no dumping messages for non-existent function
|
|
||||||
NONEXISTENT-NOT: BOLT-INFO: dumping CFG
|
|
||||||
|
|
||||||
ALL: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
|
||||||
|
|
||||||
MAIN-UNMANGLED: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
|
||||||
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
|
||||||
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
|
@ -544,7 +544,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
|
|||||||
ArrayRef<std::string> InputFiles,
|
ArrayRef<std::string> InputFiles,
|
||||||
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
|
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
|
||||||
bool ApplyAnyFix, bool EnableCheckProfile,
|
bool ApplyAnyFix, bool EnableCheckProfile,
|
||||||
llvm::StringRef StoreCheckProfile, bool Quiet) {
|
llvm::StringRef StoreCheckProfile) {
|
||||||
ClangTool Tool(Compilations, InputFiles,
|
ClangTool Tool(Compilations, InputFiles,
|
||||||
std::make_shared<PCHContainerOperations>(), BaseFS);
|
std::make_shared<PCHContainerOperations>(), BaseFS);
|
||||||
|
|
||||||
@ -581,9 +581,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
|
|||||||
class ActionFactory : public FrontendActionFactory {
|
class ActionFactory : public FrontendActionFactory {
|
||||||
public:
|
public:
|
||||||
ActionFactory(ClangTidyContext &Context,
|
ActionFactory(ClangTidyContext &Context,
|
||||||
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
|
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS)
|
||||||
bool Quiet)
|
: ConsumerFactory(Context, std::move(BaseFS)) {}
|
||||||
: ConsumerFactory(Context, std::move(BaseFS)), Quiet(Quiet) {}
|
|
||||||
std::unique_ptr<FrontendAction> create() override {
|
std::unique_ptr<FrontendAction> create() override {
|
||||||
return std::make_unique<Action>(&ConsumerFactory);
|
return std::make_unique<Action>(&ConsumerFactory);
|
||||||
}
|
}
|
||||||
@ -594,8 +593,6 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
|
|||||||
DiagnosticConsumer *DiagConsumer) override {
|
DiagnosticConsumer *DiagConsumer) override {
|
||||||
// Explicitly ask to define __clang_analyzer__ macro.
|
// Explicitly ask to define __clang_analyzer__ macro.
|
||||||
Invocation->getPreprocessorOpts().SetUpStaticAnalyzer = true;
|
Invocation->getPreprocessorOpts().SetUpStaticAnalyzer = true;
|
||||||
if (Quiet)
|
|
||||||
Invocation->getDiagnosticOpts().ShowCarets = false;
|
|
||||||
return FrontendActionFactory::runInvocation(
|
return FrontendActionFactory::runInvocation(
|
||||||
Invocation, Files, PCHContainerOps, DiagConsumer);
|
Invocation, Files, PCHContainerOps, DiagConsumer);
|
||||||
}
|
}
|
||||||
@ -614,10 +611,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
|
|||||||
};
|
};
|
||||||
|
|
||||||
ClangTidyASTConsumerFactory ConsumerFactory;
|
ClangTidyASTConsumerFactory ConsumerFactory;
|
||||||
bool Quiet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ActionFactory Factory(Context, std::move(BaseFS), Quiet);
|
ActionFactory Factory(Context, std::move(BaseFS));
|
||||||
Tool.run(&Factory);
|
Tool.run(&Factory);
|
||||||
return DiagConsumer.take();
|
return DiagConsumer.take();
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
|
|||||||
ArrayRef<std::string> InputFiles,
|
ArrayRef<std::string> InputFiles,
|
||||||
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
|
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
|
||||||
bool ApplyAnyFix, bool EnableCheckProfile = false,
|
bool ApplyAnyFix, bool EnableCheckProfile = false,
|
||||||
llvm::StringRef StoreCheckProfile = StringRef(),
|
llvm::StringRef StoreCheckProfile = StringRef());
|
||||||
bool Quiet = false);
|
|
||||||
|
|
||||||
/// Controls what kind of fixes clang-tidy is allowed to apply.
|
/// Controls what kind of fixes clang-tidy is allowed to apply.
|
||||||
enum FixBehaviour {
|
enum FixBehaviour {
|
||||||
|
@ -89,9 +89,13 @@ def write_header(
|
|||||||
+ check_name_camel.upper()
|
+ check_name_camel.upper()
|
||||||
+ "_H"
|
+ "_H"
|
||||||
)
|
)
|
||||||
|
f.write("//===--- ")
|
||||||
|
f.write(os.path.basename(filename))
|
||||||
|
f.write(" - clang-tidy ")
|
||||||
|
f.write("-" * max(0, 42 - len(os.path.basename(filename))))
|
||||||
|
f.write("*- C++ -*-===//")
|
||||||
f.write(
|
f.write(
|
||||||
"""
|
"""
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
@ -141,9 +145,13 @@ def write_implementation(
|
|||||||
filename = os.path.join(module_path, check_name_camel) + ".cpp"
|
filename = os.path.join(module_path, check_name_camel) + ".cpp"
|
||||||
print("Creating %s..." % filename)
|
print("Creating %s..." % filename)
|
||||||
with io.open(filename, "w", encoding="utf8", newline="\n") as f:
|
with io.open(filename, "w", encoding="utf8", newline="\n") as f:
|
||||||
|
f.write("//===--- ")
|
||||||
|
f.write(os.path.basename(filename))
|
||||||
|
f.write(" - clang-tidy ")
|
||||||
|
f.write("-" * max(0, 51 - len(os.path.basename(filename))))
|
||||||
|
f.write("-===//")
|
||||||
f.write(
|
f.write(
|
||||||
"""
|
"""
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
@ -1575,10 +1575,6 @@ template <typename T, std::size_t N = SmallDataStructureSize>
|
|||||||
using ParamToSmallSetMap =
|
using ParamToSmallSetMap =
|
||||||
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
|
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
|
||||||
|
|
||||||
template <typename T, std::size_t N = SmallDataStructureSize>
|
|
||||||
using ParamToSmallPtrSetMap =
|
|
||||||
llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
|
|
||||||
|
|
||||||
/// Returns whether the sets mapped to the two elements in the map have at
|
/// Returns whether the sets mapped to the two elements in the map have at
|
||||||
/// least one element in common.
|
/// least one element in common.
|
||||||
template <typename MapTy, typename ElemTy>
|
template <typename MapTy, typename ElemTy>
|
||||||
@ -1703,7 +1699,7 @@ public:
|
|||||||
/// Implements the heuristic that marks two parameters related if the same
|
/// Implements the heuristic that marks two parameters related if the same
|
||||||
/// member is accessed (referred to) inside the current function's body.
|
/// member is accessed (referred to) inside the current function's body.
|
||||||
class AccessedSameMemberOf {
|
class AccessedSameMemberOf {
|
||||||
ParamToSmallPtrSetMap<const Decl *> AccessedMembers;
|
ParamToSmallSetMap<const Decl *> AccessedMembers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setup(const FunctionDecl *FD) {
|
void setup(const FunctionDecl *FD) {
|
||||||
|
@ -188,7 +188,7 @@ static bool isKnownToHaveValue(const Expr &Cond, const ASTContext &Ctx,
|
|||||||
/// \return true iff all `CallExprs` visited have callees; false otherwise
|
/// \return true iff all `CallExprs` visited have callees; false otherwise
|
||||||
/// indicating there is an unresolved indirect call.
|
/// indicating there is an unresolved indirect call.
|
||||||
static bool populateCallees(const Stmt *StmtNode,
|
static bool populateCallees(const Stmt *StmtNode,
|
||||||
llvm::SmallPtrSet<const Decl *, 16> &Callees) {
|
llvm::SmallSet<const Decl *, 16> &Callees) {
|
||||||
if (const auto *Call = dyn_cast<CallExpr>(StmtNode)) {
|
if (const auto *Call = dyn_cast<CallExpr>(StmtNode)) {
|
||||||
const Decl *Callee = Call->getDirectCallee();
|
const Decl *Callee = Call->getDirectCallee();
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ static bool populateCallees(const Stmt *StmtNode,
|
|||||||
/// returns true iff `SCC` contains `Func` and its' function set overlaps with
|
/// returns true iff `SCC` contains `Func` and its' function set overlaps with
|
||||||
/// `Callees`
|
/// `Callees`
|
||||||
static bool overlap(ArrayRef<CallGraphNode *> SCC,
|
static bool overlap(ArrayRef<CallGraphNode *> SCC,
|
||||||
const llvm::SmallPtrSet<const Decl *, 16> &Callees,
|
const llvm::SmallSet<const Decl *, 16> &Callees,
|
||||||
const Decl *Func) {
|
const Decl *Func) {
|
||||||
bool ContainsFunc = false, Overlap = false;
|
bool ContainsFunc = false, Overlap = false;
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ static bool hasRecursionOverStaticLoopCondVariables(const Expr *Cond,
|
|||||||
if (!hasStaticLocalVariable(Cond))
|
if (!hasStaticLocalVariable(Cond))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
llvm::SmallPtrSet<const Decl *, 16> CalleesInLoop;
|
llvm::SmallSet<const Decl *, 16> CalleesInLoop;
|
||||||
|
|
||||||
if (!populateCallees(LoopStmt, CalleesInLoop)) {
|
if (!populateCallees(LoopStmt, CalleesInLoop)) {
|
||||||
// If there are unresolved indirect calls, we assume there could
|
// If there are unresolved indirect calls, we assume there could
|
||||||
|
@ -15,12 +15,14 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::bugprone {
|
namespace clang::tidy::bugprone {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
// Determine if the result of an expression is "stored" in some way.
|
// Determine if the result of an expression is "stored" in some way.
|
||||||
// It is true if the value is stored into a variable or used as initialization
|
// It is true if the value is stored into a variable or used as initialization
|
||||||
// or passed to a function or constructor.
|
// or passed to a function or constructor.
|
||||||
// For this use case compound assignments are not counted as a "store" (the 'E'
|
// For this use case compound assignments are not counted as a "store" (the 'E'
|
||||||
// expression should have pointer type).
|
// expression should have pointer type).
|
||||||
static bool isExprValueStored(const Expr *E, ASTContext &C) {
|
bool isExprValueStored(const Expr *E, ASTContext &C) {
|
||||||
E = E->IgnoreParenCasts();
|
E = E->IgnoreParenCasts();
|
||||||
// Get first non-paren, non-cast parent.
|
// Get first non-paren, non-cast parent.
|
||||||
ParentMapContext &PMap = C.getParentMapContext();
|
ParentMapContext &PMap = C.getParentMapContext();
|
||||||
@ -47,8 +49,6 @@ static bool isExprValueStored(const Expr *E, ASTContext &C) {
|
|||||||
return isa<CallExpr, CXXConstructExpr>(ParentE);
|
return isa<CallExpr, CXXConstructExpr>(ParentE);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
|
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
|
||||||
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
|
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
|
||||||
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
|
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
|
||||||
|
@ -14,8 +14,10 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::bugprone {
|
namespace clang::tidy::bugprone {
|
||||||
|
|
||||||
static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
namespace {
|
||||||
const StringLiteral *Lit) {
|
|
||||||
|
bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
||||||
|
const StringLiteral *Lit) {
|
||||||
// String literals surrounded by parentheses are assumed to be on purpose.
|
// String literals surrounded by parentheses are assumed to be on purpose.
|
||||||
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
|
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
|
||||||
|
|
||||||
@ -56,8 +58,6 @@ static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
|
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
|
||||||
MaxConcatenatedTokens) {
|
MaxConcatenatedTokens) {
|
||||||
return Node.getNumConcatenated() > 1 &&
|
return Node.getNumConcatenated() > 1 &&
|
||||||
|
@ -46,9 +46,7 @@ enum class ConversionKind {
|
|||||||
ToLongDouble
|
ToLongDouble
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
||||||
|
|
||||||
static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
|
||||||
return llvm::StringSwitch<ConversionKind>(FD->getName())
|
return llvm::StringSwitch<ConversionKind>(FD->getName())
|
||||||
.Cases("atoi", "atol", ConversionKind::ToInt)
|
.Cases("atoi", "atol", ConversionKind::ToInt)
|
||||||
.Case("atoll", ConversionKind::ToLongInt)
|
.Case("atoll", ConversionKind::ToLongInt)
|
||||||
@ -56,8 +54,8 @@ static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
|||||||
.Default(ConversionKind::None);
|
.Default(ConversionKind::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
||||||
const TargetInfo &TI) {
|
const TargetInfo &TI) {
|
||||||
// Scan the format string for the first problematic format specifier, then
|
// Scan the format string for the first problematic format specifier, then
|
||||||
// report that as the conversion type. This will miss additional conversion
|
// report that as the conversion type. This will miss additional conversion
|
||||||
// specifiers, but that is acceptable behavior.
|
// specifiers, but that is acceptable behavior.
|
||||||
@ -130,7 +128,7 @@ static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
|||||||
return H.get();
|
return H.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringRef classifyConversionType(ConversionKind K) {
|
StringRef classifyConversionType(ConversionKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
case ConversionKind::None:
|
case ConversionKind::None:
|
||||||
llvm_unreachable("Unexpected conversion kind");
|
llvm_unreachable("Unexpected conversion kind");
|
||||||
@ -150,7 +148,7 @@ static StringRef classifyConversionType(ConversionKind K) {
|
|||||||
llvm_unreachable("Unknown conversion kind");
|
llvm_unreachable("Unknown conversion kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringRef classifyReplacement(ConversionKind K) {
|
StringRef classifyReplacement(ConversionKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
case ConversionKind::None:
|
case ConversionKind::None:
|
||||||
llvm_unreachable("Unexpected conversion kind");
|
llvm_unreachable("Unexpected conversion kind");
|
||||||
@ -175,6 +173,7 @@ static StringRef classifyReplacement(ConversionKind K) {
|
|||||||
}
|
}
|
||||||
llvm_unreachable("Unknown conversion kind");
|
llvm_unreachable("Unknown conversion kind");
|
||||||
}
|
}
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
|
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
|
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
|
||||||
|
@ -59,9 +59,7 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
||||||
|
|
||||||
static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
|
||||||
switch (FD->getOverloadedOperator()) {
|
switch (FD->getOverloadedOperator()) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -77,7 +75,7 @@ static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
|||||||
llvm_unreachable("Not an overloaded allocation operator");
|
llvm_unreachable("Not an overloaded allocation operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *getOperatorName(OverloadedOperatorKind K) {
|
const char *getOperatorName(OverloadedOperatorKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -93,14 +91,13 @@ static const char *getOperatorName(OverloadedOperatorKind K) {
|
|||||||
llvm_unreachable("Not an overloaded allocation operator");
|
llvm_unreachable("Not an overloaded allocation operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
||||||
const FunctionDecl *RHS) {
|
const FunctionDecl *RHS) {
|
||||||
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
|
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
||||||
hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
const CXXRecordDecl *RD = nullptr) {
|
||||||
const CXXRecordDecl *RD = nullptr) {
|
|
||||||
if (RD) {
|
if (RD) {
|
||||||
// Check the methods in the given class and accessible to derived classes.
|
// Check the methods in the given class and accessible to derived classes.
|
||||||
for (const auto *BMD : RD->methods())
|
for (const auto *BMD : RD->methods())
|
||||||
@ -127,6 +124,8 @@ hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
|
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
// Match all operator new and operator delete overloads (including the array
|
// Match all operator new and operator delete overloads (including the array
|
||||||
// forms). Do not match implicit operators, placement operators, or
|
// forms). Do not match implicit operators, placement operators, or
|
||||||
|
@ -29,13 +29,11 @@ void UnconventionalAssignOperatorCheck::registerMatchers(
|
|||||||
const auto HasGoodReturnType =
|
const auto HasGoodReturnType =
|
||||||
cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
|
cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
|
||||||
unless(isConstQualified()),
|
unless(isConstQualified()),
|
||||||
anyOf(autoType(),
|
anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))));
|
||||||
hasDeclaration(declaresSameEntityAsBoundNode("class"))))))));
|
|
||||||
|
|
||||||
const auto IsSelf = qualType(hasCanonicalType(
|
const auto IsSelf = qualType(hasCanonicalType(
|
||||||
anyOf(hasDeclaration(declaresSameEntityAsBoundNode("class")),
|
anyOf(hasDeclaration(equalsBoundNode("class")),
|
||||||
referenceType(pointee(
|
referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))));
|
||||||
hasDeclaration(declaresSameEntityAsBoundNode("class")))))));
|
|
||||||
const auto IsAssign =
|
const auto IsAssign =
|
||||||
cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
|
cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
|
||||||
hasName("operator="), ofClass(recordDecl().bind("class")))
|
hasName("operator="), ofClass(recordDecl().bind("class")))
|
||||||
|
@ -395,12 +395,16 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
|
|||||||
--CurrentFile->ConditionScopes;
|
--CurrentFile->ConditionScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
static bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
||||||
return StringRef{HayStack, N - 1} == Needle;
|
return StringRef{HayStack, N - 1} == Needle;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N> static size_t len(const char (&)[N]) { return N - 1; }
|
template <size_t N> size_t len(const char (&)[N]) { return N - 1; }
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
|
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
|
||||||
PragmaIntroducerKind Introducer) {
|
PragmaIntroducerKind Introducer) {
|
||||||
|
@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::modernize {
|
namespace clang::tidy::modernize {
|
||||||
|
|
||||||
static constexpr char ConstructorCall[] = "constructorCall";
|
namespace {
|
||||||
static constexpr char ResetCall[] = "resetCall";
|
|
||||||
static constexpr char NewExpression[] = "newExpression";
|
|
||||||
|
|
||||||
static std::string getNewExprName(const CXXNewExpr *NewExpr,
|
constexpr char ConstructorCall[] = "constructorCall";
|
||||||
const SourceManager &SM,
|
constexpr char ResetCall[] = "resetCall";
|
||||||
const LangOptions &Lang) {
|
constexpr char NewExpression[] = "newExpression";
|
||||||
|
|
||||||
|
std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
|
||||||
|
const LangOptions &Lang) {
|
||||||
StringRef WrittenName = Lexer::getSourceText(
|
StringRef WrittenName = Lexer::getSourceText(
|
||||||
CharSourceRange::getTokenRange(
|
CharSourceRange::getTokenRange(
|
||||||
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
|
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
|
||||||
@ -33,6 +34,8 @@ static std::string getNewExprName(const CXXNewExpr *NewExpr,
|
|||||||
return WrittenName.str();
|
return WrittenName.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
|
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
|
||||||
|
|
||||||
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
|
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
|
||||||
|
@ -19,7 +19,9 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::modernize {
|
namespace clang::tidy::modernize {
|
||||||
|
|
||||||
static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
namespace {
|
||||||
|
|
||||||
|
bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
||||||
size_t BackSlash = HayStack.find('\\');
|
size_t BackSlash = HayStack.find('\\');
|
||||||
if (BackSlash == StringRef::npos)
|
if (BackSlash == StringRef::npos)
|
||||||
return false;
|
return false;
|
||||||
@ -33,16 +35,16 @@ static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isRawStringLiteral(StringRef Text) {
|
bool isRawStringLiteral(StringRef Text) {
|
||||||
// Already a raw string literal if R comes before ".
|
// Already a raw string literal if R comes before ".
|
||||||
const size_t QuotePos = Text.find('"');
|
const size_t QuotePos = Text.find('"');
|
||||||
assert(QuotePos != StringRef::npos);
|
assert(QuotePos != StringRef::npos);
|
||||||
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
|
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
||||||
const StringLiteral *Literal,
|
const StringLiteral *Literal,
|
||||||
const CharsBitSet &DisallowedChars) {
|
const CharsBitSet &DisallowedChars) {
|
||||||
// FIXME: Handle L"", u8"", u"" and U"" literals.
|
// FIXME: Handle L"", u8"", u"" and U"" literals.
|
||||||
if (!Literal->isOrdinary())
|
if (!Literal->isOrdinary())
|
||||||
return false;
|
return false;
|
||||||
@ -62,12 +64,14 @@ static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
|||||||
return containsEscapes(Text, R"('\"?x01)");
|
return containsEscapes(Text, R"('\"?x01)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
||||||
return Bytes.find(Delimiter.empty()
|
return Bytes.find(Delimiter.empty()
|
||||||
? std::string(R"lit()")lit")
|
? std::string(R"lit()")lit")
|
||||||
: (")" + Delimiter + R"(")")) != StringRef::npos;
|
: (")" + Delimiter + R"(")")) != StringRef::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
|
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -29,13 +29,12 @@
|
|||||||
using namespace clang::ast_matchers;
|
using namespace clang::ast_matchers;
|
||||||
|
|
||||||
namespace clang::tidy::objc {
|
namespace clang::tidy::objc {
|
||||||
|
namespace {
|
||||||
|
|
||||||
static constexpr StringRef WeakText = "__weak";
|
static constexpr StringRef WeakText = "__weak";
|
||||||
static constexpr StringRef StrongText = "__strong";
|
static constexpr StringRef StrongText = "__strong";
|
||||||
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
|
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
|
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
|
||||||
/// Objective-C object (or block) variables or fields whose object lifetimes
|
/// Objective-C object (or block) variables or fields whose object lifetimes
|
||||||
/// are not __unsafe_unretained.
|
/// are not __unsafe_unretained.
|
||||||
@ -50,8 +49,6 @@ AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime,
|
|||||||
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
|
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
static std::optional<FixItHint>
|
static std::optional<FixItHint>
|
||||||
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
|
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
|
||||||
StringRef Ownership) {
|
StringRef Ownership) {
|
||||||
@ -96,6 +93,8 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM,
|
|||||||
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
|
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
|
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
traverse(
|
traverse(
|
||||||
|
@ -27,14 +27,11 @@ enum NamingStyle {
|
|||||||
CategoryProperty = 2,
|
CategoryProperty = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
||||||
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
|
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
|
||||||
/// come up with a proper name by their own.
|
/// come up with a proper name by their own.
|
||||||
/// FIXME: provide fix for snake_case to snakeCase
|
/// FIXME: provide fix for snake_case to snakeCase
|
||||||
static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
|
FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
|
||||||
NamingStyle Style) {
|
|
||||||
auto Name = Decl->getName();
|
auto Name = Decl->getName();
|
||||||
auto NewName = Decl->getName().str();
|
auto NewName = Decl->getName().str();
|
||||||
size_t Index = 0;
|
size_t Index = 0;
|
||||||
@ -53,7 +50,7 @@ static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string validPropertyNameRegex(bool UsedInMatcher) {
|
std::string validPropertyNameRegex(bool UsedInMatcher) {
|
||||||
// Allow any of these names:
|
// Allow any of these names:
|
||||||
// foo
|
// foo
|
||||||
// fooBar
|
// fooBar
|
||||||
@ -75,13 +72,13 @@ static std::string validPropertyNameRegex(bool UsedInMatcher) {
|
|||||||
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
||||||
auto RegexExp =
|
auto RegexExp =
|
||||||
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
||||||
return RegexExp.match(PropertyName);
|
return RegexExp.match(PropertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
||||||
size_t Start = PropertyName.find_first_of('_');
|
size_t Start = PropertyName.find_first_of('_');
|
||||||
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
|
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
|
||||||
auto Prefix = PropertyName.substr(0, Start);
|
auto Prefix = PropertyName.substr(0, Start);
|
||||||
@ -91,6 +88,7 @@ static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
|||||||
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
|
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
|
||||||
return RegexExp.match(PropertyName.substr(Start + 1));
|
return RegexExp.match(PropertyName.substr(Start + 1));
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(objcPropertyDecl(
|
Finder->addMatcher(objcPropertyDecl(
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace clang::tidy::performance {
|
namespace clang::tidy::performance {
|
||||||
|
namespace {
|
||||||
|
|
||||||
using namespace ::clang::ast_matchers;
|
using namespace ::clang::ast_matchers;
|
||||||
using llvm::StringRef;
|
using llvm::StringRef;
|
||||||
@ -29,8 +30,8 @@ static constexpr StringRef MethodDeclId = "methodDecl";
|
|||||||
static constexpr StringRef FunctionDeclId = "functionDecl";
|
static constexpr StringRef FunctionDeclId = "functionDecl";
|
||||||
static constexpr StringRef OldVarDeclId = "oldVarDecl";
|
static constexpr StringRef OldVarDeclId = "oldVarDecl";
|
||||||
|
|
||||||
static void recordFixes(const VarDecl &Var, ASTContext &Context,
|
void recordFixes(const VarDecl &Var, ASTContext &Context,
|
||||||
DiagnosticBuilder &Diagnostic) {
|
DiagnosticBuilder &Diagnostic) {
|
||||||
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
|
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
|
||||||
if (!Var.getType().isLocalConstQualified()) {
|
if (!Var.getType().isLocalConstQualified()) {
|
||||||
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
||||||
@ -39,8 +40,8 @@ static void recordFixes(const VarDecl &Var, ASTContext &Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
||||||
SourceManager &SM) {
|
SourceManager &SM) {
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
|
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
|
||||||
if (Invalid) {
|
if (Invalid) {
|
||||||
@ -50,8 +51,8 @@ static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
|||||||
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
|
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
||||||
DiagnosticBuilder &Diagnostic) {
|
DiagnosticBuilder &Diagnostic) {
|
||||||
auto &SM = Context.getSourceManager();
|
auto &SM = Context.getSourceManager();
|
||||||
// Attempt to remove trailing comments as well.
|
// Attempt to remove trailing comments as well.
|
||||||
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
|
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
|
||||||
@ -73,8 +74,6 @@ static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
AST_MATCHER_FUNCTION_P(StatementMatcher,
|
AST_MATCHER_FUNCTION_P(StatementMatcher,
|
||||||
isRefReturningMethodCallWithConstOverloads,
|
isRefReturningMethodCallWithConstOverloads,
|
||||||
std::vector<StringRef>, ExcludedContainerTypes) {
|
std::vector<StringRef>, ExcludedContainerTypes) {
|
||||||
@ -131,8 +130,6 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
|
|||||||
hasUnaryOperand(OldVarDeclRef)))));
|
hasUnaryOperand(OldVarDeclRef)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// This checks that the variable itself is only used as const, and also makes
|
// This checks that the variable itself is only used as const, and also makes
|
||||||
// sure that it does not reference another variable that could be modified in
|
// sure that it does not reference another variable that could be modified in
|
||||||
// the BlockStmt. It does this by checking the following:
|
// the BlockStmt. It does this by checking the following:
|
||||||
@ -183,13 +180,13 @@ static bool isInitializingVariableImmutable(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
return allDeclRefExprs(Var, BlockStmt, Context).empty();
|
return allDeclRefExprs(Var, BlockStmt, Context).empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const SubstTemplateTypeParmType *
|
const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
|
||||||
getSubstitutedType(const QualType &Type, ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
auto Matches = match(
|
auto Matches = match(
|
||||||
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
|
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
|
||||||
hasDescendant(substTemplateTypeParmType().bind("subst")))),
|
hasDescendant(substTemplateTypeParmType().bind("subst")))),
|
||||||
@ -197,9 +194,9 @@ getSubstitutedType(const QualType &Type, ASTContext &Context) {
|
|||||||
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
|
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool differentReplacedTemplateParams(const QualType &VarType,
|
bool differentReplacedTemplateParams(const QualType &VarType,
|
||||||
const QualType &InitializerType,
|
const QualType &InitializerType,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
if (const SubstTemplateTypeParmType *VarTmplType =
|
if (const SubstTemplateTypeParmType *VarTmplType =
|
||||||
getSubstitutedType(VarType, Context)) {
|
getSubstitutedType(VarType, Context)) {
|
||||||
if (const SubstTemplateTypeParmType *InitializerTmplType =
|
if (const SubstTemplateTypeParmType *InitializerTmplType =
|
||||||
@ -215,8 +212,8 @@ static bool differentReplacedTemplateParams(const QualType &VarType,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QualType constructorArgumentType(const VarDecl *OldVar,
|
QualType constructorArgumentType(const VarDecl *OldVar,
|
||||||
const BoundNodes &Nodes) {
|
const BoundNodes &Nodes) {
|
||||||
if (OldVar) {
|
if (OldVar) {
|
||||||
return OldVar->getType();
|
return OldVar->getType();
|
||||||
}
|
}
|
||||||
@ -227,6 +224,8 @@ static QualType constructorArgumentType(const VarDecl *OldVar,
|
|||||||
return MethodDecl->getReturnType();
|
return MethodDecl->getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
|
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -21,14 +21,16 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::performance {
|
namespace clang::tidy::performance {
|
||||||
|
|
||||||
static std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
namespace {
|
||||||
|
|
||||||
|
std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
||||||
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
|
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
|
||||||
: llvm::Twine('\'') + Name + llvm::Twine('\''))
|
: llvm::Twine('\'') + Name + llvm::Twine('\''))
|
||||||
.str();
|
.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
auto Matches = match(
|
auto Matches = match(
|
||||||
traverse(TK_AsIs,
|
traverse(TK_AsIs,
|
||||||
decl(forEachDescendant(declRefExpr(
|
decl(forEachDescendant(declRefExpr(
|
||||||
@ -39,6 +41,8 @@ static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
|||||||
return Matches.empty();
|
return Matches.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
|
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -122,15 +122,15 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) {
|
|||||||
return !AllEnumeratorsArePowersOfTwo;
|
return !AllEnumeratorsArePowersOfTwo;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
std::string getName(const EnumDecl *Decl) {
|
||||||
|
|
||||||
static std::string getName(const EnumDecl *Decl) {
|
|
||||||
if (!Decl->getDeclName())
|
if (!Decl->getDeclName())
|
||||||
return "<unnamed>";
|
return "<unnamed>";
|
||||||
|
|
||||||
return Decl->getQualifiedNameAsString();
|
return Decl->getQualifiedNameAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
|
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -144,8 +144,6 @@ struct CognitiveComplexity final {
|
|||||||
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
|
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// All the possible messages that can be output. The choice of the message
|
// All the possible messages that can be output. The choice of the message
|
||||||
// to use is based of the combination of the CognitiveComplexity::Criteria.
|
// to use is based of the combination of the CognitiveComplexity::Criteria.
|
||||||
// It would be nice to have it in CognitiveComplexity struct, but then it is
|
// It would be nice to have it in CognitiveComplexity struct, but then it is
|
||||||
@ -165,27 +163,23 @@ static const std::array<const StringRef, 4> Msgs = {{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
// Criteria is a bitset, thus a few helpers are needed.
|
// Criteria is a bitset, thus a few helpers are needed.
|
||||||
static CognitiveComplexity::Criteria
|
CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
|
||||||
operator|(CognitiveComplexity::Criteria LHS,
|
CognitiveComplexity::Criteria RHS) {
|
||||||
CognitiveComplexity::Criteria RHS) {
|
|
||||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
|
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
|
||||||
llvm::to_underlying(RHS));
|
llvm::to_underlying(RHS));
|
||||||
}
|
}
|
||||||
static CognitiveComplexity::Criteria
|
CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
|
||||||
operator&(CognitiveComplexity::Criteria LHS,
|
CognitiveComplexity::Criteria RHS) {
|
||||||
CognitiveComplexity::Criteria RHS) {
|
|
||||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
|
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
|
||||||
llvm::to_underlying(RHS));
|
llvm::to_underlying(RHS));
|
||||||
}
|
}
|
||||||
static CognitiveComplexity::Criteria &
|
CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
|
||||||
operator|=(CognitiveComplexity::Criteria &LHS,
|
CognitiveComplexity::Criteria RHS) {
|
||||||
CognitiveComplexity::Criteria RHS) {
|
|
||||||
LHS = operator|(LHS, RHS);
|
LHS = operator|(LHS, RHS);
|
||||||
return LHS;
|
return LHS;
|
||||||
}
|
}
|
||||||
static CognitiveComplexity::Criteria &
|
CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
|
||||||
operator&=(CognitiveComplexity::Criteria &LHS,
|
CognitiveComplexity::Criteria RHS) {
|
||||||
CognitiveComplexity::Criteria RHS) {
|
|
||||||
LHS = operator&(LHS, RHS);
|
LHS = operator&(LHS, RHS);
|
||||||
return LHS;
|
return LHS;
|
||||||
}
|
}
|
||||||
@ -205,8 +199,6 @@ void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
|
|||||||
Total += Increase;
|
Total += Increase;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class FunctionASTVisitor final
|
class FunctionASTVisitor final
|
||||||
: public RecursiveASTVisitor<FunctionASTVisitor> {
|
: public RecursiveASTVisitor<FunctionASTVisitor> {
|
||||||
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
||||||
|
@ -41,11 +41,9 @@ AST_MATCHER(Stmt, isNULLMacroExpansion) {
|
|||||||
return isNULLMacroExpansion(&Node, Finder->getASTContext());
|
return isNULLMacroExpansion(&Node, Finder->getASTContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
||||||
|
QualType Type,
|
||||||
static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
ASTContext &Context) {
|
||||||
QualType Type,
|
|
||||||
ASTContext &Context) {
|
|
||||||
switch (CastExprKind) {
|
switch (CastExprKind) {
|
||||||
case CK_IntegralToBoolean:
|
case CK_IntegralToBoolean:
|
||||||
return Type->isUnsignedIntegerType() ? "0u" : "0";
|
return Type->isUnsignedIntegerType() ? "0u" : "0";
|
||||||
@ -64,15 +62,15 @@ static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
||||||
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
|
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
|
||||||
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
|
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
||||||
const ImplicitCastExpr *Cast,
|
const ImplicitCastExpr *Cast, const Stmt *Parent,
|
||||||
const Stmt *Parent, ASTContext &Context,
|
ASTContext &Context,
|
||||||
bool UseUpperCaseLiteralSuffix) {
|
bool UseUpperCaseLiteralSuffix) {
|
||||||
// In case of expressions like (! integer), we should remove the redundant not
|
// In case of expressions like (! integer), we should remove the redundant not
|
||||||
// operator and use inverted comparison (integer == 0).
|
// operator and use inverted comparison (integer == 0).
|
||||||
bool InvertComparison =
|
bool InvertComparison =
|
||||||
@ -135,8 +133,8 @@ static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
|||||||
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
|
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
if (isNULLMacroExpansion(Expression, Context)) {
|
if (isNULLMacroExpansion(Expression, Context)) {
|
||||||
return "false";
|
return "false";
|
||||||
}
|
}
|
||||||
@ -163,7 +161,7 @@ static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
||||||
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
|
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
|
||||||
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
|
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
|
||||||
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
|
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
|
||||||
@ -175,10 +173,9 @@ static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
|||||||
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
|
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
||||||
const ImplicitCastExpr *Cast,
|
const ImplicitCastExpr *Cast,
|
||||||
ASTContext &Context,
|
ASTContext &Context, StringRef OtherType) {
|
||||||
StringRef OtherType) {
|
|
||||||
if (!Context.getLangOpts().CPlusPlus) {
|
if (!Context.getLangOpts().CPlusPlus) {
|
||||||
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
|
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
|
||||||
(Twine("(") + OtherType + ")").str());
|
(Twine("(") + OtherType + ")").str());
|
||||||
@ -203,9 +200,8 @@ static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringRef
|
StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
||||||
getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
QualType DestType, ASTContext &Context) {
|
||||||
QualType DestType, ASTContext &Context) {
|
|
||||||
// Prior to C++11, false literal could be implicitly converted to pointer.
|
// Prior to C++11, false literal could be implicitly converted to pointer.
|
||||||
if (!Context.getLangOpts().CPlusPlus11 &&
|
if (!Context.getLangOpts().CPlusPlus11 &&
|
||||||
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
|
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
|
||||||
@ -226,8 +222,8 @@ getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
|||||||
return BoolLiteral->getValue() ? "1" : "0";
|
return BoolLiteral->getValue() ? "1" : "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
std::queue<const Stmt *> Q;
|
std::queue<const Stmt *> Q;
|
||||||
Q.push(Cast);
|
Q.push(Cast);
|
||||||
|
|
||||||
@ -255,6 +251,8 @@ static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
|
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -28,11 +28,8 @@ AST_MATCHER_P(QualType, hasUnqualifiedType,
|
|||||||
|
|
||||||
enum class Qualifier { Const, Volatile, Restrict };
|
enum class Qualifier { Const, Volatile, Restrict };
|
||||||
|
|
||||||
} // namespace
|
std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
|
||||||
|
const MatchFinder::MatchResult &Result) {
|
||||||
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
|
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
|
||||||
// sure that we have a consistent `CharSourceRange`, located entirely in the
|
// sure that we have a consistent `CharSourceRange`, located entirely in the
|
||||||
// source file.
|
// source file.
|
||||||
@ -61,7 +58,7 @@ findQualToken(const VarDecl *Decl, Qualifier Qual,
|
|||||||
*Result.SourceManager);
|
*Result.SourceManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<SourceRange>
|
std::optional<SourceRange>
|
||||||
getTypeSpecifierLocation(const VarDecl *Var,
|
getTypeSpecifierLocation(const VarDecl *Var,
|
||||||
const MatchFinder::MatchResult &Result) {
|
const MatchFinder::MatchResult &Result) {
|
||||||
SourceRange TypeSpecifier(
|
SourceRange TypeSpecifier(
|
||||||
@ -76,8 +73,8 @@ getTypeSpecifierLocation(const VarDecl *Var,
|
|||||||
return TypeSpecifier;
|
return TypeSpecifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<SourceRange>
|
std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
|
||||||
mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
|
const Token &ConstToken) {
|
||||||
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
|
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
|
||||||
TypeSpecifier.setBegin(ConstToken.getLocation());
|
TypeSpecifier.setBegin(ConstToken.getLocation());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -89,19 +86,21 @@ mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
|
|||||||
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
|
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isPointerConst(QualType QType) {
|
bool isPointerConst(QualType QType) {
|
||||||
QualType Pointee = QType->getPointeeType();
|
QualType Pointee = QType->getPointeeType();
|
||||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||||
return Pointee.isConstQualified();
|
return Pointee.isConstQualified();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAutoPointerConst(QualType QType) {
|
bool isAutoPointerConst(QualType QType) {
|
||||||
QualType Pointee =
|
QualType Pointee =
|
||||||
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
|
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
|
||||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||||
return Pointee.isConstQualified();
|
return Pointee.isConstQualified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
|
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -14,18 +14,19 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::readability {
|
namespace clang::tidy::readability {
|
||||||
|
|
||||||
static const char *const RedundantReturnDiag =
|
namespace {
|
||||||
"redundant return statement at the end "
|
|
||||||
"of a function with a void return type";
|
|
||||||
static const char *const RedundantContinueDiag =
|
|
||||||
"redundant continue statement at the "
|
|
||||||
"end of loop statement";
|
|
||||||
|
|
||||||
static bool isLocationInMacroExpansion(const SourceManager &SM,
|
const char *const RedundantReturnDiag = "redundant return statement at the end "
|
||||||
SourceLocation Loc) {
|
"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) {
|
||||||
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
|
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
|
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
functionDecl(isDefinition(), returns(voidType()),
|
functionDecl(isDefinition(), returns(voidType()),
|
||||||
|
@ -717,7 +717,7 @@ int clangTidyMain(int argc, const char **argv) {
|
|||||||
EnableModuleHeadersParsing);
|
EnableModuleHeadersParsing);
|
||||||
std::vector<ClangTidyError> Errors =
|
std::vector<ClangTidyError> Errors =
|
||||||
runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
|
runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
|
||||||
FixNotes, EnableCheckProfile, ProfilePrefix, Quiet);
|
FixNotes, EnableCheckProfile, ProfilePrefix);
|
||||||
bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) {
|
bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) {
|
||||||
return E.DiagLevel == ClangTidyError::Error;
|
return E.DiagLevel == ClangTidyError::Error;
|
||||||
});
|
});
|
||||||
|
@ -13,14 +13,16 @@
|
|||||||
|
|
||||||
namespace clang::tidy::utils::type_traits {
|
namespace clang::tidy::utils::type_traits {
|
||||||
|
|
||||||
static bool classHasTrivialCopyAndDestroy(QualType Type) {
|
namespace {
|
||||||
|
|
||||||
|
bool classHasTrivialCopyAndDestroy(QualType Type) {
|
||||||
auto *Record = Type->getAsCXXRecordDecl();
|
auto *Record = Type->getAsCXXRecordDecl();
|
||||||
return Record && Record->hasDefinition() &&
|
return Record && Record->hasDefinition() &&
|
||||||
!Record->hasNonTrivialCopyConstructor() &&
|
!Record->hasNonTrivialCopyConstructor() &&
|
||||||
!Record->hasNonTrivialDestructor();
|
!Record->hasNonTrivialDestructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasDeletedCopyConstructor(QualType Type) {
|
bool hasDeletedCopyConstructor(QualType Type) {
|
||||||
auto *Record = Type->getAsCXXRecordDecl();
|
auto *Record = Type->getAsCXXRecordDecl();
|
||||||
if (!Record || !Record->hasDefinition())
|
if (!Record || !Record->hasDefinition())
|
||||||
return false;
|
return false;
|
||||||
@ -31,6 +33,8 @@ static bool hasDeletedCopyConstructor(QualType Type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::optional<bool> isExpensiveToCopy(QualType Type,
|
std::optional<bool> isExpensiveToCopy(QualType Type,
|
||||||
const ASTContext &Context) {
|
const ASTContext &Context) {
|
||||||
if (Type->isDependentType() || Type->isIncompleteType())
|
if (Type->isDependentType() || Type->isIncompleteType())
|
||||||
|
@ -985,7 +985,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
|
|||||||
// Recurse on pack parameters
|
// Recurse on pack parameters
|
||||||
size_t Depth = 0;
|
size_t Depth = 0;
|
||||||
const FunctionDecl *CurrentFunction = D;
|
const FunctionDecl *CurrentFunction = D;
|
||||||
llvm::SmallPtrSet<const FunctionTemplateDecl *, 4> SeenTemplates;
|
llvm::SmallSet<const FunctionTemplateDecl *, 4> SeenTemplates;
|
||||||
if (const auto *Template = D->getPrimaryTemplate()) {
|
if (const auto *Template = D->getPrimaryTemplate()) {
|
||||||
SeenTemplates.insert(Template);
|
SeenTemplates.insert(Template);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ add_subdirectory(support)
|
|||||||
|
|
||||||
# Configure the Features.inc file.
|
# Configure the Features.inc file.
|
||||||
if (NOT DEFINED CLANGD_BUILD_XPC)
|
if (NOT DEFINED CLANGD_BUILD_XPC)
|
||||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
set(CLANGD_BUILD_XPC_DEFAULT ON)
|
set(CLANGD_BUILD_XPC_DEFAULT ON)
|
||||||
else ()
|
else ()
|
||||||
set(CLANGD_BUILD_XPC_DEFAULT OFF)
|
set(CLANGD_BUILD_XPC_DEFAULT OFF)
|
||||||
@ -193,7 +193,7 @@ if(CLANGD_TIDY_CHECKS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(refactor/tweaks)
|
add_subdirectory(refactor/tweaks)
|
||||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
# FIXME: Make fuzzer not use linux-specific APIs, build it everywhere.
|
# FIXME: Make fuzzer not use linux-specific APIs, build it everywhere.
|
||||||
add_subdirectory(fuzzer)
|
add_subdirectory(fuzzer)
|
||||||
endif()
|
endif()
|
||||||
|
@ -833,10 +833,6 @@ bool OverlayCDB::setCompileCommand(PathRef File,
|
|||||||
std::unique_ptr<ProjectModules>
|
std::unique_ptr<ProjectModules>
|
||||||
OverlayCDB::getProjectModules(PathRef File) const {
|
OverlayCDB::getProjectModules(PathRef File) const {
|
||||||
auto MDB = DelegatingCDB::getProjectModules(File);
|
auto MDB = DelegatingCDB::getProjectModules(File);
|
||||||
if (!MDB) {
|
|
||||||
log("Failed to get compilation Database for {0}", File);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command,
|
MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command,
|
||||||
PathRef CommandPath) {
|
PathRef CommandPath) {
|
||||||
Mangler(Command, CommandPath);
|
Mangler(Command, CommandPath);
|
||||||
|
@ -1876,7 +1876,7 @@ static void fillSubTypes(const SymbolID &ID,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;
|
using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
|
||||||
|
|
||||||
// Extracts parents from AST and populates the type hierarchy item.
|
// Extracts parents from AST and populates the type hierarchy item.
|
||||||
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
|
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
|
||||||
|
@ -181,7 +181,7 @@ struct ExtractionZone {
|
|||||||
bool requiresHoisting(const SourceManager &SM,
|
bool requiresHoisting(const SourceManager &SM,
|
||||||
const HeuristicResolver *Resolver) const {
|
const HeuristicResolver *Resolver) const {
|
||||||
// First find all the declarations that happened inside extraction zone.
|
// First find all the declarations that happened inside extraction zone.
|
||||||
llvm::SmallPtrSet<const Decl *, 1> DeclsInExtZone;
|
llvm::SmallSet<const Decl *, 1> DeclsInExtZone;
|
||||||
for (auto *RootStmt : RootStmts) {
|
for (auto *RootStmt : RootStmts) {
|
||||||
findExplicitReferences(
|
findExplicitReferences(
|
||||||
RootStmt,
|
RootStmt,
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
# A smoke test to check that clangd works without compilation database
|
|
||||||
#
|
|
||||||
# Windows have different escaping modes.
|
|
||||||
# FIXME: We should add one for windows.
|
|
||||||
# UNSUPPORTED: system-windows
|
|
||||||
#
|
|
||||||
# RUN: rm -fr %t
|
|
||||||
# RUN: mkdir -p %t
|
|
||||||
# RUN: split-file %s %t
|
|
||||||
#
|
|
||||||
# RUN: sed -e "s|DIR|%/t|g" %t/definition.jsonrpc.tmpl > %t/definition.jsonrpc
|
|
||||||
#
|
|
||||||
# RUN: clangd -experimental-modules-support -lit-test < %t/definition.jsonrpc \
|
|
||||||
# RUN: | FileCheck -strict-whitespace %t/definition.jsonrpc
|
|
||||||
|
|
||||||
#--- A.h
|
|
||||||
void printA();
|
|
||||||
|
|
||||||
#--- Use.cpp
|
|
||||||
#include "A.h"
|
|
||||||
void foo() {
|
|
||||||
print
|
|
||||||
}
|
|
||||||
|
|
||||||
#--- definition.jsonrpc.tmpl
|
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": 0,
|
|
||||||
"method": "initialize",
|
|
||||||
"params": {
|
|
||||||
"processId": 123,
|
|
||||||
"rootPath": "clangd",
|
|
||||||
"capabilities": {
|
|
||||||
"textDocument": {
|
|
||||||
"completion": {
|
|
||||||
"completionItem": {
|
|
||||||
"snippetSupport": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"trace": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
---
|
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "textDocument/didOpen",
|
|
||||||
"params": {
|
|
||||||
"textDocument": {
|
|
||||||
"uri": "file://DIR/Use.cpp",
|
|
||||||
"languageId": "cpp",
|
|
||||||
"version": 1,
|
|
||||||
"text": "#include \"A.h\"\nvoid foo() {\n print\n}\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# CHECK: "message"{{.*}}printA{{.*}}(fix available)
|
|
||||||
|
|
||||||
---
|
|
||||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file://DIR/Use.cpp"},"context":{"triggerKind":1},"position":{"line":2,"character":6}}}
|
|
||||||
---
|
|
||||||
{"jsonrpc":"2.0","id":2,"method":"shutdown"}
|
|
||||||
---
|
|
||||||
{"jsonrpc":"2.0","method":"exit"}
|
|
@ -4473,198 +4473,6 @@ TEST(CompletionTest, SkipExplicitObjectParameter) {
|
|||||||
snippetSuffix(""))));
|
snippetSuffix(""))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {
|
|
||||||
Annotations Code(R"cpp(
|
|
||||||
struct A {
|
|
||||||
int member {};
|
|
||||||
int memberFnA(int a);
|
|
||||||
int memberFnA(this A&, float a);
|
|
||||||
|
|
||||||
void foo(this A& self) {
|
|
||||||
// Should not offer any members here, since
|
|
||||||
// it needs to be referenced through `self`.
|
|
||||||
mem$c1^;
|
|
||||||
// should offer all results
|
|
||||||
self.mem$c2^;
|
|
||||||
|
|
||||||
[&]() {
|
|
||||||
// should not offer any results
|
|
||||||
mem$c3^;
|
|
||||||
}();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
)cpp");
|
|
||||||
|
|
||||||
auto TU = TestTU::withCode(Code.code());
|
|
||||||
TU.ExtraArgs = {"-std=c++23"};
|
|
||||||
|
|
||||||
auto Preamble = TU.preamble();
|
|
||||||
ASSERT_TRUE(Preamble);
|
|
||||||
|
|
||||||
CodeCompleteOptions Opts{};
|
|
||||||
|
|
||||||
MockFS FS;
|
|
||||||
auto Inputs = TU.inputs(FS);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
|
|
||||||
EXPECT_THAT(Result.Completions, ElementsAre());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(named("member"),
|
|
||||||
AllOf(named("memberFnA"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("memberFnA"), signature("(float a)"),
|
|
||||||
snippetSuffix("(${1:float a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
|
|
||||||
EXPECT_THAT(Result.Completions, ElementsAre());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CompletionTest, ListExplicitObjectOverloads) {
|
|
||||||
Annotations Code(R"cpp(
|
|
||||||
struct S {
|
|
||||||
void foo1(int a);
|
|
||||||
void foo2(int a) const;
|
|
||||||
void foo2(this const S& self, float a);
|
|
||||||
void foo3(this const S& self, int a);
|
|
||||||
void foo4(this S& self, int a);
|
|
||||||
};
|
|
||||||
|
|
||||||
void S::foo1(int a) {
|
|
||||||
this->$c1^;
|
|
||||||
}
|
|
||||||
|
|
||||||
void S::foo2(int a) const {
|
|
||||||
this->$c2^;
|
|
||||||
}
|
|
||||||
|
|
||||||
void S::foo3(this const S& self, int a) {
|
|
||||||
self.$c3^;
|
|
||||||
}
|
|
||||||
|
|
||||||
void S::foo4(this S& self, int a) {
|
|
||||||
self.$c4^;
|
|
||||||
}
|
|
||||||
|
|
||||||
void test1(S s) {
|
|
||||||
s.$c5^;
|
|
||||||
}
|
|
||||||
|
|
||||||
void test2(const S s) {
|
|
||||||
s.$c6^;
|
|
||||||
}
|
|
||||||
)cpp");
|
|
||||||
|
|
||||||
auto TU = TestTU::withCode(Code.code());
|
|
||||||
TU.ExtraArgs = {"-std=c++23"};
|
|
||||||
|
|
||||||
auto Preamble = TU.preamble();
|
|
||||||
ASSERT_TRUE(Preamble);
|
|
||||||
|
|
||||||
CodeCompleteOptions Opts{};
|
|
||||||
|
|
||||||
MockFS FS;
|
|
||||||
auto Inputs = TU.inputs(FS);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo4"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c4"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo4"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c5"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo4"), signature("(int a)"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto Result = codeComplete(testPath(TU.Filename), Code.point("c6"),
|
|
||||||
Preamble.get(), Inputs, Opts);
|
|
||||||
EXPECT_THAT(
|
|
||||||
Result.Completions,
|
|
||||||
UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})")),
|
|
||||||
AllOf(named("foo2"), signature("(float a) const"),
|
|
||||||
snippetSuffix("(${1:float a})")),
|
|
||||||
AllOf(named("foo3"), signature("(int a) const"),
|
|
||||||
snippetSuffix("(${1:int a})"))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace clangd
|
} // namespace clangd
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
@ -731,12 +731,6 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
|
|||||||
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
|
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
|
||||||
)cpp";
|
)cpp";
|
||||||
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
|
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
|
||||||
|
|
||||||
Code = R"cpp(
|
|
||||||
template <template <class...> class Templ, class... Types>
|
|
||||||
using dedup_types = Templ<[[__builtin_dedup_pack]]<Types...>...>;
|
|
||||||
)cpp";
|
|
||||||
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TargetDeclTest, MemberOfTemplate) {
|
TEST_F(TargetDeclTest, MemberOfTemplate) {
|
||||||
|
@ -119,9 +119,6 @@ Improvements to clang-tidy
|
|||||||
- Improved documentation of the `-line-filter` command-line flag of
|
- Improved documentation of the `-line-filter` command-line flag of
|
||||||
:program:`clang-tidy` and :program:`run-clang-tidy.py`.
|
:program:`clang-tidy` and :program:`run-clang-tidy.py`.
|
||||||
|
|
||||||
- Improved :program:`clang-tidy` option `-quiet` by suppressing diagnostic
|
|
||||||
count messages.
|
|
||||||
|
|
||||||
New checks
|
New checks
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
@ -215,8 +212,7 @@ Changes in existing checks
|
|||||||
|
|
||||||
- Improved :doc:`readability-identifier-naming
|
- Improved :doc:`readability-identifier-naming
|
||||||
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
|
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
|
||||||
declarations in system headers. The documentation is also improved to
|
declarations in system headers.
|
||||||
differentiate the general options from the specific ones.
|
|
||||||
|
|
||||||
- Improved :doc:`readability-qualified-auto
|
- Improved :doc:`readability-qualified-auto
|
||||||
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
|
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
|
||||||
|
@ -1,314 +0,0 @@
|
|||||||
======================
|
|
||||||
Clang-Change-Namespace
|
|
||||||
======================
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
:program:`clang-change-namespace` can be used to change the surrounding
|
|
||||||
namespaces of class/function definitions.
|
|
||||||
|
|
||||||
Classes/functions in the moved namespace will have new namespaces while
|
|
||||||
references to symbols (e.g. types, functions) which are not defined in the
|
|
||||||
changed namespace will be correctly qualified by prepending namespace specifiers
|
|
||||||
before them. This will try to add shortest namespace specifiers possible.
|
|
||||||
|
|
||||||
When a symbol reference needs to be fully-qualified, this adds a `::` prefix to
|
|
||||||
the namespace specifiers unless the new namespace is the global namespace. For
|
|
||||||
classes, only classes that are declared/defined in the given namespace in
|
|
||||||
specified files will be moved: forward declarations will remain in the old
|
|
||||||
namespace. The will be demonstrated in the next example.
|
|
||||||
|
|
||||||
Example usage
|
|
||||||
-------------
|
|
||||||
|
|
||||||
For example, consider this `test.cc` example here with the forward declared
|
|
||||||
class `FWD` and the defined class `A`, both in the namespace `a`.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace a {
|
|
||||||
class FWD;
|
|
||||||
class A {
|
|
||||||
FWD *fwd;
|
|
||||||
};
|
|
||||||
} // namespace a
|
|
||||||
|
|
||||||
And now let's change the namespace `a` to `x`.
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
clang-change-namespace \
|
|
||||||
--old_namespace "a" \
|
|
||||||
--new_namespace "x" \
|
|
||||||
--file_pattern "test.cc" \
|
|
||||||
--i \
|
|
||||||
test.cc
|
|
||||||
|
|
||||||
Note that in the code below there's still the forward decalred class `FWD` that
|
|
||||||
stayed in the namespace `a`. It wasn't moved to the new namespace because it
|
|
||||||
wasn't defined/declared here in `a` but only forward declared.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace a {
|
|
||||||
class FWD;
|
|
||||||
} // namespace a
|
|
||||||
namespace x {
|
|
||||||
|
|
||||||
class A {
|
|
||||||
a::FWD *fwd;
|
|
||||||
};
|
|
||||||
} // namespace x
|
|
||||||
|
|
||||||
|
|
||||||
Another example
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Consider this `test.cc` file:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace na {
|
|
||||||
class X {};
|
|
||||||
namespace nb {
|
|
||||||
class Y {
|
|
||||||
X x;
|
|
||||||
};
|
|
||||||
} // namespace nb
|
|
||||||
} // namespace na
|
|
||||||
|
|
||||||
To move the definition of class `Y` from namespace `na::nb` to `x::y`, run:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
clang-change-namespace \
|
|
||||||
--old_namespace "na::nb" \
|
|
||||||
--new_namespace "x::y" \
|
|
||||||
--file_pattern "test.cc" \
|
|
||||||
--i \
|
|
||||||
test.cc
|
|
||||||
|
|
||||||
This will overwrite `test.cc` to look like this:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace na {
|
|
||||||
class X {};
|
|
||||||
|
|
||||||
} // namespace na
|
|
||||||
namespace x {
|
|
||||||
namespace y {
|
|
||||||
class Y {
|
|
||||||
na::X x;
|
|
||||||
};
|
|
||||||
} // namespace y
|
|
||||||
} // namespace x
|
|
||||||
|
|
||||||
Note, that we've successfully moved the class `Y` from namespace `na::nb` to
|
|
||||||
namespace `x::y`.
|
|
||||||
|
|
||||||
Caveats
|
|
||||||
=======
|
|
||||||
|
|
||||||
Content already exists in new namespace
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
Consider this `test.cc` example that defines two `class A` one inside the
|
|
||||||
namespace `a` and one in namespace `b`:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace a {
|
|
||||||
class A {
|
|
||||||
int classAFromWithinNamespace_a;
|
|
||||||
};
|
|
||||||
} // namespace a
|
|
||||||
|
|
||||||
namespace b {
|
|
||||||
class A {
|
|
||||||
int classAFromWithinNamespace_b;
|
|
||||||
};
|
|
||||||
} //namespace b
|
|
||||||
|
|
||||||
Let's move everything from namespace `a` to namespace `b`:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
clang-change-namespace \
|
|
||||||
--old_namespace "a" \
|
|
||||||
--new_namespace "b" \
|
|
||||||
--file_pattern test.cc \
|
|
||||||
test.cc
|
|
||||||
|
|
||||||
As expected we now have to definitions of `class A` inside the namespace `b`:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace b {
|
|
||||||
class A {
|
|
||||||
int classAFromWithinNamespace_a;
|
|
||||||
};
|
|
||||||
} // namespace b
|
|
||||||
|
|
||||||
namespace b {
|
|
||||||
class A {
|
|
||||||
int classAFromWithinNamespace_b;
|
|
||||||
};
|
|
||||||
} //namespace b
|
|
||||||
|
|
||||||
The re-factoring looks correct but the code will not compile due to the name
|
|
||||||
duplication. It is not up to the tool to ensure compilability in that sense.
|
|
||||||
But one has to be aware of that.
|
|
||||||
|
|
||||||
Inline namespace doesn't work
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Consider this usage of two versions of implementations for a `greet` function:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace Greeter {
|
|
||||||
inline namespace Version1 {
|
|
||||||
const char* greet() { return "Hello from version 1!"; }
|
|
||||||
} // namespace Version1
|
|
||||||
namespace Version2 {
|
|
||||||
const char* greet() { return "Hello from version 2!"; }
|
|
||||||
} // namespace Version2
|
|
||||||
} // namespace Greeter
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
printf("%s\n", Greeter::greet());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Note, that currently `Greeter::greet()` will result in a call to
|
|
||||||
`Greeter::Version1::greet()` because that's the inlined namespace.
|
|
||||||
|
|
||||||
Let's say you want to move one and make `Version2` the default now and remove
|
|
||||||
the `inline` from the `Version1`. First let's try to turn `namespace Version2`
|
|
||||||
into `inline namespace Version2`:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
clang-change-namespace \
|
|
||||||
--old_namespace "Greeter::Version2" \
|
|
||||||
--new_namespace "inline Version2" \
|
|
||||||
--file_pattern main.cc main.cc
|
|
||||||
|
|
||||||
But this will put the `inline` keyword in the wrong place resulting in:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace Greeter {
|
|
||||||
inline namespace Version1 {
|
|
||||||
const char* greet() { return "Hello from version 1!"; }
|
|
||||||
} // namespace Version1
|
|
||||||
|
|
||||||
} // namespace Greeter
|
|
||||||
namespace inline Greeter {
|
|
||||||
namespace Version2 {
|
|
||||||
const char *greet() { return "Hello from version 2!"; }
|
|
||||||
} // namespace Version2
|
|
||||||
} // namespace inline Greeter
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
printf("%s\n", Greeter::greet());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
One cannot use `:program:`clang-change-namespace` to inline a namespace.
|
|
||||||
|
|
||||||
Symbol references not updated
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Consider this `test.cc` file:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace old {
|
|
||||||
struct foo {};
|
|
||||||
} // namespace old
|
|
||||||
|
|
||||||
namespace b {
|
|
||||||
old::foo g_foo;
|
|
||||||
} // namespace b
|
|
||||||
|
|
||||||
Notice that namespace `b` defines a global variable of type `old::foo`. If we
|
|
||||||
now change the name of the `old` namespace to `modern`, the reference will not
|
|
||||||
be updated:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
clang-change-namespace \
|
|
||||||
--old_namespace "old" \
|
|
||||||
--new_namespace "modern" \
|
|
||||||
--file_pattern test.cc \
|
|
||||||
test.cc
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
namespace modern {
|
|
||||||
struct foo {};
|
|
||||||
} // namespace modern
|
|
||||||
|
|
||||||
namespace b {
|
|
||||||
old::foo g_foo;
|
|
||||||
} // namespace b
|
|
||||||
|
|
||||||
`g_foo` is still of the no longer existing type `old::foo` while instead it
|
|
||||||
should use `modern::foo`.
|
|
||||||
|
|
||||||
Only symbol references in the moved namespace are updated, not outside of it.
|
|
||||||
|
|
||||||
|
|
||||||
:program:`clang-change-namespace` Command Line Options
|
|
||||||
======================================================
|
|
||||||
|
|
||||||
.. option:: --allowed_file=<string>
|
|
||||||
|
|
||||||
A file containing regexes of symbol names that are not expected to be updated
|
|
||||||
when changing namespaces around them.
|
|
||||||
|
|
||||||
.. option:: --dump_result
|
|
||||||
|
|
||||||
Dump new file contents in YAML, if specified.
|
|
||||||
|
|
||||||
.. option:: --extra-arg=<string>
|
|
||||||
|
|
||||||
Additional argument to append to the compiler command line
|
|
||||||
|
|
||||||
.. option:: --extra-arg-before=<string>
|
|
||||||
|
|
||||||
Additional argument to prepend to the compiler command line
|
|
||||||
|
|
||||||
.. option:: --file_pattern=<string>
|
|
||||||
|
|
||||||
Only rename namespaces in files that match the given regular expression
|
|
||||||
pattern.
|
|
||||||
|
|
||||||
.. option:: -i
|
|
||||||
|
|
||||||
Inplace edit <file>s, if specified.
|
|
||||||
|
|
||||||
.. option:: --new_namespace=<string>
|
|
||||||
|
|
||||||
New namespace. Use `""` when you target the global namespace.
|
|
||||||
|
|
||||||
.. option:: --old_namespace=<string>
|
|
||||||
|
|
||||||
Old namespace.
|
|
||||||
|
|
||||||
.. option:: -p <string>
|
|
||||||
|
|
||||||
Build path
|
|
||||||
|
|
||||||
.. option:: --style=<string>
|
|
||||||
|
|
||||||
The style name used for reformatting.
|
|
@ -43,21 +43,14 @@ The options and their corresponding values are:
|
|||||||
- ``LowerCase`` - example: ``int i_Variable``
|
- ``LowerCase`` - example: ``int i_Variable``
|
||||||
- ``CamelCase`` - example: ``int IVariable``
|
- ``CamelCase`` - example: ``int IVariable``
|
||||||
|
|
||||||
Options summary
|
Options
|
||||||
---------------
|
-------
|
||||||
|
|
||||||
The available options are summarized below:
|
The following options are described below:
|
||||||
|
|
||||||
**General options**
|
|
||||||
|
|
||||||
- :option:`AggressiveDependentMemberLookup`
|
|
||||||
- :option:`CheckAnonFieldInParent`
|
|
||||||
- :option:`GetConfigPerFile`
|
|
||||||
- :option:`IgnoreMainLikeFunctions`
|
|
||||||
|
|
||||||
**Specific options**
|
|
||||||
|
|
||||||
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
||||||
|
- :option:`AggressiveDependentMemberLookup`
|
||||||
|
- :option:`CheckAnonFieldInParent`
|
||||||
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
|
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
|
||||||
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
|
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
|
||||||
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
|
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
|
||||||
@ -73,11 +66,13 @@ The available options are summarized below:
|
|||||||
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
|
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
|
||||||
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
|
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
|
||||||
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
|
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
|
||||||
|
- :option:`GetConfigPerFile`
|
||||||
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
|
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
|
||||||
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
|
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
|
||||||
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
|
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
|
||||||
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
|
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
|
||||||
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
|
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
|
||||||
|
- :option:`IgnoreMainLikeFunctions`
|
||||||
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
|
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
|
||||||
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
|
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
|
||||||
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
|
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
|
||||||
@ -110,12 +105,6 @@ The available options are summarized below:
|
|||||||
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
|
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
|
||||||
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
|
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
|
||||||
|
|
||||||
|
|
||||||
Options description
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
A detailed description of each option is presented below:
|
|
||||||
|
|
||||||
.. option:: AbstractClassCase
|
.. option:: AbstractClassCase
|
||||||
|
|
||||||
When defined, the check will ensure abstract class names conform to the
|
When defined, the check will ensure abstract class names conform to the
|
||||||
|
@ -343,107 +343,6 @@ An overview of all the command-line options:
|
|||||||
some-check.SomeOption: 'some value'
|
some-check.SomeOption: 'some value'
|
||||||
...
|
...
|
||||||
|
|
||||||
Clang-Tidy Automation
|
|
||||||
=====================
|
|
||||||
|
|
||||||
:program:`clang-tidy` can analyze multiple source files by specifying them on
|
|
||||||
the command line. For larger projects, automation scripts provide additional
|
|
||||||
functionality like parallel execution and integration with version control
|
|
||||||
systems.
|
|
||||||
|
|
||||||
Running Clang-Tidy in Parallel
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
:program:`clang-tidy` can process multiple files sequentially, but for projects
|
|
||||||
with many source files, the :program:`run-clang-tidy.py` script provides
|
|
||||||
parallel execution to significantly reduce analysis time. This script is
|
|
||||||
included with clang-tidy and runs :program:`clang-tidy` over all files in a
|
|
||||||
compilation database or a specified path concurrently.
|
|
||||||
|
|
||||||
The script requires a compilation database (``compile_commands.json``) which
|
|
||||||
can be generated by build systems like CMake (using
|
|
||||||
``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON``) or by tools like `Bear`_.
|
|
||||||
|
|
||||||
The script supports most of the same options as :program:`clang-tidy` itself,
|
|
||||||
including ``-checks=``, ``-fix``, ``-header-filter=``, and configuration
|
|
||||||
options. Run ``run-clang-tidy.py --help`` for a complete list of available
|
|
||||||
options.
|
|
||||||
|
|
||||||
Example invocations:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
# Run clang-tidy on all files in the compilation database in parallel
|
|
||||||
$ run-clang-tidy.py -p=build/
|
|
||||||
|
|
||||||
# Run with specific checks and apply fixes
|
|
||||||
$ run-clang-tidy.py -p=build/ -fix -checks=-*,readability-*
|
|
||||||
|
|
||||||
# Run on specific files/directories with header filtering
|
|
||||||
$ run-clang-tidy.py -p=build/ -header-filter=src/ src/
|
|
||||||
|
|
||||||
# Run with parallel execution (uses all CPU cores by default)
|
|
||||||
$ run-clang-tidy.py -p=build/ -j 4
|
|
||||||
|
|
||||||
Running Clang-Tidy on Diff
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
The :program:`clang-tidy-diff.py` script allows you to run
|
|
||||||
:program:`clang-tidy` on the lines that have been modified in your working
|
|
||||||
directory or in a specific diff. Importantly, :program:`clang-tidy-diff.py` only reports
|
|
||||||
diagnostics for changed lines; :program:`clang-tidy` still analyzes the entire
|
|
||||||
file and filters out unchanged lines after analysis, so this does not improve
|
|
||||||
performance. This is particularly useful for code reviews and continuous
|
|
||||||
integration, as it focuses analysis on the changed code rather than the entire
|
|
||||||
codebase.
|
|
||||||
|
|
||||||
The script can work with various diff sources:
|
|
||||||
|
|
||||||
* Git working directory changes
|
|
||||||
* Output from ``git diff``
|
|
||||||
* Output from ``svn diff``
|
|
||||||
* Patch files
|
|
||||||
|
|
||||||
Example invocations:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
# Run clang-tidy on all changes in the working directory
|
|
||||||
$ git diff -U0 --no-color HEAD^ | clang-tidy-diff.py -p1
|
|
||||||
|
|
||||||
# Run with specific checks and apply fixes
|
|
||||||
$ git diff -U0 --no-color HEAD^ | clang-tidy-diff.py -p1 -fix \
|
|
||||||
-checks=-*,readability-*
|
|
||||||
|
|
||||||
# Run on staged changes
|
|
||||||
$ git diff -U0 --no-color --cached | clang-tidy-diff.py -p1
|
|
||||||
|
|
||||||
# Run on changes between two commits
|
|
||||||
$ git diff -U0 --no-color HEAD~2 HEAD | clang-tidy-diff.py -p1
|
|
||||||
|
|
||||||
# Run on a patch file
|
|
||||||
$ clang-tidy-diff.py -p1 < changes.patch
|
|
||||||
|
|
||||||
The ``-p1`` option tells the script to strip one level of path prefix from
|
|
||||||
the diff, which is typically needed for Git diffs. The script supports most of
|
|
||||||
the same options as :program:`clang-tidy` itself, including ``-checks=``,
|
|
||||||
``-fix``, ``-header-filter=``, and configuration options.
|
|
||||||
|
|
||||||
While :program:`clang-tidy-diff.py` is useful for focusing on recent changes,
|
|
||||||
relying solely on it may lead to incomplete analysis. Since the script only
|
|
||||||
reports warnings from the modified lines, it may miss issues that are caused
|
|
||||||
by the changes but manifest elsewhere in the code. For example, changes that
|
|
||||||
only add lines to a function may cause it to violate size limits (e.g.,
|
|
||||||
`readability-function-size <checks/readability/function-size.html>`_), but the
|
|
||||||
diagnostic will be reported at the function declaration, which may not be in
|
|
||||||
the diff and thus filtered out. Modifications to header files may also affect
|
|
||||||
many implementation files, but only warnings in the modified header lines will
|
|
||||||
be reported.
|
|
||||||
|
|
||||||
For comprehensive analysis, especially before merging significant changes,
|
|
||||||
consider running :program:`clang-tidy` on the entire affected files or the
|
|
||||||
whole project using :program:`run-clang-tidy.py`.
|
|
||||||
|
|
||||||
.. _clang-tidy-nolint:
|
.. _clang-tidy-nolint:
|
||||||
|
|
||||||
Suppressing Undesired Diagnostics
|
Suppressing Undesired Diagnostics
|
||||||
@ -566,6 +465,5 @@ example, ``NOLINTBEGIN(check-name)`` can be paired with
|
|||||||
:program:`clang-tidy` will generate a ``clang-tidy-nolint`` error diagnostic if
|
:program:`clang-tidy` will generate a ``clang-tidy-nolint`` error diagnostic if
|
||||||
any ``NOLINTBEGIN``/``NOLINTEND`` comment violates these requirements.
|
any ``NOLINTBEGIN``/``NOLINTEND`` comment violates these requirements.
|
||||||
|
|
||||||
.. _Bear: https://github.com/rizsotto/Bear
|
|
||||||
.. _LibTooling: https://clang.llvm.org/docs/LibTooling.html
|
.. _LibTooling: https://clang.llvm.org/docs/LibTooling.html
|
||||||
.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
|
.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
|
||||||
|
@ -17,7 +17,6 @@ Contents
|
|||||||
|
|
||||||
clang-tidy/index
|
clang-tidy/index
|
||||||
clang-include-fixer
|
clang-include-fixer
|
||||||
clang-change-namespace
|
|
||||||
modularize
|
modularize
|
||||||
pp-trace
|
pp-trace
|
||||||
clangd <https://clangd.llvm.org/>
|
clangd <https://clangd.llvm.org/>
|
||||||
|
@ -176,11 +176,3 @@ struct TemplateAssignment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace GH153770 {
|
|
||||||
struct A;
|
|
||||||
struct A {
|
|
||||||
A() = default;
|
|
||||||
A& operator=(const A&) = default;
|
|
||||||
};
|
|
||||||
} // namespace GH153770
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
|
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
|
||||||
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
|
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s
|
||||||
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s
|
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s
|
||||||
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER --allow-empty %s
|
// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s
|
||||||
|
|
||||||
// Check that `-header-filter` operates on the same file paths as paths in
|
// Check that `-header-filter` operates on the same file paths as paths in
|
||||||
// diagnostics printed by ClangTidy.
|
// diagnostics printed by ClangTidy.
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
// This test ensures that the --quiet flag only suppresses the "X warnings generated"
|
|
||||||
// message while keeping all diagnostic information including caret indicators (^).
|
|
||||||
|
|
||||||
// RUN: clang-tidy -checks=-*,readability-magic-numbers,clang-diagnostic-sign-compare %s -- \
|
|
||||||
// RUN: -Wsign-compare 2>&1 | FileCheck %s --check-prefix=CHECK-NORMAL
|
|
||||||
// RUN: clang-tidy -checks=-*,readability-magic-numbers,clang-diagnostic-sign-compare -quiet %s -- \
|
|
||||||
// RUN: -Wsign-compare 2>&1 | FileCheck %s --check-prefix=CHECK-QUIET
|
|
||||||
|
|
||||||
// CHECK-NORMAL: 2 warnings generated
|
|
||||||
// CHECK-NORMAL-DAG: warning: 42 is a magic number
|
|
||||||
// CHECK-NORMAL-DAG: {{[ ]*\^}}
|
|
||||||
// CHECK-NORMAL-DAG: warning: comparison of integers of different signs
|
|
||||||
// CHECK-NORMAL-DAG: {{[ ]*~ \^ ~}}
|
|
||||||
|
|
||||||
// CHECK-QUIET-NOT: {{[0-9]+}} warning{{s?}} generated
|
|
||||||
// CHECK-QUIET-DAG: warning: 42 is a magic number
|
|
||||||
// CHECK-QUIET-DAG: {{[ ]*\^}}
|
|
||||||
// CHECK-QUIET-DAG: warning: comparison of integers of different signs
|
|
||||||
// CHECK-QUIET-DAG: {{[ ]*~ \^ ~}}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
const int CONST_VAL = 10;
|
|
||||||
int x = 42; // trigger 'readability-magic-numbers' with caret: ^
|
|
||||||
unsigned int y = CONST_VAL;
|
|
||||||
return x < y; // trigger 'clang-diagnostic-sign-compare' with caret: ^
|
|
||||||
}
|
|
@ -35,7 +35,7 @@ if(WIN32)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The Python FFI interface is broken on AIX: https://bugs.python.org/issue38628.
|
# The Python FFI interface is broken on AIX: https://bugs.python.org/issue38628.
|
||||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||||
set(RUN_PYTHON_TESTS FALSE)
|
set(RUN_PYTHON_TESTS FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -60,10 +60,6 @@ only for the linker wrapper will be forwarded to the wrapped linker job.
|
|||||||
--v Display the version number and exit
|
--v Display the version number and exit
|
||||||
-- The separator for the wrapped linker arguments
|
-- The separator for the wrapped linker arguments
|
||||||
|
|
||||||
The linker wrapper will generate the appropriate runtime calls to register the
|
|
||||||
generated device binary with the offloading runtime. To do this step manually we
|
|
||||||
provide the ``llvm-offload-wrapper`` utility.
|
|
||||||
|
|
||||||
Relocatable Linking
|
Relocatable Linking
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
@ -9,14 +9,14 @@ Introduction
|
|||||||
============
|
============
|
||||||
|
|
||||||
Coroutines in C++ were introduced in C++20, and the user experience for
|
Coroutines in C++ were introduced in C++20, and the user experience for
|
||||||
debugging them can still be challenging. This document guides you on how to most
|
debugging them can still be challenging. This document guides you how to most
|
||||||
efficiently debug coroutines and how to navigate existing shortcomings in
|
efficiently debug coroutines and how to navigate existing shortcomings in
|
||||||
debuggers and compilers.
|
debuggers and compilers.
|
||||||
|
|
||||||
Coroutines are generally used either as generators or for asynchronous
|
Coroutines are generally used either as generators or for asynchronous
|
||||||
programming. In this document, we will discuss both use cases. Even if you are
|
programming. In this document, we will discuss both use cases. Even if you are
|
||||||
using coroutines for asynchronous programming, you should still read the
|
using coroutines for asynchronous programming, you should still read the
|
||||||
generators section, as it introduces foundational debugging techniques also
|
generators section, as it will introduce foundational debugging techniques also
|
||||||
applicable to the debugging of asynchronous programs.
|
applicable to the debugging of asynchronous programs.
|
||||||
|
|
||||||
Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are
|
Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are
|
||||||
@ -34,15 +34,15 @@ scripting. This guide comes with a basic GDB script for coroutine debugging.
|
|||||||
This guide will first showcase the more polished, bleeding-edge experience, but
|
This guide will first showcase the more polished, bleeding-edge experience, but
|
||||||
will also show you how to debug coroutines with older toolchains. In general,
|
will also show you how to debug coroutines with older toolchains. In general,
|
||||||
the older your toolchain, the deeper you will have to dive into the
|
the older your toolchain, the deeper you will have to dive into the
|
||||||
implementation details of coroutines (such as their ABI). The further down you go in
|
implementation details of coroutines (such as their ABI). The further down in
|
||||||
this document, the more low-level, technical the content will become. If
|
this document you go, the more low-level, technical the content will become. If
|
||||||
you are on an up-to-date toolchain, you will hopefully be able to stop reading
|
you are on an up-to-date toolchain, you will hopefully be able to stop reading
|
||||||
earlier.
|
earlier.
|
||||||
|
|
||||||
Debugging generators
|
Debugging generators
|
||||||
====================
|
====================
|
||||||
|
|
||||||
One of the two major use cases for coroutines in C++ is generators, i.e.,
|
One of the two major use cases for coroutines in C++ are generators, i.e.,
|
||||||
functions which can produce values via ``co_yield``. Values are produced
|
functions which can produce values via ``co_yield``. Values are produced
|
||||||
lazily, on-demand. For this purpose, every time a new value is requested, the
|
lazily, on-demand. For this purpose, every time a new value is requested, the
|
||||||
coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby
|
coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby
|
||||||
@ -141,7 +141,7 @@ a regular function.
|
|||||||
|
|
||||||
Note the two additional variables ``__promise`` and ``__coro_frame``. Those
|
Note the two additional variables ``__promise`` and ``__coro_frame``. Those
|
||||||
show the internal state of the coroutine. They are not relevant for our
|
show the internal state of the coroutine. They are not relevant for our
|
||||||
generator example but will be relevant for asynchronous programming described
|
generator example, but will be relevant for asynchronous programming described
|
||||||
in the next section.
|
in the next section.
|
||||||
|
|
||||||
Stepping out of a coroutine
|
Stepping out of a coroutine
|
||||||
@ -174,7 +174,7 @@ Inspecting a suspended coroutine
|
|||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
The ``print10Elements`` function receives an opaque ``generator`` type. Let's
|
The ``print10Elements`` function receives an opaque ``generator`` type. Let's
|
||||||
assume we are suspended at the ``++gen;`` line and want to inspect the
|
assume we are suspended at the ``++gen;`` line, and want to inspect the
|
||||||
generator and its internal state.
|
generator and its internal state.
|
||||||
|
|
||||||
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
|
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
|
||||||
@ -188,7 +188,7 @@ We can see two function pointers ``resume`` and ``destroy``. These pointers
|
|||||||
point to the resume / destroy functions. By inspecting those function pointers,
|
point to the resume / destroy functions. By inspecting those function pointers,
|
||||||
we can see that our ``generator`` is actually backed by our ``fibonacci``
|
we can see that our ``generator`` is actually backed by our ``fibonacci``
|
||||||
coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function
|
coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function
|
||||||
address (``0x555...`` in the screenshot) to jump directly to the function
|
address (``0x555...`` in the screenshot) to directly jump to the function
|
||||||
definition backing your coroutine handle.
|
definition backing your coroutine handle.
|
||||||
|
|
||||||
Next, we see the ``promise``. In our case, this reveals the current value of
|
Next, we see the ``promise``. In our case, this reveals the current value of
|
||||||
@ -247,12 +247,12 @@ the line number of the current suspension point in the promise:
|
|||||||
};
|
};
|
||||||
|
|
||||||
This stores the return address of ``await_suspend`` within the promise.
|
This stores the return address of ``await_suspend`` within the promise.
|
||||||
Thereby, we can read it back from the promise of a suspended coroutine and map
|
Thereby, we can read it back from the promise of a suspended coroutine, and map
|
||||||
it to an exact source code location. For a complete example, see the ``task``
|
it to an exact source code location. For a complete example, see the ``task``
|
||||||
type used below for asynchronous programming.
|
type used below for asynchronous programming.
|
||||||
|
|
||||||
Alternatively, we can modify the C++ code to store the line number in the
|
Alternatively, we can modify the C++ code to store the line number in the
|
||||||
promise type. We can use ``std::source_location`` to get the line number of
|
promise type. We can use a ``std::source_location`` to get the line number of
|
||||||
the await and store it inside the ``promise_type``. In the debugger, we can
|
the await and store it inside the ``promise_type``. In the debugger, we can
|
||||||
then read the line number from the promise of the suspended coroutine.
|
then read the line number from the promise of the suspended coroutine.
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ then read the line number from the promise of the suspended coroutine.
|
|||||||
};
|
};
|
||||||
|
|
||||||
The downside of both approaches is that they come at the price of additional
|
The downside of both approaches is that they come at the price of additional
|
||||||
runtime cost. In particular, the second approach increases binary size, since it
|
runtime cost. In particular the second approach increases binary size, since it
|
||||||
requires additional ``std::source_location`` objects, and those source
|
requires additional ``std::source_location`` objects, and those source
|
||||||
locations are not stripped by split-dwarf. Whether the first approach is worth
|
locations are not stripped by split-dwarf. Whether the first approach is worth
|
||||||
the additional runtime cost is a trade-off you need to make yourself.
|
the additional runtime cost is a trade-off you need to make yourself.
|
||||||
@ -285,7 +285,7 @@ provide custom debugging support, so in addition to this guide, you might want
|
|||||||
to check out their documentation.
|
to check out their documentation.
|
||||||
|
|
||||||
When using coroutines for asynchronous programming, your library usually
|
When using coroutines for asynchronous programming, your library usually
|
||||||
provides you with some ``task`` type. This type usually looks similar to this:
|
provides you some ``task`` type. This type usually looks similar to this:
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ One such solution is to store the list of in-flight coroutines in a collection:
|
|||||||
};
|
};
|
||||||
|
|
||||||
With this in place, it is possible to inspect ``inflight_coroutines`` from the
|
With this in place, it is possible to inspect ``inflight_coroutines`` from the
|
||||||
debugger and rely on LLDB's ``std::coroutine_handle`` pretty-printer to
|
debugger, and rely on LLDB's ``std::coroutine_handle`` pretty-printer to
|
||||||
inspect the coroutines.
|
inspect the coroutines.
|
||||||
|
|
||||||
This technique will track *all* coroutines, also the ones which are currently
|
This technique will track *all* coroutines, also the ones which are currently
|
||||||
@ -498,8 +498,8 @@ LLDB before 21.0 did not yet show the ``__coro_frame`` inside
|
|||||||
``coroutine_handle``. To inspect the coroutine frame, you had to use the
|
``coroutine_handle``. To inspect the coroutine frame, you had to use the
|
||||||
approach described in the :ref:`devirtualization` section.
|
approach described in the :ref:`devirtualization` section.
|
||||||
|
|
||||||
LLDB before 18.0 hid the ``__promise`` and ``__coro_frame``
|
LLDB before 18.0 was hiding the ``__promise`` and ``__coro_frame``
|
||||||
variables by default. The variables are still present, but they need to be
|
variable by default. The variables are still present, but they need to be
|
||||||
explicitly added to the "watch" pane in VS Code or requested via
|
explicitly added to the "watch" pane in VS Code or requested via
|
||||||
``print __promise`` and ``print __coro_frame`` from the debugger console.
|
``print __promise`` and ``print __coro_frame`` from the debugger console.
|
||||||
|
|
||||||
@ -511,9 +511,9 @@ section.
|
|||||||
Toolchain Implementation Details
|
Toolchain Implementation Details
|
||||||
================================
|
================================
|
||||||
|
|
||||||
This section covers the ABI as well as additional compiler-specific behavior.
|
This section covers the ABI, as well as additional compiler-specific behavior.
|
||||||
The ABI is followed by all compilers, on all major systems, including Windows,
|
The ABI is followed by all compilers, on all major systems, including Windows,
|
||||||
Linux, and macOS. Different compilers emit different debug information, though.
|
Linux and macOS. Different compilers emit different debug information, though.
|
||||||
|
|
||||||
Ramp, resume and destroy functions
|
Ramp, resume and destroy functions
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@ -595,7 +595,7 @@ functions as their first two members. As such, we can read the function
|
|||||||
pointers from the coroutine frame and then obtain the function's name from its
|
pointers from the coroutine frame and then obtain the function's name from its
|
||||||
address.
|
address.
|
||||||
|
|
||||||
The promise is guaranteed to be at a 16-byte offset from the coroutine frame.
|
The promise is guaranteed to be at a 16 byte offset from the coroutine frame.
|
||||||
If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast
|
If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast
|
||||||
the promise as follows:
|
the promise as follows:
|
||||||
|
|
||||||
@ -607,8 +607,8 @@ Implementation in clang / LLVM
|
|||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The C++ Coroutines feature in the Clang compiler is implemented in two parts of
|
The C++ Coroutines feature in the Clang compiler is implemented in two parts of
|
||||||
the compiler. Semantic analysis is performed in Clang, and coroutine
|
the compiler. Semantic analysis is performed in Clang, and Coroutine
|
||||||
construction and optimization take place in the LLVM middle-end.
|
construction and optimization takes place in the LLVM middle-end.
|
||||||
|
|
||||||
For each coroutine function, the frontend generates a single corresponding
|
For each coroutine function, the frontend generates a single corresponding
|
||||||
LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics
|
LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics
|
||||||
@ -622,7 +622,7 @@ points into the coroutine frame. Most of the heavy lifting to preserve debugging
|
|||||||
information is done in this pass. This pass needs to rewrite all variable
|
information is done in this pass. This pass needs to rewrite all variable
|
||||||
locations to point into the coroutine frame.
|
locations to point into the coroutine frame.
|
||||||
|
|
||||||
Afterwards, a couple of additional optimizations are applied before code
|
Afterwards, a couple of additional optimizations are applied, before code
|
||||||
gets emitted, but none of them are really interesting regarding debugging
|
gets emitted, but none of them are really interesting regarding debugging
|
||||||
information.
|
information.
|
||||||
|
|
||||||
@ -636,8 +636,8 @@ However, this is not possible for coroutine frames because the frames are
|
|||||||
constructed in the LLVM middle-end.
|
constructed in the LLVM middle-end.
|
||||||
|
|
||||||
To mitigate this problem, the LLVM middle end attempts to generate some debug
|
To mitigate this problem, the LLVM middle end attempts to generate some debug
|
||||||
information, which is unfortunately incomplete, since much of the
|
information, which is unfortunately incomplete, since much of the language
|
||||||
language-specific information is missing in the middle end.
|
specific information is missing in the middle end.
|
||||||
|
|
||||||
.. _devirtualization:
|
.. _devirtualization:
|
||||||
|
|
||||||
@ -655,7 +655,7 @@ There are two possible approaches to do so:
|
|||||||
We can lookup their types and thereby get the types of promise
|
We can lookup their types and thereby get the types of promise
|
||||||
and coroutine frame.
|
and coroutine frame.
|
||||||
|
|
||||||
In gdb, one can use the following approach to devirtualize a coroutine type,
|
In gdb, one can use the following approach to devirtualize coroutine type,
|
||||||
assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
|
assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -679,7 +679,7 @@ LLDB comes with devirtualization support out of the box, as part of the
|
|||||||
pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
|
pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
|
||||||
uses the second approach. We look up the types in the destroy function and not
|
uses the second approach. We look up the types in the destroy function and not
|
||||||
the resume function because the resume function pointer will be set to a
|
the resume function because the resume function pointer will be set to a
|
||||||
``nullptr`` as soon as a coroutine reaches its final suspension point. If we used
|
nullptr as soon as a coroutine reaches its final suspension point. If we used
|
||||||
the resume function, devirtualization would hence fail for all coroutines that
|
the resume function, devirtualization would hence fail for all coroutines that
|
||||||
have reached their final suspension point.
|
have reached their final suspension point.
|
||||||
|
|
||||||
@ -687,10 +687,10 @@ Interpreting the coroutine frame in optimized builds
|
|||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
The ``__coro_frame`` variable usually refers to the coroutine frame of an
|
The ``__coro_frame`` variable usually refers to the coroutine frame of an
|
||||||
*in-flight* coroutine. This means the coroutine is currently executing.
|
*in-flight* coroutine. This means, the coroutine is currently executing.
|
||||||
However, the compiler only guarantees the coroutine frame to be in a consistent
|
However, the compiler only guarantees the coroutine frame to be in a consistent
|
||||||
state while the coroutine is suspended. As such, the variables inside the
|
state while the coroutine is suspended. As such, the variables inside the
|
||||||
``__coro_frame`` variable might be outdated, particularly when optimizations
|
``__coro_frame`` variable might be outdated, in particular when optimizations
|
||||||
are enabled.
|
are enabled.
|
||||||
|
|
||||||
Furthermore, when optimizations are enabled, the compiler will layout the
|
Furthermore, when optimizations are enabled, the compiler will layout the
|
||||||
@ -731,7 +731,7 @@ despite ``a`` being frequently incremented.
|
|||||||
|
|
||||||
While this might be surprising, this is a result of the optimizer recognizing
|
While this might be surprising, this is a result of the optimizer recognizing
|
||||||
that it can eliminate most of the load/store operations.
|
that it can eliminate most of the load/store operations.
|
||||||
The above code is optimized to the equivalent of:
|
The above code gets optimized to the equivalent of:
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
@ -1180,5 +1180,5 @@ The authors of the Folly libraries wrote a blog post series on how they debug co
|
|||||||
* `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_
|
* `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_
|
||||||
|
|
||||||
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
|
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
|
||||||
additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
more additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
||||||
and printing async stack traces on crashes.
|
and printing async stack traces on crashes.
|
||||||
|
@ -635,12 +635,11 @@ C and C++. For example:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Boolean vectors are a Clang extension of the ext vector type. Boolean vectors
|
Boolean vectors are a Clang extension of the ext vector type. Boolean vectors
|
||||||
are intended, though not guaranteed, to map to vector mask registers. The size
|
are intended, though not guaranteed, to map to vector mask registers. The size
|
||||||
parameter of a boolean vector type is the number of bits in the vector. The
|
parameter of a boolean vector type is the number of bits in the vector. The
|
||||||
boolean vector is dense and each bit in the boolean vector is one vector
|
boolean vector is dense and each bit in the boolean vector is one vector
|
||||||
element. Query for this feature with ``__has_feature(ext_vector_type_boolean)``.
|
element.
|
||||||
|
|
||||||
The semantics of boolean vectors borrows from C bit-fields with the following
|
The semantics of boolean vectors borrows from C bit-fields with the following
|
||||||
differences:
|
differences:
|
||||||
@ -658,16 +657,6 @@ The size and alignment are both the number of bits rounded up to the next power
|
|||||||
of two, but the alignment is at most the maximum vector alignment of the
|
of two, but the alignment is at most the maximum vector alignment of the
|
||||||
target.
|
target.
|
||||||
|
|
||||||
A boolean vector can be used in a ternary `?:` operator to select vector
|
|
||||||
elements of a different type.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
typedef int int4 __attribute__((ext_vector_type(4)));
|
|
||||||
typedef bool bool4 __attribute__((ext_vector_type(4)));
|
|
||||||
|
|
||||||
int4 blend(bool4 cond, int4 a, int4 b) { return cond ? a : b; }
|
|
||||||
|
|
||||||
|
|
||||||
Vector Literals
|
Vector Literals
|
||||||
---------------
|
---------------
|
||||||
@ -768,12 +757,11 @@ elementwise to the input.
|
|||||||
|
|
||||||
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity
|
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity
|
||||||
|
|
||||||
The elementwise intrinsics ``__builtin_elementwise_popcount``,
|
The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
|
||||||
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
|
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
|
||||||
``__builtin_elementwise_sub_sat``, ``__builtin_elementwise_max``,
|
``__builtin_elementwise_sub_sat``, ``__builtin_elementwise_max``,
|
||||||
``__builtin_elementwise_min``, ``__builtin_elementwise_abs``,
|
``__builtin_elementwise_min``, and ``__builtin_elementwise_abs``
|
||||||
``__builtin_elementwise_ctlz``, ``__builtin_elementwise_cttz``, and
|
can be called in a ``constexpr`` context.
|
||||||
``__builtin_elementwise_fma`` can be called in a ``constexpr`` context.
|
|
||||||
|
|
||||||
No implicit promotion of integer types takes place. The mixing of integer types
|
No implicit promotion of integer types takes place. The mixing of integer types
|
||||||
of different sizes and signs is forbidden in binary and ternary builtins.
|
of different sizes and signs is forbidden in binary and ternary builtins.
|
||||||
@ -882,14 +870,6 @@ T __builtin_elementwise_fshr(T x, T y, T z) perform a funnel shift right. Co
|
|||||||
significant bits of the wide value), the combined value is shifted
|
significant bits of the wide value), the combined value is shifted
|
||||||
right by z, and the least significant bits are extracted to produce
|
right by z, and the least significant bits are extracted to produce
|
||||||
a result that is the same size as the original arguments.
|
a result that is the same size as the original arguments.
|
||||||
T __builtin_elementwise_ctlz(T x[, T y]) return the number of leading 0 bits in the first argument. If integer types
|
|
||||||
the first argument is 0 and an optional second argument is provided,
|
|
||||||
the second argument is returned. It is undefined behaviour if the
|
|
||||||
first argument is 0 and no second argument is provided.
|
|
||||||
T __builtin_elementwise_cttz(T x[, T y]) return the number of trailing 0 bits in the first argument. If integer types
|
|
||||||
the first argument is 0 and an optional second argument is provided,
|
|
||||||
the second argument is returned. It is undefined behaviour if the
|
|
||||||
first argument is 0 and no second argument is provided.
|
|
||||||
============================================== ====================================================================== =========================================
|
============================================== ====================================================================== =========================================
|
||||||
|
|
||||||
|
|
||||||
@ -942,24 +922,6 @@ Let ``VT`` be a vector type and ``ET`` the element type of ``VT``.
|
|||||||
for the comparison.
|
for the comparison.
|
||||||
======================================= ====================================================================== ==================================
|
======================================= ====================================================================== ==================================
|
||||||
|
|
||||||
*Masked Builtins*
|
|
||||||
|
|
||||||
Each builtin accesses memory according to a provided boolean mask. These are
|
|
||||||
provided as ``__builtin_masked_load`` and ``__builtin_masked_store``. The first
|
|
||||||
argument is always boolean mask vector.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
using v8b = bool [[clang::ext_vector_type(8)]];
|
|
||||||
using v8i = int [[clang::ext_vector_type(8)]];
|
|
||||||
|
|
||||||
v8i load(v8b m, v8i *p) { return __builtin_masked_load(m, p); }
|
|
||||||
|
|
||||||
void store(v8b m, v8i v, v8i *p) { __builtin_masked_store(m, v, p); }
|
|
||||||
|
|
||||||
|
|
||||||
Matrix Types
|
Matrix Types
|
||||||
============
|
============
|
||||||
|
|
||||||
@ -1763,7 +1725,6 @@ Hexadecimal floating constants (N308) C
|
|||||||
Compound literals (N716) C99 C89, C++
|
Compound literals (N716) C99 C89, C++
|
||||||
``//`` comments (N644) C99 C89
|
``//`` comments (N644) C99 C89
|
||||||
Mixed declarations and code (N740) C99 C89
|
Mixed declarations and code (N740) C99 C89
|
||||||
init-statement in for (N740) C99 C89
|
|
||||||
Variadic macros (N707) C99 C89
|
Variadic macros (N707) C99 C89
|
||||||
Empty macro arguments (N570) C99 C89
|
Empty macro arguments (N570) C99 C89
|
||||||
Trailing comma in enum declaration C99 C89
|
Trailing comma in enum declaration C99 C89
|
||||||
@ -1830,37 +1791,6 @@ __make_integer_seq
|
|||||||
|
|
||||||
This alias returns ``IntSeq`` instantiated with ``IntSeqT = T``and ``Ints`` being the pack ``0, ..., N - 1``.
|
This alias returns ``IntSeq`` instantiated with ``IntSeqT = T``and ``Ints`` being the pack ``0, ..., N - 1``.
|
||||||
|
|
||||||
__builtin_dedup_pack
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
template <class... Ts>
|
|
||||||
using __builtin_dedup_pack = ...;
|
|
||||||
|
|
||||||
This alias takes a template parameter pack ``Ts`` and produces a new unexpanded pack containing the unique types
|
|
||||||
from ``Ts``, with the order of the first occurrence of each type preserved.
|
|
||||||
It is useful in template metaprogramming to normalize type lists.
|
|
||||||
|
|
||||||
The resulting pack can be expanded in contexts like template argument lists or base specifiers.
|
|
||||||
|
|
||||||
**Example of Use**:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
template <typename...> struct TypeList;
|
|
||||||
|
|
||||||
// The resulting type is TypeList<int, double, char>
|
|
||||||
template <typename ...ExtraTypes>
|
|
||||||
using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double, ExtraTypes...>...>;
|
|
||||||
|
|
||||||
**Limitations**:
|
|
||||||
|
|
||||||
* This builtin can only be used inside a template.
|
|
||||||
* The resulting pack is currently only supported for expansion in template argument lists and base specifiers.
|
|
||||||
* This builtin cannot be assigned to a template template parameter.
|
|
||||||
|
|
||||||
|
|
||||||
Type Trait Primitives
|
Type Trait Primitives
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@ -4440,7 +4370,7 @@ fall into one of the specified floating-point classes.
|
|||||||
|
|
||||||
if (__builtin_isfpclass(x, 448)) {
|
if (__builtin_isfpclass(x, 448)) {
|
||||||
// `x` is positive finite value
|
// `x` is positive finite value
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
**Description**:
|
**Description**:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,22 +37,6 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
|
|||||||
Potentially Breaking Changes
|
Potentially Breaking Changes
|
||||||
============================
|
============================
|
||||||
|
|
||||||
- Clang will now emit a warning if the auto-detected GCC installation
|
|
||||||
directory (i.e. the one with the largest version number) does not
|
|
||||||
contain libstdc++ include directories although a "complete" GCC
|
|
||||||
installation directory containing the include directories is
|
|
||||||
available. It is planned to change the auto-detection to prefer the
|
|
||||||
"complete" directory in the future. The warning will disappear if
|
|
||||||
the libstdc++ include directories are either installed or removed
|
|
||||||
for all GCC installation directories considered by the
|
|
||||||
auto-detection; see the output of ``clang -v`` for a list of those
|
|
||||||
directories. If the GCC installations cannot be modified and
|
|
||||||
maintaining the current choice of the auto-detection is desired, the
|
|
||||||
GCC installation directory can be selected explicitly using the
|
|
||||||
``--gcc-install-dir`` command line argument. This will silence the
|
|
||||||
warning. It can also be disabled using the
|
|
||||||
``-Wno-gcc-install-dir-libstdcxx`` command line flag.
|
|
||||||
|
|
||||||
C/C++ Language Potentially Breaking Changes
|
C/C++ Language Potentially Breaking Changes
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
@ -153,41 +137,10 @@ Non-comprehensive list of changes in this release
|
|||||||
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
|
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
|
||||||
now be used in constant expressions.
|
now be used in constant expressions.
|
||||||
|
|
||||||
- A vector of booleans is now a valid condition for the ternary ``?:`` operator.
|
|
||||||
This binds to a simple vector select operation.
|
|
||||||
|
|
||||||
- Added ``__builtin_masked_load`` and ``__builtin_masked_store`` for conditional
|
|
||||||
memory loads from vectors. Binds to the LLVM intrinsic of the same name.
|
|
||||||
|
|
||||||
- Use of ``__has_feature`` to detect the ``ptrauth_qualifier`` and ``ptrauth_intrinsics``
|
|
||||||
features has been deprecated, and is restricted to the arm64e target only. The
|
|
||||||
correct method to check for these features is to test for the ``__PTRAUTH__``
|
|
||||||
macro.
|
|
||||||
|
|
||||||
- Added a new builtin, ``__builtin_dedup_pack``, to remove duplicate types from a parameter pack.
|
|
||||||
This feature is particularly useful in template metaprogramming for normalizing type lists.
|
|
||||||
The builtin produces a new, unexpanded parameter pack that can be used in contexts like template
|
|
||||||
argument lists or base specifiers.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
template <typename...> struct TypeList;
|
|
||||||
|
|
||||||
// The resulting type is TypeList<int, double, char>
|
|
||||||
using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double>...>;
|
|
||||||
|
|
||||||
Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base
|
|
||||||
specifiers, it also must be used within a template context.
|
|
||||||
|
|
||||||
|
|
||||||
New Compiler Flags
|
New Compiler Flags
|
||||||
------------------
|
------------------
|
||||||
- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
|
- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
|
||||||
|
|
||||||
Lanai Support
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
- The option ``-mcmodel={small,medium,large}`` is supported again.
|
|
||||||
|
|
||||||
Deprecated Compiler Flags
|
Deprecated Compiler Flags
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
@ -225,9 +178,6 @@ Improvements to Clang's diagnostics
|
|||||||
potential misaligned members get processed before they can get discarded.
|
potential misaligned members get processed before they can get discarded.
|
||||||
(#GH144729)
|
(#GH144729)
|
||||||
|
|
||||||
- Fixed false positive in ``-Wmissing-noreturn`` diagnostic when it was requiring the usage of
|
|
||||||
``[[noreturn]]`` on lambdas before C++23 (#GH154493).
|
|
||||||
|
|
||||||
Improvements to Clang's time-trace
|
Improvements to Clang's time-trace
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
@ -245,7 +195,6 @@ Bug Fixes in This Version
|
|||||||
cast chain. (#GH149967).
|
cast chain. (#GH149967).
|
||||||
- Fixed a crash with incompatible pointer to integer conversions in designated
|
- Fixed a crash with incompatible pointer to integer conversions in designated
|
||||||
initializers involving string literals. (#GH154046)
|
initializers involving string literals. (#GH154046)
|
||||||
- Fixed scope of typedefs present inside a template class. (#GH91451)
|
|
||||||
|
|
||||||
Bug Fixes to Compiler Builtins
|
Bug Fixes to Compiler Builtins
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -255,8 +204,8 @@ Bug Fixes to Compiler Builtins
|
|||||||
Bug Fixes to Attribute Support
|
Bug Fixes to Attribute Support
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- ``[[nodiscard]]`` is now respected on Objective-C and Objective-C++ methods
|
- ``[[nodiscard]]`` is now respected on Objective-C and Objective-C++ methods.
|
||||||
(#GH141504) and on types returned from indirect calls (#GH142453).
|
(#GH141504)
|
||||||
- Fixes some late parsed attributes, when applied to function definitions, not being parsed
|
- Fixes some late parsed attributes, when applied to function definitions, not being parsed
|
||||||
in function try blocks, and some situations where parsing of the function body
|
in function try blocks, and some situations where parsing of the function body
|
||||||
is skipped, such as error recovery and code completion. (#GH153551)
|
is skipped, such as error recovery and code completion. (#GH153551)
|
||||||
@ -268,7 +217,6 @@ Bug Fixes to C++ Support
|
|||||||
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
|
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
|
||||||
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
|
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
|
||||||
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
|
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
|
||||||
- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776)
|
|
||||||
- Fix an assertion failure when expression in assumption attribute
|
- Fix an assertion failure when expression in assumption attribute
|
||||||
(``[[assume(expr)]]``) creates temporary objects.
|
(``[[assume(expr)]]``) creates temporary objects.
|
||||||
- Fix the dynamic_cast to final class optimization to correctly handle
|
- Fix the dynamic_cast to final class optimization to correctly handle
|
||||||
@ -278,8 +226,6 @@ Bug Fixes to C++ Support
|
|||||||
"intializing multiple members of union" coincide (#GH149985).
|
"intializing multiple members of union" coincide (#GH149985).
|
||||||
- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729)
|
- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729)
|
||||||
- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445)
|
- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445)
|
||||||
- Fixed a bug that caused ``this`` captured by value in a lambda with a dependent explicit object parameter to not be
|
|
||||||
instantiated properly. (#GH154054)
|
|
||||||
|
|
||||||
Bug Fixes to AST Handling
|
Bug Fixes to AST Handling
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -309,13 +255,6 @@ NVPTX Support
|
|||||||
|
|
||||||
X86 Support
|
X86 Support
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
- More SSE, AVX and AVX512 intrinsics, including initializers and general
|
|
||||||
arithmetic can now be used in C++ constant expressions.
|
|
||||||
- Some SSE, AVX and AVX512 intrinsics have been converted to wrap
|
|
||||||
generic __builtin intrinsics.
|
|
||||||
- NOTE: Please avoid use of the __builtin_ia32_* intrinsics - these are not
|
|
||||||
guaranteed to exist in future releases, or match behaviour with previous
|
|
||||||
releases of clang or other compilers.
|
|
||||||
|
|
||||||
Arm and AArch64 Support
|
Arm and AArch64 Support
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -375,9 +314,6 @@ AST Matchers
|
|||||||
- Add a boolean member ``IgnoreSystemHeaders`` to ``MatchFinderOptions``. This
|
- Add a boolean member ``IgnoreSystemHeaders`` to ``MatchFinderOptions``. This
|
||||||
allows it to ignore nodes in system headers when traversing the AST.
|
allows it to ignore nodes in system headers when traversing the AST.
|
||||||
|
|
||||||
- ``hasConditionVariableStatement`` now supports ``for`` loop, ``while`` loop
|
|
||||||
and ``switch`` statements.
|
|
||||||
|
|
||||||
clang-format
|
clang-format
|
||||||
------------
|
------------
|
||||||
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
|
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
|
||||||
|
@ -226,8 +226,8 @@ one-phase compilation model is simpler for build systems to implement while the
|
|||||||
two-phase compilation has the potential to compile faster due to higher
|
two-phase compilation has the potential to compile faster due to higher
|
||||||
parallelism. As an example, if there are two module units ``A`` and ``B``, and
|
parallelism. As an example, if there are two module units ``A`` and ``B``, and
|
||||||
``B`` depends on ``A``, the one-phase compilation model needs to compile them
|
``B`` depends on ``A``, the one-phase compilation model needs to compile them
|
||||||
serially, whereas the two-phase compilation model can be compiled as
|
serially, whereas the two-phase compilation model is able to be compiled as
|
||||||
soon as ``A.pcm`` is available, and thus can be compiled simultaneously with the
|
soon as ``A.pcm`` is available, and thus can be compiled simultaneously as the
|
||||||
``A.pcm`` to ``A.o`` compilation step.
|
``A.pcm`` to ``A.o`` compilation step.
|
||||||
|
|
||||||
File name requirements
|
File name requirements
|
||||||
@ -391,7 +391,7 @@ And the compilation processes for module units are like:
|
|||||||
As the diagrams show, we need to compile the BMI from module units to object
|
As the diagrams show, we need to compile the BMI from module units to object
|
||||||
files and then link the object files. (However, this cannot be done for the BMI
|
files and then link the object files. (However, this cannot be done for the BMI
|
||||||
from header units. See the section on :ref:`header units <header-units>` for
|
from header units. See the section on :ref:`header units <header-units>` for
|
||||||
more details.)
|
more details.
|
||||||
|
|
||||||
BMIs cannot be shipped in an archive to create a module library. Instead, the
|
BMIs cannot be shipped in an archive to create a module library. Instead, the
|
||||||
BMIs(``*.pcm``) are compiled into object files(``*.o``) and those object files
|
BMIs(``*.pcm``) are compiled into object files(``*.o``) and those object files
|
||||||
@ -403,7 +403,7 @@ clang-cl
|
|||||||
``clang-cl`` supports the same options as ``clang++`` for modules as detailed above;
|
``clang-cl`` supports the same options as ``clang++`` for modules as detailed above;
|
||||||
there is no need to prefix these options with ``/clang:``. Note that ``cl.exe``
|
there is no need to prefix these options with ``/clang:``. Note that ``cl.exe``
|
||||||
`options to emit/consume IFC files <https://devblogs.microsoft.com/cppblog/using-cpp-modules-in-msvc-from-the-command-line-part-1/>` are *not* supported.
|
`options to emit/consume IFC files <https://devblogs.microsoft.com/cppblog/using-cpp-modules-in-msvc-from-the-command-line-part-1/>` are *not* supported.
|
||||||
The resulting precompiled modules are also not compatible for use with ``cl.exe``.
|
The resultant precompiled modules are also not compatible for use with ``cl.exe``.
|
||||||
|
|
||||||
We recommend that build system authors use the above-mentioned ``clang++`` options with ``clang-cl`` to build modules.
|
We recommend that build system authors use the above-mentioned ``clang++`` options with ``clang-cl`` to build modules.
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ Consistency Requirements
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Modules can be viewed as a kind of cache to speed up compilation. Thus, like
|
Modules can be viewed as a kind of cache to speed up compilation. Thus, like
|
||||||
other caching techniques, it is important to maintain cache consistency, which
|
other caching techniques, it is important to maintain cache consistency which
|
||||||
is why Clang does very strict checking for consistency.
|
is why Clang does very strict checking for consistency.
|
||||||
|
|
||||||
Options consistency
|
Options consistency
|
||||||
@ -472,8 +472,8 @@ To overcome these requirements and simplify cases like distributed builds and sa
|
|||||||
builds, users can use the ``-fmodules-embed-all-files`` flag to embed all input files
|
builds, users can use the ``-fmodules-embed-all-files`` flag to embed all input files
|
||||||
into the BMI so that Clang does not need to open the corresponding file on disk.
|
into the BMI so that Clang does not need to open the corresponding file on disk.
|
||||||
|
|
||||||
When the ``-fmodules-embed-all-files`` flag is enabled, Clang explicitly emits the source
|
When the ``-fmodules-embed-all-files`` flag are enabled, Clang explicitly emits the source
|
||||||
code into the BMI file; the BMI file contains a sufficiently verbose
|
code into the BMI file, the contents of the BMI file contain a sufficiently verbose
|
||||||
representation to reproduce the original source file.
|
representation to reproduce the original source file.
|
||||||
|
|
||||||
.. [1] Input files: The source files which took part in the compilation of the BMI.
|
.. [1] Input files: The source files which took part in the compilation of the BMI.
|
||||||
@ -578,7 +578,7 @@ handle the dynamic initialization of non-inline variables in the module unit.
|
|||||||
The importable module unit has to emit the initializer even if there is no
|
The importable module unit has to emit the initializer even if there is no
|
||||||
dynamic initialization; otherwise, the importer may call a nonexistent
|
dynamic initialization; otherwise, the importer may call a nonexistent
|
||||||
function. The initializer function emits calls to imported modules first
|
function. The initializer function emits calls to imported modules first
|
||||||
followed by calls to all of the dynamic initializers in the current module
|
followed by calls to all to of the dynamic initializers in the current module
|
||||||
unit.
|
unit.
|
||||||
|
|
||||||
Translation units that explicitly or implicitly import a named module must call
|
Translation units that explicitly or implicitly import a named module must call
|
||||||
@ -689,9 +689,9 @@ ensure it is reachable, e.g. ``using N::g;``.
|
|||||||
|
|
||||||
As of Clang 22.x, the Reduced BMI is enabled by default. You may still want to
|
As of Clang 22.x, the Reduced BMI is enabled by default. You may still want to
|
||||||
use Full BMI with ``-fno-modules-reduced-bmi`` in the following case:
|
use Full BMI with ``-fno-modules-reduced-bmi`` in the following case:
|
||||||
1. Your build system uses two-phase compilation, but it hasn't adjusted the
|
1. Your build system uses two-phase compilation but it haven't adjusted the
|
||||||
implementation for reduced BMI.
|
implementation for reduced BMI.
|
||||||
2. You encounter a regression with Reduced BMI that you cannot work around. Please
|
2. You meet a regression with Reduced BMI that you cannot work around. Please
|
||||||
report an issue for this case.
|
report an issue for this case.
|
||||||
|
|
||||||
Experimental Non-Cascading Changes
|
Experimental Non-Cascading Changes
|
||||||
@ -699,7 +699,7 @@ Experimental Non-Cascading Changes
|
|||||||
|
|
||||||
This section is primarily for build system vendors. For end compiler users,
|
This section is primarily for build system vendors. For end compiler users,
|
||||||
if you don't want to read it all, this is helpful to reduce recompilations.
|
if you don't want to read it all, this is helpful to reduce recompilations.
|
||||||
We encourage build system vendors and end users to try this out and bring feedback.
|
We encourage build system vendors and end users try this out and bring feedback.
|
||||||
|
|
||||||
Before Clang 19, a change in BMI of any (transitive) dependency would cause the
|
Before Clang 19, a change in BMI of any (transitive) dependency would cause the
|
||||||
outputs of the BMI to change. Starting with Clang 19, changes to non-direct
|
outputs of the BMI to change. Starting with Clang 19, changes to non-direct
|
||||||
@ -786,7 +786,7 @@ We encourage build systems to add an experimental mode that
|
|||||||
reuses the cached BMI when **direct** dependencies did not change,
|
reuses the cached BMI when **direct** dependencies did not change,
|
||||||
even if **transitive** dependencies did change.
|
even if **transitive** dependencies did change.
|
||||||
|
|
||||||
Given that there are potential compiler bugs, we recommend that build systems
|
Given there are potential compiler bugs, we recommend that build systems
|
||||||
support this feature as a configurable option so that users
|
support this feature as a configurable option so that users
|
||||||
can go back to the transitive change mode safely at any time.
|
can go back to the transitive change mode safely at any time.
|
||||||
|
|
||||||
@ -813,7 +813,7 @@ With reduced BMI, non-cascading changes can be more powerful. For example,
|
|||||||
$ md5sum B.pcm
|
$ md5sum B.pcm
|
||||||
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
|
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
|
||||||
|
|
||||||
And let's change the implementation for ``A.cppm`` to:
|
And let's change the implementation for ``A.cppm`` into:
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
@ -830,7 +830,7 @@ and recompile the example:
|
|||||||
$ md5sum B.pcm
|
$ md5sum B.pcm
|
||||||
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
|
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
|
||||||
|
|
||||||
We should find the contents of ``B.pcm`` remain the same. In this case, the build system is
|
We should find the contents of ``B.pcm`` remains the same. In this case, the build system is
|
||||||
allowed to skip recompilations of TUs which solely and directly depend on module ``B``.
|
allowed to skip recompilations of TUs which solely and directly depend on module ``B``.
|
||||||
|
|
||||||
This only happens with a reduced BMI. With reduced BMIs, we won't record the function body
|
This only happens with a reduced BMI. With reduced BMIs, we won't record the function body
|
||||||
@ -845,7 +845,7 @@ Reduce duplications
|
|||||||
|
|
||||||
While it is valid to have duplicated declarations in the global module fragments
|
While it is valid to have duplicated declarations in the global module fragments
|
||||||
of different module units, it is not free for Clang to deal with the duplicated
|
of different module units, it is not free for Clang to deal with the duplicated
|
||||||
declarations. A translation unit will compile more slowly if there are a lot of
|
declarations. A translation unit will compile more slowly if there is a lot of
|
||||||
duplicated declarations between the translation unit and modules it imports.
|
duplicated declarations between the translation unit and modules it imports.
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@ -937,7 +937,7 @@ possible. However, it may be a breaking change for existing code or libraries
|
|||||||
to switch to modules. As a result, many existing libraries need to provide
|
to switch to modules. As a result, many existing libraries need to provide
|
||||||
both headers and module interfaces for a while to not break existing users.
|
both headers and module interfaces for a while to not break existing users.
|
||||||
|
|
||||||
This section provides some suggestions on how to ease the transition process
|
This section suggests some suggestions on how to ease the transition process
|
||||||
for existing libraries. **Note that this information is only intended as
|
for existing libraries. **Note that this information is only intended as
|
||||||
guidance, rather than as requirements to use modules in Clang.** It presumes
|
guidance, rather than as requirements to use modules in Clang.** It presumes
|
||||||
the project is starting with no module-based dependencies.
|
the project is starting with no module-based dependencies.
|
||||||
@ -1140,7 +1140,7 @@ module unit which is internal to the module itself.
|
|||||||
Providing a header to skip parsing redundant headers
|
Providing a header to skip parsing redundant headers
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Many redeclarations shared between translation units cause Clang to have
|
Many redeclarations shared between translation units causes Clang to have
|
||||||
slower compile-time performance. Further, there are known issues with
|
slower compile-time performance. Further, there are known issues with
|
||||||
`include after import <https://github.com/llvm/llvm-project/issues/61465>`_.
|
`include after import <https://github.com/llvm/llvm-project/issues/61465>`_.
|
||||||
Even when that issue is resolved, users may still get slower compilation speed
|
Even when that issue is resolved, users may still get slower compilation speed
|
||||||
@ -1408,8 +1408,8 @@ P1857R3 is implemented. This is tracked by
|
|||||||
Until then, it is recommended not to mix macros with module declarations.
|
Until then, it is recommended not to mix macros with module declarations.
|
||||||
|
|
||||||
|
|
||||||
Inconsistent filename suffix requirement for importable module units
|
In consistent filename suffix requirement for importable module units
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Currently, Clang requires the file name of an ``importable module unit`` to
|
Currently, Clang requires the file name of an ``importable module unit`` to
|
||||||
have ``.cppm`` (or ``.ccm``, ``.cxxm``, ``.c++m``) as the file extension.
|
have ``.cppm`` (or ``.ccm``, ``.cxxm``, ``.c++m``) as the file extension.
|
||||||
@ -1484,7 +1484,7 @@ How to build projects using header units
|
|||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
The support for header units, including related command line options, is
|
The support for header units, including related command line options, is
|
||||||
experimental. There are still many unanswered questions about how tools
|
experimental. There are still many unanswered question about how tools
|
||||||
should interact with header units. The details described here may change in
|
should interact with header units. The details described here may change in
|
||||||
the future.
|
the future.
|
||||||
|
|
||||||
@ -1881,7 +1881,7 @@ Individual command line options can be specified after ``--``.
|
|||||||
options. Note that the path to the compiler executable needs to be specified
|
options. Note that the path to the compiler executable needs to be specified
|
||||||
explicitly instead of using ``clang++`` directly.
|
explicitly instead of using ``clang++`` directly.
|
||||||
|
|
||||||
Users may want the scanner to get the transitive dependency information for
|
Users may want the scanner to get the transitional dependency information for
|
||||||
headers. Otherwise, the project has to be scanned twice, once for headers and
|
headers. Otherwise, the project has to be scanned twice, once for headers and
|
||||||
once for modules. To address this, ``clang-scan-deps`` will recognize the
|
once for modules. To address this, ``clang-scan-deps`` will recognize the
|
||||||
specified preprocessor options in the given command line and generate the
|
specified preprocessor options in the given command line and generate the
|
||||||
@ -1912,7 +1912,7 @@ Possible Issues: Failed to find system headers
|
|||||||
|
|
||||||
If encountering an error like ``fatal error: 'stddef.h' file not found``,
|
If encountering an error like ``fatal error: 'stddef.h' file not found``,
|
||||||
the specified ``<path-to-compiler-executable>/clang++`` probably refers to a
|
the specified ``<path-to-compiler-executable>/clang++`` probably refers to a
|
||||||
symlink instead of a real binary. There are four potential solutions to the
|
symlink instead a real binary. There are four potential solutions to the
|
||||||
problem:
|
problem:
|
||||||
|
|
||||||
1. Point the specified compiler executable to the real binary instead of the
|
1. Point the specified compiler executable to the real binary instead of the
|
||||||
|
@ -825,6 +825,13 @@ doesn't know that munl.mu == mutex. The SCOPED_CAPABILITY attribute handles
|
|||||||
aliasing for MutexLocker, but does so only for that particular pattern.
|
aliasing for MutexLocker, but does so only for that particular pattern.
|
||||||
|
|
||||||
|
|
||||||
|
ACQUIRED_BEFORE(...) and ACQUIRED_AFTER(...) support is still experimental.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ACQUIRED_BEFORE(...) and ACQUIRED_AFTER(...) are currently being developed under
|
||||||
|
the ``-Wthread-safety-beta`` flag.
|
||||||
|
|
||||||
|
|
||||||
.. _mutexheader:
|
.. _mutexheader:
|
||||||
|
|
||||||
mutex.h
|
mutex.h
|
||||||
|
@ -230,8 +230,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
SubstTemplateTypeParmTypes;
|
SubstTemplateTypeParmTypes;
|
||||||
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
|
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
|
||||||
SubstTemplateTypeParmPackTypes;
|
SubstTemplateTypeParmPackTypes;
|
||||||
mutable llvm::FoldingSet<SubstBuiltinTemplatePackType>
|
|
||||||
SubstBuiltinTemplatePackTypes;
|
|
||||||
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
|
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
|
||||||
TemplateSpecializationTypes;
|
TemplateSpecializationTypes;
|
||||||
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
|
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
|
||||||
@ -1897,7 +1895,6 @@ public:
|
|||||||
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
|
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
|
||||||
unsigned Index, bool Final,
|
unsigned Index, bool Final,
|
||||||
const TemplateArgument &ArgPack);
|
const TemplateArgument &ArgPack);
|
||||||
QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
|
|
||||||
|
|
||||||
QualType
|
QualType
|
||||||
getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||||
|
@ -359,7 +359,7 @@ class CXXFinalOverriderMap
|
|||||||
|
|
||||||
/// A set of all the primary bases for a class.
|
/// A set of all the primary bases for a class.
|
||||||
class CXXIndirectPrimaryBaseSet
|
class CXXIndirectPrimaryBaseSet
|
||||||
: public llvm::SmallPtrSet<const CXXRecordDecl *, 32> {};
|
: public llvm::SmallSet<const CXXRecordDecl*, 32> {};
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
inheritanceModelHasVBPtrOffsetField(MSInheritanceModel Inheritance) {
|
inheritanceModelHasVBPtrOffsetField(MSInheritanceModel Inheritance) {
|
||||||
|
@ -3526,7 +3526,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
// Low-level accessor. If you just want the type defined by this node,
|
// Low-level accessor. If you just want the type defined by this node,
|
||||||
// check out ASTContext::getTypeDeclType or one of
|
// check out ASTContext::getTypeDeclType or one of
|
||||||
// ASTContext::getTypedefType, ASTContext::getTagType, etc. if you
|
// ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you
|
||||||
// already know the specific kind of node this is.
|
// already know the specific kind of node this is.
|
||||||
const Type *getTypeForDecl() const {
|
const Type *getTypeForDecl() const {
|
||||||
assert(!isa<TagDecl>(this));
|
assert(!isa<TagDecl>(this));
|
||||||
|
@ -1796,10 +1796,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
|
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
|
||||||
|
|
||||||
bool isPackProducingBuiltinTemplate() const;
|
|
||||||
};
|
};
|
||||||
bool isPackProducingBuiltinTemplateName(TemplateName N);
|
|
||||||
|
|
||||||
/// Provides information about an explicit instantiation of a variable or class
|
/// Provides information about an explicit instantiation of a variable or class
|
||||||
/// template.
|
/// template.
|
||||||
|
@ -1250,32 +1250,19 @@ public:
|
|||||||
SourceLocation EndLoc);
|
SourceLocation EndLoc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A structure to stand in for the recipe on a reduction. RecipeDecl is the
|
|
||||||
// 'main' declaration used for initializaiton, which is fixed.
|
|
||||||
struct OpenACCReductionRecipe {
|
|
||||||
VarDecl *RecipeDecl;
|
|
||||||
// TODO: OpenACC: this should eventually have the operations here too.
|
|
||||||
};
|
|
||||||
|
|
||||||
class OpenACCReductionClause final
|
class OpenACCReductionClause final
|
||||||
: public OpenACCClauseWithVarList,
|
: public OpenACCClauseWithVarList,
|
||||||
private llvm::TrailingObjects<OpenACCReductionClause, Expr *,
|
private llvm::TrailingObjects<OpenACCReductionClause, Expr *> {
|
||||||
OpenACCReductionRecipe> {
|
|
||||||
friend TrailingObjects;
|
friend TrailingObjects;
|
||||||
OpenACCReductionOperator Op;
|
OpenACCReductionOperator Op;
|
||||||
|
|
||||||
OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
|
OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
|
||||||
OpenACCReductionOperator Operator,
|
OpenACCReductionOperator Operator,
|
||||||
ArrayRef<Expr *> VarList,
|
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
|
||||||
ArrayRef<OpenACCReductionRecipe> Recipes,
|
|
||||||
SourceLocation EndLoc)
|
|
||||||
: OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
|
: OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
|
||||||
LParenLoc, EndLoc),
|
LParenLoc, EndLoc),
|
||||||
Op(Operator) {
|
Op(Operator) {
|
||||||
assert(VarList.size() == Recipes.size());
|
setExprs(getTrailingObjects(VarList.size()), VarList);
|
||||||
setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
|
|
||||||
llvm::uninitialized_copy(Recipes, getTrailingObjects<
|
|
||||||
OpenACCReductionRecipe > ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1283,26 +1270,12 @@ public:
|
|||||||
return C->getClauseKind() == OpenACCClauseKind::Reduction;
|
return C->getClauseKind() == OpenACCClauseKind::Reduction;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<OpenACCReductionRecipe> getRecipes() {
|
|
||||||
return ArrayRef<OpenACCReductionRecipe>{
|
|
||||||
getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()};
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayRef<OpenACCReductionRecipe> getRecipes() const {
|
|
||||||
return ArrayRef<OpenACCReductionRecipe>{
|
|
||||||
getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()};
|
|
||||||
}
|
|
||||||
|
|
||||||
static OpenACCReductionClause *
|
static OpenACCReductionClause *
|
||||||
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
|
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
|
||||||
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
|
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
|
||||||
ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc);
|
SourceLocation EndLoc);
|
||||||
|
|
||||||
OpenACCReductionOperator getReductionOp() const { return Op; }
|
OpenACCReductionOperator getReductionOp() const { return Op; }
|
||||||
|
|
||||||
size_t numTrailingObjects(OverloadToken<Expr *>) const {
|
|
||||||
return getExprs().size();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenACCLinkClause final
|
class OpenACCLinkClause final
|
||||||
|
@ -492,8 +492,6 @@ private:
|
|||||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||||
unsigned Count);
|
unsigned Count);
|
||||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||||
bool TraverseSubstPackTypeHelper(SubstPackType *T);
|
|
||||||
bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL);
|
|
||||||
bool TraverseRecordHelper(RecordDecl *D);
|
bool TraverseRecordHelper(RecordDecl *D);
|
||||||
bool TraverseCXXRecordHelper(CXXRecordDecl *D);
|
bool TraverseCXXRecordHelper(CXXRecordDecl *D);
|
||||||
bool TraverseDeclaratorHelper(DeclaratorDecl *D);
|
bool TraverseDeclaratorHelper(DeclaratorDecl *D);
|
||||||
@ -1140,10 +1138,9 @@ DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
|
|||||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
|
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
|
||||||
TRY_TO(TraverseType(T->getReplacementType()));
|
TRY_TO(TraverseType(T->getReplacementType()));
|
||||||
})
|
})
|
||||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType,
|
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
|
||||||
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
|
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
||||||
DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType,
|
})
|
||||||
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
|
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPE(AttributedType,
|
DEF_TRAVERSE_TYPE(AttributedType,
|
||||||
{ TRY_TO(TraverseType(T->getModifiedType())); })
|
{ TRY_TO(TraverseType(T->getModifiedType())); })
|
||||||
@ -1484,26 +1481,9 @@ DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
|
|||||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
|
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
|
||||||
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
|
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
|
||||||
})
|
})
|
||||||
|
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
|
||||||
template <typename Derived>
|
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper(
|
|
||||||
SubstPackTypeLoc TL) {
|
|
||||||
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
|
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
|
||||||
return true;
|
})
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Derived>
|
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeHelper(
|
|
||||||
SubstPackType *T) {
|
|
||||||
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType,
|
|
||||||
{ TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
|
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPELOC(SubstBuiltinTemplatePackType,
|
|
||||||
{ TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
|
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
||||||
|
|
||||||
|
@ -2210,24 +2210,20 @@ protected:
|
|||||||
unsigned PackIndex : 15;
|
unsigned PackIndex : 15;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SubstPackTypeBitfields {
|
class SubstTemplateTypeParmPackTypeBitfields {
|
||||||
friend class SubstPackType;
|
|
||||||
friend class SubstTemplateTypeParmPackType;
|
friend class SubstTemplateTypeParmPackType;
|
||||||
|
|
||||||
LLVM_PREFERRED_TYPE(TypeBitfields)
|
LLVM_PREFERRED_TYPE(TypeBitfields)
|
||||||
unsigned : NumTypeBits;
|
unsigned : NumTypeBits;
|
||||||
|
|
||||||
|
// The index of the template parameter this substitution represents.
|
||||||
|
unsigned Index : 16;
|
||||||
|
|
||||||
/// The number of template arguments in \c Arguments, which is
|
/// The number of template arguments in \c Arguments, which is
|
||||||
/// expected to be able to hold at least 1024 according to [implimits].
|
/// expected to be able to hold at least 1024 according to [implimits].
|
||||||
/// However as this limit is somewhat easy to hit with template
|
/// However as this limit is somewhat easy to hit with template
|
||||||
/// metaprogramming we'd prefer to keep it as large as possible.
|
/// metaprogramming we'd prefer to keep it as large as possible.
|
||||||
unsigned NumArgs : 16;
|
unsigned NumArgs : 16;
|
||||||
|
|
||||||
// The index of the template parameter this substitution represents.
|
|
||||||
// Only used by SubstTemplateTypeParmPackType. We keep it in the same
|
|
||||||
// class to avoid dealing with complexities of bitfields that go over
|
|
||||||
// the size of `unsigned`.
|
|
||||||
unsigned SubstTemplTypeParmPackIndex : 16;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TemplateSpecializationTypeBitfields {
|
class TemplateSpecializationTypeBitfields {
|
||||||
@ -2344,7 +2340,7 @@ protected:
|
|||||||
VectorTypeBitfields VectorTypeBits;
|
VectorTypeBitfields VectorTypeBits;
|
||||||
TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
|
TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
|
||||||
SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
|
SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
|
||||||
SubstPackTypeBitfields SubstPackTypeBits;
|
SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
|
||||||
TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
|
TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
|
||||||
DependentTemplateSpecializationTypeBitfields
|
DependentTemplateSpecializationTypeBitfields
|
||||||
DependentTemplateSpecializationTypeBits;
|
DependentTemplateSpecializationTypeBits;
|
||||||
@ -6405,9 +6401,6 @@ protected:
|
|||||||
bool IsInjected, const Type *CanonicalType);
|
bool IsInjected, const Type *CanonicalType);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// FIXME: Temporarily renamed from `getDecl` in order to facilitate
|
|
||||||
// rebasing, due to change in behaviour. This should be renamed back
|
|
||||||
// to `getDecl` once the change is settled.
|
|
||||||
TagDecl *getOriginalDecl() const { return decl; }
|
TagDecl *getOriginalDecl() const { return decl; }
|
||||||
|
|
||||||
NestedNameSpecifier getQualifier() const;
|
NestedNameSpecifier getQualifier() const;
|
||||||
@ -6473,9 +6466,6 @@ class RecordType final : public TagType {
|
|||||||
using TagType::TagType;
|
using TagType::TagType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// FIXME: Temporarily renamed from `getDecl` in order to facilitate
|
|
||||||
// rebasing, due to change in behaviour. This should be renamed back
|
|
||||||
// to `getDecl` once the change is settled.
|
|
||||||
RecordDecl *getOriginalDecl() const {
|
RecordDecl *getOriginalDecl() const {
|
||||||
return reinterpret_cast<RecordDecl *>(TagType::getOriginalDecl());
|
return reinterpret_cast<RecordDecl *>(TagType::getOriginalDecl());
|
||||||
}
|
}
|
||||||
@ -6493,9 +6483,6 @@ class EnumType final : public TagType {
|
|||||||
using TagType::TagType;
|
using TagType::TagType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// FIXME: Temporarily renamed from `getDecl` in order to facilitate
|
|
||||||
// rebasing, due to change in behaviour. This should be renamed back
|
|
||||||
// to `getDecl` once the change is settled.
|
|
||||||
EnumDecl *getOriginalDecl() const {
|
EnumDecl *getOriginalDecl() const {
|
||||||
return reinterpret_cast<EnumDecl *>(TagType::getOriginalDecl());
|
return reinterpret_cast<EnumDecl *>(TagType::getOriginalDecl());
|
||||||
}
|
}
|
||||||
@ -6528,9 +6515,6 @@ class InjectedClassNameType final : public TagType {
|
|||||||
bool IsInjected, const Type *CanonicalType);
|
bool IsInjected, const Type *CanonicalType);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// FIXME: Temporarily renamed from `getDecl` in order to facilitate
|
|
||||||
// rebasing, due to change in behaviour. This should be renamed back
|
|
||||||
// to `getDecl` once the change is settled.
|
|
||||||
CXXRecordDecl *getOriginalDecl() const {
|
CXXRecordDecl *getOriginalDecl() const {
|
||||||
return reinterpret_cast<CXXRecordDecl *>(TagType::getOriginalDecl());
|
return reinterpret_cast<CXXRecordDecl *>(TagType::getOriginalDecl());
|
||||||
}
|
}
|
||||||
@ -6996,56 +6980,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the result of substituting a set of types as a template argument
|
|
||||||
/// that needs to be expanded later.
|
|
||||||
///
|
|
||||||
/// These types are always dependent and produced depending on the situations:
|
|
||||||
/// - SubstTemplateTypeParmPack is an expansion that had to be delayed,
|
|
||||||
/// - SubstBuiltinTemplatePackType is an expansion from a builtin.
|
|
||||||
class SubstPackType : public Type, public llvm::FoldingSetNode {
|
|
||||||
friend class ASTContext;
|
|
||||||
|
|
||||||
/// A pointer to the set of template arguments that this
|
|
||||||
/// parameter pack is instantiated with.
|
|
||||||
const TemplateArgument *Arguments;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
SubstPackType(TypeClass Derived, QualType Canon,
|
|
||||||
const TemplateArgument &ArgPack);
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; }
|
|
||||||
|
|
||||||
TemplateArgument getArgumentPack() const;
|
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID);
|
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
|
||||||
const TemplateArgument &ArgPack);
|
|
||||||
|
|
||||||
static bool classof(const Type *T) {
|
|
||||||
return T->getTypeClass() == SubstTemplateTypeParmPack ||
|
|
||||||
T->getTypeClass() == SubstBuiltinTemplatePack;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents the result of substituting a builtin template as a pack.
|
|
||||||
class SubstBuiltinTemplatePackType : public SubstPackType {
|
|
||||||
friend class ASTContext;
|
|
||||||
|
|
||||||
SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack);
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isSugared() const { return false; }
|
|
||||||
QualType desugar() const { return QualType(this, 0); }
|
|
||||||
|
|
||||||
/// Mark that we reuse the Profile. We do not introduce new fields.
|
|
||||||
using SubstPackType::Profile;
|
|
||||||
|
|
||||||
static bool classof(const Type *T) {
|
|
||||||
return T->getTypeClass() == SubstBuiltinTemplatePack;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents the result of substituting a set of types for a template
|
/// Represents the result of substituting a set of types for a template
|
||||||
/// type parameter pack.
|
/// type parameter pack.
|
||||||
///
|
///
|
||||||
@ -7058,7 +6992,7 @@ public:
|
|||||||
/// that pack expansion (e.g., when all template parameters have corresponding
|
/// that pack expansion (e.g., when all template parameters have corresponding
|
||||||
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
|
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
|
||||||
/// at the current pack substitution index.
|
/// at the current pack substitution index.
|
||||||
class SubstTemplateTypeParmPackType : public SubstPackType {
|
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
|
||||||
friend class ASTContext;
|
friend class ASTContext;
|
||||||
|
|
||||||
/// A pointer to the set of template arguments that this
|
/// A pointer to the set of template arguments that this
|
||||||
@ -7084,17 +7018,21 @@ public:
|
|||||||
|
|
||||||
/// Returns the index of the replaced parameter in the associated declaration.
|
/// Returns the index of the replaced parameter in the associated declaration.
|
||||||
/// This should match the result of `getReplacedParameter()->getIndex()`.
|
/// This should match the result of `getReplacedParameter()->getIndex()`.
|
||||||
unsigned getIndex() const {
|
unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
|
||||||
return SubstPackTypeBits.SubstTemplTypeParmPackIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This substitution will be Final, which means the substitution will be fully
|
// This substitution will be Final, which means the substitution will be fully
|
||||||
// sugared: it doesn't need to be resugared later.
|
// sugared: it doesn't need to be resugared later.
|
||||||
bool getFinal() const;
|
bool getFinal() const;
|
||||||
|
|
||||||
|
unsigned getNumArgs() const {
|
||||||
|
return SubstTemplateTypeParmPackTypeBits.NumArgs;
|
||||||
|
}
|
||||||
|
|
||||||
bool isSugared() const { return false; }
|
bool isSugared() const { return false; }
|
||||||
QualType desugar() const { return QualType(this, 0); }
|
QualType desugar() const { return QualType(this, 0); }
|
||||||
|
|
||||||
|
TemplateArgument getArgumentPack() const;
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID);
|
void Profile(llvm::FoldingSetNodeID &ID);
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
|
static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
|
||||||
unsigned Index, bool Final,
|
unsigned Index, bool Final,
|
||||||
@ -7329,7 +7267,9 @@ public:
|
|||||||
TemplateSpecializationTypeBits.NumArgs};
|
TemplateSpecializationTypeBits.NumArgs};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSugared() const;
|
bool isSugared() const {
|
||||||
|
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
|
||||||
|
}
|
||||||
|
|
||||||
QualType desugar() const {
|
QualType desugar() const {
|
||||||
return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
|
return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
|
||||||
|
@ -989,22 +989,12 @@ class SubstTemplateTypeParmTypeLoc :
|
|||||||
SubstTemplateTypeParmType> {
|
SubstTemplateTypeParmType> {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract type representing delayed type pack expansions.
|
/// Wrapper for substituted template type parameters.
|
||||||
class SubstPackTypeLoc
|
class SubstTemplateTypeParmPackTypeLoc :
|
||||||
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc,
|
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||||
SubstPackType> {};
|
SubstTemplateTypeParmPackTypeLoc,
|
||||||
|
SubstTemplateTypeParmPackType> {
|
||||||
/// Wrapper for substituted template type parameters.
|
};
|
||||||
class SubstTemplateTypeParmPackTypeLoc
|
|
||||||
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
|
|
||||||
SubstTemplateTypeParmPackTypeLoc,
|
|
||||||
SubstTemplateTypeParmPackType> {};
|
|
||||||
|
|
||||||
/// Wrapper for substituted template type parameters.
|
|
||||||
class SubstBuiltinTemplatePackTypeLoc
|
|
||||||
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
|
|
||||||
SubstBuiltinTemplatePackTypeLoc,
|
|
||||||
SubstBuiltinTemplatePackType> {};
|
|
||||||
|
|
||||||
struct AttributedLocInfo {
|
struct AttributedLocInfo {
|
||||||
const Attr *TypeAttr;
|
const Attr *TypeAttr;
|
||||||
|
@ -820,12 +820,6 @@ let Class = PackExpansionType in {
|
|||||||
}]>;
|
}]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Class = SubstPackType in {
|
|
||||||
def : Property<"replacementPack", TemplateArgument> {
|
|
||||||
let Read = [{ node->getArgumentPack() }];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Class = SubstTemplateTypeParmPackType in {
|
let Class = SubstTemplateTypeParmPackType in {
|
||||||
def : Property<"associatedDecl", DeclRef> {
|
def : Property<"associatedDecl", DeclRef> {
|
||||||
let Read = [{ node->getAssociatedDecl() }];
|
let Read = [{ node->getAssociatedDecl() }];
|
||||||
@ -833,7 +827,12 @@ let Class = SubstTemplateTypeParmPackType in {
|
|||||||
def : Property<"Index", UInt32> {
|
def : Property<"Index", UInt32> {
|
||||||
let Read = [{ node->getIndex() }];
|
let Read = [{ node->getIndex() }];
|
||||||
}
|
}
|
||||||
def : Property<"Final", Bool> { let Read = [{ node->getFinal() }]; }
|
def : Property<"Final", Bool> {
|
||||||
|
let Read = [{ node->getFinal() }];
|
||||||
|
}
|
||||||
|
def : Property<"replacementPack", TemplateArgument> {
|
||||||
|
let Read = [{ node->getArgumentPack() }];
|
||||||
|
}
|
||||||
|
|
||||||
def : Creator<[{
|
def : Creator<[{
|
||||||
return ctx.getSubstTemplateTypeParmPackType(
|
return ctx.getSubstTemplateTypeParmPackType(
|
||||||
@ -841,12 +840,6 @@ let Class = SubstTemplateTypeParmPackType in {
|
|||||||
}]>;
|
}]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Class = SubstBuiltinTemplatePackType in {
|
|
||||||
def : Creator<[{
|
|
||||||
return ctx.getSubstBuiltinTemplatePack(replacementPack);
|
|
||||||
}]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Class = BuiltinType in {
|
let Class = BuiltinType in {
|
||||||
def : Property<"kind", BuiltinTypeKind> {
|
def : Property<"kind", BuiltinTypeKind> {
|
||||||
let Read = [{ node->getKind() }];
|
let Read = [{ node->getKind() }];
|
||||||
|
@ -5661,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
|
|||||||
return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder);
|
return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches the condition expression of an if statement, for loop, while loop,
|
/// Matches the condition expression of an if statement, for loop,
|
||||||
/// do-while loop, switch statement or conditional operator.
|
/// switch statement or conditional operator.
|
||||||
///
|
///
|
||||||
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
|
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
|
||||||
/// \code
|
/// \code
|
||||||
@ -5739,29 +5739,16 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
|
|||||||
return Builder->removeBindings(Predicate);
|
return Builder->removeBindings(Predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a declaration if it declares the same entity as the node previously
|
/// Matches the condition variable statement in an if statement.
|
||||||
/// bound to \p ID.
|
|
||||||
AST_MATCHER_P(Decl, declaresSameEntityAsBoundNode, std::string, ID) {
|
|
||||||
return Builder->removeBindings([&](const internal::BoundNodesMap &Nodes) {
|
|
||||||
return !clang::declaresSameEntity(&Node, Nodes.getNodeAs<Decl>(ID));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Matches the condition variable statement in an if statement, for loop,
|
|
||||||
/// while loop or switch statement.
|
|
||||||
///
|
///
|
||||||
/// Given
|
/// Given
|
||||||
/// \code
|
/// \code
|
||||||
/// if (A* a = GetAPointer()) {}
|
/// if (A* a = GetAPointer()) {}
|
||||||
/// for (; A* a = GetAPointer(); ) {}
|
|
||||||
/// \endcode
|
/// \endcode
|
||||||
/// hasConditionVariableStatement(...)
|
/// hasConditionVariableStatement(...)
|
||||||
/// matches both 'A* a = GetAPointer()'.
|
/// matches 'A* a = GetAPointer()'.
|
||||||
AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement,
|
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
|
||||||
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
|
internal::Matcher<DeclStmt>, InnerMatcher) {
|
||||||
WhileStmt,
|
|
||||||
SwitchStmt),
|
|
||||||
internal::Matcher<DeclStmt>, InnerMatcher) {
|
|
||||||
const DeclStmt* const DeclarationStatement =
|
const DeclStmt* const DeclarationStatement =
|
||||||
Node.getConditionVariableDeclStmt();
|
Node.getConditionVariableDeclStmt();
|
||||||
return DeclarationStatement != nullptr &&
|
return DeclarationStatement != nullptr &&
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -153,11 +152,6 @@ public:
|
|||||||
return {SyntheticFields.begin(), SyntheticFields.end()};
|
return {SyntheticFields.begin(), SyntheticFields.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a synthetic field, if none by that name is already present.
|
|
||||||
void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
|
|
||||||
SyntheticFields.insert({Name, &Loc});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the child storage location for a field `D` of reference type.
|
/// Changes the child storage location for a field `D` of reference type.
|
||||||
/// All other fields cannot change their storage location and always retain
|
/// All other fields cannot change their storage location and always retain
|
||||||
/// the storage location passed to the `RecordStorageLocation` constructor.
|
/// the storage location passed to the `RecordStorageLocation` constructor.
|
||||||
@ -170,11 +164,6 @@ public:
|
|||||||
Children[&D] = Loc;
|
Children[&D] = Loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a child storage location for a field `D`, if not already present.
|
|
||||||
void addChild(const ValueDecl &D, StorageLocation *Loc) {
|
|
||||||
Children.insert({&D, Loc});
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
|
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
|
||||||
return {Children.begin(), Children.end()};
|
return {Children.begin(), Children.end()};
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,20 @@
|
|||||||
#include "clang/Basic/DiagnosticInstallAPI.h"
|
#include "clang/Basic/DiagnosticInstallAPI.h"
|
||||||
#include "clang/Basic/DiagnosticLex.h"
|
#include "clang/Basic/DiagnosticLex.h"
|
||||||
#include "clang/Basic/DiagnosticParse.h"
|
#include "clang/Basic/DiagnosticParse.h"
|
||||||
#include "clang/Basic/DiagnosticRefactoring.h"
|
|
||||||
#include "clang/Basic/DiagnosticSema.h"
|
#include "clang/Basic/DiagnosticSema.h"
|
||||||
#include "clang/Basic/DiagnosticSerialization.h"
|
#include "clang/Basic/DiagnosticSerialization.h"
|
||||||
|
#include "clang/Basic/DiagnosticRefactoring.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
template <size_t SizeOfStr, typename FieldType> class StringSizerHelper {
|
template <size_t SizeOfStr, typename FieldType>
|
||||||
|
class StringSizerHelper {
|
||||||
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { Size = SizeOfStr };
|
enum { Size = SizeOfStr };
|
||||||
};
|
};
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#define STR_SIZE(str, fieldTy) \
|
#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
|
||||||
clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size
|
fieldTy>::Size
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1632,13 +1632,6 @@ def DeviceKernel : DeclOrTypeAttr {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
def SYCLExternal : InheritableAttr {
|
|
||||||
let Spellings = [CXX11<"clang", "sycl_external">];
|
|
||||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
|
||||||
let LangOpts = [SYCLHost, SYCLDevice];
|
|
||||||
let Documentation = [SYCLExternalDocs];
|
|
||||||
}
|
|
||||||
|
|
||||||
def SYCLKernelEntryPoint : InheritableAttr {
|
def SYCLKernelEntryPoint : InheritableAttr {
|
||||||
let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">];
|
let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">];
|
||||||
let Args = [
|
let Args = [
|
||||||
|
@ -476,47 +476,6 @@ The SYCL kernel in the previous code sample meets these expectations.
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
def SYCLExternalDocs : Documentation {
|
|
||||||
let Category = DocCatFunction;
|
|
||||||
let Heading = "sycl_external";
|
|
||||||
let Content = [{
|
|
||||||
The ``sycl_external`` attribute indicates that a function defined in another
|
|
||||||
translation unit may be called by a device function defined in the current
|
|
||||||
translation unit or, if defined in the current translation unit, the function
|
|
||||||
may be called by device functions defined in other translation units.
|
|
||||||
The attribute is intended for use in the implementation of the ``SYCL_EXTERNAL``
|
|
||||||
macro as specified in section 5.10.1, "SYCL functions and member functions
|
|
||||||
linkage", of the SYCL 2020 specification.
|
|
||||||
|
|
||||||
The attribute only appertains to functions and only those that meet the
|
|
||||||
following requirements:
|
|
||||||
|
|
||||||
* Has external linkage
|
|
||||||
* Is not explicitly defined as deleted (the function may be an explicitly
|
|
||||||
defaulted function that is defined as deleted)
|
|
||||||
|
|
||||||
The attribute shall be present on the first declaration of a function and
|
|
||||||
may optionally be present on subsequent declarations.
|
|
||||||
|
|
||||||
When compiling for a SYCL device target that does not support the generic
|
|
||||||
address space, the function shall not specify a raw pointer or reference type
|
|
||||||
as the return type or as a parameter type.
|
|
||||||
See section 5.10, "SYCL offline linking", of the SYCL 2020 specification.
|
|
||||||
The following examples demonstrate the use of this attribute:
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
[[clang::sycl_external]] void Foo(); // Ok.
|
|
||||||
|
|
||||||
[[clang::sycl_external]] void Bar() { /* ... */ } // Ok.
|
|
||||||
|
|
||||||
[[clang::sycl_external]] extern void Baz(); // Ok.
|
|
||||||
|
|
||||||
[[clang::sycl_external]] static void Quux() { /* ... */ } // error: Quux() has internal linkage.
|
|
||||||
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
def SYCLKernelEntryPointDocs : Documentation {
|
def SYCLKernelEntryPointDocs : Documentation {
|
||||||
let Category = DocCatFunction;
|
let Category = DocCatFunction;
|
||||||
let Content = [{
|
let Content = [{
|
||||||
|
@ -62,7 +62,3 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate<
|
|||||||
// typename ...Operands>
|
// typename ...Operands>
|
||||||
def __hlsl_spirv_type : HLSLBuiltinTemplate<
|
def __hlsl_spirv_type : HLSLBuiltinTemplate<
|
||||||
[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
|
[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
|
||||||
|
|
||||||
// template <class ...Args>
|
|
||||||
def __builtin_dedup_pack
|
|
||||||
: CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>;
|
|
||||||
|
@ -1232,18 +1232,6 @@ def ConvertVector : Builtin {
|
|||||||
let Prototype = "void(...)";
|
let Prototype = "void(...)";
|
||||||
}
|
}
|
||||||
|
|
||||||
def MaskedLoad : Builtin {
|
|
||||||
let Spellings = ["__builtin_masked_load"];
|
|
||||||
let Attributes = [NoThrow, CustomTypeChecking];
|
|
||||||
let Prototype = "void(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
def MaskedStore : Builtin {
|
|
||||||
let Spellings = ["__builtin_masked_store"];
|
|
||||||
let Attributes = [NoThrow, CustomTypeChecking];
|
|
||||||
let Prototype = "void(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
def AllocaUninitialized : Builtin {
|
def AllocaUninitialized : Builtin {
|
||||||
let Spellings = ["__builtin_alloca_uninitialized"];
|
let Spellings = ["__builtin_alloca_uninitialized"];
|
||||||
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
|
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
|
||||||
@ -1510,7 +1498,7 @@ def ElementwiseCopysign : Builtin {
|
|||||||
|
|
||||||
def ElementwiseFma : Builtin {
|
def ElementwiseFma : Builtin {
|
||||||
let Spellings = ["__builtin_elementwise_fma"];
|
let Spellings = ["__builtin_elementwise_fma"];
|
||||||
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
|
let Attributes = [NoThrow, Const, CustomTypeChecking];
|
||||||
let Prototype = "void(...)";
|
let Prototype = "void(...)";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1538,18 +1526,6 @@ def ElementwiseFshr : Builtin {
|
|||||||
let Prototype = "void(...)";
|
let Prototype = "void(...)";
|
||||||
}
|
}
|
||||||
|
|
||||||
def ElementwiseCtlz : Builtin {
|
|
||||||
let Spellings = ["__builtin_elementwise_ctlz"];
|
|
||||||
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
|
|
||||||
let Prototype = "void(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
def ElementwiseCttz : Builtin {
|
|
||||||
let Spellings = ["__builtin_elementwise_cttz"];
|
|
||||||
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
|
|
||||||
let Prototype = "void(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
def ReduceMax : Builtin {
|
def ReduceMax : Builtin {
|
||||||
let Spellings = ["__builtin_reduce_max"];
|
let Spellings = ["__builtin_reduce_max"];
|
||||||
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
|
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
|
||||||
|
@ -580,8 +580,6 @@ TARGET_BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "",
|
|||||||
"isa-v207-instructions")
|
"isa-v207-instructions")
|
||||||
|
|
||||||
// P9 Binary-coded decimal (BCD) builtins.
|
// P9 Binary-coded decimal (BCD) builtins.
|
||||||
TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector")
|
|
||||||
TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector")
|
|
||||||
TARGET_BUILTIN(__builtin_ppc_national2packed, "V16UcV16UcUc", "t", "power9-vector")
|
TARGET_BUILTIN(__builtin_ppc_national2packed, "V16UcV16UcUc", "t", "power9-vector")
|
||||||
TARGET_BUILTIN(__builtin_ppc_packed2national, "V16UcV16Uc", "", "power9-vector")
|
TARGET_BUILTIN(__builtin_ppc_packed2national, "V16UcV16Uc", "", "power9-vector")
|
||||||
TARGET_BUILTIN(__builtin_ppc_packed2zoned, "V16UcV16UcUc", "t", "power9-vector")
|
TARGET_BUILTIN(__builtin_ppc_packed2zoned, "V16UcV16UcUc", "t", "power9-vector")
|
||||||
|
@ -627,23 +627,11 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
|
|||||||
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
||||||
def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
|
||||||
def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
|
|
||||||
def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
|
|
||||||
|
|
||||||
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
|
||||||
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
|
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
||||||
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
|
||||||
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
|
||||||
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
|
||||||
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
|
||||||
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
|
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
|
||||||
@ -666,6 +654,46 @@ let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
|||||||
def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
|
def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
||||||
|
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
||||||
|
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
||||||
|
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
||||||
|
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
||||||
|
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
||||||
|
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
||||||
|
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
||||||
|
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
||||||
|
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
||||||
|
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
||||||
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
|
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
|
||||||
}
|
}
|
||||||
|
@ -400,9 +400,6 @@ def note_constexpr_non_const_vectorelements : Note<
|
|||||||
"cannot determine number of elements for sizeless vectors in a constant expression">;
|
"cannot determine number of elements for sizeless vectors in a constant expression">;
|
||||||
def note_constexpr_assumption_failed : Note<
|
def note_constexpr_assumption_failed : Note<
|
||||||
"assumption evaluated to false">;
|
"assumption evaluated to false">;
|
||||||
def note_constexpr_countzeroes_zero : Note<
|
|
||||||
"evaluation of %select{__builtin_elementwise_ctlz|__builtin_elementwise_cttz}0 "
|
|
||||||
"with a zero value is undefined">;
|
|
||||||
def err_experimental_clang_interp_failed : Error<
|
def err_experimental_clang_interp_failed : Error<
|
||||||
"the experimental clang interpreter failed to evaluate an expression">;
|
"the experimental clang interpreter failed to evaluate an expression">;
|
||||||
|
|
||||||
|
@ -581,13 +581,6 @@ def err_drv_reduced_module_output_overrided : Warning<
|
|||||||
"please consider use '-fmodule-output=' to specify the output file for reduced BMI explicitly">,
|
"please consider use '-fmodule-output=' to specify the output file for reduced BMI explicitly">,
|
||||||
InGroup<DiagGroup<"reduced-bmi-output-overrided">>;
|
InGroup<DiagGroup<"reduced-bmi-output-overrided">>;
|
||||||
|
|
||||||
def remark_found_cxx20_module_usage : Remark<
|
|
||||||
"found C++20 module usage in file '%0'">,
|
|
||||||
InGroup<ModulesDriver>;
|
|
||||||
def remark_performing_driver_managed_module_build : Remark<
|
|
||||||
"performing driver managed module build">,
|
|
||||||
InGroup<ModulesDriver>;
|
|
||||||
|
|
||||||
def warn_drv_delayed_template_parsing_after_cxx20 : Warning<
|
def warn_drv_delayed_template_parsing_after_cxx20 : Warning<
|
||||||
"-fdelayed-template-parsing is deprecated after C++20">,
|
"-fdelayed-template-parsing is deprecated after C++20">,
|
||||||
InGroup<DiagGroup<"delayed-template-parsing-in-cxx20">>;
|
InGroup<DiagGroup<"delayed-template-parsing-in-cxx20">>;
|
||||||
@ -885,9 +878,4 @@ def warn_drv_openacc_without_cir
|
|||||||
: Warning<"OpenACC directives will result in no runtime behavior; use "
|
: Warning<"OpenACC directives will result in no runtime behavior; use "
|
||||||
"-fclangir to enable runtime effect">,
|
"-fclangir to enable runtime effect">,
|
||||||
InGroup<SourceUsesOpenACC>;
|
InGroup<SourceUsesOpenACC>;
|
||||||
|
|
||||||
def warn_drv_gcc_install_dir_libstdcxx : Warning<
|
|
||||||
"future releases of the clang compiler will prefer GCC installations "
|
|
||||||
"containing libstdc++ include directories; '%0' would be chosen over '%1'">,
|
|
||||||
InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
|
|
||||||
}
|
}
|
||||||
|
@ -635,7 +635,6 @@ def ModuleConflict : DiagGroup<"module-conflict">;
|
|||||||
def ModuleFileExtension : DiagGroup<"module-file-extension">;
|
def ModuleFileExtension : DiagGroup<"module-file-extension">;
|
||||||
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
|
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
|
||||||
def ModuleMap : DiagGroup<"module-map">;
|
def ModuleMap : DiagGroup<"module-map">;
|
||||||
def ModulesDriver : DiagGroup<"modules-driver">;
|
|
||||||
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
|
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
|
||||||
def NewlineEOF : DiagGroup<"newline-eof">;
|
def NewlineEOF : DiagGroup<"newline-eof">;
|
||||||
def Nullability : DiagGroup<"nullability">;
|
def Nullability : DiagGroup<"nullability">;
|
||||||
@ -652,7 +651,6 @@ def NonNull : DiagGroup<"nonnull">;
|
|||||||
def NonPODVarargs : DiagGroup<"non-pod-varargs">;
|
def NonPODVarargs : DiagGroup<"non-pod-varargs">;
|
||||||
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
|
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
|
||||||
def : DiagGroup<"nonportable-cfstrings">;
|
def : DiagGroup<"nonportable-cfstrings">;
|
||||||
def NonPortableSYCL : DiagGroup<"nonportable-sycl">;
|
|
||||||
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
|
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
|
||||||
def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">;
|
def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">;
|
||||||
def NullPointerArithmetic
|
def NullPointerArithmetic
|
||||||
|
@ -23,78 +23,76 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class DiagnosticsEngine;
|
class DiagnosticsEngine;
|
||||||
class DiagnosticBuilder;
|
class DiagnosticBuilder;
|
||||||
class LangOptions;
|
class LangOptions;
|
||||||
class SourceLocation;
|
class SourceLocation;
|
||||||
|
|
||||||
// Import the diagnostic enums themselves.
|
// Import the diagnostic enums themselves.
|
||||||
namespace diag {
|
namespace diag {
|
||||||
enum class Group;
|
enum class Group;
|
||||||
|
|
||||||
// Size of each of the diagnostic categories.
|
// Size of each of the diagnostic categories.
|
||||||
enum {
|
enum {
|
||||||
DIAG_SIZE_COMMON = 300,
|
DIAG_SIZE_COMMON = 300,
|
||||||
DIAG_SIZE_DRIVER = 400,
|
DIAG_SIZE_DRIVER = 400,
|
||||||
DIAG_SIZE_FRONTEND = 200,
|
DIAG_SIZE_FRONTEND = 200,
|
||||||
DIAG_SIZE_SERIALIZATION = 120,
|
DIAG_SIZE_SERIALIZATION = 120,
|
||||||
DIAG_SIZE_LEX = 500,
|
DIAG_SIZE_LEX = 500,
|
||||||
DIAG_SIZE_PARSE = 800,
|
DIAG_SIZE_PARSE = 800,
|
||||||
DIAG_SIZE_AST = 300,
|
DIAG_SIZE_AST = 300,
|
||||||
DIAG_SIZE_COMMENT = 100,
|
DIAG_SIZE_COMMENT = 100,
|
||||||
DIAG_SIZE_CROSSTU = 100,
|
DIAG_SIZE_CROSSTU = 100,
|
||||||
DIAG_SIZE_SEMA = 5000,
|
DIAG_SIZE_SEMA = 5000,
|
||||||
DIAG_SIZE_ANALYSIS = 100,
|
DIAG_SIZE_ANALYSIS = 100,
|
||||||
DIAG_SIZE_REFACTORING = 1000,
|
DIAG_SIZE_REFACTORING = 1000,
|
||||||
DIAG_SIZE_INSTALLAPI = 100,
|
DIAG_SIZE_INSTALLAPI = 100,
|
||||||
};
|
};
|
||||||
// Start position for diagnostics.
|
// Start position for diagnostics.
|
||||||
// clang-format off
|
enum {
|
||||||
enum {
|
DIAG_START_COMMON = 0,
|
||||||
DIAG_START_COMMON = 0,
|
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
|
||||||
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
|
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
|
||||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
|
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
||||||
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_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
||||||
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_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
||||||
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_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
||||||
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_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
|
||||||
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
|
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
|
||||||
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
|
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
|
||||||
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
|
};
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
class CustomDiagInfo;
|
class CustomDiagInfo;
|
||||||
|
|
||||||
/// All of the diagnostics that can be emitted by the frontend.
|
/// All of the diagnostics that can be emitted by the frontend.
|
||||||
typedef unsigned kind;
|
typedef unsigned kind;
|
||||||
|
|
||||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||||
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
||||||
/// (emit a warning) or Error (emit as an error). It allows clients to
|
/// (emit a warning) or Error (emit as an error). It allows clients to
|
||||||
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
|
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
|
||||||
enum class Severity : uint8_t {
|
enum class Severity : uint8_t {
|
||||||
// NOTE: 0 means "uncomputed".
|
// NOTE: 0 means "uncomputed".
|
||||||
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
||||||
Remark = 2, ///< Present this diagnostic as a remark.
|
Remark = 2, ///< Present this diagnostic as a remark.
|
||||||
Warning = 3, ///< Present this diagnostic as a warning.
|
Warning = 3, ///< Present this diagnostic as a warning.
|
||||||
Error = 4, ///< Present this diagnostic as an error.
|
Error = 4, ///< Present this diagnostic as an error.
|
||||||
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
||||||
/// kind of diagnostic (for instance, for -W/-R flags).
|
/// kind of diagnostic (for instance, for -W/-R flags).
|
||||||
enum class Flavor {
|
enum class Flavor {
|
||||||
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
||||||
///< problem. Can be made fatal by -Werror.
|
///< problem. Can be made fatal by -Werror.
|
||||||
Remark ///< A diagnostic that indicates normal progress through
|
Remark ///< A diagnostic that indicates normal progress through
|
||||||
///< compilation.
|
///< compilation.
|
||||||
};
|
};
|
||||||
} // end namespace diag
|
} // end namespace diag
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
// This has to be included *after* the DIAG_START_ enums above are defined.
|
// This has to be included *after* the DIAG_START_ enums above are defined.
|
||||||
@ -175,8 +173,7 @@ public:
|
|||||||
|
|
||||||
/// Used for handling and querying diagnostic IDs.
|
/// Used for handling and querying diagnostic IDs.
|
||||||
///
|
///
|
||||||
/// Can be used and shared by multiple Diagnostics for multiple translation
|
/// Can be used and shared by multiple Diagnostics for multiple translation units.
|
||||||
/// units.
|
|
||||||
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
||||||
public:
|
public:
|
||||||
/// The level of the diagnostic, after it has been through mapping.
|
/// The level of the diagnostic, after it has been through mapping.
|
||||||
@ -501,6 +498,6 @@ private:
|
|||||||
friend class DiagnosticsEngine;
|
friend class DiagnosticsEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6074,13 +6074,6 @@ def warn_cxx23_pack_indexing : Warning<
|
|||||||
def err_pack_outside_template : Error<
|
def err_pack_outside_template : Error<
|
||||||
"pack declaration outside of template">;
|
"pack declaration outside of template">;
|
||||||
|
|
||||||
def err_builtin_pack_outside_template
|
|
||||||
: Error<"%0 cannot be used outside of template">;
|
|
||||||
|
|
||||||
def err_unsupported_builtin_template_pack_expansion
|
|
||||||
: Error<"expansions of %0 are not supported here. Only expansions in "
|
|
||||||
"template arguments and class bases are supported">;
|
|
||||||
|
|
||||||
def err_fold_expression_packs_both_sides : Error<
|
def err_fold_expression_packs_both_sides : Error<
|
||||||
"binary fold expression has unexpanded parameter packs in both operands">;
|
"binary fold expression has unexpanded parameter packs in both operands">;
|
||||||
def err_fold_expression_empty : Error<
|
def err_fold_expression_empty : Error<
|
||||||
@ -11001,15 +10994,10 @@ def err_block_on_vm : Error<
|
|||||||
def err_sizeless_nonlocal : Error<
|
def err_sizeless_nonlocal : Error<
|
||||||
"non-local variable with sizeless type %0">;
|
"non-local variable with sizeless type %0">;
|
||||||
|
|
||||||
def err_vec_masked_load_store_ptr : Error<
|
|
||||||
"%ordinal0 argument must be a %1">;
|
|
||||||
def err_vec_masked_load_store_size : Error<
|
|
||||||
"all arguments to %0 must have the same number of elements (was %1 and %2)">;
|
|
||||||
|
|
||||||
def err_vec_builtin_non_vector : Error<
|
def err_vec_builtin_non_vector : Error<
|
||||||
"%select{first two|all}1 arguments to %0 must be vectors">;
|
"%select{first two|all}1 arguments to %0 must be vectors">;
|
||||||
def err_vec_builtin_incompatible_vector : Error<
|
def err_vec_builtin_incompatible_vector : Error<
|
||||||
"%select{first two|all|last two}1 arguments to %0 must have the same type">;
|
"%select{first two|all}1 arguments to %0 must have the same type">;
|
||||||
def err_vsx_builtin_nonconstant_argument : Error<
|
def err_vsx_builtin_nonconstant_argument : Error<
|
||||||
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
|
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
|
||||||
|
|
||||||
@ -12871,7 +12859,7 @@ def err_builtin_invalid_arg_type: Error<
|
|||||||
"%plural{0:|: }1"
|
"%plural{0:|: }1"
|
||||||
// Second component: integer-like types
|
// Second component: integer-like types
|
||||||
"%select{|integer|signed integer|unsigned integer|'int'|"
|
"%select{|integer|signed integer|unsigned integer|'int'|"
|
||||||
"pointer to a valid matrix element|boolean}2"
|
"pointer to a valid matrix element}2"
|
||||||
// A space after a non-empty second component
|
// A space after a non-empty second component
|
||||||
"%plural{0:|: }2"
|
"%plural{0:|: }2"
|
||||||
// An 'or' if non-empty second and third components are combined
|
// An 'or' if non-empty second and third components are combined
|
||||||
@ -12963,17 +12951,6 @@ def err_sycl_special_type_num_init_method : Error<
|
|||||||
"types with 'sycl_special_class' attribute must have one and only one '__init' "
|
"types with 'sycl_special_class' attribute must have one and only one '__init' "
|
||||||
"method defined">;
|
"method defined">;
|
||||||
|
|
||||||
// SYCL external attribute diagnostics
|
|
||||||
def err_sycl_external_invalid_linkage : Error<
|
|
||||||
"%0 can only be applied to functions with external linkage">;
|
|
||||||
def err_sycl_external_invalid_main : Error<
|
|
||||||
"%0 cannot be applied to the 'main' function">;
|
|
||||||
def err_sycl_external_invalid_deleted_function : Error<
|
|
||||||
"%0 cannot be applied to an explicitly deleted function">;
|
|
||||||
def warn_sycl_external_missing_on_first_decl : Warning<
|
|
||||||
"%0 attribute does not appear on the first declaration">,
|
|
||||||
InGroup<NonPortableSYCL>;
|
|
||||||
|
|
||||||
// SYCL kernel entry point diagnostics
|
// SYCL kernel entry point diagnostics
|
||||||
def err_sycl_entry_point_invalid : Error<
|
def err_sycl_entry_point_invalid : Error<
|
||||||
"the %0 attribute cannot be applied to a"
|
"the %0 attribute cannot be applied to a"
|
||||||
@ -12988,7 +12965,7 @@ def err_sycl_kernel_name_conflict : Error<
|
|||||||
"the %0 kernel name argument conflicts with a previous declaration">;
|
"the %0 kernel name argument conflicts with a previous declaration">;
|
||||||
def warn_sycl_kernel_name_not_a_class_type : Warning<
|
def warn_sycl_kernel_name_not_a_class_type : Warning<
|
||||||
"%0 is not a valid SYCL kernel name type; a non-union class type is required">,
|
"%0 is not a valid SYCL kernel name type; a non-union class type is required">,
|
||||||
InGroup<NonPortableSYCL>, DefaultError;
|
InGroup<DiagGroup<"nonportable-sycl">>, DefaultError;
|
||||||
def warn_sycl_entry_point_redundant_declaration : Warning<
|
def warn_sycl_entry_point_redundant_declaration : Warning<
|
||||||
"redundant %0 attribute">, InGroup<RedundantAttribute>;
|
"redundant %0 attribute">, InGroup<RedundantAttribute>;
|
||||||
def err_sycl_entry_point_after_definition : Error<
|
def err_sycl_entry_point_after_definition : Error<
|
||||||
@ -13391,23 +13368,16 @@ def err_acc_reduction_num_gangs_conflict
|
|||||||
"appear on a '%2' construct "
|
"appear on a '%2' construct "
|
||||||
"with a '%3' clause%select{ with more than 1 argument|}0">;
|
"with a '%3' clause%select{ with more than 1 argument|}0">;
|
||||||
def err_acc_reduction_type
|
def err_acc_reduction_type
|
||||||
: Error<"invalid type %0 used in OpenACC 'reduction' variable reference; "
|
: Error<"OpenACC 'reduction' variable must be of scalar type, aggregate, "
|
||||||
"type is %enum_select<OACCReductionTy>{%NotScalar{not a scalar "
|
"sub-array, or a composite of scalar types;%select{| sub-array "
|
||||||
"value, or array of scalars, or composite of "
|
"base}1 type is %0">;
|
||||||
"scalars}|%MemberNotScalar{not a scalar value}|%NotAgg{not an "
|
def err_acc_reduction_composite_type
|
||||||
"aggregate}|%NotComplete{not a complete type}|%NotClassStruct{not "
|
: Error<"OpenACC 'reduction' variable must be a composite of scalar types; "
|
||||||
"a class or struct}}1">;
|
"%1 %select{is not a class or struct|is incomplete|is not an "
|
||||||
def note_acc_reduction_array
|
"aggregate}0">;
|
||||||
: Note<"used as element type of "
|
def err_acc_reduction_composite_member_type :Error<
|
||||||
"%enum_select<OACCReductionArray>{%Section{sub-array"
|
"OpenACC 'reduction' composite variable must not have non-scalar field">;
|
||||||
"}|%Subscript{array}|%ArrayTy{array}}0 type %1">;
|
def note_acc_reduction_composite_member_loc : Note<"invalid field is here">;
|
||||||
def note_acc_reduction_member_of_composite
|
|
||||||
: Note<"used as field '%0' of composite '%1'">;
|
|
||||||
def note_acc_reduction_type_summary
|
|
||||||
: Note<"OpenACC 'reduction' variable reference must be a scalar variable "
|
|
||||||
"or a "
|
|
||||||
"composite of scalars, or an array, sub-array, or element of scalar "
|
|
||||||
"types">;
|
|
||||||
def err_acc_loop_not_for_loop
|
def err_acc_loop_not_for_loop
|
||||||
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
|
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
|
||||||
def note_acc_construct_here : Note<"'%0' construct is here">;
|
def note_acc_construct_here : Note<"'%0' construct is here">;
|
||||||
|
@ -128,7 +128,6 @@ FEATURE(attribute_overloadable, true)
|
|||||||
FEATURE(attribute_unavailable_with_message, true)
|
FEATURE(attribute_unavailable_with_message, true)
|
||||||
FEATURE(attribute_unused_on_fields, true)
|
FEATURE(attribute_unused_on_fields, true)
|
||||||
FEATURE(attribute_diagnose_if_objc, true)
|
FEATURE(attribute_diagnose_if_objc, true)
|
||||||
FEATURE(ext_vector_type_boolean, true)
|
|
||||||
FEATURE(blocks, LangOpts.Blocks)
|
FEATURE(blocks, LangOpts.Blocks)
|
||||||
FEATURE(c_thread_safety_attributes, true)
|
FEATURE(c_thread_safety_attributes, true)
|
||||||
FEATURE(cxx_exceptions, LangOpts.CXXExceptions)
|
FEATURE(cxx_exceptions, LangOpts.CXXExceptions)
|
||||||
@ -148,10 +147,8 @@ FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
|
|||||||
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
|
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
|
||||||
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
|
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
|
||||||
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
|
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
|
||||||
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics &&
|
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
|
||||||
PP.getTargetInfo().getTriple().isOSDarwin())
|
EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
|
||||||
FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics &&
|
|
||||||
PP.getTargetInfo().getTriple().isOSDarwin())
|
|
||||||
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
|
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
|
||||||
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
|
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
|
||||||
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
|
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
|
||||||
@ -167,7 +164,7 @@ FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
|
|||||||
|
|
||||||
FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
|
FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
|
||||||
FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
|
FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
|
||||||
FEATURE(ptrauth_objc_signable_class, LangOpts.PointerAuthIntrinsics)
|
FEATURE(ptrauth_objc_signable_class, true)
|
||||||
FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)
|
FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)
|
||||||
|
|
||||||
EXTENSION(swiftcc,
|
EXTENSION(swiftcc,
|
||||||
|
@ -97,9 +97,7 @@ def HLSLAttributedResourceType : TypeNode<Type>;
|
|||||||
def HLSLInlineSpirvType : TypeNode<Type>;
|
def HLSLInlineSpirvType : TypeNode<Type>;
|
||||||
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
|
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
|
||||||
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
|
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
|
||||||
def SubstPackType : TypeNode<Type, 1>;
|
def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
|
||||||
def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
|
|
||||||
def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent;
|
|
||||||
def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
|
def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
|
||||||
def DeducedType : TypeNode<Type, 1>;
|
def DeducedType : TypeNode<Type, 1>;
|
||||||
def AutoType : TypeNode<DeducedType>;
|
def AutoType : TypeNode<DeducedType>;
|
||||||
|
@ -721,6 +721,8 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
|
|||||||
NF = nf,
|
NF = nf,
|
||||||
ManualCodegen = [{
|
ManualCodegen = [{
|
||||||
{
|
{
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
|
|
||||||
bool NoPassthru =
|
bool NoPassthru =
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
||||||
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
||||||
@ -731,18 +733,24 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
|
|||||||
else
|
else
|
||||||
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
|
||||||
|
|
||||||
if (IsMasked)
|
if (NoPassthru) { // Push poison into passthru
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
if (NoPassthru)
|
} else { // Push intrinsics operands into passthru
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
|
||||||
|
Operands.push_back(PassthruOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]);
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
Operands.push_back(Ops[Offset + 1]); // VL
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
|
||||||
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
|
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||||
if (ReturnValue.isNull())
|
if (ReturnValue.isNull())
|
||||||
return LoadValue;
|
return LoadValue;
|
||||||
else
|
else
|
||||||
@ -779,24 +787,26 @@ multiclass RVVUnitStridedSegStoreTuple<string op> {
|
|||||||
{
|
{
|
||||||
// Masked
|
// Masked
|
||||||
// Builtin: (mask, ptr, v_tuple, vl)
|
// Builtin: (mask, ptr, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, mask, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, mask, vl)
|
||||||
// Unmasked
|
// Unmasked
|
||||||
// Builtin: (ptr, v_tuple, vl)
|
// Builtin: (ptr, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, vl)
|
||||||
|
unsigned Offset = IsMasked ? 1 : 0;
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 5> Operands;
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // tuple
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(Ops[0]);
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // VL
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::swap(Ops[0], Ops[2]);
|
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[0]->getType(), Operands.back()->getType()};
|
||||||
else
|
else
|
||||||
std::swap(Ops[0], Ops[1]);
|
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Operands.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
return Builder.CreateCall(F, Operands, "");
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[3]->getType()};
|
|
||||||
else
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()};
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
defvar T = "(Tuple:" # nf # ")";
|
defvar T = "(Tuple:" # nf # ")";
|
||||||
@ -826,6 +836,8 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
|
|||||||
NF = nf,
|
NF = nf,
|
||||||
ManualCodegen = [{
|
ManualCodegen = [{
|
||||||
{
|
{
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
|
|
||||||
bool NoPassthru =
|
bool NoPassthru =
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
||||||
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
||||||
@ -836,21 +848,24 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
|
|||||||
else
|
else
|
||||||
IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()};
|
IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()};
|
||||||
|
|
||||||
if (IsMasked)
|
if (NoPassthru) { // Push poison into passthru
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
if (NoPassthru)
|
} else { // Push intrinsics operands into passthru
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
|
||||||
|
Operands.push_back(PassthruOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]);
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
if (IsMasked)
|
||||||
Value *NewVL = Ops[2];
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
Ops.erase(Ops.begin() + 2);
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
|
||||||
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
|
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||||
// Get alignment from the new vl operand
|
// Get alignment from the new vl operand
|
||||||
clang::CharUnits Align =
|
clang::CharUnits Align =
|
||||||
CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
|
CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
|
||||||
@ -859,7 +874,7 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
|
|||||||
|
|
||||||
// Store new_vl
|
// Store new_vl
|
||||||
llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1);
|
llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1);
|
||||||
Builder.CreateStore(V, Address(NewVL, V->getType(), Align));
|
Builder.CreateStore(V, Address(Ops[Offset + 1], V->getType(), Align));
|
||||||
|
|
||||||
if (ReturnValue.isNull())
|
if (ReturnValue.isNull())
|
||||||
return ReturnTuple;
|
return ReturnTuple;
|
||||||
@ -894,6 +909,8 @@ multiclass RVVStridedSegLoadTuple<string op> {
|
|||||||
NF = nf,
|
NF = nf,
|
||||||
ManualCodegen = [{
|
ManualCodegen = [{
|
||||||
{
|
{
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
|
|
||||||
bool NoPassthru =
|
bool NoPassthru =
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
||||||
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
||||||
@ -904,17 +921,24 @@ multiclass RVVStridedSegLoadTuple<string op> {
|
|||||||
else
|
else
|
||||||
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
|
||||||
|
|
||||||
if (IsMasked)
|
if (NoPassthru) { // Push poison into passthru
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
if (NoPassthru)
|
} else { // Push intrinsics operands into passthru
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
|
||||||
|
Operands.push_back(PassthruOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // Stride
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]);
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
Operands.push_back(Ops[Offset + 2]); // VL
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
|
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||||
|
|
||||||
if (ReturnValue.isNull())
|
if (ReturnValue.isNull())
|
||||||
return LoadValue;
|
return LoadValue;
|
||||||
@ -953,23 +977,27 @@ multiclass RVVStridedSegStoreTuple<string op> {
|
|||||||
{
|
{
|
||||||
// Masked
|
// Masked
|
||||||
// Builtin: (mask, ptr, stride, v_tuple, vl)
|
// Builtin: (mask, ptr, stride, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, stride, mask, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, stride, mask, vl)
|
||||||
// Unmasked
|
// Unmasked
|
||||||
// Builtin: (ptr, stride, v_tuple, vl)
|
// Builtin: (ptr, stride, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, stride, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, stride, vl)
|
||||||
|
unsigned Offset = IsMasked ? 1 : 0;
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // tuple
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // Stride
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(Ops[0]);
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // VL
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::swap(Ops[0], Ops[3]);
|
IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType(), Ops[0]->getType()};
|
||||||
else
|
else
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
|
IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
return Builder.CreateCall(F, Operands, "");
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType(), Ops[3]->getType()};
|
|
||||||
else
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
defvar T = "(Tuple:" # nf # ")";
|
defvar T = "(Tuple:" # nf # ")";
|
||||||
@ -994,30 +1022,40 @@ multiclass RVVIndexedSegLoadTuple<string op> {
|
|||||||
NF = nf,
|
NF = nf,
|
||||||
ManualCodegen = [{
|
ManualCodegen = [{
|
||||||
{
|
{
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
|
|
||||||
bool NoPassthru =
|
bool NoPassthru =
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
|
||||||
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
(!IsMasked && (PolicyAttrs & RVV_VTA));
|
||||||
|
unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
|
||||||
|
|
||||||
|
if (NoPassthru) { // Push poison into passthru
|
||||||
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
} else { // Push intrinsics operands into passthru
|
||||||
|
llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
|
||||||
|
Operands.push_back(PassthruOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // Idx
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(Ops[0]);
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // VL
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
|
||||||
if (NoPassthru)
|
Ops[Offset + 1]->getType(),
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Ops[0]->getType(),
|
||||||
|
Ops.back()->getType()};
|
||||||
if (IsMasked)
|
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(),
|
|
||||||
Ops[2]->getType(),
|
|
||||||
Ops[3]->getType(),
|
|
||||||
Ops[4]->getType()};
|
|
||||||
else
|
else
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(),
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
|
||||||
Ops[2]->getType(),
|
Ops[Offset + 1]->getType(),
|
||||||
Ops[3]->getType()};
|
Ops.back()->getType()};
|
||||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
|
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||||
|
|
||||||
if (ReturnValue.isNull())
|
if (ReturnValue.isNull())
|
||||||
return LoadValue;
|
return LoadValue;
|
||||||
@ -1052,25 +1090,30 @@ multiclass RVVIndexedSegStoreTuple<string op> {
|
|||||||
{
|
{
|
||||||
// Masked
|
// Masked
|
||||||
// Builtin: (mask, ptr, index, v_tuple, vl)
|
// Builtin: (mask, ptr, index, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, index, mask, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, index, mask, vl)
|
||||||
// Unmasked
|
// Unmasked
|
||||||
// Builtin: (ptr, index, v_tuple, vl)
|
// Builtin: (ptr, index, v_tuple, vl)
|
||||||
// Intrinsic: (tuple, ptr, index, vl, SegInstSEW)
|
// Intrinsic: (tuple, ptr, index, vl)
|
||||||
|
unsigned Offset = IsMasked ? 1 : 0;
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // tuple
|
||||||
|
Operands.push_back(Ops[Offset]); // Ptr
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // Idx
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(Ops[0]);
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // VL
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::swap(Ops[0], Ops[3]);
|
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
|
||||||
|
Ops[0]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
else
|
else
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
|
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
if (IsMasked)
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
|
|
||||||
Ops[3]->getType(), Ops[4]->getType()};
|
|
||||||
else
|
|
||||||
IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
|
|
||||||
Ops[3]->getType()};
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
defvar T = "(Tuple:" # nf # ")";
|
defvar T = "(Tuple:" # nf # ")";
|
||||||
@ -1316,21 +1359,33 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
|
unsigned Offset = IsMasked ?
|
||||||
if (IsMasked)
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
|
Operands.push_back(Ops[Offset + 2]); // vxrm
|
||||||
break;
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(), Ops.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
// 12.2. Vector Single-Width Averaging Add and Subtract
|
// 12.2. Vector Single-Width Averaging Add and Subtract
|
||||||
@ -1353,22 +1408,34 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
|
unsigned Offset = IsMasked ?
|
||||||
if (IsMasked)
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(),
|
Operands.push_back(Ops[Offset + 2]); // vxrm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
|
||||||
Ops.back()->getType()};
|
Ops.back()->getType()};
|
||||||
break;
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
// 12.5. Vector Narrowing Fixed-Point Clip Instructions
|
// 12.5. Vector Narrowing Fixed-Point Clip Instructions
|
||||||
@ -1396,6 +1463,7 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
@ -1403,20 +1471,35 @@ let ManualCodegen = [{
|
|||||||
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
||||||
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ?
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
|
if (HasRoundModeOp) {
|
||||||
break;
|
Operands.push_back(Ops[Offset + 2]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = true in {
|
let HasFRMRoundModeOp = true in {
|
||||||
@ -1457,6 +1540,7 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
@ -1464,21 +1548,35 @@ let ManualCodegen = [{
|
|||||||
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
||||||
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ?
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(),
|
if (HasRoundModeOp) {
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
|
||||||
Ops.back()->getType()};
|
Ops.back()->getType()};
|
||||||
break;
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = true in {
|
let HasFRMRoundModeOp = true in {
|
||||||
@ -1521,23 +1619,38 @@ let UnMaskedPolicyScheme = HasPolicyOperand in {
|
|||||||
let ManualCodegen = [{
|
let ManualCodegen = [{
|
||||||
{
|
{
|
||||||
// LLVM intrinsic
|
// LLVM intrinsic
|
||||||
// Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
|
bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ? 2 : 1;
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
if (HasRoundModeOp) {
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(),
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
Ops.back()->getType()};
|
|
||||||
|
|
||||||
break;
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
|
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = 1 in {
|
let HasFRMRoundModeOp = 1 in {
|
||||||
@ -1565,23 +1678,38 @@ let ManualCodegen = [{
|
|||||||
let ManualCodegen = [{
|
let ManualCodegen = [{
|
||||||
{
|
{
|
||||||
// LLVM intrinsic
|
// LLVM intrinsic
|
||||||
// Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 7> Operands;
|
||||||
bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
|
bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ? 2 : 1;
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 4);
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
if (HasRoundModeOp) {
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(),
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
Ops.back()->getType()};
|
|
||||||
|
|
||||||
break;
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
|
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = 1 in {
|
let HasFRMRoundModeOp = 1 in {
|
||||||
@ -1623,6 +1751,7 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, round_mode, vl)
|
// Unmasked: (passthru, op0, round_mode, vl)
|
||||||
// Masked: (passthru, op0, mask, frm, vl, policy)
|
// Masked: (passthru, op0, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
@ -1630,20 +1759,33 @@ let ManualCodegen = [{
|
|||||||
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
|
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
|
||||||
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
|
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ?
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops.back()->getType()};
|
if (HasRoundModeOp) {
|
||||||
break;
|
Operands.push_back(Ops[Offset + 1]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Operands.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = 1 in {
|
let HasFRMRoundModeOp = 1 in {
|
||||||
@ -1808,6 +1950,7 @@ let ManualCodegen = [{
|
|||||||
// LLVM intrinsic
|
// LLVM intrinsic
|
||||||
// Unmasked: (passthru, op0, frm, vl)
|
// Unmasked: (passthru, op0, frm, vl)
|
||||||
// Masked: (passthru, op0, mask, frm, vl, policy)
|
// Masked: (passthru, op0, mask, frm, vl, policy)
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
@ -1815,20 +1958,34 @@ let ManualCodegen = [{
|
|||||||
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
|
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
|
||||||
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
|
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ?
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
|
|
||||||
if (IsMasked)
|
if (IsMasked)
|
||||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()};
|
if (HasRoundModeOp) {
|
||||||
break;
|
Operands.push_back(Ops[Offset + 1]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 1]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
|
||||||
|
Operands.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = 1 in {
|
let HasFRMRoundModeOp = 1 in {
|
||||||
@ -1998,6 +2155,7 @@ let ManualCodegen = [{
|
|||||||
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
// Unmasked: (passthru, op0, op1, round_mode, vl)
|
||||||
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
|
||||||
|
|
||||||
|
SmallVector<llvm::Value*, 6> Operands;
|
||||||
bool HasMaskedOff = !(
|
bool HasMaskedOff = !(
|
||||||
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
|
||||||
(!IsMasked && PolicyAttrs & RVV_VTA));
|
(!IsMasked && PolicyAttrs & RVV_VTA));
|
||||||
@ -2005,17 +2163,32 @@ let ManualCodegen = [{
|
|||||||
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
|
||||||
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
|
||||||
|
|
||||||
if (!HasRoundModeOp)
|
unsigned Offset = IsMasked ?
|
||||||
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
|
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
|
||||||
|
|
||||||
if (IsMasked)
|
|
||||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
|
|
||||||
|
|
||||||
if (!HasMaskedOff)
|
if (!HasMaskedOff)
|
||||||
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
|
Operands.push_back(llvm::PoisonValue::get(ResultType));
|
||||||
|
else
|
||||||
|
Operands.push_back(Ops[IsMasked ? 1 : 0]);
|
||||||
|
|
||||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()};
|
Operands.push_back(Ops[Offset]); // op0
|
||||||
break;
|
Operands.push_back(Ops[Offset + 1]); // op1
|
||||||
|
|
||||||
|
if (IsMasked)
|
||||||
|
Operands.push_back(Ops[0]); // mask
|
||||||
|
|
||||||
|
if (HasRoundModeOp) {
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 3]); // vl
|
||||||
|
} else {
|
||||||
|
Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
|
||||||
|
Operands.push_back(Ops[Offset + 2]); // vl
|
||||||
|
}
|
||||||
|
|
||||||
|
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
|
||||||
|
Ops.back()->getType()};
|
||||||
|
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||||
|
return Builder.CreateCall(F, Operands, "");
|
||||||
}
|
}
|
||||||
}] in {
|
}] in {
|
||||||
let HasFRMRoundModeOp = 1 in {
|
let HasFRMRoundModeOp = 1 in {
|
||||||
|
@ -63,11 +63,11 @@ public:
|
|||||||
|
|
||||||
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
|
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
|
||||||
const llvm::APInt &val) {
|
const llvm::APInt &val) {
|
||||||
return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val));
|
return create<cir::ConstantOp>(loc, cir::IntAttr::get(typ, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
|
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
|
||||||
return cir::ConstantOp::create(*this, loc, attr);
|
return create<cir::ConstantOp>(loc, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
|
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
|
||||||
@ -119,7 +119,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
cir::ConstantOp getBool(bool state, mlir::Location loc) {
|
cir::ConstantOp getBool(bool state, mlir::Location loc) {
|
||||||
return cir::ConstantOp::create(*this, loc, getCIRBoolAttr(state));
|
return create<cir::ConstantOp>(loc, getCIRBoolAttr(state));
|
||||||
}
|
}
|
||||||
cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); }
|
cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); }
|
||||||
cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }
|
cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }
|
||||||
@ -144,37 +144,21 @@ public:
|
|||||||
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
|
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
|
||||||
mlir::Value imag) {
|
mlir::Value imag) {
|
||||||
auto resultComplexTy = cir::ComplexType::get(real.getType());
|
auto resultComplexTy = cir::ComplexType::get(real.getType());
|
||||||
return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real,
|
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
|
||||||
imag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
|
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
|
||||||
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
|
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
|
||||||
return cir::ComplexRealOp::create(*this, loc, operandTy.getElementType(),
|
return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
|
||||||
operand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
|
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
|
||||||
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
|
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
|
||||||
return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(),
|
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
|
||||||
operand);
|
|
||||||
}
|
|
||||||
|
|
||||||
cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr,
|
|
||||||
uint64_t alignment = 0) {
|
|
||||||
mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
|
|
||||||
assert(!cir::MissingFeatures::opLoadStoreVolatile());
|
|
||||||
return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
|
|
||||||
alignmentAttr, cir::MemOrderAttr{});
|
|
||||||
}
|
|
||||||
|
|
||||||
mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr,
|
|
||||||
uint64_t alignment) {
|
|
||||||
return createLoad(loc, ptr, alignment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createNot(mlir::Value value) {
|
mlir::Value createNot(mlir::Value value) {
|
||||||
return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
|
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
|
||||||
cir::UnaryOpKind::Not, value);
|
cir::UnaryOpKind::Not, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +167,7 @@ public:
|
|||||||
mlir::Location loc,
|
mlir::Location loc,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
|
||||||
return cir::DoWhileOp::create(*this, loc, condBuilder, bodyBuilder);
|
return create<cir::DoWhileOp>(loc, condBuilder, bodyBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a while operation.
|
/// Create a while operation.
|
||||||
@ -191,7 +175,7 @@ public:
|
|||||||
mlir::Location loc,
|
mlir::Location loc,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
|
||||||
return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder);
|
return create<cir::WhileOp>(loc, condBuilder, bodyBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a for operation.
|
/// Create a for operation.
|
||||||
@ -200,23 +184,22 @@ public:
|
|||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
|
||||||
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) {
|
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) {
|
||||||
return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder,
|
return create<cir::ForOp>(loc, condBuilder, bodyBuilder, stepBuilder);
|
||||||
stepBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a break operation.
|
/// Create a break operation.
|
||||||
cir::BreakOp createBreak(mlir::Location loc) {
|
cir::BreakOp createBreak(mlir::Location loc) {
|
||||||
return cir::BreakOp::create(*this, loc);
|
return create<cir::BreakOp>(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a continue operation.
|
/// Create a continue operation.
|
||||||
cir::ContinueOp createContinue(mlir::Location loc) {
|
cir::ContinueOp createContinue(mlir::Location loc) {
|
||||||
return cir::ContinueOp::create(*this, loc);
|
return create<cir::ContinueOp>(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
|
mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
|
||||||
mlir::Value operand) {
|
mlir::Value operand) {
|
||||||
return cir::UnaryOp::create(*this, loc, kind, operand);
|
return create<cir::UnaryOp>(loc, kind, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
|
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
|
||||||
@ -226,7 +209,7 @@ public:
|
|||||||
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
|
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
|
||||||
mlir::Type type, llvm::StringRef name,
|
mlir::Type type, llvm::StringRef name,
|
||||||
mlir::IntegerAttr alignment) {
|
mlir::IntegerAttr alignment) {
|
||||||
return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment);
|
return create<cir::AllocaOp>(loc, addrType, type, name, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get constant address of a global variable as an MLIR attribute.
|
/// Get constant address of a global variable as an MLIR attribute.
|
||||||
@ -239,8 +222,8 @@ public:
|
|||||||
|
|
||||||
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {
|
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {
|
||||||
assert(!cir::MissingFeatures::addressSpace());
|
assert(!cir::MissingFeatures::addressSpace());
|
||||||
return cir::GetGlobalOp::create(
|
return create<cir::GetGlobalOp>(loc, getPointerTo(global.getSymType()),
|
||||||
*this, loc, getPointerTo(global.getSymType()), global.getSymName());
|
global.getSymName());
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createGetGlobal(cir::GlobalOp global) {
|
mlir::Value createGetGlobal(cir::GlobalOp global) {
|
||||||
@ -248,39 +231,36 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
|
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
|
||||||
bool isVolatile = false,
|
mlir::IntegerAttr align = {}) {
|
||||||
mlir::IntegerAttr align = {},
|
return create<cir::StoreOp>(loc, val, dst, align);
|
||||||
cir::MemOrderAttr order = {}) {
|
|
||||||
return cir::StoreOp::create(*this, loc, val, dst, align, order);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
|
[[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
|
||||||
mlir::Location loc,
|
mlir::Location loc,
|
||||||
mlir::StringRef name,
|
mlir::StringRef name,
|
||||||
mlir::Type type, bool isConstant,
|
mlir::Type type,
|
||||||
cir::GlobalLinkageKind linkage) {
|
cir::GlobalLinkageKind linkage) {
|
||||||
mlir::OpBuilder::InsertionGuard guard(*this);
|
mlir::OpBuilder::InsertionGuard guard(*this);
|
||||||
setInsertionPointToStart(mlirModule.getBody());
|
setInsertionPointToStart(mlirModule.getBody());
|
||||||
return cir::GlobalOp::create(*this, loc, name, type, isConstant, linkage);
|
return create<cir::GlobalOp>(loc, name, type, linkage);
|
||||||
}
|
}
|
||||||
|
|
||||||
cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
|
cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
|
||||||
mlir::Value base, llvm::StringRef name,
|
mlir::Value base, llvm::StringRef name,
|
||||||
unsigned index) {
|
unsigned index) {
|
||||||
return cir::GetMemberOp::create(*this, loc, resultTy, base, name, index);
|
return create<cir::GetMemberOp>(loc, resultTy, base, name, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
|
mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
|
||||||
clang::CharUnits alignment) {
|
clang::CharUnits alignment) {
|
||||||
mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
|
mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
|
||||||
auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr);
|
auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr);
|
||||||
return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false,
|
return create<cir::LoadOp>(loc, addr, /*isDeref=*/false, alignmentAttr);
|
||||||
alignmentAttr, /*mem_order=*/{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
|
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
|
||||||
mlir::Value stride) {
|
mlir::Value stride) {
|
||||||
return cir::PtrStrideOp::create(*this, loc, base.getType(), base, stride);
|
return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
@ -290,7 +270,7 @@ public:
|
|||||||
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
|
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
|
||||||
mlir::Type returnType, mlir::ValueRange operands,
|
mlir::Type returnType, mlir::ValueRange operands,
|
||||||
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
|
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
|
||||||
auto op = cir::CallOp::create(*this, loc, callee, returnType, operands);
|
auto op = create<cir::CallOp>(loc, callee, returnType, operands);
|
||||||
op->setAttrs(attrs);
|
op->setAttrs(attrs);
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
@ -321,7 +301,7 @@ public:
|
|||||||
mlir::Value src, mlir::Type newTy) {
|
mlir::Value src, mlir::Type newTy) {
|
||||||
if (newTy == src.getType())
|
if (newTy == src.getType())
|
||||||
return src;
|
return src;
|
||||||
return cir::CastOp::create(*this, loc, newTy, kind, src);
|
return create<cir::CastOp>(loc, newTy, kind, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createCast(cir::CastKind kind, mlir::Value src,
|
mlir::Value createCast(cir::CastKind kind, mlir::Value src,
|
||||||
@ -371,7 +351,7 @@ public:
|
|||||||
|
|
||||||
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
|
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
|
||||||
cir::BinOpKind kind, mlir::Value rhs) {
|
cir::BinOpKind kind, mlir::Value rhs) {
|
||||||
return cir::BinOp::create(*this, loc, lhs.getType(), kind, lhs, rhs);
|
return create<cir::BinOp>(loc, lhs.getType(), kind, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
|
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
|
||||||
@ -393,8 +373,8 @@ public:
|
|||||||
mlir::Value trueValue, mlir::Value falseValue) {
|
mlir::Value trueValue, mlir::Value falseValue) {
|
||||||
assert(trueValue.getType() == falseValue.getType() &&
|
assert(trueValue.getType() == falseValue.getType() &&
|
||||||
"trueValue and falseValue should have the same type");
|
"trueValue and falseValue should have the same type");
|
||||||
return cir::SelectOp::create(*this, loc, trueValue.getType(), condition,
|
return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue,
|
||||||
trueValue, falseValue);
|
falseValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
|
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
|
||||||
@ -409,8 +389,8 @@ public:
|
|||||||
|
|
||||||
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
||||||
OverflowBehavior ob = OverflowBehavior::None) {
|
OverflowBehavior ob = OverflowBehavior::None) {
|
||||||
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Mul,
|
auto op =
|
||||||
lhs, rhs);
|
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs);
|
||||||
op.setNoUnsignedWrap(
|
op.setNoUnsignedWrap(
|
||||||
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
||||||
op.setNoSignedWrap(
|
op.setNoSignedWrap(
|
||||||
@ -428,8 +408,8 @@ public:
|
|||||||
|
|
||||||
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
||||||
OverflowBehavior ob = OverflowBehavior::Saturated) {
|
OverflowBehavior ob = OverflowBehavior::Saturated) {
|
||||||
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Sub,
|
auto op =
|
||||||
lhs, rhs);
|
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs);
|
||||||
op.setNoUnsignedWrap(
|
op.setNoUnsignedWrap(
|
||||||
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
||||||
op.setNoSignedWrap(
|
op.setNoSignedWrap(
|
||||||
@ -450,8 +430,8 @@ public:
|
|||||||
|
|
||||||
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
||||||
OverflowBehavior ob = OverflowBehavior::None) {
|
OverflowBehavior ob = OverflowBehavior::None) {
|
||||||
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Add,
|
auto op =
|
||||||
lhs, rhs);
|
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs);
|
||||||
op.setNoUnsignedWrap(
|
op.setNoUnsignedWrap(
|
||||||
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
|
||||||
op.setNoSignedWrap(
|
op.setNoSignedWrap(
|
||||||
@ -472,7 +452,7 @@ public:
|
|||||||
|
|
||||||
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
|
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
|
||||||
mlir::Value lhs, mlir::Value rhs) {
|
mlir::Value lhs, mlir::Value rhs) {
|
||||||
return cir::CmpOp::create(*this, loc, getBoolTy(), kind, lhs, rhs);
|
return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
|
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
|
||||||
@ -481,8 +461,7 @@ public:
|
|||||||
|
|
||||||
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
|
||||||
bool isShiftLeft) {
|
bool isShiftLeft) {
|
||||||
return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs,
|
return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft);
|
||||||
isShiftLeft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
|
mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
|
||||||
@ -560,12 +539,12 @@ public:
|
|||||||
|
|
||||||
/// Create a loop condition.
|
/// Create a loop condition.
|
||||||
cir::ConditionOp createCondition(mlir::Value condition) {
|
cir::ConditionOp createCondition(mlir::Value condition) {
|
||||||
return cir::ConditionOp::create(*this, condition.getLoc(), condition);
|
return create<cir::ConditionOp>(condition.getLoc(), condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a yield operation.
|
/// Create a yield operation.
|
||||||
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
|
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
|
||||||
return cir::YieldOp::create(*this, loc, value);
|
return create<cir::YieldOp>(loc, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,45 +50,6 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
|
|||||||
let isOptional = 1;
|
let isOptional = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// SourceLanguageAttr
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// TODO: Add cases for other languages that Clang supports.
|
|
||||||
|
|
||||||
def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [
|
|
||||||
I32EnumAttrCase<"C", 1, "c">,
|
|
||||||
I32EnumAttrCase<"CXX", 2, "cxx">
|
|
||||||
]> {
|
|
||||||
// The enum attr class is defined in `CIR_SourceLanguageAttr` below,
|
|
||||||
// so that it can define extra class methods.
|
|
||||||
let genSpecializedAttr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> {
|
|
||||||
|
|
||||||
let summary = "Module source language";
|
|
||||||
let description = [{
|
|
||||||
Represents the source language used to generate the module.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
// Module compiled from C.
|
|
||||||
module attributes {cir.lang = cir.lang<c>} {}
|
|
||||||
// Module compiled from C++.
|
|
||||||
module attributes {cir.lang = cir.lang<cxx>} {}
|
|
||||||
```
|
|
||||||
|
|
||||||
Module source language attribute name is `cir.lang` is defined by
|
|
||||||
`getSourceLanguageAttrName` method in CIRDialect class.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let extraClassDeclaration = [{
|
|
||||||
bool isC() const { return getValue() == SourceLanguage::C; }
|
|
||||||
bool isCXX() const { return getValue() == SourceLanguage::CXX; }
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// OptInfoAttr
|
// OptInfoAttr
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -380,44 +341,6 @@ def CIR_ConstVectorAttr : CIR_Attr<"ConstVector", "const_vector", [
|
|||||||
let genVerifyDecl = 1;
|
let genVerifyDecl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// ConstRecordAttr
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def CIR_ConstRecordAttr : CIR_Attr<"ConstRecord", "const_record", [
|
|
||||||
TypedAttrInterface
|
|
||||||
]> {
|
|
||||||
let summary = "Represents a constant record";
|
|
||||||
let description = [{
|
|
||||||
Effectively supports "struct-like" constants. It's must be built from
|
|
||||||
an `mlir::ArrayAttr` instance where each element is a typed attribute
|
|
||||||
(`mlir::TypedAttribute`).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
cir.global external @rgb2 = #cir.const_record<{0 : i8,
|
|
||||||
5 : i64, #cir.null : !cir.ptr<i8>
|
|
||||||
}> : !cir.record<"", i8, i64, !cir.ptr<i8>>
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
|
|
||||||
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
|
|
||||||
"mlir::ArrayAttr":$members);
|
|
||||||
|
|
||||||
let builders = [
|
|
||||||
AttrBuilderWithInferredContext<(ins "cir::RecordType":$type,
|
|
||||||
"mlir::ArrayAttr":$members), [{
|
|
||||||
return $_get(type.getContext(), type, members);
|
|
||||||
}]>
|
|
||||||
];
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
|
||||||
`<` custom<RecordMembers>($members) `>`
|
|
||||||
}];
|
|
||||||
|
|
||||||
let genVerifyDecl = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ConstPtrAttr
|
// ConstPtrAttr
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -535,72 +458,6 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// VTableAttr
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
|
|
||||||
let summary = "Represents a C++ vtable";
|
|
||||||
let description = [{
|
|
||||||
Wraps a #cir.const_record containing one or more vtable arrays.
|
|
||||||
|
|
||||||
In most cases, the anonymous record type wrapped by this attribute will
|
|
||||||
contain a single array corresponding to the vtable for one class. However,
|
|
||||||
in the case of multiple inheritence, the anonymous structure may contain
|
|
||||||
multiple arrays, each of which is a vtable.
|
|
||||||
|
|
||||||
Example 1 (single vtable):
|
|
||||||
```mlir
|
|
||||||
cir.global linkonce_odr @_ZTV6Mother =
|
|
||||||
#cir.vtable<{
|
|
||||||
#cir.const_array<[
|
|
||||||
#cir.ptr<null> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
|
|
||||||
]> : !cir.array<!cir.ptr<!u8i> x 4>
|
|
||||||
}> : !rec_anon_struct1
|
|
||||||
```
|
|
||||||
|
|
||||||
Example 2 (multiple vtables):
|
|
||||||
```mlir
|
|
||||||
cir.global linkonce_odr @_ZTV5Child =
|
|
||||||
#cir.vtable<{
|
|
||||||
#cir.const_array<[
|
|
||||||
#cir.ptr<null> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
|
|
||||||
]> : !cir.array<!cir.ptr<!u8i> x 4>,
|
|
||||||
#cir.const_array<[
|
|
||||||
#cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
|
|
||||||
#cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i>
|
|
||||||
]> : !cir.array<!cir.ptr<!u8i> x 3>
|
|
||||||
}> : !rec_anon_struct2
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
|
|
||||||
// `data` is a const record with one element, containing an array of
|
|
||||||
// vtable information.
|
|
||||||
let parameters = (ins
|
|
||||||
AttributeSelfTypeParameter<"">:$type,
|
|
||||||
"mlir::ArrayAttr":$data
|
|
||||||
);
|
|
||||||
|
|
||||||
let builders = [
|
|
||||||
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
|
|
||||||
"mlir::ArrayAttr":$data), [{
|
|
||||||
return $_get(type.getContext(), type, data);
|
|
||||||
}]>
|
|
||||||
];
|
|
||||||
|
|
||||||
let genVerifyDecl = 1;
|
|
||||||
let assemblyFormat = [{
|
|
||||||
`<` custom<RecordMembers>($data) `>`
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ConstComplexAttr
|
// ConstComplexAttr
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -35,7 +35,6 @@ def CIR_Dialect : Dialect {
|
|||||||
let hasConstantMaterializer = 1;
|
let hasConstantMaterializer = 1;
|
||||||
|
|
||||||
let extraClassDeclaration = [{
|
let extraClassDeclaration = [{
|
||||||
static llvm::StringRef getSourceLanguageAttrName() { return "cir.lang"; }
|
|
||||||
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
|
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
|
||||||
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
|
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
|
||||||
static llvm::StringRef getCalleeAttrName() { return "callee"; }
|
static llvm::StringRef getCalleeAttrName() { return "callee"; }
|
||||||
|
@ -299,20 +299,6 @@ def CIR_ConstantOp : CIR_Op<"const", [
|
|||||||
let hasFolder = 1;
|
let hasFolder = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// C/C++ memory order definitions
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def CIR_MemOrder : CIR_I32EnumAttr<
|
|
||||||
"MemOrder", "Memory order according to C++11 memory model", [
|
|
||||||
I32EnumAttrCase<"Relaxed", 0, "relaxed">,
|
|
||||||
I32EnumAttrCase<"Consume", 1, "consume">,
|
|
||||||
I32EnumAttrCase<"Acquire", 2, "acquire">,
|
|
||||||
I32EnumAttrCase<"Release", 3, "release">,
|
|
||||||
I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">,
|
|
||||||
I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">
|
|
||||||
]>;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// AllocaOp
|
// AllocaOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -422,14 +408,13 @@ def CIR_LoadOp : CIR_Op<"load", [
|
|||||||
let arguments = (ins Arg<CIR_PointerType, "the address to load from",
|
let arguments = (ins Arg<CIR_PointerType, "the address to load from",
|
||||||
[MemRead]>:$addr,
|
[MemRead]>:$addr,
|
||||||
UnitAttr:$isDeref,
|
UnitAttr:$isDeref,
|
||||||
OptionalAttr<I64Attr>:$alignment,
|
OptionalAttr<I64Attr>:$alignment
|
||||||
OptionalAttr<CIR_MemOrder>:$mem_order);
|
);
|
||||||
let results = (outs CIR_AnyType:$result);
|
let results = (outs CIR_AnyType:$result);
|
||||||
|
|
||||||
let assemblyFormat = [{
|
let assemblyFormat = [{
|
||||||
(`deref` $isDeref^)?
|
(`deref` $isDeref^)?
|
||||||
(`align` `(` $alignment^ `)`)?
|
(`align` `(` $alignment^ `)`)?
|
||||||
(`atomic` `(` $mem_order^ `)`)?
|
|
||||||
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
|
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -466,12 +451,10 @@ def CIR_StoreOp : CIR_Op<"store", [
|
|||||||
let arguments = (ins CIR_AnyType:$value,
|
let arguments = (ins CIR_AnyType:$value,
|
||||||
Arg<CIR_PointerType, "the address to store the value",
|
Arg<CIR_PointerType, "the address to store the value",
|
||||||
[MemWrite]>:$addr,
|
[MemWrite]>:$addr,
|
||||||
OptionalAttr<I64Attr>:$alignment,
|
OptionalAttr<I64Attr>:$alignment);
|
||||||
OptionalAttr<CIR_MemOrder>:$mem_order);
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
let assemblyFormat = [{
|
||||||
(`align` `(` $alignment^ `)`)?
|
(`align` `(` $alignment^ `)`)?
|
||||||
(`atomic` `(` $mem_order^ `)`)?
|
|
||||||
$value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr))
|
$value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr))
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -1719,14 +1702,12 @@ def CIR_GlobalOp : CIR_Op<"global", [
|
|||||||
CIR_GlobalLinkageKind:$linkage,
|
CIR_GlobalLinkageKind:$linkage,
|
||||||
OptionalAttr<AnyAttr>:$initial_value,
|
OptionalAttr<AnyAttr>:$initial_value,
|
||||||
UnitAttr:$comdat,
|
UnitAttr:$comdat,
|
||||||
UnitAttr:$constant,
|
|
||||||
UnitAttr:$dso_local,
|
UnitAttr:$dso_local,
|
||||||
OptionalAttr<I64Attr>:$alignment);
|
OptionalAttr<I64Attr>:$alignment);
|
||||||
|
|
||||||
let assemblyFormat = [{
|
let assemblyFormat = [{
|
||||||
($sym_visibility^)?
|
($sym_visibility^)?
|
||||||
(`` $global_visibility^)?
|
(`` $global_visibility^)?
|
||||||
(`constant` $constant^)?
|
|
||||||
$linkage
|
$linkage
|
||||||
(`comdat` $comdat^)?
|
(`comdat` $comdat^)?
|
||||||
(`dso_local` $dso_local^)?
|
(`dso_local` $dso_local^)?
|
||||||
@ -1745,7 +1726,6 @@ def CIR_GlobalOp : CIR_Op<"global", [
|
|||||||
let builders = [OpBuilder<(ins
|
let builders = [OpBuilder<(ins
|
||||||
"llvm::StringRef":$sym_name,
|
"llvm::StringRef":$sym_name,
|
||||||
"mlir::Type":$sym_type,
|
"mlir::Type":$sym_type,
|
||||||
CArg<"bool", "false">:$isConstant,
|
|
||||||
// CIR defaults to external linkage.
|
// CIR defaults to external linkage.
|
||||||
CArg<"cir::GlobalLinkageKind",
|
CArg<"cir::GlobalLinkageKind",
|
||||||
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
|
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
|
||||||
@ -1858,54 +1838,6 @@ def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// VTableGetVirtualFnAddrOp
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [
|
|
||||||
Pure
|
|
||||||
]> {
|
|
||||||
let summary = "Get a the address of a virtual function pointer";
|
|
||||||
let description = [{
|
|
||||||
The `vtable.get_virtual_fn_addr` operation retrieves the address of a
|
|
||||||
virtual function pointer from an object's vtable (__vptr).
|
|
||||||
This is an abstraction to perform the basic pointer arithmetic to get
|
|
||||||
the address of the virtual function pointer, which can then be loaded and
|
|
||||||
called.
|
|
||||||
|
|
||||||
The `vptr` operand must be a `!cir.ptr<!cir.vptr>` value, which would
|
|
||||||
have been returned by a previous call to `cir.vatble.get_vptr`. The
|
|
||||||
`index` operand is an index of the virtual function in the vtable.
|
|
||||||
|
|
||||||
The return type is a pointer-to-pointer to the function type.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```mlir
|
|
||||||
%2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
|
|
||||||
%3 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
|
|
||||||
%4 = cir.load %3 : !cir.ptr<!cir.vptr>, !cir.vptr
|
|
||||||
%5 = cir.vtable.get_virtual_fn_addr %4[2] : !cir.vptr
|
|
||||||
-> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>>
|
|
||||||
%6 = cir.load align(8) %5 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>)
|
|
||||||
-> !s32i>>>,
|
|
||||||
!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>
|
|
||||||
%7 = cir.call %6(%2) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>,
|
|
||||||
!cir.ptr<!rec_C>) -> !s32i
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins
|
|
||||||
Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr,
|
|
||||||
I64Attr:$index);
|
|
||||||
|
|
||||||
let results = (outs CIR_PointerType:$result);
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
|
||||||
$vptr `[` $index `]` attr-dict
|
|
||||||
`:` qualified(type($vptr)) `->` qualified(type($result))
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// SetBitfieldOp
|
// SetBitfieldOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -3634,127 +3566,4 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Variadic Operations
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def CIR_VAStartOp : CIR_Op<"va_start"> {
|
|
||||||
let summary = "Starts a variable argument list";
|
|
||||||
let description = [{
|
|
||||||
The cir.va_start operation models the C/C++ va_start macro by
|
|
||||||
initializing a variable argument list at the given va_list storage
|
|
||||||
location.
|
|
||||||
|
|
||||||
The first operand must be a pointer to the target's `va_list`
|
|
||||||
representation. This operation has no results and produces its effect by
|
|
||||||
mutating the storage referenced by the pointer operand. The second operand
|
|
||||||
must be an integer value that contains the expected number of arguments in
|
|
||||||
that list.
|
|
||||||
|
|
||||||
Each `cir.va_start` must be paired with a corresponding `cir.va_end`
|
|
||||||
on the same logical `va_list` object along all control-flow paths. After
|
|
||||||
`cir.va_end`, the `va_list` must not be accessed unless reinitialized
|
|
||||||
with another `cir.va_start`.
|
|
||||||
|
|
||||||
Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the
|
|
||||||
appropriately decayed pointer to the underlying `va_list` storage.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```mlir
|
|
||||||
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
|
|
||||||
%p = cir.cast(array_to_ptrdecay, %args
|
|
||||||
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
|
|
||||||
!cir.ptr<!rec___va_list_tag>
|
|
||||||
%count = cir.load %0 : !cir.ptr<!s32i>, !s32i
|
|
||||||
cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
let arguments = (ins
|
|
||||||
CIR_PointerType:$arg_list,
|
|
||||||
CIR_AnyFundamentalIntType:$count
|
|
||||||
);
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
|
||||||
$arg_list $count attr-dict `:` type(operands)
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
def CIR_VAEndOp : CIR_Op<"va_end"> {
|
|
||||||
let summary = "Ends a variable argument list";
|
|
||||||
let description = [{
|
|
||||||
The `cir.va_end` operation models the C/C++ va_end macro by finalizing
|
|
||||||
and cleaning up a variable argument list previously initialized with
|
|
||||||
`cir.va_start`.
|
|
||||||
|
|
||||||
The operand must be a pointer to the target's `va_list` representation.
|
|
||||||
This operation has no results and produces its effect by mutating the
|
|
||||||
storage referenced by the pointer operand.
|
|
||||||
|
|
||||||
`cir.va_end` must only be called after a matching `cir.va_start` on the
|
|
||||||
same `va_list` along all control-flow paths. After `cir.va_end`, the
|
|
||||||
`va_list` is invalid and must not be accessed unless reinitialized.
|
|
||||||
|
|
||||||
Lowering typically maps this to the LLVM intrinsic `llvm.va_end`,
|
|
||||||
passing the appropriately decayed pointer to the underlying `va_list`
|
|
||||||
storage.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```mlir
|
|
||||||
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
|
|
||||||
%p = cir.cast(array_to_ptrdecay, %args
|
|
||||||
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
|
|
||||||
!cir.ptr<!rec___va_list_tag>
|
|
||||||
cir.va_end %p : !cir.ptr<!rec___va_list_tag>
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins CIR_PointerType:$arg_list);
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
|
||||||
$arg_list attr-dict `:` type(operands)
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
def CIR_VAArgOp : CIR_Op<"va_arg"> {
|
|
||||||
let summary = "Fetches next variadic element as a given type";
|
|
||||||
let description = [{
|
|
||||||
The `cir.va_arg` operation models the C/C++ `va_arg` macro by reading the
|
|
||||||
next argument from an active variable argument list and producing it as a
|
|
||||||
value of a specified result type.
|
|
||||||
|
|
||||||
The operand must be a pointer to the target's `va_list` representation.
|
|
||||||
The operation advances the `va_list` state as a side effect and returns
|
|
||||||
the fetched value as the result, whose type is chosen by the user of the
|
|
||||||
operation.
|
|
||||||
|
|
||||||
A `cir.va_arg` must only be used on a `va_list` that has been initialized
|
|
||||||
with `cir.va.start` and not yet finalized by `cir.va.end`. The semantics
|
|
||||||
(including alignment and promotion rules) follow the platform ABI; the
|
|
||||||
frontend is responsible for providing a `va_list` pointer that matches the
|
|
||||||
target representation.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```mlir
|
|
||||||
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
|
|
||||||
%p = cir.cast(array_to_ptrdecay, %args
|
|
||||||
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
|
|
||||||
!cir.ptr<!rec___va_list_tag>
|
|
||||||
cir.va.start %p : !cir.ptr<!rec___va_list_tag>
|
|
||||||
|
|
||||||
// Fetch an `int` from the vararg list.
|
|
||||||
%v = cir.va_arg %p : (!cir.ptr<!rec___va_list_tag>) -> !s32i
|
|
||||||
|
|
||||||
cir.va.end %p : !cir.ptr<!rec___va_list_tag>
|
|
||||||
```
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins CIR_PointerType:$arg_list);
|
|
||||||
let results = (outs CIR_AnyType:$result);
|
|
||||||
|
|
||||||
let assemblyFormat = [{
|
|
||||||
$arg_list attr-dict `:` functional-type(operands, $result)
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
|
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
|
||||||
|
@ -113,18 +113,6 @@ LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind gl) {
|
|||||||
isLinkOnceLinkage(gl);
|
isLinkOnceLinkage(gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(cir::MemOrder, cir::MemOrder) = delete;
|
|
||||||
bool operator>(cir::MemOrder, cir::MemOrder) = delete;
|
|
||||||
bool operator<=(cir::MemOrder, cir::MemOrder) = delete;
|
|
||||||
bool operator>=(cir::MemOrder, cir::MemOrder) = delete;
|
|
||||||
|
|
||||||
// Validate an integral value which isn't known to fit within the enum's range
|
|
||||||
// is a valid AtomicOrderingCABI.
|
|
||||||
template <typename Int> inline bool isValidCIRAtomicOrderingCABI(Int value) {
|
|
||||||
return static_cast<Int>(cir::MemOrder::Relaxed) <= value &&
|
|
||||||
value <= static_cast<Int>(cir::MemOrder::SequentiallyConsistent);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cir
|
} // namespace cir
|
||||||
|
|
||||||
#endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
|
#endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
|
||||||
|
@ -26,7 +26,6 @@ std::unique_ptr<Pass> createCIRSimplifyPass();
|
|||||||
std::unique_ptr<Pass> createHoistAllocasPass();
|
std::unique_ptr<Pass> createHoistAllocasPass();
|
||||||
std::unique_ptr<Pass> createLoweringPreparePass();
|
std::unique_ptr<Pass> createLoweringPreparePass();
|
||||||
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
|
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
|
||||||
std::unique_ptr<Pass> createGotoSolverPass();
|
|
||||||
|
|
||||||
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
|
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
|
||||||
|
|
||||||
|
@ -72,16 +72,6 @@ def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
|
|||||||
let dependentDialects = ["cir::CIRDialect"];
|
let dependentDialects = ["cir::CIRDialect"];
|
||||||
}
|
}
|
||||||
|
|
||||||
def GotoSolver : Pass<"cir-goto-solver"> {
|
|
||||||
let summary = "Replaces goto operations with branches";
|
|
||||||
let description = [{
|
|
||||||
This pass transforms CIR and replaces goto-s with branch
|
|
||||||
operations to the proper blocks.
|
|
||||||
}];
|
|
||||||
let constructor = "mlir::createGotoSolverPass()";
|
|
||||||
let dependentDialects = ["cir::CIRDialect"];
|
|
||||||
}
|
|
||||||
|
|
||||||
def LoweringPrepare : Pass<"cir-lowering-prepare"> {
|
def LoweringPrepare : Pass<"cir-lowering-prepare"> {
|
||||||
let summary = "Lower to more fine-grained CIR operations before lowering to "
|
let summary = "Lower to more fine-grained CIR operations before lowering to "
|
||||||
"other dialects";
|
"other dialects";
|
||||||
|
@ -49,6 +49,7 @@ struct MissingFeatures {
|
|||||||
static bool opLoadEmitScalarRangeCheck() { return false; }
|
static bool opLoadEmitScalarRangeCheck() { return false; }
|
||||||
static bool opLoadBooleanRepresentation() { return false; }
|
static bool opLoadBooleanRepresentation() { return false; }
|
||||||
static bool opLoadStoreTbaa() { return false; }
|
static bool opLoadStoreTbaa() { return false; }
|
||||||
|
static bool opLoadStoreMemOrder() { return false; }
|
||||||
static bool opLoadStoreVolatile() { return false; }
|
static bool opLoadStoreVolatile() { return false; }
|
||||||
static bool opLoadStoreAtomic() { return false; }
|
static bool opLoadStoreAtomic() { return false; }
|
||||||
static bool opLoadStoreObjC() { return false; }
|
static bool opLoadStoreObjC() { return false; }
|
||||||
@ -94,6 +95,7 @@ struct MissingFeatures {
|
|||||||
static bool opCallArgEvaluationOrder() { return false; }
|
static bool opCallArgEvaluationOrder() { return false; }
|
||||||
static bool opCallCallConv() { return false; }
|
static bool opCallCallConv() { return false; }
|
||||||
static bool opCallMustTail() { return false; }
|
static bool opCallMustTail() { return false; }
|
||||||
|
static bool opCallVirtual() { return false; }
|
||||||
static bool opCallInAlloca() { return false; }
|
static bool opCallInAlloca() { return false; }
|
||||||
static bool opCallAttrs() { return false; }
|
static bool opCallAttrs() { return false; }
|
||||||
static bool opCallSurroundingTry() { return false; }
|
static bool opCallSurroundingTry() { return false; }
|
||||||
@ -162,8 +164,6 @@ struct MissingFeatures {
|
|||||||
static bool atomicInfoGetAtomicPointer() { return false; }
|
static bool atomicInfoGetAtomicPointer() { return false; }
|
||||||
static bool atomicInfoGetAtomicAddress() { return false; }
|
static bool atomicInfoGetAtomicAddress() { return false; }
|
||||||
static bool atomicUseLibCall() { return false; }
|
static bool atomicUseLibCall() { return false; }
|
||||||
static bool atomicScope() { return false; }
|
|
||||||
static bool atomicSyncScopeID() { return false; }
|
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
static bool abiArgInfo() { return false; }
|
static bool abiArgInfo() { return false; }
|
||||||
@ -176,12 +176,7 @@ struct MissingFeatures {
|
|||||||
static bool aggValueSlotVolatile() { return false; }
|
static bool aggValueSlotVolatile() { return false; }
|
||||||
static bool alignCXXRecordDecl() { return false; }
|
static bool alignCXXRecordDecl() { return false; }
|
||||||
static bool armComputeVolatileBitfields() { return false; }
|
static bool armComputeVolatileBitfields() { return false; }
|
||||||
static bool asmGoto() { return false; }
|
|
||||||
static bool asmInputOperands() { return false; }
|
|
||||||
static bool asmLabelAttr() { return false; }
|
static bool asmLabelAttr() { return false; }
|
||||||
static bool asmMemoryEffects() { return false; }
|
|
||||||
static bool asmOutputOperands() { return false; }
|
|
||||||
static bool asmUnwindClobber() { return false; }
|
|
||||||
static bool assignMemcpyizer() { return false; }
|
static bool assignMemcpyizer() { return false; }
|
||||||
static bool astVarDeclInterface() { return false; }
|
static bool astVarDeclInterface() { return false; }
|
||||||
static bool attributeBuiltin() { return false; }
|
static bool attributeBuiltin() { return false; }
|
||||||
@ -209,7 +204,6 @@ struct MissingFeatures {
|
|||||||
static bool dataLayoutTypeAllocSize() { return false; }
|
static bool dataLayoutTypeAllocSize() { return false; }
|
||||||
static bool dataLayoutTypeStoreSize() { return false; }
|
static bool dataLayoutTypeStoreSize() { return false; }
|
||||||
static bool deferredCXXGlobalInit() { return false; }
|
static bool deferredCXXGlobalInit() { return false; }
|
||||||
static bool devirtualizeMemberFunction() { return false; }
|
|
||||||
static bool ehCleanupFlags() { return false; }
|
static bool ehCleanupFlags() { return false; }
|
||||||
static bool ehCleanupScope() { return false; }
|
static bool ehCleanupScope() { return false; }
|
||||||
static bool ehCleanupScopeRequiresEHCleanup() { return false; }
|
static bool ehCleanupScopeRequiresEHCleanup() { return false; }
|
||||||
@ -221,7 +215,6 @@ struct MissingFeatures {
|
|||||||
static bool emitLValueAlignmentAssumption() { return false; }
|
static bool emitLValueAlignmentAssumption() { return false; }
|
||||||
static bool emitNullabilityCheck() { return false; }
|
static bool emitNullabilityCheck() { return false; }
|
||||||
static bool emitTypeCheck() { return false; }
|
static bool emitTypeCheck() { return false; }
|
||||||
static bool emitTypeMetadataCodeForVCall() { return false; }
|
|
||||||
static bool fastMathFlags() { return false; }
|
static bool fastMathFlags() { return false; }
|
||||||
static bool fpConstraints() { return false; }
|
static bool fpConstraints() { return false; }
|
||||||
static bool generateDebugInfo() { return false; }
|
static bool generateDebugInfo() { return false; }
|
||||||
@ -264,7 +257,6 @@ struct MissingFeatures {
|
|||||||
static bool setNonGC() { return false; }
|
static bool setNonGC() { return false; }
|
||||||
static bool setObjCGCLValueClass() { return false; }
|
static bool setObjCGCLValueClass() { return false; }
|
||||||
static bool setTargetAttributes() { return false; }
|
static bool setTargetAttributes() { return false; }
|
||||||
static bool sourceLanguageCases() { return false; }
|
|
||||||
static bool stackBase() { return false; }
|
static bool stackBase() { return false; }
|
||||||
static bool stackSaveOp() { return false; }
|
static bool stackSaveOp() { return false; }
|
||||||
static bool targetCIRGenInfoArch() { return false; }
|
static bool targetCIRGenInfoArch() { return false; }
|
||||||
@ -281,7 +273,6 @@ struct MissingFeatures {
|
|||||||
static bool vtableInitialization() { return false; }
|
static bool vtableInitialization() { return false; }
|
||||||
static bool vtableRelativeLayout() { return false; }
|
static bool vtableRelativeLayout() { return false; }
|
||||||
static bool msvcBuiltins() { return false; }
|
static bool msvcBuiltins() { return false; }
|
||||||
static bool vaArgABILowering() { return false; }
|
|
||||||
static bool vlas() { return false; }
|
static bool vlas() { return false; }
|
||||||
|
|
||||||
// Missing types
|
// Missing types
|
||||||
|
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