Compare commits

..

20 Commits

Author SHA1 Message Date
Daniel Thornburgh
9265309f0c llvm.reloc.none takes a GlobalValue again
This avoids avoid modifying Module in ISel
2025-08-21 15:09:04 -07:00
Daniel Thornburgh
b7f8a9c8b4 Add a type arg 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
68761d9bf3 Describe the semantics of the arguments copied from C format attr 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
d11cfe5d18 Correct modular_format to modular-format in docs 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
435ba3597b Emit reloc.none instinsic with metdata string arg 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
dff521f73d issing -> issuing 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
40bafe2ceb [IR] "modular-format" attribute for functions using format strings
A new InstCombine transform uses this attribute to rewrite calls to a
modular version of the implementation along with llvm.reloc.none
relocations against aspects of the implementation needed by the call.

This change only adds support for the 'float' aspect, but it also builds
the structure needed for others.

See issue #146159
2025-08-21 15:09:04 -07:00
Daniel Thornburgh
341dd6a3ca Update big-filter.td 2025-08-21 15:08:55 -07:00
Daniel Thornburgh
75c4d315dc Take symbol name by GlobalValue again to avoid modifying Module 2025-08-21 14:28:08 -07:00
Daniel Thornburgh
904c996355 Update tests 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
a6220fef9b Remove arg from emitRelocDirective call 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
20f2ad062c Lower reloc.none in Global ISel 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
6fc858761e Rename reloc_none.ll to reloc-none.ll 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
57ba236e87 Use llvm-as for test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
07ccb63a1b Remove unneeded assertion from AsmPrinter 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
dd58f21c9e IR verifier check and test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
bd4dd9ca02 Add a generic reloc_none test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
5a056672cb Take symbol name by metadata arg rather than ptr to GlobalValue 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
0e830ad120 fake.use -> reloc.none 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
f3fdeff3e3 [IR] llvm.reloc.none intrinsic for no-op symbol references
This intrinsic emits a BFD_RELOC_NONE relocation at the point of call,
which allows optimizations and languages to explicitly pull in symbols
from static libraries without there being any code or data that has an
effectual relocation against such a symbol.

See issue #146159 for context.
2025-08-18 11:37:40 -07:00
2432 changed files with 68240 additions and 161217 deletions

View File

@ -49,7 +49,8 @@ DEPENDENTS_TO_TEST = {
"flang",
},
"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"},
# Test everything if ci scripts are changed.
".ci": {

View File

@ -83,11 +83,11 @@ class TestComputeProjects(unittest.TestCase):
)
self.assertEqual(
env_variables["projects_to_build"],
"clang;clang-tools-extra;lld;lldb;llvm",
"clang;clang-tools-extra;lld;llvm",
)
self.assertEqual(
env_variables["project_check_targets"],
"check-clang check-clang-tools check-lldb",
"check-clang check-clang-tools",
)
self.assertEqual(
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"
@ -158,11 +158,11 @@ class TestComputeProjects(unittest.TestCase):
)
self.assertEqual(
env_variables["projects_to_build"],
"clang;clang-tools-extra;lld;lldb;llvm;mlir",
"clang;clang-tools-extra;lld;llvm;mlir",
)
self.assertEqual(
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(
env_variables["runtimes_to_build"], "compiler-rt;libcxx;libcxxabi;libunwind"

View File

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

View File

@ -70,6 +70,8 @@ jobs:
- name: Run code formatter
env:
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 }}
# Create an empty comments file so the pr-write job doesn't fail.
run: |

View File

@ -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}"
- 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()'
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
@ -119,11 +114,6 @@ jobs:
# 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 }}\""
- 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()'
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:

View File

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

View File

@ -1196,6 +1196,11 @@ public:
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
/// (either primary or secondary).
bool isEntryPoint(const BinaryBasicBlock &BB) const {

View File

@ -241,7 +241,7 @@ private:
/// Adjust function sizes and set proper maximum size values after the whole
/// symbol table has been processed.
void adjustFunctionBoundaries(DenseMap<uint64_t, MarkerSymType> &MarkerSyms);
void adjustFunctionBoundaries();
/// Make .eh_frame section relocatable.
void relocateEHFrameSection();

View File

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

View File

@ -1915,9 +1915,13 @@ void BinaryFunction::postProcessEntryPoints() {
continue;
// If we have grabbed a wrong code label which actually points to some
// constant island inside the function, ignore this label.
if (isStartOfConstantIsland(Offset))
// constant island inside the function, ignore this label and remove it
// from the secondary entry point map.
if (isStartOfConstantIsland(Offset)) {
BC.SymbolToFunctionMap.erase(Label);
removeSymbolFromSecondaryEntryPointMap(Label);
continue;
}
BC.errs() << "BOLT-WARNING: reference in the middle of instruction "
"detected in function "

View File

@ -30,11 +30,6 @@ using namespace bolt;
using namespace MCPlus;
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>
TerminalTrap("terminal-trap",
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 {
if (isX86HLT(Inst))
return opts::TerminalHLT;
if (Info->get(Inst.getOpcode()).isTrap())
return opts::TerminalTrap;
return Analysis->isTerminator(Inst);
return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) ||
Analysis->isTerminator(Inst)
? !isX86HLT(Inst)
: false;
}
void MCPlusBuilder::setTailCall(MCInst &Inst) const {

View File

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

View File

@ -84,7 +84,6 @@ extern cl::opt<bool> KeepNops;
extern cl::opt<bool> Lite;
extern cl::list<std::string> ReorderData;
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
extern cl::opt<bool> TerminalHLT;
extern cl::opt<bool> TerminalTrap;
extern cl::opt<bool> TimeBuild;
extern cl::opt<bool> TimeRewrite;
@ -115,35 +114,6 @@ cl::opt<bool> DumpDotAll(
"enable '-print-loops' for color-coded blocks"),
cl::Hidden, cl::cat(BoltCategory));
cl::list<std::string> DumpDotFunc(
"dump-dot-func", cl::CommaSeparated,
cl::desc(
"dump function CFGs to graphviz format for specified functions only;"
"takes function name patterns (regex supported)"),
cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
bool shouldDumpDot(const bolt::BinaryFunction &Function) {
// If dump-dot-all is enabled, dump all functions
if (DumpDotAll)
return !Function.isIgnored();
// If no specific functions specified in dump-dot-func, don't dump any
if (DumpDotFunc.empty())
return false;
if (Function.isIgnored())
return false;
// Check if function matches any of the specified patterns
for (const std::string &Name : DumpDotFunc) {
if (Function.hasNameRegex(Name)) {
return true;
}
}
return false;
}
static cl::list<std::string>
ForceFunctionNames("funcs",
cl::CommaSeparated,
@ -910,9 +880,14 @@ void RewriteInstance::discoverFileObjects() {
// code section (see IHI0056B). $d identifies data contents.
// 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
// 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 = [&]() {
bool IsData = false;
uint64_t LastAddr = 0;
@ -936,14 +911,14 @@ void RewriteInstance::discoverFileObjects() {
}
if (MarkerType != MarkerSymType::NONE) {
MarkerSymbols[SymInfo.Address] = MarkerType;
SortedMarkerSymbols.push_back(MarkerSym{SymInfo.Address, MarkerType});
LastAddr = SymInfo.Address;
IsData = MarkerType == MarkerSymType::DATA;
continue;
}
if (IsData) {
MarkerSymbols[SymInfo.Address] = MarkerSymType::DATA;
SortedMarkerSymbols.push_back({SymInfo.Address, MarkerSymType::DATA});
LastAddr = SymInfo.Address;
}
}
@ -1308,24 +1283,27 @@ void RewriteInstance::discoverFileObjects() {
BC->setHasSymbolsWithFileName(FileSymbols.size());
// Now that all the functions were created - adjust their boundaries.
adjustFunctionBoundaries(MarkerSymbols);
adjustFunctionBoundaries();
// Annotate functions with code/data markers in AArch64
for (auto &[Address, Type] : MarkerSymbols) {
auto *BF = BC->getBinaryFunctionContainingAddress(Address, true, true);
for (auto ISym = SortedMarkerSymbols.begin();
ISym != SortedMarkerSymbols.end(); ++ISym) {
auto *BF =
BC->getBinaryFunctionContainingAddress(ISym->Address, true, true);
if (!BF) {
// Stray marker
continue;
}
const auto EntryOffset = Address - BF->getAddress();
if (Type == MarkerSymType::CODE) {
const auto EntryOffset = ISym->Address - BF->getAddress();
if (ISym->Type == MarkerSymType::CODE) {
BF->markCodeAtOffset(EntryOffset);
continue;
}
if (Type == MarkerSymType::DATA) {
if (ISym->Type == MarkerSymType::DATA) {
BF->markDataAtOffset(EntryOffset);
BC->AddressToConstantIslandMap[Address] = BF;
BC->AddressToConstantIslandMap[ISym->Address] = BF;
continue;
}
llvm_unreachable("Unknown marker");
@ -1854,8 +1832,7 @@ void RewriteInstance::disassemblePLT() {
}
}
void RewriteInstance::adjustFunctionBoundaries(
DenseMap<uint64_t, MarkerSymType> &MarkerSyms) {
void RewriteInstance::adjustFunctionBoundaries() {
for (auto BFI = BC->getBinaryFunctions().begin(),
BFE = BC->getBinaryFunctions().end();
BFI != BFE; ++BFI) {
@ -1893,15 +1870,12 @@ void RewriteInstance::adjustFunctionBoundaries(
continue;
}
auto It = MarkerSyms.find(NextSymRefI->first);
if (It == MarkerSyms.end() || It->second != MarkerSymType::DATA) {
// This is potentially another entry point into the function.
uint64_t EntryOffset = NextSymRefI->first - Function.getAddress();
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding entry point to function "
<< Function << " at offset 0x"
<< Twine::utohexstr(EntryOffset) << '\n');
Function.addEntryPointAtOffset(EntryOffset);
}
++NextSymRefI;
}
@ -2203,9 +2177,7 @@ void RewriteInstance::adjustCommandLineOptions() {
if (!opts::KeepNops.getNumOccurrences())
opts::KeepNops = true;
// Linux kernel may resume execution after a trap or x86 HLT instruction.
if (!opts::TerminalHLT.getNumOccurrences())
opts::TerminalHLT = false;
// Linux kernel may resume execution after a trap instruction in some cases.
if (!opts::TerminalTrap.getNumOccurrences())
opts::TerminalTrap = false;
}
@ -3598,7 +3570,7 @@ void RewriteInstance::postProcessFunctions() {
if (opts::PrintAll || opts::PrintCFG)
Function.print(BC->outs(), "after building cfg");
if (opts::shouldDumpDot(Function))
if (opts::DumpDotAll)
Function.dumpGraphForPass("00_build-cfg");
if (opts::PrintLoopInfo) {

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

@ -544,7 +544,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
bool ApplyAnyFix, bool EnableCheckProfile,
llvm::StringRef StoreCheckProfile, bool Quiet) {
llvm::StringRef StoreCheckProfile) {
ClangTool Tool(Compilations, InputFiles,
std::make_shared<PCHContainerOperations>(), BaseFS);
@ -581,9 +581,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
class ActionFactory : public FrontendActionFactory {
public:
ActionFactory(ClangTidyContext &Context,
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
bool Quiet)
: ConsumerFactory(Context, std::move(BaseFS)), Quiet(Quiet) {}
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS)
: ConsumerFactory(Context, std::move(BaseFS)) {}
std::unique_ptr<FrontendAction> create() override {
return std::make_unique<Action>(&ConsumerFactory);
}
@ -594,8 +593,6 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
DiagnosticConsumer *DiagConsumer) override {
// Explicitly ask to define __clang_analyzer__ macro.
Invocation->getPreprocessorOpts().SetUpStaticAnalyzer = true;
if (Quiet)
Invocation->getDiagnosticOpts().ShowCarets = false;
return FrontendActionFactory::runInvocation(
Invocation, Files, PCHContainerOps, DiagConsumer);
}
@ -614,10 +611,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
};
ClangTidyASTConsumerFactory ConsumerFactory;
bool Quiet;
};
ActionFactory Factory(Context, std::move(BaseFS), Quiet);
ActionFactory Factory(Context, std::move(BaseFS));
Tool.run(&Factory);
return DiagConsumer.take();
}

View File

@ -94,8 +94,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> BaseFS,
bool ApplyAnyFix, bool EnableCheckProfile = false,
llvm::StringRef StoreCheckProfile = StringRef(),
bool Quiet = false);
llvm::StringRef StoreCheckProfile = StringRef());
/// Controls what kind of fixes clang-tidy is allowed to apply.
enum FixBehaviour {

View File

@ -89,9 +89,13 @@ def write_header(
+ check_name_camel.upper()
+ "_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(
"""
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// 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"
print("Creating %s..." % filename)
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(
"""
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.

View File

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

View File

@ -188,7 +188,7 @@ static bool isKnownToHaveValue(const Expr &Cond, const ASTContext &Ctx,
/// \return true iff all `CallExprs` visited have callees; false otherwise
/// indicating there is an unresolved indirect call.
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)) {
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
/// `Callees`
static bool overlap(ArrayRef<CallGraphNode *> SCC,
const llvm::SmallPtrSet<const Decl *, 16> &Callees,
const llvm::SmallSet<const Decl *, 16> &Callees,
const Decl *Func) {
bool ContainsFunc = false, Overlap = false;
@ -264,7 +264,7 @@ static bool hasRecursionOverStaticLoopCondVariables(const Expr *Cond,
if (!hasStaticLocalVariable(Cond))
return false;
llvm::SmallPtrSet<const Decl *, 16> CalleesInLoop;
llvm::SmallSet<const Decl *, 16> CalleesInLoop;
if (!populateCallees(LoopStmt, CalleesInLoop)) {
// If there are unresolved indirect calls, we assume there could

View File

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

View File

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

View File

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

View File

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

View File

@ -29,13 +29,11 @@ void UnconventionalAssignOperatorCheck::registerMatchers(
const auto HasGoodReturnType =
cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
unless(isConstQualified()),
anyOf(autoType(),
hasDeclaration(declaresSameEntityAsBoundNode("class"))))))));
anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))));
const auto IsSelf = qualType(hasCanonicalType(
anyOf(hasDeclaration(declaresSameEntityAsBoundNode("class")),
referenceType(pointee(
hasDeclaration(declaresSameEntityAsBoundNode("class")))))));
anyOf(hasDeclaration(equalsBoundNode("class")),
referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))));
const auto IsAssign =
cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
hasName("operator="), ofClass(recordDecl().bind("class")))

View File

@ -395,12 +395,16 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
--CurrentFile->ConditionScopes;
}
namespace {
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;
}
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,
PragmaIntroducerKind Introducer) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,13 +21,15 @@ using namespace clang::ast_matchers;
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)
: llvm::Twine('\'') + Name + llvm::Twine('\''))
.str();
}
static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
ASTContext &Context) {
auto Matches = match(
traverse(TK_AsIs,
@ -39,6 +41,8 @@ static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
return Matches.empty();
}
} // namespace
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -717,7 +717,7 @@ int clangTidyMain(int argc, const char **argv) {
EnableModuleHeadersParsing);
std::vector<ClangTidyError> Errors =
runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
FixNotes, EnableCheckProfile, ProfilePrefix, Quiet);
FixNotes, EnableCheckProfile, ProfilePrefix);
bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) {
return E.DiagLevel == ClangTidyError::Error;
});

View File

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

View File

@ -985,7 +985,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
// Recurse on pack parameters
size_t Depth = 0;
const FunctionDecl *CurrentFunction = D;
llvm::SmallPtrSet<const FunctionTemplateDecl *, 4> SeenTemplates;
llvm::SmallSet<const FunctionTemplateDecl *, 4> SeenTemplates;
if (const auto *Template = D->getPrimaryTemplate()) {
SeenTemplates.insert(Template);
}

View File

@ -6,7 +6,7 @@ add_subdirectory(support)
# Configure the Features.inc file.
if (NOT DEFINED CLANGD_BUILD_XPC)
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CLANGD_BUILD_XPC_DEFAULT ON)
else ()
set(CLANGD_BUILD_XPC_DEFAULT OFF)
@ -193,7 +193,7 @@ if(CLANGD_TIDY_CHECKS)
endif()
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.
add_subdirectory(fuzzer)
endif()

View File

@ -833,10 +833,6 @@ bool OverlayCDB::setCompileCommand(PathRef File,
std::unique_ptr<ProjectModules>
OverlayCDB::getProjectModules(PathRef File) const {
auto MDB = DelegatingCDB::getProjectModules(File);
if (!MDB) {
log("Failed to get compilation Database for {0}", File);
return {};
}
MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command,
PathRef CommandPath) {
Mangler(Command, CommandPath);

View File

@ -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.
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,

View File

@ -181,7 +181,7 @@ struct ExtractionZone {
bool requiresHoisting(const SourceManager &SM,
const HeuristicResolver *Resolver) const {
// 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) {
findExplicitReferences(
RootStmt,

View File

@ -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"}

View File

@ -4473,198 +4473,6 @@ TEST(CompletionTest, SkipExplicitObjectParameter) {
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 clangd
} // namespace clang

View File

@ -731,12 +731,6 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
)cpp";
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) {

View File

@ -119,9 +119,6 @@ Improvements to clang-tidy
- Improved documentation of the `-line-filter` command-line flag of
:program:`clang-tidy` and :program:`run-clang-tidy.py`.
- Improved :program:`clang-tidy` option `-quiet` by suppressing diagnostic
count messages.
New checks
^^^^^^^^^^
@ -215,8 +212,7 @@ Changes in existing checks
- Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
declarations in system headers. The documentation is also improved to
differentiate the general options from the specific ones.
declarations in system headers.
- Improved :doc:`readability-qualified-auto
<clang-tidy/checks/readability/qualified-auto>` check by adding the option

View File

@ -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.

View File

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

View File

@ -343,107 +343,6 @@ An overview of all the command-line options:
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:
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
any ``NOLINTBEGIN``/``NOLINTEND`` comment violates these requirements.
.. _Bear: https://github.com/rizsotto/Bear
.. _LibTooling: https://clang.llvm.org/docs/LibTooling.html
.. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html

View File

@ -17,7 +17,6 @@ Contents
clang-tidy/index
clang-include-fixer
clang-change-namespace
modularize
pp-trace
clangd <https://clangd.llvm.org/>

View File

@ -176,11 +176,3 @@ struct TemplateAssignment {
}
};
}
namespace GH153770 {
struct A;
struct A {
A() = default;
A& operator=(const A&) = default;
};
} // namespace GH153770

View File

@ -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' -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' -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
// diagnostics printed by ClangTidy.

View File

@ -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: ^
}

View File

@ -35,7 +35,7 @@ if(WIN32)
endif()
# 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)
endif()

View File

@ -60,10 +60,6 @@ only for the linker wrapper will be forwarded to the wrapped linker job.
--v Display the version number and exit
-- 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
===================

View File

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

View File

@ -635,12 +635,11 @@ C and C++. For example:
return v;
}
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
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
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
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
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
---------------
@ -768,12 +757,11 @@ elementwise to the input.
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_sub_sat``, ``__builtin_elementwise_max``,
``__builtin_elementwise_min``, ``__builtin_elementwise_abs``,
``__builtin_elementwise_ctlz``, ``__builtin_elementwise_cttz``, and
``__builtin_elementwise_fma`` can be called in a ``constexpr`` context.
``__builtin_elementwise_min``, and ``__builtin_elementwise_abs``
can be called in a ``constexpr`` context.
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.
@ -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
right by z, and the least significant bits are extracted to produce
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.
======================================= ====================================================================== ==================================
*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
============
@ -1763,7 +1725,6 @@ Hexadecimal floating constants (N308) C
Compound literals (N716) C99 C89, C++
``//`` comments (N644) C99 C89
Mixed declarations and code (N740) C99 C89
init-statement in for (N740) C99 C89
Variadic macros (N707) C99 C89
Empty macro arguments (N570) 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``.
__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
=====================

File diff suppressed because it is too large Load Diff

View File

@ -37,22 +37,6 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
Potentially Breaking Changes
============================
- Clang will now emit a warning if the auto-detected GCC installation
directory (i.e. the one with the largest version number) does not
contain libstdc++ include directories although a "complete" GCC
installation directory containing the include directories is
available. It is planned to change the auto-detection to prefer the
"complete" directory in the future. The warning will disappear if
the libstdc++ include directories are either installed or removed
for all GCC installation directories considered by the
auto-detection; see the output of ``clang -v`` for a list of those
directories. If the GCC installations cannot be modified and
maintaining the current choice of the auto-detection is desired, the
GCC installation directory can be selected explicitly using the
``--gcc-install-dir`` command line argument. This will silence the
warning. It can also be disabled using the
``-Wno-gcc-install-dir-libstdcxx`` command line flag.
C/C++ Language Potentially Breaking Changes
-------------------------------------------
@ -153,41 +137,10 @@ Non-comprehensive list of changes in this release
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
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 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
-------------------------
@ -225,9 +178,6 @@ Improvements to Clang's diagnostics
potential misaligned members get processed before they can get discarded.
(#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
----------------------------------
@ -245,7 +195,6 @@ Bug Fixes in This Version
cast chain. (#GH149967).
- Fixed a crash with incompatible pointer to integer conversions in designated
initializers involving string literals. (#GH154046)
- Fixed scope of typedefs present inside a template class. (#GH91451)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -255,8 +204,8 @@ Bug Fixes to Compiler Builtins
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``[[nodiscard]]`` is now respected on Objective-C and Objective-C++ methods
(#GH141504) and on types returned from indirect calls (#GH142453).
- ``[[nodiscard]]`` is now respected on Objective-C and Objective-C++ methods.
(#GH141504)
- 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
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)
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
- 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
(``[[assume(expr)]]``) creates temporary objects.
- 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).
- 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)
- 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
^^^^^^^^^^^^^^^^^^^^^^^^^
@ -309,13 +255,6 @@ NVPTX Support
X86 Support
^^^^^^^^^^^
- More SSE, AVX and AVX512 intrinsics, including initializers and general
arithmetic can now be used in C++ constant expressions.
- Some SSE, AVX and AVX512 intrinsics have been converted to wrap
generic __builtin intrinsics.
- NOTE: Please avoid use of the __builtin_ia32_* intrinsics - these are not
guaranteed to exist in future releases, or match behaviour with previous
releases of clang or other compilers.
Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^
@ -375,9 +314,6 @@ AST Matchers
- Add a boolean member ``IgnoreSystemHeaders`` to ``MatchFinderOptions``. This
allows it to ignore nodes in system headers when traversing the AST.
- ``hasConditionVariableStatement`` now supports ``for`` loop, ``while`` loop
and ``switch`` statements.
clang-format
------------
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.

View File

@ -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
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
serially, whereas the two-phase compilation model can be compiled as
soon as ``A.pcm`` is available, and thus can be compiled simultaneously with the
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 as the
``A.pcm`` to ``A.o`` compilation step.
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
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
more details.)
more details.
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
@ -403,7 +403,7 @@ clang-cl
``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``
`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.
@ -411,7 +411,7 @@ Consistency Requirements
~~~~~~~~~~~~~~~~~~~~~~~~
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.
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
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
code into the BMI file; the BMI file contains a sufficiently verbose
When the ``-fmodules-embed-all-files`` flag are enabled, Clang explicitly emits the source
code into the BMI file, the contents of the BMI file contain a sufficiently verbose
representation to reproduce the original source file.
.. [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
dynamic initialization; otherwise, the importer may call a nonexistent
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.
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
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.
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.
Experimental Non-Cascading Changes
@ -699,7 +699,7 @@ Experimental Non-Cascading Changes
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.
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
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,
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
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
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++
@ -830,7 +830,7 @@ and recompile the example:
$ md5sum 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``.
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
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.
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
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
guidance, rather than as requirements to use modules in Clang.** It presumes
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
`include after import <https://github.com/llvm/llvm-project/issues/61465>`_.
Even when that issue is resolved, users may still get slower compilation speed
@ -1409,7 +1409,7 @@ Until then, it is recommended not to mix macros with module declarations.
In consistent filename suffix requirement for importable module units
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently, Clang requires the file name of an ``importable module unit`` to
have ``.cppm`` (or ``.ccm``, ``.cxxm``, ``.c++m``) as the file extension.
@ -1484,7 +1484,7 @@ How to build projects using header units
.. warning::
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
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
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
once for modules. To address this, ``clang-scan-deps`` will recognize 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``,
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:
1. Point the specified compiler executable to the real binary instead of the

View File

@ -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.
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:
mutex.h

View File

@ -230,8 +230,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
SubstTemplateTypeParmTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
SubstTemplateTypeParmPackTypes;
mutable llvm::FoldingSet<SubstBuiltinTemplatePackType>
SubstBuiltinTemplatePackTypes;
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
TemplateSpecializationTypes;
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
@ -1897,7 +1895,6 @@ public:
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);
QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
QualType
getTemplateTypeParmType(unsigned Depth, unsigned Index,

View File

@ -359,7 +359,7 @@ class CXXFinalOverriderMap
/// A set of all the primary bases for a class.
class CXXIndirectPrimaryBaseSet
: public llvm::SmallPtrSet<const CXXRecordDecl *, 32> {};
: public llvm::SmallSet<const CXXRecordDecl*, 32> {};
inline bool
inheritanceModelHasVBPtrOffsetField(MSInheritanceModel Inheritance) {

View File

@ -3526,7 +3526,7 @@ protected:
public:
// Low-level accessor. If you just want the type defined by this node,
// 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.
const Type *getTypeForDecl() const {
assert(!isa<TagDecl>(this));

View File

@ -1796,10 +1796,7 @@ public:
}
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
bool isPackProducingBuiltinTemplate() const;
};
bool isPackProducingBuiltinTemplateName(TemplateName N);
/// Provides information about an explicit instantiation of a variable or class
/// template.

View File

@ -1250,32 +1250,19 @@ public:
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
: public OpenACCClauseWithVarList,
private llvm::TrailingObjects<OpenACCReductionClause, Expr *,
OpenACCReductionRecipe> {
private llvm::TrailingObjects<OpenACCReductionClause, Expr *> {
friend TrailingObjects;
OpenACCReductionOperator Op;
OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator,
ArrayRef<Expr *> VarList,
ArrayRef<OpenACCReductionRecipe> Recipes,
SourceLocation EndLoc)
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
LParenLoc, EndLoc),
Op(Operator) {
assert(VarList.size() == Recipes.size());
setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
llvm::uninitialized_copy(Recipes, getTrailingObjects<
OpenACCReductionRecipe > ());
setExprs(getTrailingObjects(VarList.size()), VarList);
}
public:
@ -1283,26 +1270,12 @@ public:
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 *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc);
SourceLocation EndLoc);
OpenACCReductionOperator getReductionOp() const { return Op; }
size_t numTrailingObjects(OverloadToken<Expr *>) const {
return getExprs().size();
}
};
class OpenACCLinkClause final

View File

@ -492,8 +492,6 @@ private:
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
bool TraverseSubstPackTypeHelper(SubstPackType *T);
bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL);
bool TraverseRecordHelper(RecordDecl *D);
bool TraverseCXXRecordHelper(CXXRecordDecl *D);
bool TraverseDeclaratorHelper(DeclaratorDecl *D);
@ -1140,10 +1138,9 @@ DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
TRY_TO(TraverseType(T->getReplacementType()));
})
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType,
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType,
{ TRY_TO(TraverseSubstPackTypeHelper(T)); })
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
})
DEF_TRAVERSE_TYPE(AttributedType,
{ TRY_TO(TraverseType(T->getModifiedType())); })
@ -1484,26 +1481,9 @@ DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
})
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper(
SubstPackTypeLoc TL) {
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
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())); })

View File

@ -2210,24 +2210,20 @@ protected:
unsigned PackIndex : 15;
};
class SubstPackTypeBitfields {
friend class SubstPackType;
class SubstTemplateTypeParmPackTypeBitfields {
friend class SubstTemplateTypeParmPackType;
LLVM_PREFERRED_TYPE(TypeBitfields)
unsigned : NumTypeBits;
// The index of the template parameter this substitution represents.
unsigned Index : 16;
/// The number of template arguments in \c Arguments, which is
/// expected to be able to hold at least 1024 according to [implimits].
/// However as this limit is somewhat easy to hit with template
/// metaprogramming we'd prefer to keep it as large as possible.
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 {
@ -2344,7 +2340,7 @@ protected:
VectorTypeBitfields VectorTypeBits;
TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
SubstPackTypeBitfields SubstPackTypeBits;
SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
DependentTemplateSpecializationTypeBitfields
DependentTemplateSpecializationTypeBits;
@ -6405,9 +6401,6 @@ protected:
bool IsInjected, const Type *CanonicalType);
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; }
NestedNameSpecifier getQualifier() const;
@ -6473,9 +6466,6 @@ class RecordType final : public TagType {
using TagType::TagType;
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 {
return reinterpret_cast<RecordDecl *>(TagType::getOriginalDecl());
}
@ -6493,9 +6483,6 @@ class EnumType final : public TagType {
using TagType::TagType;
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 {
return reinterpret_cast<EnumDecl *>(TagType::getOriginalDecl());
}
@ -6528,9 +6515,6 @@ class InjectedClassNameType final : public TagType {
bool IsInjected, const Type *CanonicalType);
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 {
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
/// type parameter pack.
///
@ -7058,7 +6992,7 @@ public:
/// that pack expansion (e.g., when all template parameters have corresponding
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
/// at the current pack substitution index.
class SubstTemplateTypeParmPackType : public SubstPackType {
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
/// 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.
/// This should match the result of `getReplacedParameter()->getIndex()`.
unsigned getIndex() const {
return SubstPackTypeBits.SubstTemplTypeParmPackIndex;
}
unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
// This substitution will be Final, which means the substitution will be fully
// sugared: it doesn't need to be resugared later.
bool getFinal() const;
unsigned getNumArgs() const {
return SubstTemplateTypeParmPackTypeBits.NumArgs;
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
TemplateArgument getArgumentPack() const;
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
unsigned Index, bool Final,
@ -7329,7 +7267,9 @@ public:
TemplateSpecializationTypeBits.NumArgs};
}
bool isSugared() const;
bool isSugared() const {
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
}
QualType desugar() const {
return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();

View File

@ -989,22 +989,12 @@ class SubstTemplateTypeParmTypeLoc :
SubstTemplateTypeParmType> {
};
/// Abstract type representing delayed type pack expansions.
class SubstPackTypeLoc
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc,
SubstPackType> {};
/// Wrapper for substituted template type parameters.
class SubstTemplateTypeParmPackTypeLoc
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
class SubstTemplateTypeParmPackTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
SubstTemplateTypeParmPackTypeLoc,
SubstTemplateTypeParmPackType> {};
/// Wrapper for substituted template type parameters.
class SubstBuiltinTemplatePackTypeLoc
: public InheritingConcreteTypeLoc<SubstPackTypeLoc,
SubstBuiltinTemplatePackTypeLoc,
SubstBuiltinTemplatePackType> {};
SubstTemplateTypeParmPackType> {
};
struct AttributedLocInfo {
const Attr *TypeAttr;

View File

@ -820,12 +820,6 @@ let Class = PackExpansionType in {
}]>;
}
let Class = SubstPackType in {
def : Property<"replacementPack", TemplateArgument> {
let Read = [{ node->getArgumentPack() }];
}
}
let Class = SubstTemplateTypeParmPackType in {
def : Property<"associatedDecl", DeclRef> {
let Read = [{ node->getAssociatedDecl() }];
@ -833,7 +827,12 @@ let Class = SubstTemplateTypeParmPackType in {
def : Property<"Index", UInt32> {
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<[{
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 {
def : Property<"kind", BuiltinTypeKind> {
let Read = [{ node->getKind() }];

View File

@ -5661,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder);
}
/// Matches the condition expression of an if statement, for loop, while loop,
/// do-while loop, switch statement or conditional operator.
/// Matches the condition expression of an if statement, for loop,
/// switch statement or conditional operator.
///
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
/// \code
@ -5739,28 +5739,15 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
return Builder->removeBindings(Predicate);
}
/// Matches a declaration if it declares the same entity as the node previously
/// 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.
/// Matches the condition variable statement in an if statement.
///
/// Given
/// \code
/// if (A* a = GetAPointer()) {}
/// for (; A* a = GetAPointer(); ) {}
/// \endcode
/// hasConditionVariableStatement(...)
/// matches both 'A* a = GetAPointer()'.
AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement,
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
WhileStmt,
SwitchStmt),
/// matches 'A* a = GetAPointer()'.
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
internal::Matcher<DeclStmt>, InnerMatcher) {
const DeclStmt* const DeclarationStatement =
Node.getConditionVariableDeclStmt();

View File

@ -17,7 +17,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
#include <cassert>
@ -153,11 +152,6 @@ public:
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.
/// All other fields cannot change their storage location and always retain
/// the storage location passed to the `RecordStorageLocation` constructor.
@ -170,11 +164,6 @@ public:
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 {
return {Children.begin(), Children.end()};
}

View File

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

View File

@ -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 {
let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">];
let Args = [

View File

@ -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 {
let Category = DocCatFunction;
let Content = [{

View File

@ -62,7 +62,3 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate<
// typename ...Operands>
def __hlsl_spirv_type : HLSLBuiltinTemplate<
[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
// template <class ...Args>
def __builtin_dedup_pack
: CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>;

View File

@ -1232,18 +1232,6 @@ def ConvertVector : Builtin {
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 {
let Spellings = ["__builtin_alloca_uninitialized"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
@ -1510,7 +1498,7 @@ def ElementwiseCopysign : Builtin {
def ElementwiseFma : Builtin {
let Spellings = ["__builtin_elementwise_fma"];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}
@ -1538,18 +1526,6 @@ def ElementwiseFshr : Builtin {
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 {
let Spellings = ["__builtin_reduce_max"];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];

View File

@ -580,8 +580,6 @@ TARGET_BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "",
"isa-v207-instructions")
// 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_packed2national, "V16UcV16Uc", "", "power9-vector")
TARGET_BUILTIN(__builtin_ppc_packed2zoned, "V16UcV16UcUc", "t", "power9-vector")

View File

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

View File

@ -400,9 +400,6 @@ def note_constexpr_non_const_vectorelements : Note<
"cannot determine number of elements for sizeless vectors in a constant expression">;
def note_constexpr_assumption_failed : Note<
"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<
"the experimental clang interpreter failed to evaluate an expression">;

View File

@ -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">,
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<
"-fdelayed-template-parsing is deprecated after C++20">,
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 "
"-fclangir to enable runtime effect">,
InGroup<SourceUsesOpenACC>;
def warn_drv_gcc_install_dir_libstdcxx : Warning<
"future releases of the clang compiler will prefer GCC installations "
"containing libstdc++ include directories; '%0' would be chosen over '%1'">,
InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
}

View File

@ -635,7 +635,6 @@ def ModuleConflict : DiagGroup<"module-conflict">;
def ModuleFileExtension : DiagGroup<"module-file-extension">;
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
def ModuleMap : DiagGroup<"module-map">;
def ModulesDriver : DiagGroup<"modules-driver">;
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
def NewlineEOF : DiagGroup<"newline-eof">;
def Nullability : DiagGroup<"nullability">;
@ -652,7 +651,6 @@ def NonNull : DiagGroup<"nonnull">;
def NonPODVarargs : DiagGroup<"non-pod-varargs">;
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
def : DiagGroup<"nonportable-cfstrings">;
def NonPortableSYCL : DiagGroup<"nonportable-sycl">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">;
def NullPointerArithmetic

View File

@ -49,7 +49,6 @@ enum {
DIAG_SIZE_INSTALLAPI = 100,
};
// Start position for diagnostics.
// clang-format off
enum {
DIAG_START_COMMON = 0,
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
@ -66,7 +65,6 @@ enum {
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
};
// clang-format on
class CustomDiagInfo;
@ -175,8 +173,7 @@ public:
/// Used for handling and querying diagnostic IDs.
///
/// Can be used and shared by multiple Diagnostics for multiple translation
/// units.
/// Can be used and shared by multiple Diagnostics for multiple translation units.
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
/// The level of the diagnostic, after it has been through mapping.

View File

@ -6074,13 +6074,6 @@ def warn_cxx23_pack_indexing : Warning<
def err_pack_outside_template : Error<
"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<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
@ -11001,15 +10994,10 @@ def err_block_on_vm : Error<
def err_sizeless_nonlocal : Error<
"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<
"%select{first two|all}1 arguments to %0 must be vectors">;
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<
"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"
// Second component: integer-like types
"%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
"%plural{0:|: }2"
// 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' "
"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
def err_sycl_entry_point_invalid : Error<
"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">;
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">,
InGroup<NonPortableSYCL>, DefaultError;
InGroup<DiagGroup<"nonportable-sycl">>, DefaultError;
def warn_sycl_entry_point_redundant_declaration : Warning<
"redundant %0 attribute">, InGroup<RedundantAttribute>;
def err_sycl_entry_point_after_definition : Error<
@ -13391,23 +13368,16 @@ def err_acc_reduction_num_gangs_conflict
"appear on a '%2' construct "
"with a '%3' clause%select{ with more than 1 argument|}0">;
def err_acc_reduction_type
: Error<"invalid type %0 used in OpenACC 'reduction' variable reference; "
"type is %enum_select<OACCReductionTy>{%NotScalar{not a scalar "
"value, or array of scalars, or composite of "
"scalars}|%MemberNotScalar{not a scalar value}|%NotAgg{not an "
"aggregate}|%NotComplete{not a complete type}|%NotClassStruct{not "
"a class or struct}}1">;
def note_acc_reduction_array
: Note<"used as element type of "
"%enum_select<OACCReductionArray>{%Section{sub-array"
"}|%Subscript{array}|%ArrayTy{array}}0 type %1">;
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">;
: Error<"OpenACC 'reduction' variable must be of scalar type, aggregate, "
"sub-array, or a composite of scalar types;%select{| sub-array "
"base}1 type is %0">;
def err_acc_reduction_composite_type
: Error<"OpenACC 'reduction' variable must be a composite of scalar types; "
"%1 %select{is not a class or struct|is incomplete|is not an "
"aggregate}0">;
def err_acc_reduction_composite_member_type :Error<
"OpenACC 'reduction' composite variable must not have non-scalar field">;
def note_acc_reduction_composite_member_loc : Note<"invalid field is here">;
def err_acc_loop_not_for_loop
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
def note_acc_construct_here : Note<"'%0' construct is here">;

View File

@ -128,7 +128,6 @@ FEATURE(attribute_overloadable, true)
FEATURE(attribute_unavailable_with_message, true)
FEATURE(attribute_unused_on_fields, true)
FEATURE(attribute_diagnose_if_objc, true)
FEATURE(ext_vector_type_boolean, true)
FEATURE(blocks, LangOpts.Blocks)
FEATURE(c_thread_safety_attributes, true)
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(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics &&
PP.getTargetInfo().getTriple().isOSDarwin())
FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics &&
PP.getTargetInfo().getTriple().isOSDarwin())
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
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_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)
EXTENSION(swiftcc,

View File

@ -97,9 +97,7 @@ def HLSLAttributedResourceType : TypeNode<Type>;
def HLSLInlineSpirvType : TypeNode<Type>;
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
def SubstPackType : TypeNode<Type, 1>;
def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent;
def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def DeducedType : TypeNode<Type, 1>;
def AutoType : TypeNode<DeducedType>;

View File

@ -721,6 +721,8 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
NF = nf,
ManualCodegen = [{
{
SmallVector<llvm::Value*, 6> Operands;
bool NoPassthru =
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
(!IsMasked && (PolicyAttrs & RVV_VTA));
@ -731,18 +733,24 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
else
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
if (NoPassthru)
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
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
if (IsMasked)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
Operands.push_back(Ops[0]);
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::Value *LoadValue = Builder.CreateCall(F, Ops, "");
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
if (ReturnValue.isNull())
return LoadValue;
else
@ -779,24 +787,26 @@ multiclass RVVUnitStridedSegStoreTuple<string op> {
{
// Masked
// Builtin: (mask, ptr, v_tuple, vl)
// Intrinsic: (tuple, ptr, mask, vl, SegInstSEW)
// Intrinsic: (tuple, ptr, mask, vl)
// Unmasked
// 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)
std::swap(Ops[0], Ops[2]);
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[0]->getType(), Operands.back()->getType()};
else
std::swap(Ops[0], Ops[1]);
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
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;
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Operands.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
defvar T = "(Tuple:" # nf # ")";
@ -826,6 +836,8 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
NF = nf,
ManualCodegen = [{
{
SmallVector<llvm::Value*, 6> Operands;
bool NoPassthru =
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
(!IsMasked && (PolicyAttrs & RVV_VTA));
@ -836,21 +848,24 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
else
IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()};
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
if (NoPassthru)
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
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
if (IsMasked)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
Value *NewVL = Ops[2];
Ops.erase(Ops.begin() + 2);
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));
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
clang::CharUnits Align =
CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
@ -859,7 +874,7 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
// Store new_vl
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())
return ReturnTuple;
@ -894,6 +909,8 @@ multiclass RVVStridedSegLoadTuple<string op> {
NF = nf,
ManualCodegen = [{
{
SmallVector<llvm::Value*, 7> Operands;
bool NoPassthru =
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
(!IsMasked && (PolicyAttrs & RVV_VTA));
@ -904,17 +921,24 @@ multiclass RVVStridedSegLoadTuple<string op> {
else
IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
if (NoPassthru)
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
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]); // Stride
if (IsMasked)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
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));
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
if (ReturnValue.isNull())
return LoadValue;
@ -953,23 +977,27 @@ multiclass RVVStridedSegStoreTuple<string op> {
{
// Masked
// Builtin: (mask, ptr, stride, v_tuple, vl)
// Intrinsic: (tuple, ptr, stride, mask, vl, SegInstSEW)
// Intrinsic: (tuple, ptr, stride, mask, vl)
// Unmasked
// 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)
std::swap(Ops[0], Ops[3]);
IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType(), Ops[0]->getType()};
else
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
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;
IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
defvar T = "(Tuple:" # nf # ")";
@ -994,30 +1022,40 @@ multiclass RVVIndexedSegLoadTuple<string op> {
NF = nf,
ManualCodegen = [{
{
SmallVector<llvm::Value*, 7> Operands;
bool NoPassthru =
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
(!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)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
if (NoPassthru)
Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
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()};
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
Ops[Offset + 1]->getType(),
Ops[0]->getType(),
Ops.back()->getType()};
else
IntrinsicTypes = {ResultType, Ops[1]->getType(),
Ops[2]->getType(),
Ops[3]->getType()};
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
Ops[Offset + 1]->getType(),
Ops.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
if (ReturnValue.isNull())
return LoadValue;
@ -1052,25 +1090,30 @@ multiclass RVVIndexedSegStoreTuple<string op> {
{
// Masked
// Builtin: (mask, ptr, index, v_tuple, vl)
// Intrinsic: (tuple, ptr, index, mask, vl, SegInstSEW)
// Intrinsic: (tuple, ptr, index, mask, vl)
// Unmasked
// 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)
std::swap(Ops[0], Ops[3]);
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
Ops[0]->getType(),
Operands.back()->getType()};
else
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
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;
IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
Operands.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
defvar T = "(Tuple:" # nf # ")";
@ -1316,21 +1359,33 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, op1, round_mode, vl)
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
SmallVector<llvm::Value*, 7> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Operands.push_back(Ops[0]); // mask
IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
break;
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 + 1]->getType(), Ops.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
// 12.2. Vector Single-Width Averaging Add and Subtract
@ -1353,22 +1408,34 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, op1, round_mode, vl)
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
SmallVector<llvm::Value*, 7> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
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()};
break;
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
// 12.5. Vector Narrowing Fixed-Point Clip Instructions
@ -1396,6 +1463,7 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, op1, round_mode, vl)
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
SmallVector<llvm::Value*, 7> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
@ -1403,20 +1471,35 @@ let ManualCodegen = [{
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Operands.push_back(Ops[0]); // mask
IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
break;
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 + 1]->getType(),
Operands.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
let HasFRMRoundModeOp = true in {
@ -1457,6 +1540,7 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, op1, round_mode, vl)
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
SmallVector<llvm::Value*, 7> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
@ -1464,21 +1548,35 @@ let ManualCodegen = [{
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
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()};
break;
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
let HasFRMRoundModeOp = true in {
@ -1521,23 +1619,38 @@ let UnMaskedPolicyScheme = HasPolicyOperand in {
let ManualCodegen = [{
{
// LLVM intrinsic
// Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy)
// Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy)
// Unmasked: (passthru, op0, op1, round_mode, vl)
// 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;
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
unsigned Offset = IsMasked ? 2 : 1;
Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
Operands.push_back(Ops[Offset]); // op0
Operands.push_back(Ops[Offset + 1]); // op1
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(),
Ops.back()->getType()};
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
break;
IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
Operands.back()->getType()};
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Operands, "");
}
}] in {
let HasFRMRoundModeOp = 1 in {
@ -1565,23 +1678,38 @@ let ManualCodegen = [{
let ManualCodegen = [{
{
// LLVM intrinsic
// Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy)
// Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy)
// Unmasked: (passthru, op0, op1, round_mode, vl)
// 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;
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
unsigned Offset = IsMasked ? 2 : 1;
Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
Operands.push_back(Ops[Offset]); // op0
Operands.push_back(Ops[Offset + 1]); // op1
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(),
Ops.back()->getType()};
Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
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 {
let HasFRMRoundModeOp = 1 in {
@ -1623,6 +1751,7 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, round_mode, vl)
// Masked: (passthru, op0, mask, frm, vl, policy)
SmallVector<llvm::Value*, 6> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
@ -1630,20 +1759,33 @@ let ManualCodegen = [{
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Operands.push_back(Ops[0]); // mask
IntrinsicTypes = {ResultType, Ops.back()->getType()};
break;
if (HasRoundModeOp) {
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 {
let HasFRMRoundModeOp = 1 in {
@ -1808,6 +1950,7 @@ let ManualCodegen = [{
// LLVM intrinsic
// Unmasked: (passthru, op0, frm, vl)
// Masked: (passthru, op0, mask, frm, vl, policy)
SmallVector<llvm::Value*, 6> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
@ -1815,20 +1958,34 @@ let ManualCodegen = [{
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
(HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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)
Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
Operands.push_back(Ops[0]); // mask
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()};
break;
if (HasRoundModeOp) {
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 {
let HasFRMRoundModeOp = 1 in {
@ -1998,6 +2155,7 @@ let ManualCodegen = [{
// Unmasked: (passthru, op0, op1, round_mode, vl)
// Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
SmallVector<llvm::Value*, 6> Operands;
bool HasMaskedOff = !(
(IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
(!IsMasked && PolicyAttrs & RVV_VTA));
@ -2005,17 +2163,32 @@ let ManualCodegen = [{
(HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
(HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
if (!HasRoundModeOp)
Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm
if (IsMasked)
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
unsigned Offset = IsMasked ?
(HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
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()};
break;
Operands.push_back(Ops[Offset]); // op0
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 {
let HasFRMRoundModeOp = 1 in {

View File

@ -63,11 +63,11 @@ public:
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
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) {
return cir::ConstantOp::create(*this, loc, attr);
return create<cir::ConstantOp>(loc, attr);
}
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
@ -119,7 +119,7 @@ public:
}
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 getTrue(mlir::Location loc) { return getBool(true, loc); }
@ -144,37 +144,21 @@ public:
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
mlir::Value imag) {
auto resultComplexTy = cir::ComplexType::get(real.getType());
return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real,
imag);
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
}
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
return cir::ComplexRealOp::create(*this, loc, operandTy.getElementType(),
operand);
return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
}
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(),
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);
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
}
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);
}
@ -183,7 +167,7 @@ public:
mlir::Location loc,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
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.
@ -191,7 +175,7 @@ public:
mlir::Location loc,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
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.
@ -200,23 +184,22 @@ public:
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)> stepBuilder) {
return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder,
stepBuilder);
return create<cir::ForOp>(loc, condBuilder, bodyBuilder, stepBuilder);
}
/// Create a break operation.
cir::BreakOp createBreak(mlir::Location loc) {
return cir::BreakOp::create(*this, loc);
return create<cir::BreakOp>(loc);
}
/// Create a continue operation.
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 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) {
@ -226,7 +209,7 @@ public:
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
mlir::Type type, llvm::StringRef name,
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.
@ -239,8 +222,8 @@ public:
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {
assert(!cir::MissingFeatures::addressSpace());
return cir::GetGlobalOp::create(
*this, loc, getPointerTo(global.getSymType()), global.getSymName());
return create<cir::GetGlobalOp>(loc, getPointerTo(global.getSymType()),
global.getSymName());
}
mlir::Value createGetGlobal(cir::GlobalOp global) {
@ -248,39 +231,36 @@ public:
}
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
bool isVolatile = false,
mlir::IntegerAttr align = {},
cir::MemOrderAttr order = {}) {
return cir::StoreOp::create(*this, loc, val, dst, align, order);
mlir::IntegerAttr align = {}) {
return create<cir::StoreOp>(loc, val, dst, align);
}
[[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
mlir::Location loc,
mlir::StringRef name,
mlir::Type type, bool isConstant,
mlir::Type type,
cir::GlobalLinkageKind linkage) {
mlir::OpBuilder::InsertionGuard guard(*this);
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,
mlir::Value base, llvm::StringRef name,
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,
clang::CharUnits alignment) {
mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr);
return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false,
alignmentAttr, /*mem_order=*/{});
return create<cir::LoadOp>(loc, addr, /*isDeref=*/false, alignmentAttr);
}
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
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,
mlir::Type returnType, mlir::ValueRange operands,
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);
return op;
}
@ -321,7 +301,7 @@ public:
mlir::Value src, mlir::Type newTy) {
if (newTy == src.getType())
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,
@ -371,7 +351,7 @@ public:
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
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,
@ -393,8 +373,8 @@ public:
mlir::Value trueValue, mlir::Value falseValue) {
assert(trueValue.getType() == falseValue.getType() &&
"trueValue and falseValue should have the same type");
return cir::SelectOp::create(*this, loc, trueValue.getType(), condition,
trueValue, falseValue);
return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue,
falseValue);
}
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,
OverflowBehavior ob = OverflowBehavior::None) {
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Mul,
lhs, rhs);
auto op =
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@ -428,8 +408,8 @@ public:
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
OverflowBehavior ob = OverflowBehavior::Saturated) {
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Sub,
lhs, rhs);
auto op =
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@ -450,8 +430,8 @@ public:
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
OverflowBehavior ob = OverflowBehavior::None) {
auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Add,
lhs, rhs);
auto op =
create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@ -472,7 +452,7 @@ public:
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
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) {
@ -481,8 +461,7 @@ public:
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
bool isShiftLeft) {
return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs,
isShiftLeft);
return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft);
}
mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
@ -560,12 +539,12 @@ public:
/// Create a loop 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.
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
return cir::YieldOp::create(*this, loc, value);
return create<cir::YieldOp>(loc, value);
}
};

View File

@ -50,45 +50,6 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
let isOptional = 1;
}
//===----------------------------------------------------------------------===//
// SourceLanguageAttr
//===----------------------------------------------------------------------===//
// TODO: Add cases for other languages that Clang supports.
def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [
I32EnumAttrCase<"C", 1, "c">,
I32EnumAttrCase<"CXX", 2, "cxx">
]> {
// The enum attr class is defined in `CIR_SourceLanguageAttr` below,
// so that it can define extra class methods.
let genSpecializedAttr = 0;
}
def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> {
let summary = "Module source language";
let description = [{
Represents the source language used to generate the module.
Example:
```
// Module compiled from C.
module attributes {cir.lang = cir.lang<c>} {}
// Module compiled from C++.
module attributes {cir.lang = cir.lang<cxx>} {}
```
Module source language attribute name is `cir.lang` is defined by
`getSourceLanguageAttrName` method in CIRDialect class.
}];
let extraClassDeclaration = [{
bool isC() const { return getValue() == SourceLanguage::C; }
bool isCXX() const { return getValue() == SourceLanguage::CXX; }
}];
}
//===----------------------------------------------------------------------===//
// OptInfoAttr
//===----------------------------------------------------------------------===//
@ -380,44 +341,6 @@ def CIR_ConstVectorAttr : CIR_Attr<"ConstVector", "const_vector", [
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
//===----------------------------------------------------------------------===//
@ -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
//===----------------------------------------------------------------------===//

View File

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

View File

@ -299,20 +299,6 @@ def CIR_ConstantOp : CIR_Op<"const", [
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
//===----------------------------------------------------------------------===//
@ -422,14 +408,13 @@ def CIR_LoadOp : CIR_Op<"load", [
let arguments = (ins Arg<CIR_PointerType, "the address to load from",
[MemRead]>:$addr,
UnitAttr:$isDeref,
OptionalAttr<I64Attr>:$alignment,
OptionalAttr<CIR_MemOrder>:$mem_order);
OptionalAttr<I64Attr>:$alignment
);
let results = (outs CIR_AnyType:$result);
let assemblyFormat = [{
(`deref` $isDeref^)?
(`align` `(` $alignment^ `)`)?
(`atomic` `(` $mem_order^ `)`)?
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
}];
@ -466,12 +451,10 @@ def CIR_StoreOp : CIR_Op<"store", [
let arguments = (ins CIR_AnyType:$value,
Arg<CIR_PointerType, "the address to store the value",
[MemWrite]>:$addr,
OptionalAttr<I64Attr>:$alignment,
OptionalAttr<CIR_MemOrder>:$mem_order);
OptionalAttr<I64Attr>:$alignment);
let assemblyFormat = [{
(`align` `(` $alignment^ `)`)?
(`atomic` `(` $mem_order^ `)`)?
$value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr))
}];
@ -1719,14 +1702,12 @@ def CIR_GlobalOp : CIR_Op<"global", [
CIR_GlobalLinkageKind:$linkage,
OptionalAttr<AnyAttr>:$initial_value,
UnitAttr:$comdat,
UnitAttr:$constant,
UnitAttr:$dso_local,
OptionalAttr<I64Attr>:$alignment);
let assemblyFormat = [{
($sym_visibility^)?
(`` $global_visibility^)?
(`constant` $constant^)?
$linkage
(`comdat` $comdat^)?
(`dso_local` $dso_local^)?
@ -1745,7 +1726,6 @@ def CIR_GlobalOp : CIR_Op<"global", [
let builders = [OpBuilder<(ins
"llvm::StringRef":$sym_name,
"mlir::Type":$sym_type,
CArg<"bool", "false">:$isConstant,
// CIR defaults to external linkage.
CArg<"cir::GlobalLinkageKind",
"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
//===----------------------------------------------------------------------===//
@ -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

View File

@ -113,18 +113,6 @@ LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind 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
#endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H

View File

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

View File

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

View File

@ -49,6 +49,7 @@ struct MissingFeatures {
static bool opLoadEmitScalarRangeCheck() { return false; }
static bool opLoadBooleanRepresentation() { return false; }
static bool opLoadStoreTbaa() { return false; }
static bool opLoadStoreMemOrder() { return false; }
static bool opLoadStoreVolatile() { return false; }
static bool opLoadStoreAtomic() { return false; }
static bool opLoadStoreObjC() { return false; }
@ -94,6 +95,7 @@ struct MissingFeatures {
static bool opCallArgEvaluationOrder() { return false; }
static bool opCallCallConv() { return false; }
static bool opCallMustTail() { return false; }
static bool opCallVirtual() { return false; }
static bool opCallInAlloca() { return false; }
static bool opCallAttrs() { return false; }
static bool opCallSurroundingTry() { return false; }
@ -162,8 +164,6 @@ struct MissingFeatures {
static bool atomicInfoGetAtomicPointer() { return false; }
static bool atomicInfoGetAtomicAddress() { return false; }
static bool atomicUseLibCall() { return false; }
static bool atomicScope() { return false; }
static bool atomicSyncScopeID() { return false; }
// Misc
static bool abiArgInfo() { return false; }
@ -176,12 +176,7 @@ struct MissingFeatures {
static bool aggValueSlotVolatile() { return false; }
static bool alignCXXRecordDecl() { return false; }
static bool armComputeVolatileBitfields() { return false; }
static bool asmGoto() { return false; }
static bool asmInputOperands() { 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 astVarDeclInterface() { return false; }
static bool attributeBuiltin() { return false; }
@ -209,7 +204,6 @@ struct MissingFeatures {
static bool dataLayoutTypeAllocSize() { return false; }
static bool dataLayoutTypeStoreSize() { return false; }
static bool deferredCXXGlobalInit() { return false; }
static bool devirtualizeMemberFunction() { return false; }
static bool ehCleanupFlags() { return false; }
static bool ehCleanupScope() { return false; }
static bool ehCleanupScopeRequiresEHCleanup() { return false; }
@ -221,7 +215,6 @@ struct MissingFeatures {
static bool emitLValueAlignmentAssumption() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool emitTypeCheck() { return false; }
static bool emitTypeMetadataCodeForVCall() { return false; }
static bool fastMathFlags() { return false; }
static bool fpConstraints() { return false; }
static bool generateDebugInfo() { return false; }
@ -264,7 +257,6 @@ struct MissingFeatures {
static bool setNonGC() { return false; }
static bool setObjCGCLValueClass() { return false; }
static bool setTargetAttributes() { return false; }
static bool sourceLanguageCases() { return false; }
static bool stackBase() { return false; }
static bool stackSaveOp() { return false; }
static bool targetCIRGenInfoArch() { return false; }
@ -281,7 +273,6 @@ struct MissingFeatures {
static bool vtableInitialization() { return false; }
static bool vtableRelativeLayout() { return false; }
static bool msvcBuiltins() { return false; }
static bool vaArgABILowering() { return false; }
static bool vlas() { return false; }
// Missing types

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