diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 78a9cb77ff7d90f03179049c069aa9e05af3e66d..033ab804b165eada6c0de4972b102360d75d8525 100755 --- a/.ci/generate-buildkite-pipeline-premerge +++ b/.ci/generate-buildkite-pipeline-premerge @@ -53,6 +53,8 @@ echo "Directories modified:" >&2 echo "$modified_dirs" >&2 function compute-projects-to-test() { + isForWindows=$1 + shift projects=${@} for project in ${projects}; do echo "${project}" @@ -63,12 +65,16 @@ function compute-projects-to-test() { done ;; llvm) - for p in bolt clang clang-tools-extra flang lld lldb mlir polly; do + for p in bolt clang clang-tools-extra lld lldb mlir polly; do echo $p done + # Flang is not stable in Windows CI at the moment + if [[ $isForWindows == 0 ]]; then + echo flang + fi ;; clang) - for p in clang-tools-extra compiler-rt flang lldb cross-project-tests; do + for p in clang-tools-extra compiler-rt lldb cross-project-tests; do echo $p done ;; @@ -76,7 +82,26 @@ function compute-projects-to-test() { echo libc ;; mlir) - echo flang + # Flang is not stable in Windows CI at the moment + if [[ $isForWindows == 0 ]]; then + echo flang + fi + ;; + *) + # Nothing to do + ;; + esac + done +} + +function compute-runtimes-to-test() { + projects=${@} + for project in ${projects}; do + case ${project} in + clang) + for p in libcxx libcxxabi libunwind; do + echo $p + done ;; *) # Nothing to do @@ -178,6 +203,15 @@ function check-targets() { cross-project-tests) echo "check-cross-project" ;; + libcxx) + echo "check-cxx" + ;; + libcxxabi) + echo "check-cxxabi" + ;; + libunwind) + echo "check-unwind" + ;; lldb) echo "check-all" # TODO: check-lldb may not include all the LLDB tests? ;; @@ -207,17 +241,6 @@ if echo "$modified_dirs" | grep -q -E "^(libcxx|libcxxabi|libunwind|runtimes|cma EOF fi -# If clang changed. -if echo "$modified_dirs" | grep -q -E "^(clang)$"; then - cat <` @@ -50,7 +46,7 @@ Save recorded profile to a file -### BOLT generic options +### BOLT generic options: - `--align-text=` @@ -89,15 +85,20 @@ - `--data=` - + data file + +- `--data2=` + + data file - `--debug-skeleton-cu` - Prints out offsets for abbrev and debug_info of Skeleton CUs that get patched. + Prints out offsetrs for abbrev and debu_info of Skeleton CUs that get patched. - `--deterministic-debuginfo` - Disables parallel execution of tasks that may produce nondeterministic debug info + Disables parallel execution of tasks that may produce nondeterministic debug + info - `--dot-tooltip-code` @@ -113,7 +114,7 @@ - `--dump-dot-all` - Dump function CFGs to graphviz format after each stage; enable '-print-loops' + Dump function CFGs to graphviz format after each stage;enable '-print-loops' for color-coded blocks - `--dump-orc` @@ -179,8 +180,8 @@ - `--hot-text` Generate hot text symbols. Apply this option to a precompiled binary that - manually calls into hugify, such that at runtime hugify call will put hot - code into 2M pages. This requires relocation. + manually calls into hugify, such that at runtime hugify call will put hot code + into 2M pages. This requires relocation. - `--hot-text-move-sections=` @@ -227,15 +228,15 @@ - `--profile-format=` Format to dump profile output in aggregation mode, default is fdata - - `=fdata`: offset-based plaintext format - - `=yaml`: dense YAML representation + - `fdata`: offset-based plaintext format + - `yaml`: dense YAML representation - `--r11-availability=` Determine the availability of r11 before indirect branches - - `=never`: r11 not available - - `=always`: r11 available before calls and jumps - - `=abi`r11 available before calls but not before jumps + - `never`: r11 not available + - `always`: r11 available before calls and jumps + - `abi`: r11 available before calls but not before jumps - `--relocs` @@ -283,7 +284,8 @@ - `--trap-avx512` - In relocation mode trap upon entry to any function that uses AVX-512 instructions + In relocation mode trap upon entry to any function that uses AVX-512 + instructions - `--trap-old-code` @@ -311,7 +313,7 @@ Output a single dwarf package file (dwp) instead of multiple non-relocatable dwarf object files (dwo). -### BOLT optimization options +### BOLT optimization options: - `--align-blocks` @@ -357,13 +359,14 @@ - `--cg-use-split-hot-size` - Use hot/cold data on basic blocks to determine hot sizes for call graph functions + Use hot/cold data on basic blocks to determine hot sizes for call graph + functions - `--cold-threshold=` Tenths of percents of main entry frequency to use as a threshold when - evaluating whether a basic block is cold (0 means it is only considered - cold if the block has zero samples). Default: 0 + evaluating whether a basic block is cold (0 means it is only considered cold + if the block has zero samples). Default: 0 - `--elim-link-veneers` @@ -375,8 +378,8 @@ - `--equalize-bb-counts` - Use same count for BBs that should have equivalent count (used in non-LBR - and shrink wrapping) + Use same count for BBs that should have equivalent count (used in non-LBR and + shrink wrapping) - `--execution-count-threshold=` @@ -438,8 +441,8 @@ - `--icp-calls-remaining-percent-threshold=` - The percentage threshold against remaining unpromoted indirect call count - for the promotion for calls + The percentage threshold against remaining unpromoted indirect call count for + the promotion for calls - `--icp-calls-topn` @@ -518,22 +521,18 @@ - `--indirect-call-promotion-jump-tables-topn=` - Limit number of targets to consider when doing indirect call promotion on - jump tables. 0 = no limit - -- `--indirect-call-promotion-mispredict-threshold=` - - Misprediction threshold for skipping ICP on an indirect call + Limit number of targets to consider when doing indirect call promotion on jump + tables. 0 = no limit - `--indirect-call-promotion-topn=` - Limit number of targets to consider when doing indirect call promotion. - 0 = no limit + Limit number of targets to consider when doing indirect call promotion. 0 = no + limit - `--indirect-call-promotion-use-mispredicts` Use misprediction frequency for determining whether or not ICP should be - applied at a callsite. The `-indirect-call-promotion-mispredict-threshold` + applied at a callsite. The -indirect-call-promotion-mispredict-threshold value will be used by this heuristic - `--infer-fall-throughs` @@ -566,11 +565,13 @@ - `--inline-small-functions` - Inline functions if increase in size is less than defined by `-inline-small-functions-bytes` + Inline functions if increase in size is less than defined by -inline-small- + functions-bytes - `--inline-small-functions-bytes=` - Max number of bytes for the function to be considered small for inlining purposes + Max number of bytes for the function to be considered small for inlining + purposes - `--instrument` @@ -590,7 +591,7 @@ Make jump tables size smaller at the cost of using more instructions at jump sites -- `-jump-tables=` +- `--jump-tables=` Jump tables support (default=basic) - `none`: do not optimize functions with jump tables @@ -780,23 +781,22 @@ - `--split-strategy=` Strategy used to partition blocks into fragments - - - `profile2`: split each function into a hot and cold fragment using - profiling information + - `profile2`: split each function into a hot and cold fragment using profiling + information - `cdsplit`: split each function into a hot, warm, and cold fragment using profiling information - `random2`: split each function into a hot and cold fragment at a randomly chosen split point (ignoring any available profiling information) - - `randomN`: split each function into N fragments at randomly chosen split + - `randomN`: split each function into N fragments at a randomly chosen split points (ignoring any available profiling information) - - `all`: split all basic blocks of each function into fragments such that - each fragment contains exactly a single basic block + - `all`: split all basic blocks of each function into fragments such that each + fragment contains exactly a single basic block - `--split-threshold=` Split function only if its main size is reduced by more than given amount of - bytes. Default value: 0, i.e. split iff the size is reduced. Note that on - some architectures the size can increase after splitting. + bytes. Default value: 0, i.e. split iff the size is reduced. Note that on some + architectures the size can increase after splitting. - `--stale-matching-max-func-size=` @@ -817,19 +817,20 @@ - `--tail-duplication=` Duplicate unconditional branches that cross a cache line - - - `none` do not apply - - `aggressive` aggressive strategy - - `moderate` moderate strategy - - `cache` cache-aware duplication strategy + - `none`: do not apply + - `aggressive`: aggressive strategy + - `moderate`: moderate strategy + - `cache`: cache-aware duplication strategy - `--tsp-threshold=` - Maximum number of hot basic blocks in a function for which to use a precise TSP solution while re-ordering basic blocks + Maximum number of hot basic blocks in a function for which to use a precise + TSP solution while re-ordering basic blocks - `--use-aggr-reg-reassign` - Use register liveness analysis to try to find more opportunities for -reg-reassign optimization + Use register liveness analysis to try to find more opportunities for -reg- + reassign optimization - `--use-compact-aligner` @@ -847,21 +848,16 @@ Only apply branch boundary alignment in hot code -- `--x86-strip-redundant-address-size` +### BOLT options in relocation mode: - Remove redundant Address-Size override prefix - -### BOLT options in relocation mode - -- `-align-macro-fusion=` +- `--align-macro-fusion=` Fix instruction alignment for macro-fusion (x86 relocation mode) - - `none`: do not insert alignment no-ops for macro-fusion - `hot`: only insert alignment no-ops on hot execution paths (default) - `all`: always align instructions to allow macro-fusion -### BOLT instrumentation options +### BOLT instrumentation options: `llvm-bolt -instrument [-o outputfile] ` @@ -893,72 +889,21 @@ - `--instrumentation-no-counters-clear` - Don't clear counters across dumps (use with `instrumentation-sleep-time` option) + Don't clear counters across dumps (use with instrumentation-sleep-time option) - `--instrumentation-sleep-time=` Interval between profile writes (default: 0 = write only at program end). This is useful for service workloads when you want to dump profile every X - minutes or if you are killing the program and the profile is not being - dumped at the end. + minutes or if you are killing the program and the profile is not being dumped + at the end. - `--instrumentation-wait-forks` Wait until all forks of instrumented process will finish (use with - `instrumentation-sleep-time` option) - -### Data aggregation options (perf2bolt) - -`perf2bolt -p perf.data [-o outputfile] perf.fdata ` - -- `--autofdo` - - Generate autofdo textual data instead of bolt data - -- `--filter-mem-profile` - - If processing a memory profile, filter out stack or heap accesses that won't - be useful for BOLT to reduce profile file size - -- `--ignore-build-id` - - Continue even if build-ids in input binary and perf.data mismatch - -- `--ignore-interrupt-lbr` - - Ignore kernel interrupt LBR that happens asynchronously - -- `--itrace=` - - Generate LBR info with perf itrace argument + instrumentation-sleep-time option) -- `--nl` - - Aggregate basic samples (without LBR info) - -- `--pa` - - Skip perf and read data from a pre-aggregated file format - -- `--perfdata=` - - Data file - -- `--pid=` - - Only use samples from process with specified PID - -- `--time-aggr` - - Time BOLT aggregator - -- `--use-event-pc` - - Use event PC in combination with LBR sampling - -### BOLT printing options - -#### Generic options +### BOLT printing options: - `--print-aliases` @@ -1032,10 +977,10 @@ - `--print-pseudo-probes=` Print pseudo probe info - - `=decode`: decode probes section from binary - - `=address_conversion`: update address2ProbesMap with output block address - - `=encoded_probes`: display the encoded probes in binary section - - `=all`: enable all debugging printout + - `decode`: decode probes section from binary + - `address_conversion`: update address2ProbesMap with output block address + - `encoded_probes`: display the encoded probes in binary section + - `all`: enable all debugging printout - `--print-relocations` @@ -1061,11 +1006,13 @@ Print names of functions with unknown control flow -- `--time-opts` +- `--time-build` - Print time spent in each optimization + Print time spent constructing binary functions + +- `--time-rewrite` -#### Optimization options + Print time spent in rewriting passes - `--print-after-branch-fixup` @@ -1204,10 +1151,14 @@ Print functions after veneer elimination pass -- `--time-build` +- `--time-opts` - Print time spent constructing binary functions + Print time spent in each optimization -- `--time-rewrite` +- `--print-all-options` - Print time spent in rewriting passes + Print all option values after command line parsing + +- `--print-options` + + Print non-default options after command line parsing \ No newline at end of file diff --git a/bolt/docs/generate_doc.py b/bolt/docs/generate_doc.py new file mode 100644 index 0000000000000000000000000000000000000000..d8829daf677b4ca2014fb77d2631b7ecd4eb01b4 --- /dev/null +++ b/bolt/docs/generate_doc.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# A tool to parse the output of `llvm-bolt --help-hidden` and update the +# documentation in CommandLineArgumentReference.md automatically. +# Run from the directory in which this file is located to update the docs. + +import subprocess +from textwrap import wrap + +LINE_LIMIT = 80 + + +def wrap_text(text, indent, limit=LINE_LIMIT): + wrapped_lines = wrap(text, width=limit - len(indent)) + wrapped_text = ("\n" + indent).join(wrapped_lines) + return wrapped_text + + +def add_info(sections, section, option, description): + indent = " " + wrapped_description = "\n".join( + [ + wrap_text(line, indent) if len(line) > LINE_LIMIT else line + for line in description + ] + ) + sections[section].append((option, indent + wrapped_description)) + + +def parse_bolt_options(output): + section_headers = [ + "Generic options:", + "Output options:", + "BOLT generic options:", + "BOLT optimization options:", + "BOLT options in relocation mode:", + "BOLT instrumentation options:", + "BOLT printing options:", + ] + + sections = {key: [] for key in section_headers} + current_section, prev_section = None, None + option, description = None, [] + + for line in output.split("\n"): + cleaned_line = line.strip() + + if cleaned_line.casefold() in map(str.casefold, section_headers): + if prev_section != None: # Save last option from prev section + add_info(sections, current_section, option, description) + option, description = None, [] + + cleaned_line = cleaned_line.split() + # Apply lowercase to all words except the first one + cleaned_line = [cleaned_line[0]] + [ + word.lower() for word in cleaned_line[1:] + ] + # Join the words back together into a string + cleaned_line = " ".join(cleaned_line) + + current_section = cleaned_line + prev_section = current_section + continue + + if cleaned_line.startswith("-"): + if option and description: + # Join description lines, adding an extra newline for + # sub-options that start with '=' + add_info(sections, current_section, option, description) + option, description = None, [] + + parts = cleaned_line.split(" ", 1) + if len(parts) > 1: + option = parts[0].strip() + descr = parts[1].strip() + descr = descr[2].upper() + descr[3:] + description = [descr] + if option.startswith("--print") or option.startswith("--time"): + current_section = "BOLT printing options:" + elif prev_section != None: + current_section = prev_section + continue + + if cleaned_line.startswith("="): + parts = cleaned_line.split(maxsplit=1) + # Split into two parts: sub-option and description + if len(parts) == 2: + # Rejoin with a single space + cleaned_line = parts[0] + " " + parts[1].rstrip() + description.append(cleaned_line) + elif cleaned_line: # Multiline description continuation + description.append(cleaned_line) + + add_info(sections, current_section, option, description) + return sections + + +def generate_markdown(sections): + markdown_lines = [ + "# BOLT - a post-link optimizer developed to speed up large applications\n", + "## SYNOPSIS\n", + "`llvm-bolt [-o outputfile] .bolt " + "[-data=perf.fdata] [options]`\n", + "## OPTIONS", + ] + + for section, options in sections.items(): + markdown_lines.append(f"\n### {section}") + if section == "BOLT instrumentation options:": + markdown_lines.append( + f"\n`llvm-bolt -instrument" + " [-o outputfile] `" + ) + for option, desc in options: + markdown_lines.append(f"\n- `{option}`\n") + # Split description into lines to handle sub-options + desc_lines = desc.split("\n") + for line in desc_lines: + if line.startswith("="): + # Sub-option: correct formatting with bullet + sub_option, sub_desc = line[1:].split(" ", 1) + markdown_lines.append(f" - `{sub_option}`: {sub_desc[4:]}") + else: + # Regular line of description + if line[2:].startswith("<"): + line = line.replace("<", "").replace(">", "") + markdown_lines.append(f"{line}") + + return "\n".join(markdown_lines) + + +def main(): + try: + help_output = subprocess.run( + ["llvm-bolt", "--help-hidden"], capture_output=True, text=True, check=True + ).stdout + except subprocess.CalledProcessError as e: + print("Failed to execute llvm-bolt --help:") + print(e) + return + + sections = parse_bolt_options(help_output) + markdown = generate_markdown(sections) + + with open("CommandLineArgumentReference.md", "w") as md_file: + md_file.write(markdown) + + +if __name__ == "__main__": + main() diff --git a/bolt/include/bolt/Core/BinaryBasicBlock.h b/bolt/include/bolt/Core/BinaryBasicBlock.h index bc95e2c4de3a11ec2b94e9faf7575ce696856611..a57b70714fe386fbaf2cb09dcf8b409dbb4c5ea9 100644 --- a/bolt/include/bolt/Core/BinaryBasicBlock.h +++ b/bolt/include/bolt/Core/BinaryBasicBlock.h @@ -115,7 +115,7 @@ private: unsigned Index{InvalidIndex}; /// Index in the current layout. - mutable unsigned LayoutIndex{InvalidIndex}; + unsigned LayoutIndex{InvalidIndex}; /// Number of pseudo instructions in this block. uint32_t NumPseudos{0}; @@ -891,7 +891,7 @@ public: } /// Set layout index. To be used by BinaryFunction. - void setLayoutIndex(unsigned Index) const { LayoutIndex = Index; } + void setLayoutIndex(unsigned Index) { LayoutIndex = Index; } /// Needed by graph traits. BinaryFunction *getParent() const { return getFunction(); } diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 75765819ac464eb83bec5d5643d50195ee07a88e..4ec3de3da1bf8b8326010c3d6af07828555e285e 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -17,6 +17,7 @@ #include "bolt/Core/BinaryData.h" #include "bolt/Core/BinarySection.h" #include "bolt/Core/DebugData.h" +#include "bolt/Core/DynoStats.h" #include "bolt/Core/JumpTable.h" #include "bolt/Core/MCPlusBuilder.h" #include "bolt/RuntimeLibs/RuntimeLibrary.h" @@ -359,7 +360,7 @@ public: void setFileBuildID(StringRef ID) { FileBuildID = std::string(ID); } bool hasSymbolsWithFileName() const { return HasSymbolsWithFileName; } - void setHasSymbolsWithFileName(bool Value) { HasSymbolsWithFileName = true; } + void setHasSymbolsWithFileName(bool Value) { HasSymbolsWithFileName = Value; } /// Return true if relocations against symbol with a given name /// must be created. @@ -677,6 +678,9 @@ public: /// have an origin file name available. bool HasSymbolsWithFileName{false}; + /// Does the binary have BAT section. + bool HasBATSection{false}; + /// Sum of execution count of all functions uint64_t SumExecutionCount{0}; @@ -714,6 +718,9 @@ public: uint64_t NumStaleBlocksWithEqualIcount{0}; } Stats; + // Original binary execution count stats. + DynoStats InitialDynoStats; + // Address of the first allocated segment. uint64_t FirstAllocAddress{std::numeric_limits::max()}; @@ -1217,8 +1224,7 @@ public: /// Return a signed value of \p Size stored at \p Address. The address has /// to be a valid statically allocated address for the binary. - ErrorOr getSignedValueAtAddress(uint64_t Address, - size_t Size) const; + ErrorOr getSignedValueAtAddress(uint64_t Address, size_t Size) const; /// Special case of getUnsignedValueAtAddress() that uses a pointer size. ErrorOr getPointerAtAddress(uint64_t Address) const { diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h index 5b7a5b08820e6e5190559ce2ad59992c7a998e2a..d362961176b3262d259110562373eee30316f703 100644 --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -284,6 +284,7 @@ public: return true; } } + bool isNote() const { return isELF() && ELFType == ELF::SHT_NOTE; } bool isReordered() const { return IsReordered; } bool isAnonymous() const { return IsAnonymous; } bool isRelro() const { return IsRelro; } diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h index c5ad0ac18339ab6fd667e27dd5ac95e46c8d625f..c562373c718baf5be05cf7144d311000bf6aecc9 100644 --- a/bolt/include/bolt/Core/DIEBuilder.h +++ b/bolt/include/bolt/Core/DIEBuilder.h @@ -215,10 +215,9 @@ private: /// Along with current CU, and DIE being processed and the new DIE offset to /// be updated, it takes in Parents vector that can be empty if this DIE has /// no parents. - uint32_t - finalizeDIEs(DWARFUnit &CU, DIE &Die, - std::vector> &Parents, - uint32_t &CurOffset); + uint32_t finalizeDIEs(DWARFUnit &CU, DIE &Die, + std::optional Parent, + uint32_t NumberParentsInChain, uint32_t &CurOffset); void registerUnit(DWARFUnit &DU, bool NeedSort); diff --git a/bolt/include/bolt/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h index a4fdde7c396ad886e3d8c96bb92d25a657a4a0e1..a14a30529fad52d9a465f46d1c942f01e22e74eb 100644 --- a/bolt/include/bolt/Core/DebugNames.h +++ b/bolt/include/bolt/Core/DebugNames.h @@ -24,16 +24,17 @@ public: BOLTDWARF5AccelTableData(const uint64_t DieOffset, const std::optional DefiningParentOffset, const unsigned DieTag, const unsigned UnitID, - const bool IsTU, + const bool IsParentRoot, const bool IsTU, const std::optional SecondUnitID) : DWARF5AccelTableData(DieOffset, DefiningParentOffset, DieTag, UnitID, IsTU), - SecondUnitID(SecondUnitID) {} + SecondUnitID(SecondUnitID), IsParentRoot(IsParentRoot) {} uint64_t getDieOffset() const { return DWARF5AccelTableData::getDieOffset(); } unsigned getDieTag() const { return DWARF5AccelTableData::getDieTag(); } unsigned getUnitID() const { return DWARF5AccelTableData::getUnitID(); } bool isTU() const { return DWARF5AccelTableData::isTU(); } + bool isParentRoot() const { return IsParentRoot; } std::optional getSecondUnitID() const { return SecondUnitID; } void setPatchOffset(uint64_t PatchOffset) { OffsetVal = PatchOffset; } @@ -41,6 +42,7 @@ public: private: std::optional SecondUnitID; + bool IsParentRoot; }; class DWARF5AcceleratorTable { @@ -57,6 +59,7 @@ public: std::optional addAccelTableEntry(DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID, + const uint32_t NumberParentsInChain, std::optional &Parent); /// Set current unit being processed. void setCurrentUnit(DWARFUnit &Unit, const uint64_t UnitStartOffset); diff --git a/bolt/include/bolt/Core/FunctionLayout.h b/bolt/include/bolt/Core/FunctionLayout.h index b685a99c79c14cccd0e7661ed8a48991c9a53b98..6a13cbec69fee7f55534d8c1df7de1aeabc45f5d 100644 --- a/bolt/include/bolt/Core/FunctionLayout.h +++ b/bolt/include/bolt/Core/FunctionLayout.h @@ -213,7 +213,8 @@ public: void eraseBasicBlocks(const DenseSet ToErase); /// Make sure fragments' and basic blocks' indices match the current layout. - void updateLayoutIndices(); + void updateLayoutIndices() const; + void updateLayoutIndices(ArrayRef Order) const; /// Replace the current layout with NewLayout. Uses the block's /// self-identifying fragment number to assign blocks to infer function diff --git a/bolt/include/bolt/Passes/BinaryPasses.h b/bolt/include/bolt/Passes/BinaryPasses.h index 5d7692559eda882b125ee5314117eb5fe65932d0..ad8473c4aae02b40fed0e6ac56eae4cc065e65bd 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -16,6 +16,7 @@ #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Core/DynoStats.h" +#include "bolt/Profile/BoltAddressTranslation.h" #include "llvm/Support/CommandLine.h" #include #include @@ -52,15 +53,31 @@ public: virtual Error runOnFunctions(BinaryContext &BC) = 0; }; +/// A pass to set initial program-wide dynostats. +class DynoStatsSetPass : public BinaryFunctionPass { +public: + DynoStatsSetPass() : BinaryFunctionPass(false) {} + + const char *getName() const override { + return "set dyno-stats before optimizations"; + } + + bool shouldPrint(const BinaryFunction &BF) const override { return false; } + + Error runOnFunctions(BinaryContext &BC) override { + BC.InitialDynoStats = getDynoStats(BC.getBinaryFunctions(), BC.isAArch64()); + return Error::success(); + } +}; + /// A pass to print program-wide dynostats. class DynoStatsPrintPass : public BinaryFunctionPass { protected: - DynoStats PrevDynoStats; std::string Title; public: - DynoStatsPrintPass(const DynoStats &PrevDynoStats, const char *Title) - : BinaryFunctionPass(false), PrevDynoStats(PrevDynoStats), Title(Title) {} + DynoStatsPrintPass(const char *Title) + : BinaryFunctionPass(false), Title(Title) {} const char *getName() const override { return "print dyno-stats after optimizations"; @@ -69,6 +86,7 @@ public: bool shouldPrint(const BinaryFunction &BF) const override { return false; } Error runOnFunctions(BinaryContext &BC) override { + const DynoStats PrevDynoStats = BC.InitialDynoStats; const DynoStats NewDynoStats = getDynoStats(BC.getBinaryFunctions(), BC.isAArch64()); const bool Changed = (NewDynoStats != PrevDynoStats); @@ -399,8 +417,11 @@ public: /// Prints a list of the top 100 functions sorted by a set of /// dyno stats categories. class PrintProgramStats : public BinaryFunctionPass { + BoltAddressTranslation *BAT = nullptr; + public: - explicit PrintProgramStats() : BinaryFunctionPass(false) {} + explicit PrintProgramStats(BoltAddressTranslation *BAT = nullptr) + : BinaryFunctionPass(false), BAT(BAT) {} const char *getName() const override { return "print-stats"; } bool shouldPrint(const BinaryFunction &) const override { return false; } diff --git a/bolt/include/bolt/Passes/MCF.h b/bolt/include/bolt/Passes/MCF.h index feac7f88ac11e2c6013efdc0836784710d158bb3..3fe674463bf13622ef21ad34ad4419a3bba9b691 100644 --- a/bolt/include/bolt/Passes/MCF.h +++ b/bolt/include/bolt/Passes/MCF.h @@ -9,20 +9,14 @@ #ifndef BOLT_PASSES_MCF_H #define BOLT_PASSES_MCF_H +#include "bolt/Passes/BinaryPasses.h" +#include "llvm/Support/CommandLine.h" + namespace llvm { namespace bolt { -class BinaryFunction; class DataflowInfoManager; -enum MCFCostFunction : char { - MCF_DISABLE = 0, - MCF_LINEAR, - MCF_QUADRATIC, - MCF_LOG, - MCF_BLAMEFTS -}; - /// Implement the idea in "SamplePGO - The Power of Profile Guided Optimizations /// without the Usability Burden" by Diego Novillo to make basic block counts /// equal if we show that A dominates B, B post-dominates A and they are in the @@ -31,23 +25,18 @@ void equalizeBBCounts(DataflowInfoManager &Info, BinaryFunction &BF); /// Fill edge counts based on the basic block count. Used in nonLBR mode when /// we only have bb count. -void estimateEdgeCounts(BinaryFunction &BF); - -/// Entry point for computing a min-cost flow for the CFG with the goal -/// of fixing the flow of the CFG edges, that is, making sure it obeys the -/// flow-conservation equation SumInEdges = SumOutEdges. -/// -/// To do this, we create an instance of the min-cost flow problem in a -/// similar way as the one discussed in the work of Roy Levin "Completing -/// Incomplete Edge Profile by Applying Minimum Cost Circulation Algorithms". -/// We do a few things differently, though. We don't populate edge counts using -/// weights coming from a static branch prediction technique and we don't -/// use the same cost function. -/// -/// If cost function BlameFTs is used, assign all remaining flow to -/// fall-throughs. This is used when the sampling is based on taken branches -/// that do not account for them. -void solveMCF(BinaryFunction &BF, MCFCostFunction CostFunction); +class EstimateEdgeCounts : public BinaryFunctionPass { + void runOnFunction(BinaryFunction &BF); + +public: + explicit EstimateEdgeCounts(const cl::opt &PrintPass) + : BinaryFunctionPass(PrintPass) {} + + const char *getName() const override { return "estimate-edge-counts"; } + + /// Pass entry point + Error runOnFunctions(BinaryContext &BC) override; +}; } // end namespace bolt } // end namespace llvm diff --git a/bolt/include/bolt/Passes/StokeInfo.h b/bolt/include/bolt/Passes/StokeInfo.h index 76417e6a2c3baa612ff7041142d8bba4933b3f04..a18c2a05d0153eacf04f44f79e1514a5f38ec271 100644 --- a/bolt/include/bolt/Passes/StokeInfo.h +++ b/bolt/include/bolt/Passes/StokeInfo.h @@ -87,10 +87,10 @@ struct StokeFuncInfo { << "," << NumBlocks << "," << IsLoopFree << "," << NumLoops << "," << MaxLoopDepth << "," << HotSize << "," << TotalSize << "," << Score << "," << HasCall << ",\"{ "; - for (std::string S : DefIn) + for (const std::string &S : DefIn) Outfile << "%" << S << " "; Outfile << "}\",\"{ "; - for (std::string S : LiveOut) + for (const std::string &S : LiveOut) Outfile << "%" << S << " "; Outfile << "}\"," << HeapOut << "," << StackOut << "," << HasRipAddr << "," << Omitted << "\n"; diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h index 68b993ee363cc0d0a3bbd59113e4a42c896da4cb..65b9ba874368f392bd409054cf6729d3847fdb60 100644 --- a/bolt/include/bolt/Profile/BoltAddressTranslation.h +++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h @@ -70,7 +70,7 @@ class BinaryFunction; class BoltAddressTranslation { public: // In-memory representation of the address translation table - using MapTy = std::map; + using MapTy = std::multimap; // List of taken fall-throughs using FallthroughListTy = SmallVector, 16>; @@ -90,7 +90,7 @@ public: std::error_code parse(raw_ostream &OS, StringRef Buf); /// Dump the parsed address translation tables - void dump(raw_ostream &OS); + void dump(raw_ostream &OS) const; /// If the maps are loaded in memory, perform the lookup to translate LBR /// addresses in function located at \p FuncAddress. @@ -107,7 +107,12 @@ public: /// If available, fetch the address of the hot part linked to the cold part /// at \p Address. Return 0 otherwise. - uint64_t fetchParentAddress(uint64_t Address) const; + uint64_t fetchParentAddress(uint64_t Address) const { + auto Iter = ColdPartSource.find(Address); + if (Iter == ColdPartSource.end()) + return 0; + return Iter->second; + } /// True if the input binary has a translation table we can use to convert /// addresses when aggregating profile @@ -132,7 +137,8 @@ private: /// emitted for the start of the BB. More entries may be emitted to cover /// the location of calls or any instruction that may change control flow. void writeEntriesForBB(MapTy &Map, const BinaryBasicBlock &BB, - uint64_t FuncInputAddress, uint64_t FuncOutputAddress); + uint64_t FuncInputAddress, + uint64_t FuncOutputAddress) const; /// Write the serialized address translation table for a function. template @@ -147,7 +153,7 @@ private: /// Returns the bitmask with set bits corresponding to indices of BRANCHENTRY /// entries in function address translation map. - APInt calculateBranchEntriesBitMask(MapTy &Map, size_t EqualElems); + APInt calculateBranchEntriesBitMask(MapTy &Map, size_t EqualElems) const; /// Calculate the number of equal offsets (output = input - skew) in the /// beginning of the function. @@ -178,14 +184,9 @@ private: public: /// Map basic block input offset to a basic block index and hash pair. class BBHashMapTy { - class EntryTy { + struct EntryTy { unsigned Index; size_t Hash; - - public: - unsigned getBBIndex() const { return Index; } - size_t getBBHash() const { return Hash; } - EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {} }; std::map Map; @@ -201,15 +202,15 @@ public: } unsigned getBBIndex(uint32_t BBInputOffset) const { - return getEntry(BBInputOffset).getBBIndex(); + return getEntry(BBInputOffset).Index; } size_t getBBHash(uint32_t BBInputOffset) const { - return getEntry(BBInputOffset).getBBHash(); + return getEntry(BBInputOffset).Hash; } void addEntry(uint32_t BBInputOffset, unsigned BBIndex, size_t BBHash) { - Map.emplace(BBInputOffset, EntryTy(BBIndex, BBHash)); + Map.emplace(BBInputOffset, EntryTy{BBIndex, BBHash}); } size_t getNumBasicBlocks() const { return Map.size(); } @@ -217,18 +218,14 @@ public: auto begin() const { return Map.begin(); } auto end() const { return Map.end(); } auto upper_bound(uint32_t Offset) const { return Map.upper_bound(Offset); } + auto size() const { return Map.size(); } }; /// Map function output address to its hash and basic blocks hash map. class FuncHashesTy { - class EntryTy { + struct EntryTy { size_t Hash; BBHashMapTy BBHashMap; - - public: - size_t getBFHash() const { return Hash; } - const BBHashMapTy &getBBHashMap() const { return BBHashMap; } - EntryTy(size_t Hash) : Hash(Hash) {} }; std::unordered_map Map; @@ -240,15 +237,15 @@ public: public: size_t getBFHash(uint64_t FuncOutputAddress) const { - return getEntry(FuncOutputAddress).getBFHash(); + return getEntry(FuncOutputAddress).Hash; } const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const { - return getEntry(FuncOutputAddress).getBBHashMap(); + return getEntry(FuncOutputAddress).BBHashMap; } void addEntry(uint64_t FuncOutputAddress, size_t BFHash) { - Map.emplace(FuncOutputAddress, EntryTy(BFHash)); + Map.emplace(FuncOutputAddress, EntryTy{BFHash, BBHashMapTy()}); } size_t getNumFunctions() const { return Map.size(); }; @@ -256,7 +253,7 @@ public: size_t getNumBasicBlocks() const { size_t NumBasicBlocks{0}; for (auto &I : Map) - NumBasicBlocks += I.second.getBBHashMap().getNumBasicBlocks(); + NumBasicBlocks += I.second.BBHashMap.getNumBasicBlocks(); return NumBasicBlocks; } }; @@ -278,7 +275,9 @@ public: /// Returns the number of basic blocks in a function. size_t getNumBasicBlocks(uint64_t OutputAddress) const { - return NumBasicBlocksMap.at(OutputAddress); + auto It = NumBasicBlocksMap.find(OutputAddress); + assert(It != NumBasicBlocksMap.end()); + return It->second; } private: diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index c158a9bb3e3f253f5d0e60f4f22c8bb53c42b12b..6453b3070ceb8d23983e09c77c3ef3f5e29764be 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -15,6 +15,7 @@ #define BOLT_PROFILE_DATA_AGGREGATOR_H #include "bolt/Profile/DataReader.h" +#include "bolt/Profile/YAMLProfileWriter.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/Program.h" @@ -248,7 +249,7 @@ private: BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const; /// Retrieve the location name to be used for samples recorded in \p Func. - StringRef getLocationName(const BinaryFunction &Func) const; + static StringRef getLocationName(const BinaryFunction &Func, bool BAT); /// Semantic actions - parser hooks to interpret parsed perf samples /// Register a sample (non-LBR mode), i.e. a new hit at \p Address @@ -490,6 +491,8 @@ public: /// Parse the output generated by "perf buildid-list" to extract build-ids /// and return a file name matching a given \p FileBuildID. std::optional getFileNameForBuildID(StringRef FileBuildID); + + friend class YAMLProfileWriter; }; } // namespace bolt } // namespace llvm diff --git a/bolt/include/bolt/Rewrite/MetadataManager.h b/bolt/include/bolt/Rewrite/MetadataManager.h index 2ff70dbaab3de74d6af6ec14cf89cc84d29c69b4..6001b70f625e2eacb29444e9b1e32ef3e92e0068 100644 --- a/bolt/include/bolt/Rewrite/MetadataManager.h +++ b/bolt/include/bolt/Rewrite/MetadataManager.h @@ -28,6 +28,9 @@ public: /// Register a new \p Rewriter. void registerRewriter(std::unique_ptr Rewriter); + /// Run initializers after sections are discovered. + void runSectionInitializers(); + /// Execute initialization of rewriters while functions are disassembled, but /// CFG is not yet built. void runInitializersPreCFG(); diff --git a/bolt/include/bolt/Rewrite/MetadataRewriter.h b/bolt/include/bolt/Rewrite/MetadataRewriter.h index 1e7e0381c1e98c2b242ed02646bba3525e73bcad..6ff8f0af7a8e67e19ff7769f76de10f531979f3e 100644 --- a/bolt/include/bolt/Rewrite/MetadataRewriter.h +++ b/bolt/include/bolt/Rewrite/MetadataRewriter.h @@ -45,6 +45,10 @@ public: /// Return name for the rewriter. StringRef getName() const { return Name; } + /// Run initialization after the binary is read and sections are identified, + /// but before functions are discovered. + virtual Error sectionInitializer() { return Error::success(); } + /// Interface for modifying/annotating functions in the binary based on the /// contents of the section. Functions are in pre-cfg state. virtual Error preCFGInitializer() { return Error::success(); } diff --git a/bolt/include/bolt/Rewrite/MetadataRewriters.h b/bolt/include/bolt/Rewrite/MetadataRewriters.h index 852323188650395435d841cc9c608c0c5f257605..b71bd6cad2505272634f58db66606fbcec7dea96 100644 --- a/bolt/include/bolt/Rewrite/MetadataRewriters.h +++ b/bolt/include/bolt/Rewrite/MetadataRewriters.h @@ -21,6 +21,8 @@ class BinaryContext; std::unique_ptr createLinuxKernelRewriter(BinaryContext &); +std::unique_ptr createBuildIDRewriter(BinaryContext &); + std::unique_ptr createPseudoProbeRewriter(BinaryContext &); std::unique_ptr createSDTRewriter(BinaryContext &); diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 64113bd026012e8a66c29c0442039348baf71385..af1d9b4b70a3db5b21712f76e94875ffbaef6856 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -21,6 +21,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Regex.h" #include #include #include @@ -78,15 +79,6 @@ public: return InputFile->getFileName(); } - /// Set the build-id string if we did not fail to parse the contents of the - /// ELF note section containing build-id information. - void parseBuildID(); - - /// The build-id is typically a stream of 20 bytes. Return these bytes in - /// printable hexadecimal form if they are available, or std::nullopt - /// otherwise. - std::optional getPrintableBuildID() const; - /// If this instance uses a profile, return appropriate profile reader. const ProfileReaderBase *getProfileReader() const { return ProfileReader.get(); @@ -183,6 +175,9 @@ private: /// Link additional runtime code to support instrumentation. void linkRuntime(); + /// Process metadata in sections before functions are discovered. + void processSectionMetadata(); + /// Process metadata in special sections before CFG is built for functions. void processMetadataPreCFG(); @@ -367,11 +362,6 @@ private: /// Loop over now emitted functions to write translation maps void encodeBATSection(); - /// Update the ELF note section containing the binary build-id to reflect - /// a new build-id, so tools can differentiate between the old and the - /// rewritten binary. - void patchBuildID(); - /// Return file offset corresponding to a virtual \p Address. /// Return 0 if the address has no mapping in the file, including being /// part of .bss section. @@ -561,18 +551,12 @@ private: /// Exception handling and stack unwinding information in this binary. ErrorOr EHFrameSection{std::errc::bad_address}; - /// .note.gnu.build-id section. - ErrorOr BuildIDSection{std::errc::bad_address}; - /// Helper for accessing sections by name. BinarySection *getSection(const Twine &Name) { ErrorOr ErrOrSection = BC->getUniqueSectionByName(Name); return ErrOrSection ? &ErrOrSection.get() : nullptr; } - /// A reference to the build-id bytes in the original binary - StringRef BuildID; - /// Keep track of functions we fail to write in the binary. We need to avoid /// rewriting CFI info for these functions. std::vector FailedAddresses; @@ -596,6 +580,9 @@ private: NameResolver NR; + // Regex object matching split function names. + const Regex FunctionFragmentTemplate{"(.*)\\.(cold|warm)(\\.[0-9]+)?"}; + friend class RewriteInstanceDiff; }; diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index ad2eb18caf109b0c987b1e568404649142599c9c..db02dc0fae4ee24c2d3ed1361e052bbb6bcb4efe 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -142,7 +142,7 @@ BinaryContext::BinaryContext(std::unique_ptr Ctx, AsmInfo(std::move(AsmInfo)), MII(std::move(MII)), STI(std::move(STI)), InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)), - Logger(Logger) { + Logger(Logger), InitialDynoStats(isAArch64()) { Relocation::Arch = this->TheTriple->getArch(); RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86; PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize; @@ -934,10 +934,13 @@ std::string BinaryContext::generateJumpTableName(const BinaryFunction &BF, uint64_t Offset = 0; if (const JumpTable *JT = BF.getJumpTableContainingAddress(Address)) { Offset = Address - JT->getAddress(); - auto Itr = JT->Labels.find(Offset); - if (Itr != JT->Labels.end()) - return std::string(Itr->second->getName()); - Id = JumpTableIds.at(JT->getAddress()); + auto JTLabelsIt = JT->Labels.find(Offset); + if (JTLabelsIt != JT->Labels.end()) + return std::string(JTLabelsIt->second->getName()); + + auto JTIdsIt = JumpTableIds.find(JT->getAddress()); + assert(JTIdsIt != JumpTableIds.end()); + Id = JTIdsIt->second; } else { Id = JumpTableIds[Address] = BF.JumpTables.size(); } @@ -1322,7 +1325,9 @@ void BinaryContext::processInterproceduralReferences() { InterproceduralReferences) { BinaryFunction &Function = *It.first; uint64_t Address = It.second; - if (!Address || Function.isIgnored()) + // Process interprocedural references from ignored functions in BAT mode + // (non-simple in non-relocation mode) to properly register entry points + if (!Address || (Function.isIgnored() && !HasBATSection)) continue; BinaryFunction *TargetFunction = @@ -2212,8 +2217,8 @@ ErrorOr BinaryContext::getUnsignedValueAtAddress(uint64_t Address, return DE.getUnsigned(&ValueOffset, Size); } -ErrorOr BinaryContext::getSignedValueAtAddress(uint64_t Address, - size_t Size) const { +ErrorOr BinaryContext::getSignedValueAtAddress(uint64_t Address, + size_t Size) const { const ErrorOr Section = getSectionForAddress(Address); if (!Section) return std::make_error_code(std::errc::bad_address); diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp index 6f86ddc774544a6e7a65d098b0c22e2962cbf2fd..0b44acb0816f2fab0c627ae7e451a7782732de53 100644 --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -813,7 +813,9 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection, // determining its destination. std::map LabelCounts; if (opts::JumpTables > JTS_SPLIT && !JT.Counts.empty()) { - MCSymbol *CurrentLabel = JT.Labels.at(0); + auto It = JT.Labels.find(0); + assert(It != JT.Labels.end()); + MCSymbol *CurrentLabel = It->second; uint64_t CurrentLabelCount = 0; for (unsigned Index = 0; Index < JT.Entries.size(); ++Index) { auto LI = JT.Labels.find(Index * JT.EntrySize); diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 10b93e702984fb180f8d38e652b07340cc5a2846..d13e28999a05ca61dc3aec0cdd891dedec641734 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -851,15 +851,19 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, return IndirectBranchType::UNKNOWN; } - // RIP-relative addressing should be converted to symbol form by now - // in processed instructions (but not in jump). - if (DispExpr) { + auto getExprValue = [&](const MCExpr *Expr) { const MCSymbol *TargetSym; uint64_t TargetOffset; - std::tie(TargetSym, TargetOffset) = BC.MIB->getTargetSymbolInfo(DispExpr); + std::tie(TargetSym, TargetOffset) = BC.MIB->getTargetSymbolInfo(Expr); ErrorOr SymValueOrError = BC.getSymbolValue(*TargetSym); - assert(SymValueOrError && "global symbol needs a value"); - ArrayStart = *SymValueOrError + TargetOffset; + assert(SymValueOrError && "Global symbol needs a value"); + return *SymValueOrError + TargetOffset; + }; + + // RIP-relative addressing should be converted to symbol form by now + // in processed instructions (but not in jump). + if (DispExpr) { + ArrayStart = getExprValue(DispExpr); BaseRegNum = BC.MIB->getNoRegister(); if (BC.isAArch64()) { ArrayStart &= ~0xFFFULL; @@ -1666,7 +1670,8 @@ void BinaryFunction::postProcessEntryPoints() { // In non-relocation mode there's potentially an external undetectable // reference to the entry point and hence we cannot move this entry // point. Optimizing without moving could be difficult. - if (!BC.HasRelocations) + // In BAT mode, register any known entry points for CFG construction. + if (!BC.HasRelocations && !BC.HasBATSection) setSimple(false); const uint32_t Offset = KV.first; @@ -3636,8 +3641,8 @@ bool BinaryFunction::forEachEntryPoint(EntryPointCallbackTy Callback) const { BinaryFunction::BasicBlockListType BinaryFunction::dfs() const { BasicBlockListType DFS; - unsigned Index = 0; std::stack Stack; + std::set Visited; // Push entry points to the stack in reverse order. // @@ -3654,17 +3659,13 @@ BinaryFunction::BasicBlockListType BinaryFunction::dfs() const { for (BinaryBasicBlock *const BB : reverse(EntryPoints)) Stack.push(BB); - for (BinaryBasicBlock &BB : blocks()) - BB.setLayoutIndex(BinaryBasicBlock::InvalidIndex); - while (!Stack.empty()) { BinaryBasicBlock *BB = Stack.top(); Stack.pop(); - if (BB->getLayoutIndex() != BinaryBasicBlock::InvalidIndex) + if (Visited.find(BB) != Visited.end()) continue; - - BB->setLayoutIndex(Index++); + Visited.insert(BB); DFS.push_back(BB); for (BinaryBasicBlock *SuccBB : BB->landing_pads()) { @@ -3697,6 +3698,13 @@ BinaryFunction::BasicBlockListType BinaryFunction::dfs() const { size_t BinaryFunction::computeHash(bool UseDFS, HashFunction HashFunction, OperandHashFuncTy OperandHashFunc) const { + LLVM_DEBUG({ + dbgs() << "BOLT-DEBUG: computeHash " << getPrintName() << ' ' + << (UseDFS ? "dfs" : "bin") << " order " + << (HashFunction == HashFunction::StdHash ? "std::hash" : "xxh3") + << '\n'; + }); + if (size() == 0) return 0; diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index 34c455a36cce4c98fa302d27a3071d5a3bfa09ff..6633eaa9574216bc266acd2b18622b2ed29a0ed0 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -461,32 +461,42 @@ getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx, return nullptr; } -uint32_t DIEBuilder::finalizeDIEs( - DWARFUnit &CU, DIE &Die, - std::vector> &Parents, - uint32_t &CurOffset) { +uint32_t +DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die, + std::optional Parent, + uint32_t NumberParentsInChain, uint32_t &CurOffset) { getState().DWARFDieAddressesParsed.erase(Die.getOffset()); uint32_t CurSize = 0; Die.setOffset(CurOffset); std::optional NameEntry = DebugNamesTable.addAccelTableEntry( CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt, - Parents.back()); + NumberParentsInChain, Parent); // It is possible that an indexed debugging information entry has a parent // that is not indexed (for example, if its parent does not have a name // attribute). In such a case, a parent attribute may point to a nameless // index entry (that is, one that cannot be reached from any entry in the name // table), or it may point to the nearest ancestor that does have an index // entry. + // Skipping entry is not very useful for LLDB. This follows clang where + // children of forward declaration won't have DW_IDX_parent. + // https://github.com/llvm/llvm-project/pull/91808 + + // If Parent is nullopt and NumberParentsInChain is not zero, then forward + // declaration was encountered in this DF traversal. Propagating nullopt for + // Parent to children. + if (!Parent && NumberParentsInChain) + NameEntry = std::nullopt; if (NameEntry) - Parents.push_back(std::move(NameEntry)); + ++NumberParentsInChain; for (DIEValue &Val : Die.values()) CurSize += Val.sizeOf(CU.getFormParams()); CurSize += getULEB128Size(Die.getAbbrevNumber()); CurOffset += CurSize; for (DIE &Child : Die.children()) { - uint32_t ChildSize = finalizeDIEs(CU, Child, Parents, CurOffset); + uint32_t ChildSize = + finalizeDIEs(CU, Child, NameEntry, NumberParentsInChain, CurOffset); CurSize += ChildSize; } // for children end mark. @@ -496,9 +506,6 @@ uint32_t DIEBuilder::finalizeDIEs( } Die.setSize(CurSize); - if (NameEntry) - Parents.pop_back(); - return CurSize; } @@ -510,7 +517,7 @@ void DIEBuilder::finish() { DebugNamesTable.setCurrentUnit(CU, UnitStartOffset); std::vector> Parents; Parents.push_back(std::nullopt); - finalizeDIEs(CU, *UnitDIE, Parents, CurOffset); + finalizeDIEs(CU, *UnitDIE, std::nullopt, 0, CurOffset); DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU); CurUnitInfo.UnitOffset = UnitStartOffset; diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp index 049244c4b51518a88cd9d8af1b5d64c24010d705..ebe895e019ccb4c0ad11963e65a60cc06c9217e2 100644 --- a/bolt/lib/Core/DebugNames.cpp +++ b/bolt/lib/Core/DebugNames.cpp @@ -112,8 +112,6 @@ void DWARF5AcceleratorTable::addUnit(DWARFUnit &Unit, // Returns true if DW_TAG_variable should be included in .debug-names based on // section 6.1.1.1 for DWARF5 spec. static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) { - if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration)) - return false; const DIEValue LocAttrInfo = Die.findAttribute(dwarf::Attribute::DW_AT_location); if (!LocAttrInfo) @@ -148,6 +146,8 @@ static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) { bool static canProcess(const DWARFUnit &Unit, const DIE &Die, std::string &NameToUse, const bool TagsOnly) { + if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration)) + return false; switch (Die.getTag()) { case dwarf::DW_TAG_base_type: case dwarf::DW_TAG_class_type: @@ -220,6 +220,7 @@ static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) { std::optional DWARF5AcceleratorTable::addAccelTableEntry( DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID, + const uint32_t NumberParentsInChain, std::optional &Parent) { if (Unit.getVersion() < 5 || !NeedToCreate) return std::nullopt; @@ -312,8 +313,14 @@ DWARF5AcceleratorTable::addAccelTableEntry( // Keeping memory footprint down. if (ParentOffset) EntryRelativeOffsets.insert({*ParentOffset, 0}); + bool IsParentRoot = false; + // If there is no parent and no valid Entries in parent chain this is a root + // to be marked with a flag. + if (!Parent && !NumberParentsInChain) + IsParentRoot = true; It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData( - Die.getOffset(), ParentOffset, DieTag, UnitID, IsTU, SecondIndex)); + Die.getOffset(), ParentOffset, DieTag, UnitID, IsParentRoot, IsTU, + SecondIndex)); return It.Values.back(); }; @@ -462,7 +469,7 @@ void DWARF5AcceleratorTable::populateAbbrevsMap() { Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); if (std::optional Offset = Value->getParentDieOffset()) Abbrev.addAttribute({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4}); - else + else if (Value->isParentRoot()) Abbrev.addAttribute( {dwarf::DW_IDX_parent, dwarf::DW_FORM_flag_present}); FoldingSetNodeID ID; diff --git a/bolt/lib/Core/DynoStats.cpp b/bolt/lib/Core/DynoStats.cpp index 5de0f9e0d6b8cd2f0f1f855ac5a8663e202482cf..1d9818777596e49b9ed6c543b08824cd45a5fd54 100644 --- a/bolt/lib/Core/DynoStats.cpp +++ b/bolt/lib/Core/DynoStats.cpp @@ -114,8 +114,9 @@ void DynoStats::print(raw_ostream &OS, const DynoStats *Other, for (auto &Stat : llvm::reverse(SortedHistogram)) { OS << format("%20s,%'18lld", Printer->getOpcodeName(Stat.second).data(), Stat.first * opts::DynoStatsScale); - - MaxOpcodeHistogramTy MaxMultiMap = OpcodeHistogram.at(Stat.second).second; + auto It = OpcodeHistogram.find(Stat.second); + assert(It != OpcodeHistogram.end()); + MaxOpcodeHistogramTy MaxMultiMap = It->second.second; // Start with function name:BB offset with highest execution count. for (auto &Max : llvm::reverse(MaxMultiMap)) { OS << format(", %'18lld, ", Max.first * opts::DynoStatsScale) diff --git a/bolt/lib/Core/FunctionLayout.cpp b/bolt/lib/Core/FunctionLayout.cpp index 73f4d5247d9ac06092601f1e931055223b83c00d..15e6127ad2e9e82878a0393853ea5fb7329340b5 100644 --- a/bolt/lib/Core/FunctionLayout.cpp +++ b/bolt/lib/Core/FunctionLayout.cpp @@ -164,15 +164,20 @@ void FunctionLayout::eraseBasicBlocks( updateLayoutIndices(); } -void FunctionLayout::updateLayoutIndices() { +void FunctionLayout::updateLayoutIndices() const { unsigned BlockIndex = 0; - for (FunctionFragment &FF : fragments()) { + for (const FunctionFragment &FF : fragments()) { for (BinaryBasicBlock *const BB : FF) { BB->setLayoutIndex(BlockIndex++); BB->setFragmentNum(FF.getFragmentNum()); } } } +void FunctionLayout::updateLayoutIndices( + ArrayRef Order) const { + for (auto [Index, BB] : llvm::enumerate(Order)) + BB->setLayoutIndex(Index); +} bool FunctionLayout::update(const ArrayRef NewLayout) { const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout); diff --git a/bolt/lib/Passes/BinaryFunctionCallGraph.cpp b/bolt/lib/Passes/BinaryFunctionCallGraph.cpp index 2373710c9edd629619a08f0acb9cd0bde53a3655..bbcc9751c0cbe61f583a6fc4e5d7b26d46b74457 100644 --- a/bolt/lib/Passes/BinaryFunctionCallGraph.cpp +++ b/bolt/lib/Passes/BinaryFunctionCallGraph.cpp @@ -56,7 +56,9 @@ std::deque BinaryFunctionCallGraph::buildTraversalOrder() { std::stack Worklist; for (BinaryFunction *Func : Funcs) { - const NodeId Id = FuncToNodeId.at(Func); + auto It = FuncToNodeId.find(Func); + assert(It != FuncToNodeId.end()); + const NodeId Id = It->second; Worklist.push(Id); NodeStatus[Id] = NEW; } diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp index 298ba29ff5b3ff0404a9815f2a17cf95efa23ffc..2810f723719d0efcfed93d5a29754092ec12cfd4 100644 --- a/bolt/lib/Passes/BinaryPasses.cpp +++ b/bolt/lib/Passes/BinaryPasses.cpp @@ -1390,9 +1390,19 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { if (Function.isPLTFunction()) continue; + // Adjustment for BAT mode: the profile for BOLT split fragments is combined + // so only count the hot fragment. + const uint64_t Address = Function.getAddress(); + bool IsHotParentOfBOLTSplitFunction = !Function.getFragments().empty() && + BAT && BAT->isBATFunction(Address) && + !BAT->fetchParentAddress(Address); + ++NumRegularFunctions; - if (!Function.isSimple()) { + // In BOLTed binaries split functions are non-simple (due to non-relocation + // mode), but the original function is known to be simple and we have a + // valid profile for it. + if (!Function.isSimple() && !IsHotParentOfBOLTSplitFunction) { if (Function.hasProfile()) ++NumNonSimpleProfiledFunctions; continue; @@ -1553,23 +1563,28 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { const bool Ascending = opts::DynoStatsSortOrderOpt == opts::DynoStatsSortOrder::Ascending; - if (SortAll) { - llvm::stable_sort(Functions, - [Ascending, &Stats](const BinaryFunction *A, - const BinaryFunction *B) { - return Ascending ? Stats.at(A) < Stats.at(B) - : Stats.at(B) < Stats.at(A); - }); - } else { - llvm::stable_sort( - Functions, [Ascending, &Stats](const BinaryFunction *A, - const BinaryFunction *B) { - const DynoStats &StatsA = Stats.at(A); - const DynoStats &StatsB = Stats.at(B); - return Ascending ? StatsA.lessThan(StatsB, opts::PrintSortedBy) - : StatsB.lessThan(StatsA, opts::PrintSortedBy); - }); - } + std::function + DynoStatsComparator = + SortAll ? [](const DynoStats &StatsA, + const DynoStats &StatsB) { return StatsA < StatsB; } + : [](const DynoStats &StatsA, const DynoStats &StatsB) { + return StatsA.lessThan(StatsB, opts::PrintSortedBy); + }; + + llvm::stable_sort(Functions, + [Ascending, &Stats, DynoStatsComparator]( + const BinaryFunction *A, const BinaryFunction *B) { + auto StatsItr = Stats.find(A); + assert(StatsItr != Stats.end()); + const DynoStats &StatsA = StatsItr->second; + + StatsItr = Stats.find(B); + assert(StatsItr != Stats.end()); + const DynoStats &StatsB = StatsItr->second; + + return Ascending ? DynoStatsComparator(StatsA, StatsB) + : DynoStatsComparator(StatsB, StatsA); + }); BC.outs() << "BOLT-INFO: top functions sorted by "; if (SortAll) { diff --git a/bolt/lib/Passes/CacheMetrics.cpp b/bolt/lib/Passes/CacheMetrics.cpp index b02d4303110b37392ff1115254827b194a8b18fd..21b420a5c2b018ba23e314677a45a3b7b793f638 100644 --- a/bolt/lib/Passes/CacheMetrics.cpp +++ b/bolt/lib/Passes/CacheMetrics.cpp @@ -67,7 +67,20 @@ calcTSPScore(const std::vector &BinaryFunctions, for (BinaryBasicBlock *DstBB : SrcBB->successors()) { if (SrcBB != DstBB && BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) { JumpCount += BI->Count; - if (BBAddr.at(SrcBB) + BBSize.at(SrcBB) == BBAddr.at(DstBB)) + + auto BBAddrIt = BBAddr.find(SrcBB); + assert(BBAddrIt != BBAddr.end()); + uint64_t SrcBBAddr = BBAddrIt->second; + + auto BBSizeIt = BBSize.find(SrcBB); + assert(BBSizeIt != BBSize.end()); + uint64_t SrcBBSize = BBSizeIt->second; + + BBAddrIt = BBAddr.find(DstBB); + assert(BBAddrIt != BBAddr.end()); + uint64_t DstBBAddr = BBAddrIt->second; + + if (SrcBBAddr + SrcBBSize == DstBBAddr) Score += BI->Count; } ++BI; @@ -149,20 +162,28 @@ double expectedCacheHitRatio( for (BinaryFunction *BF : BinaryFunctions) { if (BF->getLayout().block_empty()) continue; - const uint64_t Page = - BBAddr.at(BF->getLayout().block_front()) / ITLBPageSize; - PageSamples[Page] += FunctionSamples.at(BF); + auto BBAddrIt = BBAddr.find(BF->getLayout().block_front()); + assert(BBAddrIt != BBAddr.end()); + const uint64_t Page = BBAddrIt->second / ITLBPageSize; + + auto FunctionSamplesIt = FunctionSamples.find(BF); + assert(FunctionSamplesIt != FunctionSamples.end()); + PageSamples[Page] += FunctionSamplesIt->second; } // Computing the expected number of misses for every function double Misses = 0; for (BinaryFunction *BF : BinaryFunctions) { // Skip the function if it has no samples - if (BF->getLayout().block_empty() || FunctionSamples.at(BF) == 0.0) + auto FunctionSamplesIt = FunctionSamples.find(BF); + assert(FunctionSamplesIt != FunctionSamples.end()); + double Samples = FunctionSamplesIt->second; + if (BF->getLayout().block_empty() || Samples == 0.0) continue; - double Samples = FunctionSamples.at(BF); - const uint64_t Page = - BBAddr.at(BF->getLayout().block_front()) / ITLBPageSize; + + auto BBAddrIt = BBAddr.find(BF->getLayout().block_front()); + assert(BBAddrIt != BBAddr.end()); + const uint64_t Page = BBAddrIt->second / ITLBPageSize; // The probability that the page is not present in the cache const double MissProb = pow(1.0 - PageSamples[Page] / TotalSamples, ITLBEntries); @@ -170,8 +191,10 @@ double expectedCacheHitRatio( // Processing all callers of the function for (std::pair Pair : Calls[BF]) { BinaryFunction *SrcFunction = Pair.first; - const uint64_t SrcPage = - BBAddr.at(SrcFunction->getLayout().block_front()) / ITLBPageSize; + + BBAddrIt = BBAddr.find(SrcFunction->getLayout().block_front()); + assert(BBAddrIt != BBAddr.end()); + const uint64_t SrcPage = BBAddrIt->second / ITLBPageSize; // Is this a 'long' or a 'short' call? if (Page != SrcPage) { // This is a miss diff --git a/bolt/lib/Passes/IdenticalCodeFolding.cpp b/bolt/lib/Passes/IdenticalCodeFolding.cpp index 87eba10354a37b1d26a70dc481b67e8b4db947f7..38e080c9dd621363de1a9e2022ca57d6e3097a93 100644 --- a/bolt/lib/Passes/IdenticalCodeFolding.cpp +++ b/bolt/lib/Passes/IdenticalCodeFolding.cpp @@ -356,7 +356,10 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { "ICF breakdown", opts::TimeICF); ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { // Make sure indices are in-order. - BF.getLayout().updateLayoutIndices(); + if (opts::ICFUseDFS) + BF.getLayout().updateLayoutIndices(BF.dfs()); + else + BF.getLayout().updateLayoutIndices(); // Pre-compute hash before pushing into hashtable. // Hash instruction operands to minimize hash collisions. diff --git a/bolt/lib/Passes/Inliner.cpp b/bolt/lib/Passes/Inliner.cpp index 84e7d97067b0cf7bde944c7a139e4c5246a0ddf7..f004a8eeea185b6a70bcfa4073de5db9e1f9a985 100644 --- a/bolt/lib/Passes/Inliner.cpp +++ b/bolt/lib/Passes/Inliner.cpp @@ -355,7 +355,9 @@ Inliner::inlineCall(BinaryBasicBlock &CallerBB, std::vector Successors(BB.succ_size()); llvm::transform(BB.successors(), Successors.begin(), [&InlinedBBMap](const BinaryBasicBlock *BB) { - return InlinedBBMap.at(BB); + auto It = InlinedBBMap.find(BB); + assert(It != InlinedBBMap.end()); + return It->second; }); if (CallerFunction.hasValidProfile() && Callee.hasValidProfile()) diff --git a/bolt/lib/Passes/MCF.cpp b/bolt/lib/Passes/MCF.cpp index c3898d2dce989efdd7f3f77149b5417578ad678a..77dea7369140e754270a9459bf0ff41b1049b388 100644 --- a/bolt/lib/Passes/MCF.cpp +++ b/bolt/lib/Passes/MCF.cpp @@ -12,9 +12,11 @@ #include "bolt/Passes/MCF.h" #include "bolt/Core/BinaryFunction.h" +#include "bolt/Core/ParallelUtilities.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/CommandLine.h" #include #include @@ -29,19 +31,10 @@ namespace opts { extern cl::OptionCategory BoltOptCategory; -extern cl::opt TimeOpts; - static cl::opt IterativeGuess( "iterative-guess", cl::desc("in non-LBR mode, guess edge counts using iterative technique"), cl::Hidden, cl::cat(BoltOptCategory)); - -static cl::opt UseRArcs( - "mcf-use-rarcs", - cl::desc("in MCF, consider the possibility of cancelling flow to balance " - "edges"), - cl::Hidden, cl::cat(BoltOptCategory)); - } // namespace opts namespace llvm { @@ -441,7 +434,7 @@ void equalizeBBCounts(DataflowInfoManager &Info, BinaryFunction &BF) { } } -void estimateEdgeCounts(BinaryFunction &BF) { +void EstimateEdgeCounts::runOnFunction(BinaryFunction &BF) { EdgeWeightMap PredEdgeWeights; EdgeWeightMap SuccEdgeWeights; if (!opts::IterativeGuess) { @@ -462,8 +455,24 @@ void estimateEdgeCounts(BinaryFunction &BF) { recalculateBBCounts(BF, /*AllEdges=*/false); } -void solveMCF(BinaryFunction &BF, MCFCostFunction CostFunction) { - llvm_unreachable("not implemented"); +Error EstimateEdgeCounts::runOnFunctions(BinaryContext &BC) { + if (llvm::none_of(llvm::make_second_range(BC.getBinaryFunctions()), + [](const BinaryFunction &BF) { + return BF.getProfileFlags() == BinaryFunction::PF_SAMPLE; + })) + return Error::success(); + + ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { + runOnFunction(BF); + }; + ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) { + return BF.getProfileFlags() != BinaryFunction::PF_SAMPLE; + }; + + ParallelUtilities::runOnEachFunction( + BC, ParallelUtilities::SchedulingPolicy::SP_BB_QUADRATIC, WorkFun, + SkipFunc, "EstimateEdgeCounts"); + return Error::success(); } } // namespace bolt diff --git a/bolt/lib/Passes/ValidateMemRefs.cpp b/bolt/lib/Passes/ValidateMemRefs.cpp index f29a97c43f497c289edbadfef7a59461f90b9694..ca58493b279c9eaf07ac01000f94f0a10dc8d36d 100644 --- a/bolt/lib/Passes/ValidateMemRefs.cpp +++ b/bolt/lib/Passes/ValidateMemRefs.cpp @@ -29,8 +29,7 @@ bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction &BF, MCInst &Inst, if (!BD) return false; - const uint64_t TargetAddress = BD->getAddress() + Offset; - JumpTable *JT = BC.getJumpTableContainingAddress(TargetAddress); + JumpTable *JT = BC.getJumpTableContainingAddress(BD->getAddress()); if (!JT) return false; @@ -43,8 +42,9 @@ bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction &BF, MCInst &Inst, // the jump table label with a regular rodata reference. Get a // non-JT reference by fetching the symbol 1 byte before the JT // label. - MCSymbol *NewSym = BC.getOrCreateGlobalSymbol(TargetAddress - 1, "DATAat"); - BC.MIB->setOperandToSymbolRef(Inst, OperandNum, NewSym, 1, &*BC.Ctx, 0); + MCSymbol *NewSym = BC.getOrCreateGlobalSymbol(BD->getAddress() - 1, "DATAat"); + BC.MIB->setOperandToSymbolRef(Inst, OperandNum, NewSym, Offset + 1, &*BC.Ctx, + 0); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: replaced reference @" << BF.getPrintName() << " from " << BD->getName() << " to " << NewSym->getName() << " + 1\n"); diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp index 7cfb9c132c2c68f98c59df0ada96c7820ef7eb94..cdfca2b9871acfa6dee5adc57fedcb65557afb20 100644 --- a/bolt/lib/Profile/BoltAddressTranslation.cpp +++ b/bolt/lib/Profile/BoltAddressTranslation.cpp @@ -20,10 +20,9 @@ namespace bolt { const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat"; -void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, - const BinaryBasicBlock &BB, - uint64_t FuncInputAddress, - uint64_t FuncOutputAddress) { +void BoltAddressTranslation::writeEntriesForBB( + MapTy &Map, const BinaryBasicBlock &BB, uint64_t FuncInputAddress, + uint64_t FuncOutputAddress) const { const uint64_t BBOutputOffset = BB.getOutputAddressRange().first - FuncOutputAddress; const uint32_t BBInputOffset = BB.getInputOffset(); @@ -55,7 +54,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, // and this deleted block will both share the same output address (the same // key), and we need to map back. We choose here to privilege the successor by // allowing it to overwrite the previously inserted key in the map. - Map[BBOutputOffset] = BBInputOffset << 1; + Map.emplace(BBOutputOffset, BBInputOffset << 1); const auto &IOAddressMap = BB.getFunction()->getBinaryContext().getIOAddressMap(); @@ -72,8 +71,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(OutputOffset) << " Val: " << Twine::utohexstr(InputOffset) << " (branch)\n"); - Map.insert(std::pair(OutputOffset, - (InputOffset << 1) | BRANCHENTRY)); + Map.emplace(OutputOffset, (InputOffset << 1) | BRANCHENTRY); } } @@ -108,6 +106,19 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { for (const BinaryBasicBlock *const BB : Function.getLayout().getMainFragment()) writeEntriesForBB(Map, *BB, InputAddress, OutputAddress); + // Add entries for deleted blocks. They are still required for correct BB + // mapping of branches modified by SCTC. By convention, they would have the + // end of the function as output address. + const BBHashMapTy &BBHashMap = getBBHashMap(InputAddress); + if (BBHashMap.size() != Function.size()) { + const uint64_t EndOffset = Function.getOutputSize(); + std::unordered_set MappedInputOffsets; + for (const BinaryBasicBlock &BB : Function) + MappedInputOffsets.emplace(BB.getInputOffset()); + for (const auto &[InputOffset, _] : BBHashMap) + if (!llvm::is_contained(MappedInputOffsets, InputOffset)) + Map.emplace(EndOffset, InputOffset << 1); + } Maps.emplace(Function.getOutputAddress(), std::move(Map)); ReverseMap.emplace(OutputAddress, InputAddress); @@ -138,8 +149,8 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { << " basic block hashes\n"; } -APInt BoltAddressTranslation::calculateBranchEntriesBitMask(MapTy &Map, - size_t EqualElems) { +APInt BoltAddressTranslation::calculateBranchEntriesBitMask( + MapTy &Map, size_t EqualElems) const { APInt BitMask(alignTo(EqualElems, 8), 0); size_t Index = 0; for (std::pair &KeyVal : Map) { @@ -422,7 +433,7 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, } } -void BoltAddressTranslation::dump(raw_ostream &OS) { +void BoltAddressTranslation::dump(raw_ostream &OS) const { const size_t NumTables = Maps.size(); OS << "BAT tables for " << NumTables << " functions:\n"; for (const auto &MapEntry : Maps) { @@ -447,11 +458,15 @@ void BoltAddressTranslation::dump(raw_ostream &OS) { OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val)); OS << "\n"; } - if (IsHotFunction) - OS << "NumBlocks: " << NumBasicBlocksMap[Address] << '\n'; - if (SecondaryEntryPointsMap.count(Address)) { + if (IsHotFunction) { + auto NumBasicBlocksIt = NumBasicBlocksMap.find(Address); + assert(NumBasicBlocksIt != NumBasicBlocksMap.end()); + OS << "NumBlocks: " << NumBasicBlocksIt->second << '\n'; + } + auto SecondaryEntryPointsIt = SecondaryEntryPointsMap.find(Address); + if (SecondaryEntryPointsIt != SecondaryEntryPointsMap.end()) { const std::vector &SecondaryEntryPoints = - SecondaryEntryPointsMap[Address]; + SecondaryEntryPointsIt->second; OS << SecondaryEntryPoints.size() << " secondary entry points:\n"; for (uint32_t EntryPointOffset : SecondaryEntryPoints) OS << formatv("{0:x}\n", EntryPointOffset); @@ -547,13 +562,6 @@ BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress, return Res; } -uint64_t BoltAddressTranslation::fetchParentAddress(uint64_t Address) const { - auto Iter = ColdPartSource.find(Address); - if (Iter == ColdPartSource.end()) - return 0; - return Iter->second; -} - bool BoltAddressTranslation::enabledFor( llvm::object::ELFObjectFileBase *InputFile) const { for (const SectionRef &Section : InputFile->sections()) { diff --git a/bolt/lib/Profile/CMakeLists.txt b/bolt/lib/Profile/CMakeLists.txt index 045ac47edb950bb1ebc99fd4dc56fb38cc652667..ca8b9c34e63b17454a04963c57c37d8744175c9d 100644 --- a/bolt/lib/Profile/CMakeLists.txt +++ b/bolt/lib/Profile/CMakeLists.txt @@ -17,6 +17,5 @@ add_llvm_library(LLVMBOLTProfile target_link_libraries(LLVMBOLTProfile PRIVATE LLVMBOLTCore - LLVMBOLTPasses LLVMBOLTUtils ) diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index f55caa7f03f738b839ad5aca914f65aea654639e..ce6ec0a04ac1600572521365184bad68e3f76176 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -613,7 +613,6 @@ Error DataAggregator::readProfile(BinaryContext &BC) { if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile)) report_error("cannot create output data file", EC); } - BC.logBOLTErrorsAndQuitOnFatal(PrintProgramStats().runOnFunctions(BC)); } return Error::success(); @@ -673,7 +672,8 @@ DataAggregator::getBATParentFunction(const BinaryFunction &Func) const { return nullptr; } -StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const { +StringRef DataAggregator::getLocationName(const BinaryFunction &Func, + bool BAT) { if (!BAT) return Func.getOneName(); @@ -702,7 +702,7 @@ bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address, auto I = NamesToSamples.find(Func.getOneName()); if (I == NamesToSamples.end()) { bool Success; - StringRef LocName = getLocationName(Func); + StringRef LocName = getLocationName(Func, BAT); std::tie(I, Success) = NamesToSamples.insert( std::make_pair(Func.getOneName(), FuncSampleData(LocName, FuncSampleData::ContainerTy()))); @@ -722,7 +722,7 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From, FuncBranchData *AggrData = getBranchData(Func); if (!AggrData) { AggrData = &NamesToBranches[Func.getOneName()]; - AggrData->Name = getLocationName(Func); + AggrData->Name = getLocationName(Func, BAT); setBranchData(Func, AggrData); } @@ -741,7 +741,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, StringRef SrcFunc; StringRef DstFunc; if (FromFunc) { - SrcFunc = getLocationName(*FromFunc); + SrcFunc = getLocationName(*FromFunc, BAT); FromAggrData = getBranchData(*FromFunc); if (!FromAggrData) { FromAggrData = &NamesToBranches[FromFunc->getOneName()]; @@ -752,7 +752,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, recordExit(*FromFunc, From, Mispreds, Count); } if (ToFunc) { - DstFunc = getLocationName(*ToFunc); + DstFunc = getLocationName(*ToFunc, BAT); ToAggrData = getBranchData(*ToFunc); if (!ToAggrData) { ToAggrData = &NamesToBranches[ToFunc->getOneName()]; @@ -2340,7 +2340,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, continue; BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress); assert(BF); - YamlBF.Name = getLocationName(*BF); + YamlBF.Name = getLocationName(*BF, BAT); YamlBF.Id = BF->getFunctionNumber(); YamlBF.Hash = BAT->getBFHash(FuncAddress); YamlBF.ExecCount = BF->getKnownExecutionCount(); @@ -2349,11 +2349,11 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, BAT->getBBHashMap(FuncAddress); YamlBF.Blocks.resize(YamlBF.NumBasicBlocks); - for (auto &&[Idx, YamlBB] : llvm::enumerate(YamlBF.Blocks)) - YamlBB.Index = Idx; - - for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI) - YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash(); + for (auto &&[Entry, YamlBB] : llvm::zip(BlockMap, YamlBF.Blocks)) { + const auto &Block = Entry.second; + YamlBB.Hash = Block.Hash; + YamlBB.Index = Block.Index; + } // Lookup containing basic block offset and index auto getBlock = [&BlockMap](uint32_t Offset) { @@ -2363,7 +2363,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, exit(1); } --BlockIt; - return std::pair(BlockIt->first, BlockIt->second.getBBIndex()); + return std::pair(BlockIt->first, BlockIt->second.Index); }; for (const BranchInfo &BI : Branches.Data) { diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index 06c5e96b780643a947b6851ba8c36ca3b988f322..f2e999bbfdc6dca0bbfc6df5918bd62b99859f68 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -598,8 +598,6 @@ void DataReader::readSampleData(BinaryFunction &BF) { } BF.ExecutionCount = TotalEntryCount; - - estimateEdgeCounts(BF); } void DataReader::convertBranchData(BinaryFunction &BF) const { diff --git a/bolt/lib/Profile/StaleProfileMatching.cpp b/bolt/lib/Profile/StaleProfileMatching.cpp index 016962ff34d8dff0637ff6880f55f15aef6b0b19..365bc5389266df8fa76a40f608122db24d8c8ca4 100644 --- a/bolt/lib/Profile/StaleProfileMatching.cpp +++ b/bolt/lib/Profile/StaleProfileMatching.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/Bitfields.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/xxhash.h" #include "llvm/Transforms/Utils/SampleProfileInference.h" @@ -42,6 +43,7 @@ using namespace llvm; namespace opts { +extern cl::opt TimeRewrite; extern cl::OptionCategory BoltOptCategory; cl::opt @@ -372,8 +374,10 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) { // Create necessary metadata for the flow function for (FlowJump &Jump : Func.Jumps) { - Func.Blocks.at(Jump.Source).SuccJumps.push_back(&Jump); - Func.Blocks.at(Jump.Target).PredJumps.push_back(&Jump); + assert(Jump.Source < Func.Blocks.size()); + Func.Blocks[Jump.Source].SuccJumps.push_back(&Jump); + assert(Jump.Target < Func.Blocks.size()); + Func.Blocks[Jump.Target].PredJumps.push_back(&Jump); } return Func; } @@ -705,6 +709,10 @@ void assignProfile(BinaryFunction &BF, bool YAMLProfileReader::inferStaleProfile( BinaryFunction &BF, const yaml::bolt::BinaryFunctionProfile &YamlBF) { + + NamedRegionTimer T("inferStaleProfile", "stale profile inference", "rewrite", + "Rewrite passes", opts::TimeRewrite); + if (!BF.hasCFG()) return false; diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp index 29d94067f459fc0500211679083607b4cc8cfcc3..f25f59201f1cd9bf73ef9890d49938e0cc3783ec 100644 --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -102,11 +102,14 @@ bool YAMLProfileReader::parseFunctionProfile( if (BF.empty()) return true; - if (!opts::IgnoreHash && - YamlBF.Hash != BF.computeHash(IsDFSOrder, HashFunction)) { - if (opts::Verbosity >= 1) - errs() << "BOLT-WARNING: function hash mismatch\n"; - ProfileMatched = false; + if (!opts::IgnoreHash) { + if (!BF.getHash()) + BF.computeHash(IsDFSOrder, HashFunction); + if (YamlBF.Hash != BF.getHash()) { + if (opts::Verbosity >= 1) + errs() << "BOLT-WARNING: function hash mismatch\n"; + ProfileMatched = false; + } } if (YamlBF.NumBasicBlocks != BF.size()) { @@ -253,10 +256,8 @@ bool YAMLProfileReader::parseFunctionProfile( if (BB.getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE) BB.setExecutionCount(0); - if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) { + if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) BF.setExecutionCount(FunctionExecutionCount); - estimateEdgeCounts(BF); - } ProfileMatched &= !MismatchedBlocks && !MismatchedCalls && !MismatchedEdges; diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index ef04ba0d21ad75cf29421c24922738e9f0cba1d9..9adbfdc5ff0897cb228f8e28ea58727185dc55f6 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -10,6 +10,7 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Profile/BoltAddressTranslation.h" +#include "bolt/Profile/DataAggregator.h" #include "bolt/Profile/ProfileReaderBase.h" #include "bolt/Rewrite/RewriteInstance.h" #include "llvm/Support/CommandLine.h" @@ -39,6 +40,10 @@ const BinaryFunction *YAMLProfileWriter::setCSIDestination( BC.getFunctionForSymbol(Symbol, &EntryID)) { if (BAT && BAT->isBATFunction(Callee->getAddress())) std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset); + else if (const BinaryBasicBlock *BB = + Callee->getBasicBlockContainingOffset(Offset)) + BC.getFunctionForSymbol(Callee->getSecondaryEntryPointSymbol(*BB), + &EntryID); CSI.DestId = Callee->getFunctionNumber(); CSI.EntryDiscriminator = EntryID; return Callee; @@ -59,7 +64,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, BF.computeHash(UseDFS); BF.computeBlockHashes(); - YamlBF.Name = BF.getPrintName(); + YamlBF.Name = DataAggregator::getLocationName(BF, BAT); YamlBF.Id = BF.getFunctionNumber(); YamlBF.Hash = BF.getHash(); YamlBF.NumBasicBlocks = BF.size(); @@ -69,6 +74,9 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, llvm::copy(UseDFS ? BF.dfs() : BF.getLayout().blocks(), std::back_inserter(Order)); + const FunctionLayout Layout = BF.getLayout(); + Layout.updateLayoutIndices(Order); + for (const BinaryBasicBlock *BB : Order) { yaml::bolt::BinaryBasicBlockProfile YamlBB; YamlBB.Index = BB->getLayoutIndex(); diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp index cbb7199a53ddd14f77730645efd8a8fd2a4109a4..aaa0e1ff4d46ff911cdfebdb7708a418b897dd98 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -23,6 +23,7 @@ #include "bolt/Passes/JTFootprintReduction.h" #include "bolt/Passes/LongJmp.h" #include "bolt/Passes/LoopInversionPass.h" +#include "bolt/Passes/MCF.h" #include "bolt/Passes/PLTCall.h" #include "bolt/Passes/PatchEntries.h" #include "bolt/Passes/RegReAssign.h" @@ -90,6 +91,11 @@ PrintAfterLowering("print-after-lowering", cl::desc("print function after instruction lowering"), cl::Hidden, cl::cat(BoltOptCategory)); +static cl::opt PrintEstimateEdgeCounts( + "print-estimate-edge-counts", + cl::desc("print function after edge counts are set for no-LBR profile"), + cl::Hidden, cl::cat(BoltOptCategory)); + cl::opt PrintFinalized("print-finalized", cl::desc("print function after CFG is finalized"), @@ -334,8 +340,10 @@ Error BinaryFunctionPassManager::runPasses() { Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { BinaryFunctionPassManager Manager(BC); - const DynoStats InitialDynoStats = - getDynoStats(BC.getBinaryFunctions(), BC.isAArch64()); + Manager.registerPass( + std::make_unique(PrintEstimateEdgeCounts)); + + Manager.registerPass(std::make_unique()); Manager.registerPass(std::make_unique(), opts::AsmDump.getNumOccurrences()); @@ -447,10 +455,9 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { Manager.registerPass(std::make_unique(PrintSplit)); // Print final dyno stats right while CFG and instruction analysis are intact. - Manager.registerPass( - std::make_unique( - InitialDynoStats, "after all optimizations before SCTC and FOP"), - opts::PrintDynoStats || opts::DynoStatsAll); + Manager.registerPass(std::make_unique( + "after all optimizations before SCTC and FOP"), + opts::PrintDynoStats || opts::DynoStatsAll); // Add the StokeInfo pass, which extract functions for stoke optimization and // get the liveness information for them diff --git a/bolt/lib/Rewrite/BuildIDRewriter.cpp b/bolt/lib/Rewrite/BuildIDRewriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83d0c9bfe182aeb91dd7d897c62f200dc95790b6 --- /dev/null +++ b/bolt/lib/Rewrite/BuildIDRewriter.cpp @@ -0,0 +1,113 @@ +//===- bolt/Rewrite/BuildIDRewriter.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Read and update build ID stored in ELF note section. +// +//===----------------------------------------------------------------------===// + +#include "bolt/Rewrite/MetadataRewriter.h" +#include "bolt/Rewrite/MetadataRewriters.h" +#include "llvm/Support/Errc.h" + +using namespace llvm; +using namespace bolt; + +namespace { + +/// The build-id is typically a stream of 20 bytes. Return these bytes in +/// printable hexadecimal form. +std::string getPrintableBuildID(StringRef BuildID) { + std::string Str; + raw_string_ostream OS(Str); + for (const char &Char : BuildID) + OS << format("%.2x", static_cast(Char)); + + return OS.str(); +} + +class BuildIDRewriter final : public MetadataRewriter { + + /// Information about binary build ID. + ErrorOr BuildIDSection{std::errc::bad_address}; + StringRef BuildID; + std::optional BuildIDOffset; + std::optional BuildIDSize; + +public: + BuildIDRewriter(StringRef Name, BinaryContext &BC) + : MetadataRewriter(Name, BC) {} + + Error sectionInitializer() override; + + Error postEmitFinalizer() override; +}; + +Error BuildIDRewriter::sectionInitializer() { + // Typically, build ID will reside in .note.gnu.build-id section. Howerver, + // a linker script can change the section name and such is the case with + // the Linux kernel. Hence, we iterate over all note sections. + for (BinarySection &NoteSection : BC.sections()) { + if (!NoteSection.isNote()) + continue; + + StringRef Buf = NoteSection.getContents(); + DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + DataExtractor::Cursor Cursor(0); + while (Cursor && !DE.eof(Cursor)) { + const uint32_t NameSz = DE.getU32(Cursor); + const uint32_t DescSz = DE.getU32(Cursor); + const uint32_t Type = DE.getU32(Cursor); + + StringRef Name = + NameSz ? Buf.slice(Cursor.tell(), Cursor.tell() + NameSz) : ""; + Cursor.seek(alignTo(Cursor.tell() + NameSz, 4)); + + const uint64_t DescOffset = Cursor.tell(); + StringRef Desc = + DescSz ? Buf.slice(DescOffset, DescOffset + DescSz) : ""; + Cursor.seek(alignTo(DescOffset + DescSz, 4)); + + if (!Cursor) + return createStringError(errc::executable_format_error, + "out of bounds while reading note section: %s", + toString(Cursor.takeError()).c_str()); + + if (Type == ELF::NT_GNU_BUILD_ID && Name.substr(0, 3) == "GNU" && + DescSz) { + BuildIDSection = NoteSection; + BuildID = Desc; + BC.setFileBuildID(getPrintableBuildID(Desc)); + BuildIDOffset = DescOffset; + BuildIDSize = DescSz; + + return Error::success(); + } + } + } + + return Error::success(); +} + +Error BuildIDRewriter::postEmitFinalizer() { + if (!BuildIDSection || !BuildIDOffset) + return Error::success(); + + const uint8_t LastByte = BuildID[BuildID.size() - 1]; + SmallVector Patch = {static_cast(LastByte ^ 1)}; + BuildIDSection->addPatch(*BuildIDOffset + BuildID.size() - 1, Patch); + BC.outs() << "BOLT-INFO: patched build-id (flipped last bit)\n"; + + return Error::success(); +} +} // namespace + +std::unique_ptr +llvm::bolt::createBuildIDRewriter(BinaryContext &BC) { + return std::make_unique("build-id-rewriter", BC); +} diff --git a/bolt/lib/Rewrite/CMakeLists.txt b/bolt/lib/Rewrite/CMakeLists.txt index 578f1763bfe4ec9e5e345c4d5cc5ca102188400e..34993af2623bfb897242c59cdbf134ba44edcb7f 100644 --- a/bolt/lib/Rewrite/CMakeLists.txt +++ b/bolt/lib/Rewrite/CMakeLists.txt @@ -21,6 +21,7 @@ add_llvm_library(LLVMBOLTRewrite LinuxKernelRewriter.cpp MachORewriteInstance.cpp MetadataManager.cpp + BuildIDRewriter.cpp PseudoProbeRewriter.cpp RewriteInstance.cpp SDTRewriter.cpp diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index d582ce7b33a27fbc56b4cbb8ac8a6cad88aa7645..8814ebbd10aa500cc168b2e2633d10b13cc8343b 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -73,8 +73,7 @@ static void printDie(DWARFUnit &DU, uint64_t DIEOffset) { DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor(); DWARFDebugInfoEntry DIEEntry; if (DIEEntry.extractFast(DU, &DIEOffset, DebugInfoData, NextCUOffset, 0)) { - if (const DWARFAbbreviationDeclaration *AbbrDecl = - DIEEntry.getAbbreviationDeclarationPtr()) { + if (DIEEntry.getAbbreviationDeclarationPtr()) { DWARFDie DDie(&DU, &DIEEntry); printDie(DDie); } else { @@ -353,7 +352,7 @@ static cl::opt CreateDebugNames( static cl::opt DebugSkeletonCu("debug-skeleton-cu", - cl::desc("prints out offsetrs for abbrev and debu_info of " + cl::desc("prints out offsets for abbrev and debug_info of " "Skeleton CUs that get patched."), cl::ZeroOrMore, cl::Hidden, cl::init(false), cl::cat(BoltCategory)); diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index 99775ccfe38d30f427915d3f015397cc37726756..b2c8b2446f7e1ed730a96668e8ccd9c5950369c2 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -393,7 +393,7 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) { for (uint64_t I = 0; I < SectionSize; I += 4) { const uint64_t EntryAddress = SectionAddress + I; - ErrorOr Offset = BC.getSignedValueAtAddress(EntryAddress, 4); + ErrorOr Offset = BC.getSignedValueAtAddress(EntryAddress, 4); assert(Offset && "Reading valid PC-relative offset for a ksymtab entry"); const int32_t SignedOffset = *Offset; const uint64_t RefAddress = EntryAddress + SignedOffset; diff --git a/bolt/lib/Rewrite/MetadataManager.cpp b/bolt/lib/Rewrite/MetadataManager.cpp index 4ce44820d9eca6cd861487e60e838b5531fe4246..713d2e47b6efa285fbd7d0c6354bb54c1df86b9f 100644 --- a/bolt/lib/Rewrite/MetadataManager.cpp +++ b/bolt/lib/Rewrite/MetadataManager.cpp @@ -20,6 +20,18 @@ void MetadataManager::registerRewriter( Rewriters.emplace_back(std::move(Rewriter)); } +void MetadataManager::runSectionInitializers() { + for (auto &Rewriter : Rewriters) { + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invoking " << Rewriter->getName() + << " after reading sections\n"); + if (Error E = Rewriter->sectionInitializer()) { + errs() << "BOLT-ERROR: while running " << Rewriter->getName() + << " after reading sections: " << toString(std::move(E)) << '\n'; + exit(1); + } + } +} + void MetadataManager::runInitializersPreCFG() { for (auto &Rewriter : Rewriters) { LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invoking " << Rewriter->getName() diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 6e1021a6df22c8640c17285fb4743fa667a67373..1a3a8af21d81b680f3451a749330a6144f21ae9c 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -17,6 +17,7 @@ #include "bolt/Core/MCPlusBuilder.h" #include "bolt/Core/ParallelUtilities.h" #include "bolt/Core/Relocation.h" +#include "bolt/Passes/BinaryPasses.h" #include "bolt/Passes/CacheMetrics.h" #include "bolt/Passes/ReorderFunctions.h" #include "bolt/Profile/BoltAddressTranslation.h" @@ -54,7 +55,6 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Regex.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" @@ -86,6 +86,7 @@ extern cl::list ReorderData; extern cl::opt ReorderFunctions; extern cl::opt TerminalTrap; extern cl::opt TimeBuild; +extern cl::opt TimeRewrite; cl::opt AllowStripped("allow-stripped", cl::desc("allow processing of stripped binaries"), @@ -235,11 +236,6 @@ UseGnuStack("use-gnu-stack", cl::ZeroOrMore, cl::cat(BoltCategory)); -static cl::opt - TimeRewrite("time-rewrite", - cl::desc("print time spent in rewriting passes"), cl::Hidden, - cl::cat(BoltCategory)); - static cl::opt SequentialDisassembly("sequential-disassembly", cl::desc("performs disassembly sequentially"), @@ -647,82 +643,6 @@ Error RewriteInstance::discoverStorage() { return Error::success(); } -void RewriteInstance::parseBuildID() { - if (!BuildIDSection) - return; - - StringRef Buf = BuildIDSection->getContents(); - - // Reading notes section (see Portable Formats Specification, Version 1.1, - // pg 2-5, section "Note Section"). - DataExtractor DE = - DataExtractor(Buf, - /*IsLittleEndian=*/true, InputFile->getBytesInAddress()); - uint64_t Offset = 0; - if (!DE.isValidOffset(Offset)) - return; - uint32_t NameSz = DE.getU32(&Offset); - if (!DE.isValidOffset(Offset)) - return; - uint32_t DescSz = DE.getU32(&Offset); - if (!DE.isValidOffset(Offset)) - return; - uint32_t Type = DE.getU32(&Offset); - - LLVM_DEBUG(dbgs() << "NameSz = " << NameSz << "; DescSz = " << DescSz - << "; Type = " << Type << "\n"); - - // Type 3 is a GNU build-id note section - if (Type != 3) - return; - - StringRef Name = Buf.slice(Offset, Offset + NameSz); - Offset = alignTo(Offset + NameSz, 4); - if (Name.substr(0, 3) != "GNU") - return; - - BuildID = Buf.slice(Offset, Offset + DescSz); -} - -std::optional RewriteInstance::getPrintableBuildID() const { - if (BuildID.empty()) - return std::nullopt; - - std::string Str; - raw_string_ostream OS(Str); - const unsigned char *CharIter = BuildID.bytes_begin(); - while (CharIter != BuildID.bytes_end()) { - if (*CharIter < 0x10) - OS << "0"; - OS << Twine::utohexstr(*CharIter); - ++CharIter; - } - return OS.str(); -} - -void RewriteInstance::patchBuildID() { - raw_fd_ostream &OS = Out->os(); - - if (BuildID.empty()) - return; - - size_t IDOffset = BuildIDSection->getContents().rfind(BuildID); - assert(IDOffset != StringRef::npos && "failed to patch build-id"); - - uint64_t FileOffset = getFileOffsetForAddress(BuildIDSection->getAddress()); - if (!FileOffset) { - BC->errs() - << "BOLT-WARNING: Non-allocatable build-id will not be updated.\n"; - return; - } - - char LastIDByte = BuildID[BuildID.size() - 1]; - LastIDByte ^= 1; - OS.pwrite(&LastIDByte, 1, FileOffset + IDOffset + BuildID.size() - 1); - - BC->outs() << "BOLT-INFO: patched build-id (flipped last bit)\n"; -} - Error RewriteInstance::run() { assert(BC && "failed to create a binary context"); @@ -948,9 +868,6 @@ void RewriteInstance::discoverFileObjects() { BinaryFunction *PreviousFunction = nullptr; unsigned AnonymousId = 0; - // Regex object for matching cold fragments. - const Regex ColdFragment(".*\\.cold(\\.[0-9]+)?"); - const auto SortedSymbolsEnd = LastSymbol == SortedSymbols.end() ? LastSymbol : std::next(LastSymbol); for (auto Iter = SortedSymbols.begin(); Iter != SortedSymbolsEnd; ++Iter) { @@ -1232,7 +1149,7 @@ void RewriteInstance::discoverFileObjects() { } // Check if it's a cold function fragment. - if (ColdFragment.match(SymName)) { + if (FunctionFragmentTemplate.match(SymName)) { static bool PrintedWarning = false; if (!PrintedWarning) { PrintedWarning = true; @@ -1463,10 +1380,10 @@ void RewriteInstance::registerFragments() { for (StringRef Name : Function.getNames()) { StringRef BaseName = NR.restore(Name); const bool IsGlobal = BaseName == Name; - const size_t ColdSuffixPos = BaseName.find(".cold"); - if (ColdSuffixPos == StringRef::npos) + SmallVector Matches; + if (!FunctionFragmentTemplate.match(BaseName, &Matches)) continue; - StringRef ParentName = BaseName.substr(0, ColdSuffixPos); + StringRef ParentName = Matches[1]; const BinaryData *BD = BC->getBinaryDataByName(ParentName); const uint64_t NumPossibleLocalParents = NR.getUniquifiedNameCount(ParentName); @@ -1500,7 +1417,7 @@ void RewriteInstance::registerFragments() { if (!BC->hasSymbolsWithFileName()) { BC->errs() << "BOLT-ERROR: input file has split functions but does not " "have FILE symbols. If the binary was stripped, preserve " - "FILE symbols with --keep-file-symbols strip option"; + "FILE symbols with --keep-file-symbols strip option\n"; exit(1); } @@ -1984,10 +1901,10 @@ Error RewriteInstance::readSpecialSections() { ".rela" + std::string(BC->getMainCodeSectionName())); HasSymbolTable = (bool)BC->getUniqueSectionByName(".symtab"); EHFrameSection = BC->getUniqueSectionByName(".eh_frame"); - BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id"); if (ErrorOr BATSec = BC->getUniqueSectionByName(BoltAddressTranslation::SECTION_NAME)) { + BC->HasBATSection = true; // Do not read BAT when plotting a heatmap if (!opts::HeatmapMode) { if (std::error_code EC = BAT->parse(BC->outs(), BATSec->getContents())) { @@ -2041,10 +1958,7 @@ Error RewriteInstance::readSpecialSections() { report_error("expected valid eh_frame section", EHFrameOrError.takeError()); CFIRdWrt.reset(new CFIReaderWriter(*BC, *EHFrameOrError.get())); - // Parse build-id - parseBuildID(); - if (std::optional FileBuildID = getPrintableBuildID()) - BC->setFileBuildID(*FileBuildID); + processSectionMetadata(); // Read .dynamic/PT_DYNAMIC. return readELFDynamic(); @@ -3208,12 +3122,14 @@ void RewriteInstance::preprocessProfileData() { if (Error E = ProfileReader->preprocessProfile(*BC.get())) report_error("cannot pre-process profile", std::move(E)); - if (!BC->hasSymbolsWithFileName() && ProfileReader->hasLocalsWithFileName()) { + if (!BC->hasSymbolsWithFileName() && ProfileReader->hasLocalsWithFileName() && + !opts::AllowStripped) { BC->errs() << "BOLT-ERROR: input binary does not have local file symbols " "but profile data includes function names with embedded file " "names. It appears that the input binary was stripped while a " - "profiled binary was not\n"; + "profiled binary was not. If you know what you are doing and " + "wish to proceed, use -allow-stripped option.\n"; exit(1); } } @@ -3222,14 +3138,20 @@ void RewriteInstance::initializeMetadataManager() { if (BC->IsLinuxKernel) MetadataManager.registerRewriter(createLinuxKernelRewriter(*BC)); + MetadataManager.registerRewriter(createBuildIDRewriter(*BC)); + MetadataManager.registerRewriter(createPseudoProbeRewriter(*BC)); MetadataManager.registerRewriter(createSDTRewriter(*BC)); } -void RewriteInstance::processMetadataPreCFG() { +void RewriteInstance::processSectionMetadata() { initializeMetadataManager(); + MetadataManager.runSectionInitializers(); +} + +void RewriteInstance::processMetadataPreCFG() { MetadataManager.runInitializersPreCFG(); processProfileDataPreCFG(); @@ -3284,8 +3206,11 @@ void RewriteInstance::processProfileData() { // Release memory used by profile reader. ProfileReader.reset(); - if (opts::AggregateOnly) + if (opts::AggregateOnly) { + PrintProgramStats PPS(&*BAT); + BC->logBOLTErrorsAndQuitOnFatal(PPS.runOnFunctions(*BC)); exit(0); + } } void RewriteInstance::disassembleFunctions() { @@ -5773,8 +5698,6 @@ void RewriteInstance::rewriteFile() { // Update symbol tables. patchELFSymTabs(); - patchBuildID(); - if (opts::EnableBAT) encodeBATSection(); diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 8fdacffcb147b69ef8306fd915cb4c9929d4cb66..a33a9dc8c013ce0b4c07591e64421b275f449b33 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -1932,6 +1932,19 @@ public: // = R_X86_64_PC32(Ln) + En - JT // = R_X86_64_PC32(Ln + offsetof(En)) // + auto isRIPRel = [&](X86MemOperand &MO) { + // NB: DispExpr should be set + return MO.DispExpr != nullptr && + MO.BaseRegNum == RegInfo->getProgramCounter() && + MO.IndexRegNum == X86::NoRegister && + MO.SegRegNum == X86::NoRegister; + }; + auto isIndexed = [](X86MemOperand &MO, MCPhysReg R) { + // NB: IndexRegNum should be set. + return MO.IndexRegNum != X86::NoRegister && MO.BaseRegNum == R && + MO.ScaleImm == 4 && MO.DispImm == 0 && + MO.SegRegNum == X86::NoRegister; + }; LLVM_DEBUG(dbgs() << "Checking for PIC jump table\n"); MCInst *MemLocInstr = nullptr; const MCInst *MovInstr = nullptr; @@ -1965,9 +1978,8 @@ public: std::optional MO = evaluateX86MemoryOperand(Instr); if (!MO) break; - if (MO->BaseRegNum != R1 || MO->ScaleImm != 4 || - MO->IndexRegNum == X86::NoRegister || MO->DispImm != 0 || - MO->SegRegNum != X86::NoRegister) + if (!isIndexed(*MO, R1)) + // POSSIBLE_PIC_JUMP_TABLE break; MovInstr = &Instr; } else { @@ -1986,9 +1998,7 @@ public: std::optional MO = evaluateX86MemoryOperand(Instr); if (!MO) break; - if (MO->BaseRegNum != RegInfo->getProgramCounter() || - MO->IndexRegNum != X86::NoRegister || - MO->SegRegNum != X86::NoRegister || MO->DispExpr == nullptr) + if (!isRIPRel(*MO)) break; MemLocInstr = &Instr; break; @@ -2105,13 +2115,15 @@ public: return IndirectBranchType::POSSIBLE_FIXED_BRANCH; } - if (Type == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE && - (MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister)) - return IndirectBranchType::UNKNOWN; - - if (Type != IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE && - MO->ScaleImm != PtrSize) - return IndirectBranchType::UNKNOWN; + switch (Type) { + case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE: + if (MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister) + return IndirectBranchType::UNKNOWN; + break; + default: + if (MO->ScaleImm != PtrSize) + return IndirectBranchType::UNKNOWN; + } MemLocInstrOut = MemLocInstr; diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp index ba296c10c00ae14169a9e819a07302d3506c7cea..41c89bc8aeba4e7a7d3393bc1b0d0593b414220a 100644 --- a/bolt/lib/Utils/CommandLineOpts.cpp +++ b/bolt/lib/Utils/CommandLineOpts.cpp @@ -179,6 +179,10 @@ cl::opt TimeOpts("time-opts", cl::desc("print time spent in each optimization"), cl::cat(BoltOptCategory)); +cl::opt TimeRewrite("time-rewrite", + cl::desc("print time spent in rewriting passes"), + cl::Hidden, cl::cat(BoltCategory)); + cl::opt UseOldText( "use-old-text", cl::desc("re-use space in old .text if possible (relocation mode)"), diff --git a/bolt/runtime/instr.cpp b/bolt/runtime/instr.cpp index 16e0bbd55f90b1ed373b472fc0d70039b27aba93..d1f8a216badcf2713efab082dbed55952e374f19 100644 --- a/bolt/runtime/instr.cpp +++ b/bolt/runtime/instr.cpp @@ -1245,7 +1245,6 @@ void Graph::computeEdgeFrequencies(const uint64_t *Counters, continue; assert(SpanningTreeNodes[Cur].NumInEdges == 1, "must have 1 parent"); - const uint32_t Parent = SpanningTreeNodes[Cur].InEdges[0].Node; const uint32_t ParentEdge = SpanningTreeNodes[Cur].InEdges[0].ID; // Calculate parent edge freq. @@ -1464,9 +1463,8 @@ void visitCallFlowEntry(CallFlowHashTable::MapEntry &Entry, int FD, int openProfile() { // Build the profile name string by appending our PID char Buf[BufSize]; - char *Ptr = Buf; uint64_t PID = __getpid(); - Ptr = strCopy(Buf, __bolt_instr_filename, BufSize); + char *Ptr = strCopy(Buf, __bolt_instr_filename, BufSize); if (__bolt_instr_use_pid) { Ptr = strCopy(Ptr, ".", BufSize - (Ptr - Buf + 1)); Ptr = intToStr(Ptr, PID, 10); diff --git a/bolt/test/AArch64/Inputs/array_end.lld_script b/bolt/test/AArch64/Inputs/array_end.lld_script index 182c13d370a39ceed6e72a7a281d9f2ccbd41156..bf77c0493a095833ebef80de6b58340a14da7633 100644 --- a/bolt/test/AArch64/Inputs/array_end.lld_script +++ b/bolt/test/AArch64/Inputs/array_end.lld_script @@ -1,4 +1,7 @@ SECTIONS { + .interp : { *(.interp) } + + . = ALIGN(CONSTANT(MAXPAGESIZE)); .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); diff --git a/bolt/test/AArch64/lit.local.cfg b/bolt/test/AArch64/lit.local.cfg index 59fa15a876b5057c398d594fd27ff280f17759cd..9432240469c7b832492d14d52bd0835bd4f647d9 100644 --- a/bolt/test/AArch64/lit.local.cfg +++ b/bolt/test/AArch64/lit.local.cfg @@ -1,7 +1,7 @@ if "AArch64" not in config.root.targets: config.unsupported = True -flags = "--target=aarch64-pc-linux -nostartfiles -nostdlib -ffreestanding" +flags = "--target=aarch64-unknown-linux-gnu -nostartfiles -nostdlib -ffreestanding" config.substitutions.insert(0, ("%cflags", f"%cflags {flags}")) config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}")) diff --git a/bolt/test/CMakeLists.txt b/bolt/test/CMakeLists.txt index 89862fd59eb8ec219914528bfeb2e6cb1d9f0c71..d468ff984840fccd597d2abdaa08ca08826b64db 100644 --- a/bolt/test/CMakeLists.txt +++ b/bolt/test/CMakeLists.txt @@ -56,7 +56,7 @@ list(APPEND BOLT_TEST_DEPS ) add_custom_target(bolt-test-depends DEPENDS ${BOLT_TEST_DEPS}) -set_target_properties(bolt-test-depends PROPERTIES FOLDER "BOLT") +set_target_properties(bolt-test-depends PROPERTIES FOLDER "BOLT/Tests") add_lit_testsuite(check-bolt "Running the BOLT regression tests" ${CMAKE_CURRENT_BINARY_DIR} @@ -64,7 +64,6 @@ add_lit_testsuite(check-bolt "Running the BOLT regression tests" DEPENDS ${BOLT_TEST_DEPS} ARGS ${BOLT_TEST_EXTRA_ARGS} ) -set_target_properties(check-bolt PROPERTIES FOLDER "BOLT") add_lit_testsuites(BOLT ${CMAKE_CURRENT_SOURCE_DIR} PARAMS ${BOLT_TEST_PARAMS} diff --git a/bolt/test/Inputs/lsda.ldscript b/bolt/test/Inputs/lsda.ldscript deleted file mode 100644 index aa608ecd97e8c5cdda5fc404eae2a3fa9ddf456c..0000000000000000000000000000000000000000 --- a/bolt/test/Inputs/lsda.ldscript +++ /dev/null @@ -1,7 +0,0 @@ -SECTIONS { - .text : { *(.text*) } - .gcc_except_table.main : { *(.gcc_except_table*) } - . = 0x20000; - .eh_frame : { *(.eh_frame) } - . = 0x80000; -} diff --git a/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s new file mode 100644 index 0000000000000000000000000000000000000000..c04fb521c75d3280a87479eb2ce301679d62044c --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s @@ -0,0 +1,710 @@ +## clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-4 -gsplit-dwarf -fdebug-compilation-dir='.' +## __attribute__((always_inline)) +## int doStuffOther(int val) { +## if (val) +## ++val; +## return val; +## } +## __attribute__((always_inline)) +## int doStuffOther2(int val) { +## int foo = 3; +## return val + foo; +## } +## +## +## int mainOther(int argc, const char** argv) { +## return doStuffOther(argc) + doStuffOther2(argc);; +## } + + .text + .file "mainOther.cpp" + .section .text._Z12doStuffOtheri,"ax",@progbits + .globl _Z12doStuffOtheri # -- Begin function _Z12doStuffOtheri + .p2align 4, 0x90 + .type _Z12doStuffOtheri,@function +_Z12doStuffOtheri: # @_Z12doStuffOtheri +.Lfunc_begin0: + .file 1 "." "mainOther.cpp" + .loc 1 2 0 # mainOther.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 1 3 8 prologue_end # mainOther.cpp:3:8 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 1 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z12doStuffOtheri.__part.2 + jmp _Z12doStuffOtheri.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,1 +_Z12doStuffOtheri.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z12doStuffOtheri.__part.2 +.LBB_END0_1: + .size _Z12doStuffOtheri.__part.1, .LBB_END0_1-_Z12doStuffOtheri.__part.1 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,2 +_Z12doStuffOtheri.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 11 # mainOther.cpp:5:11 + movl -4(%rbp), %eax + .loc 1 5 4 epilogue_begin is_stmt 0 # mainOther.cpp:5:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z12doStuffOtheri.__part.2, .LBB_END0_2-_Z12doStuffOtheri.__part.2 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits +.Lfunc_end0: + .size _Z12doStuffOtheri, .Lfunc_end0-_Z12doStuffOtheri + # -- End function + .section .text._Z13doStuffOther2i,"ax",@progbits + .globl _Z13doStuffOther2i # -- Begin function _Z13doStuffOther2i + .p2align 4, 0x90 + .type _Z13doStuffOther2i,@function +_Z13doStuffOther2i: # @_Z13doStuffOther2i +.Lfunc_begin1: + .loc 1 8 0 is_stmt 1 # mainOther.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp2: + .loc 1 9 8 prologue_end # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 1 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %eax + .loc 1 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %eax + .loc 1 10 4 epilogue_begin # mainOther.cpp:10:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z13doStuffOther2i, .Lfunc_end1-_Z13doStuffOther2i + # -- End function + .section .text._Z9mainOtheriPPKc,"ax",@progbits + .globl _Z9mainOtheriPPKc # -- Begin function _Z9mainOtheriPPKc + .p2align 4, 0x90 + .type _Z9mainOtheriPPKc,@function +_Z9mainOtheriPPKc: # @_Z9mainOtheriPPKc +.Lfunc_begin2: + .loc 1 14 0 is_stmt 1 # mainOther.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -16(%rbp) + movq %rsi, -24(%rbp) +.Ltmp3: + .loc 1 15 27 prologue_end # mainOther.cpp:15:27 + movl -16(%rbp), %eax + movl %eax, -12(%rbp) +.Ltmp4: + .loc 1 3 8 # mainOther.cpp:3:8 + cmpl $0, -12(%rbp) +.Ltmp5: + .loc 1 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z9mainOtheriPPKc.__part.2 + jmp _Z9mainOtheriPPKc.__part.1 +.LBB_END2_0: + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,3 +_Z9mainOtheriPPKc.__part.1: # %if.then.i + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -12(%rbp), %eax + addl $1, %eax + movl %eax, -12(%rbp) + jmp _Z9mainOtheriPPKc.__part.2 +.LBB_END2_1: + .size _Z9mainOtheriPPKc.__part.1, .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,4 +_Z9mainOtheriPPKc.__part.2: # %_Z12doStuffOtheri.exit + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 11 # mainOther.cpp:5:11 + movl -12(%rbp), %eax +.Ltmp6: + .loc 1 15 49 # mainOther.cpp:15:49 + movl -16(%rbp), %ecx + movl %ecx, -4(%rbp) +.Ltmp7: + .loc 1 9 8 # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 1 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %ecx + .loc 1 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %ecx +.Ltmp8: + .loc 1 15 33 is_stmt 1 # mainOther.cpp:15:33 + addl %ecx, %eax + .loc 1 15 6 epilogue_begin is_stmt 0 # mainOther.cpp:15:6 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END2_2: + .size _Z9mainOtheriPPKc.__part.2, .LBB_END2_2-_Z9mainOtheriPPKc.__part.2 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits +.Lfunc_end2: + .size _Z9mainOtheriPPKc, .Lfunc_end2-_Z9mainOtheriPPKc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\262B" # DW_AT_GNU_ranges_base + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x29 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lskel_string0 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + .long .Lskel_string1 # DW_AT_GNU_dwo_name + .quad -1082921489565291703 # DW_AT_GNU_dwo_id + .long .debug_ranges # DW_AT_GNU_ranges_base + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges3 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_GNU_addr_base +.Ldebug_info_end0: + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad 0 + .quad 0 +.Ldebug_ranges1: + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 +.Ldebug_ranges2: + .quad .Ltmp4 + .quad .Lfunc_end2 + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .Ltmp6 + .quad 0 + .quad 0 +.Ldebug_ranges3: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 + .section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "." # string offset=0 +.Lskel_string1: + .asciz "mainOther.dwo" # string offset=2 + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "_Z12doStuffOtheri" # string offset=0 +.Linfo_string1: + .asciz "doStuffOther" # string offset=18 +.Linfo_string2: + .asciz "int" # string offset=31 +.Linfo_string3: + .asciz "val" # string offset=35 +.Linfo_string4: + .asciz "_Z13doStuffOther2i" # string offset=39 +.Linfo_string5: + .asciz "doStuffOther2" # string offset=58 +.Linfo_string6: + .asciz "foo" # string offset=72 +.Linfo_string7: + .asciz "_Z9mainOtheriPPKc" # string offset=76 +.Linfo_string8: + .asciz "mainOther" # string offset=94 +.Linfo_string9: + .asciz "argc" # string offset=104 +.Linfo_string10: + .asciz "argv" # string offset=109 +.Linfo_string11: + .asciz "char" # string offset=114 +.Linfo_string12: + .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" # string offset=119 +.Linfo_string13: + .asciz "mainOther.cpp" # string offset=223 +.Linfo_string14: + .asciz "mainOther.dwo" # string offset=237 + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .long 18 + .long 31 + .long 35 + .long 39 + .long 58 + .long 72 + .long 76 + .long 94 + .long 104 + .long 109 + .long 114 + .long 119 + .long 223 + .long 237 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0xde DW_TAG_compile_unit + .byte 12 # DW_AT_producer + .short 33 # DW_AT_language + .byte 13 # DW_AT_name + .byte 14 # DW_AT_GNU_dwo_name + .quad -1082921489565291703 # DW_AT_GNU_dwo_id + .byte 2 # Abbrev [2] 0x19:0x14 DW_TAG_subprogram + .long .Ldebug_ranges0-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long 74 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x24:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x2d:0x1d DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 97 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x39:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x41:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x4a:0x13 DW_TAG_subprogram + .byte 0 # DW_AT_linkage_name + .byte 1 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x54:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x5d:0x4 DW_TAG_base_type + .byte 2 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x61:0x1b DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x6b:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 9 # Abbrev [9] 0x73:0x8 DW_TAG_variable + .byte 6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x7c:0x59 DW_TAG_subprogram + .long .Ldebug_ranges1-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_linkage_name + .byte 8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 11 # Abbrev [11] 0x8b:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 112 + .byte 9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 11 # Abbrev [11] 0x96:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 104 + .byte 10 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 213 # DW_AT_type + .byte 12 # Abbrev [12] 0xa1:0x15 DW_TAG_inlined_subroutine + .long 74 # DW_AT_abstract_origin + .long .Ldebug_ranges2-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 14 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xad:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 13 # Abbrev [13] 0xb6:0x1e DW_TAG_inlined_subroutine + .long 97 # DW_AT_abstract_origin + .byte 7 # DW_AT_low_pc + .long .Ltmp8-.Ltmp7 # DW_AT_high_pc + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 35 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xc3:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0xcb:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 14 # Abbrev [14] 0xd5:0x5 DW_TAG_pointer_type + .long 218 # DW_AT_type + .byte 14 # Abbrev [14] 0xda:0x5 DW_TAG_pointer_type + .long 223 # DW_AT_type + .byte 15 # Abbrev [15] 0xdf:0x5 DW_TAG_const_type + .long 228 # DW_AT_type + .byte 8 # Abbrev [8] 0xe4:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\260B" # DW_AT_GNU_dwo_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 15 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_addr,"",@progbits +.Laddr_table_base0: + .quad _Z12doStuffOtheri.__part.1 + .quad _Z12doStuffOtheri.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + .quad _Z9mainOtheriPPKc.__part.1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .Lfunc_begin2 + .quad .Ltmp7 + .section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info +.LpubNames_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 74 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther" # External Name + .long 97 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther2" # External Name + .long 124 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "mainOther" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_gnu_pubtypes,"",@progbits + .long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info +.LpubTypes_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 93 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "int" # External Name + .long 228 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "char" # External Name + .long 0 # End Mark +.LpubTypes_end0: + .ident "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf4-subprogram-multiple-ranges-other.s b/bolt/test/X86/Inputs/dwarf4-subprogram-multiple-ranges-other.s new file mode 100644 index 0000000000000000000000000000000000000000..0745b2f4cef83e5af67f3196a1662a61ba9b7ac0 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-subprogram-multiple-ranges-other.s @@ -0,0 +1,335 @@ +## clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-4 +## int doStuffOther(int val) { +## if (val) +## ++val; +## return val; +## } +## +## int mainOther(int argc, const char** argv) { +## return doStuffOther(argc); +## } + .text + .file "mainOther.cpp" + .section .text._Z12doStuffOtheri,"ax",@progbits + .globl _Z12doStuffOtheri # -- Begin function _Z12doStuffOtheri + .p2align 4, 0x90 + .type _Z12doStuffOtheri,@function +_Z12doStuffOtheri: # @_Z12doStuffOtheri +.Lfunc_begin0: + .file 1 "." "mainOther.cpp" + .loc 1 1 0 # mainOther.cpp:1:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 1 2 8 prologue_end # mainOther.cpp:2:8 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 1 2 8 is_stmt 0 # mainOther.cpp:2:8 + je _Z12doStuffOtheri.__part.2 + jmp _Z12doStuffOtheri.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,1 +_Z12doStuffOtheri.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 3 6 is_stmt 1 # mainOther.cpp:3:6 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z12doStuffOtheri.__part.2 +.LBB_END0_1: + .size _Z12doStuffOtheri.__part.1, .LBB_END0_1-_Z12doStuffOtheri.__part.1 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,2 +_Z12doStuffOtheri.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 11 # mainOther.cpp:4:11 + movl -4(%rbp), %eax + .loc 1 4 4 epilogue_begin is_stmt 0 # mainOther.cpp:4:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z12doStuffOtheri.__part.2, .LBB_END0_2-_Z12doStuffOtheri.__part.2 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits +.Lfunc_end0: + .size _Z12doStuffOtheri, .Lfunc_end0-_Z12doStuffOtheri + # -- End function + .section .text._Z9mainOtheriPPKc,"ax",@progbits + .globl _Z9mainOtheriPPKc # -- Begin function _Z9mainOtheriPPKc + .p2align 4, 0x90 + .type _Z9mainOtheriPPKc,@function +_Z9mainOtheriPPKc: # @_Z9mainOtheriPPKc +.Lfunc_begin1: + .loc 1 7 0 is_stmt 1 # mainOther.cpp:7:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl %edi, -4(%rbp) + movq %rsi, -16(%rbp) +.Ltmp2: + .loc 1 8 27 prologue_end # mainOther.cpp:8:27 + movl -4(%rbp), %edi + .loc 1 8 14 is_stmt 0 # mainOther.cpp:8:14 + callq _Z12doStuffOtheri + .loc 1 8 6 epilogue_begin # mainOther.cpp:8:6 + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z9mainOtheriPPKc, .Lfunc_end1-_Z9mainOtheriPPKc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 14 # DW_FORM_strp + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 14 # DW_FORM_strp + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x9b DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 33 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges1 # DW_AT_ranges + .byte 2 # Abbrev [2] 0x2a:0x24 DW_TAG_subprogram + .long .Ldebug_ranges0 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long .Linfo_string3 # DW_AT_linkage_name + .long .Linfo_string4 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 136 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x3f:0xe DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long .Linfo_string8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 136 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x4e:0x3a DW_TAG_subprogram + .quad .Lfunc_begin1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long .Linfo_string6 # DW_AT_linkage_name + .long .Linfo_string7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 136 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x6b:0xe DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long .Linfo_string9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 136 # DW_AT_type + .byte 3 # Abbrev [3] 0x79:0xe DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 112 + .long .Linfo_string10 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 143 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 5 # Abbrev [5] 0x88:0x7 DW_TAG_base_type + .long .Linfo_string5 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x8f:0x5 DW_TAG_pointer_type + .long 148 # DW_AT_type + .byte 6 # Abbrev [6] 0x94:0x5 DW_TAG_pointer_type + .long 153 # DW_AT_type + .byte 7 # Abbrev [7] 0x99:0x5 DW_TAG_const_type + .long 158 # DW_AT_type + .byte 5 # Abbrev [5] 0x9e:0x7 DW_TAG_base_type + .long .Linfo_string11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad 0 + .quad 0 +.Ldebug_ranges1: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad 0 + .quad 0 + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" # string offset=0 +.Linfo_string1: + .asciz "mainOther.cpp" # string offset=104 +.Linfo_string2: + .asciz "." # string offset=118 +.Linfo_string3: + .asciz "_Z12doStuffOtheri" # string offset=120 +.Linfo_string4: + .asciz "doStuffOther" # string offset=138 +.Linfo_string5: + .asciz "int" # string offset=151 +.Linfo_string6: + .asciz "_Z9mainOtheriPPKc" # string offset=155 +.Linfo_string7: + .asciz "mainOther" # string offset=173 +.Linfo_string8: + .asciz "val" # string offset=183 +.Linfo_string9: + .asciz "argc" # string offset=187 +.Linfo_string10: + .asciz "argv" # string offset=192 +.Linfo_string11: + .asciz "char" # string offset=197 + .ident "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" + .section ".note.GNU-stack","",@progbits + .addrsig + .addrsig_sym _Z12doStuffOtheri + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-other.s b/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-other.s new file mode 100644 index 0000000000000000000000000000000000000000..84a30b09c2f1d22bc14d42f7850dd65344b814c4 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-other.s @@ -0,0 +1,753 @@ +## clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-5 -gsplit-dwarf -fdebug-compilation-dir='.' +## __attribute__((always_inline)) +## int doStuffOther(int val) { +## if (val) +## ++val; +## return val; +## } +## __attribute__((always_inline)) +## int doStuffOther2(int val) { +## int foo = 3; +## return val + foo; +## } +## +## +## int mainOther(int argc, const char** argv) { +## return doStuffOther(argc) + doStuffOther2(argc);; +## } + .text + .file "mainOther.cpp" + .section .text._Z12doStuffOtheri,"ax",@progbits + .globl _Z12doStuffOtheri # -- Begin function _Z12doStuffOtheri + .p2align 4, 0x90 + .type _Z12doStuffOtheri,@function +_Z12doStuffOtheri: # @_Z12doStuffOtheri +.Lfunc_begin0: + .file 0 "." "mainOther.cpp" md5 0x60d62a5a58057785ee2656b69563989b + .loc 0 2 0 # mainOther.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 0 3 8 prologue_end # mainOther.cpp:3:8 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 0 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z12doStuffOtheri.__part.2 + jmp _Z12doStuffOtheri.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,1 +_Z12doStuffOtheri.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z12doStuffOtheri.__part.2 +.LBB_END0_1: + .size _Z12doStuffOtheri.__part.1, .LBB_END0_1-_Z12doStuffOtheri.__part.1 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,2 +_Z12doStuffOtheri.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 5 11 # mainOther.cpp:5:11 + movl -4(%rbp), %eax + .loc 0 5 4 epilogue_begin is_stmt 0 # mainOther.cpp:5:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z12doStuffOtheri.__part.2, .LBB_END0_2-_Z12doStuffOtheri.__part.2 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits +.Lfunc_end0: + .size _Z12doStuffOtheri, .Lfunc_end0-_Z12doStuffOtheri + # -- End function + .section .text._Z13doStuffOther2i,"ax",@progbits + .globl _Z13doStuffOther2i # -- Begin function _Z13doStuffOther2i + .p2align 4, 0x90 + .type _Z13doStuffOther2i,@function +_Z13doStuffOther2i: # @_Z13doStuffOther2i +.Lfunc_begin1: + .loc 0 8 0 is_stmt 1 # mainOther.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp2: + .loc 0 9 8 prologue_end # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 0 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %eax + .loc 0 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %eax + .loc 0 10 4 epilogue_begin # mainOther.cpp:10:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z13doStuffOther2i, .Lfunc_end1-_Z13doStuffOther2i + # -- End function + .section .text._Z9mainOtheriPPKc,"ax",@progbits + .globl _Z9mainOtheriPPKc # -- Begin function _Z9mainOtheriPPKc + .p2align 4, 0x90 + .type _Z9mainOtheriPPKc,@function +_Z9mainOtheriPPKc: # @_Z9mainOtheriPPKc +.Lfunc_begin2: + .loc 0 14 0 is_stmt 1 # mainOther.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -16(%rbp) + movq %rsi, -24(%rbp) +.Ltmp3: + .loc 0 15 27 prologue_end # mainOther.cpp:15:27 + movl -16(%rbp), %eax + movl %eax, -12(%rbp) +.Ltmp4: + .loc 0 3 8 # mainOther.cpp:3:8 + cmpl $0, -12(%rbp) +.Ltmp5: + .loc 0 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z9mainOtheriPPKc.__part.2 + jmp _Z9mainOtheriPPKc.__part.1 +.LBB_END2_0: + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,3 +_Z9mainOtheriPPKc.__part.1: # %if.then.i + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -12(%rbp), %eax + addl $1, %eax + movl %eax, -12(%rbp) + jmp _Z9mainOtheriPPKc.__part.2 +.LBB_END2_1: + .size _Z9mainOtheriPPKc.__part.1, .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,4 +_Z9mainOtheriPPKc.__part.2: # %_Z12doStuffOtheri.exit + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 5 11 # mainOther.cpp:5:11 + movl -12(%rbp), %eax +.Ltmp6: + .loc 0 15 49 # mainOther.cpp:15:49 + movl -16(%rbp), %ecx + movl %ecx, -4(%rbp) +.Ltmp7: + .loc 0 9 8 # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 0 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %ecx + .loc 0 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %ecx +.Ltmp8: + .loc 0 15 33 is_stmt 1 # mainOther.cpp:15:33 + addl %ecx, %eax + .loc 0 15 6 epilogue_begin is_stmt 0 # mainOther.cpp:15:6 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END2_2: + .size _Z9mainOtheriPPKc.__part.2, .LBB_END2_2-_Z9mainOtheriPPKc.__part.2 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits +.Lfunc_end2: + .size _Z9mainOtheriPPKc, .Lfunc_end2-_Z9mainOtheriPPKc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 74 # DW_TAG_skeleton_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .byte 118 # DW_AT_dwo_name + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 116 # DW_AT_rnglists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 4 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad -1082921489565291703 + .byte 1 # Abbrev [1] 0x14:0x1c DW_TAG_skeleton_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 0 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + .byte 1 # DW_AT_dwo_name + .quad 0 # DW_AT_low_pc + .byte 0 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lrnglists_table_base0 # DW_AT_rnglists_base +.Ldebug_info_end0: + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges4-.Lrnglists_table_base0 +.Ldebug_ranges4: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z12doStuffOtheri.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z12doStuffOtheri.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 3 # DW_RLE_startx_length + .byte 3 # start index + .uleb128 .Lfunc_end1-.Lfunc_begin1 # length + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .LBB_END2_2-_Z9mainOtheriPPKc.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 6 # start index + .uleb128 .Lfunc_end2-.Lfunc_begin2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_str_offsets,"",@progbits + .long 12 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "." # string offset=0 +.Lskel_string1: + .asciz "mainOther.dwo" # string offset=2 + .section .debug_str_offsets,"",@progbits + .long .Lskel_string0 + .long .Lskel_string1 + .section .debug_str_offsets.dwo,"e",@progbits + .long 64 # Length of String Offsets Set + .short 5 + .short 0 + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "_Z12doStuffOtheri" # string offset=0 +.Linfo_string1: + .asciz "doStuffOther" # string offset=18 +.Linfo_string2: + .asciz "int" # string offset=31 +.Linfo_string3: + .asciz "val" # string offset=35 +.Linfo_string4: + .asciz "_Z13doStuffOther2i" # string offset=39 +.Linfo_string5: + .asciz "doStuffOther2" # string offset=58 +.Linfo_string6: + .asciz "foo" # string offset=72 +.Linfo_string7: + .asciz "_Z9mainOtheriPPKc" # string offset=76 +.Linfo_string8: + .asciz "mainOther" # string offset=94 +.Linfo_string9: + .asciz "argc" # string offset=104 +.Linfo_string10: + .asciz "argv" # string offset=109 +.Linfo_string11: + .asciz "char" # string offset=114 +.Linfo_string12: + .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" # string offset=119 +.Linfo_string13: + .asciz "mainOther.cpp" # string offset=223 +.Linfo_string14: + .asciz "mainOther.dwo" # string offset=237 + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .long 18 + .long 31 + .long 35 + .long 39 + .long 58 + .long 72 + .long 76 + .long 94 + .long 104 + .long 109 + .long 114 + .long 119 + .long 223 + .long 237 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 5 # DWARF version number + .byte 5 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad -1082921489565291703 + .byte 1 # Abbrev [1] 0x14:0xc7 DW_TAG_compile_unit + .byte 12 # DW_AT_producer + .short 33 # DW_AT_language + .byte 13 # DW_AT_name + .byte 14 # DW_AT_dwo_name + .byte 2 # Abbrev [2] 0x1a:0x11 DW_TAG_subprogram + .byte 0 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long 72 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x22:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 81 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x2b:0x1d DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 94 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x37:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 103 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x3f:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 111 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x48:0x12 DW_TAG_subprogram + .byte 0 # DW_AT_linkage_name + .byte 1 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + # DW_AT_inline + .byte 7 # Abbrev [7] 0x51:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x5a:0x4 DW_TAG_base_type + .byte 2 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x5e:0x1a DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + # DW_AT_inline + .byte 7 # Abbrev [7] 0x67:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 9 # Abbrev [9] 0x6f:0x8 DW_TAG_variable + .byte 6 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x78:0x4f DW_TAG_subprogram + .byte 1 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_linkage_name + .byte 8 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + .byte 11 # Abbrev [11] 0x84:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 112 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 11 # Abbrev [11] 0x8f:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 104 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 199 # DW_AT_type + .byte 12 # Abbrev [12] 0x9a:0x12 DW_TAG_inlined_subroutine + .long 72 # DW_AT_abstract_origin + .byte 2 # DW_AT_ranges + .byte 0 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 14 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xa3:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .long 81 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 12 # Abbrev [12] 0xac:0x1a DW_TAG_inlined_subroutine + .long 94 # DW_AT_abstract_origin + .byte 3 # DW_AT_ranges + .byte 0 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 35 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xb5:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 103 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0xbd:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 111 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 13 # Abbrev [13] 0xc7:0x5 DW_TAG_pointer_type + .long 204 # DW_AT_type + .byte 13 # Abbrev [13] 0xcc:0x5 DW_TAG_pointer_type + .long 209 # DW_AT_type + .byte 14 # Abbrev [14] 0xd1:0x5 DW_TAG_const_type + .long 214 # DW_AT_type + .byte 8 # Abbrev [8] 0xd6:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 118 # DW_AT_dwo_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 33 # DW_FORM_implicit_const + .byte 1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_rnglists.dwo,"e",@progbits + .long .Ldebug_list_header_end1-.Ldebug_list_header_start1 # Length +.Ldebug_list_header_start1: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 4 # Offset entry count +.Lrnglists_dwo_table_base0: + .long .Ldebug_ranges0-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges1-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges2-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges3-.Lrnglists_dwo_table_base0 +.Ldebug_ranges0: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z12doStuffOtheri.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z12doStuffOtheri.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges1: + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .LBB_END2_2-_Z9mainOtheriPPKc.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 6 # start index + .uleb128 .Lfunc_end2-.Lfunc_begin2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges2: + .byte 1 # DW_RLE_base_addressx + .byte 6 # base address index + .byte 4 # DW_RLE_offset_pair + .uleb128 .Ltmp4-.Lfunc_begin2 # starting offset + .uleb128 .Lfunc_end2-.Lfunc_begin2 # ending offset + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .Ltmp6-_Z9mainOtheriPPKc.__part.2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges3: + .byte 1 # DW_RLE_base_addressx + .byte 5 # base address index + .byte 4 # DW_RLE_offset_pair + .uleb128 .Ltmp7-_Z9mainOtheriPPKc.__part.2 # starting offset + .uleb128 .Ltmp8-_Z9mainOtheriPPKc.__part.2 # ending offset + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end1: + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad _Z12doStuffOtheri.__part.1 + .quad _Z12doStuffOtheri.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + .quad _Z9mainOtheriPPKc.__part.1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .Lfunc_begin2 +.Ldebug_addr_end0: + .section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info +.LpubNames_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 48 # Compilation Unit Length + .long 72 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther" # External Name + .long 94 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther2" # External Name + .long 120 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "mainOther" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_gnu_pubtypes,"",@progbits + .long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info +.LpubTypes_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 48 # Compilation Unit Length + .long 90 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "int" # External Name + .long 214 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "char" # External Name + .long 0 # End Mark +.LpubTypes_end0: + .ident "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf5-subprogram-multiple-ranges-other.s b/bolt/test/X86/Inputs/dwarf5-subprogram-multiple-ranges-other.s new file mode 100644 index 0000000000000000000000000000000000000000..6586fc73ed8daffb6f2003fd599bb35f04d1afce --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf5-subprogram-multiple-ranges-other.s @@ -0,0 +1,390 @@ +## clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-5 +## int doStuffOther(int val) { +## if (val) +## ++val; +## return val; +## } +## +## int mainOther(int argc, const char** argv) { +## return doStuffOther(argc); +## } + .text + .file "mainOther.cpp" + .section .text._Z12doStuffOtheri,"ax",@progbits + .globl _Z12doStuffOtheri # -- Begin function _Z12doStuffOtheri + .p2align 4, 0x90 + .type _Z12doStuffOtheri,@function +_Z12doStuffOtheri: # @_Z12doStuffOtheri +.Lfunc_begin0: + .file 0 "." "mainOther.cpp" md5 0xe43cc8133fbf67674318eacbcc46a59e + .loc 0 1 0 # mainOther.cpp:1:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 0 2 8 prologue_end # mainOther.cpp:2:8 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 0 2 8 is_stmt 0 # mainOther.cpp:2:8 + je _Z12doStuffOtheri.__part.2 + jmp _Z12doStuffOtheri.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,1 +_Z12doStuffOtheri.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 3 6 is_stmt 1 # mainOther.cpp:3:6 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z12doStuffOtheri.__part.2 +.LBB_END0_1: + .size _Z12doStuffOtheri.__part.1, .LBB_END0_1-_Z12doStuffOtheri.__part.1 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,2 +_Z12doStuffOtheri.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 4 11 # mainOther.cpp:4:11 + movl -4(%rbp), %eax + .loc 0 4 4 epilogue_begin is_stmt 0 # mainOther.cpp:4:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z12doStuffOtheri.__part.2, .LBB_END0_2-_Z12doStuffOtheri.__part.2 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits +.Lfunc_end0: + .size _Z12doStuffOtheri, .Lfunc_end0-_Z12doStuffOtheri + # -- End function + .section .text._Z9mainOtheriPPKc,"ax",@progbits + .globl _Z9mainOtheriPPKc # -- Begin function _Z9mainOtheriPPKc + .p2align 4, 0x90 + .type _Z9mainOtheriPPKc,@function +_Z9mainOtheriPPKc: # @_Z9mainOtheriPPKc +.Lfunc_begin1: + .loc 0 7 0 is_stmt 1 # mainOther.cpp:7:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl %edi, -4(%rbp) + movq %rsi, -16(%rbp) +.Ltmp2: + .loc 0 8 27 prologue_end # mainOther.cpp:8:27 + movl -4(%rbp), %edi + .loc 0 8 14 is_stmt 0 # mainOther.cpp:8:14 + callq _Z12doStuffOtheri + .loc 0 8 6 epilogue_begin # mainOther.cpp:8:6 + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z9mainOtheriPPKc, .Lfunc_end1-_Z9mainOtheriPPKc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 116 # DW_AT_rnglists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x76 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .quad 0 # DW_AT_low_pc + .byte 1 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lrnglists_table_base0 # DW_AT_rnglists_base + .byte 2 # Abbrev [2] 0x2b:0x18 DW_TAG_subprogram + .byte 0 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 3 # DW_AT_linkage_name + .byte 4 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 106 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x37:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .byte 8 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 106 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x43:0x27 DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 6 # DW_AT_linkage_name + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 106 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x53:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 106 # DW_AT_type + .byte 3 # Abbrev [3] 0x5e:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 112 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 110 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 5 # Abbrev [5] 0x6a:0x4 DW_TAG_base_type + .byte 5 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x6e:0x5 DW_TAG_pointer_type + .long 115 # DW_AT_type + .byte 6 # Abbrev [6] 0x73:0x5 DW_TAG_pointer_type + .long 120 # DW_AT_type + .byte 7 # Abbrev [7] 0x78:0x5 DW_TAG_const_type + .long 125 # DW_AT_type + .byte 5 # Abbrev [5] 0x7d:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 2 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges0-.Lrnglists_table_base0 + .long .Ldebug_ranges1-.Lrnglists_table_base0 +.Ldebug_ranges0: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z12doStuffOtheri.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z12doStuffOtheri.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges1: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z12doStuffOtheri.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z12doStuffOtheri.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 3 # DW_RLE_startx_length + .byte 3 # start index + .uleb128 .Lfunc_end1-.Lfunc_begin1 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_str_offsets,"",@progbits + .long 52 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" # string offset=0 +.Linfo_string1: + .asciz "mainOther.cpp" # string offset=104 +.Linfo_string2: + .asciz "." # string offset=118 +.Linfo_string3: + .asciz "_Z12doStuffOtheri" # string offset=120 +.Linfo_string4: + .asciz "doStuffOther" # string offset=138 +.Linfo_string5: + .asciz "int" # string offset=151 +.Linfo_string6: + .asciz "_Z9mainOtheriPPKc" # string offset=155 +.Linfo_string7: + .asciz "mainOther" # string offset=173 +.Linfo_string8: + .asciz "val" # string offset=183 +.Linfo_string9: + .asciz "argc" # string offset=187 +.Linfo_string10: + .asciz "argv" # string offset=192 +.Linfo_string11: + .asciz "char" # string offset=197 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .long .Linfo_string11 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad _Z12doStuffOtheri.__part.1 + .quad _Z12doStuffOtheri.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .ident "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" + .section ".note.GNU-stack","",@progbits + .addrsig + .addrsig_sym _Z12doStuffOtheri + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/addr32.s b/bolt/test/X86/addr32.s index 1f926c20c7ba8d078407e5b86b7cec6cd82525af..03d62690319179908cd97f59637d2c28547af1e3 100644 --- a/bolt/test/X86/addr32.s +++ b/bolt/test/X86/addr32.s @@ -1,4 +1,4 @@ -# Check that we don't accidentally strip addr32 prefix +## Check that we don't accidentally strip addr32 prefix # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: ld.lld %t.o -o %t.exe -nostdlib diff --git a/bolt/test/X86/asm-func-debug.test b/bolt/test/X86/asm-func-debug.test index 095ae92da07133836cfdf518716e00ae33bc64dc..3c65051b833d7129f17fd5fdcbad82bd95cf1b37 100644 --- a/bolt/test/X86/asm-func-debug.test +++ b/bolt/test/X86/asm-func-debug.test @@ -1,13 +1,13 @@ -# Verify that we update DW_TAG_compile_unit' ranges and .debug_aranges -# for assembly function that doesn't have corresponding DIE. -# -# The input test case foo() contains nops that we remove. +## Verify that we update DW_TAG_compile_unit' ranges and .debug_aranges +## for assembly function that doesn't have corresponding DIE. +## +## The input test case foo() contains nops that we remove. RUN: %clang %cflags -gdwarf-5 -no-pie %p/../Inputs/asm_foo.s %p/../Inputs/asm_main.c -o %t.exe RUN: llvm-bolt %t.exe -o %t --update-debug-sections RUN: llvm-dwarfdump -all %t | FileCheck %s -# Check ranges were created/updated for asm compile unit +## Check ranges were created/updated for asm compile unit CHECK: 0x0000000c: DW_TAG_compile_unit CHECK-NEXT: DW_AT_stmt_list (0x00000000) CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) @@ -16,11 +16,11 @@ CHECK-NEXT: [0x0000000000[[#%x,ADDR:]], CHECK-SAME: 0x0000000000[[#ADDR+1]])) CHECK-NEXT: DW_AT_name ("{{.*}}asm_foo.s") -# Check .debug_aranges was updated for asm module +## Check .debug_aranges was updated for asm module CHECK: .debug_aranges contents: CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00 CHECK-NEXT: [0x0000000000[[#ADDR]], 0x0000000000[[#ADDR+1]]) -# Check line number info was updated +## Check line number info was updated CHECK: 0x0000000000[[#ADDR]] 13 0 0 0 0 0 is_stmt CHECK-NEXT: 0x0000000000[[#ADDR+1]] 13 0 0 0 0 0 is_stmt end_sequence diff --git a/bolt/test/X86/avx512-trap.test b/bolt/test/X86/avx512-trap.test index 68a0fbc8ff52cdc3807a682814ae9b608fb77d36..93b02f4397cc8f1a6b36f0da21ab39557708203c 100644 --- a/bolt/test/X86/avx512-trap.test +++ b/bolt/test/X86/avx512-trap.test @@ -1,5 +1,5 @@ -# Check that BOLT inserts trap instruction at entry to functions that use AVX-512. -# Check that AVX-512 instruction is updated correctly when -trap-avx512=0 is passed. +## Check that BOLT inserts trap instruction at entry to functions that use AVX-512. +## Check that AVX-512 instruction is updated correctly when -trap-avx512=0 is passed. RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-unknown -o %t.o \ RUN: %S/Inputs/avx512.s @@ -17,11 +17,11 @@ RUN: FileCheck %s --check-prefix=CHECK-DIS-NO-TRAP CHECK: BOLT-WARNING: 1 function will trap on entry -# Check that we have two ud2 instructions - one per entry. +## Check that we have two ud2 instructions - one per entry. CHECK-DIS: use_avx512 CHECK-DIS-NEXT: ud2 CHECK-DIS-NEXT: ud2 -# Check that we generate correct AVX-512 +## Check that we generate correct AVX-512 CHECK-DIS-NO-TRAP: use_avx512 -CHECK-DIS-NO-TRAP: 62 e2 f5 70 2c da vscalefpd +CHECK-DIS-NO-TRAP: 62 e2 f5 70 2c da vscalefpd diff --git a/bolt/test/X86/bb-with-two-tail-calls.s b/bolt/test/X86/bb-with-two-tail-calls.s index b6703e352ff4bfdd6a29cfc74343c745b826fde6..71807510527f9a23b45ab4a413363beb61214b8d 100644 --- a/bolt/test/X86/bb-with-two-tail-calls.s +++ b/bolt/test/X86/bb-with-two-tail-calls.s @@ -1,5 +1,5 @@ -# This reproduces a bug with dynostats when trying to compute branch stats -# at a block with two tails calls (one conditional and one unconditional). +## This reproduces a bug with dynostats when trying to compute branch stats +## at a block with two tails calls (one conditional and one unconditional). # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ # RUN: %s -o %t.o @@ -8,11 +8,21 @@ # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib # RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata --lite=0 --dyno-stats \ # RUN: --print-sctc --print-only=_start -enable-bat 2>&1 | FileCheck %s +# RUN: llvm-objdump --syms %t.out > %t.log +# RUN: llvm-bat-dump %t.out --dump-all >> %t.log +# RUN: FileCheck %s --input-file %t.log --check-prefix=CHECK-BAT + # CHECK-NOT: Assertion `BranchInfo.size() == 2 && "could only be called for blocks with 2 successors"' failed. # Two tail calls in the same basic block after SCTC: # CHECK: {{.*}}: ja {{.*}} # TAILCALL # Offset: 7 # CTCTakenCount: 4 # CHECK-NEXT: {{.*}}: jmp {{.*}} # TAILCALL # Offset: 13 +## Confirm that a deleted basic block is emitted at function end offset (0xe) +# CHECK-BAT: [[#%x,ADDR:]] g .text [[#%x,SIZE:]] _start +# CHECK-BAT: Function Address: 0x[[#%x,ADDR]] +# CHECK-BAT: 0x[[#%x,SIZE]] +# CHECK-BAT: NumBlocks: 5 + .globl _start _start: je x diff --git a/bolt/test/X86/block-reordering.test b/bolt/test/X86/block-reordering.test index f3a3390e27cb97e47988df59194d7263b3010a13..526467f996b074096c203d336532e9df4158570c 100644 --- a/bolt/test/X86/block-reordering.test +++ b/bolt/test/X86/block-reordering.test @@ -1,5 +1,5 @@ -# Tests whether llvm-bolt is able to reorder blocks and fix branches -# according to the new function layout. +## Tests whether llvm-bolt is able to reorder blocks and fix branches +## according to the new function layout. RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --data %p/Inputs/blarge.fdata \ @@ -46,4 +46,3 @@ CHECK: Exec Count : 0 CHECK: Predecessors: .Ltmp{{.*}} CHECK: {{.*}}: movq %rax, (%rsi) CHECK: {{.*}}: retq - diff --git a/bolt/test/X86/bolt-address-translation-internal-call.test b/bolt/test/X86/bolt-address-translation-internal-call.test index 24cb635e13e9830e4a0f103b6aadcb83426cbc97..f20aeb67725fcc4171481d903594385cd7723163 100644 --- a/bolt/test/X86/bolt-address-translation-internal-call.test +++ b/bolt/test/X86/bolt-address-translation-internal-call.test @@ -1,8 +1,8 @@ -# This checks for an issue with internal calls and BAT (BOLT address -# translation). BAT needs to map every output block back to an input -# block, but passes that introduce new blocks (such as validate -# internal calls) might create new blocks without a mapping to an -# input block. +## This checks for an issue with internal calls and BAT (BOLT address +## translation). BAT needs to map every output block back to an input +## block, but passes that introduce new blocks (such as validate +## internal calls) might create new blocks without a mapping to an +## input block. # REQUIRES: x86_64-linux,bolt-runtime diff --git a/bolt/test/X86/bolt-address-translation-yaml.test b/bolt/test/X86/bolt-address-translation-yaml.test index e21513b7dfe592cb5a2bc14f6aab74564440259a..3778891c8d9160d29e58030571e672be9dd320f9 100644 --- a/bolt/test/X86/bolt-address-translation-yaml.test +++ b/bolt/test/X86/bolt-address-translation-yaml.test @@ -1,11 +1,11 @@ -# Check new BAT format containing hashes for YAML profile. +## Check new BAT format containing hashes for YAML profile. RUN: yaml2obj %p/Inputs/blarge_new.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.out --pa -p %p/Inputs/blarge_new.preagg.txt \ RUN: --reorder-blocks=ext-tsp --split-functions --split-strategy=cdsplit \ RUN: --reorder-functions=cdsort --enable-bat --dyno-stats --skip-funcs=main \ RUN: 2>&1 | FileCheck --check-prefix WRITE-BAT-CHECK %s -# Check that branch with entry in BAT is accounted for. +## Check that branch with entry in BAT is accounted for. RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat_branchentry.preagg.txt \ RUN: -w %t.yaml -o %t.fdata RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o %t.null @@ -15,7 +15,7 @@ BRANCHENTRY-YAML-CHECK: - name: SolveCubic BRANCHENTRY-YAML-CHECK: bid: 0 BRANCHENTRY-YAML-CHECK: hash: 0x700F19D24600000 BRANCHENTRY-YAML-CHECK-NEXT: succ: [ { bid: 7, cnt: 1 } -# Check that the order is correct between BAT YAML and FDATA->YAML. +## Check that the order is correct between BAT YAML and FDATA->YAML. RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat_order.preagg.txt \ RUN: -w %t.yaml -o %t.fdata RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o %t.null @@ -26,25 +26,28 @@ ORDER-YAML-CHECK: bid: 3 ORDER-YAML-CHECK: hash: 0xDDA1DC5F69F900AC ORDER-YAML-CHECK-NEXT: calls: [ { off: 0x26, fid: [[#]], cnt: 20 } ] ORDER-YAML-CHECK-NEXT: succ: [ { bid: 5, cnt: 7 } -# Large profile test +## Large profile test RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat.preagg.txt -w %t.yaml -o %t.fdata \ RUN: 2>&1 | FileCheck --check-prefix READ-BAT-CHECK %s RUN: FileCheck --input-file %t.yaml --check-prefix YAML-BAT-CHECK %s -# Check that YAML converted from fdata matches YAML created directly with BAT. -RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null +## Check that YAML converted from fdata matches YAML created directly with BAT. +RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null \ +RUN: 2>&1 | FileCheck --check-prefix READ-BAT-FDATA-CHECK %s RUN: FileCheck --input-file %t.yaml-fdata --check-prefix YAML-BAT-CHECK %s -# Test resulting YAML profile with the original binary (no-stale mode) +## Test resulting YAML profile with the original binary (no-stale mode) RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -dyno-stats 2>&1 \ RUN: | FileCheck --check-prefix CHECK-BOLT-YAML %s WRITE-BAT-CHECK: BOLT-INFO: Wrote 5 BAT maps WRITE-BAT-CHECK: BOLT-INFO: Wrote 4 function and 22 basic block hashes -WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 384 +WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 404 READ-BAT-CHECK-NOT: BOLT-ERROR: unable to save profile in YAML format for input file processed by BOLT READ-BAT-CHECK: BOLT-INFO: Parsed 5 BAT entries READ-BAT-CHECK: PERF2BOLT: read 79 aggregated LBR entries +READ-BAT-CHECK: BOLT-INFO: 5 out of 21 functions in the binary (23.8%) have non-empty execution profile +READ-BAT-FDATA-CHECK: BOLT-INFO: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile YAML-BAT-CHECK: functions: # Function not covered by BAT - has insns in basic block diff --git a/bolt/test/X86/bolt-address-translation.test b/bolt/test/X86/bolt-address-translation.test index e6b21c14077b454e9d3e1719da8dc3c2f896b322..cdaab1e2d7efa8398449f1db63a2033ab069fb6b 100644 --- a/bolt/test/X86/bolt-address-translation.test +++ b/bolt/test/X86/bolt-address-translation.test @@ -1,9 +1,9 @@ -# Check a common case for BOLT address translation tables. These tables are used -# to translate profile activity happening in a bolted binary back to the -# original binary, so you can run BOLT again, with updated profile collected -# in a production environment that only runs bolted binaries. As BOLT only -# takes no-bolt binaries as inputs, this translation is necessary to cover -# this scenario. +## Check a common case for BOLT address translation tables. These tables are used +## to translate profile activity happening in a bolted binary back to the +## original binary, so you can run BOLT again, with updated profile collected +## in a production environment that only runs bolted binaries. As BOLT only +## takes no-bolt binaries as inputs, this translation is necessary to cover +## this scenario. # # RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe # RUN: llvm-bolt %t.exe -o %t.out --data %p/Inputs/blarge.fdata \ @@ -11,33 +11,33 @@ # RUN: llvm-bat-dump %t.out --dump-all \ # RUN: --translate=0x401180 | FileCheck %s --check-prefix=CHECK-BAT-DUMP # -# In this test we focus on function usqrt at address 0x401170. This is a -# non-reloc binary case, so we don't expect this address to change, that's -# why we hardcode its address here. This address also comes hardcoded in the -# blarge.yaml input file. -# -# This is the layout of the function before BOLT reorder blocks: -# -# BB Layout : .LBB02, .Ltmp39, .LFT1, .Ltmp38, .LFT2 -# -# This is the layout of the function after BOLT reorder blocks: -# -# BB Layout : .LBB02, .Ltmp38, .Ltmp39, .LFT2, .LFT3 -# -# .Ltmp38 is originally at offset 0x39 but gets moved to 0xc (see full dump -# below). -# -# We check that BAT is able to translate references happening in .Ltmp38 to -# its original offset. -# +## In this test we focus on function usqrt at address 0x401170. This is a +## non-reloc binary case, so we don't expect this address to change, that's +## why we hardcode its address here. This address also comes hardcoded in the +## blarge.yaml input file. +## +## This is the layout of the function before BOLT reorder blocks: +## +## BB Layout : .LBB02, .Ltmp39, .LFT1, .Ltmp38, .LFT2 +## +## This is the layout of the function after BOLT reorder blocks: +## +## BB Layout : .LBB02, .Ltmp38, .Ltmp39, .LFT2, .LFT3 +## +## .Ltmp38 is originally at offset 0x39 but gets moved to 0xc (see full dump +## below). +## +## We check that BAT is able to translate references happening in .Ltmp38 to +## its original offset. +## -# This binary has 3 functions with profile, all of them are split, so 6 maps. -# BAT creates one map per function fragment. +## This binary has 3 functions with profile, all of them are split, so 6 maps. +## BAT creates one map per function fragment. # # CHECK: BOLT: 3 out of 7 functions were overwritten. # CHECK: BOLT-INFO: Wrote 6 BAT maps # CHECK: BOLT-INFO: Wrote 3 function and 58 basic block hashes -# CHECK: BOLT-INFO: BAT section size (bytes): 928 +# CHECK: BOLT-INFO: BAT section size (bytes): 940 # # usqrt mappings (hot part). We match against any key (left side containing # the bolted binary offsets) because BOLT may change where it puts instructions diff --git a/bolt/test/X86/branch-data.test b/bolt/test/X86/branch-data.test index 0c64caaee8a50b0a9df6191d9366cdb4ace19efc..231a77307ffefe1f8b1f817d61a74e61f9a9b16f 100644 --- a/bolt/test/X86/branch-data.test +++ b/bolt/test/X86/branch-data.test @@ -1,6 +1,6 @@ -# Checks that llvm-bolt is able to read data generated by perf2bolt and update -# the CFG edges accordingly with absolute number of branches and mispredictions. -# Also checks that llvm-bolt disassembler and CFG builder is working properly. +## Checks that llvm-bolt is able to read data generated by perf2bolt and update +## the CFG edges accordingly with absolute number of branches and mispredictions. +## Also checks that llvm-bolt disassembler and CFG builder is working properly. RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --data %p/Inputs/blarge.fdata --print-cfg | FileCheck %s diff --git a/bolt/test/X86/broken_dynsym.test b/bolt/test/X86/broken_dynsym.test index 9e7ed405afba904b6f9ff9872d7cd937eb39fef9..f89fe4aaa474ce759a08e20991b0015dab75125e 100644 --- a/bolt/test/X86/broken_dynsym.test +++ b/bolt/test/X86/broken_dynsym.test @@ -1,8 +1,8 @@ -# This test checks if BOLT can process stripped binaries, where symbol's section -# header index is corrupted due to strip tool. +## This test checks if BOLT can process stripped binaries, where symbol's section +## header index is corrupted due to strip tool. # RUN: yaml2obj %p/Inputs/broken_dynsym.yaml -o %t # RUN: llvm-strip -s %t # RUN: llvm-bolt %t -o %t.bolt --allow-stripped | FileCheck %s -# CHECK-NOT: section index out of bounds +# CHECK-NOT: section index out of bounds diff --git a/bolt/test/X86/bug-function-layout-execount.s b/bolt/test/X86/bug-function-layout-execount.s index c88e4d0043b46335c37efa1cae108224faa1567e..238347339f4e1f338d6ce98bc54c0355a8598b05 100644 --- a/bolt/test/X86/bug-function-layout-execount.s +++ b/bolt/test/X86/bug-function-layout-execount.s @@ -1,4 +1,4 @@ -# Verifies that llvm-bolt correctly sorts functions by their execution counts. +## Verifies that llvm-bolt correctly sorts functions by their execution counts. # REQUIRES: x86_64-linux, asserts diff --git a/bolt/test/X86/bug-reorder-bb-jrcxz.s b/bolt/test/X86/bug-reorder-bb-jrcxz.s index 13611119beaf0745ca68e67202401b265d650de5..d5ac3548909e3f73fcca11e33e114626488b669a 100644 --- a/bolt/test/X86/bug-reorder-bb-jrcxz.s +++ b/bolt/test/X86/bug-reorder-bb-jrcxz.s @@ -1,11 +1,11 @@ -# Test performs a BB reordering with unsupported -# instruction jrcxz. Reordering works correctly with the -# follow options: None, Normal or Reverse. Other strategies -# are completed with Assertion `isIntN(Size * 8 + 1, Value). -# The cause is the distance between BB where one contains -# jrcxz instruction. -# Example: OpenSSL -# https://github.com/openssl/openssl/blob/master/crypto/bn/asm/x86_64-mont5.pl#L3319 +## Test performs a BB reordering with unsupported +## instruction jrcxz. Reordering works correctly with the +## follow options: None, Normal or Reverse. Other strategies +## are completed with Assertion `isIntN(Size * 8 + 1, Value). +## The cause is the distance between BB where one contains +## jrcxz instruction. +## Example: OpenSSL +## https://github.com/openssl/openssl/blob/master/crypto/bn/asm/x86_64-mont5.pl#L3319 # REQUIRES: system-linux diff --git a/bolt/test/X86/calculate-emitted-block-size.s b/bolt/test/X86/calculate-emitted-block-size.s index b1d05b83cb87c74d8794066504331e47899452d0..820c00fa55086d4aa1c0ca66b92bacb0fa643f43 100644 --- a/bolt/test/X86/calculate-emitted-block-size.s +++ b/bolt/test/X86/calculate-emitted-block-size.s @@ -1,6 +1,6 @@ -# Test BinaryContext::calculateEmittedSize's functionality to update -# BinaryBasicBlock::OutputAddressRange in place so that the emitted size -# of each basic block is given by BinaryBasicBlock::getOutputSize() +## Test BinaryContext::calculateEmittedSize's functionality to update +## BinaryBasicBlock::OutputAddressRange in place so that the emitted size +## of each basic block is given by BinaryBasicBlock::getOutputSize() # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata diff --git a/bolt/test/X86/call-zero.s b/bolt/test/X86/call-zero.s index 3d6308d9e6f837b6ea1244730e6ed78d76de70f7..05ae4b609b1998a537abaf775bfe1941d0dcd53e 100644 --- a/bolt/test/X86/call-zero.s +++ b/bolt/test/X86/call-zero.s @@ -1,4 +1,4 @@ -# Verifies that llvm-bolt ignores function calls to 0. +## Verifies that llvm-bolt ignores function calls to 0. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe diff --git a/bolt/test/X86/cdsplit-call-scale.s b/bolt/test/X86/cdsplit-call-scale.s index 5701d9e6dfd6965abcdcae3696eccf1c019e4164..66f30036de8c1f53874016ffa330535168f0d5a1 100644 --- a/bolt/test/X86/cdsplit-call-scale.s +++ b/bolt/test/X86/cdsplit-call-scale.s @@ -1,10 +1,10 @@ -# Test the control of aggressiveness of 3-way splitting by -call-scale. -# When -call-scale=0.0, the tested function is 2-way splitted. -# When -call-scale=1.0, the tested function is 3-way splitted with 5 blocks -# in warm because of the increased benefit of shortening the call edges. -# When -call-scale=1000.0, the tested function is still 3-way splitted with -# 5 blocks in warm because cdsplit does not allow hot-warm splitting to break -# a fall through branch from a basic block to its most likely successor. +## Test the control of aggressiveness of 3-way splitting by -call-scale. +## When -call-scale=0.0, the tested function is 2-way splitted. +## When -call-scale=1.0, the tested function is 3-way splitted with 5 blocks +## in warm because of the increased benefit of shortening the call edges. +## When -call-scale=1000.0, the tested function is still 3-way splitted with +## 5 blocks in warm because cdsplit does not allow hot-warm splitting to break +## a fall through branch from a basic block to its most likely successor. # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata diff --git a/bolt/test/X86/cdsplit-symbol-names.s b/bolt/test/X86/cdsplit-symbol-names.s index e53863e22246d63d54ce4f56283d69c8ac37c856..0960020d747896531aaac8825c0b85ea08756af0 100644 --- a/bolt/test/X86/cdsplit-symbol-names.s +++ b/bolt/test/X86/cdsplit-symbol-names.s @@ -1,6 +1,6 @@ -# Test the correctness of section names and function symbol names post cdsplit. -# Warm section should have name .text.warm and warm function fragments should -# have symbol names ending in warm. +## Test the correctness of section names and function symbol names post cdsplit. +## Warm section should have name .text.warm and warm function fragments should +## have symbol names ending in warm. # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata diff --git a/bolt/test/X86/cfi-expr-rewrite.s b/bolt/test/X86/cfi-expr-rewrite.s index 0d2065417854363ddefa14834dcd7e788d26be71..6735b382025d88c275f82a23453d76d782778117 100644 --- a/bolt/test/X86/cfi-expr-rewrite.s +++ b/bolt/test/X86/cfi-expr-rewrite.s @@ -1,5 +1,5 @@ -# Check that llvm-bolt is able to parse DWARF expressions in CFI instructions, -# store them in memory and correctly write them back to the output binary. +## Check that llvm-bolt is able to parse DWARF expressions in CFI instructions, +## store them in memory and correctly write them back to the output binary. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe diff --git a/bolt/test/X86/cfi-instrs-count.s b/bolt/test/X86/cfi-instrs-count.s index 635d560ae75335930cd70a5692d8d4c254ab96ac..d91c9bb47fb1415b470ae72e2da79559d7e6c104 100644 --- a/bolt/test/X86/cfi-instrs-count.s +++ b/bolt/test/X86/cfi-instrs-count.s @@ -1,10 +1,10 @@ -# Check that llvm-bolt is able to read a file with DWARF Exception CFI -# information and annotate this into a disassembled function. +## Check that llvm-bolt is able to read a file with DWARF Exception CFI +## information and annotate this into a disassembled function. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe # RUN: llvm-bolt %t.exe -o %t.null --print-cfg 2>&1 | FileCheck %s -# +# # CHECK: Binary Function "_Z7catchitv" after building cfg { # CHECK: CFI Instrs : 6 # CHECK: } @@ -23,7 +23,7 @@ main: # FDATA: 0 [unknown] 0 1 main 0 0 0 .cfi_startproc -.LBB000: +.LBB000: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 @@ -49,7 +49,7 @@ main: _Z7catchitv: # FDATA: 0 [unknown] 0 1 _Z7catchitv 0 0 0 .cfi_startproc -.LBB00: +.LBB00: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 @@ -64,18 +64,18 @@ _Z7catchitv: .LBB00_br: jmp .Ltmp0 # FDATA: 1 _Z7catchitv #.LBB00_br# 1 _Z7catchitv #.Ltmp0# 0 0 -.LLP0: +.LLP0: cmpq $0x1, %rdx .LLP0_br: je .Ltmp1 # FDATA: 1 _Z7catchitv #.LLP0_br# 1 _Z7catchitv #.Ltmp1# 0 0 # FDATA: 1 _Z7catchitv #.LLP0_br# 1 _Z7catchitv #.LFT0# 0 0 -.LFT0: +.LFT0: movq %rax, %rdi .LFT0_br: callq _Unwind_Resume@PLT # FDATA: 1 _Z7catchitv #.LFT0_br# 1 _Z7catchitv #.Ltmp1# 0 0 -.Ltmp1: +.Ltmp1: movq %rax, %rdi callq __cxa_begin_catch@PLT movq %rax, -0x18(%rbp) @@ -85,7 +85,7 @@ _Z7catchitv: .Ltmp1_br: jmp .Ltmp2 # FDATA: 1 _Z7catchitv #.Ltmp1_br# 1 _Z7catchitv #.Ltmp2# 0 0 -.LLP1: +.LLP1: movl %edx, %ebx movq %rax, %r12 callq __cxa_end_catch@PLT @@ -95,11 +95,11 @@ _Z7catchitv: .LLP1_br: callq _Unwind_Resume@PLT # FDATA: 1 _Z7catchitv #.LLP1_br# 1 _Z7catchitv #.Ltmp2# 0 0 -.Ltmp2: +.Ltmp2: .Ltmp2_br: callq __cxa_end_catch@PLT # FDATA: 1 _Z7catchitv #.Ltmp2_br# 1 _Z7catchitv #.Ltmp0# 0 0 -.Ltmp0: +.Ltmp0: addq $0x10, %rsp popq %rbx popq %r12 diff --git a/bolt/test/X86/cfi-instrs-reordered.s b/bolt/test/X86/cfi-instrs-reordered.s index 8b2fe512f392ca7558709fe8cf16dfc075092857..c325aaf1ad8b18adf7e26beb047a0137c5c3b7ef 100644 --- a/bolt/test/X86/cfi-instrs-reordered.s +++ b/bolt/test/X86/cfi-instrs-reordered.s @@ -1,5 +1,5 @@ -# Check that llvm-bolt is able to read a file with DWARF Exception CFI -# information and fix CFI information after reordering. +## Check that llvm-bolt is able to read a file with DWARF Exception CFI +## information and fix CFI information after reordering. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: llvm-strip --strip-unneeded %t.o diff --git a/bolt/test/X86/checkvma-large-section.test b/bolt/test/X86/checkvma-large-section.test index 89aa4f78d52d12afda8200f697ccaa8f437b7e86..427dcdbabf3758d78d1df7adaf4806f174f67793 100644 --- a/bolt/test/X86/checkvma-large-section.test +++ b/bolt/test/X86/checkvma-large-section.test @@ -1,4 +1,4 @@ -# This test reproduces the issue with a section which ends at >4G address +## This test reproduces the issue with a section which ends at >4G address REQUIRES: asserts RUN: split-file %s %t RUN: yaml2obj %t/yaml -o %t.exe --max-size=0 diff --git a/bolt/test/X86/ctc-and-unreachable.test b/bolt/test/X86/ctc-and-unreachable.test index 0a0b7fcff4ce9be5e11e725b8f5892436d411281..55ba1fe316a91dd24d4261441d51a142df86f122 100644 --- a/bolt/test/X86/ctc-and-unreachable.test +++ b/bolt/test/X86/ctc-and-unreachable.test @@ -1,5 +1,5 @@ -# Check that we don't fail processing a function with conditional tail call and -# a fall-through to a next function (result of builtin_unreachable()). +## Check that we don't fail processing a function with conditional tail call and +## a fall-through to a next function (result of builtin_unreachable()). RUN: %clang %cflags %p/Inputs/ctc_and_unreachable.s -o %t.exe -Wl,-q RUN: llvm-bolt %t.exe -o %t --print-after-lowering --print-only=foo 2>&1 | FileCheck %s diff --git a/bolt/test/X86/debug-fission-single-convert.s b/bolt/test/X86/debug-fission-single-convert.s index 82db6700079f9f634f46ead9b312dffc05858cb1..28fcb6686e0a27a2634b8aeab14df821ec04f3a1 100644 --- a/bolt/test/X86/debug-fission-single-convert.s +++ b/bolt/test/X86/debug-fission-single-convert.s @@ -1,4 +1,4 @@ -# Checks debug fission support in BOLT +## Checks debug fission support in BOLT # REQUIRES: system-linux diff --git a/bolt/test/X86/debug-fission-single.s b/bolt/test/X86/debug-fission-single.s index 0d25aaef274a08b83c1a8e657330f2d3988bd4f7..4350bd9ec18158b45f32d0067623c7fce6fa4456 100644 --- a/bolt/test/X86/debug-fission-single.s +++ b/bolt/test/X86/debug-fission-single.s @@ -1,4 +1,4 @@ -# Checks debug fission support in BOLT +## Checks debug fission support in BOLT # REQUIRES: system-linux diff --git a/bolt/test/X86/double-jump.test b/bolt/test/X86/double-jump.test index cbd5ce9dae0e5b97a08c51f507e613a8cfe7e840..791872a2b4f8966cdb229ac6f4ae413c543dd102 100644 --- a/bolt/test/X86/double-jump.test +++ b/bolt/test/X86/double-jump.test @@ -1,7 +1,7 @@ -# Test the double jump removal peephole. +## Test the double jump removal peephole. -# This test has commands that rely on shell capabilities that won't execute -# correctly on Windows e.g. subshell execution +## This test has commands that rely on shell capabilities that won't execute +## correctly on Windows e.g. subshell execution REQUIRES: shell RUN: %clang %cflags %p/Inputs/double_jump.cpp -o %t.exe diff --git a/bolt/test/X86/dwarf-handle-visit-loclist-error.s b/bolt/test/X86/dwarf-handle-visit-loclist-error.s index d5ba74fb60166a7453073c08f7737bc143341524..f14d77285c485a65d94bad21896a5bf2c369e932 100644 --- a/bolt/test/X86/dwarf-handle-visit-loclist-error.s +++ b/bolt/test/X86/dwarf-handle-visit-loclist-error.s @@ -7,7 +7,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections &> file # RUN: cat file | FileCheck --check-prefix=CHECK %s -# Making sure we handle error returned by visitLocationList correctly. +## Making sure we handle error returned by visitLocationList correctly. # CHECK: BOLT-WARNING: empty location list detected at # CHECK-NEXT: BOLT-WARNING: empty location list detected at diff --git a/bolt/test/X86/dwarf-test-df-logging.test b/bolt/test/X86/dwarf-test-df-logging.test index 6126e9628a31a99112b98466156ec5005e8d72dd..4219eb3f9205e9520e98a5d15d7a002c9afe9fe4 100644 --- a/bolt/test/X86/dwarf-test-df-logging.test +++ b/bolt/test/X86/dwarf-test-df-logging.test @@ -1,4 +1,4 @@ -; Testing that we print out INFO message when binary has split dwarf. +;; Testing that we print out INFO message when binary has split dwarf. ; RUN: mkdir -p %t ; RUN: cd %t diff --git a/bolt/test/X86/dwarf3-lowpc-highpc-convert.s b/bolt/test/X86/dwarf3-lowpc-highpc-convert.s index faa4dc418f3b118028f3ae00d79c98c950ad99f4..96777a808c4ea4f3ebb28d4a1732b1e759aaa5a6 100644 --- a/bolt/test/X86/dwarf3-lowpc-highpc-convert.s +++ b/bolt/test/X86/dwarf3-lowpc-highpc-convert.s @@ -8,7 +8,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that DW_AT_high_pc[DW_FORM_ADDR] can be converted to DW_AT_ranges correctly in Dwarf3 +## This tests checks that DW_AT_high_pc[DW_FORM_ADDR] can be converted to DW_AT_ranges correctly in Dwarf3 # PRECHECK: version = 0x0003 # PRECHECK: DW_AT_low_pc diff --git a/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test index e609440696db42293808a7e951ebc972b800fd65..555887a067589f3d421239cdc883c91e0cd6f11a 100644 --- a/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test +++ b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test @@ -7,8 +7,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles backward cross CU references for dwarf4 -# when CUs are have different abbrev tables. +## This test checks that BOLT handles backward cross CU references for dwarf4 +## when CUs are have different abbrev tables. # PRECHECK: DW_TAG_compile_unit # PRECHECK: DW_TAG_compile_unit diff --git a/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test b/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test index e73960e7251e624cd98c756c9c1739adf0dfea17..74c9491d95d36ea7d43913d8f0d9ca24b7979e84 100644 --- a/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test +++ b/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test @@ -7,8 +7,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles forward cross CU references for dwarf4 -# when CUs are have different abbrev tables. +## This test checks that BOLT handles forward cross CU references for dwarf4 +## when CUs are have different abbrev tables. # PRECHECK: DW_TAG_compile_unit # PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] diff --git a/bolt/test/X86/dwarf4-cross-cu-loclist-dwarf4-loclist--dwarf5-loclist.test b/bolt/test/X86/dwarf4-cross-cu-loclist-dwarf4-loclist--dwarf5-loclist.test index 581ce2cffcfd41ed2b79b8cd20be3de4249f9449..6bcf8892ed0a8a0cd097c8695e6689e30e0ffabf 100644 --- a/bolt/test/X86/dwarf4-cross-cu-loclist-dwarf4-loclist--dwarf5-loclist.test +++ b/bolt/test/X86/dwarf4-cross-cu-loclist-dwarf4-loclist--dwarf5-loclist.test @@ -8,7 +8,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles location list with DWARF5/DWARF4 when order of CUs is not the same as in input. +## Tests that BOLT correctly handles location list with DWARF5/DWARF4 when order of CUs is not the same as in input. # PRECHECK: version = 0x0005 # PRECHECK: version = 0x0004 diff --git a/bolt/test/X86/dwarf4-df-basic.test b/bolt/test/X86/dwarf4-df-basic.test index d373b62ee6186b88f181f64abf49f753afe91a1a..601c0c58ec0a688eea08a61ebb3b2202938e73d3 100644 --- a/bolt/test/X86/dwarf4-df-basic.test +++ b/bolt/test/X86/dwarf4-df-basic.test @@ -7,6 +7,6 @@ ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections -v 1 &> log ; RUN: cat log | FileCheck %s -check-prefix=BOLT-LOG-CHECK -; Test check we don't print out a warning in -v 1 when Unit DIE doesn't have low_pc/high_pc +;; Test check we don't print out a warning in -v 1 when Unit DIE doesn't have low_pc/high_pc ; BOLT-LOG-CHECK-NOT: BOLT-ERROR: cannot update ranges for DIE in Unit offset diff --git a/bolt/test/X86/dwarf4-df-call-site-change-low-pc.test b/bolt/test/X86/dwarf4-df-call-site-change-low-pc.test index e00958d106141dab62339979b90676d64874438b..fa72c798516ba0017a7e417aa8f501d46290763c 100644 --- a/bolt/test/X86/dwarf4-df-call-site-change-low-pc.test +++ b/bolt/test/X86/dwarf4-df-call-site-change-low-pc.test @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/maindwodwo.txt ; RUN: cat %t/maindwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests that DW_AT_low_pc changes in DW_TAG_GNU_call_site. +;; Tests that DW_AT_low_pc changes in DW_TAG_GNU_call_site. ; PRE-BOLT-DWO-MAIN: version = 0x0004 ; PRE-BOLT-DWO-MAIN: DW_TAG_GNU_call_site diff --git a/bolt/test/X86/dwarf4-df-change-in-dw-op-gnu-addr-index-main.test b/bolt/test/X86/dwarf4-df-change-in-dw-op-gnu-addr-index-main.test index 5173c890f66abcf236014cc462977e8ff292d852..b5aee42f337f986a40950f51c795c6c2f9e80f4b 100644 --- a/bolt/test/X86/dwarf4-df-change-in-dw-op-gnu-addr-index-main.test +++ b/bolt/test/X86/dwarf4-df-change-in-dw-op-gnu-addr-index-main.test @@ -10,7 +10,7 @@ ; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/maindwodwo.txt ; RUN: cat %t/maindwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests that new indices are assigned to DW_OP_GNU_addr_index. +;; Tests that new indices are assigned to DW_OP_GNU_addr_index. ; PRE-BOLT-DWO-MAIN: version = 0x0004 ; PRE-BOLT-DWO-MAIN: DW_AT_location [DW_FORM_exprloc] (DW_OP_GNU_addr_index 0x0) diff --git a/bolt/test/X86/dwarf4-df-do-no-convert-low-pc-high-pc-to-ranges.test b/bolt/test/X86/dwarf4-df-do-no-convert-low-pc-high-pc-to-ranges.test index 95c1c747a3d04e78813d500665a86ef4c2a4aca7..9ba8264eac071a1a144279538697a23f3fc3765f 100644 --- a/bolt/test/X86/dwarf4-df-do-no-convert-low-pc-high-pc-to-ranges.test +++ b/bolt/test/X86/dwarf4-df-do-no-convert-low-pc-high-pc-to-ranges.test @@ -10,8 +10,8 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck --check-prefix=PRECHECK %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck --check-prefix=POSTCHECK %s -; This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, -; when there is only one output range entry. +;; This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, +;; when there is only one output range entry. ; PRECHECK: DW_TAG_inlined_subroutine ; PRECHECK: DW_AT_abstract_origin diff --git a/bolt/test/X86/dwarf4-df-dualcu-loclist.test b/bolt/test/X86/dwarf4-df-dualcu-loclist.test index 6ef4fb97e8caa42c2f367daf7d5b8ce529f75304..57c75e282421acad04e03c006efac126788875f6 100644 --- a/bolt/test/X86/dwarf4-df-dualcu-loclist.test +++ b/bolt/test/X86/dwarf4-df-dualcu-loclist.test @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s -; Testing dwarf4 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_sec_offset] is updated correctly. +;; Testing dwarf4 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_sec_offset] is updated correctly. ; PRE-BOLT-DWO-MAIN: version = 0x0004 ; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10] diff --git a/bolt/test/X86/dwarf4-df-dualcu.test b/bolt/test/X86/dwarf4-df-dualcu.test index 91b3e9e4cf0926c69eb894ae7c651571b111bdd0..b690623b70d835d0f30a2cae65d2a9062e372de9 100644 --- a/bolt/test/X86/dwarf4-df-dualcu.test +++ b/bolt/test/X86/dwarf4-df-dualcu.test @@ -20,8 +20,8 @@ ; RUN: not llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo &> helperdwodwo.txt ; RUN: cat helperdwodwo.txt | FileCheck -check-prefix=BOLT-DWO-HELPER %s -; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. -; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx ##) are updated correctly. +;; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. +;; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx ##) are updated correctly. ; PRE-BOLT: version = 0x0004 ; PRE-BOLT: DW_TAG_compile_unit diff --git a/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test b/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test index 32bffcba4bec0861bae941e2681de57b3fc5bffe..0553a217a12c12da94aa2e5bd7da0fda87450f56 100644 --- a/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test +++ b/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test @@ -9,8 +9,8 @@ ; RUN: llvm-dwarfdump --debug-info --verbose --show-form main.dwo.dwo >> log.txt ; RUN: cat log.txt | FileCheck -check-prefix=BOLT-MAIN %s -; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_low_pc is 0, -; and split dwarf is enabled. +;; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_low_pc is 0, +;; and split dwarf is enabled. ; BOLT-MAIN: 0x ; BOLT-MAIN: 0x diff --git a/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test b/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test new file mode 100644 index 0000000000000000000000000000000000000000..c9abd02bbb7d9d9323387a150495cd5312507b30 --- /dev/null +++ b/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test @@ -0,0 +1,97 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-other.s \ +; RUN: -split-dwarf-file=mainOther.dwo -o other.o +; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o other.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt +; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s + +;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges. + +; BOLT: .debug_ranges +; BOLT-NEXT: 00000000 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000090 [[#%.16x,ADDR1:]] [[#%.16x,ADDRB1:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR2:]] [[#%.16x,ADDRB2:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR3:]] [[#%.16x,ADDRB3:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR4:]] [[#%.16x,ADDRB4:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR5:]] [[#%.16x,ADDRB5:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR6:]] [[#%.16x,ADDRB6:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR7:]] [[#%.16x,ADDRB7:]] +; BOLT-NEXT: 00000090 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000190 [[#%.16x,ADDR8:]] [[#%.16x,ADDRB8:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR9:]] [[#%.16x,ADDRB9:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR10:]] [[#%.16x,ADDRB10:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR11:]] [[#%.16x,ADDRB11:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR12:]] [[#%.16x,ADDRB12:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR13:]] [[#%.16x,ADDRB13:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR14:]] [[#%.16x,ADDRB14:]] +; BOLT-NEXT: 00000190 + +; BOLT: DW_TAG_compile_unit +; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "main.dwo.dwo") +; BOLT-NEXT: DW_AT_GNU_dwo_id +; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000010) +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000090 +; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDRB1]]) +; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDRB2]]) +; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDRB3]]) +; BOLT-NEXT: [0x[[#ADDR4]], 0x[[#ADDRB4]]) +; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDRB5]]) +; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDRB6]]) +; BOLT-NEXT: [0x[[#ADDR7]], 0x[[#ADDRB7]]) +; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) + +; BOLT: DW_TAG_compile_unit +; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "mainOther.dwo.dwo") +; BOLT-NEXT: DW_AT_GNU_dwo_id +; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000110) +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000190 +; BOLT-NEXT: [0x[[#ADDR8]], 0x[[#ADDRB8]]) +; BOLT-NEXT: [0x[[#ADDR9]], 0x[[#ADDRB9]]) +; BOLT-NEXT: [0x[[#ADDR10]], 0x[[#ADDRB10]]) +; BOLT-NEXT: [0x[[#ADDR11]], 0x[[#ADDRB11]]) +; BOLT-NEXT: [0x[[#ADDR12]], 0x[[#ADDRB12]]) +; BOLT-NEXT: [0x[[#ADDR13]], 0x[[#ADDRB13]]) +; BOLT-NEXT: [0x[[#ADDR14]], 0x[[#ADDRB14]]) +; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000018) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 diff --git a/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test b/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test index fa116206950bb60e32ea4367b7dfa11c1ffde4ea..276bea4ba0c1c76344f57f3f6939e3af2db0a142 100644 --- a/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test +++ b/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test @@ -1,7 +1,7 @@ ; RUN: rm -rf %t ; RUN: mkdir %t ; RUN: cd %t -;; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ +; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o -o main.exe ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections @@ -11,7 +11,7 @@ ; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/mainddwodwo.txt ; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests BOLT handles correctly Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. +;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. ; BOLT: .debug_ranges ; BOLT-NEXT: 00000000 diff --git a/bolt/test/X86/dwarf4-df-no-base.test b/bolt/test/X86/dwarf4-df-no-base.test index e5274cb829bc72dbf2d9761be63c6404b5b9c9ae..338aa5444cb5153a34d8a64cd6c776fb00b950a4 100644 --- a/bolt/test/X86/dwarf4-df-no-base.test +++ b/bolt/test/X86/dwarf4-df-no-base.test @@ -8,8 +8,8 @@ ; RUN: llvm-dwarfdump --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT-MAIN %s ; RUN: llvm-dwarfdump --debug-info main.exe.bolt | FileCheck -check-prefix=BOLT-MAIN %s -; Tests whether we add DW_AT_GNU_ranges_base, if it's not present when Skeleton CU has -; DW_AT_ranges. +;; Tests whether we add DW_AT_GNU_ranges_base, if it's not present when Skeleton CU has +;; DW_AT_ranges. ; PRE-BOLT-MAIN-NOT: DW_AT_GNU_ranges_base ; BOLT-MAIN: DW_AT_GNU_ranges_base diff --git a/bolt/test/X86/dwarf4-do-no-convert-low-pc-high-pc-to-ranges.test b/bolt/test/X86/dwarf4-do-no-convert-low-pc-high-pc-to-ranges.test index 2e861c7ea504b8db5a25533e6b1b74b17bba2a91..2ff0b5dd365802c4e0b44810106f97a510ef27be 100644 --- a/bolt/test/X86/dwarf4-do-no-convert-low-pc-high-pc-to-ranges.test +++ b/bolt/test/X86/dwarf4-do-no-convert-low-pc-high-pc-to-ranges.test @@ -6,8 +6,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, -# when there is only one output range entry. +## This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, +## when there is only one output range entry. # PRECHECK: DW_TAG_inlined_subroutine # PRECHECK: DW_AT_abstract_origin diff --git a/bolt/test/X86/dwarf4-duplicate-types.test b/bolt/test/X86/dwarf4-duplicate-types.test index 8deed6ab0939fad828bd285fd56f6a4189cb155b..065ec7c7ac2c2021d80d2b3a78088d1fed26478e 100644 --- a/bolt/test/X86/dwarf4-duplicate-types.test +++ b/bolt/test/X86/dwarf4-duplicate-types.test @@ -6,10 +6,10 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --debug-types %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# LLD does not de-duplicate COMDAT sections for LTO. -# Clang can generate type units with the same hash. -# https://discourse.llvm.org/t/dwarf-different-tu-with-the-same-hash/70095 -# Modified helper.s to have the same TU hash with a different COMDAT signature to test this. +## LLD does not de-duplicate COMDAT sections for LTO. +## Clang can generate type units with the same hash. +## https://discourse.llvm.org/t/dwarf-different-tu-with-the-same-hash/70095 +## Modified helper.s to have the same TU hash with a different COMDAT signature to test this. # POSTCHECK: Type Unit: length = 0x00000055, format = DWARF32, version = 0x0004, # POSTCHECK-SAME: abbr_offset = 0x0000, addr_size = 0x08, name = 'Foo', type_signature = 0x675d23e4f33235f2, type_offset = 0x001e (next unit at 0x00000059) diff --git a/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test index 8fd2f195043732c2dbc4fdad964228f26cc6c5a7..d08b596ec8dd1f8cd3f7b1873c8497d11123953b 100644 --- a/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test @@ -10,8 +10,8 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s -; Test input into bolt a .dwo file with TU Index. -; Make sure the output .dwp file has a type information. +;; Test input into bolt a .dwo file with TU Index. +;; Make sure the output .dwp file has a type information. ; PRE-BOLT: DW_TAG_type_unit ; PRE-BOLT: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test index 40eae605b6a8ee8dd0fd75028ad3d51d905c51f2..54382142afc8fb9ddf5759cee7d26a37b6102b45 100644 --- a/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test @@ -12,9 +12,9 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s -; Test input into bolt a .dwo file with TU Index. -; Test split-dwarf and monolithic TUs. -; Make sure the output .dwp file has a type information. +;; Test input into bolt a .dwo file with TU Index. +;; Test split-dwarf and monolithic TUs. +;; Make sure the output .dwp file has a type information. ; PRE-BOLT: 0x675d23e4f33235f2 ; PRE-BOLT: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test index c6b8671deb98ac3a67ee48d1c010f65d3bbd7ccf..8077cc080823859bf608db1e34d8b5da49149e17 100644 --- a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test @@ -11,8 +11,8 @@ ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections ; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.dwo.dwo | FileCheck -check-prefix=BOLT %s -; Test input into bolt a DWP file with TU Index. -; Make sure output in the .dwo files has type information. +;; Test input into bolt a DWP file with TU Index. +;; Make sure output in the .dwo files has type information. ; PRE-BOLT: DW_TAG_type_unit ; PRE-BOLT: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test index b326a6386ba92df970f0ba80ad2d599b7dc5dcc1..673e86bb1533a29551275d7a79a9466232f0b58c 100644 --- a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test @@ -12,8 +12,8 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s -; Test input into bolt a DWP file with TU Index. -; Make sure the output .dwp file has a type information. +;; Test input into bolt a DWP file with TU Index. +;; Make sure the output .dwp file has a type information. ; PRE-BOLT: DW_TAG_type_unit ; PRE-BOLT: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf4-gdb-index-types-gdb-generated.test b/bolt/test/X86/dwarf4-gdb-index-types-gdb-generated.test index 51293ce560088bacd66b59e7fc60f1f8a6743d5c..eaf7580917016811758792de3a8499b4e0637375 100644 --- a/bolt/test/X86/dwarf4-gdb-index-types-gdb-generated.test +++ b/bolt/test/X86/dwarf4-gdb-index-types-gdb-generated.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %tgdb.exe -o %tgdb.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %tgdb.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB. +## Tests that BOLT correctly handles gdb-index generated by GDB. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf4-gdb-index-types-lld-generated.test b/bolt/test/X86/dwarf4-gdb-index-types-lld-generated.test index 8943ce851a7e54c87c5f236ee94fbf259b3fc969..640598978be7ce783d59a41e4d3f6e9d92ecac7e 100644 --- a/bolt/test/X86/dwarf4-gdb-index-types-lld-generated.test +++ b/bolt/test/X86/dwarf4-gdb-index-types-lld-generated.test @@ -6,7 +6,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by LLD. +## Tests that BOLT correctly handles gdb-index generated by LLD. # POSTCHECK: Version = 7 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf4-invalid-reference-die-offset-no-internal-dwarf-error.s b/bolt/test/X86/dwarf4-invalid-reference-die-offset-no-internal-dwarf-error.s index 4cf0d3d0e2558c443002f9f3ba19f335e3481aed..494fe43cf105f0c3d9aa049180c58b7a844c608a 100755 --- a/bolt/test/X86/dwarf4-invalid-reference-die-offset-no-internal-dwarf-error.s +++ b/bolt/test/X86/dwarf4-invalid-reference-die-offset-no-internal-dwarf-error.s @@ -6,7 +6,7 @@ # RUN: cat %tlog.txt | FileCheck --check-prefix=CHECKBOLT %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=CHECK %s -# Tests BOLT does not assert when DIE reference is invalid. +## Tests BOLT does not assert when DIE reference is invalid. # CHECKBOLT: Referenced DIE offsets not in .debug_info # CHECKBOLT-NEXT: 91 diff --git a/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-cant-parse-die.s b/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-cant-parse-die.s index 9d27c9cd9ff871f40ede95dc488985421b593f57..1bbb12ef3139df23d0dec075e50c7d2c7945e431 100755 --- a/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-cant-parse-die.s +++ b/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-cant-parse-die.s @@ -6,7 +6,7 @@ # RUN: cat %tlog.txt | FileCheck --check-prefix=CHECKBOLT %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=CHECK %s -# Tests BOLT does not assert when DIE reference is invalid. +## Tests BOLT does not assert when DIE reference is invalid. # CHECKBOLT: BOLT-WARNING: [internal-dwarf-error]: could not parse referenced DIE at offset: # CHECKBOLT-NOT: Referenced DIE offsets not in .debug_info diff --git a/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-invalid-die.s b/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-invalid-die.s index b9cbf513bb26f7cb8beab9c41365421cf057e8a5..3cec66132e9efed7aade95e7b53c17c4a6fc0580 100755 --- a/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-invalid-die.s +++ b/bolt/test/X86/dwarf4-invalid-reference-die-offset-with-internal-dwarf-error-invalid-die.s @@ -6,7 +6,7 @@ # RUN: cat %tlog.txt | FileCheck --check-prefix=CHECKBOLT %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=CHECK %s -# Tests BOLT does not assert when DIE reference is invalid. +## Tests BOLT does not assert when DIE reference is invalid. # CHECKBOLT: BOLT-WARNING: [internal-dwarf-error]: invalid referenced DIE at offset: # CHECKBOLT-NOT: Referenced DIE offsets not in .debug_info diff --git a/bolt/test/X86/dwarf4-sibling.s b/bolt/test/X86/dwarf4-sibling.s index 0ba97acb4f9e65246bdc0aef84287f5012135bd3..94e112101f9ba731fb2934c00743c6ac5078915d 100644 --- a/bolt/test/X86/dwarf4-sibling.s +++ b/bolt/test/X86/dwarf4-sibling.s @@ -5,9 +5,9 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles DW_AT_sibling. +## This test checks that BOLT handles DW_AT_sibling. -# The assembly was manually modified to do cross CU reference. +## The assembly was manually modified to do cross CU reference. # POSTCHECK: version = 0x0004 # POSTCHECK: DW_TAG_structure_type [5] diff --git a/bolt/test/X86/dwarf4-size-0-inlined_subroutine.s b/bolt/test/X86/dwarf4-size-0-inlined_subroutine.s index 584e67b1c79febdbeebfaacb5ad1ce0b2cc66339..e7fc0dae3e44032b359701c305ef9b40fba4b4e2 100644 --- a/bolt/test/X86/dwarf4-size-0-inlined_subroutine.s +++ b/bolt/test/X86/dwarf4-size-0-inlined_subroutine.s @@ -16,8 +16,8 @@ # CHECK: DW_AT_high_pc [DW_FORM_data4] (0x00000000) -# Testing BOLT handles correctly when size of DW_AT_inlined_subroutine is 0. -# In other words DW_AT_high_pc is 0 or DW_AT_low_pc == DW_AT_high_pc. +## Testing BOLT handles correctly when size of DW_AT_inlined_subroutine is 0. +## In other words DW_AT_high_pc is 0 or DW_AT_low_pc == DW_AT_high_pc. # Modified assembly manually to set DW_AT_high_pc to 0. # clang++ -g2 -gdwarf-4 main.cpp -O1 -S -o main4.s diff --git a/bolt/test/X86/dwarf4-split-dwarf-no-address.test b/bolt/test/X86/dwarf4-split-dwarf-no-address.test index 753fad06eb069fd477aaebe8ea4e77f5f331a64e..fc6d8d324b9597c4967944aec7f0ee302319735c 100644 --- a/bolt/test/X86/dwarf4-split-dwarf-no-address.test +++ b/bolt/test/X86/dwarf4-split-dwarf-no-address.test @@ -9,7 +9,7 @@ ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt | FileCheck -check-prefix=BOLT %s -; Testing that there are no asserts/crashes when one of the DWARF4 CUs does not modify .debug_addr +;; Testing that there are no asserts/crashes when one of the DWARF4 CUs does not modify .debug_addr ; BOLT: DW_TAG_compile_unit ; BOLT: DW_TAG_compile_unit diff --git a/bolt/test/X86/dwarf4-split-gdb-index-types-gdb-generated.test b/bolt/test/X86/dwarf4-split-gdb-index-types-gdb-generated.test index e3734492d8f4c764c8ce9171c16728e2ca83cc3b..c9b12574caa3acff6f0db2c378ff398a65266c97 100644 --- a/bolt/test/X86/dwarf4-split-gdb-index-types-gdb-generated.test +++ b/bolt/test/X86/dwarf4-split-gdb-index-types-gdb-generated.test @@ -10,7 +10,7 @@ # RUN: llvm-bolt maingdb.exe -o maingdb.exe.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index maingdb.exe.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB with split-dwarf DWARF4. +## Tests that BOLT correctly handles gdb-index generated by GDB with split-dwarf DWARF4. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf4-subprogram-multiple-ranges-cus.test b/bolt/test/X86/dwarf4-subprogram-multiple-ranges-cus.test new file mode 100644 index 0000000000000000000000000000000000000000..c9ade995b70878dd6d52bf26cdf006391e7e1910 --- /dev/null +++ b/bolt/test/X86/dwarf4-subprogram-multiple-ranges-cus.test @@ -0,0 +1,38 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-subprogram-multiple-ranges-main.s -o %t1.o +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-subprogram-multiple-ranges-other.s -o %t2.o +# RUN: %clang %cflags %t1.o %t2.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-objdump %t.bolt --disassemble > %t1.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt +# RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s + +## This test checks that BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries and handles multiple CUs with ranges. + +# POSTCHECK: _Z7doStuffi>: +# POSTCHECK: [[#%.6x,ADDR:]] +# POSTCHECK: _Z7doStuffi.__part.1>: +# POSTCHECK-NEXT: [[#%.6x,ADDR1:]] +# POSTCHECK: _Z7doStuffi.__part.2>: +# POSTCHECK-NEXT: [[#%.6x,ADDR2:]] + +# POSTCHECK: _Z12doStuffOtheri>: +# POSTCHECK: [[#%.6x,ADDR3:]] +# POSTCHECK: _Z12doStuffOtheri.__part.1>: +# POSTCHECK-NEXT: [[#%.6x,ADDR4:]] +# POSTCHECK: _Z12doStuffOtheri.__part.2>: +# POSTCHECK-NEXT: [[#%.6x,ADDR5:]] + +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_AT_ranges +# POSTCHECK-NEXT: [0x0000000000[[#ADDR1]], 0x0000000000[[#ADDR1 + 0xb]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR2]], 0x0000000000[[#ADDR2 + 0x5]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR]], 0x0000000000[[#ADDR + 0xf]])) + +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_AT_ranges +# POSTCHECK-NEXT: [0x0000000000[[#ADDR4]], 0x0000000000[[#ADDR4 + 0xb]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR5]], 0x0000000000[[#ADDR5 + 0x5]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR3]], 0x0000000000[[#ADDR3 + 0xf]])) diff --git a/bolt/test/X86/dwarf4-subprogram-multiple-ranges.test b/bolt/test/X86/dwarf4-subprogram-multiple-ranges.test index 63db886c913739517308b7b462892ba9a3f89cb0..5efe07a280575ced094325c9ebc941cd9e82c55f 100644 --- a/bolt/test/X86/dwarf4-subprogram-multiple-ranges.test +++ b/bolt/test/X86/dwarf4-subprogram-multiple-ranges.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries. # POSTCHECK: _Z7doStuffi>: # POSTCHECK: [[#%.6x,ADDR:]] diff --git a/bolt/test/X86/dwarf4-subprogram-single-gc-ranges.test b/bolt/test/X86/dwarf4-subprogram-single-gc-ranges.test index 3e7e765f98b197190f1c7b82bdd35bc151cab6ef..9c121e5acc4aad5887777f083eb13981a21b9834 100644 --- a/bolt/test/X86/dwarf4-subprogram-single-gc-ranges.test +++ b/bolt/test/X86/dwarf4-subprogram-single-gc-ranges.test @@ -6,7 +6,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry, when function was GCed. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry, when function was GCed. # POSTCHECK: DW_TAG_subprogram # POSTCHECK-NEXT: DW_AT_frame_base diff --git a/bolt/test/X86/dwarf4-subprogram-single-ranges.test b/bolt/test/X86/dwarf4-subprogram-single-ranges.test index 0dcbbcdfcce3f04202d31e4d7f4620fda81fef89..c02d2e4e6d44563493d915811431ec77194ffd11 100644 --- a/bolt/test/X86/dwarf4-subprogram-single-ranges.test +++ b/bolt/test/X86/dwarf4-subprogram-single-ranges.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry. # POSTCHECK: _Z7doStuffi>: # POSTCHECK: [[#%.6x,ADDR:]] diff --git a/bolt/test/X86/dwarf4-types-dwarf5-types.test b/bolt/test/X86/dwarf4-types-dwarf5-types.test index a5d2ec8df20a689a963119a10a3595e6dcef5f88..a253f2283609017f5c2ff82fe5258fb079c618e9 100644 --- a/bolt/test/X86/dwarf4-types-dwarf5-types.test +++ b/bolt/test/X86/dwarf4-types-dwarf5-types.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-types %t.bolt | FileCheck --check-prefix=POSTCHECKTU %s -# Check BOLT handles DWARF4/5 with fdebug-types. +## Check BOLT handles DWARF4/5 with fdebug-types. # POSTCHECK: version = 0x0005 # POSTCHECK: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf4-types-dwarf5.test b/bolt/test/X86/dwarf4-types-dwarf5.test index 9ece6db3f00a09829db7fc3951fef623d7244c5a..1eb42683e40ee812c0efdafd799ee002a1149428 100644 --- a/bolt/test/X86/dwarf4-types-dwarf5.test +++ b/bolt/test/X86/dwarf4-types-dwarf5.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-types %t.bolt | FileCheck --check-prefix=POSTCHECKTU %s -# Check BOLT handles DWARF4 with fdebug-types, and DWARF5 without. +## Check BOLT handles DWARF4 with fdebug-types, and DWARF5 without. # POSTCHECK: version = 0x0004 # POSTCHECK: DW_TAG_compile_unit diff --git a/bolt/test/X86/dwarf4-types-forward-backward-cross-reference.s b/bolt/test/X86/dwarf4-types-forward-backward-cross-reference.s index c407ecadd1119e5ce58170e0f703f5afe725f167..3cfe8a3b74f6e9f00af3d003b7b92a6c14834ba0 100644 --- a/bolt/test/X86/dwarf4-types-forward-backward-cross-reference.s +++ b/bolt/test/X86/dwarf4-types-forward-backward-cross-reference.s @@ -5,8 +5,8 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles correctly backward and forward cross CU references -# for DWARF4 with -fdebug-types-section +## This test checks that BOLT handles correctly backward and forward cross CU references +## for DWARF4 with -fdebug-types-section # POSTCHECK: version = 0x0004 # POSTCHECK: DW_TAG_variable [10] diff --git a/bolt/test/X86/dwarf4-types.test b/bolt/test/X86/dwarf4-types.test index d717b4b3b47ddc4f6ad7c85476262f52540a7569..7ea804e95aa3f98e81fe5172e744aa568dae5c2c 100644 --- a/bolt/test/X86/dwarf4-types.test +++ b/bolt/test/X86/dwarf4-types.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-types %t.bolt | FileCheck --check-prefix=POSTCHECKTU %s -# Check BOLT handles DWARF4/5 with fdebug-types. +## Check BOLT handles DWARF4/5 with fdebug-types. # POSTCHECK: version = 0x0004 # POSTCHECK: DW_TAG_compile_unit [6] diff --git a/bolt/test/X86/dwarf5-addr-section-reuse.s b/bolt/test/X86/dwarf5-addr-section-reuse.s index bc747e0657b54bc2299ba24eef5093e963b58388..6b00ce0fdf80598b39954a2f8c75f827ebfa0a16 100644 --- a/bolt/test/X86/dwarf5-addr-section-reuse.s +++ b/bolt/test/X86/dwarf5-addr-section-reuse.s @@ -6,8 +6,8 @@ # RUN: llvm-bolt %t.exe -o %t.exe.bolt --update-debug-sections # RUN: llvm-dwarfdump --debug-info %t.exe.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that when a binary is bolted if CU is not modified and has DW_AT_addr_base that is shared -# after being bolted CUs still share same entry in .debug_addr. +## This test checks that when a binary is bolted if CU is not modified and has DW_AT_addr_base that is shared +## after being bolted CUs still share same entry in .debug_addr. # PRECHECK: DW_AT_addr_base (0x00000008) # PRECHECK: DW_AT_addr_base (0x00000008) diff --git a/bolt/test/X86/dwarf5-call-pc-function-null-check.test b/bolt/test/X86/dwarf5-call-pc-function-null-check.test index b04e30bcf53293339fe9c173f1560347295fa6eb..761a4da696217c542934bed120bee4a99b4cbfa0 100644 --- a/bolt/test/X86/dwarf5-call-pc-function-null-check.test +++ b/bolt/test/X86/dwarf5-call-pc-function-null-check.test @@ -8,8 +8,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=CHECK %s -# Test checks we correctly handle nullptr returned by getBinaryFunctionContainingAddress for DW_AT_call_pc. -# This happens when address is not contained in any function. +## Test checks we correctly handle nullptr returned by getBinaryFunctionContainingAddress for DW_AT_call_pc. +## This happens when address is not contained in any function. # CHECK: DW_AT_call_pc [DW_FORM_addrx] # CHECK-SAME: address = 0x[[#%.16x,ADDR:]] diff --git a/bolt/test/X86/dwarf5-call-pc.test b/bolt/test/X86/dwarf5-call-pc.test index ec03a7bf8ad4add5f259e739a88101bd91af9469..dc7773dc053d90a986f5609255d59d35d4b2957b 100644 --- a/bolt/test/X86/dwarf5-call-pc.test +++ b/bolt/test/X86/dwarf5-call-pc.test @@ -11,7 +11,7 @@ # RUN: cat %tmain.txt | FileCheck --check-prefix=PRECHECK %s # RUN: cat %tmainbolt.txt | FileCheck --check-prefix=POSTCHECK %s -# Test checks that DW_AT_call_pc address points to a correct address for jmp instruction. +## Test checks that DW_AT_call_pc address points to a correct address for jmp instruction. # PRECHECK: DW_TAG_call_site [6] # PRECHECK-NEXT: DW_AT_call_origin [DW_FORM_ref4] diff --git a/bolt/test/X86/dwarf5-cu-no-debug-addr.test b/bolt/test/X86/dwarf5-cu-no-debug-addr.test index d194808059369339ec6ff94821d21adf2987cbf2..e78b68680d6cc103b9bd169223de046d9d1601f6 100644 --- a/bolt/test/X86/dwarf5-cu-no-debug-addr.test +++ b/bolt/test/X86/dwarf5-cu-no-debug-addr.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that we handle correctly, don't crash, DWARF5 CUs that does not access .debug_addr. +## This tests checks that we handle correctly, don't crash, DWARF5 CUs that does not access .debug_addr. # PRECHECK: DW_TAG_compile_unit # PRECHECK: DW_AT_addr_base diff --git a/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s b/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s index 6042bbee8948c7028888e273f2c091a51a02af9b..dbf6aef20a9cbea44fb5cefdd84a970df459c24c 100644 --- a/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s +++ b/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s @@ -6,7 +6,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that .debug_line gets generated correctly when .debug_info is DWARF5, and .debug_line is DWARF4. +## This test checks that .debug_line gets generated correctly when .debug_info is DWARF5, and .debug_line is DWARF4. # PRECHECK: version: 4 # PRECHECK: file_names[ 1]: diff --git a/bolt/test/X86/dwarf5-debug-line-not-modified.test b/bolt/test/X86/dwarf5-debug-line-not-modified.test index 20dd9083169acf49108ccd062294c212bd4beaf5..15f7ead42dc130e3f8d831441d800a57ecafbd7d 100644 --- a/bolt/test/X86/dwarf5-debug-line-not-modified.test +++ b/bolt/test/X86/dwarf5-debug-line-not-modified.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT generates correct debug_line_str when one of CU contributions is not modified. +## This test checks that BOLT generates correct debug_line_str when one of CU contributions is not modified. # POSTCHECK: version: 5 # POSTCHECK: include_directories[ 0] = .debug_line_str[{{.*}}] = "/test" diff --git a/bolt/test/X86/dwarf5-debug-line.s b/bolt/test/X86/dwarf5-debug-line.s index 5b1cdba712a9b60d61e211d851c59f47322e9f66..732e0d61d672638062a3068d9530d4c0e855dd30 100644 --- a/bolt/test/X86/dwarf5-debug-line.s +++ b/bolt/test/X86/dwarf5-debug-line.s @@ -6,7 +6,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that DWARF5 .debug_line is handled correctly. +## This test checks that DWARF5 .debug_line is handled correctly. # PRECHECK: version: 5 # PRECHECK: include_directories[ 0] = .debug_line_str diff --git a/bolt/test/X86/dwarf5-debug-loclists.s b/bolt/test/X86/dwarf5-debug-loclists.s index 753858d0b32e96ddfd4fa36fc1ebeedd3e0003c1..6ce0467a840b8b695c0cc930f241502351b45aba 100644 --- a/bolt/test/X86/dwarf5-debug-loclists.s +++ b/bolt/test/X86/dwarf5-debug-loclists.s @@ -8,7 +8,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that re-writing of .debug_loclists is handled correctly. +## This tests checks that re-writing of .debug_loclists is handled correctly. # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c) diff --git a/bolt/test/X86/dwarf5-debug-names-class-type-decl.s b/bolt/test/X86/dwarf5-debug-names-class-type-decl.s new file mode 100644 index 0000000000000000000000000000000000000000..587eaaf6f4ffa6311449663a800b11cd25d15b26 --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-class-type-decl.s @@ -0,0 +1,670 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-names %t.bolt >> %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s + +## This tests that BOLT doesn't generate entry for a DW_TAG_class_type declaration with DW_AT_name. + +# POSTCHECK: DW_TAG_type_unit +# POSTCHECK: DW_TAG_class_type [7] +# POSTCHECK-NEXT: DW_AT_name [DW_FORM_strx1] (indexed (00000006) string = "InnerState") +# POSTCHECK-NEXT: DW_AT_declaration [DW_FORM_flag_present] (true) +# POSTCHECK: Name Index +# POSTCHECK-NOT: "InnerState" + +## -g2 -O0 -fdebug-types-section -gpubnames +## namespace A { +## namespace B { +## class State { +## public: +## class InnerState{ +## InnerState() {} +## }; +## State(){} +## State(InnerState S){} +## }; +## } +## } +## +## int main() { +## A::B::State S; +## return 0; +## } + + .text + .file "main.cpp" + .file 0 "/DW_TAG_class_type" "main.cpp" md5 0x80f261b124b76c481b8761c040ab4802 + .section .debug_info,"G",@progbits,16664150534606561860,comdat +.Ltu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad -1782593539102989756 # Type Signature + .long 39 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x3b DW_TAG_type_unit + .short 33 # DW_AT_language + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 2 # Abbrev [2] 0x23:0x2a DW_TAG_namespace + .byte 3 # DW_AT_name + .byte 2 # Abbrev [2] 0x25:0x27 DW_TAG_namespace + .byte 4 # DW_AT_name + .byte 3 # Abbrev [3] 0x27:0x24 DW_TAG_class_type + .byte 5 # DW_AT_calling_convention + .byte 5 # DW_AT_name + .byte 1 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 4 # Abbrev [4] 0x2d:0xb DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x32:0x5 DW_TAG_formal_parameter + .long 77 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x38:0x10 DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_formal_parameter + .long 77 # DW_AT_type + # DW_AT_artificial + .byte 6 # Abbrev [6] 0x42:0x5 DW_TAG_formal_parameter + .long 72 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x48:0x2 DW_TAG_class_type + .byte 6 # DW_AT_name + # DW_AT_declaration + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x4d:0x5 DW_TAG_pointer_type + .long 39 # DW_AT_type + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .text + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .loc 0 14 0 # main.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl $0, -4(%rbp) +.Ltmp0: + .loc 0 15 15 prologue_end # main.cpp:15:15 + leaq -5(%rbp), %rdi + callq _ZN1A1B5StateC2Ev + .loc 0 16 3 # main.cpp:16:3 + xorl %eax, %eax + .loc 0 16 3 epilogue_begin is_stmt 0 # main.cpp:16:3 + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp1: +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .section .text._ZN1A1B5StateC2Ev,"axG",@progbits,_ZN1A1B5StateC2Ev,comdat + .weak _ZN1A1B5StateC2Ev # -- Begin function _ZN1A1B5StateC2Ev + .p2align 4, 0x90 + .type _ZN1A1B5StateC2Ev,@function +_ZN1A1B5StateC2Ev: # @_ZN1A1B5StateC2Ev +.Lfunc_begin1: + .loc 0 8 0 is_stmt 1 # main.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movq %rdi, -8(%rbp) +.Ltmp2: + .loc 0 8 15 prologue_end epilogue_begin # main.cpp:8:15 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp3: +.Lfunc_end1: + .size _ZN1A1B5StateC2Ev, .Lfunc_end1-_ZN1A1B5StateC2Ev + .cfi_endproc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 50 # DW_AT_accessibility + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 116 # DW_AT_rnglists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 100 # DW_AT_object_pointer + .byte 19 # DW_FORM_ref4 + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 71 # DW_AT_specification + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 15 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 9 # Abbrev [9] 0xc:0x7f DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .quad 0 # DW_AT_low_pc + .byte 0 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lrnglists_table_base0 # DW_AT_rnglists_base + .byte 2 # Abbrev [2] 0x2b:0x1b DW_TAG_namespace + .byte 3 # DW_AT_name + .byte 2 # Abbrev [2] 0x2d:0x18 DW_TAG_namespace + .byte 4 # DW_AT_name + .byte 10 # Abbrev [10] 0x2f:0x15 DW_TAG_class_type + # DW_AT_declaration + .quad -1782593539102989756 # DW_AT_signature + .byte 4 # Abbrev [4] 0x38:0xb DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_formal_parameter + .long 97 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 11 # Abbrev [11] 0x46:0x1b DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 129 # DW_AT_type + # DW_AT_external + .byte 12 # Abbrev [12] 0x55:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 123 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 15 # DW_AT_decl_line + .long 47 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x61:0x5 DW_TAG_pointer_type + .long 47 # DW_AT_type + .byte 13 # Abbrev [13] 0x66:0x1b DW_TAG_subprogram + .byte 1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 119 # DW_AT_object_pointer + .byte 9 # DW_AT_linkage_name + .long 56 # DW_AT_specification + .byte 14 # Abbrev [14] 0x77:0x9 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .byte 11 # DW_AT_name + .long 133 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 15 # Abbrev [15] 0x81:0x4 DW_TAG_base_type + .byte 8 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 8 # Abbrev [8] 0x85:0x5 DW_TAG_pointer_type + .long 47 # DW_AT_type + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges0-.Lrnglists_table_base0 +.Ldebug_ranges0: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .Lfunc_end1-.Lfunc_begin1 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_str_offsets,"",@progbits + .long 52 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/home/ayermolo/local/tasks/T190087639/DW_TAG_class_type" # string offset=33 +.Linfo_string3: + .asciz "A" # string offset=89 +.Linfo_string4: + .asciz "B" # string offset=91 +.Linfo_string5: + .asciz "State" # string offset=93 +.Linfo_string6: + .asciz "InnerState" # string offset=99 +.Linfo_string7: + .asciz "main" # string offset=110 +.Linfo_string8: + .asciz "_ZN1A1B5StateC2Ev" # string offset=115 +.Linfo_string9: + .asciz "int" # string offset=133 +.Linfo_string10: + .asciz "S" # string offset=137 +.Linfo_string11: + .asciz "this" # string offset=139 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string9 + .long .Linfo_string8 + .long .Linfo_string10 + .long .Linfo_string11 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 1 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 6 # Header: bucket count + .long 6 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long .Ltu_begin0 # Type unit 0 + .long 0 # Bucket 0 + .long 0 # Bucket 1 + .long 1 # Bucket 2 + .long 2 # Bucket 3 + .long 3 # Bucket 4 + .long 6 # Bucket 5 + .long 193495088 # Hash in Bucket 2 + .long 1059643959 # Hash in Bucket 3 + .long 177670 # Hash in Bucket 4 + .long 274811398 # Hash in Bucket 4 + .long 2090499946 # Hash in Bucket 4 + .long 177671 # Hash in Bucket 5 + .long .Linfo_string9 # String in Bucket 2: int + .long .Linfo_string8 # String in Bucket 3: _ZN1A1B5StateC2Ev + .long .Linfo_string3 # String in Bucket 4: A + .long .Linfo_string5 # String in Bucket 4: State + .long .Linfo_string7 # String in Bucket 4: main + .long .Linfo_string4 # String in Bucket 5: B + .long .Lnames5-.Lnames_entries0 # Offset in Bucket 2 + .long .Lnames4-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 5 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 4 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 5 # Abbrev code + .byte 2 # DW_TAG_class_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 6 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 7 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames5: +.L2: + .byte 1 # Abbreviation code + .long 129 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames4: +.L3: + .byte 2 # Abbreviation code + .long 102 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: _ZN1A1B5StateC2Ev +.Lnames0: +.L4: + .byte 3 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 35 # DW_IDX_die_offset +.L7: # DW_IDX_parent + .byte 4 # Abbreviation code + .long 43 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: A +.Lnames2: +.L1: + .byte 5 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 39 # DW_IDX_die_offset + .long .L5-.Lnames_entries0 # DW_IDX_parent + .byte 2 # Abbreviation code + .long 102 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: State +.Lnames3: +.L0: + .byte 2 # Abbreviation code + .long 70 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames1: +.L5: + .byte 6 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 37 # DW_IDX_die_offset + .long .L4-.Lnames_entries0 # DW_IDX_parent +.L6: + .byte 7 # Abbreviation code + .long 45 # DW_IDX_die_offset + .long .L7-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: B + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-debug-names-enumeration-type-decl.s b/bolt/test/X86/dwarf5-debug-names-enumeration-type-decl.s new file mode 100644 index 0000000000000000000000000000000000000000..031175763d794bdfb0ad1b4f96ca32457d999465 --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-enumeration-type-decl.s @@ -0,0 +1,485 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-names %t.bolt >> %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s + +## This tests that BOLT doesn't generate entry for a DW_TAG_enumeration_type declaration with DW_AT_name. + +# POSTCHECK: DW_TAG_type_unit +# POSTCHECK: DW_TAG_enumeration_type [6] +# POSTCHECK-NEXT: DW_AT_name [DW_FORM_strx1] (indexed (00000009) string = "InnerState") +# POSTCHECK-NEXT: DW_AT_byte_size [DW_FORM_data1] (0x04) +# POSTCHECK-NEXT: DW_AT_declaration [DW_FORM_flag_present] (true) +# POSTCHECK: Name Index +# POSTCHECK-NOT: "InnerState" + +## -g2 -O0 -fdebug-types-section -gpubnames +## namespace B { +## template +## class State { +## public: +## enum class InnerState { STATE0 }; +## InnerState St; +## }; +## } +## +## int main() { +## B::State S; +## return 0; +## } + + .text + .file "main.cpp" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .file 0 "/DW_TAG_enumeration_type" "main.cpp" md5 0x2e8962f8ef4bf6eb6f8bd92966c0848b + .loc 0 10 0 # main.cpp:10:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -4(%rbp) +.Ltmp0: + .loc 0 12 3 prologue_end # main.cpp:12:3 + xorl %eax, %eax + .loc 0 12 3 epilogue_begin is_stmt 0 # main.cpp:12:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp1: +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .section .debug_info,"G",@progbits,8822129917070965541,comdat +.Ltu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad 8822129917070965541 # Type Signature + .long 37 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x2d DW_TAG_type_unit + .short 33 # DW_AT_language + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 2 # Abbrev [2] 0x23:0x1d DW_TAG_namespace + .byte 6 # DW_AT_name + .byte 3 # Abbrev [3] 0x25:0x1a DW_TAG_class_type + .byte 5 # DW_AT_calling_convention + .byte 10 # DW_AT_name + .byte 4 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 4 # Abbrev [4] 0x2b:0x6 DW_TAG_template_type_parameter + .long 64 # DW_AT_type + .byte 7 # DW_AT_name + .byte 5 # Abbrev [5] 0x31:0xa DW_TAG_member + .byte 8 # DW_AT_name + .long 59 # DW_AT_type + .byte 0 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .byte 0 # DW_AT_data_member_location + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 6 # Abbrev [6] 0x3b:0x3 DW_TAG_enumeration_type + .byte 9 # DW_AT_name + .byte 4 # DW_AT_byte_size + # DW_AT_declaration + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x40:0x4 DW_TAG_base_type + .byte 4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 47 # DW_TAG_template_type_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 13 # DW_TAG_member + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 56 # DW_AT_data_member_location + .byte 11 # DW_FORM_data1 + .byte 50 # DW_AT_accessibility + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 4 # DW_TAG_enumeration_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 0 # DW_CHILDREN_no + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Abbrev [8] 0xc:0x43 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 9 # Abbrev [9] 0x23:0x1b DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 10 # DW_AT_decl_line + .long 62 # DW_AT_type + # DW_AT_external + .byte 10 # Abbrev [10] 0x32:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 11 # DW_AT_decl_line + .long 68 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x3e:0x4 DW_TAG_base_type + .byte 4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 2 # Abbrev [2] 0x42:0xc DW_TAG_namespace + .byte 6 # DW_AT_name + .byte 11 # Abbrev [11] 0x44:0x9 DW_TAG_class_type + # DW_AT_declaration + .quad 8822129917070965541 # DW_AT_signature + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_str_offsets,"",@progbits + .long 48 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/home/ayermolo/local/tasks/T190087639/DW_TAG_enumeration_type" # string offset=33 +.Linfo_string3: + .asciz "main" # string offset=95 +.Linfo_string4: + .asciz "int" # string offset=100 +.Linfo_string5: + .asciz "S" # string offset=104 +.Linfo_string6: + .asciz "B" # string offset=106 +.Linfo_string7: + .asciz "Task" # string offset=108 +.Linfo_string8: + .asciz "St" # string offset=113 +.Linfo_string9: + .asciz "InnerState" # string offset=116 +.Linfo_string10: + .asciz "State" # string offset=127 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 1 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 4 # Header: bucket count + .long 4 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long .Ltu_begin0 # Type unit 0 + .long 1 # Bucket 0 + .long 0 # Bucket 1 + .long 2 # Bucket 2 + .long 3 # Bucket 3 + .long 193495088 # Hash in Bucket 0 + .long 2090499946 # Hash in Bucket 2 + .long 177671 # Hash in Bucket 3 + .long 624407275 # Hash in Bucket 3 + .long .Linfo_string4 # String in Bucket 0: int + .long .Linfo_string3 # String in Bucket 2: main + .long .Linfo_string6 # String in Bucket 3: B + .long .Linfo_string10 # String in Bucket 3: State + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 2 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 3 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 4 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 5 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 6 # Abbrev code + .byte 2 # DW_TAG_class_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames1: +.L0: + .byte 1 # Abbreviation code + .long 62 # DW_IDX_die_offset +.L2: # DW_IDX_parent + .byte 2 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 64 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames0: +.L3: + .byte 3 # Abbreviation code + .long 35 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames2: + .byte 4 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 35 # DW_IDX_die_offset +.L1: # DW_IDX_parent + .byte 5 # Abbreviation code + .long 66 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: B +.Lnames3: +.L4: + .byte 6 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 37 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: State + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-debug-names-skip-forward-decl.s b/bolt/test/X86/dwarf5-debug-names-skip-forward-decl.s new file mode 100644 index 0000000000000000000000000000000000000000..cae27f3cbd3f45d2c072d37ec33ca8d9080227b8 --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-skip-forward-decl.s @@ -0,0 +1,708 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --debug-names %t.bolt FileCheck --check-prefix=POSTCHECK %s + +## This test checks that BOLT doesn't set DW_IDX_parent an entry, InnerState, when it's parent is a forward declaration. + +# POSTCHECK: debug_names +# POSTCHECK: Bucket 0 [ +# POSTCHECK-NEXT: Name 1 { +# POSTCHECK-NEXT: Hash: 0xB888030 +# POSTCHECK-NEXT: String: 0x00000047 "int" +# POSTCHECK-NEXT: Entry @ 0xfb { +# POSTCHECK-NEXT: Abbrev: 0x1 +# POSTCHECK-NEXT: Tag: DW_TAG_base_type +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x0000005c +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 1 [ +# POSTCHECK-NEXT: EMPTY +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 2 [ +# POSTCHECK-NEXT: Name 2 { +# POSTCHECK-NEXT: Hash: 0x7C9A7F6A +# POSTCHECK-NEXT: String: {{.+}} "main" +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x2 +# POSTCHECK-NEXT: Tag: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000034 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Name 3 { +# POSTCHECK-NEXT: Hash: 0xE0CDC6A2 +# POSTCHECK-NEXT: String: {{.+}} "InnerState" +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x3 +# POSTCHECK-NEXT: Tag: DW_TAG_class_type +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x01 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000030 +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 3 [ +# POSTCHECK-NEXT: EMPTY +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 4 [ +# POSTCHECK-NEXT: EMPTY +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 5 [ +# POSTCHECK-NEXT: Name 4 { +# POSTCHECK-NEXT: Hash: 0x2F94396D +# POSTCHECK-NEXT: String: {{.+}} "_Z9get_statev" +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x2 +# POSTCHECK-NEXT: Tag: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000024 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Name 5 { +# POSTCHECK-NEXT: Hash: 0xCD86E3E5 +# POSTCHECK-NEXT: String: {{.+}} "get_state" +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x2 +# POSTCHECK-NEXT: Tag: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000024 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 6 [ +# POSTCHECK-NEXT: Name 6 { +# POSTCHECK-NEXT: Hash: 0x2B606 +# POSTCHECK-NEXT: String: {{.+}} "A" +# POSTCHECK-NEXT: Entry @ 0x11a { +# POSTCHECK-NEXT: Abbrev: 0x4 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x00 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000023 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Entry @ 0x120 { +# POSTCHECK-NEXT: Abbrev: 0x4 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x01 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000023 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Entry @ 0x126 { +# POSTCHECK-NEXT: Abbrev: 0x5 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000043 +# POSTCHECK-NEXT: DW_IDX_parent: +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Name 7 { +# POSTCHECK-NEXT: Hash: 0x10614A06 +# POSTCHECK-NEXT: String: {{.+}} "State" +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x6 +# POSTCHECK-NEXT: Tag: DW_TAG_structure_type +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x00 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000027 +# POSTCHECK-NEXT: DW_IDX_parent: Entry @ 0x137 +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: Bucket 7 [ +# POSTCHECK-NEXT: Name 8 { +# POSTCHECK-NEXT: Hash: 0x2B607 +# POSTCHECK-NEXT: String: {{.+}} "B" +# POSTCHECK-NEXT: Entry @ 0x137 { +# POSTCHECK-NEXT: Abbrev: 0x7 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x00 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000025 +# POSTCHECK-NEXT: DW_IDX_parent: Entry @ 0x11a +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x7 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_type_unit: 0x01 +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000025 +# POSTCHECK-NEXT: DW_IDX_parent: Entry @ 0x120 +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: Entry @ {{.+}} { +# POSTCHECK-NEXT: Abbrev: 0x8 +# POSTCHECK-NEXT: Tag: DW_TAG_namespace +# POSTCHECK-NEXT: DW_IDX_die_offset: 0x00000045 +# POSTCHECK-NEXT: DW_IDX_parent: Entry @ 0x126 +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: } +# POSTCHECK-NEXT: ] +# POSTCHECK-NEXT: } + +## clang++ -g2 -O0 -fdebug-types-section -gpubnames -S +## A::B::State::InnerState get_state() { return A::B::State::InnerState(); } +## int main() { +## return 0; +## } + +## Manually modified to fix bug in clang where for TU0 "B" was pointing to CU DIE instead of parent in TU + .text + .file "main.cpp" + .globl _Z9get_statev # -- Begin function _Z9get_statev + .p2align 4, 0x90 + .type _Z9get_statev,@function +_Z9get_statev: # @_Z9get_statev +.Lfunc_begin0: + .file 0 "/skipDecl" "main.cpp" md5 0xd417b4a09217d7c3ec58d64286de7ba4 + .loc 0 2 0 # main.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp +.Ltmp0: + .loc 0 2 39 prologue_end epilogue_begin # main.cpp:2:39 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp1: +.Lfunc_end0: + .size _Z9get_statev, .Lfunc_end0-_Z9get_statev + .cfi_endproc + # -- End function + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin1: + .loc 0 4 0 # main.cpp:4:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -4(%rbp) +.Ltmp2: + .loc 0 5 3 prologue_end # main.cpp:5:3 + xorl %eax, %eax + .loc 0 5 3 epilogue_begin is_stmt 0 # main.cpp:5:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp3: +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function + .section .debug_info,"G",@progbits,16664150534606561860,comdat +.Ltu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad -1782593539102989756 # Type Signature + .long 39 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x18 DW_TAG_type_unit + .short 33 # DW_AT_language + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 2 # Abbrev [2] 0x23:0xc DW_TAG_namespace + .byte 5 # DW_AT_name + .byte 2 # Abbrev [2] 0x25:0x9 DW_TAG_namespace + .byte 6 # DW_AT_name + .byte 3 # Abbrev [3] 0x27:0x6 DW_TAG_structure_type + .byte 5 # DW_AT_calling_convention + .byte 7 # DW_AT_name + .byte 1 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_info,"G",@progbits,1766745463811827694,comdat +.Ltu_begin1: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad 1766745463811827694 # Type Signature + .long 48 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x22 DW_TAG_type_unit + .short 33 # DW_AT_language + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 2 # Abbrev [2] 0x23:0x16 DW_TAG_namespace + .byte 5 # DW_AT_name + .byte 2 # Abbrev [2] 0x25:0x13 DW_TAG_namespace + .byte 6 # DW_AT_name + .byte 4 # Abbrev [4] 0x27:0x10 DW_TAG_structure_type + # DW_AT_declaration + .quad -1782593539102989756 # DW_AT_signature + .byte 5 # Abbrev [5] 0x30:0x6 DW_TAG_class_type + .byte 5 # DW_AT_calling_convention + .byte 8 # DW_AT_name + .byte 1 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 19 # DW_TAG_structure_type + .byte 0 # DW_CHILDREN_no + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 19 # DW_TAG_structure_type + .byte 1 # DW_CHILDREN_yes + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 0 # DW_CHILDREN_no + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 0 # DW_CHILDREN_no + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end2-.Ldebug_info_start2 # Length of Unit +.Ldebug_info_start2: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 6 # Abbrev [6] 0xc:0x54 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 0 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 7 # Abbrev [7] 0x23:0x10 DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 3 # DW_AT_linkage_name + .byte 4 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 79 # DW_AT_type + # DW_AT_external + .byte 8 # Abbrev [8] 0x33:0xf DW_TAG_subprogram + .byte 1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 4 # DW_AT_decl_line + .long 91 # DW_AT_type + # DW_AT_external + .byte 2 # Abbrev [2] 0x42:0x19 DW_TAG_namespace + .byte 5 # DW_AT_name + .byte 2 # Abbrev [2] 0x44:0x16 DW_TAG_namespace + .byte 6 # DW_AT_name + .byte 4 # Abbrev [4] 0x46:0x13 DW_TAG_structure_type + # DW_AT_declaration + .quad -1782593539102989756 # DW_AT_signature + .byte 9 # Abbrev [9] 0x4f:0x9 DW_TAG_class_type + # DW_AT_declaration + .quad 1766745463811827694 # DW_AT_signature + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x5b:0x4 DW_TAG_base_type + .byte 10 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end2: + .section .debug_str_offsets,"",@progbits + .long 48 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/skipDecl" # string offset=33 +.Linfo_string3: + .asciz "get_state" # string offset=80 +.Linfo_string4: + .asciz "_Z9get_statev" # string offset=90 +.Linfo_string5: + .asciz "main" # string offset=104 +.Linfo_string6: + .asciz "A" # string offset=109 +.Linfo_string7: + .asciz "B" # string offset=111 +.Linfo_string8: + .asciz "State" # string offset=113 +.Linfo_string9: + .asciz "InnerState" # string offset=119 +.Linfo_string10: + .asciz "int" # string offset=130 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string4 + .long .Linfo_string3 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string5 + .long .Linfo_string10 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 2 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 8 # Header: bucket count + .long 8 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long .Ltu_begin0 # Type unit 0 + .long .Ltu_begin1 # Type unit 1 + .long 1 # Bucket 0 + .long 0 # Bucket 1 + .long 2 # Bucket 2 + .long 0 # Bucket 3 + .long 0 # Bucket 4 + .long 4 # Bucket 5 + .long 6 # Bucket 6 + .long 8 # Bucket 7 + .long 193495088 # Hash in Bucket 0 + .long 2090499946 # Hash in Bucket 2 + .long -523385182 # Hash in Bucket 2 + .long 798243181 # Hash in Bucket 5 + .long -846797851 # Hash in Bucket 5 + .long 177670 # Hash in Bucket 6 + .long 274811398 # Hash in Bucket 6 + .long 177671 # Hash in Bucket 7 + .long .Linfo_string10 # String in Bucket 0: int + .long .Linfo_string5 # String in Bucket 2: main + .long .Linfo_string9 # String in Bucket 2: InnerState + .long .Linfo_string4 # String in Bucket 5: _Z9get_statev + .long .Linfo_string3 # String in Bucket 5: get_state + .long .Linfo_string6 # String in Bucket 6: A + .long .Linfo_string8 # String in Bucket 6: State + .long .Linfo_string7 # String in Bucket 7: B + .long .Lnames7-.Lnames_entries0 # Offset in Bucket 0 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 2 + .long .Lnames6-.Lnames_entries0 # Offset in Bucket 2 + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 5 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 5 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 6 + .long .Lnames5-.Lnames_entries0 # Offset in Bucket 6 + .long .Lnames4-.Lnames_entries0 # Offset in Bucket 7 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 2 # DW_TAG_class_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 4 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 5 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 6 # Abbrev code + .byte 19 # DW_TAG_structure_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 7 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 8 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames7: +.L6: + .byte 1 # Abbreviation code + .long 91 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames2: +.L1: + .byte 2 # Abbreviation code + .long 51 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames6: +.L8: + .byte 3 # Abbreviation code + .byte 1 # DW_IDX_type_unit + .long 48 # DW_IDX_die_offset + .byte 0 # End of list: InnerState +.Lnames1: +.L4: + .byte 2 # Abbreviation code + .long 35 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: _Z9get_statev +.Lnames0: + .byte 2 # Abbreviation code + .long 35 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: get_state +.Lnames3: +.LmanualLabel: + .byte 4 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 35 # DW_IDX_die_offset +.L3: # DW_IDX_parent + .byte 4 # Abbreviation code + .byte 1 # DW_IDX_type_unit + .long 35 # DW_IDX_die_offset +.L2: # DW_IDX_parent + .byte 5 # Abbreviation code + .long 66 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: A +.Lnames5: +.L0: + .byte 6 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 39 # DW_IDX_die_offset + .long .L5-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: State +.Lnames4: +.L5: + .byte 7 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 37 # DW_IDX_die_offset + .long .LmanualLabel-.Lnames_entries0 # DW_IDX_parent +.L7: + .byte 7 # Abbreviation code + .byte 1 # DW_IDX_type_unit + .long 37 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent +.L9: + .byte 8 # Abbreviation code + .long 68 # DW_IDX_die_offset + .long .L2-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: B + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-debug-names-structure-type-decl.s b/bolt/test/X86/dwarf5-debug-names-structure-type-decl.s new file mode 100644 index 0000000000000000000000000000000000000000..6eb2852c26ba0fecaddce303edd6a65a2d758fbe --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-structure-type-decl.s @@ -0,0 +1,671 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-names %t.bolt >> %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s + +## This tests that BOLT doesn't generate entry for a DW_TAG_structure_type declaration with DW_AT_name. + +# POSTCHECK: DW_TAG_type_unit +# POSTCHECK: DW_TAG_structure_type [7] +# POSTCHECK-NEXT: DW_AT_name [DW_FORM_strx1] (indexed (00000006) string = "InnerState") +# POSTCHECK-NEXT: DW_AT_declaration [DW_FORM_flag_present] (true) +# POSTCHECK: Name Index +# POSTCHECK-NOT: "InnerState" + +## -g2 -O0 -fdebug-types-section -gpubnames +## namespace A { +## namespace B { +## class State { +## public: +## struct InnerState{ +## InnerState() {} +## }; +## State(){} +## State(InnerState S){} +## }; +## } +## } +## +## int main() { +## A::B::State S; +## return 0; +## } + + + .text + .file "main.cpp" + .file 0 "/DW_TAG_structure_type" "main.cpp" md5 0xd43ba503b70d00353c195087e1fe16e2 + .section .debug_info,"G",@progbits,16664150534606561860,comdat +.Ltu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad -1782593539102989756 # Type Signature + .long 39 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x3b DW_TAG_type_unit + .short 33 # DW_AT_language + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 2 # Abbrev [2] 0x23:0x2a DW_TAG_namespace + .byte 3 # DW_AT_name + .byte 2 # Abbrev [2] 0x25:0x27 DW_TAG_namespace + .byte 4 # DW_AT_name + .byte 3 # Abbrev [3] 0x27:0x24 DW_TAG_class_type + .byte 5 # DW_AT_calling_convention + .byte 5 # DW_AT_name + .byte 1 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 4 # Abbrev [4] 0x2d:0xb DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x32:0x5 DW_TAG_formal_parameter + .long 77 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x38:0x10 DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_formal_parameter + .long 77 # DW_AT_type + # DW_AT_artificial + .byte 6 # Abbrev [6] 0x42:0x5 DW_TAG_formal_parameter + .long 72 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x48:0x2 DW_TAG_structure_type + .byte 6 # DW_AT_name + # DW_AT_declaration + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x4d:0x5 DW_TAG_pointer_type + .long 39 # DW_AT_type + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .text + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .loc 0 14 0 # main.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + subq $16, %rsp + movl $0, -4(%rbp) +.Ltmp0: + .loc 0 15 15 prologue_end # main.cpp:15:15 + leaq -5(%rbp), %rdi + callq _ZN1A1B5StateC2Ev + .loc 0 16 3 # main.cpp:16:3 + xorl %eax, %eax + .loc 0 16 3 epilogue_begin is_stmt 0 # main.cpp:16:3 + addq $16, %rsp + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp1: +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .section .text._ZN1A1B5StateC2Ev,"axG",@progbits,_ZN1A1B5StateC2Ev,comdat + .weak _ZN1A1B5StateC2Ev # -- Begin function _ZN1A1B5StateC2Ev + .p2align 4, 0x90 + .type _ZN1A1B5StateC2Ev,@function +_ZN1A1B5StateC2Ev: # @_ZN1A1B5StateC2Ev +.Lfunc_begin1: + .loc 0 8 0 is_stmt 1 # main.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movq %rdi, -8(%rbp) +.Ltmp2: + .loc 0 8 15 prologue_end epilogue_begin # main.cpp:8:15 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp3: +.Lfunc_end1: + .size _ZN1A1B5StateC2Ev, .Lfunc_end1-_ZN1A1B5StateC2Ev + .cfi_endproc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 50 # DW_AT_accessibility + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 19 # DW_TAG_structure_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 116 # DW_AT_rnglists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 2 # DW_TAG_class_type + .byte 1 # DW_CHILDREN_yes + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 100 # DW_AT_object_pointer + .byte 19 # DW_FORM_ref4 + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 71 # DW_AT_specification + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 52 # DW_AT_artificial + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 15 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 9 # Abbrev [9] 0xc:0x7f DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .quad 0 # DW_AT_low_pc + .byte 0 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lrnglists_table_base0 # DW_AT_rnglists_base + .byte 2 # Abbrev [2] 0x2b:0x1b DW_TAG_namespace + .byte 3 # DW_AT_name + .byte 2 # Abbrev [2] 0x2d:0x18 DW_TAG_namespace + .byte 4 # DW_AT_name + .byte 10 # Abbrev [10] 0x2f:0x15 DW_TAG_class_type + # DW_AT_declaration + .quad -1782593539102989756 # DW_AT_signature + .byte 4 # Abbrev [4] 0x38:0xb DW_TAG_subprogram + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + # DW_AT_declaration + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_formal_parameter + .long 97 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 11 # Abbrev [11] 0x46:0x1b DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 129 # DW_AT_type + # DW_AT_external + .byte 12 # Abbrev [12] 0x55:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 123 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 15 # DW_AT_decl_line + .long 47 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x61:0x5 DW_TAG_pointer_type + .long 47 # DW_AT_type + .byte 13 # Abbrev [13] 0x66:0x1b DW_TAG_subprogram + .byte 1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 119 # DW_AT_object_pointer + .byte 9 # DW_AT_linkage_name + .long 56 # DW_AT_specification + .byte 14 # Abbrev [14] 0x77:0x9 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .byte 11 # DW_AT_name + .long 133 # DW_AT_type + # DW_AT_artificial + .byte 0 # End Of Children Mark + .byte 15 # Abbrev [15] 0x81:0x4 DW_TAG_base_type + .byte 8 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 8 # Abbrev [8] 0x85:0x5 DW_TAG_pointer_type + .long 47 # DW_AT_type + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges0-.Lrnglists_table_base0 +.Ldebug_ranges0: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .Lfunc_end1-.Lfunc_begin1 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_str_offsets,"",@progbits + .long 52 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/home/ayermolo/local/tasks/T190087639/DW_TAG_structure_type" # string offset=33 +.Linfo_string3: + .asciz "A" # string offset=93 +.Linfo_string4: + .asciz "B" # string offset=95 +.Linfo_string5: + .asciz "State" # string offset=97 +.Linfo_string6: + .asciz "InnerState" # string offset=103 +.Linfo_string7: + .asciz "main" # string offset=114 +.Linfo_string8: + .asciz "_ZN1A1B5StateC2Ev" # string offset=119 +.Linfo_string9: + .asciz "int" # string offset=137 +.Linfo_string10: + .asciz "S" # string offset=141 +.Linfo_string11: + .asciz "this" # string offset=143 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string9 + .long .Linfo_string8 + .long .Linfo_string10 + .long .Linfo_string11 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 1 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 6 # Header: bucket count + .long 6 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long .Ltu_begin0 # Type unit 0 + .long 0 # Bucket 0 + .long 0 # Bucket 1 + .long 1 # Bucket 2 + .long 2 # Bucket 3 + .long 3 # Bucket 4 + .long 6 # Bucket 5 + .long 193495088 # Hash in Bucket 2 + .long 1059643959 # Hash in Bucket 3 + .long 177670 # Hash in Bucket 4 + .long 274811398 # Hash in Bucket 4 + .long 2090499946 # Hash in Bucket 4 + .long 177671 # Hash in Bucket 5 + .long .Linfo_string9 # String in Bucket 2: int + .long .Linfo_string8 # String in Bucket 3: _ZN1A1B5StateC2Ev + .long .Linfo_string3 # String in Bucket 4: A + .long .Linfo_string5 # String in Bucket 4: State + .long .Linfo_string7 # String in Bucket 4: main + .long .Linfo_string4 # String in Bucket 5: B + .long .Lnames5-.Lnames_entries0 # Offset in Bucket 2 + .long .Lnames4-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 5 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 4 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 5 # Abbrev code + .byte 2 # DW_TAG_class_type + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 6 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 2 # DW_IDX_type_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 7 # Abbrev code + .byte 57 # DW_TAG_namespace + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames5: +.L2: + .byte 1 # Abbreviation code + .long 129 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames4: +.L3: + .byte 2 # Abbreviation code + .long 102 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: _ZN1A1B5StateC2Ev +.Lnames0: +.L4: + .byte 3 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 35 # DW_IDX_die_offset +.L7: # DW_IDX_parent + .byte 4 # Abbreviation code + .long 43 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: A +.Lnames2: +.L1: + .byte 5 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 39 # DW_IDX_die_offset + .long .L5-.Lnames_entries0 # DW_IDX_parent + .byte 2 # Abbreviation code + .long 102 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: State +.Lnames3: +.L0: + .byte 2 # Abbreviation code + .long 70 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames1: +.L5: + .byte 6 # Abbreviation code + .byte 0 # DW_IDX_type_unit + .long 37 # DW_IDX_die_offset + .long .L4-.Lnames_entries0 # DW_IDX_parent +.L6: + .byte 7 # Abbreviation code + .long 45 # DW_IDX_die_offset + .long .L7-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: B + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-df-call-site-change-low-pc.test b/bolt/test/X86/dwarf5-df-call-site-change-low-pc.test index ea717a5e0888dc362ba2858b0908c46b0fe9f3c8..27614fe08634dbc8d79ac6d436eee7b1b9216200 100644 --- a/bolt/test/X86/dwarf5-df-call-site-change-low-pc.test +++ b/bolt/test/X86/dwarf5-df-call-site-change-low-pc.test @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/maindwodwo.txt ; RUN: cat %t/maindwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests that DW_AT_low_pc changes in DW_TAG_call_site. +;; Tests that DW_AT_low_pc changes in DW_TAG_call_site. ; PRE-BOLT-DWO-MAIN: version = 0x0005 ; PRE-BOLT-DWO-MAIN: DW_TAG_call_site diff --git a/bolt/test/X86/dwarf5-df-change-in-dw-op-gnu-addr-index-main.test b/bolt/test/X86/dwarf5-df-change-in-dw-op-gnu-addr-index-main.test index f266caec7af3bc1a610067d7ae1168e6f9ad4614..e31d1e0a6351b76007a9a0b0de13bd47ad877ecf 100644 --- a/bolt/test/X86/dwarf5-df-change-in-dw-op-gnu-addr-index-main.test +++ b/bolt/test/X86/dwarf5-df-change-in-dw-op-gnu-addr-index-main.test @@ -10,7 +10,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/maindwodwo.txt ; RUN: cat %t/maindwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests that new indices are assigned to DW_OP_GNU_addr_index. +;; Tests that new indices are assigned to DW_OP_GNU_addr_index. ; PRE-BOLT-DWO-MAIN: version = 0x0005 ; PRE-BOLT-DWO-MAIN: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x0) diff --git a/bolt/test/X86/dwarf5-df-cu-function-gc.test b/bolt/test/X86/dwarf5-df-cu-function-gc.test index 62f75c2c75532d447aa8868c93316b18401a5242..01a9ed9d85e53524b2b1ecd6e2b3431aaeba30bd 100644 --- a/bolt/test/X86/dwarf5-df-cu-function-gc.test +++ b/bolt/test/X86/dwarf5-df-cu-function-gc.test @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> addr.txt ; RUN: cat addr.txt | FileCheck -check-prefix=BOLT %s -; Tests we generate range when linker GCs only function used in CU +;; Tests we generate range when linker GCs only function used in CU ; BOLT: Addrs: ; BOLT-NEXT: 0x[[#%.16x,ADDR:]] diff --git a/bolt/test/X86/dwarf5-df-dualcu-loclist.test b/bolt/test/X86/dwarf5-df-dualcu-loclist.test index ea5b28a2e88f690dd9131aa6ac8d0b3b01eac43a..4461f5b35ff04ff0f7349d88328cd78b12d4632a 100644 --- a/bolt/test/X86/dwarf5-df-dualcu-loclist.test +++ b/bolt/test/X86/dwarf5-df-dualcu-loclist.test @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s -; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_loclistx] is updated correctly. +;; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_loclistx] is updated correctly. ; PRE-BOLT-DWO-MAIN: version = 0x0005 ; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10] diff --git a/bolt/test/X86/dwarf5-df-dualcu.test b/bolt/test/X86/dwarf5-df-dualcu.test index deaeea03669081f670e52d529428470a3f87af23..c6ad5afa305c2f484efad2e5f132d1e4dc91ecdf 100644 --- a/bolt/test/X86/dwarf5-df-dualcu.test +++ b/bolt/test/X86/dwarf5-df-dualcu.test @@ -16,8 +16,8 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s -; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. -; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx ##) are updated correctly. +;; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. +;; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx ##) are updated correctly. ; PRE-BOLT: version = 0x0005 ; PRE-BOLT: DW_TAG_skeleton_unit diff --git a/bolt/test/X86/dwarf5-df-inlined-subroutine-gc-sections-range.test b/bolt/test/X86/dwarf5-df-inlined-subroutine-gc-sections-range.test index 6e9bd0502d8b6e0b7a5e4d2cad8b18be90eda6a3..3132208475bd7728c88161c92cfceb91d4f13d61 100644 --- a/bolt/test/X86/dwarf5-df-inlined-subroutine-gc-sections-range.test +++ b/bolt/test/X86/dwarf5-df-inlined-subroutine-gc-sections-range.test @@ -19,8 +19,8 @@ ; RUN: cat log.txt | FileCheck -check-prefix=BOLT-PRE %s ; RUN: cat logBolt.txt | FileCheck -check-prefix=BOLT-MAIN %s -; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_ranges is 0, -; and split dwarf is enabled. +;; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_ranges is 0, +;; and split dwarf is enabled. ; BOLT-PRE: Addrs: ; BOLT-PRE: 0x0000000000000000 diff --git a/bolt/test/X86/dwarf5-df-inlined-subroutine-range-0.test b/bolt/test/X86/dwarf5-df-inlined-subroutine-range-0.test index 4ecc66f52ff84bce85d60aa4f2e761b5c71522c0..b9f38d42aa923f1f0478d1a236d88938d3cac3fc 100644 --- a/bolt/test/X86/dwarf5-df-inlined-subroutine-range-0.test +++ b/bolt/test/X86/dwarf5-df-inlined-subroutine-range-0.test @@ -9,8 +9,8 @@ ; RUN: llvm-dwarfdump --debug-info --verbose --show-form main.dwo.dwo >> log.txt ; RUN: cat log.txt | FileCheck -check-prefix=BOLT-MAIN %s -; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_ranges is 0, -; and split dwarf is enabled. +;; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_ranges is 0, +;; and split dwarf is enabled. ; BOLT-MAIN: 0x ; BOLT-MAIN: 0x diff --git a/bolt/test/X86/dwarf5-df-input-lowpc-ranges-cus.test b/bolt/test/X86/dwarf5-df-input-lowpc-ranges-cus.test new file mode 100644 index 0000000000000000000000000000000000000000..a325395fd532027ce1f2adb6e9530731782d69a2 --- /dev/null +++ b/bolt/test/X86/dwarf5-df-input-lowpc-ranges-cus.test @@ -0,0 +1,87 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-other.s \ +; RUN: -split-dwarf-file=mainOther.dwo -o other.o +; RUN: %clang %cflags main.o other.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --show-form --verbose --debug-rnglists main.exe.bolt &> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt >> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt +; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s + +;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges. + +; BOLT: Addrs: [ +; BOLT-NEXT: 0x[[#%.16x,ADDR1:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR2:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR3:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR4:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR5:]] + +; BOLT: Addrs: [ +; BOLT-NEXT: 0x[[#%.16x,ADDR6:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR7:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR8:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR9:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR10:]] + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "main.dwo.dwo") +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010 +; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDR1 + 0x16]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x16]], 0x[[#ADDR1 + 0x24]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x24]], 0x[[#ADDR1 + 0x29]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x30]], 0x[[#ADDR1 + 0x46]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x50]], 0x[[#ADDR1 + 0x77]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x77]], 0x[[#ADDR1 + 0x85]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x85]], 0x[[#ADDR1 + 0x9f]]) +; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) +; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "mainOther.dwo.dwo") +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x0000003b +; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDR6 + 0x16]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x16]], 0x[[#ADDR6 + 0x24]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x24]], 0x[[#ADDR6 + 0x29]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x30]], 0x[[#ADDR6 + 0x46]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x50]], 0x[[#ADDR6 + 0x70]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x70]], 0x[[#ADDR6 + 0x7e]]) +; BOLT-NEXT: [0x[[#ADDR6 + 0x7e]], 0x[[#ADDR6 + 0x98]]) +; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000038) +; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000037) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000014 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000016) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000016, 0x0000000000000024) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000024, 0x0000000000000029)) +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000002, 0x0000000000000029) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000029, 0x0000000000000037) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000037, 0x0000000000000051)) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000014 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000016) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000016, 0x0000000000000024) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000024, 0x0000000000000029)) +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000002, 0x0000000000000022) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000022, 0x0000000000000030) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000030, 0x000000000000004a)) diff --git a/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test b/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test index 1867f49a520455c1161c27454f652f42821b3e36..2123353044c37b86baccdc61b96717bc5cca5bc7 100644 --- a/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test +++ b/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test @@ -1,7 +1,7 @@ ; RUN: rm -rf %t ; RUN: mkdir %t ; RUN: cd %t -;; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-main.s \ +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-main.s \ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o -o main.exe ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections @@ -12,7 +12,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/mainddwodwo.txt ; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Tests BOLT handles correctly Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. +;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. ; BOLT: Addrs: [ ; BOLT-NEXT: 0x[[#%.16x,ADDR1:]] diff --git a/bolt/test/X86/dwarf5-df-mono-dualcu.test b/bolt/test/X86/dwarf5-df-mono-dualcu.test index 12269287ef132f18fe66b8460cd2aa246674d49d..13272cc1c3c4da925d777560a1a38d23c3716a6e 100644 --- a/bolt/test/X86/dwarf5-df-mono-dualcu.test +++ b/bolt/test/X86/dwarf5-df-mono-dualcu.test @@ -13,7 +13,7 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-MAIN %s -; Testing dwarf5 mix of split dwarf and monolithic CUs. +;; Testing dwarf5 mix of split dwarf and monolithic CUs. ; PRE-BOLT: version = 0x0005 ; PRE-BOLT: DW_TAG_skeleton_unit diff --git a/bolt/test/X86/dwarf5-df-output-dir-same-name.test b/bolt/test/X86/dwarf5-df-output-dir-same-name.test index 1f78da2022b8ced39b8be57fcb458f11b1ffea24..b466f87d95e5eb1ee68691ff4b348c5b88e6694a 100644 --- a/bolt/test/X86/dwarf5-df-output-dir-same-name.test +++ b/bolt/test/X86/dwarf5-df-output-dir-same-name.test @@ -14,15 +14,15 @@ ; RUN: llvm-dwarfdump --debug-info main.exe.bolt >> log ; RUN: cat log | FileCheck -check-prefix=BOLT %s -; Tests that BOLT handles correctly writing out .dwo files to the same directory when input has input where part of path -; is in DW_AT_dwo_name and the .dwo file names are the same. +;; Tests that BOLT handles correctly writing out .dwo files to the same directory when input has input where part of path +;; is in DW_AT_dwo_name and the .dwo file names are the same. ; BOLT: split.dwo0.dwo ; BOLT: split.dwo1.dwo ; BOLT: DW_AT_dwo_name ("split.dwo0.dwo") ; BOLT: DW_AT_dwo_name ("split.dwo1.dwo") -; Tests that when --dwarf-output-path is specified, but path do not exist BOLT creates it. +;; Tests that when --dwarf-output-path is specified, but path do not exist BOLT creates it. ; RUN: rm -rf dwo ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --dwarf-output-path=%t/dwo @@ -30,8 +30,8 @@ ; RUN: llvm-dwarfdump --debug-info main.exe.bolt >> log ; RUN: cat log | FileCheck -check-prefix=BOLT1 %s -; Tests that BOLT handles correctly writing out .dwo files to the same directory when input has input where part of path -; is in DW_AT_dwo_name and the .dwo file names are the same. +;; Tests that BOLT handles correctly writing out .dwo files to the same directory when input has input where part of path +;; is in DW_AT_dwo_name and the .dwo file names are the same. ; BOLT1: split.dwo0.dwo ; BOLT1: split.dwo1.dwo diff --git a/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test b/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test index 036d4c9168ee5aa3f5941abbaa565be6c139e826..754f05dc963288873b6f7a120d94e52338ac2b20 100644 --- a/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test +++ b/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test @@ -11,7 +11,7 @@ ; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-DWO-MAIN %s ; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-DWO-HELPER %s -; Tests that BOLT correctly handles DWARF5 DWP file as input. Output has correct CU, and all the type units are written out. +;; Tests that BOLT correctly handles DWARF5 DWP file as input. Output has correct CU, and all the type units are written out. ; BOLT-DWO-DWO-MAIN: debug_info.dwo ; BOLT-DWO-DWO-MAIN-NEXT: type_signature = 0x49dc260088be7e56 diff --git a/bolt/test/X86/dwarf5-do-no-convert-low-pc-high-pc-to-ranges.test b/bolt/test/X86/dwarf5-do-no-convert-low-pc-high-pc-to-ranges.test index 1a59844814cda032dca0e58b69c67638e8110b2c..1c7843e1f210fa808069fcc47aed7afefc0fc0e9 100644 --- a/bolt/test/X86/dwarf5-do-no-convert-low-pc-high-pc-to-ranges.test +++ b/bolt/test/X86/dwarf5-do-no-convert-low-pc-high-pc-to-ranges.test @@ -6,8 +6,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, -# when there is only one output range entry. +## This test checks that we do not convert low_pc/high_pc to ranges for DW_TAG_inlined_subroutine, +## when there is only one output range entry. # PRECHECK: DW_TAG_inlined_subroutine # PRECHECK: DW_AT_abstract_origin diff --git a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb11.test b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb11.test index 17663a7f72df4f40ea882e003e2ad0bee4c49271..10ad6ed404f1c1a0e508906b2d76bd1e09f49e67 100644 --- a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb11.test +++ b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb11.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %tgdb.exe -o %tgdb.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %tgdb.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB. +## Tests that BOLT correctly handles gdb-index generated by GDB. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb9.test b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb9.test index c283ec02387fea3e427f99b75526b611bb8b6486..2da0bcca89b2ac748fcbd02c178ae603a9c0f642 100644 --- a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb9.test +++ b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-gdb-generated-gdb9.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %tgdb.exe -o %tgdb.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %tgdb.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB. +## Tests that BOLT correctly handles gdb-index generated by GDB. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 3 entries diff --git a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-lld-generated.test b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-lld-generated.test index 6eaad4cd06d3b9928fb0577fc1611c44f74b6c47..9be540352005de19d9aeee7de48aba748fca67bc 100644 --- a/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-lld-generated.test +++ b/bolt/test/X86/dwarf5-dwarf4-gdb-index-types-lld-generated.test @@ -6,7 +6,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by LLD. +## Tests that BOLT correctly handles gdb-index generated by LLD. # POSTCHECK: Version = 7 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf5-dwarf4-monolithic.test b/bolt/test/X86/dwarf5-dwarf4-monolithic.test index 274451c4546ac611bd526d9ac675db355e7d3e79..ff0f6990aaac0f3ab5cb68c13f584272d669e736 100644 --- a/bolt/test/X86/dwarf5-dwarf4-monolithic.test +++ b/bolt/test/X86/dwarf5-dwarf4-monolithic.test @@ -15,7 +15,7 @@ # RUN: FileCheck --check-prefix=CHECK-LINE %s --input-file %t_line.txt -# Check BOLT handles monolithic mix of DWARF4 and DWARF5. +## Check BOLT handles monolithic mix of DWARF4 and DWARF5. # main.cpp # PRECHECK: version = 0x0005 diff --git a/bolt/test/X86/dwarf5-dwarf4-types-backward-forward-cross-reference.test b/bolt/test/X86/dwarf5-dwarf4-types-backward-forward-cross-reference.test index 8afbe9e747d24030cd2451788b40c8f1f10d4ca2..070648c042c1d3188c36873fc822781e394e4e42 100644 --- a/bolt/test/X86/dwarf5-dwarf4-types-backward-forward-cross-reference.test +++ b/bolt/test/X86/dwarf5-dwarf4-types-backward-forward-cross-reference.test @@ -7,8 +7,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-types %t.bolt | FileCheck --check-prefix=POSTCHECKTU %s -# This test checks that BOLT handles correctly backward and forward cross CU references -# for DWARF5 and DWARF4 with -fdebug-types-section +## This test checks that BOLT handles correctly backward and forward cross CU references +## for DWARF5 and DWARF4 with -fdebug-types-section # POSTCHECK: version = 0x0005 # POSTCHECK: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test b/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test index 69758505c2a61a49bf73e6b45ecef03a00c6c5f6..b6e9f60bbfc70795620bfc663e472f811965ac7e 100644 --- a/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test +++ b/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test @@ -13,9 +13,9 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-cu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-CU-INDEX %s -; Test input into bolt a .dwo file with TU Index. -; Test split-dwarf and monolithic TUs. -; Make sure the output .dwp file has a type and cu information. +;; Test input into bolt a .dwo file with TU Index. +;; Test split-dwarf and monolithic TUs. +;; Make sure the output .dwp file has a type and cu information. ; PRE-BOLT: Type Unit ; PRE-BOLT-SAME: 0x675d23e4f33235f2 diff --git a/bolt/test/X86/dwarf5-ftypes-dwp-input-dwo-output.test b/bolt/test/X86/dwarf5-ftypes-dwp-input-dwo-output.test index b59a3f056b226fea6f854b7cf82bbb417411fe99..5381039ffa375a9e77da52e82589f709bd0025cc 100644 --- a/bolt/test/X86/dwarf5-ftypes-dwp-input-dwo-output.test +++ b/bolt/test/X86/dwarf5-ftypes-dwp-input-dwo-output.test @@ -13,8 +13,8 @@ ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT %s -; Test input into bolt a DWP file with TU Index. -; Make sure output in the .dwo files has type information. +;; Test input into bolt a DWP file with TU Index. +;; Make sure output in the .dwo files has type information. ; PRE-BOLT: DW_TAG_type_unit ; PRE-BOLT: DW_TAG_type_unit diff --git a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test index f8f33b321a7d4682edf01e46fb8c403d157188c4..338a476e46f3b3ea8ead71583e37683da2e3d101 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %tgdb.exe -o %tgdb.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %tgdb.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB. +## Tests that BOLT correctly handles gdb-index generated by GDB. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test index bccc92d3de84df324e5bed57364a76d3b1a21625..c9d3913a1933cda1e65931f3306dff0ec5ee415d 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test @@ -7,7 +7,7 @@ # RUN: llvm-bolt %tgdb.exe -o %tgdb.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %tgdb.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB. +## Tests that BOLT correctly handles gdb-index generated by GDB. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 4 entries diff --git a/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test b/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test index 18fe7daa4ad48590d7fd9dd0531e02a9f9d17ba5..a770e40260dde349b76f6e3ea6a97336b702aaaa 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test @@ -6,7 +6,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by LLD. +## Tests that BOLT correctly handles gdb-index generated by LLD. # POSTCHECK: Version = 7 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf5-locaddrx.test b/bolt/test/X86/dwarf5-locaddrx.test index 00e15101f85311235f9c27c66e38a48533b118a6..6cb198515e0fff57e002729aceedcbb35a8e39d1 100644 --- a/bolt/test/X86/dwarf5-locaddrx.test +++ b/bolt/test/X86/dwarf5-locaddrx.test @@ -12,8 +12,8 @@ ; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.dwo | FileCheck -check-prefix=PRE-BOLT-DWO %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.dwo.dwo | FileCheck -check-prefix=BOLT-DWO %s -; Testing dwarf5 split dwarf. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. -; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x0) is updated correctly. +;; Testing dwarf5 split dwarf. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo. +;; Checking that DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x0) is updated correctly. ; PRE-BOLT: version = 0x0005 ; PRE-BOLT: DW_TAG_skeleton_unit diff --git a/bolt/test/X86/dwarf5-locexpr-addrx.s b/bolt/test/X86/dwarf5-locexpr-addrx.s index 1e8183b7527dfafce91b94bb04b63d9276483281..6a8d81d2d08ee7db95b26a0a7ab794404ed4ddf4 100644 --- a/bolt/test/X86/dwarf5-locexpr-addrx.s +++ b/bolt/test/X86/dwarf5-locexpr-addrx.s @@ -6,8 +6,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that we correctly encode new index into .debug_addr section -# from DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x#) +## This test checks that we correctly encode new index into .debug_addr section +## from DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x#) # PRECHECK: version = 0x0005 # PRECHECK: DW_TAG_variable diff --git a/bolt/test/X86/dwarf5-locexpr-referrence.test b/bolt/test/X86/dwarf5-locexpr-referrence.test index 27b7a2b38d97acc361d9e019a161f45906854910..ea73d7601b2534bf53cbe24b025e5baa734e39e4 100644 --- a/bolt/test/X86/dwarf5-locexpr-referrence.test +++ b/bolt/test/X86/dwarf5-locexpr-referrence.test @@ -6,7 +6,7 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=CHECK %s -# This test checks that we update relative DIE references with DW_OP_convert that are in locexpr. +## This test checks that we update relative DIE references with DW_OP_convert that are in locexpr. # CHECK: version = 0x0005 # CHECK: DW_TAG_variable diff --git a/bolt/test/X86/dwarf5-loclist-offset-form.test b/bolt/test/X86/dwarf5-loclist-offset-form.test index d4b8ab15fd0f5bff5956716a930ddd3500602dda..3178c11a67069fba01d2021df49312a5c7c59911 100644 --- a/bolt/test/X86/dwarf5-loclist-offset-form.test +++ b/bolt/test/X86/dwarf5-loclist-offset-form.test @@ -9,7 +9,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# Checks we can handle DWARF5 CU with DWARF4 DW_AT_location access pattern. +## Checks we can handle DWARF5 CU with DWARF4 DW_AT_location access pattern. # PRECHECK: DW_TAG_compile_unit # PRECHECK: DW_TAG_variable [5] diff --git a/bolt/test/X86/dwarf5-lowpc-highpc-convert.s b/bolt/test/X86/dwarf5-lowpc-highpc-convert.s index aba62ea9845412dc62cc38d6bf84d454c60631a0..6cdc345b435e185cc4dfb31d1cf34976544b8def 100644 --- a/bolt/test/X86/dwarf5-lowpc-highpc-convert.s +++ b/bolt/test/X86/dwarf5-lowpc-highpc-convert.s @@ -8,8 +8,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that DW_AT_low_pc/DW_AT_high_pc is converted to DW_AT_low_pc/DW_AT_ranges. -# Checks that DW_AT_rnglists_base is inserted, and that correct address is used. +## This tests checks that DW_AT_low_pc/DW_AT_high_pc is converted to DW_AT_low_pc/DW_AT_ranges. +## Checks that DW_AT_rnglists_base is inserted, and that correct address is used. # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_low_pc diff --git a/bolt/test/X86/dwarf5-multiple-dw-op-addrx-locexpr.s b/bolt/test/X86/dwarf5-multiple-dw-op-addrx-locexpr.s index 6429ccd86b32535f2f3ce32c7856c37f180507d5..b88e69e86eb70187c070ef659b502dcee2a5ed4c 100644 --- a/bolt/test/X86/dwarf5-multiple-dw-op-addrx-locexpr.s +++ b/bolt/test/X86/dwarf5-multiple-dw-op-addrx-locexpr.s @@ -21,7 +21,7 @@ # CHECK: DW_AT_decl_line [DW_FORM_data1] # CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x2, DW_OP_piece 0x4, DW_OP_addrx 0x3, DW_OP_piece 0x4) -# This test checks that we update DW_AT_location [DW_FORM_exprloc] with multiple DW_OP_addrx. +## This test checks that we update DW_AT_location [DW_FORM_exprloc] with multiple DW_OP_addrx. # struct pair {int i; int j; }; # static pair p; diff --git a/bolt/test/X86/dwarf5-one-loclists-two-bases.test b/bolt/test/X86/dwarf5-one-loclists-two-bases.test index 7ef53f6813814f1cef6e94d92b24ffc1f4f7948b..873512aad5e8d8a6b9b63ecdd1eb11f38c0e8081 100644 --- a/bolt/test/X86/dwarf5-one-loclists-two-bases.test +++ b/bolt/test/X86/dwarf5-one-loclists-two-bases.test @@ -9,8 +9,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that re-writing of .debug_loclists is handled correctly when one of the CUs -# doesn't have any DW_AT_location accesses. +## This tests checks that re-writing of .debug_loclists is handled correctly when one of the CUs +## doesn't have any DW_AT_location accesses. # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c) diff --git a/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s b/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s index 481ff41c301f331da3874cd5a7c0266b100a168c..647d498956195ac2ef3b824ce5a66e57c8cfb492 100644 --- a/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s +++ b/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s @@ -8,7 +8,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests conversion for DWARF5 ranges DW_AT_ranges [DW_FORM_sec_offset] to DW_AT_ranges [DW_FORM_rnglistx] +## This tests conversion for DWARF5 ranges DW_AT_ranges [DW_FORM_sec_offset] to DW_AT_ranges [DW_FORM_rnglistx] # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_ranges [DW_FORM_sec_offset] diff --git a/bolt/test/X86/dwarf5-return-pc-form-addr.test b/bolt/test/X86/dwarf5-return-pc-form-addr.test index 737aae91608ba0d80ae510d5eff4e03d4a3b9141..5a83615cac031cc42f7f643d7bfcca4340c5ffc0 100644 --- a/bolt/test/X86/dwarf5-return-pc-form-addr.test +++ b/bolt/test/X86/dwarf5-return-pc-form-addr.test @@ -11,7 +11,7 @@ # RUN: cat %tmain.txt | FileCheck --check-prefix=PRECHECK %s # RUN: cat %tmainbolt.txt | FileCheck --check-prefix=POSTCHECK %s -# Test checks that DW_AT_call_return_pc points to an address after the callq instruction. +## Test checks that DW_AT_call_return_pc points to an address after the callq instruction. # PRECHECK: DW_TAG_call_site [11] # PRECHECK-NEXT: DW_AT_call_origin [DW_FORM_ref4] diff --git a/bolt/test/X86/dwarf5-return-pc.test b/bolt/test/X86/dwarf5-return-pc.test index 987a9fa8cefadef545a4044e181e2b8d3e90f663..e9ef99ef5b945fb3c52278ed482f1eaacef02267 100644 --- a/bolt/test/X86/dwarf5-return-pc.test +++ b/bolt/test/X86/dwarf5-return-pc.test @@ -11,7 +11,7 @@ # RUN: cat %tmain.txt | FileCheck --check-prefix=PRECHECK %s # RUN: cat %tmainbolt.txt | FileCheck --check-prefix=POSTCHECK %s -# Test checks that DW_AT_call_return_pc points to an address after the callq instruction. +## Test checks that DW_AT_call_return_pc points to an address after the callq instruction. # PRECHECK: DW_TAG_call_site [11] # PRECHECK-NEXT: DW_AT_call_origin [DW_FORM_ref4] diff --git a/bolt/test/X86/dwarf5-shared-str-offset-base.s b/bolt/test/X86/dwarf5-shared-str-offset-base.s index 0756d537b25a5ddb00410578fbaf451d3b9987d5..d8492298a1604b5aad2a651959f58ba48adc5d76 100644 --- a/bolt/test/X86/dwarf5-shared-str-offset-base.s +++ b/bolt/test/X86/dwarf5-shared-str-offset-base.s @@ -9,8 +9,8 @@ # RUN: llvm-dwarfdump --show-section-sizes %tmain.exe.bolt >> %tout.text # RUN: cat %tout.text | FileCheck %s -# This test checks that with DWARF5 when two CUs share the same .debug_str_offsets -# entry BOLT does not create a duplicate. +## This test checks that with DWARF5 when two CUs share the same .debug_str_offsets +## entry BOLT does not create a duplicate. # CHECK: DW_AT_str_offsets_base (0x[[#%.8x,ADDR:]] # CHECK: DW_AT_str_offsets_base (0x[[#ADDR]] diff --git a/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test b/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test index 6fc0825cd2fae4dc4e573a946adcc37128daced9..2cfe5e26bd4cdc1da0c5adf6fb2a043c2b325c6a 100644 --- a/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test +++ b/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test @@ -20,7 +20,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-line main.bolt | FileCheck --check-prefix=POSTCHECK-LINE %s -# Check BOLT handles monolithic mix of DWARF4 and DWARF5. +## Check BOLT handles monolithic mix of DWARF4 and DWARF5. # main.cpp # PRECHECK: version = 0x0005 @@ -89,7 +89,7 @@ # PRECHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] # PRECHECK-NEXT: DW_AT_high_pc -# Checking debug line. +## Checking debug line. # PRECHECK-LINE: debug_line[ # PRECHECK-LINE: version: 5 @@ -262,7 +262,7 @@ # POSTCHECK-DWO-HELPER1-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000018 # POSTCHECK-DWO-HELPER1-NEXT: [0x0000000000000000, 0x0000000000000003)) -# Checking debug line. +## Checking debug line. # POSTCHECK-LINE: debug_line[ # POSTCHECK-LINE: version: 5 diff --git a/bolt/test/X86/dwarf5-split-gdb-index-types-gdb-generated.test b/bolt/test/X86/dwarf5-split-gdb-index-types-gdb-generated.test index 414f3d6954947ecd6d32b7ef899e092cbc2517a1..ec2b8f7084c78d6cb9148aed945d3cbd1d024d1a 100644 --- a/bolt/test/X86/dwarf5-split-gdb-index-types-gdb-generated.test +++ b/bolt/test/X86/dwarf5-split-gdb-index-types-gdb-generated.test @@ -10,7 +10,7 @@ # RUN: llvm-bolt maingdb.exe -o maingdb.exe.bolt --update-debug-sections # RUN: llvm-dwarfdump --gdb-index maingdb.exe.bolt | FileCheck --check-prefix=POSTCHECK %s -# Tests that BOLT correctly handles gdb-index generated by GDB with split-dwarf DWARF4. +## Tests that BOLT correctly handles gdb-index generated by GDB with split-dwarf DWARF4. # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries diff --git a/bolt/test/X86/dwarf5-subprogram-multiple-ranges-cus.test b/bolt/test/X86/dwarf5-subprogram-multiple-ranges-cus.test new file mode 100644 index 0000000000000000000000000000000000000000..bcf63fe6a0d8cebf3292aaeea8ed38b535372783 --- /dev/null +++ b/bolt/test/X86/dwarf5-subprogram-multiple-ranges-cus.test @@ -0,0 +1,38 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-subprogram-multiple-ranges-main.s -o %t1.o +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-subprogram-multiple-ranges-other.s -o %t2.o +# RUN: %clang %cflags %t1.o %t2.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-objdump %t.bolt --disassemble > %t1.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt +# RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s + +## This test checks that BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries and handles multiple CUs with ranges. + +# POSTCHECK: _Z7doStuffi>: +# POSTCHECK: [[#%.6x,ADDR:]] +# POSTCHECK: _Z7doStuffi.__part.1>: +# POSTCHECK-NEXT: [[#%.6x,ADDR1:]] +# POSTCHECK: _Z7doStuffi.__part.2>: +# POSTCHECK-NEXT: [[#%.6x,ADDR2:]] + +# POSTCHECK: _Z12doStuffOtheri>: +# POSTCHECK: [[#%.6x,ADDR3:]] +# POSTCHECK: _Z12doStuffOtheri.__part.1>: +# POSTCHECK-NEXT: [[#%.6x,ADDR4:]] +# POSTCHECK: _Z12doStuffOtheri.__part.2>: +# POSTCHECK-NEXT: [[#%.6x,ADDR5:]] + +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_AT_ranges +# POSTCHECK-NEXT: [0x0000000000[[#ADDR]], 0x0000000000[[#ADDR + 0xf]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR1]], 0x0000000000[[#ADDR1 + 0xb]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR2]], 0x0000000000[[#ADDR2 + 0x5]])) + +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK-NEXT: DW_AT_ranges +# POSTCHECK-NEXT: [0x0000000000[[#ADDR3]], 0x0000000000[[#ADDR3 + 0xf]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR4]], 0x0000000000[[#ADDR4 + 0xb]]) +# POSTCHECK-NEXT: [0x0000000000[[#ADDR5]], 0x0000000000[[#ADDR5 + 0x5]])) diff --git a/bolt/test/X86/dwarf5-subprogram-multiple-ranges.test b/bolt/test/X86/dwarf5-subprogram-multiple-ranges.test index 9fedd57b0c6ff752f2598b18705cf5fca48e63c3..80bf8f8990407175ec0b1d261c34be31d23595cc 100644 --- a/bolt/test/X86/dwarf5-subprogram-multiple-ranges.test +++ b/bolt/test/X86/dwarf5-subprogram-multiple-ranges.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with multiple entries. # POSTCHECK: _Z7doStuffi>: # POSTCHECK: [[#%.6x,ADDR:]] diff --git a/bolt/test/X86/dwarf5-subprogram-single-gc-ranges.test b/bolt/test/X86/dwarf5-subprogram-single-gc-ranges.test index 9f8f895ed5f16d1630b24a5e60a27fe20374bd75..21944eba4c92f8e2c06e7bb83bd953370ff9862a 100644 --- a/bolt/test/X86/dwarf5-subprogram-single-gc-ranges.test +++ b/bolt/test/X86/dwarf5-subprogram-single-gc-ranges.test @@ -6,7 +6,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry, when function was GCed. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry, when function was GCed. # POSTCHECK: DW_TAG_subprogram # POSTCHECK-NEXT: DW_AT_frame_base diff --git a/bolt/test/X86/dwarf5-subprogram-single-ranges.test b/bolt/test/X86/dwarf5-subprogram-single-ranges.test index f53780eeb5b032458f074595b7b13c2fd374af87..8ffa73c8c9dff042d9981ed46cdf1167f395d935 100644 --- a/bolt/test/X86/dwarf5-subprogram-single-ranges.test +++ b/bolt/test/X86/dwarf5-subprogram-single-ranges.test @@ -7,7 +7,7 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt # RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry. +## This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry. # POSTCHECK: _Z7doStuffi>: # POSTCHECK: [[#%.6x,ADDR:]] diff --git a/bolt/test/X86/dwarf5-two-loclists.test b/bolt/test/X86/dwarf5-two-loclists.test index f5c399a944a9114fe065b520994ab0356dbffa03..2ede02f3b76fba21810c03ada8da5fc011a47791 100644 --- a/bolt/test/X86/dwarf5-two-loclists.test +++ b/bolt/test/X86/dwarf5-two-loclists.test @@ -9,8 +9,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that re-writing of .debug_loclists is handled correctly for two CUs, -# and two loclist entries. +## This tests checks that re-writing of .debug_loclists is handled correctly for two CUs, +## and two loclist entries. # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c) diff --git a/bolt/test/X86/dwarf5-two-rnglists.test b/bolt/test/X86/dwarf5-two-rnglists.test index 98330558a573b7e5cdf92f5d88fd9f70ca65e1e3..17cdc7643bae57bdb96ce44219c43377d3a308cc 100644 --- a/bolt/test/X86/dwarf5-two-rnglists.test +++ b/bolt/test/X86/dwarf5-two-rnglists.test @@ -9,8 +9,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This tests checks that re-writing of .debug_rnglists is handled correctly for two CUs, -# and DW_AT_low_pc/DW_AT_high_pc conversion is handled correctly. +## This tests checks that re-writing of .debug_rnglists is handled correctly for two CUs, +## and DW_AT_low_pc/DW_AT_high_pc conversion is handled correctly. # PRECHECK: version = 0x0005 # PRECHECK: DW_AT_low_pc [DW_FORM_addrx] diff --git a/bolt/test/X86/dwarf5-types-backward-cross-reference.s b/bolt/test/X86/dwarf5-types-backward-cross-reference.s index 9278c23ef51077a3a390f692a0db6dd81d91770c..2345cac2fde96975f9891708c376cff9f64f958d 100644 --- a/bolt/test/X86/dwarf5-types-backward-cross-reference.s +++ b/bolt/test/X86/dwarf5-types-backward-cross-reference.s @@ -5,8 +5,8 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles backward cross CU references for dwarf5 -# when -fdebug-types-sections is specified. +## This test checks that BOLT handles backward cross CU references for dwarf5 +## when -fdebug-types-sections is specified. # The assembly was manually modified to do cross CU reference. diff --git a/bolt/test/X86/dwarf5-types-forward-cross-reference.s b/bolt/test/X86/dwarf5-types-forward-cross-reference.s index feeb75da93a85d0d36d3603781da5164aea6b7bc..5ff4ba4286dbf08208a59639ec7aa46701f2a178 100644 --- a/bolt/test/X86/dwarf5-types-forward-cross-reference.s +++ b/bolt/test/X86/dwarf5-types-forward-cross-reference.s @@ -5,10 +5,10 @@ # RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that BOLT handles forward cross CU references for dwarf5 -# when -fdebug-types-sections is specified. +## This test checks that BOLT handles forward cross CU references for dwarf5 +## when -fdebug-types-sections is specified. -# The assembly was manually modified to do cross CU reference. +## The assembly was manually modified to do cross CU reference. # POSTCHECK: Type Unit # POSTCHECK-SAME: version = 0x0005 diff --git a/bolt/test/X86/dynrelocs.s b/bolt/test/X86/dynrelocs.s index 6d771df4b4ff81957344738e6cc38b39f9738ac7..b12942e93575d324a6e6f7314bd226f4bad80911 100644 --- a/bolt/test/X86/dynrelocs.s +++ b/bolt/test/X86/dynrelocs.s @@ -1,26 +1,26 @@ -# This reproduces a bug when rewriting dynamic relocations in X86 as -# BOLT incorrectly attributes R_X86_64_64 dynamic relocations -# to the wrong section when the -jump-tables=move flag is used. We -# expect the relocations to belong to the .bolt.org.rodata section but -# it is attributed to a new .rodata section that only contains jump -# table entries, created by BOLT. BOLT will only create this new .rodata -# section if both -jump-tables=move is used and a hot function with -# jt is present in the input binary, triggering a scenario where the -# dynamic relocs rewriting gets confused on where to put .rodata relocs. +## This reproduces a bug when rewriting dynamic relocations in X86 as +## BOLT incorrectly attributes R_X86_64_64 dynamic relocations +## to the wrong section when the -jump-tables=move flag is used. We +## expect the relocations to belong to the .bolt.org.rodata section but +## it is attributed to a new .rodata section that only contains jump +## table entries, created by BOLT. BOLT will only create this new .rodata +## section if both -jump-tables=move is used and a hot function with +## jt is present in the input binary, triggering a scenario where the +## dynamic relocs rewriting gets confused on where to put .rodata relocs. -# It is uncommon to end up with dynamic relocations against .rodata, -# but it can happen. In these cases we cannot corrupt the -# output binary by writing out dynamic relocs incorrectly. The linker -# avoids emitting relocs against read-only sections but we override -# this behavior with the -z notext flag. During runtime, these pages -# are mapped with write permission and then changed to read-only after -# the dynamic linker finishes processing the dynamic relocs. +## It is uncommon to end up with dynamic relocations against .rodata, +## but it can happen. In these cases we cannot corrupt the +## output binary by writing out dynamic relocs incorrectly. The linker +## avoids emitting relocs against read-only sections but we override +## this behavior with the -z notext flag. During runtime, these pages +## are mapped with write permission and then changed to read-only after +## the dynamic linker finishes processing the dynamic relocs. -# In this test, we create a reference to a dynamic object that will -# imply in R_X86_64_64 being used for .rodata. Now BOLT, when creating -# a new .rodata to hold jump table entries, needs to remember to emit -# these dynamic relocs against the original .rodata, and not the new -# one it just created. +## In this test, we create a reference to a dynamic object that will +## imply in R_X86_64_64 being used for .rodata. Now BOLT, when creating +## a new .rodata to hold jump table entries, needs to remember to emit +## these dynamic relocs against the original .rodata, and not the new +## one it just created. # REQUIRES: system-linux @@ -36,8 +36,8 @@ # RUN: -jump-tables=move # RUN: llvm-readobj -rs %t.out | FileCheck --check-prefix=READOBJ %s -# Verify that BOLT outputs the dynamic reloc at the correct address, -# which is the start of the .bolt.org.rodata section. +## Verify that BOLT outputs the dynamic reloc at the correct address, +## which is the start of the .bolt.org.rodata section. # READOBJ: Relocations [ # READOBJ: Section ([[#]]) .rela.dyn { # READOBJ-NEXT: 0x[[#%X,ADDR:]] R_X86_64_64 bar 0x10 diff --git a/bolt/test/X86/exceptions-args.test b/bolt/test/X86/exceptions-args.test index 3a4fa2f0eac13b3fddc79ad2e043938172653ffb..a617ab653c6388bbbeefb5f23654546871730839 100644 --- a/bolt/test/X86/exceptions-args.test +++ b/bolt/test/X86/exceptions-args.test @@ -1,5 +1,5 @@ -# Check that we handle GNU_args_size correctly. -# It is generated for throwing functions with LP that have parameters on stack. +## Check that we handle GNU_args_size correctly. +## It is generated for throwing functions with LP that have parameters on stack. RUN: %clang %cflags %p/../Inputs/stub.c -fPIC -pie -shared -o %t.so RUN: %clangxx %cxxflags -no-pie %p/Inputs/exc_args.s -o %t %t.so -Wl,-z,notext diff --git a/bolt/test/X86/fallthrough-to-noop.test b/bolt/test/X86/fallthrough-to-noop.test index 2055ca603043ab42c2f6c63c8a30152eb7347bb0..61782f7136072be438991eadd19ea19e65b58498 100644 --- a/bolt/test/X86/fallthrough-to-noop.test +++ b/bolt/test/X86/fallthrough-to-noop.test @@ -1,5 +1,5 @@ -# Check that profile data for the fall-through jump is not ignored when there is -# a conditional jump followed by a no-op. +## Check that profile data for the fall-through jump is not ignored when there is +## a conditional jump followed by a no-op. RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ RUN: %S/Inputs/ft_to_noop.s -o %t.o @@ -13,11 +13,11 @@ CHECK: Binary Function "foo" after building cfg CHECK: Exec Count : 20 CHECK: Profile Acc : 100.0% -# This block is terminated with a conditional jump to .Ltmp0 followed by a -# no-op. The profile data contains a count for the fall-through (3) which -# is different from what would be inferred (2). However the destination -# offset of this fall-through jump in the profile data points to the no-op -# following the jump and not the start of the fall-through block .LFT0. +## This block is terminated with a conditional jump to .Ltmp0 followed by a +## no-op. The profile data contains a count for the fall-through (3) which +## is different from what would be inferred (2). However the destination +## offset of this fall-through jump in the profile data points to the no-op +## following the jump and not the start of the fall-through block .LFT0. CHECK: Entry Point CHECK-NEXT: Exec Count : 20 CHECK: Successors: .Ltmp[[#BB1:]] (mispreds: 0, count: 18), .LFT[[#BB2:]] (mispreds: 0, count: 3) diff --git a/bolt/test/X86/false-jump-table.s b/bolt/test/X86/false-jump-table.s index 8cb87ed821e0e2da66e8e98402dd8df8e508907e..fafaa62ccb08191e80d0344950885a4cc81dbab9 100644 --- a/bolt/test/X86/false-jump-table.s +++ b/bolt/test/X86/false-jump-table.s @@ -1,5 +1,5 @@ -# Check that jump table detection does not fail on a false -# reference to a jump table. +## Check that jump table detection does not fail on a false +## reference to a jump table. # REQUIRES: system-linux diff --git a/bolt/test/X86/fatal-error.s b/bolt/test/X86/fatal-error.s index 312d1d47429f536aa1fd96343b8100ce1888c4db..b883ed1a076bb89a11a1b2574a24d47e86e0f72e 100644 --- a/bolt/test/X86/fatal-error.s +++ b/bolt/test/X86/fatal-error.s @@ -1,6 +1,6 @@ -# Tests whether llvm-bolt will correctly exit with error code and printing -# fatal error message in case one occurs. Here we test opening a function -# reordering file that does not exist. +## Tests whether llvm-bolt will correctly exit with error code and printing +## fatal error message in case one occurs. Here we test opening a function +## reordering file that does not exist. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q diff --git a/bolt/test/X86/fragment-lite-reverse.s b/bolt/test/X86/fragment-lite-reverse.s index 3d681208d3e95513b18d391613f304c4d7ccff24..94bd2961c951877ae4dcb98ea8d5e9fbb2a93e2a 100644 --- a/bolt/test/X86/fragment-lite-reverse.s +++ b/bolt/test/X86/fragment-lite-reverse.s @@ -1,4 +1,4 @@ -# Check that BOLT in lite mode processes fragments as expected. +## Check that BOLT in lite mode processes fragments as expected. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata diff --git a/bolt/test/X86/fragment-lite.s b/bolt/test/X86/fragment-lite.s index 32d1f5a98b64a3732295d8f6898ce60b19e3c149..9a5e5f83bc3f2fb6b8913d4d32a76dcc9ee3931b 100644 --- a/bolt/test/X86/fragment-lite.s +++ b/bolt/test/X86/fragment-lite.s @@ -1,4 +1,4 @@ -# Check that BOLT in lite mode processes fragments as expected. +## Check that BOLT in lite mode processes fragments as expected. # RUN: split-file %s %t # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o diff --git a/bolt/test/X86/fragmented-symbols.s b/bolt/test/X86/fragmented-symbols.s index ac2f705c64e94c89c0e4e25b916b4d246412003d..c03e2f5d46c83ba7a2683cdc45fc1bd1cad8e34d 100644 --- a/bolt/test/X86/fragmented-symbols.s +++ b/bolt/test/X86/fragmented-symbols.s @@ -1,5 +1,5 @@ -# Checks that symbols are allocated in correct sections, and that empty -# fragments are not allocated at all. +## Checks that symbols are allocated in correct sections, and that empty +## fragments are not allocated at all. # REQUIRES: x86_64-linux diff --git a/bolt/test/X86/frame-opt-lea.s b/bolt/test/X86/frame-opt-lea.s index fe84e8c03744742c27df1876ae0ff72803e3b25f..4b0c9e44080f711d47784786f06ec36b373053e4 100644 --- a/bolt/test/X86/frame-opt-lea.s +++ b/bolt/test/X86/frame-opt-lea.s @@ -1,6 +1,6 @@ -# This checks that frame optimizer does not try to optimize away caller-saved -# regs when we do not have complete aliasing info (when there is an LEA -# instruction and the function does arithmetic with stack addresses). +## This checks that frame optimizer does not try to optimize away caller-saved +## regs when we do not have complete aliasing info (when there is an LEA +## instruction and the function does arithmetic with stack addresses). # REQUIRES: system-linux diff --git a/bolt/test/X86/function-order-lite.s b/bolt/test/X86/function-order-lite.s index 5cedc833b08934bcc6671aea9ca38454554d61f6..b8a6497c755d457908cef6d1e2379a11bc2cec08 100644 --- a/bolt/test/X86/function-order-lite.s +++ b/bolt/test/X86/function-order-lite.s @@ -1,5 +1,5 @@ -# Check that functions listed in -function-order list take precedence over -# lite mode function filtering. +## Check that functions listed in -function-order list take precedence over +## lite mode function filtering. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata diff --git a/bolt/test/X86/gdbindex.test b/bolt/test/X86/gdbindex.test index 87a5ec142af258df61becebd724b0067885b4286..f9ae7aebe78670a9dabbef50737cdba4bf457cea 100644 --- a/bolt/test/X86/gdbindex.test +++ b/bolt/test/X86/gdbindex.test @@ -4,15 +4,15 @@ RUN: ld.lld --gdb-index %t.o %t2.o -o %tfile.exe RUN: llvm-bolt %tfile.exe -o %tfile.exe.bolt --update-debug-sections RUN: llvm-dwarfdump -gdb-index %tfile.exe.bolt | FileCheck %s -; test.cpp: -; int main() { return 0; } -; test2.cpp: -; int main2() { return 0; } -; Compiled with: -; gcc -gsplit-dwarf -c test.cpp test2.cpp -; gold --gdb-index test.o test2.o -o dwarfdump-gdbindex-v7.elf-x86-64 -; gcc version 5.3.1 20160413, GNU gold (GNU Binutils for Ubuntu 2.26) 1.11 -; Info about gdb-index: https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html +;; test.cpp: +;; int main() { return 0; } +;; test2.cpp: +;; int main2() { return 0; } +;; Compiled with: +;; gcc -gsplit-dwarf -c test.cpp test2.cpp +;; gold --gdb-index test.o test2.o -o dwarfdump-gdbindex-v7.elf-x86-64 +;; gcc version 5.3.1 20160413, GNU gold (GNU Binutils for Ubuntu 2.26) 1.11 +;; Info about gdb-index: https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html ; CHECK-LABEL: .gdb_index contents: ; CHECK: Version = 7 diff --git a/bolt/test/X86/high_pc_udata.s b/bolt/test/X86/high_pc_udata.s index c3a62842b875608ab280daeedc084fb0b10cc176..ad15d41bc5b7a9691d94e67b033d39f4b1bbca88 100644 --- a/bolt/test/X86/high_pc_udata.s +++ b/bolt/test/X86/high_pc_udata.s @@ -15,8 +15,8 @@ # POSTCHECK-NEXT: DW_AT_name [DW_FORM_strp] # POSTCHECK-SAME: "main.cpp" -# Testing that BOLT transforms DW_AT_high_pc of form DW_FORM_udata correctly into DW_AT_ranges. -# Manually changed so that DW_AT_high_pc is DW_FORM_udata, and that DW_AT_name is after it. +## Testing that BOLT transforms DW_AT_high_pc of form DW_FORM_udata correctly into DW_AT_ranges. +## Manually changed so that DW_AT_high_pc is DW_FORM_udata, and that DW_AT_name is after it. # int main() { # return 0; # } diff --git a/bolt/test/X86/icp-inline.s b/bolt/test/X86/icp-inline.s index 3c863833449fa6eb6318a351cf2dd4aa88dd6274..c5106db5a538972f9ac38e356f96c9548360d4e3 100644 --- a/bolt/test/X86/icp-inline.s +++ b/bolt/test/X86/icp-inline.s @@ -1,7 +1,7 @@ -# This test verifies the effect of -icp-inline option: that ICP is only -# performed for call targets eligible for inlining. +## This test verifies the effect of -icp-inline option: that ICP is only +## performed for call targets eligible for inlining. -# The assembly was produced from C code compiled with clang-15 -O1 -S: +## The assembly was produced from C code compiled with clang-15 -O1 -S: # int foo(int x) { return x + 1; } # int bar(int x) { return x*100 + 42; } diff --git a/bolt/test/X86/ignored-interprocedural-reference.s b/bolt/test/X86/ignored-interprocedural-reference.s new file mode 100644 index 0000000000000000000000000000000000000000..94d7a91f2c7fd99d529ec5b7a8e606d0e53c356a --- /dev/null +++ b/bolt/test/X86/ignored-interprocedural-reference.s @@ -0,0 +1,49 @@ +## This reproduces a bug with not processing interprocedural references from +## ignored functions. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -nostdlib -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.out --enable-bat -funcs=main +# RUN: link_fdata %s %t.out %t.preagg PREAGG +# RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.fdata -w %t.yaml +# RUN: FileCheck %s --input-file=%t.fdata --check-prefix=CHECK-FDATA +# RUN: FileCheck %s --input-file=%t.yaml --check-prefix=CHECK-YAML + +# CHECK-FDATA: 1 main 0 1 foo a 1 1 +# CHECK-YAML: name: main +# CHECK-YAML: calls: {{.*}} disc: 1 + +# PREAGG: B #main# #foo_secondary# 1 1 +## main calls foo at valid instruction offset past nops that are to be stripped. + .globl main +main: + .cfi_startproc + call foo_secondary + ret + .cfi_endproc +.size main,.-main + +## Placeholder cold fragment to force main to be ignored in non-relocation mode. + .globl main.cold +main.cold: + .cfi_startproc + ud2 + .cfi_endproc +.size main.cold,.-main.cold + +## foo is set up to contain a valid instruction at called offset, and trapping +## instructions past that. + .globl foo +foo: + .cfi_startproc + .nops 10 + .globl foo_secondary +foo_secondary: + ret + .rept 20 + int3 + .endr + .cfi_endproc +.size foo,.-foo diff --git a/bolt/test/X86/indirect-goto-pie.test b/bolt/test/X86/indirect-goto-pie.test index 039ff5c41d3d6842d2e9de2d94908f7dda88fd7f..81cff9a32fbbddc1fe4886615ac5c36021570bf3 100644 --- a/bolt/test/X86/indirect-goto-pie.test +++ b/bolt/test/X86/indirect-goto-pie.test @@ -1,6 +1,6 @@ -# Check that llvm-bolt fails to process PIC binaries with computed goto, as the -# support is not there yet for correctly updating dynamic relocations -# referencing code inside functions. +## Check that llvm-bolt fails to process PIC binaries with computed goto, as the +## support is not there yet for correctly updating dynamic relocations +## referencing code inside functions. REQUIRES: x86_64-linux @@ -8,7 +8,7 @@ RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q RUN: not llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \ RUN: |& FileCheck %s -# Check that processing works if main() is skipped. +## Check that processing works if main() is skipped. RUN: llvm-bolt %t -o %t.bolt --relocs=1 --skip-funcs=main CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW diff --git a/bolt/test/X86/indirect-goto.test b/bolt/test/X86/indirect-goto.test index bbc11e7d3317154add8bd436f4ceee969e6c2bee..8d2cb5e62a97b23dd31bc1908b2ae9553d01d2eb 100644 --- a/bolt/test/X86/indirect-goto.test +++ b/bolt/test/X86/indirect-goto.test @@ -1,9 +1,9 @@ -# Check llvm-bolt processes binaries compiled from sources that use indirect goto. +## Check llvm-bolt processes binaries compiled from sources that use indirect goto. RUN: %clang %cflags -no-pie %S/Inputs/indirect_goto.c -Wl,-q -o %t RUN: llvm-bolt %t -o %t.null --relocs=1 --print-cfg --print-only=main \ RUN: --strict \ RUN: 2>&1 | FileCheck %s -# Check that all possible destinations are included as successors. +## Check that all possible destinations are included as successors. CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW CHECK: Successors: .Ltmp0, .Ltmp1, .Ltmp2 diff --git a/bolt/test/X86/inlined-function-mixed.test b/bolt/test/X86/inlined-function-mixed.test index 5a87bdde9535ef83910b0dfad4e026c0a282901d..9f6ef396bb159720d6ca437bbf9c1ea2b57f968c 100644 --- a/bolt/test/X86/inlined-function-mixed.test +++ b/bolt/test/X86/inlined-function-mixed.test @@ -1,5 +1,5 @@ -# Make sure inlining from a unit with debug info into unit without -# debug info does not cause a crash. +## Make sure inlining from a unit with debug info into unit without +## debug info does not cause a crash. RUN: %clangxx %cxxflags %S/Inputs/inlined.cpp -c -o %T/inlined.o RUN: %clangxx %cxxflags %S/Inputs/inlinee.cpp -c -o %T/inlinee.o -g diff --git a/bolt/test/X86/insert-addr-rnglists_base.s b/bolt/test/X86/insert-addr-rnglists_base.s index 800bed27243d16fa0a3325f1040c391608ceb68f..c08376c91634c9e3e1108de61274b978d602d20a 100644 --- a/bolt/test/X86/insert-addr-rnglists_base.s +++ b/bolt/test/X86/insert-addr-rnglists_base.s @@ -6,8 +6,8 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s -# This test checks we correctly insert DW_AT_addr_base, when converting DW_AT_low_pc into DW_AT_ranges. -# PRECHECK-NOT: DW_AT_addr_base +## This test checks we correctly insert DW_AT_addr_base, when converting DW_AT_low_pc into DW_AT_ranges. +## PRECHECK-NOT: DW_AT_addr_base # POSTCHECK: DW_AT_ranges [DW_FORM_rnglistx] # POSTCHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) diff --git a/bolt/test/X86/insert-debug-info-entry.test b/bolt/test/X86/insert-debug-info-entry.test index f36e3ed6f72206f90fe3f4e1cb6b220b22b64261..31af3db7d4a827f2ce7846ba8f30de3a650ee1d6 100644 --- a/bolt/test/X86/insert-debug-info-entry.test +++ b/bolt/test/X86/insert-debug-info-entry.test @@ -7,7 +7,7 @@ ; RUN: llvm-dwarfdump --debug-info foo.exe | FileCheck -check-prefix=PRE-BOLT %s ; RUN: llvm-dwarfdump --debug-info foo.exe.bolt | FileCheck %s -; This tests checks that DW_AT_GNU_ranges_base is added at the end of the CU. +;; This tests checks that DW_AT_GNU_ranges_base is added at the end of the CU. ; PRE-BOLT: DW_AT_GNU_addr_base ; PRE-BOLT-NOT: DW_AT_GNU_ranges_base diff --git a/bolt/test/X86/internal-call-instrument-so.s b/bolt/test/X86/internal-call-instrument-so.s index d13c828f605c3e3d5d8d5b4af93f03ebe198b05f..99e5b292214090fce00a7656fba8bc710a9ec017 100644 --- a/bolt/test/X86/internal-call-instrument-so.s +++ b/bolt/test/X86/internal-call-instrument-so.s @@ -1,4 +1,4 @@ -# This reproduces a bug with instrumentation crashes on internal call +## This reproduces a bug with instrumentation crashes on internal call # REQUIRES: system-linux,bolt-runtime,target=x86_64{{.*}} diff --git a/bolt/test/X86/internal-call-instrument.s b/bolt/test/X86/internal-call-instrument.s index c393f1dac864718c38dc6080394d495b6d119171..4dc0408c6d12f78c7c01d7e5d62254eae4c33398 100644 --- a/bolt/test/X86/internal-call-instrument.s +++ b/bolt/test/X86/internal-call-instrument.s @@ -1,4 +1,4 @@ -# This reproduces a bug with instrumentation crashes on internal call +## This reproduces a bug with instrumentation crashes on internal call # REQUIRES: x86_64-linux,bolt-runtime,target=x86_64{{.*}} diff --git a/bolt/test/X86/interprocedural-ref-entry-point.s b/bolt/test/X86/interprocedural-ref-entry-point.s index 0e1cca5c9bfe68133caaf2f8bfb866ac6aebea81..67f0a452bf34c02977fe34e0203313d421943319 100644 --- a/bolt/test/X86/interprocedural-ref-entry-point.s +++ b/bolt/test/X86/interprocedural-ref-entry-point.s @@ -1,7 +1,7 @@ -# This reproduces a bug where not registering cold fragment entry points -# leads to removing blocks and an inconsistent CFG after UCE. -# Test assembly was obtained using C-Reduce from this C++ code: -# (compiled with `g++ -O2 -Wl,-q`) +## This reproduces a bug where not registering cold fragment entry points +## leads to removing blocks and an inconsistent CFG after UCE. +## Test assembly was obtained using C-Reduce from this C++ code: +## (compiled with `g++ -O2 -Wl,-q`) # # #include # int a; diff --git a/bolt/test/X86/is-strip.s b/bolt/test/X86/is-strip.s index df12986efc42d7238e71f5c089fe274abb0b83a7..1ce81872326c149fec3f45d09fff703279181154 100644 --- a/bolt/test/X86/is-strip.s +++ b/bolt/test/X86/is-strip.s @@ -1,4 +1,4 @@ -# This test checks whether a binary is stripped or not. +## This test checks whether a binary is stripped or not. # RUN: %clang++ %cflags %p/Inputs/linenumber.cpp -o %t -Wl,-q # RUN: llvm-bolt %t -o %t.out 2>&1 | FileCheck %s -check-prefix=CHECK-NOSTRIP diff --git a/bolt/test/X86/issue20.s b/bolt/test/X86/issue20.s index 785064df89c9cd88ba0307bf46979ba1b1a8e56e..99a4f2ea2ac9982126b3c8a1e68305046e8bf868 100644 --- a/bolt/test/X86/issue20.s +++ b/bolt/test/X86/issue20.s @@ -1,6 +1,6 @@ -# This reproduces issue 20 from our github repo -# "BOLT crashes when removing unreachable BBs that are a target -# in a JT" +## This reproduces issue 20 from our github repo +## "BOLT crashes when removing unreachable BBs that are a target +## in a JT" # REQUIRES: system-linux diff --git a/bolt/test/X86/issue20.test b/bolt/test/X86/issue20.test index eeb76d15aec44820e8da2fe2af45a05fc34d2c54..dcb1ce5ab1567f4f5b197684965f9345ccf31427 100644 --- a/bolt/test/X86/issue20.test +++ b/bolt/test/X86/issue20.test @@ -1,6 +1,6 @@ -# This reproduces issue 20 from our github repo -# "BOLT crashes when removing unreachable BBs that are a target -# in a JT" +## This reproduces issue 20 from our github repo +## "BOLT crashes when removing unreachable BBs that are a target +## in a JT" # RUN: yaml2obj %p/Inputs/issue20.yaml &> %t.exe # RUN: llvm-bolt %t.exe --relocs=0 --jump-tables=move --print-finalized \ diff --git a/bolt/test/X86/issue26.s b/bolt/test/X86/issue26.s index 6f9bc72d6e10dcff385e6d5e920407b0b02ae2cf..2a97febfd23cd7167553e20f536c8b668be03ecb 100644 --- a/bolt/test/X86/issue26.s +++ b/bolt/test/X86/issue26.s @@ -1,6 +1,6 @@ -# This reproduces issue 26 from our github repo -# BOLT fails with the following assertion: -# llvm/tools/llvm-bolt/src/BinaryFunction.cpp:2950: void llvm::bolt::BinaryFunction::postProcessBranches(): Assertion `validateCFG() && "invalid CFG"' failed. +## This reproduces issue 26 from our github repo +## BOLT fails with the following assertion: +## llvm/tools/llvm-bolt/src/BinaryFunction.cpp:2950: void llvm::bolt::BinaryFunction::postProcessBranches(): Assertion `validateCFG() && "invalid CFG"' failed. # REQUIRES: system-linux diff --git a/bolt/test/X86/issue26.test b/bolt/test/X86/issue26.test index bafd0912cf4a48e7f98e86e0653ab09ec8640c02..55704a884d20810400c8f85535a955a676683384 100644 --- a/bolt/test/X86/issue26.test +++ b/bolt/test/X86/issue26.test @@ -1,4 +1,4 @@ -# This reproduces issue 26 from our github repo +## This reproduces issue 26 from our github repo # RUN: yaml2obj %p/Inputs/issue26.yaml &> %t.exe # RUN: llvm-bolt %t.exe --relocs --print-cfg -o %t.out 2>&1 \ diff --git a/bolt/test/X86/jmp-optimization.test b/bolt/test/X86/jmp-optimization.test index 92f4b9a14f0f4b3b31011f0b5bfa9442eafd7d44..a98be115734162d476797e98c20b71938a11dd6b 100644 --- a/bolt/test/X86/jmp-optimization.test +++ b/bolt/test/X86/jmp-optimization.test @@ -1,7 +1,7 @@ -# Tests the optimization of functions that just do a tail call in the beginning. +## Tests the optimization of functions that just do a tail call in the beginning. -# This test has commands that rely on shell capabilities that won't execute -# correctly on Windows e.g. unsupported parameter expansion +## This test has commands that rely on shell capabilities that won't execute +## correctly on Windows e.g. unsupported parameter expansion REQUIRES: shell RUN: %clang %cflags -O2 %S/Inputs/jmp_opt{,2,3}.cpp -o %t diff --git a/bolt/test/X86/jmpjmp.test b/bolt/test/X86/jmpjmp.test index cc6107f47812757a3343c1158e35b3eeb3f53c68..0d058fec8af48d820f1646df6710343b3db05035 100644 --- a/bolt/test/X86/jmpjmp.test +++ b/bolt/test/X86/jmpjmp.test @@ -1,5 +1,5 @@ -# Verifies that llvm-bolt allocates two consecutive jumps in two separate basic -# blocks. +## Verifies that llvm-bolt allocates two consecutive jumps in two separate basic +## blocks. RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %S/Inputs/jmpjmp.s -o %t.o RUN: %clang %cflags %t.o -o %t.exe diff --git a/bolt/test/X86/jt-symbol-disambiguation-3.s b/bolt/test/X86/jt-symbol-disambiguation-3.s index c472b6bbf9c6a20ecf940a2361685bd7cced9c7b..22b34cef1bc4d820afc4904d97ad24fc6904ed6e 100644 --- a/bolt/test/X86/jt-symbol-disambiguation-3.s +++ b/bolt/test/X86/jt-symbol-disambiguation-3.s @@ -1,11 +1,11 @@ -# In this test case, we reproduce the behavior seen in gcc where the -# base address of a jump table is decremented by some number and ends up -# at the exact addess of a jump table from another function. After -# linking, the instruction references another jump table and that -# confuses BOLT. -# We repro here the following issue: -# Before assembler: Instruction operand is: jumptable - 32 -# After linking: Instruction operand is: another_jumptable +## In this test case, we reproduce the behavior seen in gcc where the +## base address of a jump table is decremented by some number and ends up +## at the exact addess of a jump table from another function. After +## linking, the instruction references another jump table and that +## confuses BOLT. +## We repro here the following issue: +## Before assembler: Instruction operand is: jumptable - 32 +## After linking: Instruction operand is: another_jumptable # REQUIRES: system-linux, asserts @@ -18,8 +18,8 @@ # RUN: llvm-bolt %t.exe -o %t.exe.bolt --relocs=1 --lite=0 \ # RUN: --reorder-blocks=reverse -# Useful when manually testing this. Currently we just check that -# the test does not cause BOLT to assert. +## Useful when manually testing this. Currently we just check that +## the test does not cause BOLT to assert. # COM: %t.exe.bolt 1 2 .file "jt-symbol-disambiguation-3.s" diff --git a/bolt/test/X86/jt-symbol-disambiguation-4.s b/bolt/test/X86/jt-symbol-disambiguation-4.s new file mode 100644 index 0000000000000000000000000000000000000000..d3d3dcd8070541eae38236dc240a2993316eb067 --- /dev/null +++ b/bolt/test/X86/jt-symbol-disambiguation-4.s @@ -0,0 +1,63 @@ +## If the operand references a symbol that differs from the jump table label, +## no reference updating is required even if its target address resides within +## the jump table's range. +## In this test case, consider the second instruction within the main function, +## where the address resulting from 'c + 17' corresponds to one byte beyond the +## address of the .LJTI2_0 jump table label. However, this operand represents +## an offset calculation related to the global variable 'c' and should remain +## unaffected by the jump table. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang -no-pie %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt --funcs=main,foo/1 %t.exe -o %t.exe.bolt --print-normalized \ +# RUN: 2>&1 | FileCheck %s + + .text + .globl main + .type main,@function +main: +# CHECK: Binary Function "main" + pushq %rbp + movq %rsp, %rbp + movq $-16, %rax + movl c+17(%rax), %edx +# CHECK: movl c+17(%rax), %edx + cmpl $255, %edx + je .LCorrect + movl $1, %eax + popq %rbp + ret +.LCorrect: + movl $0, %eax + popq %rbp + ret + + .p2align 4, 0x90 + .type foo,@function +foo: +# CHECK: Binary Function "foo + movq $0, %rax + jmpq *.LJTI2_0(,%rax,8) +# CHECK: jmpq *{{.*}} # JUMPTABLE + addl $-36, %eax +.LBB2_2: + addl $-16, %eax + retq + .section .rodata,"a",@progbits + .type c,@object + .data + .globl c + .p2align 4, 0x0 +c: + .byte 1 + .byte 0xff + .zero 14 + .size c, 16 +.LJTI2_0: + .quad .LBB2_2 + .quad .LBB2_2 + .quad .LBB2_2 + .quad .LBB2_2 + diff --git a/bolt/test/X86/jump-table-fixed-ref-pic.test b/bolt/test/X86/jump-table-fixed-ref-pic.test index 4195b97aac501ebc4a77a22f1c3efb601400a529..c8b6eda2278b9329fac22b0fc0b1d546f3990f9b 100644 --- a/bolt/test/X86/jump-table-fixed-ref-pic.test +++ b/bolt/test/X86/jump-table-fixed-ref-pic.test @@ -1,5 +1,5 @@ -# Verify that BOLT detects fixed destination of indirect jump for PIC -# case. +## Verify that BOLT detects fixed destination of indirect jump for PIC +## case. XFAIL: * diff --git a/bolt/test/X86/jump-table-footprint-reduction.test b/bolt/test/X86/jump-table-footprint-reduction.test index 4e0f9b16818d3f81abb0a8379381ee4a417db6fc..290e585fc1b7501781282bd3eb24c40db18999ef 100644 --- a/bolt/test/X86/jump-table-footprint-reduction.test +++ b/bolt/test/X86/jump-table-footprint-reduction.test @@ -1,5 +1,5 @@ -# Checks that jump table footprint reduction optimization is reducing entry -# sizes. +## Checks that jump table footprint reduction optimization is reducing entry +## sizes. RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ RUN: %S/Inputs/jump_table_footprint_reduction.s -o %t.o diff --git a/bolt/test/X86/jump-table-icp.test b/bolt/test/X86/jump-table-icp.test index 5b989d18018b0505f7293c6d00d238e5b1e101d6..f1474326db3b6bfbd58eec9f5e8c161b69525d05 100644 --- a/bolt/test/X86/jump-table-icp.test +++ b/bolt/test/X86/jump-table-icp.test @@ -4,8 +4,8 @@ RUN: link_fdata %p/Inputs/jump_table_icp.s %t.o %t.fdata --nmtool llvm-nm RUN: llvm-strip --strip-unneeded %t.o RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q -# This test has commands that rely on shell capabilities that won't execute -# correctly on Windows e.g. subshell execution +## This test has commands that rely on shell capabilities that won't execute +## correctly on Windows e.g. subshell execution REQUIRES: shell RUN: (llvm-bolt %t.exe --data %t.fdata -o %t --relocs \ diff --git a/bolt/test/X86/jump-table-pic-conflict.s b/bolt/test/X86/jump-table-pic-conflict.s index ed3c77d49b6cc4620efa722e7766e434481beb11..c84551a0e2132ec587ec5f088fb9df5a7cec03d8 100644 --- a/bolt/test/X86/jump-table-pic-conflict.s +++ b/bolt/test/X86/jump-table-pic-conflict.s @@ -1,16 +1,16 @@ -# Check cases when the first PIC jump table entries of one function can be -# interpreted as valid last entries of the previous function. +## Check cases when the first PIC jump table entries of one function can be +## interpreted as valid last entries of the previous function. -# Conditions to trigger the bug: Function A and B have jump tables that -# are adjacent in memory. We run in lite relocation mode. Function B -# is not disassembled because it does not have profile. Function A -# triggers a special conditional that forced BOLT to rewrite its jump -# table in-place (instead of moving it) because it is marked as -# non-simple (in this case, containing unknown control flow). The -# first entry of B's jump table (a PIC offset) happens to be a valid -# address inside A when added to A's jump table base address. In this -# case, BOLT could overwrite B's jump table, corrupting it, thinking -# the first entry of it is actually part of A's jump table. +## Conditions to trigger the bug: Function A and B have jump tables that +## are adjacent in memory. We run in lite relocation mode. Function B +## is not disassembled because it does not have profile. Function A +## triggers a special conditional that forced BOLT to rewrite its jump +## table in-place (instead of moving it) because it is marked as +## non-simple (in this case, containing unknown control flow). The +## first entry of B's jump table (a PIC offset) happens to be a valid +## address inside A when added to A's jump table base address. In this +## case, BOLT could overwrite B's jump table, corrupting it, thinking +## the first entry of it is actually part of A's jump table. # REQUIRES: system-linux @@ -26,8 +26,8 @@ # readelf. This is another way to check this bug: # COM: %t.out -# BOLT needs to create a new rodata section, indicating that it -# successfully moved the jump table in _start. +## BOLT needs to create a new rodata section, indicating that it +## successfully moved the jump table in _start. # CHECK: [{{.*}}] .bolt.org.rodata .globl _start @@ -41,8 +41,8 @@ _start: cmpq $3, %rdi ja .L5 jmp .L6 -# Unreachable code, here to mark this function as non-simple -# (containing unknown control flow) with a stray indirect jmp +## Unreachable code, here to mark this function as non-simple +## (containing unknown control flow) with a stray indirect jmp jmp *%rax .L6: decq %rdi @@ -115,8 +115,8 @@ str1: .asciz "Message 1\n" str2: .asciz "Message 2\n" str3: .asciz "Message 3\n" str4: .asciz "Highrange\n" -# Special case where the first .LJT2 entry is a valid offset of -# _start when interpreted with .LJT1 as a base address. +## Special case where the first .LJT2 entry is a valid offset of +## _start when interpreted with .LJT1 as a base address. .LJT1: .long .L1-.LJT1 .long .L2-.LJT1 diff --git a/bolt/test/X86/jump-table-pic-order.test b/bolt/test/X86/jump-table-pic-order.test index 59c0af252b07b39fc020457914623c66563a3b2d..09bda932121b3e4a32d0e41489fb390f95d53c41 100644 --- a/bolt/test/X86/jump-table-pic-order.test +++ b/bolt/test/X86/jump-table-pic-order.test @@ -1,5 +1,5 @@ -# Check that successors of a basic block with jump table are generated -# in the same order as they appear in the input code. +## Check that successors of a basic block with jump table are generated +## in the same order as they appear in the input code. RUN: %clang %cflags %S/Inputs/jump-table-pic.s -o %t.exe -Wl,-q RUN: llvm-bolt %t.exe --strict --print-cfg --print-only=main -o %t.null \ @@ -7,6 +7,6 @@ RUN: | FileCheck %s CHECK: BB Layout : {{.*, .*, .*,}} [[BB4to6:.*, .*, .*]] -# Check that successors appear in the order matching the input layout. +## Check that successors appear in the order matching the input layout. CHECK: jmpq *%rax # JUMPTABLE CHECK-NEXT: Successors: [[BB4to6]] diff --git a/bolt/test/X86/jump-table-reference.test b/bolt/test/X86/jump-table-reference.test index 9d33c0d5e72718ed30a8ecdc4a57887f7d3237d4..32696683fb5ea5f5a8a46fdcd82eddd0ac163b9f 100644 --- a/bolt/test/X86/jump-table-reference.test +++ b/bolt/test/X86/jump-table-reference.test @@ -1,4 +1,4 @@ -# Verifies that BOLT detects fixed destination of indirect jump +## Verifies that BOLT detects fixed destination of indirect jump RUN: %clang %cflags -no-pie %S/Inputs/jump_table_reference.s -Wl,-q -o %t RUN: llvm-bolt %t --relocs -o %t.null 2>&1 | FileCheck %s diff --git a/bolt/test/X86/layout-heuristic.test b/bolt/test/X86/layout-heuristic.test index 3d24e1aad139a5f113abbb20036620a130bf3ef3..c614e7b0f33e6f0df5299aebaf195d98760bcde3 100644 --- a/bolt/test/X86/layout-heuristic.test +++ b/bolt/test/X86/layout-heuristic.test @@ -1,8 +1,8 @@ -# Checks that llvm-bolt is able to read data generated by perf2bolt, update the -# CFG edges accordingly with absolute number of branches and mispredictions, -# infer fallthrough branch info and reorder basic blocks using a greedy -# heuristic, or find the optimal solution if the function is small enough. -# Also checks that llvm-bolt disassembler and CFG builder is working properly. +## Checks that llvm-bolt is able to read data generated by perf2bolt, update the +## CFG edges accordingly with absolute number of branches and mispredictions, +## infer fallthrough branch info and reorder basic blocks using a greedy +## heuristic, or find the optimal solution if the function is small enough. +## Also checks that llvm-bolt disassembler and CFG builder is working properly. RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --data %p/Inputs/blarge.fdata \ diff --git a/bolt/test/X86/line-number.test b/bolt/test/X86/line-number.test index b039962643d4064e4f0e8714a76563f3de295650..d4dca825502eefcadd7d27c4c9b16034fbfd0d41 100644 --- a/bolt/test/X86/line-number.test +++ b/bolt/test/X86/line-number.test @@ -1,17 +1,17 @@ -# Verifies that the extraction of DWARF line number information is correct. +## Verifies that the extraction of DWARF line number information is correct. RUN: %clangxx %cxxflags %S/Inputs/linenumber.cpp -g -o %t RUN: llvm-bolt %t -o %t.null --print-reordered --update-debug-sections \ RUN: --print-debug-info --reorder-blocks=reverse --sequential-disassembly \ RUN: 2>&1 | FileCheck %s -# Local variable in f() +## Local variable in f() CHECK: movl $0xbeef, -0x4(%rbp) # debug line {{.*}}linenumber.cpp:9 -# Checks that a branch instruction that is inserted by BOLT does not have -# debug line info associated with it. +## Checks that a branch instruction that is inserted by BOLT does not have +## debug line info associated with it. CHECK-NOT: jmp .LFT0 # debug line {{.*}}linenumber.cpp:1 -# Call to f() in g() +## Call to f() in g() CHECK: callq _Z1fv{{.*}} # debug line {{.*}}linenumber.cpp:19 -# Calls to g() and f() in main +## Calls to g() and f() in main CHECK: callq _Z1gv{{.*}} # debug line {{.*}}linenumber.cpp:23 CHECK: callq _Z1fv{{.*}} # debug line {{.*}}linenumber.cpp:23 diff --git a/bolt/test/X86/lit.local.cfg b/bolt/test/X86/lit.local.cfg index 947d25cb6e8c4d4db7ed2bb149c71afd9a8441a8..ea9928d1918847ddc4606bac2e46cd7d3fd4282e 100644 --- a/bolt/test/X86/lit.local.cfg +++ b/bolt/test/X86/lit.local.cfg @@ -1,7 +1,7 @@ if not "X86" in config.root.targets: config.unsupported = True -flags = "--target=x86_64-pc-linux -nostdlib" +flags = "--target=x86_64-unknown-linux-gnu -nostdlib" config.substitutions.insert(0, ("%cflags", f"%cflags {flags}")) config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}")) diff --git a/bolt/test/X86/log.test b/bolt/test/X86/log.test index 0cbb5b625d007dab307f70f4874dd07b4d87864b..42109db87d9eee5fc71b8f5333998670642b6fdb 100644 --- a/bolt/test/X86/log.test +++ b/bolt/test/X86/log.test @@ -1,6 +1,6 @@ -# Tests whether llvm-bolt is able to redirect logs when processing a simple -# input. If this test fails on your changes, please use BinaryContext::outs() -# to print BOLT logging instead of llvm::outs(). +## Tests whether llvm-bolt is able to redirect logs when processing a simple +## input. If this test fails on your changes, please use BinaryContext::outs() +## to print BOLT logging instead of llvm::outs(). RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --data %p/Inputs/blarge.fdata -v=2 \ @@ -12,7 +12,7 @@ CHECK-NOT: BOLT-INFO CHECK-NOT: BOLT-WARNING CHECK-NOT: BOLT-ERROR -# Check some usual BOLT output lines are being redirected to the log file +## Check some usual BOLT output lines are being redirected to the log file CHECK-LOG: BOLT-INFO: Target architecture CHECK-LOG: BOLT-INFO: BOLT version CHECK-LOG: BOLT-INFO: basic block reordering modified layout diff --git a/bolt/test/X86/loop-inversion-pass.s b/bolt/test/X86/loop-inversion-pass.s index cb241110cf70db428c3148d8cc2b4f95d19e2b25..4957375809840ed7dbd2c6810a7469311108b17f 100644 --- a/bolt/test/X86/loop-inversion-pass.s +++ b/bolt/test/X86/loop-inversion-pass.s @@ -16,19 +16,19 @@ # RUN: --print-finalized --loop-inversion-opt -o %t.out3 \ # RUN: | FileCheck --check-prefix="CHECK3" %s -# The case where the loop is used: +## The case where the loop is used: # FDATA: 1 main 2 1 main #.J1# 0 420 # FDATA: 1 main b 1 main #.Jloop# 0 420 # FDATA: 1 main b 1 main d 0 1 # CHECK: BB Layout : .LBB00, .Ltmp0, .Ltmp1, .LFT0 -# The case where the loop is unused: +## The case where the loop is unused: # FDATA2: 1 main 2 1 main #.J1# 0 420 # FDATA2: 1 main b 1 main #.Jloop# 0 1 # FDATA2: 1 main b 1 main d 0 420 # CHECK2: BB Layout : .LBB00, .Ltmp1, .LFT0, .Ltmp0 -# The case where the loop does not require rotation: +## The case where the loop does not require rotation: # FDATA3: 1 main 2 1 main #.J1# 0 420 # FDATA3: 1 main b 1 main #.Jloop# 0 420 # FDATA3: 1 main b 1 main d 0 1 diff --git a/bolt/test/X86/loop-nest.test b/bolt/test/X86/loop-nest.test index 24fde1004b007ad8d8a25e1657ee647d8d7a3b43..51c8fcdb32eaaed2c82d6171899155f1055fd85d 100644 --- a/bolt/test/X86/loop-nest.test +++ b/bolt/test/X86/loop-nest.test @@ -1,4 +1,4 @@ -# Verifies that llvm-bolt prints correct loop information. +## Verifies that llvm-bolt prints correct loop information. RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ RUN: %p/Inputs/loop_nest.s -o %t.o diff --git a/bolt/test/X86/merge-fdata-bat-mode.test b/bolt/test/X86/merge-fdata-bat-mode.test index 41738e196b5d3824e0930e4a682cedc2f0dc127d..2d2a423fb85b66b5f7a17a62d9901268be47024c 100644 --- a/bolt/test/X86/merge-fdata-bat-mode.test +++ b/bolt/test/X86/merge-fdata-bat-mode.test @@ -1,5 +1,5 @@ -# Check merge-fdata tool correctly processes fdata files with header strings -# such as the ones produced by BAT mode (boltedcollection) +## Check merge-fdata tool correctly processes fdata files with header strings +## such as the ones produced by BAT mode (boltedcollection) RUN: merge-fdata %S/Inputs/bat_profile_1.fdata \ RUN: %S/Inputs/bat_profile_2.fdata \ RUN: | FileCheck %s --check-prefix=CHECK-FDATA diff --git a/bolt/test/X86/merge-fdata-nobat-mode.test b/bolt/test/X86/merge-fdata-nobat-mode.test index 870d9f880e2866f8fb51871feb85d1790fcc8c71..978052e35007a162c24cf50c825d9add03d3ecf0 100644 --- a/bolt/test/X86/merge-fdata-nobat-mode.test +++ b/bolt/test/X86/merge-fdata-nobat-mode.test @@ -1,4 +1,4 @@ -# Check that merge-fdata tool doesn't spuriously print boltedcollection +## Check that merge-fdata tool doesn't spuriously print boltedcollection RUN: merge-fdata %S/Inputs/blarge.fdata %S/Inputs/blarge.fdata \ RUN: | FileCheck %s --check-prefix=CHECK-FDATA diff --git a/bolt/test/X86/merge-fdata-output.test b/bolt/test/X86/merge-fdata-output.test index 17050e48a95f9ba568cad07144344f42700cdb1c..b12b460d9d7b3f7939654573b8327a9a8bb0e86a 100644 --- a/bolt/test/X86/merge-fdata-output.test +++ b/bolt/test/X86/merge-fdata-output.test @@ -1,4 +1,4 @@ -# Check merge-fdata tool correctly handles `-o` option. +## Check merge-fdata tool correctly handles `-o` option. RUN: merge-fdata %S/Inputs/bat_profile_1.fdata \ RUN: %S/Inputs/bat_profile_2.fdata \ RUN: | FileCheck %s @@ -13,4 +13,4 @@ RUN: %S/Inputs/bat_profile_2.fdata \ RUN: -o %t RUN: FileCheck %s < %t -CHECK: 1 main 451 1 SolveCubic 0 0 302 \ No newline at end of file +CHECK: 1 main 451 1 SolveCubic 0 0 302 diff --git a/bolt/test/X86/no-entry-reordering.test b/bolt/test/X86/no-entry-reordering.test index a2638e1388c9a722055e53b50bbe010d3df1e72b..309e5c1d04f9c228ab18374aada0dc035348b5fb 100644 --- a/bolt/test/X86/no-entry-reordering.test +++ b/bolt/test/X86/no-entry-reordering.test @@ -1,5 +1,5 @@ -# Verifies that llvm-bolt reordering heuristic does not allocate a BB before the -# entry point even if there is a hot edge from a block to entry point +## Verifies that llvm-bolt reordering heuristic does not allocate a BB before the +## entry point even if there is a hot edge from a block to entry point RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %S/Inputs/entry.s -o %t.o RUN: link_fdata %S/Inputs/entry.s %t.o %t.fdata --nmtool llvm-nm diff --git a/bolt/test/X86/no-output.test b/bolt/test/X86/no-output.test index 523bdf25f52175f5c67338497e4fd886b75d25b7..fa0c8dd68ae455b5ac39d5cb3574b7d39b34121f 100644 --- a/bolt/test/X86/no-output.test +++ b/bolt/test/X86/no-output.test @@ -1,4 +1,4 @@ -# This script checks that BOLT is able to work in dry run mode (no output) +## This script checks that BOLT is able to work in dry run mode (no output) # REQUIRES: system-linux diff --git a/bolt/test/X86/nolbr.s b/bolt/test/X86/nolbr.s index bebb697122f4907ae940c5043887d9b19c33cd97..999c68566c949242497a29d48097bfedc709fe60 100644 --- a/bolt/test/X86/nolbr.s +++ b/bolt/test/X86/nolbr.s @@ -1,6 +1,6 @@ -# This reproduces a bug where profile collected from perf without LBRs and -# converted into fdata-no-lbr format is reported to not contain profile for any -# functions. +## This reproduces a bug where profile collected from perf without LBRs and +## converted into fdata-no-lbr format is reported to not contain profile for any +## functions. # REQUIRES: system-linux diff --git a/bolt/test/X86/patch-entries.test b/bolt/test/X86/patch-entries.test index 4a725412dd616adeb760df155837c17b003213e0..bf31af342dc61bbd5c963072b72095bade9bb5a6 100644 --- a/bolt/test/X86/patch-entries.test +++ b/bolt/test/X86/patch-entries.test @@ -1,7 +1,7 @@ -# Checking crashes against injected binary functions created by patch -# entries pass and debug info turned on. In these cases, we were -# trying to fetch input to output maps on injected functions and -# crashing. +## Checking crashes against injected binary functions created by patch +## entries pass and debug info turned on. In these cases, we were +## trying to fetch input to output maps on injected functions and +## crashing. REQUIRES: system-linux @@ -10,8 +10,8 @@ RUN: -Wl,-q -I%p/../Inputs RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch \ RUN: --enable-bat -# Check that patched functions can be disassembled (override FDE from the -# original function) +## Check that patched functions can be disassembled (override FDE from the +## original function) # PREAGG: B X:0 #foo.org.0# 1 0 RUN: link_fdata %s %t.out %t.preagg PREAGG RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.yaml --profile-format=yaml \ @@ -19,13 +19,13 @@ RUN: -print-disasm -print-only=foo.org.0/1 2>&1 | FileCheck %s CHECK-NOT: BOLT-WARNING: sizes differ for function foo.org.0/1 CHECK: Binary Function "foo.org.0/1(*2)" after disassembly { -# Check the expected eh_frame contents +## Check the expected eh_frame contents RUN: llvm-nm --print-size %t.out > %t.foo RUN: llvm-objdump %t.out --dwarf=frames >> %t.foo RUN: FileCheck %s --input-file %t.foo --check-prefix=CHECK-FOO CHECK-FOO: 0000000000[[#%x,FOO:]] [[#%x,OPTSIZE:]] t foo CHECK-FOO: 0000000000[[#%x,ORG:]] [[#%x,ORGSIZE:]] t foo.org.0 -# patched FDE comes first +## patched FDE comes first CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+ORGSIZE]] -# original FDE comes second +## original FDE comes second CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+OPTSIZE]] diff --git a/bolt/test/X86/pre-aggregated-perf.test b/bolt/test/X86/pre-aggregated-perf.test index 0bd44720f1b7a102f8590d575d3156277c488624..90252f9ff68daa066b95b7a8735cdc1526fea27c 100644 --- a/bolt/test/X86/pre-aggregated-perf.test +++ b/bolt/test/X86/pre-aggregated-perf.test @@ -1,12 +1,12 @@ -# This script checks that perf2bolt is reading pre-aggregated perf information -# correctly for a simple example. The perf.data of this example was generated -# with the following command: -# -# $ perf record -j any,u -e branch -o perf.data -- ./blarge -# -# blarge is the binary for "basicmath large inputs" taken from Mibench. +## This script checks that perf2bolt is reading pre-aggregated perf information +## correctly for a simple example. The perf.data of this example was generated +## with the following command: +## +## $ perf record -j any,u -e branch -o perf.data -- ./blarge +## +## blarge is the binary for "basicmath large inputs" taken from Mibench. -# Currently failing in MacOS / generating different hash for usqrt +## Currently failing in MacOS / generating different hash for usqrt REQUIRES: system-linux RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe @@ -22,7 +22,7 @@ CHECK: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty exec RUN: cat %t | sort | FileCheck %s -check-prefix=PERF2BOLT RUN: cat %t.new | FileCheck %s -check-prefix=NEWFORMAT -# Test --profile-format option with perf2bolt +## Test --profile-format option with perf2bolt RUN: perf2bolt %t.exe -o %t.fdata --pa -p %p/Inputs/pre-aggregated.txt \ RUN: --profile-format=fdata RUN: cat %t.fdata | sort | FileCheck %s -check-prefix=PERF2BOLT @@ -31,7 +31,7 @@ RUN: perf2bolt %t.exe -o %t.yaml --pa -p %p/Inputs/pre-aggregated.txt \ RUN: --profile-format=yaml --profile-use-dfs RUN: cat %t.yaml | FileCheck %s -check-prefix=NEWFORMAT -# Test --profile-format option with llvm-bolt --aggregate-only +## Test --profile-format option with llvm-bolt --aggregate-only RUN: llvm-bolt %t.exe -o %t.bolt.fdata --pa -p %p/Inputs/pre-aggregated.txt \ RUN: --aggregate-only --profile-format=fdata RUN: cat %t.bolt.fdata | sort | FileCheck %s -check-prefix=PERF2BOLT diff --git a/bolt/test/X86/pt_gnu_relro.s b/bolt/test/X86/pt_gnu_relro.s index fa4af8287494fcb47cb614f836aad011a24595f5..d7cfad5f954be5ef0acae43bf08134219a4fcd5d 100644 --- a/bolt/test/X86/pt_gnu_relro.s +++ b/bolt/test/X86/pt_gnu_relro.s @@ -1,7 +1,7 @@ # REQUIRES: system-linux -# Check that BOLT recognizes PT_GNU_RELRO segment and marks respective sections -# accordingly. +## Check that BOLT recognizes PT_GNU_RELRO segment and marks respective sections +## accordingly. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe -q --no-relax diff --git a/bolt/test/X86/reader-stale-yaml-std.test b/bolt/test/X86/reader-stale-yaml-std.test index e0b6ca0645e1954c84258d356dd114985e2ec493..b43442ca9ea957c4a9cfea70e9e4cc04c1a1d0e5 100644 --- a/bolt/test/X86/reader-stale-yaml-std.test +++ b/bolt/test/X86/reader-stale-yaml-std.test @@ -1,19 +1,19 @@ -# This script checks that YamlProfileReader in llvm-bolt is reading data -# correctly and stale data is corrected by profile inference. +## This script checks that YamlProfileReader in llvm-bolt is reading data +## correctly and stale data is corrected by profile inference. RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null -b %p/Inputs/blarge_profile_stale.std-hash.yaml \ RUN: --print-cfg --print-only=usqrt,SolveCubic --infer-stale-profile=1 -v=1 \ RUN: 2>&1 | FileCheck %s -# Verify that yaml reader works as expected. +## Verify that yaml reader works as expected. CHECK: pre-processing profile using YAML profile reader CHECK: BOLT-INFO: YAML profile with hash: std::hash -# Function "SolveCubic" has stale profile, since there is one jump in the -# profile (from bid=13 to bid=2) which is not in the CFG in the binary. The test -# verifies that the inference is able to match two blocks (bid=1 and bid=13) -# using "loose" hashes and then correctly propagate the counts. +## Function "SolveCubic" has stale profile, since there is one jump in the +## profile (from bid=13 to bid=2) which is not in the CFG in the binary. The test +## verifies that the inference is able to match two blocks (bid=1 and bid=13) +## using "loose" hashes and then correctly propagate the counts. CHECK: Binary Function "SolveCubic" after building cfg { CHECK: State : CFG constructed @@ -25,7 +25,7 @@ CHECK: BB Count : 18 CHECK: Exec Count : 151 CHECK: Branch Count: 552 CHECK: } -# Verify block counts. +## Verify block counts. CHECK: .LBB00 (43 instructions, align : 1) CHECK: Successors: .Ltmp[[#BB07:]] (mispreds: 0, count: 0), .LFT[[#BB01:]] (mispreds: 0, count: 151) CHECK: .LFT[[#BB01:]] (5 instructions, align : 1) @@ -37,10 +37,10 @@ CHECK: .Ltmp[[#BB013:]] (12 instructions, align : 1) CHECK: Successors: .Ltmp[[#BB03:]] (mispreds: 0, count: 151) CHECK: End of Function "SolveCubic" -# Function "usqrt" has stale profile, since the number of blocks in the profile -# (nblocks=6) does not match the size of the CFG in the binary. The entry -# block (bid=0) has an incorrect (missing) count, which should be inferred by -# the algorithm. +## Function "usqrt" has stale profile, since the number of blocks in the profile +## (nblocks=6) does not match the size of the CFG in the binary. The entry +## block (bid=0) has an incorrect (missing) count, which should be inferred by +# #the algorithm. CHECK: Binary Function "usqrt" after building cfg { CHECK: State : CFG constructed @@ -52,7 +52,7 @@ CHECK: BB Count : 5 CHECK: Exec Count : 20 CHECK: Branch Count: 640 CHECK: } -# Verify block counts. +## Verify block counts. CHECK: .LBB01 (4 instructions, align : 1) CHECK: Successors: .Ltmp[[#BB113:]] (mispreds: 0, count: 20) CHECK: .Ltmp[[#BB113:]] (9 instructions, align : 1) @@ -63,6 +63,6 @@ CHECK: .Ltmp[[#BB112:]] (2 instructions, align : 1) CHECK: Successors: .Ltmp[[#BB113:]] (mispreds: 0, count: 300), .LFT[[#BB11:]] (mispreds: 0, count: 20) CHECK: .LFT[[#BB11:]] (2 instructions, align : 1) CHECK: End of Function "usqrt" -# Check the overall inference stats. +## Check the overall inference stats. CHECK: 2 out of 7 functions in the binary (28.6%) have non-empty execution profile CHECK: inferred profile for 2 (100.00% of profiled, 100.00% of stale) functions responsible for {{.*}} samples ({{.*}} out of {{.*}}) diff --git a/bolt/test/X86/reader-stale-yaml.test b/bolt/test/X86/reader-stale-yaml.test index f4a8865b1f9a46506ecd068cf4fb0c25d51e0b66..378abc38252462d4bbaaae4a2bcd9936905904fe 100644 --- a/bolt/test/X86/reader-stale-yaml.test +++ b/bolt/test/X86/reader-stale-yaml.test @@ -1,20 +1,20 @@ -# This script checks that YamlProfileReader in llvm-bolt is reading data -# correctly and stale data is corrected by profile inference. +## This script checks that YamlProfileReader in llvm-bolt is reading data +## correctly and stale data is corrected by profile inference. REQUIRES: asserts RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \ RUN: --infer-stale-profile=0 --profile-ignore-hash=1 --profile-use-dfs=0 \ RUN: 2>&1 | FileCheck %s -check-prefix=CHECK0 -# Testing "usqrt" +## Testing "usqrt" RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \ RUN: --print-cfg --print-only=usqrt --infer-stale-profile=1 \ RUN: --profile-ignore-hash=1 --profile-use-dfs=0 --debug-only=bolt-prof 2>&1 | FileCheck %s -check-prefix=CHECK1 -# Testing "SolveCubic" +## Testing "SolveCubic" RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \ RUN: --print-cfg --print-only=SolveCubic --infer-stale-profile=1 \ RUN: --profile-ignore-hash=1 --profile-use-dfs=0 --debug-only=bolt-prof 2>&1 | FileCheck %s -check-prefix=CHECK2 -# Testing skipped function +## Testing skipped function RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \ RUN: --print-cfg --print-only=usqrt --infer-stale-profile=1 --skip-funcs=usqrt \ RUN: --profile-ignore-hash=1 --profile-use-dfs=0 @@ -23,12 +23,12 @@ CHECK0: BOLT-INFO: 2 out of 7 functions in the binary (28.6%) have non-empty exe CHECK0: BOLT-WARNING: 2 (100.0% of all profiled) functions have invalid (possibly stale) profile CHECK0: BOLT-WARNING: 1192 out of 1192 samples in the binary (100.0%) belong to functions with invalid (possibly stale) profile -# Function "usqrt" has stale profile, since the number of blocks in the profile -# (nblocks=6) does not match the size of the CFG in the binary. The entry -# block (bid=0) has an incorrect (missing) count, which should be inferred by -# the algorithm. +## Function "usqrt" has stale profile, since the number of blocks in the profile +## (nblocks=6) does not match the size of the CFG in the binary. The entry +## block (bid=0) has an incorrect (missing) count, which should be inferred by +## the algorithm. -# Verify inference details. +## Verify inference details. CHECK1: pre-processing profile using YAML profile reader CHECK1: applying profile inference for "usqrt" CHECK1: Matched yaml block (bid = 0) with hash 1111111111111111 to BB (index = 0) with hash 36007ba1d80c0000 @@ -38,7 +38,7 @@ CHECK1-NEXT: exact match CHECK1: Matched yaml block (bid = 3) with hash 5c06705524800039 to BB (index = 3) with hash 5c06705524800039 CHECK1-NEXT: exact match -# Verify that yaml reader works as expected. +## Verify that yaml reader works as expected. CHECK1: Binary Function "usqrt" after building cfg { CHECK1: State : CFG constructed CHECK1: Address : 0x401170 @@ -50,7 +50,7 @@ CHECK1: Exec Count : 20 CHECK1: Branch Count: 640 CHECK1: } -# Verify block counts. +## Verify block counts. CHECK1: .LBB01 (4 instructions, align : 1) CHECK1: Successors: .Ltmp[[#BB13:]] (mispreds: 0, count: 20) CHECK1: .Ltmp[[#BB13:]] (9 instructions, align : 1) @@ -60,19 +60,19 @@ CHECK1: Successors: .Ltmp[[#BB12:]] (mispreds: 0, count: 0) CHECK1: .Ltmp[[#BB12:]] (2 instructions, align : 1) CHECK1: Successors: .Ltmp[[#BB13:]] (mispreds: 0, count: 300), .LFT[[#BB1:]] (mispreds: 0, count: 20) CHECK1: .LFT[[#BB1:]] (2 instructions, align : 1) -# Check the overall inference stats. +## Check the overall inference stats. CHECK1: 2 out of 7 functions in the binary (28.6%) have non-empty execution profile CHECK1: BOLT-WARNING: 2 (100.0% of all profiled) functions have invalid (possibly stale) profile CHECK1: BOLT-WARNING: 1192 out of 1192 samples in the binary (100.0%) belong to functions with invalid (possibly stale) profile CHECK1: inferred profile for 2 (100.00% of profiled, 100.00% of stale) functions responsible for {{.*}} samples ({{.*}} out of {{.*}}) -# Function "SolveCubic" has stale profile, since there is one jump in the -# profile (from bid=13 to bid=2) which is not in the CFG in the binary. The test -# verifies that the inference is able to match two blocks (bid=1 and bid=13) -# using "loose" hashes and then correctly propagate the counts. +## Function "SolveCubic" has stale profile, since there is one jump in the +## profile (from bid=13 to bid=2) which is not in the CFG in the binary. The test +## verifies that the inference is able to match two blocks (bid=1 and bid=13) +## using "loose" hashes and then correctly propagate the counts. -# Verify inference details. +## Verify inference details. CHECK2: pre-processing profile using YAML profile reader CHECK2: applying profile inference for "SolveCubic" CHECK2: Matched yaml block (bid = 0) with hash 4600940a609c0000 to BB (index = 0) with hash 4600940a609c0000 @@ -86,7 +86,7 @@ CHECK2-NEXT: loose match CHECK2: Matched yaml block (bid = 5) with hash 6446e1ea500111 to BB (index = 5) with hash 6446e1ea500111 CHECK2-NEXT: exact match -# Verify that yaml reader works as expected. +## Verify that yaml reader works as expected. CHECK2: Binary Function "SolveCubic" after building cfg { CHECK2: State : CFG constructed CHECK2: Address : 0x400e00 @@ -97,7 +97,7 @@ CHECK2: BB Count : 18 CHECK2: Exec Count : 151 CHECK2: Branch Count: 552 -# Verify block counts. +## Verify block counts. CHECK2: .LBB00 (43 instructions, align : 1) CHECK2: Successors: .Ltmp[[#BB7:]] (mispreds: 0, count: 0), .LFT[[#BB1:]] (mispreds: 0, count: 151) CHECK2: .LFT[[#BB1:]] (5 instructions, align : 1) diff --git a/bolt/test/X86/reader.test b/bolt/test/X86/reader.test index 308b97e30bb5602102eeb3fef29d8f1ddcfe9533..4d5d7bc818dd7ab0008566075cd87c81f9949586 100644 --- a/bolt/test/X86/reader.test +++ b/bolt/test/X86/reader.test @@ -1,4 +1,4 @@ -# This script checks that DataReader in llvm-bolt is reading data correctly +## This script checks that DataReader in llvm-bolt is reading data correctly RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: llvm-bolt %t.exe -o %t.null --data %p/Inputs/blarge.fdata --dump-data \ diff --git a/bolt/test/X86/register-fragments-bolt-symbols.s b/bolt/test/X86/register-fragments-bolt-symbols.s index 6478adf19372b2938061dd36389330e4b6ebe79d..5c9fb5ed1a757e2870ea2ab8eef8a23cff2bff6c 100644 --- a/bolt/test/X86/register-fragments-bolt-symbols.s +++ b/bolt/test/X86/register-fragments-bolt-symbols.s @@ -1,10 +1,22 @@ -# Test the heuristics for matching BOLT-added split functions. +## Test the heuristics for matching BOLT-added split functions. # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o # RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata -# RUN: sed -i 's|chain|chain/2|g' %t.fdata # RUN: llvm-strip --strip-unneeded %t.main.o + +## Check warm fragment name matching (produced by cdsplit) +# RUN: %clang %cflags %t.main.o -o %t.warm.exe -Wl,-q +# RUN: llvm-bolt %t.warm.exe -o %t.warm.bolt --split-functions --split-strategy=cdsplit \ +# RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp --enable-bat +# RUN: link_fdata %s %t.warm.bolt %t.preagg.warm PREAGGWARM +# PREAGGWARM: B X:0 #chain.warm# 1 0 +# RUN: perf2bolt %t.warm.bolt -p %t.preagg.warm --pa -o %t.warm.fdata -w %t.warm.yaml \ +# RUN: -v=1 | FileCheck %s --check-prefix=CHECK-BOLT-WARM + +# CHECK-BOLT-WARM: marking chain.warm/1(*2) as a fragment of chain + +# RUN: sed -i 's|chain|chain/2|g' %t.fdata # RUN: llvm-objcopy --localize-symbol=chain %t.main.o # RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q # RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \ @@ -18,6 +30,11 @@ # RUN: FileCheck --input-file %t.bat.fdata --check-prefix=CHECK-FDATA %s # RUN: FileCheck --input-file %t.bat.yaml --check-prefix=CHECK-YAML %s +# RUN: link_fdata --no-redefine %s %t.bolt %t.preagg2 PREAGG2 +# PREAGG2: B X:0 #chain# 1 0 +# RUN: perf2bolt %t.bolt -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml +# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix=CHECK-YAML2 + # CHECK-SYMS: l df *ABS* [[#]] chain.s # CHECK-SYMS: l F .bolt.org.text [[#]] chain # CHECK-SYMS: l F .text.cold [[#]] chain.cold.0 @@ -28,6 +45,9 @@ # CHECK-FDATA: 0 [unknown] 0 1 chain/chain.s/2 10 0 1 # CHECK-YAML: - name: 'chain/chain.s/2' +# CHECK-YAML2: - name: 'chain/chain.s/1' +## non-BAT function has non-zero insns: +# CHECK-YAML2: insns: 1 .file "chain.s" .text diff --git a/bolt/test/X86/relaxed-tailcall.test b/bolt/test/X86/relaxed-tailcall.test index d303c4255ae7e206c1b55b1a5d717be6034c3217..c2f7a71b9e3e52ed66a893d9cc3526bdd08c4d2f 100644 --- a/bolt/test/X86/relaxed-tailcall.test +++ b/bolt/test/X86/relaxed-tailcall.test @@ -1,4 +1,4 @@ -# Check that tail calls can be 2 bytes in the output binary. +## Check that tail calls can be 2 bytes in the output binary. RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-unknown -o %t.o \ RUN: %S/Inputs/relaxed_tc.s diff --git a/bolt/test/X86/remove-unused.test b/bolt/test/X86/remove-unused.test index 45e9f428e91d6887a9a9b329f842b29a7bd29c69..83223ace26b7e06246fe5c024ea7973ef8816a70 100644 --- a/bolt/test/X86/remove-unused.test +++ b/bolt/test/X86/remove-unused.test @@ -1,5 +1,5 @@ -# Verifies that llvm-bolt is able to remove dead basic blocks. Also check that -# the BB reordering ignores dead BBs. +## Verifies that llvm-bolt is able to remove dead basic blocks. Also check that +## the BB reordering ignores dead BBs. RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %S/Inputs/entry.s -o %t.o RUN: link_fdata %S/Inputs/entry.s %t.o %t.fdata --nmtool llvm-nm @@ -9,5 +9,5 @@ RUN: llvm-bolt %t.exe --data %t.fdata -o %t --funcs=_start \ RUN: --eliminate-unreachable --reorder-blocks=none \ RUN: --print-finalized --sequential-disassembly 2>&1 | FileCheck %s -# Optimized +## Optimized CHECK: BB Layout : .LBB00, .Ltmp0, .Ltmp2, .Ltmp3, .Ltmp4, .Ltmp5, .Ltmp6, .Ltmp7, .Ltmp8, .Ltmp9, .Ltmp10, .Ltmp11 diff --git a/bolt/test/X86/rodata-simpl-loads.test b/bolt/test/X86/rodata-simpl-loads.test index 8018ad75e5d69a3867e39726db634cce5583a919..4617331fb7613b5422889739682593550640b44d 100644 --- a/bolt/test/X86/rodata-simpl-loads.test +++ b/bolt/test/X86/rodata-simpl-loads.test @@ -1,4 +1,4 @@ -# Check for the simplification of .rodata loads. +## Check for the simplification of .rodata loads. RUN: %clang %cflags %p/Inputs/rodata_simpl_loads.s -o %t.exe RUN: llvm-bolt %t.exe -o %t --simplify-rodata-loads @@ -7,8 +7,8 @@ RUN: llvm-objdump -d %t --print-imm-hex --disassemble-symbols=main | FileCheck % CHECK: Disassembly of section .text: CHECK:
: -# check that the following rip-relative operands have been -# replaced with immediates +## check that the following rip-relative operands have been +## replaced with immediates ORIGINAL: movzbl s1(%rip), %eax CHECK: movl $0x41, %eax diff --git a/bolt/test/X86/sctc-bug.test b/bolt/test/X86/sctc-bug.test index 1b581df23749033ad7728cf739f8b54aa16ebc93..fb3aff8529f8ce29a0af40313f785c95e2563b53 100644 --- a/bolt/test/X86/sctc-bug.test +++ b/bolt/test/X86/sctc-bug.test @@ -1,4 +1,4 @@ -# Check that we don't accidentally optimize out a tail call. +## Check that we don't accidentally optimize out a tail call. RUN: %clang %cflags %S/Inputs/sctc_bug.s -o %t RUN: llvm-bolt %t -o %t.null --funcs=main --print-after-lowering \ diff --git a/bolt/test/X86/sctc-bug2.test b/bolt/test/X86/sctc-bug2.test index 0e235564dc3bd99ee5d31ec17e041c5b9858b09c..8b2f58f62507528beb22e18b9a95427356bd9686 100644 --- a/bolt/test/X86/sctc-bug2.test +++ b/bolt/test/X86/sctc-bug2.test @@ -1,4 +1,4 @@ -# Check that conditional tail call is not treated as a regular tail call by SCTC. +## Check that conditional tail call is not treated as a regular tail call by SCTC. RUN: %clang %cflags %S/Inputs/sctc_bug2.s -o %t RUN: llvm-bolt %t -o %t.null --funcs=main --print-after-lowering \ diff --git a/bolt/test/X86/sctc-bug3.test b/bolt/test/X86/sctc-bug3.test index 69c8c454284445dc3b516f9d958cac0d8110cc18..d821389a459fb2e5cb834b945e21b451d5b68070 100644 --- a/bolt/test/X86/sctc-bug3.test +++ b/bolt/test/X86/sctc-bug3.test @@ -1,4 +1,4 @@ -# Check that we don't accidentally optimize out a tail call. +## Check that we don't accidentally optimize out a tail call. RUN: %clang %cflags %S/Inputs/sctc_bug3.s -o %t RUN: llvm-bolt %t -o %t.null --funcs=main --print-after-lowering \ @@ -7,9 +7,9 @@ RUN: --sequential-disassembly 2>&1 | FileCheck %s CHECK: .LBB00 (1 instructions, align : 1) CHECK: cmpq %rdi, 0x0 -# Check that .Ltmp0 does not have a deleted predecessor. +## Check that .Ltmp0 does not have a deleted predecessor. CHECK: .Ltmp0 (1 instructions, align : 1) CHECK: Predecessors: .LBB00 -# Tail call. +## Tail call. CHECK: jmp foo diff --git a/bolt/test/X86/sctc-bug4.test b/bolt/test/X86/sctc-bug4.test index 92aca5110059f4a7fd5ef9cc43db9e1c22286c35..21a602b6729ae3111d0a29115d114f54b4ad876a 100644 --- a/bolt/test/X86/sctc-bug4.test +++ b/bolt/test/X86/sctc-bug4.test @@ -1,5 +1,5 @@ -# Check that fallthrough blocks are handled properly and Offset annotation is -# set for conditional tail calls. +## Check that fallthrough blocks are handled properly and Offset annotation is +## set for conditional tail calls. RUN: %clang %cflags %S/Inputs/sctc_bug4.s -o %t RUN: llvm-bolt %t -o %t.null --enable-bat \ diff --git a/bolt/test/X86/shared_object_entry.s b/bolt/test/X86/shared_object_entry.s index eeefbd8ee4e6f929535a07f829b03e117d48eeff..87a3c0655533d1552d947abd2f5468fa9bb3c916 100644 --- a/bolt/test/X86/shared_object_entry.s +++ b/bolt/test/X86/shared_object_entry.s @@ -4,7 +4,7 @@ # RUN: -split-functions -reorder-blocks=ext-tsp -split-all-cold \ # RUN: -dyno-stats -icf=1 -use-gnu-stack -# Check that an entry point is a cold symbol +## Check that an entry point is a cold symbol # RUN: llvm-readelf -h %t.so > %t.log # RUN: llvm-nm %t.so >> %t.log # RUN: FileCheck %s --input-file %t.log diff --git a/bolt/test/X86/shorten-mov.test b/bolt/test/X86/shorten-mov.test index db911ad0c0ebf3350a520920e97b2b17e3180b64..dfe21ef967ef3a96b9d2754749d19803ae70fdad 100644 --- a/bolt/test/X86/shorten-mov.test +++ b/bolt/test/X86/shorten-mov.test @@ -1,5 +1,5 @@ -# Test that 64 bit movq instructions with immediate operands -# that fit in 32 bits are shortened. +## Test that 64 bit movq instructions with immediate operands +## that fit in 32 bits are shortened. RUN: %clang %cflags %p/Inputs/asm_main.c %p/Inputs/shorten_mov.s -o %t.exe RUN: llvm-bolt %t.exe -o %t diff --git a/bolt/test/X86/shrinkwrapping-and-rsp.s b/bolt/test/X86/shrinkwrapping-and-rsp.s index 2e5918e857e62d46b6f48b175289f3400cb6361e..cbc2953d5db0aa1b9acbbd386ea35ed3e149f592 100644 --- a/bolt/test/X86/shrinkwrapping-and-rsp.s +++ b/bolt/test/X86/shrinkwrapping-and-rsp.s @@ -1,5 +1,5 @@ -# This checks that shrink wrapping does attempt at accessing stack elements -# using RSP when the function is aligning RSP and changing offsets. +## This checks that shrink wrapping does attempt at accessing stack elements +## using RSP when the function is aligning RSP and changing offsets. # REQUIRES: system-linux @@ -12,10 +12,10 @@ # RUN: --frame-opt=all --simplify-conditional-tail-calls=false \ # RUN: --eliminate-unreachable=false | FileCheck %s -# Here we have a function that aligns the stack at prologue. Stack pointer -# analysis can't try to infer offset positions after AND because that depends -# on the runtime value of the stack pointer of callee (whether it is misaligned -# or not). +## Here we have a function that aligns the stack at prologue. Stack pointer +## analysis can't try to infer offset positions after AND because that depends +## on the runtime value of the stack pointer of callee (whether it is misaligned +## or not). .globl _start .type _start, %function _start: diff --git a/bolt/test/X86/shrinkwrapping-critedge.s b/bolt/test/X86/shrinkwrapping-critedge.s index ed9a206dec41fca35233c9805c5f296062e8b6b0..6b5213ba1985321fac6d629716b9c00c7321a4c6 100644 --- a/bolt/test/X86/shrinkwrapping-critedge.s +++ b/bolt/test/X86/shrinkwrapping-critedge.s @@ -1,5 +1,5 @@ -# This reproduces a bug with shrink wrapping when trying to split critical -# edges originating at the same basic block. +## This reproduces a bug with shrink wrapping when trying to split critical +## edges originating at the same basic block. # REQUIRES: system-linux diff --git a/bolt/test/X86/shrinkwrapping-do-not-pessimize.s b/bolt/test/X86/shrinkwrapping-do-not-pessimize.s index 3fdd5f5e38fe0da9b964a36fbfb0edb35b6a15e5..343dd89f75fca871925a5a59fe0ee5895aebab8a 100644 --- a/bolt/test/X86/shrinkwrapping-do-not-pessimize.s +++ b/bolt/test/X86/shrinkwrapping-do-not-pessimize.s @@ -1,10 +1,10 @@ -# This checks that shrink wrapping does not pessimize a CFG pattern where two -# blocks can be proved to have the same execution count but, because of profile -# inaccuricies, we could move saves into the second block. We can prove two -# blocks have the same frequency when B post-dominate A and A dominates B and -# are at the same loop nesting level. This would be a pessimization because -# shrink wrapping is unlikely to be able to cleanly move PUSH instructions, -# inserting additional store instructions. +## This checks that shrink wrapping does not pessimize a CFG pattern where two +## blocks can be proved to have the same execution count but, because of profile +## inaccuricies, we could move saves into the second block. We can prove two +## blocks have the same frequency when B post-dominate A and A dominates B and +## are at the same loop nesting level. This would be a pessimization because +## shrink wrapping is unlikely to be able to cleanly move PUSH instructions, +## inserting additional store instructions. # REQUIRES: system-linux @@ -16,15 +16,15 @@ # RUN: llvm-bolt -relocs %t.exe -o %t.out -data %t.fdata \ # RUN: -frame-opt=all -equalize-bb-counts | FileCheck %s -# Here we create a CFG pattern with two blocks A and B belonging to the same -# equivalency class as defined by dominance relations and having in theory -# the same frequency. But we tweak edge counts from profile to make block A -# hotter than block B. +## Here we create a CFG pattern with two blocks A and B belonging to the same +## equivalency class as defined by dominance relations and having in theory +## the same frequency. But we tweak edge counts from profile to make block A +## hotter than block B. .globl _start .type _start, %function _start: .cfi_startproc -# Hot prologue +## Hot prologue # FDATA: 0 [unknown] 0 1 _start 0 0 10 push %rbp mov %rsp, %rbp @@ -36,7 +36,7 @@ b: je end_if_1 if_false: movq rel(%rip), %rdi # Add this to create a relocation and run bolt w/ relocs c: jmp end_if_1 -# Reduce frequency from 9 to 1 to simulate an inaccurate profile +## Reduce frequency from 9 to 1 to simulate an inaccurate profile # FDATA: 1 _start #c# 1 _start #end_if_1# 0 1 end_if_1: # first uses of R14 and RBX appear at this point, possible move point for SW diff --git a/bolt/test/X86/shrinkwrapping-insertcfi.s b/bolt/test/X86/shrinkwrapping-insertcfi.s index 57b43cf4b6623df27d96978c484571d41db4141e..b3813ad86b46ac8316e6bb299b4d4c3361d8babc 100644 --- a/bolt/test/X86/shrinkwrapping-insertcfi.s +++ b/bolt/test/X86/shrinkwrapping-insertcfi.s @@ -1,5 +1,5 @@ -# This test reproduces the issue with inserting updated CFI in shrink wrapping -# into the first basic block. +## This test reproduces the issue with inserting updated CFI in shrink wrapping +## into the first basic block. # REQUIRES: system-linux @@ -10,10 +10,10 @@ # RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata --frame-opt=all --lite=0 \ # RUN: --print-fop 2>&1 | FileCheck %s -# Check shrink wrapping results: +## Check shrink wrapping results: # CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 1 spills inserting push/pops -# Check that CFI is successfully inserted into the first basic block: +## Check that CFI is successfully inserted into the first basic block: # CHECK: Binary Function "_start" after frame-optimizer # CHECK: .LBB00 (2 instructions, align : 1) # CHECK-NEXT: Entry Point @@ -34,8 +34,8 @@ c: .cfi_offset 3, 4 pop %rbx -# This basic block is treated as having 0 execution count. -# push and pop will be sinked into this block. +## This basic block is treated as having 0 execution count. +## push and pop will be sinked into this block. a: ud2 .cfi_endproc diff --git a/bolt/test/X86/shrinkwrapping-lea.s b/bolt/test/X86/shrinkwrapping-lea.s index db31696ebd6dbd3037b0bf973a432b2f2f54c1c9..c4860826bea5e6970107527e1f0a07e9d2b8c39f 100644 --- a/bolt/test/X86/shrinkwrapping-lea.s +++ b/bolt/test/X86/shrinkwrapping-lea.s @@ -1,5 +1,5 @@ -# This checks that shrink wrapping correctly drops moving push/pops when -# there is an LEA instruction. +## This checks that shrink wrapping correctly drops moving push/pops when +## there is an LEA instruction. # REQUIRES: system-linux @@ -58,7 +58,7 @@ JT: # CHECK: BOLT-INFO: Shrink wrapping moved 2 spills inserting load/stores and 0 spills inserting push/pops -# Checks that offsets of instructions accessing the stack were not changed +## Checks that offsets of instructions accessing the stack were not changed # CHECK-OBJDUMP: <_start>: # CHECK-OBJDUMP: movq %rbx, %rdi # CHECK-OBJDUMP-NEXT: leaq -0x20(%rbp), %r14 diff --git a/bolt/test/X86/shrinkwrapping-mov.s b/bolt/test/X86/shrinkwrapping-mov.s index 4a81b369c9766a6a6053077c8172886340133a2f..c6e5aed34419f1128403c9b2ae60ffb3f6ff6c87 100644 --- a/bolt/test/X86/shrinkwrapping-mov.s +++ b/bolt/test/X86/shrinkwrapping-mov.s @@ -1,6 +1,6 @@ -# This checks that shrink wrapping correctly drops moving push/pops when -# there is a MOV instruction loading the value of the stack pointer in -# order to do pointer arithmetic with a stack address. +## This checks that shrink wrapping correctly drops moving push/pops when +## there is a MOV instruction loading the value of the stack pointer in +## order to do pointer arithmetic with a stack address. # REQUIRES: system-linux diff --git a/bolt/test/X86/shrinkwrapping-pop-order.s b/bolt/test/X86/shrinkwrapping-pop-order.s index 2a5db3685e526918b3ee7715fcbdaee8bf99a4b4..abad44e618003311bc5f385ab7a2c41b068ff677 100644 --- a/bolt/test/X86/shrinkwrapping-pop-order.s +++ b/bolt/test/X86/shrinkwrapping-pop-order.s @@ -1,6 +1,6 @@ -# This test reproduces a POP reordering issue in shrink wrapping where we would -# incorrectly put a store after a load (instead of before) when having multiple -# insertions at the same point. Check that the order is correct in this test. +## This test reproduces a POP reordering issue in shrink wrapping where we would +## incorrectly put a store after a load (instead of before) when having multiple +## insertions at the same point. Check that the order is correct in this test. # REQUIRES: system-linux @@ -25,23 +25,23 @@ c: pop %rbp pop %rbx -# This basic block is treated as having 0 execution count. -# push and pop will be sinked into this block. +## This basic block is treated as having 0 execution count. +## push and pop will be sinked into this block. a: ud2 .cfi_endproc -# Check shrink wrapping results: +## Check shrink wrapping results: # CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 2 spills inserting push/pops # CHECK: BOLT-INFO: Shrink wrapping reduced 6 store executions (28.6% total instructions executed, 100.0% store instructions) # CHECK: BOLT-INFO: Shrink wrapping failed at reducing 0 store executions (0.0% total instructions executed, 0.0% store instructions) -# Check that order is correct +## Check that order is correct # CHECK: Binary Function "_start" after frame-optimizer # Pushes are ordered according to their reg number and come first # CHECK: pushq %rbp # CHECK: pushq %rbx -# Pops are ordered according to their dominance relation and come last +## Pops are ordered according to their dominance relation and come last # CHECK: popq %rbx # CHECK: popq %rbp diff --git a/bolt/test/X86/shrinkwrapping-popf.s b/bolt/test/X86/shrinkwrapping-popf.s index 9e1dcd54a617eb22fb1a5c31aa09abc98e13bd8d..a21ea99c37efac4b2fdeb4d90d9dcdb3f2a2ec39 100644 --- a/bolt/test/X86/shrinkwrapping-popf.s +++ b/bolt/test/X86/shrinkwrapping-popf.s @@ -1,4 +1,4 @@ -# This test checks that POPF will not crash our frame analysis pass +## This test checks that POPF will not crash our frame analysis pass # REQUIRES: system-linux @@ -26,7 +26,7 @@ c: pop %rbx popf -# This basic block is treated as having 0 execution count. +## This basic block is treated as having 0 execution count. a: ud2 .cfi_endproc diff --git a/bolt/test/X86/shrinkwrapping-restore-position.s b/bolt/test/X86/shrinkwrapping-restore-position.s index 576fa8fcc39436ab6b95adb1baf1512a2a4f1ac5..1d26b6e48e6fcac61e1cdf5f5524b1115929e626 100644 --- a/bolt/test/X86/shrinkwrapping-restore-position.s +++ b/bolt/test/X86/shrinkwrapping-restore-position.s @@ -1,5 +1,5 @@ -# This checks that shrink wrapping uses the red zone defined in the X86 ABI by -# placing restores that access elements already deallocated by the stack. +## This checks that shrink wrapping uses the red zone defined in the X86 ABI by +## placing restores that access elements already deallocated by the stack. # REQUIRES: system-linux @@ -16,10 +16,10 @@ # RUN: FileCheck --check-prefix CHECK-OBJDUMP %s -# Here we create a CFG where the restore position matches the previous (deleted) -# restore position. Shrink wrapping then will put a stack access to an element -# that was deallocated at the previously deleted POP, which falls in the red -# zone and should be safe for X86 Linux ABI. +## Here we create a CFG where the restore position matches the previous (deleted) +## restore position. Shrink wrapping then will put a stack access to an element +## that was deallocated at the previously deleted POP, which falls in the red +## zone and should be safe for X86 Linux ABI. .globl _start .type _start, %function _start: diff --git a/bolt/test/X86/shrinkwrapping.test b/bolt/test/X86/shrinkwrapping.test index 1767db2978d1fd63e8ff831389412ca1eab857d6..8581d7e0c0f7b1adf630fa702b324101416872df 100644 --- a/bolt/test/X86/shrinkwrapping.test +++ b/bolt/test/X86/shrinkwrapping.test @@ -1,9 +1,9 @@ -# Verifies that llvm-bolt updates CFI correctly after -# shrink-wrapping when optimizing a function without -# frame pointers. +## Verifies that llvm-bolt updates CFI correctly after +## shrink-wrapping when optimizing a function without +## frame pointers. -# This test has commands that rely on shell capabilities that won't execute -# correctly on Windows e.g. subshell execution to capture command output. +## This test has commands that rely on shell capabilities that won't execute +## correctly on Windows e.g. subshell execution to capture command output. REQUIRES: shell RUN: %clangxx %cxxflags -no-pie %S/Inputs/exc4sw.S -o %t.exe -Wl,-q diff --git a/bolt/test/X86/split-all-lptrampoline.s b/bolt/test/X86/split-all-lptrampoline.s index 4629a2cf9b957f17a553082c688e807078ed39c2..df50a7fbe030558262a6722694b6f75f394d79da 100644 --- a/bolt/test/X86/split-all-lptrampoline.s +++ b/bolt/test/X86/split-all-lptrampoline.s @@ -1,6 +1,6 @@ -# This test checks that trampolines are inserted in split fragments if -# necessary. There are 4 LSDA ranges with a landing pad to three landing pads. -# After splitting all blocks, there have to be 4 trampolines in the output. +## This test checks that trampolines are inserted in split fragments if +## necessary. There are 4 LSDA ranges with a landing pad to three landing pads. +## After splitting all blocks, there have to be 4 trampolines in the output. # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: %clangxx %cxxflags %t.o -o %t.exe -Wl,-q -pie diff --git a/bolt/test/X86/split-all.s b/bolt/test/X86/split-all.s index 1f51ba2e375e83f2fdf875dcdb5ea7d62ff48552..0b21e1b2b53581f560978a10a996e7a98226c681 100644 --- a/bolt/test/X86/split-all.s +++ b/bolt/test/X86/split-all.s @@ -1,4 +1,4 @@ -# Test split all block strategy +## Test split all block strategy # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q diff --git a/bolt/test/X86/split-func-icf.s b/bolt/test/X86/split-func-icf.s index 259c301864002b292b5d6a2a0a9f75fae402480e..a87c52cccb0fc1fe7a5b849d848cc1d1383b3244 100644 --- a/bolt/test/X86/split-func-icf.s +++ b/bolt/test/X86/split-func-icf.s @@ -1,7 +1,7 @@ -# This reproduces an issue where two cold fragments are folded into one, so the -# fragment has two parents. -# The fragment is only reachable through a jump table, so all functions must be -# ignored. +## This reproduces an issue where two cold fragments are folded into one, so the +## fragment has two parents. +## The fragment is only reachable through a jump table, so all functions must be +## ignored. # REQUIRES: system-linux @@ -27,10 +27,10 @@ main: LBB0: andl $0xf, %ecx cmpb $0x4, %cl - # exit through ret + ## exit through ret ja LBB3 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: leaq JUMP_TABLE1(%rip), %r8 movzbl %cl, %ecx @@ -55,7 +55,7 @@ LBB20: # exit through ret ja LBB23 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB21: leaq JUMP_TABLE2(%rip), %r8 movzbl %cl, %ecx @@ -70,7 +70,7 @@ LBB23: ret .size main2, .-main2 -# cold fragment is only reachable through jump table +## cold fragment is only reachable through jump table .globl main2.cold.1 .type main2.cold.1, %function main2.cold.1: @@ -78,15 +78,15 @@ main2.cold.1: .type main.cold.1, %function .p2align 2 main.cold.1: - # load bearing nop: pad LBB4 so that it can't be treated - # as __builtin_unreachable by analyzeJumpTable + ## load bearing nop: pad LBB4 so that it can't be treated + ## as __builtin_unreachable by analyzeJumpTable nop LBB4: callq abort .size main.cold.1, .-main.cold.1 .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE1 JUMP_TABLE1: .long LBB2-JUMP_TABLE1 diff --git a/bolt/test/X86/split-func-jump-table-fragment-bidirection.s b/bolt/test/X86/split-func-jump-table-fragment-bidirection.s index caebe59ed086569893d8dc4f8b018002e8bc724f..52c816ccd90057f480b5046cb0516350ac8df6e4 100644 --- a/bolt/test/X86/split-func-jump-table-fragment-bidirection.s +++ b/bolt/test/X86/split-func-jump-table-fragment-bidirection.s @@ -1,7 +1,7 @@ -# This reproduces an issue where two fragments of same function access same -# jump table, which means at least one fragment visits the other, i.e., one -# of them has split jump table. As a result, all of them will be marked as -# non-simple function. +## This reproduces an issue where two fragments of same function access same +## jump table, which means at least one fragment visits the other, i.e., one +## of them has split jump table. As a result, all of them will be marked as +## non-simple function. # REQUIRES: system-linux @@ -21,10 +21,10 @@ main: LBB0: andl $0xf, %ecx cmpb $0x4, %cl - # exit through ret + ## exit through ret ja LBB3 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: leaq JUMP_TABLE1(%rip), %r8 movzbl %cl, %ecx @@ -39,13 +39,13 @@ LBB3: ret .size main, .-main -# cold fragment is only reachable +## cold fragment is only reachable .globl main.cold.1 .type main.cold.1, %function .p2align 2 main.cold.1: - # load bearing nop: pad LBB8 so that it can't be treated - # as __builtin_unreachable by analyzeJumpTable + ## load bearing nop: pad LBB8 so that it can't be treated + ## as __builtin_unreachable by analyzeJumpTable nop LBB4: andl $0xb, %ebx @@ -53,7 +53,7 @@ LBB4: # exit through ret ja LBB7 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB5: leaq JUMP_TABLE1(%rip), %r8 movzbl %cl, %ecx @@ -71,7 +71,7 @@ LBB8: .size main.cold.1, .-main.cold.1 .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE1 JUMP_TABLE1: .long LBB2-JUMP_TABLE1 diff --git a/bolt/test/X86/split-func-jump-table-fragment-noparent.s b/bolt/test/X86/split-func-jump-table-fragment-noparent.s index a3ac643ee1376a2400115fce67502950991c2864..499dcaf4ced4c09e19c58bf56142289e0de569c1 100644 --- a/bolt/test/X86/split-func-jump-table-fragment-noparent.s +++ b/bolt/test/X86/split-func-jump-table-fragment-noparent.s @@ -1,6 +1,6 @@ -# This reproduces a bug with jump table identification where jump table has -# entries pointing to code in function and its cold fragment. -# The fragment is only reachable through jump table. +## This reproduces a bug with jump table identification where jump table has +## entries pointing to code in function and its cold fragment. +## The fragment is only reachable through jump table. # REQUIRES: system-linux @@ -19,10 +19,10 @@ main: LBB0: andl $0xf, %ecx cmpb $0x4, %cl - # exit through ret + ## exit through ret ja LBB3 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: leaq JUMP_TABLE(%rip), %r8 movzbl %cl, %ecx @@ -37,20 +37,20 @@ LBB3: ret .size main, .-main -# cold fragment is only reachable through jump table +## cold fragment is only reachable through jump table .globl main.cold.1 .type main.cold.1, %function .p2align 2 main.cold.1: - # load bearing nop: pad LBB4 so that it can't be treated - # as __builtin_unreachable by analyzeJumpTable + ## load bearing nop: pad LBB4 so that it can't be treated + ## as __builtin_unreachable by analyzeJumpTable nop LBB4: callq abort .size main.cold.1, .-main.cold.1 .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE JUMP_TABLE: .long LBB2-JUMP_TABLE diff --git a/bolt/test/X86/split-func-jump-table-fragment-reverse.s b/bolt/test/X86/split-func-jump-table-fragment-reverse.s index 639c800a795b1ea73f1342396e6040032d328f54..634a45b3f2f10711417bc59cdbc1d43a51ec1d49 100644 --- a/bolt/test/X86/split-func-jump-table-fragment-reverse.s +++ b/bolt/test/X86/split-func-jump-table-fragment-reverse.s @@ -1,6 +1,6 @@ -# This reproduces a bug with jump table identification where jump table has -# entries pointing to code in function and its cold fragment. -# The fragment is only reachable through jump table. +## This reproduces a bug with jump table identification where jump table has +## entries pointing to code in function and its cold fragment. +## The fragment is only reachable through jump table. # REQUIRES: system-linux @@ -26,10 +26,10 @@ main.cold: LBB0: andl $0xf, %ecx cmpb $0x4, %cl - # exit through ret + ## exit through ret ja LBB3 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: leaq JUMP_TABLE(%rip), %r8 movzbl %cl, %ecx @@ -44,20 +44,20 @@ LBB3: ret .size main.cold, .-main.cold -# main function, referenced from jump table in cold fragment +## main function, referenced from jump table in cold fragment .globl main .type main, %function .p2align 2 main: - # load bearing nop: pad LBB4 so that it can't be treated - # as __builtin_unreachable by analyzeJumpTable + ## load bearing nop: pad LBB4 so that it can't be treated + ## as __builtin_unreachable by analyzeJumpTable nop LBB4: callq abort .size main, .-main .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE JUMP_TABLE: .long LBB2-JUMP_TABLE diff --git a/bolt/test/X86/split-func-jump-table-fragment.s b/bolt/test/X86/split-func-jump-table-fragment.s index a92e6731dffe6b1e994d4073711560a933c62a4e..12fe69110b260e2c2a87818ae5c24bb3f406d93f 100644 --- a/bolt/test/X86/split-func-jump-table-fragment.s +++ b/bolt/test/X86/split-func-jump-table-fragment.s @@ -19,10 +19,10 @@ main: LBB0: andl $0xf, %ecx cmpb $0x4, %cl - # exit through abort in main.cold.1, registers cold fragment the regular way + ## exit through abort in main.cold.1, registers cold fragment the regular way ja main.cold.1 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: leaq JUMP_TABLE(%rip), %r8 movzbl %cl, %ecx @@ -37,8 +37,8 @@ LBB3: ret .size main, .-main -# Insert padding between functions, so that the next instruction cannot be -# treated as __builtin_unreachable destination for the jump table. +## Insert padding between functions, so that the next instruction cannot be +## treated as __builtin_unreachable destination for the jump table. .quad 0 .globl main.cold.1 @@ -50,7 +50,7 @@ LBB4: .size main.cold.1, .-main.cold.1 .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE JUMP_TABLE: .long LBB2-JUMP_TABLE diff --git a/bolt/test/X86/split-func-jump-table-unknown.s b/bolt/test/X86/split-func-jump-table-unknown.s index 71a172bb5f4a43975c74c43de58f3cea1bedf57e..aae140418401fc94f2ec72fb33dc91ba6fe0f902 100644 --- a/bolt/test/X86/split-func-jump-table-unknown.s +++ b/bolt/test/X86/split-func-jump-table-unknown.s @@ -1,5 +1,5 @@ -# This reproduces a bug with converting an unknown control flow jump table with -# entries pointing to code in function and its cold fragment. +## This reproduces a bug with converting an unknown control flow jump table with +## entries pointing to code in function and its cold fragment. # REQUIRES: system-linux @@ -27,10 +27,10 @@ LBB0: leaq JUMP_TABLE(%rip), %r8 andl $0xf, %ecx cmpb $0x4, %cl - # exit through abort in main.cold.1, registers cold fragment the regular way + ## exit through abort in main.cold.1, registers cold fragment the regular way ja main.cold.1 -# jump table dispatch, jumping to label indexed by val in %ecx +## jump table dispatch, jumping to label indexed by val in %ecx LBB1: movzbl %cl, %ecx movslq (%r8,%rcx,4), %rax @@ -48,15 +48,15 @@ LBB3: .type main.cold.1, %function .p2align 2 main.cold.1: - # load bearing nop: pad LBB4 so that it can't be treated - # as __builtin_unreachable by analyzeJumpTable + ## load bearing nop: pad LBB4 so that it can't be treated + ## as __builtin_unreachable by analyzeJumpTable nop LBB4: callq abort .size main.cold.1, .-main.cold.1 .rodata -# jmp table, entries must be R_X86_64_PC32 relocs +## jmp table, entries must be R_X86_64_PC32 relocs .globl JUMP_TABLE JUMP_TABLE: .long LBB2-JUMP_TABLE diff --git a/bolt/test/X86/split-landing-pad.s b/bolt/test/X86/split-landing-pad.s index dda27891443f2f9e092a0da0066ff774179fa4ad..681f14f1e533ec2baafb97d74c17e0fce511eb54 100644 --- a/bolt/test/X86/split-landing-pad.s +++ b/bolt/test/X86/split-landing-pad.s @@ -1,25 +1,25 @@ -# This test reproduces the case where C++ exception handling is used and split -# function optimization is enabled. In particular, function foo is splitted -# to two fragments: -# foo: contains 2 try blocks, which invokes bar to throw exception -# foo.cold.1: contains 2 corresponding catch blocks (landing pad) -# -# Similar to split jump table, split landing pad target to different fragment. -# This test is written to ensure BOLT safely handle these targets, e.g., by -# marking them as non-simple. -# -# Steps to write this test: -# - Create a copy of Inputs/src/unreachable.cpp -# - Simplify bar(), focus on throw an exception -# - Create the second switch case in foo() to have multiple landing pads -# - Compile with clang++ to .s -# - Move landing pad code from foo to foo.cold.1 -# - Ensure that all landing pads can be reached normally -# -# Additional details: -# .gcc_except_table specify the landing pads for try blocks -# LPStart = 255 (omit), which means LPStart = foo start -# Landing pads .Ltmp2 and .Ltmp5 in call site record are offset to foo start. +## This test reproduces the case where C++ exception handling is used and split +## function optimization is enabled. In particular, function foo is splitted +## to two fragments: +## foo: contains 2 try blocks, which invokes bar to throw exception +## foo.cold.1: contains 2 corresponding catch blocks (landing pad) +## +## Similar to split jump table, split landing pad target to different fragment. +## This test is written to ensure BOLT safely handle these targets, e.g., by +## marking them as non-simple. +## +## Steps to write this test: +## - Create a copy of Inputs/src/unreachable.cpp +## - Simplify bar(), focus on throw an exception +## - Create the second switch case in foo() to have multiple landing pads +## - Compile with clang++ to .s +## - Move landing pad code from foo to foo.cold.1 +## - Ensure that all landing pads can be reached normally +## +## Additional details: +## .gcc_except_table specify the landing pads for try blocks +## LPStart = 255 (omit), which means LPStart = foo start +## Landing pads .Ltmp2 and .Ltmp5 in call site record are offset to foo start. # REQUIRES: system-linux diff --git a/bolt/test/X86/split-random.s b/bolt/test/X86/split-random.s index de9a4f108065653be1ba25e46f393d651ab524b9..5bed619e82a9659329e1eb371f8a5a35ff573be1 100644 --- a/bolt/test/X86/split-random.s +++ b/bolt/test/X86/split-random.s @@ -1,4 +1,4 @@ -# Test random function splitting option +## Test random function splitting option # RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q diff --git a/bolt/test/X86/static-exe.test b/bolt/test/X86/static-exe.test index d12ac0a0f6f6ced60cf1453c9debc2c7fd84e0c2..e288160da1521b5f3fe1eec95d96c625db3274cd 100644 --- a/bolt/test/X86/static-exe.test +++ b/bolt/test/X86/static-exe.test @@ -1,4 +1,4 @@ -# Check that llvm-bolt can rewrite static executable +## Check that llvm-bolt can rewrite static executable RUN: %clang %cflags %S/Inputs/static_exe.s -static -o %t.exe -nostdlib RUN: llvm-bolt %t.exe -o %t 2>&1 | FileCheck %s diff --git a/bolt/test/X86/symtab-secondary-entries.test b/bolt/test/X86/symtab-secondary-entries.test index 6e05129340a0f86f3518808d57178aea1f464780..5291f64b1c4614f9eaba891e7a99dccf107ed521 100644 --- a/bolt/test/X86/symtab-secondary-entries.test +++ b/bolt/test/X86/symtab-secondary-entries.test @@ -1,4 +1,4 @@ -# Check that secondary entry points are updated correctly in the ELF symtab +## Check that secondary entry points are updated correctly in the ELF symtab RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ RUN: %p/Inputs/user-order.S -o %t.o @@ -13,7 +13,7 @@ CHECK: [[#]] FUNC GLOBAL DEFAULT [[#NDX]] main CHECK: [[#]] FUNC LOCAL DEFAULT [[#NDX]] _a CHECK: [[#]] FUNC GLOBAL DEFAULT [[#NDX]] _b CHECK: [[#]] FUNC GLOBAL DEFAULT [[#NDX]] _f -# The following are all secondary entries of _f +## The following are all secondary entries of _f CHECK: 0 FUNC GLOBAL DEFAULT [[#NDX]] _c CHECK: 0 FUNC GLOBAL DEFAULT [[#NDX]] _d CHECK: 0 FUNC GLOBAL DEFAULT [[#NDX]] _e diff --git a/bolt/test/X86/tail-duplication-cache.s b/bolt/test/X86/tail-duplication-cache.s index c3890c0337dd70f858a0d2360f16546b485c49a9..8021cfacd543335532ec85cff89e0eb27328c073 100644 --- a/bolt/test/X86/tail-duplication-cache.s +++ b/bolt/test/X86/tail-duplication-cache.s @@ -11,7 +11,7 @@ # RUN: --print-finalized --tail-duplication=cache -o %t.out2 \ # RUN: | FileCheck --check-prefix="CHECK2" %s -# A test where the tail is duplicated to eliminate an unconditional jump +## A test where the tail is duplicated to eliminate an unconditional jump # FDATA: 1 main #.BB0_br# 1 main #.BB4# 0 100 # FDATA: 1 main #.BB0_br# 1 main #.BB1# 0 100 # FDATA: 1 main #.BB1_br# 1 main #.BB3# 0 50 @@ -20,7 +20,7 @@ # CHECK: BOLT-INFO: tail duplication modified 1 ({{.*}}%) functions; duplicated 1 blocks (13 bytes) responsible for 50 dynamic executions ({{.*}}% of all block executions) # CHECK: BB Layout : .LBB00, .Ltmp0, .Ltmp1, .Ltmp2, .Ltmp3, .Ltmp4, .Ltmp5, .Ltail-dup0, .Ltmp6 -# A test where the tail is not duplicated due to the cache score +## A test where the tail is not duplicated due to the cache score # FDATA2: 1 main #.BB0_br# 1 main #.BB4# 0 100 # FDATA2: 1 main #.BB0_br# 1 main #.BB1# 0 2 # FDATA2: 1 main #.BB1_br# 1 main #.BB3# 0 1 diff --git a/bolt/test/X86/tail-duplication-cacheline.s b/bolt/test/X86/tail-duplication-cacheline.s index acc49dc3483406b41afa8d49f002be5251f27cf9..de77dbcdae07d04ca2b4f7506e2f7bce05ae488b 100644 --- a/bolt/test/X86/tail-duplication-cacheline.s +++ b/bolt/test/X86/tail-duplication-cacheline.s @@ -1,5 +1,5 @@ -# This reproduces a bug in TailDuplication::isInCacheLine -# with accessing BlockLayout past bounds (unreachable blocks). +## This reproduces a bug in TailDuplication::isInCacheLine +## with accessing BlockLayout past bounds (unreachable blocks). # REQUIRES: system-linux diff --git a/bolt/test/X86/tail-duplication-complex.s b/bolt/test/X86/tail-duplication-complex.s index ced59aea7a4c4a82e998e3d9da0500ffceec2d9a..71407da548b7a6a3bab6275e390b0a437f5465d7 100644 --- a/bolt/test/X86/tail-duplication-complex.s +++ b/bolt/test/X86/tail-duplication-complex.s @@ -17,12 +17,12 @@ # CHECK: tail duplication modified 1 ({{.*}}%) functions; duplicated 1 blocks ({{.*}} bytes) responsible for {{.*}} dynamic executions ({{.*}} of all block executions) # CHECK: BB Layout : .LBB00, .Ltmp0, .Ltail-dup0, .Ltmp1, .Ltmp2 -# This is the C++ code fed to Clang -# int fib(int term) { -# if (term <= 1) -# return term; -# return fib(term-1) + fib(term-2); -# } +## This is the C++ code fed to Clang +## int fib(int term) { +## if (term <= 1) +## return term; +## return fib(term-1) + fib(term-2); +## } .text .globl main diff --git a/bolt/test/X86/tail-duplication-jt.s b/bolt/test/X86/tail-duplication-jt.s index 03211b399ba676a7a5ea438135fb5c6aae941c52..c050aa8ddb85ef8ce6e17e88d6de282c5e68e359 100644 --- a/bolt/test/X86/tail-duplication-jt.s +++ b/bolt/test/X86/tail-duplication-jt.s @@ -1,5 +1,5 @@ -# This reproduces a bug in tail duplication when aggressiveCodeToDuplicate -# fails to handle a block with a jump table. +## This reproduces a bug in tail duplication when aggressiveCodeToDuplicate +## fails to handle a block with a jump table. # REQUIRES: system-linux diff --git a/bolt/test/X86/tail-duplication-pass.s b/bolt/test/X86/tail-duplication-pass.s index ed50cc5227d8557dc39a71db4a5b481c71f9971a..9867f74fa3444f1f5316f485e940f3d4a171738d 100644 --- a/bolt/test/X86/tail-duplication-pass.s +++ b/bolt/test/X86/tail-duplication-pass.s @@ -16,7 +16,7 @@ # CHECK: BOLT-INFO: tail duplication modified 1 ({{.*}}%) functions; duplicated 1 blocks (1 bytes) responsible for {{.*}} dynamic executions ({{.*}}% of all block executions) # CHECK: BB Layout : .LBB00, .Ltail-dup0, .Ltmp0, .Ltmp1 -# Check that the successor of Ltail-dup0 is .LBB00, not itself. +## Check that the successor of Ltail-dup0 is .LBB00, not itself. # CHECK-NOLOOP: .Ltail-dup0 (1 instructions, align : 1) # CHECK-NOLOOP: Predecessors: .LBB00 # CHECK-NOLOOP: retq diff --git a/bolt/test/X86/tail-duplication-prop-bug.s b/bolt/test/X86/tail-duplication-prop-bug.s index 5e9efc87fa2f25efb69e49f27eb06ced7fffd2ea..431851d12190ff96244af15c1e754ef501d4c7ce 100644 --- a/bolt/test/X86/tail-duplication-prop-bug.s +++ b/bolt/test/X86/tail-duplication-prop-bug.s @@ -1,4 +1,4 @@ -# This reproduces a bug in aggressive tail duplication/copy propagation. +## This reproduces a bug in aggressive tail duplication/copy propagation. # REQUIRES: system-linux # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o diff --git a/bolt/test/X86/tailcall-traps.test b/bolt/test/X86/tailcall-traps.test index 7ce6d61a738b501756497b6d43d74e3545d42345..ab4fcf10f7a3c8002ebf78e55f829b47bf83f86f 100644 --- a/bolt/test/X86/tailcall-traps.test +++ b/bolt/test/X86/tailcall-traps.test @@ -1,4 +1,4 @@ -# Tests the peephole that adds trap instructions following indirect tail calls. +## Tests the peephole that adds trap instructions following indirect tail calls. RUN: %clang %cflags %p/Inputs/tailcall_traps.s -o %t.exe RUN: llvm-bolt %t.exe -o %t --peepholes=tailcall-traps \ diff --git a/bolt/test/X86/tailcall.test b/bolt/test/X86/tailcall.test index 83b69bd25ab922af7b3e14151a9271ace7483492..f00b04d255c084be04305a8be99f533156b886e1 100644 --- a/bolt/test/X86/tailcall.test +++ b/bolt/test/X86/tailcall.test @@ -1,5 +1,5 @@ -# Verifies that llvm-bolt recognizes tailcalls and mark them -# in control flow graph. +## Verifies that llvm-bolt recognizes tailcalls and mark them +## in control flow graph. RUN: %clang %cflags %S/Inputs/tailcall.s -o %t.exe RUN: llvm-bolt %t.exe -o %t.null --print-cfg 2>&1 | FileCheck %s diff --git a/bolt/test/X86/unclaimed-jt-entries.s b/bolt/test/X86/unclaimed-jt-entries.s index 454de7e1b30b7db962334fd0ff33560b887307fa..2d56167286c36bbdd19e9a22909385c123b8d84b 100644 --- a/bolt/test/X86/unclaimed-jt-entries.s +++ b/bolt/test/X86/unclaimed-jt-entries.s @@ -1,5 +1,5 @@ -# This test ensures that "unclaimed" jump table entries are accounted later -# in postProcessIndirectBranches and the function is marked as non-simple. +## This test ensures that "unclaimed" jump table entries are accounted later +## in postProcessIndirectBranches and the function is marked as non-simple. # The test is compiled from the following source using GCC 12.2 -O3: # https://godbolt.org/z/YcPG131s6 diff --git a/bolt/test/X86/unreachable-jmp.s b/bolt/test/X86/unreachable-jmp.s index 201e999907362b2fb847ece3b69c8b3305975fd7..1a96f128e0f7c5834ca0840375226f856d14b4f4 100644 --- a/bolt/test/X86/unreachable-jmp.s +++ b/bolt/test/X86/unreachable-jmp.s @@ -1,5 +1,5 @@ -# This checks that we don't create an invalid CFG when there is an -# unreachable direct jump right after an indirect one. +## This checks that we don't create an invalid CFG when there is an +## unreachable direct jump right after an indirect one. # REQUIRES: system-linux @@ -25,8 +25,8 @@ _start: b: jmpq *JUMP_TABLE(,%rcx,8) # FDATA: 1 _start #b# 1 _start #hotpath# 0 20 -# Unreachable direct jump here. Our CFG should still make sense and properly -# place this instruction in a new basic block. +## Unreachable direct jump here. Our CFG should still make sense and properly +## place this instruction in a new basic block. jmp .lbb2 .lbb1: je .lexit .lbb2: @@ -60,7 +60,7 @@ JUMP_TABLE: .quad .lbb2 .quad hotpath -# No basic blocks above should have 4 successors! That is a bug. +## No basic blocks above should have 4 successors! That is a bug. # CHECK-NOT: Successors: {{.*}} (mispreds: 0, count: 20), {{.*}} (mispreds: 0, count: 0), {{.*}} (mispreds: 0, count: 0), {{.*}} (mispreds: 0, count: 0) # Check successful removal of stray direct jmp # CHECK: UCE removed 1 block diff --git a/bolt/test/X86/unreachable.test b/bolt/test/X86/unreachable.test index 63b70813c8851d1758a77168f35c64cbab453b69..3939b5cd338c6db6fa7f1e98f3fc61fdb18d231c 100644 --- a/bolt/test/X86/unreachable.test +++ b/bolt/test/X86/unreachable.test @@ -1,4 +1,4 @@ -# Check unreachable code elimination +## Check unreachable code elimination RUN: %clang %cflags %p/../Inputs/stub.c -fPIC -pie -shared -o %t.so RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ diff --git a/bolt/test/X86/vararg.test b/bolt/test/X86/vararg.test index 5df4f3da04214698b8382ec71d2f9059773a12b8..0b8668a842ed4d55d0d693b09f51c2e5cbf85ef5 100644 --- a/bolt/test/X86/vararg.test +++ b/bolt/test/X86/vararg.test @@ -1,6 +1,6 @@ -# Check that a function that references a label inside itself, -# as in the case of vararg handling code generated by GCC 4.5 -# and earlier, is recognized as multi-entry. +## Check that a function that references a label inside itself, +## as in the case of vararg handling code generated by GCC 4.5 +## and earlier, is recognized as multi-entry. REQUIRES: x86_64-linux diff --git a/bolt/test/X86/yaml-multiple-profiles.test b/bolt/test/X86/yaml-multiple-profiles.test index 5684da4226be62f8318c03b04c7621774200daea..6d0a26823fe529443fd60d1eeba89360a521a539 100644 --- a/bolt/test/X86/yaml-multiple-profiles.test +++ b/bolt/test/X86/yaml-multiple-profiles.test @@ -1,5 +1,5 @@ -# This test ensures that a YAML profile with multiple profiles matching the same -# function is handled gracefully. +## This test ensures that a YAML profile with multiple profiles matching the same +## function is handled gracefully. # REQUIRES: system-linux # RUN: split-file %s %t diff --git a/bolt/test/X86/zero-sized-object.s b/bolt/test/X86/zero-sized-object.s index 1f3522bce213c44af4bc9dd51ca01fe030e0c792..fa381dbeb7b0f181458c37d43d9ca9c7ba2f8dfc 100644 --- a/bolt/test/X86/zero-sized-object.s +++ b/bolt/test/X86/zero-sized-object.s @@ -1,5 +1,5 @@ -# Check that references to local (unnamed) objects below are not -# treated as references relative to zero-sized A object. +## Check that references to local (unnamed) objects below are not +## treated as references relative to zero-sized A object. # REQUIRES: system-linux diff --git a/bolt/test/bad-exe.test b/bolt/test/bad-exe.test index fadc5590ea86f3cf0b77b982640f658553141aea..2f69fdbcfe39d8342f3796287649d5ddd46ca699 100644 --- a/bolt/test/bad-exe.test +++ b/bolt/test/bad-exe.test @@ -1,8 +1,8 @@ -# Check that llvm-bolt rejects input that is not a valid ELF executable -# bzip2.debuginfo is the result of running "objcopy --only-keep-debug". +## Check that llvm-bolt rejects input that is not a valid ELF executable +## bzip2.debuginfo is the result of running "objcopy --only-keep-debug". -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags %S/Inputs/icf-jump-tables.c -g -o %t diff --git a/bolt/test/bolt-icf.test b/bolt/test/bolt-icf.test index f7b056e2ddb0e4244ec18862afae193faf955db6..cd80d96744ddccc4435dbb8a5cb536e2373cd223 100644 --- a/bolt/test/bolt-icf.test +++ b/bolt/test/bolt-icf.test @@ -1,4 +1,4 @@ -# Check for the replacement of calls to identical functions. +## Check for the replacement of calls to identical functions. REQUIRES: system-linux diff --git a/bolt/test/bolt-info.test b/bolt/test/bolt-info.test index c329c553813d25556ee0a90e6b0b562c51e5f501..fff67abbcea0269c4ab7bd3114f7f4af56eccf03 100644 --- a/bolt/test/bolt-info.test +++ b/bolt/test/bolt-info.test @@ -1,7 +1,7 @@ -# Check that the .bolt_info section is generated properly. +## Check that the .bolt_info section is generated properly. -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags %S/Inputs/icf-jump-tables.c -o %t diff --git a/bolt/test/heatmap.test b/bolt/test/heatmap.test index eb63ab37b4132d257050283483601067d26ca53b..fa69691a590dc779add6ce1416e2f5b9475b2d71 100644 --- a/bolt/test/heatmap.test +++ b/bolt/test/heatmap.test @@ -1,4 +1,4 @@ -# Verifies basic functioning of heatmap mode +## Verifies basic functioning of heatmap mode REQUIRES: system-linux diff --git a/bolt/test/invalid-profile.test b/bolt/test/invalid-profile.test index 1725a08577e347552f9b02f68eaa66e34b5c12ea..df94ff08c8dac11b34e219b89ae440d73168d3d0 100644 --- a/bolt/test/invalid-profile.test +++ b/bolt/test/invalid-profile.test @@ -1,7 +1,7 @@ -# Check that llvm-bolt detects bad profile data and aborts +## Check that llvm-bolt detects bad profile data and aborts -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %S/Inputs/icf-jump-tables.c -o %t diff --git a/bolt/test/keep-aranges.test b/bolt/test/keep-aranges.test index 5a9d932bc1af275a5f739e5d8cb575316577108b..e5c9faa97bb4919ed6bd14332f27c6ec3b9127d8 100644 --- a/bolt/test/keep-aranges.test +++ b/bolt/test/keep-aranges.test @@ -1,5 +1,5 @@ -# Check that BOLT generates .debug_aranges section for an input -# where it was removed when .gdb_index was generated. +## Check that BOLT generates .debug_aranges section for an input +## where it was removed when .gdb_index was generated. REQUIRES: system-linux diff --git a/bolt/test/link_fdata.py b/bolt/test/link_fdata.py index 0232dd3211e9bbcccecd5c37cf2269fa0373dcc2..3837e394ccc87bb6b0c79d9613f0cec8bf8aff9c 100755 --- a/bolt/test/link_fdata.py +++ b/bolt/test/link_fdata.py @@ -19,6 +19,7 @@ parser.add_argument("output") parser.add_argument("prefix", nargs="?", default="FDATA", help="Custom FDATA prefix") parser.add_argument("--nmtool", default="nm", help="Path to nm tool") parser.add_argument("--no-lbr", action="store_true") +parser.add_argument("--no-redefine", action="store_true") args = parser.parse_args() @@ -90,6 +91,8 @@ nm_output = subprocess.run( symbols = {} for symline in nm_output.splitlines(): symval, _, symname = symline.split(maxsplit=2) + if symname in symbols and args.no_redefine: + continue symbols[symname] = symval diff --git a/bolt/test/lit.local.cfg b/bolt/test/lit.local.cfg index 4f4d84e49b1332a357ea7bcc65c7f18a31cb5991..8aa5f15d5ccfb43d0a1506928e0bcebc5cc17d60 100644 --- a/bolt/test/lit.local.cfg +++ b/bolt/test/lit.local.cfg @@ -1,4 +1,4 @@ -host_linux_triple = config.target_triple.split("-")[0] + "-linux" +host_linux_triple = config.target_triple.split("-")[0] + "-unknown-linux-gnu" common_linker_flags = "-fuse-ld=lld -Wl,--unresolved-symbols=ignore-all" flags = f"--target={host_linux_triple} {common_linker_flags}" diff --git a/bolt/test/lsda-section-name.cpp b/bolt/test/lsda-section-name.cpp index 41fb17665821911bdf15080730f27b5333d06e0c..929b17f3b63d42d879d85bac0af234a646e547d1 100644 --- a/bolt/test/lsda-section-name.cpp +++ b/bolt/test/lsda-section-name.cpp @@ -2,10 +2,10 @@ // disassembled by BOLT. // RUN: %clang++ %cxxflags -O3 -no-pie -c %s -o %t.o -// RUN: %clang++ %cxxflags -no-pie -fuse-ld=lld %t.o -o %t.exe \ -// RUN: -Wl,-q -Wl,--script=%S/Inputs/lsda.ldscript -// RUN: llvm-readelf -SW %t.exe | FileCheck %s -// RUN: llvm-bolt %t.exe -o %t.bolt +// RUN: %clang++ %cxxflags -O3 -no-pie -fuse-ld=lld %t.o -o %t +// RUN: llvm-objcopy --rename-section .gcc_except_table=.gcc_except_table.main %t +// RUN: llvm-readelf -SW %t | FileCheck %s +// RUN: llvm-bolt %t -o %t.bolt // CHECK: .gcc_except_table.main diff --git a/bolt/test/no-relocs.test b/bolt/test/no-relocs.test index 34993eb330cbdd799a8ab2103ffdc51b65c77e08..3dd4251f7078fb0d460182d46c98679545404486 100644 --- a/bolt/test/no-relocs.test +++ b/bolt/test/no-relocs.test @@ -1,7 +1,7 @@ -# Verifies that input without relocations is rejected in relocs mode. +## Verifies that input without relocations is rejected in relocs mode. -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags %S/Inputs/icf-jump-tables.c -o %t diff --git a/bolt/test/non-empty-debug-line.test b/bolt/test/non-empty-debug-line.test index e3de8335238d97f8f3d1c78488fddd766c03e017..0650e9ec1c7ab9013dfc0eef3cfe76c9a4d172fa 100644 --- a/bolt/test/non-empty-debug-line.test +++ b/bolt/test/non-empty-debug-line.test @@ -1,5 +1,5 @@ -# Verifies that BOLT emits DWARF line table with the same size if -# no functions with debug info were modified. +## Verifies that BOLT emits DWARF line table with the same size if +## no functions with debug info were modified. REQUIRES: system-linux @@ -9,12 +9,12 @@ RUN: llvm-readobj -S %t > %t2 RUN: llvm-readobj -S %t1 >> %t2 RUN: FileCheck %s --input-file %t2 -# Check the input and grab .debug_line size. +## Check the input and grab .debug_line size. CHECK: File: CHECK: Name: .debug_line CHECK: Size: [[SIZE:[0-9]+]] -# Verify .debug_line size is the same after BOLT. +## Verify .debug_line size is the same after BOLT. CHECK: File: CHECK: Name: .debug_line CHECK: Size: diff --git a/bolt/test/pie.test b/bolt/test/pie.test index 0ce2576ee401c0b77c3a96f9283ceb394e36c4eb..7c833c09bbf09bbfb429cae95137d6a3f4ce76e3 100644 --- a/bolt/test/pie.test +++ b/bolt/test/pie.test @@ -1,7 +1,7 @@ -# Check that we do not reject position-independent executables (PIEs). +## Check that we do not reject position-independent executables (PIEs). -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags -fPIC -pie %p/Inputs/jump_table_icp.cpp -o %t diff --git a/bolt/test/re-optimize.test b/bolt/test/re-optimize.test index 2c436d708df82c1873350992c7df081475f1d8d7..41216d81aa4b0904032097359a3312961d615f81 100644 --- a/bolt/test/re-optimize.test +++ b/bolt/test/re-optimize.test @@ -1,7 +1,7 @@ -# Check that we detect re-optimization attempt. +## Check that we detect re-optimization attempt. -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags %S/Inputs/icf-jump-tables.c -o %t.exe diff --git a/bolt/test/runtime/X86/asm-dump.c b/bolt/test/runtime/X86/asm-dump.c index e5383b52351594466d953adfccbbf19bf239e758..7656fda44d8d4a7ee01482b37b2f91705241651e 100644 --- a/bolt/test/runtime/X86/asm-dump.c +++ b/bolt/test/runtime/X86/asm-dump.c @@ -1,5 +1,5 @@ /** - * Test for asm-dump functionality. + ** Test for asm-dump functionality. * * REQUIRES: x86_64-linux,bolt-runtime * diff --git a/bolt/test/shared-object.test b/bolt/test/shared-object.test index 361f4ea94f2a515ee8c5dccfac8d2ebb075b71b9..06afff976e4a82b2f2bb5e62a1bc7cdf5541eac1 100644 --- a/bolt/test/shared-object.test +++ b/bolt/test/shared-object.test @@ -1,7 +1,7 @@ -# Test that llvm-bolt processes *.so without a failure +## Test that llvm-bolt processes *.so without a failure -# This test uses the clang driver without target flags and will only succeed -# on Linux systems where the host triple matches the target. +## This test uses the clang driver without target flags and will only succeed +## on Linux systems where the host triple matches the target. REQUIRES: system-linux RUN: %clang %cflags %S/Inputs/icf-jump-tables.c -o %t.so -shared -fPIC -Wl,--build-id diff --git a/bolt/unittests/CMakeLists.txt b/bolt/unittests/CMakeLists.txt index 77159e92dec5576c11bf55dee172f3ddee069735..64414b83d39fe8ac6a6dc4b9be7f4a8fbdd79adf 100644 --- a/bolt/unittests/CMakeLists.txt +++ b/bolt/unittests/CMakeLists.txt @@ -1,5 +1,5 @@ add_custom_target(BoltUnitTests) -set_target_properties(BoltUnitTests PROPERTIES FOLDER "BOLT tests") +set_target_properties(BoltUnitTests PROPERTIES FOLDER "BOLT/Tests") function(add_bolt_unittest test_dirname) add_unittest(BoltUnitTests ${test_dirname} ${ARGN}) diff --git a/clang-tools-extra/CMakeLists.txt b/clang-tools-extra/CMakeLists.txt index 6a3f741721ee6c748b3a47ef930b11fcb1d0c390..f6a6b57b5ef0bc76cee6258f05d5d6e50d89df42 100644 --- a/clang-tools-extra/CMakeLists.txt +++ b/clang-tools-extra/CMakeLists.txt @@ -1,3 +1,5 @@ +set(LLVM_SUBPROJECT_TITLE "Clang Tools Extra") + include(CMakeDependentOption) include(GNUInstallDirs) diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt b/clang-tools-extra/clang-tidy/CMakeLists.txt index 7e1905aa897b7e7a7362f9d023ec178e4d730f4f..430ea4cdbb38e198ff6a0aa4c3170d2d4ae19920 100644 --- a/clang-tools-extra/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/CMakeLists.txt @@ -121,7 +121,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) PATTERN "*.h" ) add_custom_target(clang-tidy-headers) - set_target_properties(clang-tidy-headers PROPERTIES FOLDER "Misc") + set_target_properties(clang-tidy-headers PROPERTIES FOLDER "Clang Tools Extra/Resources") if(NOT LLVM_ENABLE_IDE) add_llvm_install_targets(install-clang-tidy-headers DEPENDS clang-tidy-headers diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp index 36687a8e761e85fce8b52494d2c68fb20051c2e5..c87b3ea7e261632d8f5b954ffff9c88ef445cc2c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp @@ -54,7 +54,9 @@ AST_MATCHER(QualType, isEnableIf) { AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument, clang::ast_matchers::internal::Matcher, TypeMatcher) { return Node.hasDefaultArgument() && - TypeMatcher.matches(Node.getDefaultArgument(), Finder, Builder); + TypeMatcher.matches( + Node.getDefaultArgument().getArgument().getAsType(), Finder, + Builder); } AST_MATCHER(TemplateDecl, hasAssociatedConstraints) { return Node.hasAssociatedConstraints(); diff --git a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp index 09aaf3e31d5dd7f4bd57c4465316a1994dae904c..75f1107904fcec9b455588fb0e1e53d66a4f3b95 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp @@ -19,10 +19,11 @@ namespace { AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument, ast_matchers::internal::Matcher, InnerMatcher) { if (Node.getIdentifier() != nullptr || !Node.hasDefaultArgument() || - Node.getDefaultArgumentInfo() == nullptr) + Node.getDefaultArgument().getArgument().isNull()) return false; - TypeLoc DefaultArgTypeLoc = Node.getDefaultArgumentInfo()->getTypeLoc(); + TypeLoc DefaultArgTypeLoc = + Node.getDefaultArgument().getTypeSourceInfo()->getTypeLoc(); return InnerMatcher.matches(DefaultArgTypeLoc, Finder, Builder); } diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp index a1cffbc6661992154c8a09b5f196198f174b730f..5e64d23874ec17728f5401bbb4b7642099940efd 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp @@ -144,16 +144,13 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) { unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName("*"))), binaryOperator(hasEitherOperand(ArrayExpr)), castExpr(hasSourceExpression(ArrayExpr)))); - const auto PointerToArrayExpr = ignoringParenImpCasts( - hasType(hasCanonicalType(pointerType(pointee(arrayType()))))); + const auto PointerToArrayExpr = + hasType(hasCanonicalType(pointerType(pointee(arrayType())))); - const auto StructAddrOfExpr = unaryOperator( - hasOperatorName("&"), hasUnaryOperand(ignoringParenImpCasts( - hasType(hasCanonicalType(recordType()))))); const auto PointerToStructType = hasUnqualifiedDesugaredType(pointerType(pointee(recordType()))); - const auto PointerToStructExpr = ignoringParenImpCasts(expr( - hasType(hasCanonicalType(PointerToStructType)), unless(cxxThisExpr()))); + const auto PointerToStructExpr = expr( + hasType(hasCanonicalType(PointerToStructType)), unless(cxxThisExpr())); const auto ArrayOfPointersExpr = ignoringParenImpCasts( hasType(hasCanonicalType(arrayType(hasElementType(pointerType())) @@ -166,18 +163,19 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) { ignoringParenImpCasts(arraySubscriptExpr( hasBase(ArrayOfSamePointersExpr), hasIndex(ZeroLiteral))); const auto ArrayLengthExprDenom = - expr(hasParent(expr(ignoringParenImpCasts(binaryOperator( - hasOperatorName("/"), hasLHS(ignoringParenImpCasts(sizeOfExpr( - has(ArrayOfPointersExpr)))))))), + expr(hasParent(binaryOperator(hasOperatorName("/"), + hasLHS(ignoringParenImpCasts(sizeOfExpr( + has(ArrayOfPointersExpr)))))), sizeOfExpr(has(ArrayOfSamePointersZeroSubscriptExpr))); - Finder->addMatcher(expr(anyOf(sizeOfExpr(has(ignoringParenImpCasts(anyOf( - ArrayCastExpr, PointerToArrayExpr, - StructAddrOfExpr, PointerToStructExpr)))), - sizeOfExpr(has(PointerToStructType))), - unless(ArrayLengthExprDenom)) - .bind("sizeof-pointer-to-aggregate"), - this); + Finder->addMatcher( + expr(sizeOfExpr(anyOf( + has(ignoringParenImpCasts(anyOf( + ArrayCastExpr, PointerToArrayExpr, PointerToStructExpr))), + has(PointerToStructType))), + unless(ArrayLengthExprDenom)) + .bind("sizeof-pointer-to-aggregate"), + this); } // Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'. diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index d9ec268650c05321eb60ddf535130cb48c656cc8..35e29b9a7d13670f2feb130aef1ef5cdef8d1119 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -15,6 +15,7 @@ add_custom_command( DEPENDS ${clang_tidy_confusable_chars_gen_target} ConfusableTable/confusables.txt) add_custom_target(genconfusable DEPENDS Confusables.inc) +set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourcegenning") add_clang_library(clangTidyMiscModule ConstCorrectnessCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index 7a021fe14436a102037f442433db810ff0ef3366..ea4d99586c71102117a15e53736800e94e1ecb4f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -177,9 +177,11 @@ matchTrailingTemplateParam(const FunctionTemplateDecl *FunctionTemplate) { dyn_cast(LastParam)) { if (LastTemplateParam->hasDefaultArgument() && LastTemplateParam->getIdentifier() == nullptr) { - return {matchEnableIfSpecialization( - LastTemplateParam->getDefaultArgumentInfo()->getTypeLoc()), - LastTemplateParam}; + return { + matchEnableIfSpecialization(LastTemplateParam->getDefaultArgument() + .getTypeSourceInfo() + ->getTypeLoc()), + LastTemplateParam}; } } return {}; diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp index 6cef21f1318a2a96fa11a2b5d366dc74b723e824..d082faa786b37527e1ce4c06276834dd98c5e171 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp @@ -47,13 +47,15 @@ void UseStdFormatCheck::registerPPCallbacks(const SourceManager &SM, } void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) { + auto CharPointerType = + hasType(pointerType(pointee(matchers::isSimpleChar()))); Finder->addMatcher( - callExpr(argumentCountAtLeast(1), - hasArgument(0, stringLiteral(isOrdinary())), - callee(functionDecl(unless(cxxMethodDecl()), - matchers::matchesAnyListedName( - StrFormatLikeFunctions)) - .bind("func_decl"))) + callExpr( + argumentCountAtLeast(1), hasArgument(0, stringLiteral(isOrdinary())), + callee(functionDecl( + unless(cxxMethodDecl()), hasParameter(0, CharPointerType), + matchers::matchesAnyListedName(StrFormatLikeFunctions)) + .bind("func_decl"))) .bind("strformat"), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp index ff990feadc0c1d944f786b15eecd3f9d35a9a5be..1ea170c3cd31061bdfe183f4bc755ac11dc7c18a 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp @@ -95,12 +95,15 @@ unusedReturnValue(clang::ast_matchers::StatementMatcher MatchedCallExpr) { } void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) { + auto CharPointerType = + hasType(pointerType(pointee(matchers::isSimpleChar()))); if (!PrintfLikeFunctions.empty()) Finder->addMatcher( unusedReturnValue( callExpr(argumentCountAtLeast(1), hasArgument(0, stringLiteral(isOrdinary())), callee(functionDecl(unless(cxxMethodDecl()), + hasParameter(0, CharPointerType), matchers::matchesAnyListedName( PrintfLikeFunctions)) .bind("func_decl"))) @@ -113,6 +116,7 @@ void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) { callExpr(argumentCountAtLeast(2), hasArgument(1, stringLiteral(isOrdinary())), callee(functionDecl(unless(cxxMethodDecl()), + hasParameter(1, CharPointerType), matchers::matchesAnyListedName( FprintfLikeFunctions)) .bind("func_decl"))) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp index 19307b4cdcbe3ce3d2fe7cfcc1d64059b0ac1d45..bbc1b47b97ae6143c01cf5bd9afce7a18e3fc008 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp @@ -150,6 +150,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( cxxMemberCallExpr( + argumentCountIs(0), on(expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), hasType(references(ValidContainer)))) @@ -163,7 +164,8 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { this); Finder->addMatcher( - callExpr(has(cxxDependentScopeMemberExpr( + callExpr(argumentCountIs(0), + has(cxxDependentScopeMemberExpr( hasObjectExpression( expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index c3208392df1566f98b38933a71fe40d9cf26d976..828f13805a69802689cbe91d7af8a1c6a893ab5a 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -1414,13 +1414,21 @@ IdentifierNamingCheck::getDiagInfo(const NamingCheckId &ID, }}; } +StringRef IdentifierNamingCheck::getRealFileName(StringRef FileName) const { + auto Iter = RealFileNameCache.try_emplace(FileName); + SmallString<256U> &RealFileName = Iter.first->getValue(); + if (!Iter.second) + return RealFileName; + llvm::sys::fs::real_path(FileName, RealFileName); + return RealFileName; +} + const IdentifierNamingCheck::FileStyle & IdentifierNamingCheck::getStyleForFile(StringRef FileName) const { if (!GetConfigPerFile) return *MainFileStyle; - SmallString<128> RealFileName; - llvm::sys::fs::real_path(FileName, RealFileName); + StringRef RealFileName = getRealFileName(FileName); StringRef Parent = llvm::sys::path::parent_path(RealFileName); auto Iter = NamingStylesCache.find(Parent); if (Iter != NamingStylesCache.end()) diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h index 27c8e4bc768c40637147bff4d96ec4c1d44bf38c..646ec0eac8dd1c889dad7ad2dc932863cfbb363d 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h @@ -205,6 +205,7 @@ private: const NamingCheckFailure &Failure) const override; const FileStyle &getStyleForFile(StringRef FileName) const; + StringRef getRealFileName(StringRef FileName) const; /// Find the style kind of a field in an anonymous record. StyleKind findStyleKindForAnonField( @@ -222,6 +223,7 @@ private: /// Stores the style options as a vector, indexed by the specified \ref /// StyleKind, for a given directory. mutable llvm::StringMap NamingStylesCache; + mutable llvm::StringMap> RealFileNameCache; FileStyle *MainFileStyle; ClangTidyContext *Context; const bool GetConfigPerFile; diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index 74152c6034510b9e4b881c6c4e00ec20ca821c09..28f5eada6d825af19876a096d90f6ee95181d6aa 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -50,7 +50,9 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind, case CK_PointerToBoolean: case CK_MemberPointerToBoolean: // Fall-through on purpose. - return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0"; + return (Context.getLangOpts().CPlusPlus11 || Context.getLangOpts().C23) + ? "nullptr" + : "0"; default: llvm_unreachable("Unexpected cast kind"); @@ -165,6 +167,12 @@ bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) { void fixGenericExprCastFromBool(DiagnosticBuilder &Diag, const ImplicitCastExpr *Cast, ASTContext &Context, StringRef OtherType) { + if (!Context.getLangOpts().CPlusPlus) { + Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(), + (Twine("(") + OtherType + ")").str()); + return; + } + const Expr *SubExpr = Cast->getSubExpr(); const bool NeedParens = !isa(SubExpr->IgnoreImplicit()); const bool NeedSpace = needsSpacePrefix(Cast->getBeginLoc(), Context); @@ -267,6 +275,10 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { auto BoolXor = binaryOperator(hasOperatorName("^"), hasLHS(ImplicitCastFromBool), hasRHS(ImplicitCastFromBool)); + auto ComparisonInCall = allOf( + hasParent(callExpr()), + hasSourceExpression(binaryOperator(hasAnyOperatorName("==", "!=")))); + Finder->addMatcher( traverse(TK_AsIs, implicitCastExpr( @@ -281,6 +293,8 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))), // Exclude cases common to implicit cast to and from bool. unless(ExceptionCases), unless(has(BoolXor)), + // Exclude C23 cases common to implicit cast to bool. + unless(ComparisonInCall), // Retrieve also parent statement, to check if we need // additional parens in replacement. optionally(hasParent(stmt().bind("parentStmt"))), diff --git a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp index 015347ee9294ce50751bcaf2bccd247529904bb7..601ff44cdd10a52e94ab31830024d0e772259c62 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp @@ -41,25 +41,35 @@ void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { auto ConstructorMatcher = - cxxConstructExpr(argumentCountIs(0), - hasDeclaration(cxxConstructorDecl(ofClass(cxxRecordDecl( - unless(isTriviallyDefaultConstructible())))))) + cxxConstructExpr( + argumentCountIs(0), + hasDeclaration(cxxConstructorDecl( + ofClass(cxxRecordDecl(unless(isTriviallyDefaultConstructible())) + .bind("class"))))) .bind("construct"); + auto HasUnionAsParent = hasParent(recordDecl(isUnion())); + + auto HasTypeEqualToConstructorClass = hasType(qualType( + hasCanonicalType(qualType(hasDeclaration(equalsBoundNode("class")))))); + Finder->addMatcher( cxxConstructorDecl( unless(isDelegatingConstructor()), ofClass(unless(isUnion())), forEachConstructorInitializer( - cxxCtorInitializer(withInitializer(ConstructorMatcher), - unless(forField(fieldDecl( - anyOf(hasType(isConstQualified()), - hasParent(recordDecl(isUnion()))))))) + cxxCtorInitializer( + withInitializer(ConstructorMatcher), + anyOf(isBaseInitializer(), + forField(fieldDecl(unless(hasType(isConstQualified())), + unless(HasUnionAsParent), + HasTypeEqualToConstructorClass)))) .bind("init"))) .bind("constructor"), this); Finder->addMatcher(fieldDecl(hasInClassInitializer(ConstructorMatcher), - unless(hasParent(recordDecl(isUnion())))) + HasTypeEqualToConstructorClass, + unless(HasUnionAsParent)) .bind("field"), this); } diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index 845e71c5003b80bbdb2cfc8ecb8bb9751f04dd2f..33f3ea47df1e3888deef2dc2b86e5f3d3082fc30 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -208,9 +208,11 @@ FormatStringConverter::FormatStringConverter(ASTContext *ContextIn, assert(ArgsOffset <= NumArgs); FormatExpr = llvm::dyn_cast( Args[FormatArgOffset]->IgnoreImplicitAsWritten()); - assert(FormatExpr); - if (!FormatExpr->isOrdinary()) - return; // No wide string support yet + if (!FormatExpr || !FormatExpr->isOrdinary()) { + // Function must have a narrow string literal as its first argument. + conversionNotPossible("first argument is not a narrow string literal"); + return; + } PrintfFormatString = FormatExpr->getString(); // Assume that the output will be approximately the same size as the input, diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h index 045e3ffbb6a8b45e0b24f877501fbc2d05493465..5fd98db9678708b479f70bdb1756529231c906d8 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -49,6 +49,14 @@ AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) { return pointerType(pointee(qualType(isConstQualified()))); } +// Returns QualType matcher for target char type only. +AST_MATCHER(QualType, isSimpleChar) { + const auto ActualType = Node.getTypePtr(); + return ActualType && + (ActualType->isSpecificBuiltinType(BuiltinType::Char_S) || + ActualType->isSpecificBuiltinType(BuiltinType::Char_U)); +} + AST_MATCHER(Expr, hasUnevaluatedContext) { if (isa(Node) || isa(Node)) return true; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index e811f5519de2c136c2789aeb26fb569f2095832c..88e4886cd0df938923ce0e871fb7bb3827471744 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -123,6 +123,9 @@ static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) { if (const auto *Method = dyn_cast(ND)) { if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) Canonical = cast(Overridden->getCanonicalDecl()); + else if (const FunctionTemplateDecl *Primary = Method->getPrimaryTemplate()) + if (const FunctionDecl *TemplatedDecl = Primary->getTemplatedDecl()) + Canonical = cast(TemplatedDecl->getCanonicalDecl()); if (Canonical != ND) return Canonical; diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c5877fc7a29777604e21413fb86dce0..41143b9ebc8d273f0bb287061655d3fc84615d23 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -110,10 +110,11 @@ struct Config { IncludesPolicy UnusedIncludes = IncludesPolicy::Strict; IncludesPolicy MissingIncludes = IncludesPolicy::None; - /// IncludeCleaner will not diagnose usages of these headers matched by - /// these regexes. struct { + /// IncludeCleaner will not diagnose usages of these headers matched by + /// these regexes. std::vector> IgnoreHeader; + bool AnalyzeAngledIncludes = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803fb805244f87c139ac4cb4cdb2c5..f32f674443ffeb79e98304cdb46009c26a44a52b 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,46 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif - auto Filters = std::make_shared>(); - for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { - diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); - continue; + std::shared_ptr> Filters; + if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { + // Anchor on the right. + std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; + llvm::Regex CompiledRegex(AnchoredPattern, Flags); + std::string RegexError; + if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; + } + Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } - if (Filters->empty()) + // Optional to override the resulting AnalyzeAngledIncludes + // only if it's explicitly set in the current fragment. + // Otherwise it's inherited from parent fragment. + std::optional AnalyzeAngledIncludes; + if (F.AnalyzeAngledIncludes.has_value()) + AnalyzeAngledIncludes = **F.AnalyzeAngledIncludes; + if (!Filters && !AnalyzeAngledIncludes.has_value()) return; - auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) - if (Regex.match(Path)) - return true; - return false; - }; - Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); + Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeAngledIncludes](const Params &, Config &C) { + if (Filters) { + auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) + if (Regex.match(Path)) + return true; + return false; + }; + C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter)); + } + if (AnalyzeAngledIncludes.has_value()) + C.Diagnostics.Includes.AnalyzeAngledIncludes = *AnalyzeAngledIncludes; }); } diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 7fa61108c78a05d10bb00f8a2b33375cf4cf5376..f3e51a9b6dbc4ba078fd6fbe944f016e738454ce 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -254,6 +254,10 @@ struct Fragment { /// unused or missing. These can match any suffix of the header file in /// question. std::vector> IgnoreHeader; + + /// If false (default), unused system headers will be ignored. + /// Standard library headers are analyzed regardless of this option. + std::optional> AnalyzeAngledIncludes; }; IncludesBlock Includes; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index ce09af819247aecea89cb14a6ab67bf0f4d45c3a..3e9b6a07d3b325fb8ca19199c8f3556f273f596b 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -169,6 +169,10 @@ private: if (auto Values = scalarValues(N)) F.IgnoreHeader = std::move(*Values); }); + Dict.handle("AnalyzeAngledIncludes", [&](Node &N) { + if (auto Value = boolValue(N, "AnalyzeAngledIncludes")) + F.AnalyzeAngledIncludes = *Value; + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 06b949bc4a2b552907c5dbe95d0fd7c768096346..de103e011c70852641e1552741067af647150015 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -247,8 +247,12 @@ fetchTemplateParameters(const TemplateParameterList *Params, if (!TTP->getName().empty()) P.Name = TTP->getNameAsString(); - if (TTP->hasDefaultArgument()) - P.Default = TTP->getDefaultArgument().getAsString(PP); + if (TTP->hasDefaultArgument()) { + P.Default.emplace(); + llvm::raw_string_ostream Out(*P.Default); + TTP->getDefaultArgument().getArgument().print(PP, Out, + /*IncludeType=*/false); + } } else if (const auto *NTTP = dyn_cast(Param)) { P.Type = printType(NTTP, PP); @@ -258,7 +262,8 @@ fetchTemplateParameters(const TemplateParameterList *Params, if (NTTP->hasDefaultArgument()) { P.Default.emplace(); llvm::raw_string_ostream Out(*P.Default); - NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP); + NTTP->getDefaultArgument().getArgument().print(PP, Out, + /*IncludeType=*/false); } } else if (const auto *TTPD = dyn_cast(Param)) { P.Type = printType(TTPD, PP); diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp index 8e48f546d94e7799ca727a5e3de0895c90fd69cd..01b47679790f1d52633b8bb8b49aeca13147a060 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -68,24 +68,30 @@ bool isIgnored(llvm::StringRef HeaderPath, HeaderFilter IgnoreHeaders) { } bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST, - const include_cleaner::PragmaIncludes *PI) { + const include_cleaner::PragmaIncludes *PI, + bool AnalyzeAngledIncludes) { assert(Inc.HeaderID); auto HID = static_cast(*Inc.HeaderID); auto FE = AST.getSourceManager().getFileManager().getFileRef( AST.getIncludeStructure().getRealPath(HID)); assert(FE); if (FE->getDir() == AST.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .getBuiltinDir()) + .getHeaderSearchInfo() + .getModuleMap() + .getBuiltinDir()) return false; if (PI && PI->shouldKeep(*FE)) return false; // FIXME(kirillbobyrev): We currently do not support the umbrella headers. // System headers are likely to be standard library headers. - // Until we have good support for umbrella headers, don't warn about them. - if (Inc.Written.front() == '<') - return tooling::stdlib::Header::named(Inc.Written).has_value(); + // Until we have good support for umbrella headers, don't warn about them + // (unless analysis is explicitly enabled). + if (Inc.Written.front() == '<') { + if (tooling::stdlib::Header::named(Inc.Written)) + return true; + if (!AnalyzeAngledIncludes) + return false; + } if (PI) { // Check if main file is the public interface for a private header. If so we // shouldn't diagnose it as unused. @@ -266,7 +272,8 @@ Fix fixAll(const Fix &RemoveAllUnused, const Fix &AddAllMissing) { std::vector getUnused(ParsedAST &AST, - const llvm::DenseSet &ReferencedFiles) { + const llvm::DenseSet &ReferencedFiles, + bool AnalyzeAngledIncludes) { trace::Span Tracer("IncludeCleaner::getUnused"); std::vector Unused; for (const Inclusion &MFI : AST.getIncludeStructure().MainFileIncludes) { @@ -275,7 +282,8 @@ getUnused(ParsedAST &AST, auto IncludeID = static_cast(*MFI.HeaderID); if (ReferencedFiles.contains(IncludeID)) continue; - if (!mayConsiderUnused(MFI, AST, &AST.getPragmaIncludes())) { + if (!mayConsiderUnused(MFI, AST, &AST.getPragmaIncludes(), + AnalyzeAngledIncludes)) { dlog("{0} was not used, but is not eligible to be diagnosed as unused", MFI.Written); continue; @@ -347,7 +355,8 @@ include_cleaner::Includes convertIncludes(const ParsedAST &AST) { return ConvertedIncludes; } -IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) { +IncludeCleanerFindings +computeIncludeCleanerFindings(ParsedAST &AST, bool AnalyzeAngledIncludes) { // Interaction is only polished for C/CPP. if (AST.getLangOpts().ObjC) return {}; @@ -432,7 +441,8 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) { MapInfo::getHashValue(RHS.Symbol); }); MissingIncludes.erase(llvm::unique(MissingIncludes), MissingIncludes.end()); - std::vector UnusedIncludes = getUnused(AST, Used); + std::vector UnusedIncludes = + getUnused(AST, Used, AnalyzeAngledIncludes); return {std::move(UnusedIncludes), std::move(MissingIncludes)}; } diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h index 624e2116be7da3015816dfec628d8de6ac7f363c..a01146d14e3c17aacfd5b8798d3a46e5c737e362 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.h +++ b/clang-tools-extra/clangd/IncludeCleaner.h @@ -53,7 +53,9 @@ struct IncludeCleanerFindings { std::vector MissingIncludes; }; -IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST); +IncludeCleanerFindings +computeIncludeCleanerFindings(ParsedAST &AST, + bool AnalyzeAngledIncludes = false); using HeaderFilter = llvm::ArrayRef>; std::vector diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 3ff759415f7c8b24fab5a3a538c13755dd14544f..2bd1fbcad2ada0f69a269805e121f51ef144ced0 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -373,7 +373,8 @@ std::vector getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code, Cfg.Diagnostics.UnusedIncludes == Config::IncludesPolicy::None; if (SuppressMissing && SuppressUnused) return {}; - auto Findings = computeIncludeCleanerFindings(AST); + auto Findings = computeIncludeCleanerFindings( + AST, Cfg.Diagnostics.Includes.AnalyzeAngledIncludes); if (SuppressMissing) Findings.MissingIncludes.clear(); if (SuppressUnused) diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index fef827a801c33974ef1118d31ccc402af0bb9c73..f43f2417df8fcef8cc686f65e09eb18a89523c6a 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -179,14 +179,11 @@ deleteTokensWithKind(const syntax::TokenBuffer &TokBuf, tok::TokenKind Kind, // looked up in the context containing the function/method. // FIXME: Drop attributes in function signature. llvm::Expected -getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, +getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext, const syntax::TokenBuffer &TokBuf, const HeuristicResolver *Resolver) { auto &AST = FD->getASTContext(); auto &SM = AST.getSourceManager(); - auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext()); - if (!TargetContext) - return error("define outline: couldn't find a context for target"); llvm::Error Errors = llvm::Error::success(); tooling::Replacements DeclarationCleanups; @@ -216,7 +213,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, } const NamedDecl *ND = Ref.Targets.front(); const std::string Qualifier = - getQualification(AST, *TargetContext, + getQualification(AST, TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), ND); if (auto Err = DeclarationCleanups.add( tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier))) @@ -232,7 +229,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, if (const auto *Destructor = llvm::dyn_cast(FD)) { if (auto Err = DeclarationCleanups.add(tooling::Replacement( SM, Destructor->getLocation(), 0, - getQualification(AST, *TargetContext, + getQualification(AST, TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), Destructor)))) Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); @@ -319,29 +316,9 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, } struct InsertionPoint { - std::string EnclosingNamespace; + const DeclContext *EnclosingNamespace = nullptr; size_t Offset; }; -// Returns the most natural insertion point for \p QualifiedName in \p Contents. -// This currently cares about only the namespace proximity, but in feature it -// should also try to follow ordering of declarations. For example, if decls -// come in order `foo, bar, baz` then this function should return some point -// between foo and baz for inserting bar. -llvm::Expected getInsertionPoint(llvm::StringRef Contents, - llvm::StringRef QualifiedName, - const LangOptions &LangOpts) { - auto Region = getEligiblePoints(Contents, QualifiedName, LangOpts); - - assert(!Region.EligiblePoints.empty()); - // FIXME: This selection can be made smarter by looking at the definition - // locations for adjacent decls to Source. Unfortunately pseudo parsing in - // getEligibleRegions only knows about namespace begin/end events so we - // can't match function start/end positions yet. - auto Offset = positionToOffset(Contents, Region.EligiblePoints.back()); - if (!Offset) - return Offset.takeError(); - return InsertionPoint{Region.EnclosingNamespace, *Offset}; -} // Returns the range that should be deleted from declaration, which always // contains function body. In addition to that it might contain constructor @@ -409,14 +386,9 @@ public: } bool prepare(const Selection &Sel) override { - // Bail out if we are not in a header file. - // FIXME: We might want to consider moving method definitions below class - // definition even if we are inside a source file. - if (!isHeaderFile(Sel.AST->getSourceManager().getFilename(Sel.Cursor), - Sel.AST->getLangOpts())) - return false; - + SameFile = !isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts()); Source = getSelectedFunction(Sel.ASTSelection.commonAncestor()); + // Bail out if the selection is not a in-line function definition. if (!Source || !Source->doesThisDeclarationHaveABody() || Source->isOutOfLine()) @@ -429,19 +401,24 @@ public: if (Source->getTemplateSpecializationInfo()) return false; - if (auto *MD = llvm::dyn_cast(Source)) { - // Bail out in templated classes, as it is hard to spell the class name, - // i.e if the template parameter is unnamed. - if (MD->getParent()->isTemplated()) - return false; - - // The refactoring is meaningless for unnamed classes and definitions - // within unnamed namespaces. - for (const DeclContext *DC = MD->getParent(); DC; DC = DC->getParent()) { - if (auto *ND = llvm::dyn_cast(DC)) { - if (ND->getDeclName().isEmpty()) - return false; - } + auto *MD = llvm::dyn_cast(Source); + if (!MD) { + // Can't outline free-standing functions in the same file. + return !SameFile; + } + + // Bail out in templated classes, as it is hard to spell the class name, + // i.e if the template parameter is unnamed. + if (MD->getParent()->isTemplated()) + return false; + + // The refactoring is meaningless for unnamed classes and namespaces, + // unless we're outlining in the same file + for (const DeclContext *DC = MD->getParent(); DC; DC = DC->getParent()) { + if (auto *ND = llvm::dyn_cast(DC)) { + if (ND->getDeclName().isEmpty() && + (!SameFile || !llvm::dyn_cast(ND))) + return false; } } @@ -453,8 +430,8 @@ public: Expected apply(const Selection &Sel) override { const SourceManager &SM = Sel.AST->getSourceManager(); - auto CCFile = getSourceFile(Sel.AST->tuPath(), Sel); - + auto CCFile = SameFile ? Sel.AST->tuPath().str() + : getSourceFile(Sel.AST->tuPath(), Sel); if (!CCFile) return error("Couldn't find a suitable implementation file."); assert(Sel.FS && "FS Must be set in apply"); @@ -464,8 +441,7 @@ public: if (!Buffer) return llvm::errorCodeToError(Buffer.getError()); auto Contents = Buffer->get()->getBuffer(); - auto InsertionPoint = getInsertionPoint( - Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts()); + auto InsertionPoint = getInsertionPoint(Contents, Sel); if (!InsertionPoint) return InsertionPoint.takeError(); @@ -499,17 +475,77 @@ public: HeaderUpdates = HeaderUpdates.merge(*DelInline); } - auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates); - if (!HeaderFE) - return HeaderFE.takeError(); - - Effect->ApplyEdits.try_emplace(HeaderFE->first, - std::move(HeaderFE->second)); + if (SameFile) { + tooling::Replacements &R = Effect->ApplyEdits[*CCFile].Replacements; + R = R.merge(HeaderUpdates); + } else { + auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates); + if (!HeaderFE) + return HeaderFE.takeError(); + Effect->ApplyEdits.try_emplace(HeaderFE->first, + std::move(HeaderFE->second)); + } return std::move(*Effect); } + // Returns the most natural insertion point for \p QualifiedName in \p + // Contents. This currently cares about only the namespace proximity, but in + // feature it should also try to follow ordering of declarations. For example, + // if decls come in order `foo, bar, baz` then this function should return + // some point between foo and baz for inserting bar. + // FIXME: The selection can be made smarter by looking at the definition + // locations for adjacent decls to Source. Unfortunately pseudo parsing in + // getEligibleRegions only knows about namespace begin/end events so we + // can't match function start/end positions yet. + llvm::Expected getInsertionPoint(llvm::StringRef Contents, + const Selection &Sel) { + // If the definition goes to the same file and there is a namespace, + // we should (and, in the case of anonymous namespaces, need to) + // put the definition into the original namespace block. + if (SameFile) { + auto *Klass = Source->getDeclContext()->getOuterLexicalRecordContext(); + if (!Klass) + return error("moving to same file not supported for free functions"); + const SourceLocation EndLoc = Klass->getBraceRange().getEnd(); + const auto &TokBuf = Sel.AST->getTokens(); + auto Tokens = TokBuf.expandedTokens(); + auto It = llvm::lower_bound( + Tokens, EndLoc, [](const syntax::Token &Tok, SourceLocation EndLoc) { + return Tok.location() < EndLoc; + }); + while (It != Tokens.end()) { + if (It->kind() != tok::semi) { + ++It; + continue; + } + unsigned Offset = Sel.AST->getSourceManager() + .getDecomposedLoc(It->endLocation()) + .second; + return InsertionPoint{Klass->getEnclosingNamespaceContext(), Offset}; + } + return error( + "failed to determine insertion location: no end of class found"); + } + + auto Region = getEligiblePoints( + Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts()); + + assert(!Region.EligiblePoints.empty()); + auto Offset = positionToOffset(Contents, Region.EligiblePoints.back()); + if (!Offset) + return Offset.takeError(); + + auto TargetContext = + findContextForNS(Region.EnclosingNamespace, Source->getDeclContext()); + if (!TargetContext) + return error("define outline: couldn't find a context for target"); + + return InsertionPoint{*TargetContext, *Offset}; + } + private: const FunctionDecl *Source = nullptr; + bool SameFile = false; }; REGISTER_TWEAK(DefineOutline) diff --git a/clang-tools-extra/clangd/test/infinite-instantiation.test b/clang-tools-extra/clangd/test/infinite-instantiation.test index d379a9c2d523e6fe2287ec2357cd4c07c84ebc1e..a9c787c77027c7e06c607a00862410c07193359d 100644 --- a/clang-tools-extra/clangd/test/infinite-instantiation.test +++ b/clang-tools-extra/clangd/test/infinite-instantiation.test @@ -1,5 +1,5 @@ // RUN: rm -rf %t.dir && mkdir -p %t.dir -// RUN: echo '[{"directory": "%/t.dir", "command": "clang -ftemplate-depth=100 -x c++ %s", "file": "%/s"}]' > %t.dir/compile_commands.json +// RUN: echo '[{"directory": "%/t.dir", "command": "clang -ftemplate-depth=100 -x c++ %/s", "file": "%/s"}]' > %t.dir/compile_commands.json // RUN: not clangd --compile-commands-dir=%t.dir -check=%s 2>&1 | FileCheck -strict-whitespace %s // CHECK: [template_recursion_depth_exceeded] diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt index 7f1ae5c43d80c69cd896c886cdd4100467e9b88c..0d4628ccf25d8c953b68b3c70a970fe8c87c7e80 100644 --- a/clang-tools-extra/clangd/unittests/CMakeLists.txt +++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -29,6 +29,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../quality/CompletionModel.cmake) gen_decision_forest(${CMAKE_CURRENT_SOURCE_DIR}/decision_forest_model DecisionForestRuntimeTest ::ns1::ns2::test::Example) add_custom_target(ClangdUnitTests) +set_target_properties(ClangdUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests") add_unittest(ClangdUnitTests ClangdTests Annotations.cpp ASTTests.cpp diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index 864337b98f44637b6a0e6a9126a022d5fe5727a5..c324643498d94cbb7c94da0521052e3f883515ee 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -392,7 +392,7 @@ TEST(ClangdServerTest, SearchLibDir) { ErrorCheckingCallbacks DiagConsumer; MockCompilationDatabase CDB; CDB.ExtraClangFlags.insert(CDB.ExtraClangFlags.end(), - {"-xc++", "-target", "x86_64-linux-unknown", + {"-xc++", "--target=x86_64-unknown-linux-gnu", "-m64", "--gcc-toolchain=/randomusr", "-stdlib=libstdc++"}); ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer); diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp index f0ffc429c0ca9096621aa5700c191dcd01e666d6..4ecfdf0184ab40de2017ff9cb03f783706afa7d7 100644 --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -277,6 +277,12 @@ TEST_F(ConfigCompileTests, DiagnosticsIncludeCleaner) { }; EXPECT_TRUE(HeaderFilter("foo.h")); EXPECT_FALSE(HeaderFilter("bar.h")); + + Frag = {}; + EXPECT_FALSE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes); + Frag.Diagnostics.Includes.AnalyzeAngledIncludes = true; + EXPECT_TRUE(compileAndApply()); + EXPECT_TRUE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes); } TEST_F(ConfigCompileTests, DiagnosticSuppression) { diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp index 44a6647d4c0a818fe81541e555a51588866847b7..10d67dead342c3013ff8f6064ef6128c3d64c73a 100644 --- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp @@ -278,6 +278,21 @@ Diagnostics: ElementsAre(val("foo"), val("bar"))); } +TEST(ParseYAML, IncludesAnalyzeAngledIncludes) { + CapturedDiags Diags; + Annotations YAML(R"yaml( +Diagnostics: + Includes: + AnalyzeAngledIncludes: true + )yaml"); + auto Results = + Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback()); + ASSERT_THAT(Diags.Diagnostics, IsEmpty()); + ASSERT_EQ(Results.size(), 1u); + EXPECT_THAT(Results[0].Diagnostics.Includes.AnalyzeAngledIncludes, + llvm::ValueIs(val(true))); +} + TEST(ParseYAML, Style) { CapturedDiags Diags; Annotations YAML(R"yaml( diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 0b2273f0a9a6e36f218c9c06382fa6cee6f2ad80..3220a5a6a98250f55a0bee00e8a8c1f47e996667 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -836,7 +836,9 @@ TEST_F(TargetDeclTest, OverloadExpr) { [[delete]] x; } )cpp"; - EXPECT_DECLS("CXXDeleteExpr", "void operator delete(void *) noexcept"); + // Sized deallocation is enabled by default in C++14 onwards. + EXPECT_DECLS("CXXDeleteExpr", + "void operator delete(void *, unsigned long) noexcept"); } TEST_F(TargetDeclTest, DependentExprs) { diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp index 142310837bd9ce276d92b6ab1f1e9bb4b20e35f2..7027232460354cd66982236edc04293d952528e3 100644 --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -108,6 +108,7 @@ TEST(IncludeCleaner, GetUnusedHeaders) { #include "unguarded.h" #include "unused.h" #include + #include void foo() { a(); b(); @@ -122,6 +123,7 @@ TEST(IncludeCleaner, GetUnusedHeaders) { TU.AdditionalFiles["dir/c.h"] = guard("void c();"); TU.AdditionalFiles["unused.h"] = guard("void unused();"); TU.AdditionalFiles["dir/unused.h"] = guard("void dirUnused();"); + TU.AdditionalFiles["dir/non_system_angled_header.h"] = guard(""); TU.AdditionalFiles["system/system_header.h"] = guard(""); TU.AdditionalFiles["unguarded.h"] = ""; TU.ExtraArgs.push_back("-I" + testPath("dir")); @@ -135,6 +137,48 @@ TEST(IncludeCleaner, GetUnusedHeaders) { Pointee(writtenInclusion("\"dir/unused.h\"")))); } +TEST(IncludeCleaner, IgnoredAngledHeaders) { + // Currently the default behavior is to ignore unused angled includes + auto TU = TestTU::withCode(R"cpp( + #include + #include + #include + SystemClass x; + )cpp"); + TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};"); + TU.AdditionalFiles["system/system_unused.h"] = guard(""); + TU.AdditionalFiles["dir/non_system_angled_unused.h"] = guard(""); + TU.ExtraArgs = { + "-isystem" + testPath("system"), + "-I" + testPath("dir"), + }; + auto AST = TU.build(); + IncludeCleanerFindings Findings = computeIncludeCleanerFindings(AST); + EXPECT_THAT(Findings.UnusedIncludes, IsEmpty()); +} + +TEST(IncludeCleaner, UnusedAngledHeaders) { + auto TU = TestTU::withCode(R"cpp( + #include + #include + #include + SystemClass x; + )cpp"); + TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};"); + TU.AdditionalFiles["system/system_unused.h"] = guard(""); + TU.AdditionalFiles["dir/non_system_angled_unused.h"] = guard(""); + TU.ExtraArgs = { + "-isystem" + testPath("system"), + "-I" + testPath("dir"), + }; + auto AST = TU.build(); + IncludeCleanerFindings Findings = computeIncludeCleanerFindings(AST, true); + EXPECT_THAT(Findings.UnusedIncludes, + UnorderedElementsAre( + Pointee(writtenInclusion("")), + Pointee(writtenInclusion("")))); +} + TEST(IncludeCleaner, ComputeMissingHeaders) { Annotations MainFile(R"cpp( #include "a.h" diff --git a/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp b/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp index 147d9abe691372a3f53c74b05d6b8599641e5a75..32942e6bbfdc8f94862245af4c04380e55fd5558 100644 --- a/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp @@ -25,7 +25,6 @@ #include "clang/AST/DeclTemplate.h" #include "clang/Basic/FileEntry.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" @@ -42,7 +41,11 @@ #include #include -namespace clang::clangd { +namespace clang { + +class Module; + +namespace clangd { namespace { struct Inclusion { Inclusion(const SourceManager &SM, SourceLocation HashLoc, @@ -170,4 +173,5 @@ TEST(ReplayPreambleTest, IncludesAndSkippedFiles) { } } } // namespace -} // namespace clang::clangd +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp index d1e60b070f20e958cf01eea9438c8e5aba122cdb..906ff33db8734414fc08b8e82170ec2afa2b380d 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp @@ -19,12 +19,47 @@ TWEAK_TEST(DefineOutline); TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) { FileName = "Test.cpp"; - // Not available unless in a header file. + // Not available for free function unless in a header file. EXPECT_UNAVAILABLE(R"cpp( [[void [[f^o^o]]() [[{ return; }]]]])cpp"); + // Available in soure file. + EXPECT_AVAILABLE(R"cpp( + struct Foo { + void f^oo() {} + }; + )cpp"); + + // Available within named namespace in source file. + EXPECT_AVAILABLE(R"cpp( + namespace N { + struct Foo { + void f^oo() {} + }; + } // namespace N + )cpp"); + + // Available within anonymous namespace in source file. + EXPECT_AVAILABLE(R"cpp( + namespace { + struct Foo { + void f^oo() {} + }; + } // namespace + )cpp"); + + // Not available for out-of-line method. + EXPECT_UNAVAILABLE(R"cpp( + class Bar { + void baz(); + }; + + [[void [[Bar::[[b^a^z]]]]() [[{ + return; + }]]]])cpp"); + FileName = "Test.hpp"; // Not available unless function name or fully body is selected. EXPECT_UNAVAILABLE(R"cpp( @@ -100,7 +135,7 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) { }; )cpp"); - // Not available on definitions within unnamed namespaces + // Not available on definitions in header file within unnamed namespaces EXPECT_UNAVAILABLE(R"cpp( namespace { struct Foo { @@ -349,6 +384,40 @@ TEST_F(DefineOutlineTest, ApplyTest) { } } +TEST_F(DefineOutlineTest, InCppFile) { + FileName = "Test.cpp"; + + struct { + llvm::StringRef Test; + llvm::StringRef ExpectedSource; + } Cases[] = { + { + R"cpp( + namespace foo { + namespace { + struct Foo { void ba^r() {} }; + struct Bar { void foo(); }; + void Bar::foo() {} + } + } + )cpp", + R"cpp( + namespace foo { + namespace { + struct Foo { void bar() ; };void Foo::bar() {} + struct Bar { void foo(); }; + void Bar::foo() {} + } + } + )cpp"}, + }; + + for (const auto &Case : Cases) { + SCOPED_TRACE(Case.Test); + EXPECT_EQ(apply(Case.Test, nullptr), Case.ExpectedSource); + } +} + TEST_F(DefineOutlineTest, HandleMacros) { llvm::StringMap EditedFiles; ExtraFiles["Test.cpp"] = ""; diff --git a/clang-tools-extra/docs/CMakeLists.txt b/clang-tools-extra/docs/CMakeLists.txt index 8f442e1f661ed34a4f0f3f8b249d98094dc0d8c0..272db266b5054620af9d51aaaea8018eda691f0a 100644 --- a/clang-tools-extra/docs/CMakeLists.txt +++ b/clang-tools-extra/docs/CMakeLists.txt @@ -77,6 +77,7 @@ if (DOXYGEN_FOUND) COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating clang doxygen documentation." VERBATIM) + set_target_properties(doxygen-clang-tools PROPERTIES FOLDER "Clang Tools Extra/Docs") if (LLVM_BUILD_DOCS) add_dependencies(doxygen doxygen-clang-tools) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6a9892bada9155e4ee87ceef384e1937f0e2cfa9..6947cf06f6e56a075c91b8dd4ff4e01bb8dd1d0f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -84,6 +84,11 @@ Objective-C Miscellaneous ^^^^^^^^^^^^^ +- Added a boolean option `AnalyzeAngledIncludes` to `Includes` config section, + which allows to enable unused includes detection for all angled ("system") headers. + At this moment umbrella headers are not supported, so enabling this option + may result in false-positives. + Improvements to clang-doc ------------------------- @@ -346,6 +351,11 @@ Changes in existing checks ` check to also handle calls to ``compare`` method. +- Improved :doc:`modernize-use-std-print + ` check to not crash if the + format string parameter of the function to be replaced is not of the + expected type. + - Improved :doc:`modernize-use-using ` check by adding support for detection of typedefs declared on function level. @@ -363,6 +373,10 @@ Changes in existing checks ` check to eliminate false positives when returning types with const not at the top level. +- Improved :doc:`readability-container-size-empty + ` check to prevent false + positives when utilizing ``size`` or ``length`` methods that accept parameter. + - Improved :doc:`readability-duplicate-include ` check by excluding include directives that form the filename using macro. @@ -375,17 +389,25 @@ Changes in existing checks ` check in `GetConfigPerFile` mode by resolving symbolic links to header files. Fixed handling of Hungarian Prefix when configured to `LowerCase`. Added support for renaming designated - initializers. Added support for renaming macro arguments. + initializers. Added support for renaming macro arguments. Fixed renaming + conflicts arising from out-of-line member function template definitions. - Improved :doc:`readability-implicit-bool-conversion ` check to provide valid fix suggestions for ``static_cast`` without a preceding space and - fixed problem with duplicate parentheses in double implicit casts. + fixed problem with duplicate parentheses in double implicit casts. Corrected + the fix suggestions for C23 and later by using C-style casts instead of + ``static_cast``. - Improved :doc:`readability-redundant-inline-specifier ` check to properly emit warnings for static data member with an in-class initializer. +- Improved :doc:`readability-redundant-member-init + ` check to avoid + false-positives when type of the member does not match the type of the + initializer. + - Improved :doc:`readability-static-accessed-through-instance ` check to support calls to overloaded operators as base expression and provide fixes to diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst index 44d97f7b363bff6220bd761affabffe48054c89b..271970c292c8fab8fc939e5be2d117d7d366815c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst @@ -28,10 +28,7 @@ The following options are described below: .. code-block:: c++ - int doubler(int x) // warns that x is too short - { - return 2 * x; - } + int i = 42; // warns that 'i' is too short This check does not have any fix suggestions in the general case since variable names have semantic value. @@ -50,7 +47,10 @@ The following options are described below: .. code-block:: c++ - int i = 42; // warns that 'i' is too short + int doubler(int x) // warns that x is too short + { + return 2 * x; + } This check does not have any fix suggestions in the general case since variable names have semantic value. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst index 1ea67a0b55e96044829287e6b74aeac37ca17935..1ab21ffeb42289f0a97072ca9a3ea1d8b30eb2e9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst @@ -96,8 +96,8 @@ The rules for generating fix-it hints are: - ``if (!pointer)`` is changed to ``if (pointer == nullptr)``, - in case of conversions from bool to other built-in types, an explicit - ``static_cast`` is proposed to make it clear that a conversion is taking - place: + ``static_cast`` (or a C-style cast since C23) is proposed to make it clear + that a conversion is taking place: - ``int integer = boolean;`` is changed to ``int integer = static_cast(boolean);``, diff --git a/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt b/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt index 1e89534b511161bf18b316c9c6619fa4a70378b5..416535649f62221523b2a573255669b17dd5c376 100644 --- a/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt +++ b/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS ) add_custom_target(ClangIncludeCleanerUnitTests) +set_target_properties(ClangIncludeCleanerUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests") add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests AnalysisTest.cpp FindHeadersTest.cpp diff --git a/clang-tools-extra/pseudo/include/CMakeLists.txt b/clang-tools-extra/pseudo/include/CMakeLists.txt index 2334cfa12e33761fb7dc6a24cb40febc7fc59d40..619b00f34a5caac69858322677d94d61065960fb 100644 --- a/clang-tools-extra/pseudo/include/CMakeLists.txt +++ b/clang-tools-extra/pseudo/include/CMakeLists.txt @@ -29,3 +29,4 @@ add_custom_command(OUTPUT ${cxx_bnf_inc} add_custom_target(cxx_gen DEPENDS ${cxx_symbols_inc} ${cxx_bnf_inc} VERBATIM) +set_target_properties(cxx_gen PROPERTIES FOLDER "Clang Tools Extra/Sourcegenning") diff --git a/clang-tools-extra/pseudo/tool/CMakeLists.txt b/clang-tools-extra/pseudo/tool/CMakeLists.txt index 49e1dc29a5a4e4653d8144922fa22c63fcf391e1..bead383228396e9210ae561ea6dae20103368828 100644 --- a/clang-tools-extra/pseudo/tool/CMakeLists.txt +++ b/clang-tools-extra/pseudo/tool/CMakeLists.txt @@ -26,4 +26,5 @@ add_custom_command(OUTPUT HTMLForestResources.inc DEPENDS ${CLANG_SOURCE_DIR}/utils/bundle_resources.py HTMLForest.css HTMLForest.js HTMLForest.html VERBATIM) add_custom_target(clang-pseudo-resources DEPENDS HTMLForestResources.inc) +set_target_properties(clang-pseudo-resources PROPERTIES FOLDER "Clang Tools Extra/Resources") add_dependencies(clang-pseudo clang-pseudo-resources) diff --git a/clang-tools-extra/pseudo/unittests/CMakeLists.txt b/clang-tools-extra/pseudo/unittests/CMakeLists.txt index 821ca4d0652e1cdc0e0e4c5759a8b2519cdb8357..53583ceb61864032e5fa8da47f764ac90e32d530 100644 --- a/clang-tools-extra/pseudo/unittests/CMakeLists.txt +++ b/clang-tools-extra/pseudo/unittests/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS ) add_custom_target(ClangPseudoUnitTests) +set_target_properties(ClangPseudoUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests") add_unittest(ClangPseudoUnitTests ClangPseudoTests BracketTest.cpp CXXTest.cpp diff --git a/clang-tools-extra/test/CMakeLists.txt b/clang-tools-extra/test/CMakeLists.txt index 7a1c168e22f97c6796f10e8c24ed1ae69f78c732..50546f62259ca17f6a4de9b439f3aece579cd59b 100644 --- a/clang-tools-extra/test/CMakeLists.txt +++ b/clang-tools-extra/test/CMakeLists.txt @@ -97,7 +97,6 @@ add_lit_testsuite(check-clang-extra "Running clang-tools-extra/test" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${CLANG_TOOLS_TEST_DEPS} ) -set_target_properties(check-clang-extra PROPERTIES FOLDER "Clang extra tools' tests") add_lit_testsuites(CLANG-EXTRA ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CLANG_TOOLS_TEST_DEPS} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/new-delete-overloads.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/new-delete-overloads.cpp index 78f021144b2e19c1d8f91534cf0c6b0242e8dec7..f86fe8a4c5b14f606bd5a37c6c8b283682223a11 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/new-delete-overloads.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/new-delete-overloads.cpp @@ -12,16 +12,6 @@ struct S { // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope void *operator new(size_t size) noexcept(false); -struct T { - // Sized deallocations are not enabled by default, and so this new/delete pair - // does not match. However, we expect only one warning, for the new, because - // the operator delete is a placement delete and we do not warn on mismatching - // placement operations. - // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope - void *operator new(size_t size) noexcept; - void operator delete(void *ptr, size_t) noexcept; // ok only if sized deallocation is enabled -}; - struct U { void *operator new(size_t size) noexcept; void operator delete(void *ptr) noexcept; diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp index 815e22b29155153b392a34e5238fc8deba9bb6a9..c025113055ccec9deb9122feda23e3a01940252e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp @@ -2,7 +2,7 @@ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ // RUN: -config="{CheckOptions: { \ // RUN: modernize-use-std-format.StrictMode: true, \ -// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \ // RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ // RUN: modernize-use-std-format.FormatHeader: '' \ // RUN: }}" \ @@ -10,7 +10,7 @@ // RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ // RUN: -config="{CheckOptions: { \ -// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \ // RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ // RUN: modernize-use-std-format.FormatHeader: '' \ // RUN: }}" \ @@ -50,3 +50,17 @@ std::string A(const std::string &in) { return "_" + in; } + +// Issue #92896: Ensure that the check doesn't assert if the argument is +// promoted to something that isn't a string. +struct S { + S(...); +}; +std::string bad_format_type_strprintf(const S &, ...); + +std::string unsupported_format_parameter_type() +{ + // No fixes here because the format parameter of the function called is not a + // string. + return bad_format_type_strprintf(""); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp index 8466217b765a8799169aa2550e5ffbc48fb776ab..09720001ab8370adf21eee7f51f6b4a51fcad9ee 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp @@ -1,8 +1,8 @@ // RUN: %check_clang_tidy -std=c++23 %s modernize-use-std-print %t -- \ // RUN: -config="{CheckOptions: \ // RUN: { \ -// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2', \ -// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2' \ +// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; bad_format_type_printf', \ +// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; bad_format_type_fprintf' \ // RUN: } \ // RUN: }" \ // RUN: -- -isystem %clang_tidy_headers @@ -86,3 +86,25 @@ void no_name(const std::string &in) { "A" + in; } + +int myprintf(const wchar_t *, ...); + +void wide_string_not_supported() { + myprintf(L"wide string %s", L"string"); +} + +// Issue #92896: Ensure that the check doesn't assert if the argument is +// promoted to something that isn't a string. +struct S { + S(...) {} +}; +int bad_format_type_printf(const S &, ...); +int bad_format_type_fprintf(FILE *, const S &, ...); + +void unsupported_format_parameter_type() +{ + // No fixes here because the format parameter of the function called is not a + // string. + bad_format_type_printf("Hello %s", "world"); + bad_format_type_fprintf(stderr, "Hello %s", "world"); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp index 84bdbd58b85e96a15531c2e71a939fab2ee52cd9..ecaf97fa348cc1a4134659b0d39564fe9a2bc6c2 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp @@ -861,3 +861,31 @@ namespace PR72619 { if (0 >= s.size()) {} } } + +namespace PR88203 { + struct SS { + bool empty() const; + int size() const; + int length(int) const; + }; + + struct SU { + bool empty() const; + int size(int) const; + int length() const; + }; + + void f(const SS& s) { + if (0 == s.length(1)) {} + if (0 == s.size()) {} + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-FIXES: {{^ }}if (s.empty()) {}{{$}} + } + + void f(const SU& s) { + if (0 == s.size(1)) {} + if (0 == s.length()) {} + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'length' [readability-container-size-empty] + // CHECK-FIXES: {{^ }}if (s.empty()) {}{{$}} + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f807875e27698da28337cb8444c40c8844ef5357 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp @@ -0,0 +1,30 @@ +// RUN: %check_clang_tidy %s readability-identifier-naming %t -std=c++20 \ +// RUN: --config='{CheckOptions: { \ +// RUN: readability-identifier-naming.MethodCase: CamelCase, \ +// RUN: }}' + +namespace SomeNamespace { +namespace Inner { + +class SomeClass { +public: + template + int someMethod(); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for method 'someMethod' [readability-identifier-naming] +// CHECK-FIXES: {{^}} int SomeMethod(); +}; +template +int SomeClass::someMethod() { +// CHECK-FIXES: {{^}}int SomeClass::SomeMethod() { + return 5; +} + +} // namespace Inner + +void someFunc() { + Inner::SomeClass S; + S.someMethod(); +// CHECK-FIXES: {{^}} S.SomeMethod(); +} + +} // namespace SomeNamespace diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c new file mode 100644 index 0000000000000000000000000000000000000000..a8c69858f76b6136de3c0c2c831996f14bae0fd5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c @@ -0,0 +1,354 @@ +// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c23 + +#undef NULL +#define NULL 0L + +void functionTakingBool(bool); +void functionTakingInt(int); +void functionTakingUnsignedLong(unsigned long); +void functionTakingChar(char); +void functionTakingFloat(float); +void functionTakingDouble(double); +void functionTakingSignedChar(signed char); + + +////////// Implicit conversion from bool. + +void implicitConversionFromBoolSimpleCases() { + bool boolean = true; + + functionTakingBool(boolean); + + functionTakingInt(boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion] + // CHECK-FIXES: functionTakingInt((int)boolean); + + functionTakingUnsignedLong(boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long' + // CHECK-FIXES: functionTakingUnsignedLong((unsigned long)boolean); + + functionTakingChar(boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'char' + // CHECK-FIXES: functionTakingChar((char)boolean); + + functionTakingFloat(boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float' + // CHECK-FIXES: functionTakingFloat((float)boolean); + + functionTakingDouble(boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double' + // CHECK-FIXES: functionTakingDouble((double)boolean); +} + +float implicitConversionFromBoolInReturnValue() { + bool boolean = false; + return boolean; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'bool' -> 'float' + // CHECK-FIXES: return (float)boolean; +} + +void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) { + bool boolean = true; + boolean = b1 ^ b2; + boolean |= !b1 || !b2; + boolean &= b1; + + int integer = boolean - 3; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: int integer = (int)boolean - 3; + + float floating = boolean / 0.3f; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion 'bool' -> 'float' + // CHECK-FIXES: float floating = (float)boolean / 0.3f; + + char character = boolean; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion 'bool' -> 'char' + // CHECK-FIXES: char character = (char)boolean; +} + +void implicitConversionFromBoolInComplexBoolExpressions() { + bool boolean = true; + bool anotherBoolean = false; + + int integer = boolean && anotherBoolean; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 'int' + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: int integer = (int)boolean && (int)anotherBoolean; + + float floating = (boolean || anotherBoolean) * 0.3f; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int' + // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: float floating = ((int)boolean || (int)anotherBoolean) * 0.3f; + + double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'int' + // CHECK-MESSAGES: :[[@LINE-2]]:40: warning: implicit conversion 'bool' -> 'int' + // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: double doubleFloating = ((int)boolean && ((int)anotherBoolean || (int)boolean)) * 0.3; +} + +void implicitConversionFromBoolLiterals() { + functionTakingInt(true); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: functionTakingInt(1); + + functionTakingUnsignedLong(false); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long' + // CHECK-FIXES: functionTakingUnsignedLong(0u); + + functionTakingSignedChar(true); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'signed char' + // CHECK-FIXES: functionTakingSignedChar(1); + + functionTakingFloat(false); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float' + // CHECK-FIXES: functionTakingFloat(0.0f); + + functionTakingDouble(true); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double' + // CHECK-FIXES: functionTakingDouble(1.0); +} + +void implicitConversionFromBoolInComparisons() { + bool boolean = true; + int integer = 0; + + functionTakingBool(boolean == integer); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: functionTakingBool((int)boolean == integer); + + functionTakingBool(integer != boolean); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: functionTakingBool(integer != (int)boolean); +} + +void ignoreBoolComparisons() { + bool boolean = true; + bool anotherBoolean = false; + + functionTakingBool(boolean == anotherBoolean); + functionTakingBool(boolean != anotherBoolean); +} + +void ignoreExplicitCastsFromBool() { + bool boolean = true; + + int integer = (int)boolean + 3; + float floating = (float)boolean * 0.3f; + char character = (char)boolean; +} + +void ignoreImplicitConversionFromBoolInMacroExpansions() { + bool boolean = true; + + #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3 + int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY; + + #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3 + int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean); +} + +////////// Implicit conversions to bool. + +void implicitConversionToBoolSimpleCases() { + int integer = 10; + functionTakingBool(integer); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool(integer != 0); + + unsigned long unsignedLong = 10; + functionTakingBool(unsignedLong); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool' + // CHECK-FIXES: functionTakingBool(unsignedLong != 0u); + + float floating = 0.0f; + functionTakingBool(floating); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: functionTakingBool(floating != 0.0f); + + double doubleFloating = 1.0f; + functionTakingBool(doubleFloating); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool' + // CHECK-FIXES: functionTakingBool(doubleFloating != 0.0); + + signed char character = 'a'; + functionTakingBool(character); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'signed char' -> 'bool' + // CHECK-FIXES: functionTakingBool(character != 0); + + int* pointer = nullptr; + functionTakingBool(pointer); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int *' -> 'bool' + // CHECK-FIXES: functionTakingBool(pointer != nullptr); +} + +void implicitConversionToBoolInSingleExpressions() { + int integer = 10; + bool boolComingFromInt; + boolComingFromInt = integer; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: boolComingFromInt = (integer != 0); + + float floating = 10.0f; + bool boolComingFromFloat; + boolComingFromFloat = floating; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: boolComingFromFloat = (floating != 0.0f); + + signed char character = 'a'; + bool boolComingFromChar; + boolComingFromChar = character; + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> 'bool' + // CHECK-FIXES: boolComingFromChar = (character != 0); + + int* pointer = nullptr; + bool boolComingFromPointer; + boolComingFromPointer = pointer; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int *' -> 'bool' + // CHECK-FIXES: boolComingFromPointer = (pointer != nullptr); +} + +void implicitConversionToBoolInComplexExpressions() { + bool boolean = true; + + int integer = 10; + int anotherInteger = 20; + bool boolComingFromInteger; + boolComingFromInteger = integer + anotherInteger; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: boolComingFromInteger = ((integer + anotherInteger) != 0); +} + +void implicitConversionInNegationExpressions() { + int integer = 10; + bool boolComingFromNegatedInt; + boolComingFromNegatedInt = !integer; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: boolComingFromNegatedInt = ((!integer) != 0); +} + +bool implicitConversionToBoolInReturnValue() { + float floating = 1.0f; + return floating; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: return floating != 0.0f; +} + +void implicitConversionToBoolFromLiterals() { + functionTakingBool(0); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool(false); + + functionTakingBool(1); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool(2ul); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool(0.0f); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: functionTakingBool(false); + + functionTakingBool(1.0f); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool(2.0); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool('\0'); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool(false); + + functionTakingBool('a'); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool(""); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool("abc"); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool' + // CHECK-FIXES: functionTakingBool(true); + + functionTakingBool(NULL); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'long' -> 'bool' + // CHECK-FIXES: functionTakingBool(false); +} + +void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() { + functionTakingBool(-0); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: functionTakingBool((-0) != 0); + + functionTakingBool(-0.0f); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool' + // CHECK-FIXES: functionTakingBool((-0.0f) != 0.0f); + + functionTakingBool(-0.0); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool' + // CHECK-FIXES: functionTakingBool((-0.0) != 0.0); +} + +void ignoreExplicitCastsToBool() { + int integer = 10; + bool boolComingFromInt = (bool)integer; + + float floating = 10.0f; + bool boolComingFromFloat = (bool)floating; + + char character = 'a'; + bool boolComingFromChar = (bool)character; + + int* pointer = nullptr; + bool booleanComingFromPointer = (bool)pointer; +} + +void ignoreImplicitConversionToBoolInMacroExpansions() { + int integer = 3; + + #define CAST_TO_BOOL_IN_MACRO_BODY integer && false + bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY; + + #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true + bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer); +} + +int implicitConversionReturnInt() +{ + return true; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: return 1 +} + +int implicitConversionReturnIntWithParens() +{ + return (true); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int' + // CHECK-FIXES: return 1 +} + +bool implicitConversionReturnBool() +{ + return 1; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: return true +} + +bool implicitConversionReturnBoolWithParens() +{ + return (1); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool' + // CHECK-FIXES: return true +} + +int keepCompactReturnInC_PR71848() { + bool foo = false; + return( foo ); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion] +// CHECK-FIXES: return(int)( foo ); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp index 17b2714abca07b64b5545c580381d6b70d58a711..6f18a6043be93e95ed9f16167a822408d1729839 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp @@ -302,3 +302,19 @@ struct D7 { D7 d7i; D7 d7s; + +struct SS { + SS() = default; + SS(S s) : s(s) {} + + S s; +}; + +struct D8 { + SS ss = S(); +}; + +struct D9 { + D9() : ss(S()) {} + SS ss; +}; diff --git a/clang-tools-extra/unittests/CMakeLists.txt b/clang-tools-extra/unittests/CMakeLists.txt index 086a68e638307ebe313459deb6025cffe2675f73..77311540e719f6effaf25a2226ca21012d90b24f 100644 --- a/clang-tools-extra/unittests/CMakeLists.txt +++ b/clang-tools-extra/unittests/CMakeLists.txt @@ -1,5 +1,5 @@ add_custom_target(ExtraToolsUnitTests) -set_target_properties(ExtraToolsUnitTests PROPERTIES FOLDER "Extra Tools Unit Tests") +set_target_properties(ExtraToolsUnitTests PROPERTIES FOLDER "Clang Tools Extra/Tests") function(add_extra_unittest test_dirname) add_unittest(ExtraToolsUnitTests ${test_dirname} ${ARGN}) diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index c20ce47a12abbd8390ce66a57efde38ac6b52125..2ac0bccb42f50d1a2fbf5527ce02831dff7cfd55 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.20.0) +set(LLVM_SUBPROJECT_TITLE "Clang") if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) @@ -349,10 +350,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-long-long") endif () - check_cxx_compiler_flag("-Werror -Wnested-anon-types" CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG) - if( CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" ) - endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" ) endif () # Determine HOST_LINK_VERSION on Darwin. @@ -394,7 +392,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) # Installing the headers needs to depend on generating any public # tablegen'd headers. add_custom_target(clang-headers DEPENDS clang-tablegen-targets) - set_target_properties(clang-headers PROPERTIES FOLDER "Misc") + set_target_properties(clang-headers PROPERTIES FOLDER "Clang/Resources") if(NOT LLVM_ENABLE_IDE) add_llvm_install_targets(install-clang-headers DEPENDS clang-headers @@ -402,6 +400,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) endif() add_custom_target(bash-autocomplete DEPENDS utils/bash-autocomplete.sh) + set_target_properties(bash-autocomplete PROPERTIES FOLDER "Clang/Misc") install(FILES utils/bash-autocomplete.sh DESTINATION "${CMAKE_INSTALL_DATADIR}/clang" COMPONENT bash-autocomplete) @@ -482,7 +481,7 @@ add_custom_target(clang-tablegen-targets omp_gen ClangDriverOptions ${CLANG_TABLEGEN_TARGETS}) -set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Misc") +set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Clang/Tablegenning/Targets") list(APPEND LLVM_COMMON_DEPENDS clang-tablegen-targets) # Force target to be built as soon as possible. Clang modules builds depend @@ -547,7 +546,7 @@ endif() # Custom target to install all clang libraries. add_custom_target(clang-libraries) -set_target_properties(clang-libraries PROPERTIES FOLDER "Misc") +set_target_properties(clang-libraries PROPERTIES FOLDER "Clang/Install") if(NOT LLVM_ENABLE_IDE) add_llvm_install_targets(install-clang-libraries diff --git a/clang/README.txt b/clang/README.txt index 63842d42bc208b4fa9a124f0ee366ad81041f56f..477f720b193fbdd6c7ca344bdd8ee98a49f47c43 100644 --- a/clang/README.txt +++ b/clang/README.txt @@ -23,4 +23,4 @@ on the Clang forums: https://discourse.llvm.org/c/clang/ If you find a bug in Clang, please file it in the LLVM bug tracker: - http://llvm.org/bugs/ + https://github.com/llvm/llvm-project/issues diff --git a/clang/bindings/python/tests/CMakeLists.txt b/clang/bindings/python/tests/CMakeLists.txt index c4cd2539e9d6cf3a48676c12e213514d4b9045e2..2543cf739463d93ceb169e97b26354e2eb0c61b2 100644 --- a/clang/bindings/python/tests/CMakeLists.txt +++ b/clang/bindings/python/tests/CMakeLists.txt @@ -11,7 +11,7 @@ add_custom_target(check-clang-python WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..) set(RUN_PYTHON_TESTS TRUE) -set_target_properties(check-clang-python PROPERTIES FOLDER "Clang tests") +set_target_properties(check-clang-python PROPERTIES FOLDER "Clang/Tests") # Tests require libclang.so which is only built with LLVM_ENABLE_PIC=ON if(NOT LLVM_ENABLE_PIC) diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index 736a54ece550c62a589e0a48b97e7a61eccd01af..6826d01f8b2a7381fb9c9c4bc245d2f6c7816bee 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -6,14 +6,21 @@ # on Windows platform. # # NOTE: the build requires a development ARM Linux root filesystem to use -# proper target platform depended library and header files. +# proper target platform depended library and header files: +# - create directory and put the clang configuration +# file named .cfg into it. +# - add the `--sysroot=` argument into +# this configuration file. +# - add other necessary target depended clang arguments there, +# such as '-mcpu=cortex-a78' & etc. +# +# See more details here: https://clang.llvm.org/docs/UsersManual.html#configuration-files # # Configure: # cmake -G Ninja ^ -# -DTOOLCHAIN_TARGET_TRIPLE=armv7-unknown-linux-gnueabihf ^ +# -DTOOLCHAIN_TARGET_TRIPLE=aarch64-unknown-linux-gnu ^ # -DCMAKE_INSTALL_PREFIX=../install ^ -# -DDEFAULT_SYSROOT= ^ -# -DLLVM_AR=/bin/llvm-ar[.exe] ^ +# -DCLANG_CONFIG_FILE_USER_DIR= ^ # -DCMAKE_CXX_FLAGS="-D__OPTIMIZE__" ^ # -DREMOTE_TEST_HOST="" ^ # -DREMOTE_TEST_USER="" ^ @@ -43,10 +50,6 @@ get_filename_component(LLVM_PROJECT_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) -if (NOT DEFINED DEFAULT_SYSROOT) - message(WARNING "DEFAULT_SYSROOT must be specified for the cross toolchain build.") -endif() - if (NOT DEFINED LLVM_ENABLE_ASSERTIONS) set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "") endif() @@ -89,6 +92,13 @@ endif() message(STATUS "Toolchain target to build: ${LLVM_TARGETS_TO_BUILD}") +# Allow to override libc++ ABI version. Use 2 by default. +if (NOT DEFINED LIBCXX_ABI_VERSION) + set(LIBCXX_ABI_VERSION 2) +endif() + +message(STATUS "Toolchain's Libc++ ABI version: ${LIBCXX_ABI_VERSION}") + if (NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") endif() @@ -109,8 +119,15 @@ set(CLANG_DEFAULT_OBJCOPY "llvm-objcopy" CACHE STRING "") set(CLANG_DEFAULT_RTLIB "compiler-rt" CACHE STRING "") set(CLANG_DEFAULT_UNWINDLIB "libunwind" CACHE STRING "") -if(WIN32) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded" CACHE STRING "") +if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY AND WIN32) + #Note: Always specify MT DLL for the LLDB build configurations on Windows host. + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL" CACHE STRING "") + else() + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL" CACHE STRING "") + endif() + # Grab all ucrt/vcruntime related DLLs into the binary installation folder. + set(CMAKE_INSTALL_UCRT_LIBRARIES ON CACHE BOOL "") endif() # Set up RPATH for the target runtime/builtin libraries. @@ -122,21 +139,37 @@ endif() set(LLVM_BUILTIN_TARGETS "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSTEM_NAME "Linux" CACHE STRING "") -set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH "${RUNTIMES_INSTALL_RPATH}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_CMAKE_DIR "${LLVM_PROJECT_DIR}/llvm/cmake/modules" CACHE PATH "") +if (DEFINED TOOLCHAIN_TARGET_COMPILER_FLAGS) + foreach(lang C;CXX;ASM) + set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${lang}_FLAGS "${TOOLCHAIN_TARGET_COMPILER_FLAGS}" CACHE STRING "") + endforeach() +endif() +foreach(type SHARED;MODULE;EXE) + set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") +endforeach() + set(LLVM_RUNTIME_TARGETS "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_ENABLE_RUNTIMES "${LLVM_ENABLE_RUNTIMES}" CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSTEM_NAME "Linux" CACHE STRING "") -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH "${RUNTIMES_INSTALL_RPATH}" CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "") +if (DEFINED TOOLCHAIN_TARGET_COMPILER_FLAGS) + foreach(lang C;CXX;ASM) + set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${lang}_FLAGS "${TOOLCHAIN_TARGET_COMPILER_FLAGS}" CACHE STRING "") + endforeach() +endif() +foreach(type SHARED;MODULE;EXE) + set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") +endforeach() + set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_BUILTINS ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") @@ -164,7 +197,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "") -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION 2 CACHE STRING "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION ${LIBCXX_ABI_VERSION} CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!! set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "") diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index d5546e20873b3c580684a5b1d330aeb0a462a944..66e764968e85ce499f66668c63c564c9a7a673ff 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -19,7 +19,6 @@ set(LLVM_ENABLE_LLD ON CACHE BOOL "") set(LLVM_ENABLE_LTO ON CACHE BOOL "") set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(LLVM_ENABLE_PLUGINS OFF CACHE BOOL "") -set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "") set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "") set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "") set(LLVM_ENABLE_ZLIB ON CACHE BOOL "") diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake index 30a3b9116a461f3f65d2bfdfab0f5aaecccc2e6c..4d3af3ad3f4031908415e2aad3ed56107e51f144 100644 --- a/clang/cmake/caches/Fuchsia.cmake +++ b/clang/cmake/caches/Fuchsia.cmake @@ -12,7 +12,6 @@ set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "") set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "") set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "") set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") -set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "") set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "") set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "") set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") @@ -34,7 +33,6 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH LibXml2_ROOT LLVM_ENABLE_CURL LLVM_ENABLE_HTTPLIB - LLVM_ENABLE_TERMINFO LLVM_ENABLE_LIBEDIT CURL_ROOT OpenSSL_ROOT @@ -47,11 +45,6 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH CURSES_LIBRARIES PANEL_LIBRARIES - # Deprecated - Terminfo_ROOT - - Terminfo_LIBRARIES - # Deprecated LibEdit_ROOT diff --git a/clang/cmake/caches/VectorEngine.cmake b/clang/cmake/caches/VectorEngine.cmake index 2f968a21cc407e7a79220b68cec30229101d22cf..b429fb0997d7a0665a6d9f6fa5178fcaea2beae6 100644 --- a/clang/cmake/caches/VectorEngine.cmake +++ b/clang/cmake/caches/VectorEngine.cmake @@ -13,9 +13,7 @@ # ninja # -# Disable TERMINFO, ZLIB, and ZSTD for VE since there is no pre-compiled -# libraries. -set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "") +# Disable ZLIB, and ZSTD for VE since there is no pre-compiled libraries. set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") set(LLVM_ENABLE_ZSTD OFF CACHE BOOL "") diff --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake index 75b0080f67156463a86c77a50580b00596126b23..a5ef639187d9db2f06bc88bcc5ddd7cf54c32d7b 100644 --- a/clang/cmake/modules/AddClang.cmake +++ b/clang/cmake/modules/AddClang.cmake @@ -26,7 +26,6 @@ function(clang_tablegen) if(CTG_TARGET) add_public_tablegen_target(${CTG_TARGET}) - set_target_properties( ${CTG_TARGET} PROPERTIES FOLDER "Clang tablegenning") set_property(GLOBAL APPEND PROPERTY CLANG_TABLEGEN_TARGETS ${CTG_TARGET}) endif() endfunction(clang_tablegen) @@ -138,13 +137,11 @@ macro(add_clang_library name) endif() endforeach() - set_target_properties(${name} PROPERTIES FOLDER "Clang libraries") set_clang_windows_version_resource_properties(${name}) endmacro(add_clang_library) macro(add_clang_executable name) add_llvm_executable( ${name} ${ARGN} ) - set_target_properties(${name} PROPERTIES FOLDER "Clang executables") set_clang_windows_version_resource_properties(${name}) endmacro(add_clang_executable) diff --git a/clang/docs/CMakeLists.txt b/clang/docs/CMakeLists.txt index 4163dd2d90ad5b3530bc374407d5a736591fe798..51e9db29f887f3bc857b5fc494dda65b3cc2c253 100644 --- a/clang/docs/CMakeLists.txt +++ b/clang/docs/CMakeLists.txt @@ -78,6 +78,7 @@ if (LLVM_ENABLE_DOXYGEN) COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating clang doxygen documentation." VERBATIM) + set_target_properties(doxygen-clang PROPERTIES FOLDER "Clang/Docs") if (LLVM_BUILD_DOCS) add_dependencies(doxygen doxygen-clang) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 6d092219877f91f68d46025cf550e37531f029d5..bb00c20922d361c93df32db36a563a64d6ae1481 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1421,13 +1421,21 @@ the configuration (without a prefix: ``Auto``). .. code-block:: c++ - true: #define A \ int aaaa; \ int b; \ int dddddddddd; - false: + * ``ENAS_LeftWithLastLine`` (in configuration: ``LeftWithLastLine``) + Align escaped newlines as far left as possible, using the last line of + the preprocessor directive as the reference if it's the longest. + + .. code-block:: c++ + + #define A \ + int aaaa; \ + int b; \ + int dddddddddd; * ``ENAS_Right`` (in configuration: ``Right``) Align escaped newlines in the right-most column. @@ -1791,8 +1799,8 @@ the configuration (without a prefix: ``Auto``). Never merge functions into a single line. * ``SFS_InlineOnly`` (in configuration: ``InlineOnly``) - Only merge functions defined inside a class. Same as "inline", - except it does not implies "empty": i.e. top level empty functions + Only merge functions defined inside a class. Same as ``inline``, + except it does not implies ``empty``: i.e. top level empty functions are not merged either. .. code-block:: c++ @@ -1817,7 +1825,7 @@ the configuration (without a prefix: ``Auto``). } * ``SFS_Inline`` (in configuration: ``Inline``) - Only merge functions defined inside a class. Implies "empty". + Only merge functions defined inside a class. Implies ``empty``. .. code-block:: c++ @@ -2034,7 +2042,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - AttributeMacros: ['__capability', '__output', '__unused'] + AttributeMacros: [__capability, __output, __unused] .. _BinPackArguments: @@ -3794,7 +3802,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - ForEachMacros: ['RANGES_FOR', 'FOREACH'] + ForEachMacros: [RANGES_FOR, FOREACH] For example: BOOST_FOREACH. @@ -3817,7 +3825,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - IfMacros: ['IF'] + IfMacros: [IF] For example: `KJ_IF_MAYBE `_ @@ -4366,7 +4374,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - JavaImportGroups: ['com.example', 'com', 'org'] + JavaImportGroups: [com.example, com, org] .. code-block:: java @@ -4430,7 +4438,7 @@ the configuration (without a prefix: ``Auto``). VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, - } from 'some/module.js' + } from "some/module.js" false: import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" @@ -5080,7 +5088,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - QualifierOrder: ['inline', 'static', 'type', 'const'] + QualifierOrder: [inline, static, type, const] .. code-block:: c++ @@ -5109,16 +5117,16 @@ the configuration (without a prefix: ``Auto``). .. note:: - it MUST contain 'type'. + It **must** contain ``type``. - Items to the left of 'type' will be placed to the left of the type and - aligned in the order supplied. Items to the right of 'type' will be + Items to the left of ``type`` will be placed to the left of the type and + aligned in the order supplied. Items to the right of ``type`` will be placed to the right of the type and aligned in the order supplied. .. code-block:: yaml - QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ] + QualifierOrder: [inline, static, type, const, volatile] .. _RawStringFormats: @@ -5130,10 +5138,10 @@ the configuration (without a prefix: ``Auto``). name will be reformatted assuming the specified language based on the style for that language defined in the .clang-format file. If no style has been defined in the .clang-format file for the specific language, a - predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not - found, the formatting is based on llvm style. A matching delimiter takes - precedence over a matching enclosing function name for determining the - language of the raw string contents. + predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is + not found, the formatting is based on ``LLVM`` style. A matching delimiter + takes precedence over a matching enclosing function name for determining + the language of the raw string contents. If a canonical delimiter is specified, occurrences of other delimiters for the same language will be updated to the canonical if possible. @@ -5148,17 +5156,17 @@ the configuration (without a prefix: ``Auto``). RawStringFormats: - Language: TextProto Delimiters: - - 'pb' - - 'proto' + - pb + - proto EnclosingFunctions: - - 'PARSE_TEXT_PROTO' + - PARSE_TEXT_PROTO BasedOnStyle: google - Language: Cpp Delimiters: - - 'cc' - - 'cpp' - BasedOnStyle: llvm - CanonicalDelimiter: 'cc' + - cc + - cpp + BasedOnStyle: LLVM + CanonicalDelimiter: cc .. _ReferenceAlignment: @@ -5525,7 +5533,7 @@ the configuration (without a prefix: ``Auto``). This determines the maximum length of short namespaces by counting unwrapped lines (i.e. containing neither opening nor closing - namespace brace) and makes "FixNamespaceComments" omit adding + namespace brace) and makes ``FixNamespaceComments`` omit adding end comments for those. .. code-block:: c++ @@ -5637,7 +5645,7 @@ the configuration (without a prefix: ``Auto``). * ``SUD_Lexicographic`` (in configuration: ``Lexicographic``) Using declarations are sorted in the order defined as follows: - Split the strings by "::" and discard any initial empty strings. Sort + Split the strings by ``::`` and discard any initial empty strings. Sort the lists of names lexicographically, and within those groups, names are in case-insensitive lexicographic order. @@ -5651,7 +5659,7 @@ the configuration (without a prefix: ``Auto``). * ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``) Using declarations are sorted in the order defined as follows: - Split the strings by "::" and discard any initial empty strings. The + Split the strings by ``::`` and discard any initial empty strings. The last element of each list is a non-namespace name; all others are namespace names. Sort the lists of names lexicographically, where the sort order of individual names is that all non-namespace names come @@ -5691,7 +5699,7 @@ the configuration (without a prefix: ``Auto``). .. _SpaceAfterTemplateKeyword: **SpaceAfterTemplateKeyword** (``Boolean``) :versionbadge:`clang-format 4` :ref:`¶ ` - If ``true``, a space will be inserted after the 'template' keyword. + If ``true``, a space will be inserted after the ``template`` keyword. .. code-block:: c++ @@ -5852,7 +5860,7 @@ the configuration (without a prefix: ``Auto``). * ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``) Put a space before opening parentheses only if the parentheses are not - empty i.e. '()' + empty. .. code-block:: c++ @@ -6237,7 +6245,7 @@ the configuration (without a prefix: ``Auto``). true: false: x = ( int32 )y vs. x = (int32)y - * ``bool InEmptyParentheses`` Put a space in parentheses only if the parentheses are empty i.e. '()' + * ``bool InEmptyParentheses`` Insert a space in empty parentheses, i.e. ``()``. .. code-block:: c++ @@ -6401,10 +6409,10 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml TableGenBreakInsideDAGArg: BreakAll - TableGenBreakingDAGArgOperators: ['ins', 'outs'] + TableGenBreakingDAGArgOperators: [ins, outs] makes the line break only occurs inside DAGArgs beginning with the - specified identifiers 'ins' and 'outs'. + specified identifiers ``ins`` and ``outs``. .. code-block:: c++ @@ -6442,7 +6450,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - TypenameMacros: ['STACK_OF', 'LIST'] + TypenameMacros: [STACK_OF, LIST] For example: OpenSSL STACK_OF, BSD LIST_ENTRY. @@ -6510,7 +6518,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE'] + WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] For example: BOOST_PP_STRINGIZE @@ -6530,7 +6538,7 @@ The goal of the clang-format project is more on the side of supporting a limited set of styles really well as opposed to supporting every single style used by a codebase somewhere in the wild. Of course, we do want to support all major projects and thus have established the following bar for adding style -options. Each new style option must .. +options. Each new style option must: * be used in a project of significant size (have dozens of contributors) * have a publicly accessible style guide diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst index b3e2b870ae5f9aad96983e3f6d678c999f7f3989..3d21e37784b36354d95d5dfccf34f5c0e7b74b8c 100644 --- a/clang/docs/InternalsManual.rst +++ b/clang/docs/InternalsManual.rst @@ -123,6 +123,44 @@ severe that error recovery won't be able to recover sensibly from them (thus spewing a ton of bogus errors). One example of this class of error are failure to ``#include`` a file. +Diagnostic Wording +^^^^^^^^^^^^^^^^^^ +The wording used for a diagnostic is critical because it is the only way for a +user to know how to correct their code. Use the following suggestions when +wording a diagnostic. + +* Diagnostics in Clang do not start with a capital letter and do not end with + punctuation. + + * This does not apply to proper nouns like ``Clang`` or ``OpenMP``, to + acronyms like ``GCC`` or ``ARC``, or to language standards like ``C23`` + or ``C++17``. + * A trailing question mark is allowed. e.g., ``unknown identifier %0; did + you mean %1?``. + +* Appropriately capitalize proper nouns like ``Clang``, ``OpenCL``, ``GCC``, + ``Objective-C``, etc and language standard versions like ``C11`` or ``C++11``. +* The wording should be succinct. If necessary, use a semicolon to combine + sentence fragments instead of using complete sentences. e.g., prefer wording + like ``'%0' is deprecated; it will be removed in a future release of Clang`` + over wording like ``'%0' is deprecated. It will be removed in a future release + of Clang``. +* The wording should be actionable and avoid using standards terms or grammar + productions that a new user would not be familiar with. e.g., prefer wording + like ``missing semicolon`` over wording like ``syntax error`` (which is not + actionable) or ``expected unqualified-id`` (which uses standards terminology). +* The wording should clearly explain what is wrong with the code rather than + restating what the code does. e.g., prefer wording like ``type %0 requires a + value in the range %1 to %2`` over wording like ``%0 is invalid``. +* The wording should have enough contextual information to help the user + identify the issue in a complex expression. e.g., prefer wording like + ``both sides of the %0 binary operator are identical`` over wording like + ``identical operands to binary operator``. +* Use single quotes to denote syntactic constructs or command line arguments + named in a diagnostic message. e.g., prefer wording like ``'this' pointer + cannot be null in well-defined C++ code`` over wording like ``this pointer + cannot be null in well-defined C++ code``. + The Format String ^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index a09c409f8f91a3da3b3a47ba15b846fd8103a5a6..46f99d0bbdd066932de0adbb7cb83ff5322ae36e 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -4403,6 +4403,7 @@ immediately after the name being declared. For example, this applies the GNU ``unused`` attribute to ``a`` and ``f``, and also applies the GNU ``noreturn`` attribute to ``f``. +Examples: .. code-block:: c++ [[gnu::unused]] int a, f [[gnu::noreturn]] (); @@ -4412,6 +4413,42 @@ Target-Specific Extensions Clang supports some language features conditionally on some targets. +AMDGPU Language Extensions +-------------------------- + +__builtin_amdgcn_fence +^^^^^^^^^^^^^^^^^^^^^^ + +``__builtin_amdgcn_fence`` emits a fence. + +* ``unsigned`` atomic ordering, e.g. ``__ATOMIC_ACQUIRE`` +* ``const char *`` synchronization scope, e.g. ``workgroup`` +* Zero or more ``const char *`` address spaces names. + +The address spaces arguments must be one of the following string literals: + +* ``"local"`` +* ``"global"`` + +If one or more address space name are provided, the code generator will attempt +to emit potentially faster instructions that order access to at least those +address spaces. +Emitting such instructions may not always be possible and the compiler is free +to fence more aggressively. + +If no address spaces names are provided, all address spaces are fenced. + +.. code-block:: c++ + + // Fence all address spaces. + __builtin_amdgcn_fence(__ATOMIC_SEQ_CST, "workgroup"); + __builtin_amdgcn_fence(__ATOMIC_ACQUIRE, "agent"); + + // Fence only requested address spaces. + __builtin_amdgcn_fence(__ATOMIC_SEQ_CST, "workgroup", "local") + __builtin_amdgcn_fence(__ATOMIC_SEQ_CST, "workgroup", "local", "global") + + ARM/AArch64 Language Extensions ------------------------------- @@ -5602,4 +5639,4 @@ Compiling different TUs depending on these flags (including use of ``std::hardware_constructive_interference`` or ``std::hardware_destructive_interference``) with different compilers, macro definitions, or architecture flags will lead to ODR violations and should be -avoided. \ No newline at end of file +avoided. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 81e9d0423f96aecced463f43e5ffadb4efde3288..69ac08133c9f0d1a6e8e8128d1ef7ac4924226f5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -59,6 +59,18 @@ C++ Specific Potentially Breaking Changes - Clang now performs semantic analysis for unary operators with dependent operands that are known to be of non-class non-enumeration type prior to instantiation. + This change uncovered a bug in libstdc++ 14.1.0 which may cause compile failures + on systems using that version of libstdc++ and Clang 19, with an error that looks + something like this: + + .. code-block:: text + + :4:5: error: expression is not assignable + 4 | ++this; + | ^ ~~~~ + + To fix this, update libstdc++ to version 14.1.1 or greater. + ABI Changes in This Version --------------------------- - Fixed Microsoft name mangling of implicitly defined variables used for thread @@ -86,6 +98,8 @@ ABI Changes in This Version AST Dumping Potentially Breaking Changes ---------------------------------------- +- The text ast-dumper has improved printing of TemplateArguments. + Clang Frontend Potentially Breaking Changes ------------------------------------------- - Removed support for constructing on-stack ``TemplateArgumentList``\ s; interfaces should instead @@ -155,6 +169,11 @@ C++17 Feature Support files because they may not be stable across multiple TUs (the values may vary based on compiler version as well as CPU tuning). #GH60174 +C++14 Feature Support +^^^^^^^^^^^^^^^^^^^^^ +- Sized deallocation is enabled by default in C++14 onwards. The user may specify + ``-fno-sized-deallocation`` to disable it if there are some regressions. + C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -188,10 +207,16 @@ C++23 Feature Support - Implemented `P1774R8: Portable assumptions `_. - Implemented `P2448R2: Relaxing some constexpr restrictions `_. + Note, the ``-Winvalid-constexpr`` diagnostic is now disabled in C++23 mode, + but can be explicitly specified to retain the old diagnostic checking + behavior. - Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for `P2255R2: Type trait to determine if a reference binds to a temporary `_. +- Implemented `P2797R0: Static and explicit object member functions with the same parameter-type-lists `_. + This completes the support for "deducing this". + C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -232,6 +257,9 @@ Resolutions to C++ Defect Reports - P0522 implementation is enabled by default in all language versions, and provisional wording for CWG2398 is implemented. +- Clang now requires a template argument list after a template keyword. + (`CWG96: Syntactic disambiguation using the template keyword `_). + C Language Changes ------------------ @@ -301,6 +329,17 @@ Non-comprehensive list of changes in this release - Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may now be used within constant expressions. +- When compiling a constexpr function, Clang will check to see whether the + function can *never* be used in a constant expression context and issues a + diagnostic under the ``-Winvalid-constexpr`` diagostic flag (which defaults + to an error). This check can be expensive because the mere presence of a + function marked ``constexpr`` will cause us to undergo constant expression + evaluation, even if the function is not called within the translation unit + being compiled. Due to the expense, Clang no longer checks constexpr function + bodies when the function is defined in a system header file or when + ``-Winvalid-constexpr`` is not enabled for the function definition, which + should result in mild compile-time performance improvements. + New Compiler Flags ------------------ - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and @@ -317,13 +356,18 @@ New Compiler Flags - ``-fexperimental-late-parse-attributes`` enables an experimental feature to allow late parsing certain attributes in specific contexts where they would - not normally be late parsed. + not normally be late parsed. Currently this allows late parsing the + `counted_by` attribute in C. See `Attribute Changes in Clang`_. - ``-fseparate-named-sections`` uses separate unique sections for global symbols in named special sections (i.e. symbols annotated with ``__attribute__((section(...)))``. This enables linker GC to collect unused symbols without having to use a per-symbol section. +- ``-fms-define-stdc`` and its clang-cl counterpart ``/Zc:__STDC__``. + Matches MSVC behaviour by defining ``__STDC__`` to ``1`` when + MSVC compatibility mode is used. It has no effect for C++ code. + Deprecated Compiler Flags ------------------------- @@ -406,6 +450,24 @@ Attribute Changes in Clang - The ``clspv_libclc_builtin`` attribute has been added to allow clspv (`OpenCL-C to Vulkan SPIR-V compiler `_) to identify functions coming from libclc (`OpenCL-C builtin library `_). +- The ``counted_by`` attribute is now allowed on pointers that are members of a + struct in C. + +- The ``counted_by`` attribute can now be late parsed in C when + ``-fexperimental-late-parse-attributes`` is passed but only when attribute is + used in the declaration attribute position. This allows using the + attribute on existing code where it previously impossible to do so without + re-ordering struct field declarations would break ABI as shown below. + + .. code-block:: c + + struct BufferTy { + /* Refering to `count` requires late parsing */ + char* buffer __counted_by(count); + /* Swapping `buffer` and `count` to avoid late parsing would break ABI */ + size_t count; + }; + Improvements to Clang's diagnostics ----------------------------------- @@ -501,6 +563,9 @@ Improvements to Clang's diagnostics - Clang emits a ``-Wparentheses`` warning for expressions with consecutive comparisons like ``x < y < z``. Fixes #GH20456. +- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source. + Fixes #GH93369. + Improvements to Clang's time-trace ---------------------------------- @@ -589,9 +654,14 @@ Bug Fixes in This Version - ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for zero-sized arrays. Fixes (#GH54705). +- Correctly reject declarations where a statement is required in C. + Fixes #GH92775 + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fix crash when atomic builtins are called with pointer to zero-size struct (#GH90330) + Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -694,7 +764,6 @@ Bug Fixes to C++ Support from being explicitly specialized for a given implicit instantiation of the class template. - Fixed a crash when ``this`` is used in a dependent class scope function template specialization that instantiates to a static member function. - - Fix crash when inheriting from a cv-qualified type. Fixes #GH35603 - Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790). - Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220) @@ -749,24 +818,54 @@ Bug Fixes to C++ Support - Clang now correctly diagnoses when the current instantiation is used as an incomplete base class. - Clang no longer treats ``constexpr`` class scope function template specializations of non-static members as implicitly ``const`` in language modes after C++11. +- Fixed a crash when trying to emit captures in a lambda call operator with an explicit object + parameter that is called on a derived type of the lambda. + Fixes (#GH87210), (GH89541). +- Clang no longer tries to check if an expression is immediate-escalating in an unevaluated context. + Fixes (#GH91308). +- Fix a crash caused by a regression in the handling of ``source_location`` + in dependent contexts. Fixes (#GH92680). +- Fixed a crash when diagnosing failed conversions involving template parameter + packs. (#GH93076) +- Fixed a regression introduced in Clang 18 causing a static function overloading a non-static function + with the same parameters not to be diagnosed. (Fixes #GH93456). +- Clang now diagnoses unexpanded parameter packs in attributes. (Fixes #GH93269). +- Clang now allows ``@$``` in raw string literals. Fixes (#GH93130). +- Fix an assertion failure when checking invalid ``this`` usage in the wrong context. (Fixes #GH91536). +- Clang no longer models dependent NTTP arguments as ``TemplateParamObjectDecl`` s. Fixes (#GH84052). +- Fix incorrect merging of modules which contain using declarations which shadow + other declarations. This could manifest as ODR checker false positives. + Fixes (`#80252 `_) +- Fix a regression introduced in Clang 18 causing incorrect overload resolution in the presence of functions only + differering by their constraints when only one of these function was variadic. +- Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625). +- Fixed a type constraint substitution issue involving a generic lambda expression. (#GH93821) +- Fix a crash caused by improper use of ``__array_extent``. (#GH80474) +- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307), + (#GH88081), (#GH89496), (#GH90669) and (#GH91633). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628) - The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``. - Fixed malformed AST generated for anonymous union access in templates. (#GH90842) +- Improved preservation of qualifiers and sugar in `TemplateNames`, including + template keyword. Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an infinite recursion in ASTImporter, on return type declared inside body of C++11 lambda without trailing return (#GH68775). +- Fixed declaration name source location of instantiated function definitions (GH71161). +- Improve diagnostic output to print an expression instead of 'no argument` when comparing Values as template arguments. Miscellaneous Clang Crashes Fixed ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Do not attempt to dump the layout of dependent types or invalid declarations when ``-fdump-record-layouts-complete`` is passed. Fixes #GH83684. +- Unhandled StructuralValues in the template differ (#GH93068). OpenACC Specific Changes ------------------------ @@ -780,6 +879,8 @@ AMDGPU Support X86 Support ^^^^^^^^^^^ +- Remove knl/knm specific ISA supports: AVX512PF, AVX512ER, PREFETCHWT1 + Arm and AArch64 Support ^^^^^^^^^^^^^^^^^^^^^^^ @@ -832,6 +933,10 @@ Windows Support including STL headers will no longer slow down compile times since ``intrin.h`` is not included from MSVC STL. +- When the target triple is `*-windows-msvc` strict aliasing is now disabled by default + to ensure compatibility with msvc. Previously strict aliasing was only disabled if the + driver mode was cl. + LoongArch Support ^^^^^^^^^^^^^^^^^ @@ -849,7 +954,7 @@ CUDA/HIP Language Changes CUDA Support ^^^^^^^^^^^^ -- Clang now supports CUDA SDK up to 12.4 +- Clang now supports CUDA SDK up to 12.5 AIX Support ^^^^^^^^^^^ @@ -894,6 +999,7 @@ AST Matchers - Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to not skip the explicit object parameter for operator calls. - Fixed captureVars assertion failure if not capturesVariables. (#GH76425) +- ``forCallable`` now properly preserves binding on successful match. (#GH89657) clang-format ------------ @@ -902,9 +1008,10 @@ clang-format ``BreakTemplateDeclarations``. - ``AlwaysBreakAfterReturnType`` is deprecated and renamed to ``BreakAfterReturnType``. -- Handles Java ``switch`` expressions. +- Handles Java switch expressions. - Adds ``AllowShortCaseExpressionOnASingleLine`` option. - Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``. +- Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``. libclang -------- diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 80ba70f67126fa23543819655e98e2fcb7d46a32..f954857b0235af6d238b1f3ea346b4a36be57365 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -4430,9 +4430,9 @@ To generate SPIR-V binaries, Clang uses the external ``llvm-spirv`` tool from th Prior to the generation of SPIR-V binary with Clang, ``llvm-spirv`` should be built or installed. Please refer to `the following instructions `_ -for more details. Clang will expect the ``llvm-spirv`` executable to -be present in the ``PATH`` environment variable. Clang uses ``llvm-spirv`` -with `the widely adopted assembly syntax package +for more details. Clang will look for ``llvm-spirv-`` and +``llvm-spirv`` executables, in this order, in the ``PATH`` environment variable. +Clang uses ``llvm-spirv`` with `the widely adopted assembly syntax package `_. `The versioning diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index eb8b58323da4d783695c73310f717cb32feb2d05..f53dd545df5a9ecb4dbb73bfed2b6663d04e9b99 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -599,7 +599,7 @@ Warns when a nullable pointer is returned from a function that has _Nonnull retu optin ^^^^^ -Checkers for portability, performance or coding style specific rules. +Checkers for portability, performance, optional security and coding style specific rules. .. _optin-core-EnumCastOutOfRange: @@ -938,6 +938,53 @@ optin.portability.UnixAPI """"""""""""""""""""""""" Finds implementation-defined behavior in UNIX/Posix functions. +.. _optin-taint-TaintedAlloc: + +optin.taint.TaintedAlloc (C, C++) +""""""""""""""""""""""""""""""""" + +This checker warns for cases when the ``size`` parameter of the ``malloc`` , +``calloc``, ``realloc``, ``alloca`` or the size parameter of the +array new C++ operator is tainted (potentially attacker controlled). +If an attacker can inject a large value as the size parameter, memory exhaustion +denial of service attack can be carried out. + +The ``alpha.security.taint.TaintPropagation`` checker also needs to be enabled for +this checker to give warnings. + +The analyzer emits warning only if it cannot prove that the size parameter is +within reasonable bounds (``<= SIZE_MAX/4``). This functionality partially +covers the SEI Cert coding standard rule `INT04-C +`_. + +You can silence this warning either by bound checking the ``size`` parameter, or +by explicitly marking the ``size`` parameter as sanitized. See the +:ref:`alpha-security-taint-TaintPropagation` checker for more details. + +.. code-block:: c + + void vulnerable(void) { + size_t size = 0; + scanf("%zu", &size); + int *p = malloc(size); // warn: malloc is called with a tainted (potentially attacker controlled) value + free(p); + } + + void not_vulnerable(void) { + size_t size = 0; + scanf("%zu", &size); + if (1024 < size) + return; + int *p = malloc(size); // No warning expected as the the user input is bound + free(p); + } + + void vulnerable_cpp(void) { + size_t size = 0; + scanf("%zu", &size); + int *ptr = new int[size];// warn: Memory allocation function is called with a tainted (potentially attacker controlled) value + delete[] ptr; + } .. _security-checkers: @@ -1179,6 +1226,82 @@ security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C) strncpy(buf, "a", 1); // warn } +.. _security-putenv-stack-array: + +security.PutenvStackArray (C) +""""""""""""""""""""""""""""" +Finds calls to the ``putenv`` function which pass a pointer to a stack-allocated +(automatic) array as the argument. Function ``putenv`` does not copy the passed +string, only a pointer to the data is stored and this data can be read even by +other threads. Content of a stack-allocated array is likely to be overwritten +after exiting from the function. + +The problem can be solved by using a static array variable or dynamically +allocated memory. Even better is to avoid using ``putenv`` (it has other +problems related to memory leaks) and use ``setenv`` instead. + +The check corresponds to CERT rule +`POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument +`_. + +.. code-block:: c + + int f() { + char env[] = "NAME=value"; + return putenv(env); // putenv function should not be called with stack-allocated string + } + +There is one case where the checker can report a false positive. This is when +the stack-allocated array is used at `putenv` in a function or code branch that +does not return (process is terminated on all execution paths). + +Another special case is if the `putenv` is called from function `main`. Here +the stack is deallocated at the end of the program and it should be no problem +to use the stack-allocated string (a multi-threaded program may require more +attention). The checker does not warn for cases when stack space of `main` is +used at the `putenv` call. + +security.SetgidSetuidOrder (C) +"""""""""""""""""""""""""""""" +When dropping user-level and group-level privileges in a program by using +``setuid`` and ``setgid`` calls, it is important to reset the group-level +privileges (with ``setgid``) first. Function ``setgid`` will likely fail if +the superuser privileges are already dropped. + +The checker checks for sequences of ``setuid(getuid())`` and +``setgid(getgid())`` calls (in this order). If such a sequence is found and +there is no other privilege-changing function call (``seteuid``, ``setreuid``, +``setresuid`` and the GID versions of these) in between, a warning is +generated. The checker finds only exactly ``setuid(getuid())`` calls (and the +GID versions), not for example if the result of ``getuid()`` is stored in a +variable. + +.. code-block:: c + + void test1() { + // ... + // end of section with elevated privileges + // reset privileges (user and group) to normal user + if (setuid(getuid()) != 0) { + handle_error(); + return; + } + if (setgid(getgid()) != 0) { // warning: A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail + handle_error(); + return; + } + // user-ID and group-ID are reset to normal user now + // ... + } + +In the code above the problem is that ``setuid(getuid())`` removes superuser +privileges before ``setgid(getgid())`` is called. To fix the problem the +``setgid(getgid())`` should be called first. Further attention is needed to +avoid code like ``setgid(getuid())`` (this checker does not detect bugs like +this) and always check the return value of these calls. + +This check corresponds to SEI CERT Rule `POS36-C `_. + .. _unix-checkers: unix @@ -1194,6 +1317,50 @@ Check calls to various UNIX/Posix functions: ``open, pthread_once, calloc, mallo .. literalinclude:: checkers/unix_api_example.c :language: c +.. _unix-BlockInCriticalSection: + +unix.BlockInCriticalSection (C, C++) +"""""""""""""""""""""""""""""""""""" +Check for calls to blocking functions inside a critical section. +Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``. +Critical section handling functions modeled by this checker: +``lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``. + +.. code-block:: c + + void pthread_lock_example(pthread_mutex_t *m) { + pthread_mutex_lock(m); // note: entering critical section here + sleep(10); // warn: Call to blocking function 'sleep' inside of critical section + pthread_mutex_unlock(m); + } + +.. code-block:: cpp + + void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) { + std::lock_guard lg{m2}; // note: entering critical section here + mtx_lock(m1); // note: entering critical section here + sleep(10); // warn: Call to blocking function 'sleep' inside of critical section + mtx_unlock(m1); + sleep(10); // warn: Call to blocking function 'sleep' inside of critical section + // still inside of the critical section of the std::lock_guard + } + +**Limitations** + +* The ``trylock`` and ``timedlock`` versions of acquiring locks are currently assumed to always succeed. + This can lead to false positives. + +.. code-block:: c + + void trylock_example(pthread_mutex_t *m) { + if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds + sleep(10); // warn: Call to blocking function 'sleep' inside of critical section + pthread_mutex_unlock(m); + } else { + sleep(10); // false positive: Incorrect warning about blocking function inside critical section. + } + } + .. _unix-Errno: unix.Errno (C) @@ -2818,55 +2985,6 @@ alpha.security.cert SEI CERT checkers which tries to find errors based on their `C coding rules `_. -.. _alpha-security-cert-pos-checkers: - -alpha.security.cert.pos -^^^^^^^^^^^^^^^^^^^^^^^ - -SEI CERT checkers of `POSIX C coding rules `_. - -.. _alpha-security-cert-pos-34c: - -alpha.security.cert.pos.34c -""""""""""""""""""""""""""" -Finds calls to the ``putenv`` function which pass a pointer to an automatic variable as the argument. - -.. code-block:: c - - int func(const char *var) { - char env[1024]; - int retval = snprintf(env, sizeof(env),"TEST=%s", var); - if (retval < 0 || (size_t)retval >= sizeof(env)) { - /* Handle error */ - } - - return putenv(env); // putenv function should not be called with auto variables - } - -Limitations: - - - Technically, one can pass automatic variables to ``putenv``, - but one needs to ensure that the given environment key stays - alive until it's removed or overwritten. - Since the analyzer cannot keep track of which envvars get overwritten - and when, it needs to be slightly more aggressive and warn for such - cases too, leading in some cases to false-positive reports like this: - - .. code-block:: c - - void baz() { - char env[] = "NAME=value"; - putenv(env); // false-positive warning: putenv function should not be called... - // More code... - putenv((char *)"NAME=anothervalue"); - // This putenv call overwrites the previous entry, thus that can no longer dangle. - } // 'env' array becomes dead only here. - -alpha.security.cert.env -^^^^^^^^^^^^^^^^^^^^^^^ - -SEI CERT checkers of `Environment C coding rules `_. - alpha.security.taint ^^^^^^^^^^^^^^^^^^^^ @@ -3103,24 +3221,6 @@ For a more detailed description of configuration options, please see the alpha.unix ^^^^^^^^^^ -.. _alpha-unix-BlockInCriticalSection: - -alpha.unix.BlockInCriticalSection (C) -""""""""""""""""""""""""""""""""""""" -Check for calls to blocking functions inside a critical section. -Applies to: ``lock, unlock, sleep, getc, fgets, read, recv, pthread_mutex_lock,`` -`` pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock`` - -.. code-block:: c - - void test() { - std::mutex m; - m.lock(); - sleep(3); // warn: a blocking function sleep is called inside a critical - // section - m.unlock(); - } - .. _alpha-unix-Chroot: alpha.unix.Chroot (C) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 365b607c741179e94146e57d3909e164857a9960..ce2282937f86cbc3144fc84ad226f64eea833a3a 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2150,7 +2150,11 @@ enum CXCursorKind { */ CXCursor_OpenACCComputeConstruct = 320, - CXCursor_LastStmt = CXCursor_OpenACCComputeConstruct, + /** OpenACC Loop Construct. + */ + CXCursor_OpenACCLoopConstruct = 321, + + CXCursor_LastStmt = CXCursor_OpenACCLoopConstruct, /** * Cursor that represents the translation unit itself. diff --git a/clang/include/clang/APINotes/APINotesManager.h b/clang/include/clang/APINotes/APINotesManager.h index 18375c9e51a173b7e21de4a4851adca9de79112e..98592438e90eab94b27242c32352d528b2cb9188 100644 --- a/clang/include/clang/APINotes/APINotesManager.h +++ b/clang/include/clang/APINotes/APINotesManager.h @@ -9,7 +9,6 @@ #ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H #define LLVM_CLANG_APINOTES_APINOTESMANAGER_H -#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -24,6 +23,7 @@ namespace clang { class DirectoryEntry; class FileEntry; class LangOptions; +class Module; class SourceManager; namespace api_notes { diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2ce2b810d3636498cb8f8fe27a427d22cb0ee612..a1d1d1c51cd417d18d4253eedb510b1e05f34f3e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -110,6 +110,9 @@ class VarTemplateDecl; class VTableContextBase; class XRayFunctionFilter; +/// A simple array of base specifiers. +typedef SmallVector CXXCastPath; + namespace Builtin { class Context; @@ -1170,6 +1173,12 @@ public: /// in device compilation. llvm::DenseSet CUDAImplicitHostDeviceFunUsedByDevice; + /// For capturing lambdas with an explicit object parameter whose type is + /// derived from the lambda type, we need to perform derived-to-base + /// conversion so we can access the captures; the cast paths for that + /// are stored here. + llvm::DenseMap LambdaCastPaths; + ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, TranslationUnitKind TUKind); diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index bf7c204e4ad73ab6408292215d3a839cc495c0ca..616f92691ec32375f665c4c67404715a698e0675 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -695,7 +695,7 @@ public: if (const auto *TC = D->getTypeConstraint()) Visit(TC->getImmediatelyDeclaredConstraint()); if (D->hasDefaultArgument()) - Visit(D->getDefaultArgument(), SourceRange(), + Visit(D->getDefaultArgument().getArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), D->defaultArgumentWasInherited() ? "inherited from" : "previous"); } @@ -704,9 +704,9 @@ public: if (const auto *E = D->getPlaceholderTypeConstraint()) Visit(E); if (D->hasDefaultArgument()) - Visit(D->getDefaultArgument(), SourceRange(), - D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" : "previous"); + dumpTemplateArgumentLoc( + D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(), + D->defaultArgumentWasInherited() ? "inherited from" : "previous"); } void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 5e485ccb85a1391c936b0ec803c96d927caa5033..7fd80b90d1033762d571eb5136e0503695535213 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2188,6 +2188,8 @@ public: void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } + void setDeclarationNameLoc(DeclarationNameLoc L) { DNLoc = L; } + /// Returns the location of the ellipsis of a variadic function. SourceLocation getEllipsisLoc() const { const auto *FPT = getType()->getAs(); diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index e43e812cd94558469ee5d6c53f6742dd89045e59..600ce73c7f01995adcfaa0a1bd05997289e02aef 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -670,6 +670,13 @@ public: /// Whether this declaration comes from another module unit. bool isInAnotherModuleUnit() const; + /// Whether the definition of the declaration should be emitted in external + /// sources. + bool shouldEmitInExternalSource() const; + + /// Whether this declaration comes from a named module; + bool isInNamedModule() const; + /// Whether this declaration comes from explicit global module. bool isFromExplicitGlobalModule() const; @@ -2148,6 +2155,10 @@ public: getDeclKind() <= Decl::lastRecord; } + bool isRequiresExprBody() const { + return getDeclKind() == Decl::RequiresExprBody; + } + bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isStdNamespace() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index f3d6a321ecf104c279a0b855f4e21c46474e7596..5b6a6b40b28ef8f507e0821befb156a7d3be14b9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1185,7 +1185,7 @@ class TemplateTypeParmDecl final : public TypeDecl, /// The default template argument, if any. using DefArgStorage = - DefaultArgStorage; + DefaultArgStorage; DefArgStorage DefaultArgument; TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, @@ -1225,13 +1225,9 @@ public: bool hasDefaultArgument() const { return DefaultArgument.isSet(); } /// Retrieve the default argument, if any. - QualType getDefaultArgument() const { - return DefaultArgument.get()->getType(); - } - - /// Retrieves the default argument's source information, if any. - TypeSourceInfo *getDefaultArgumentInfo() const { - return DefaultArgument.get(); + const TemplateArgumentLoc &getDefaultArgument() const { + static const TemplateArgumentLoc NoneLoc; + return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc; } /// Retrieves the location of the default argument declaration. @@ -1244,9 +1240,8 @@ public: } /// Set the default argument for this template parameter. - void setDefaultArgument(TypeSourceInfo *DefArg) { - DefaultArgument.set(DefArg); - } + void setDefaultArgument(const ASTContext &C, + const TemplateArgumentLoc &DefArg); /// Set that this default argument was inherited from another /// parameter. @@ -1365,7 +1360,8 @@ class NonTypeTemplateParmDecl final /// The default template argument, if any, and whether or not /// it was inherited. - using DefArgStorage = DefaultArgStorage; + using DefArgStorage = + DefaultArgStorage; DefArgStorage DefaultArgument; // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index @@ -1435,7 +1431,10 @@ public: bool hasDefaultArgument() const { return DefaultArgument.isSet(); } /// Retrieve the default argument, if any. - Expr *getDefaultArgument() const { return DefaultArgument.get(); } + const TemplateArgumentLoc &getDefaultArgument() const { + static const TemplateArgumentLoc NoneLoc; + return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc; + } /// Retrieve the location of the default argument, if any. SourceLocation getDefaultArgumentLoc() const; @@ -1449,7 +1448,8 @@ public: /// Set the default argument for this template parameter, and /// whether that default argument was inherited from another /// declaration. - void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); } + void setDefaultArgument(const ASTContext &C, + const TemplateArgumentLoc &DefArg); void setInheritedDefaultArgument(const ASTContext &C, NonTypeTemplateParmDecl *Parm) { DefaultArgument.setInherited(C, Parm); diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index dbf693611a7fa56edf7a9345d0613a3a1af71f59..d2e8d936563595a0794e26be565e960fbc86c14f 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3025,9 +3025,10 @@ protected: public: struct FindResult { - OverloadExpr *Expression; - bool IsAddressOfOperand; - bool HasFormOfMemberPointer; + OverloadExpr *Expression = nullptr; + bool IsAddressOfOperand = false; + bool IsAddressOfOperandWithParen = false; + bool HasFormOfMemberPointer = false; }; /// Finds the overloaded expression in the given expression \p E of @@ -3039,6 +3040,7 @@ public: assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); FindResult Result; + bool HasParen = isa(E); E = E->IgnoreParens(); if (isa(E)) { @@ -3048,10 +3050,9 @@ public: Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier()); Result.IsAddressOfOperand = true; + Result.IsAddressOfOperandWithParen = HasParen; Result.Expression = Ovl; } else { - Result.HasFormOfMemberPointer = false; - Result.IsAddressOfOperand = false; Result.Expression = cast(E); } diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 28ff8c44bd25698564251cb69d67e165f95bbd36..a4c82cdad87bda0caad72282bb285e5b4a8d6003 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -54,6 +54,149 @@ public: virtual ~OpenACCClause() = default; }; +// Represents the 'auto' clause. +class OpenACCAutoClause : public OpenACCClause { +protected: + OpenACCAutoClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Auto, BeginLoc, EndLoc) {} + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Auto; + } + + static OpenACCAutoClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +// Represents the 'independent' clause. +class OpenACCIndependentClause : public OpenACCClause { +protected: + OpenACCIndependentClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Independent, BeginLoc, EndLoc) {} + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Independent; + } + + static OpenACCIndependentClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; +// Represents the 'seq' clause. +class OpenACCSeqClause : public OpenACCClause { +protected: + OpenACCSeqClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Seq, BeginLoc, EndLoc) {} + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Seq; + } + + static OpenACCSeqClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so +// this provides a basic, do-nothing implementation. We still need to add this +// type to the visitors/etc, as well as get it to take its proper arguments. +class OpenACCGangClause : public OpenACCClause { +protected: + OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { + llvm_unreachable("Not yet implemented"); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Gang; + } + + static OpenACCGangClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so +// this provides a basic, do-nothing implementation. We still need to add this +// type to the visitors/etc, as well as get it to take its proper arguments. +class OpenACCVectorClause : public OpenACCClause { +protected: + OpenACCVectorClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Vector, BeginLoc, EndLoc) { + llvm_unreachable("Not yet implemented"); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Gang; + } + + static OpenACCVectorClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so +// this provides a basic, do-nothing implementation. We still need to add this +// type to the visitors/etc, as well as get it to take its proper arguments. +class OpenACCWorkerClause : public OpenACCClause { +protected: + OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { + llvm_unreachable("Not yet implemented"); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Gang; + } + + static OpenACCWorkerClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + /// Represents a clause that has a list of parameters. class OpenACCClauseWithParams : public OpenACCClause { /// Location of the '('. diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f5cefedb07e0eba340bd950b3c36769b5a39a774..aa55e2e7e87188d7d5fe41b3c7452202417c0dd7 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -30,6 +30,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenACCClause.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" @@ -510,6 +511,7 @@ private: bool TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S); bool VisitOpenACCClauseList(ArrayRef); + bool VisitOpenACCClause(const OpenACCClause *); }; template @@ -853,10 +855,14 @@ bool RecursiveASTVisitor::TraverseDeclarationNameInfo( template bool RecursiveASTVisitor::TraverseTemplateName(TemplateName Template) { - if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); - else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); + } else if (QualifiedTemplateName *QTN = + Template.getAsQualifiedTemplateName()) { + if (QTN->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); + } + } return true; } @@ -1960,7 +1966,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); TRY_TO(TraverseTemplateTypeParamDeclConstraints(D)); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); + TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument())); }) DEF_TRAVERSE_DECL(TypedefDecl, { @@ -2320,7 +2326,7 @@ DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { // A non-type template parameter, e.g. "S" in template class Foo ... TRY_TO(TraverseDeclaratorHelper(D)); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - TRY_TO(TraverseStmt(D->getDefaultArgument())); + TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument())); }) DEF_TRAVERSE_DECL(ParmVarDecl, { @@ -3967,9 +3973,26 @@ bool RecursiveASTVisitor::TraverseOpenACCAssociatedStmtConstruct( return true; } +template +bool RecursiveASTVisitor::VisitOpenACCClause(const OpenACCClause *C) { + for (const Stmt *Child : C->children()) + TRY_TO(TraverseStmt(const_cast(Child))); + return true; +} + template bool RecursiveASTVisitor::VisitOpenACCClauseList( - ArrayRef) { + ArrayRef Clauses) { + + for (const auto *C : Clauses) + TRY_TO(VisitOpenACCClause(C)); +// if (const auto *WithCond = dyn_cast(C); +// WithCond && WIthCond->hasConditionExpr()) { +// TRY_TO(TraverseStmt(WithCond->getConditionExpr()); +// } else if (const auto * +// } +// OpenACCClauseWithCondition::getConditionExpr/hasConditionExpr +//OpenACCClauseWithExprs::children (might be null?) // TODO OpenACC: When we have Clauses with expressions, we should visit them // here. return true; @@ -3977,6 +4000,8 @@ bool RecursiveASTVisitor::VisitOpenACCClauseList( DEF_TRAVERSE_STMT(OpenACCComputeConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) +DEF_TRAVERSE_STMT(OpenACCLoopConstruct, + { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index b706864798baaf3f156aafcd1aafc848261f2944..b3aea09be03ddf1789008c7ec96bd26465c72b9c 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -31,6 +31,8 @@ class OpenACCConstructStmt : public Stmt { /// The location of the directive statement, from the '#' to the last token of /// the directive. SourceRange Range; + /// The location of the directive name. + SourceLocation DirectiveLoc; /// The list of clauses. This is stored here as an ArrayRef, as this is the /// most convienient place to access the list, however the list itself should @@ -39,8 +41,9 @@ class OpenACCConstructStmt : public Stmt { protected: OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K, - SourceLocation Start, SourceLocation End) - : Stmt(SC), Kind(K), Range(Start, End) {} + SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End) + : Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {} // Used only for initialization, the leaf class can initialize this to // trailing storage. @@ -59,6 +62,7 @@ public: SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } + SourceLocation getDirectiveLoc() const { return DirectiveLoc; } ArrayRef clauses() const { return Clauses; } child_range children() { @@ -81,9 +85,11 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt { protected: OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K, - SourceLocation Start, SourceLocation End, - Stmt *AssocStmt) - : OpenACCConstructStmt(SC, K, Start, End), AssociatedStmt(AssocStmt) {} + SourceLocation Start, + SourceLocation DirectiveLoc, + SourceLocation End, Stmt *AssocStmt) + : OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End), + AssociatedStmt(AssocStmt) {} void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; } Stmt *getAssociatedStmt() { return AssociatedStmt; } @@ -107,6 +113,8 @@ public: return const_cast(this)->children(); } }; + +class OpenACCLoopConstruct; /// This class represents a compute construct, representing a 'Kind' of /// `parallel', 'serial', or 'kernel'. These constructs are associated with a /// 'structured block', defined as: @@ -126,10 +134,10 @@ class OpenACCComputeConstruct final friend class ASTStmtReader; friend class ASTContext; OpenACCComputeConstruct(unsigned NumClauses) - : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, - OpenACCDirectiveKind::Invalid, - SourceLocation{}, SourceLocation{}, - /*AssociatedStmt=*/nullptr) { + : OpenACCAssociatedStmtConstruct( + OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid, + SourceLocation{}, SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { // We cannot send the TrailingObjects storage to the base class (which holds // a reference to the data) until it is constructed, so we have to set it // separately here. @@ -141,11 +149,11 @@ class OpenACCComputeConstruct final } OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start, - SourceLocation End, + SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start, - End, StructuredBlock) { + DirectiveLoc, End, StructuredBlock) { assert(isOpenACCComputeDirectiveKind(K) && "Only parallel, serial, and kernels constructs should be " "represented by this type"); @@ -159,6 +167,11 @@ class OpenACCComputeConstruct final } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } + // Serialization helper function that searches the structured block for 'loop' + // constructs that should be associated with this, and sets their parent + // compute construct to this one. This isn't necessary normally, since we have + // the ability to record the state during parsing. + void findAndSetChildLoops(); public: static bool classof(const Stmt *T) { @@ -169,13 +182,75 @@ public: unsigned NumClauses); static OpenACCComputeConstruct * Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, - SourceLocation EndLoc, ArrayRef Clauses, - Stmt *StructuredBlock); + SourceLocation DirectiveLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *StructuredBlock, + ArrayRef AssociatedLoopConstructs); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { return const_cast(this)->getStructuredBlock(); } }; +/// This class represents a 'loop' construct. The 'loop' construct applies to a +/// 'for' loop (or range-for loop), and is optionally associated with a Compute +/// Construct. +class OpenACCLoopConstruct final + : public OpenACCAssociatedStmtConstruct, + public llvm::TrailingObjects { + // The compute construct this loop is associated with, or nullptr if this is + // an orphaned loop construct, or if it hasn't been set yet. Because we + // construct the directives at the end of their statement, the 'parent' + // construct is not yet available at the time of construction, so this needs + // to be set 'later'. + const OpenACCComputeConstruct *ParentComputeConstruct = nullptr; + + friend class ASTStmtWriter; + friend class ASTStmtReader; + friend class ASTContext; + friend class OpenACCComputeConstruct; + + OpenACCLoopConstruct(unsigned NumClauses); + + OpenACCLoopConstruct(SourceLocation Start, SourceLocation DirLoc, + SourceLocation End, + ArrayRef Clauses, Stmt *Loop); + void setLoop(Stmt *Loop); + + void setParentComputeConstruct(OpenACCComputeConstruct *CC) { + assert(!ParentComputeConstruct && "Parent already set?"); + ParentComputeConstruct = CC; + } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCLoopConstructClass; + } + + static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + + static OpenACCLoopConstruct * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation DirLoc, + SourceLocation EndLoc, ArrayRef Clauses, + Stmt *Loop); + + Stmt *getLoop() { return getAssociatedStmt(); } + const Stmt *getLoop() const { + return const_cast(this)->getLoop(); + } + + /// OpenACC 3.3 2.9: + /// An orphaned loop construct is a loop construct that is not lexically + /// enclosed within a compute construct. The parent compute construct of a + /// loop construct is the nearest compute construct that lexically contains + /// the loop construct. + bool isOrphanedLoopConstruct() const { + return ParentComputeConstruct == nullptr; + } + const OpenACCComputeConstruct *getParentComputeConstruct() const { + return ParentComputeConstruct; + } +}; } // namespace clang #endif // LLVM_CLANG_AST_STMTOPENACC_H diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index b7732e54ba1079f2d037e451f45bbe2e9dcec725..489fccb2ef74d6beb43614cc5c6127ed549e5983 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -314,11 +314,6 @@ public: TemplateName getUnderlying() const; - /// Get the template name to substitute when this template name is used as a - /// template template argument. This refers to the most recent declaration of - /// the template, including any default template arguments. - TemplateName getNameToSubstitute() const; - TemplateNameDependence getDependence() const; /// Determines whether this is a dependent template name. @@ -332,7 +327,7 @@ public: /// unexpanded parameter pack (for C++0x variadic templates). bool containsUnexpandedParameterPack() const; - enum class Qualified { None, AsWritten, Fully }; + enum class Qualified { None, AsWritten }; /// Print the template name. /// /// \param OS the output stream to which the template name will be @@ -360,6 +355,10 @@ public: static TemplateName getFromVoidPointer(void *Ptr) { return TemplateName(Ptr); } + + /// Structural equality. + bool operator==(TemplateName Other) const { return Storage == Other.Storage; } + bool operator!=(TemplateName Other) const { return !operator==(Other); } }; /// Insertion operator for diagnostics. This allows sending TemplateName's @@ -417,17 +416,18 @@ inline TemplateName TemplateName::getUnderlying() const { return *this; } -/// Represents a template name that was expressed as a -/// qualified name. +/// Represents a template name as written in source code. /// -/// This kind of template name refers to a template name that was +/// This kind of template name may refer to a template name that was /// preceded by a nested name specifier, e.g., \c std::vector. Here, /// the nested name specifier is "std::" and the template name is the -/// declaration for "vector". The QualifiedTemplateName class is only -/// used to provide "sugar" for template names that were expressed -/// with a qualified name, and has no semantic meaning. In this -/// manner, it is to TemplateName what ElaboratedType is to Type, -/// providing extra syntactic sugar for downstream clients. +/// declaration for "vector". It may also have been written with the +/// 'template' keyword. The QualifiedTemplateName class is only +/// used to provide "sugar" for template names, so that they can +/// be differentiated from canonical template names. and has no +/// semantic meaning. In this manner, it is to TemplateName what +/// ElaboratedType is to Type, providing extra syntactic sugar +/// for downstream clients. class QualifiedTemplateName : public llvm::FoldingSetNode { friend class ASTContext; diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1fede6e462e9253c253cc7cc302900084c2d48d6..abfafcaef271b6cbb989846e288eb558d53db5e5 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -213,6 +213,9 @@ public: void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); void dumpConceptReference(const ConceptReference *R); + void dumpTemplateArgument(const TemplateArgument &TA); + void dumpBareTemplateName(TemplateName TN); + void dumpTemplateName(TemplateName TN, StringRef Label = {}); void dumpDeclRef(const Decl *D, StringRef Label = {}); @@ -405,6 +408,7 @@ public: VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D); void VisitHLSLBufferDecl(const HLSLBufferDecl *D); void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S); + void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S); }; } // namespace clang diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 9a5c6e8d562c34a8a19cf26f79b1df442e1901fd..263b632df23ce42d00e9d04c6b7acbdf0b3d6df6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2515,6 +2515,7 @@ public: bool isRecordType() const; bool isClassType() const; bool isStructureType() const; + bool isStructureTypeWithFlexibleArrayMember() const; bool isObjCBoxableRecordType() const; bool isInterfaceType() const; bool isStructureOrClassType() const; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 0f3257db6f415fd7e8a6cda8f34f9cbb46a2df89..ca44c3ee085654947830ce7a44eacc0e021587bc 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -8371,20 +8371,28 @@ AST_MATCHER_P(Stmt, forCallable, internal::Matcher, InnerMatcher) { const auto &CurNode = Stack.back(); Stack.pop_back(); if (const auto *FuncDeclNode = CurNode.get()) { - if (InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + BoundNodesTreeBuilder B = *Builder; + if (InnerMatcher.matches(*FuncDeclNode, Finder, &B)) { + *Builder = std::move(B); return true; } } else if (const auto *LambdaExprNode = CurNode.get()) { + BoundNodesTreeBuilder B = *Builder; if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder, - Builder)) { + &B)) { + *Builder = std::move(B); return true; } } else if (const auto *ObjCMethodDeclNode = CurNode.get()) { - if (InnerMatcher.matches(*ObjCMethodDeclNode, Finder, Builder)) { + BoundNodesTreeBuilder B = *Builder; + if (InnerMatcher.matches(*ObjCMethodDeclNode, Finder, &B)) { + *Builder = std::move(B); return true; } } else if (const auto *BlockDeclNode = CurNode.get()) { - if (InnerMatcher.matches(*BlockDeclNode, Finder, Builder)) { + BoundNodesTreeBuilder B = *Builder; + if (InnerMatcher.matches(*BlockDeclNode, Finder, &B)) { + *Builder = std::move(B); return true; } } else { diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h index 05748f300a932f6e6c66c8821dba70d055664dc4..925b99af9141a3906625a5824cedae56008cc5b2 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h +++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "llvm/ADT/DenseSet.h" @@ -80,6 +81,52 @@ private: std::optional ImplicitValueInitForUnion; }; +/// Specialization of `RecursiveASTVisitor` that visits those nodes that are +/// relevant to the dataflow analysis; generally, these are the ones that also +/// appear in the CFG. +/// To start the traversal, call `TraverseStmt()` on the statement or body of +/// the function to analyze. Don't call `TraverseDecl()` on the function itself; +/// this won't work as `TraverseDecl()` contains code to avoid traversing nested +/// functions. +template +class AnalysisASTVisitor : public RecursiveASTVisitor { +public: + bool shouldVisitImplicitCode() { return true; } + + bool shouldVisitLambdaBody() const { return false; } + + bool TraverseDecl(Decl *D) { + // Don't traverse nested record or function declarations. + // - We won't be analyzing code contained in these anyway + // - We don't model fields that are used only in these nested declaration, + // so trying to propagate a result object to initializers of such fields + // would cause an error. + if (isa_and_nonnull(D) || isa_and_nonnull(D)) + return true; + + return RecursiveASTVisitor::TraverseDecl(D); + } + + // Don't traverse expressions in unevaluated contexts, as we don't model + // fields that are only used in these. + // Note: The operand of the `noexcept` operator is an unevaluated operand, but + // nevertheless it appears in the Clang CFG, so we don't exclude it here. + bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; } + bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; } + bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; } + bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) { + return true; + } + + bool TraverseBindingDecl(BindingDecl *BD) { + // `RecursiveASTVisitor` doesn't traverse holding variables for + // `BindingDecl`s by itself, so we need to tell it to. + if (VarDecl *HoldingVar = BD->getHoldingVar()) + TraverseDecl(HoldingVar); + return RecursiveASTVisitor::TraverseBindingDecl(BD); + } +}; + /// A collection of several types of declarations, all referenced from the same /// function. struct ReferencedDecls { diff --git a/clang/include/clang/Basic/ASTSourceDescriptor.h b/clang/include/clang/Basic/ASTSourceDescriptor.h new file mode 100644 index 0000000000000000000000000000000000000000..175e0551db76562637b6e47db2b46032fb245fb7 --- /dev/null +++ b/clang/include/clang/Basic/ASTSourceDescriptor.h @@ -0,0 +1,52 @@ +//===- ASTSourceDescriptor.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the clang::ASTSourceDescriptor class, which abstracts clang modules +/// and precompiled header files +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H +#define LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H + +#include "clang/Basic/Module.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { + +/// Abstracts clang modules and precompiled header files and holds +/// everything needed to generate debug info for an imported module +/// or PCH. +class ASTSourceDescriptor { + StringRef PCHModuleName; + StringRef Path; + StringRef ASTFile; + ASTFileSignature Signature; + Module *ClangModule = nullptr; + +public: + ASTSourceDescriptor() = default; + ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, + ASTFileSignature Signature) + : PCHModuleName(std::move(Name)), Path(std::move(Path)), + ASTFile(std::move(ASTFile)), Signature(Signature) {} + ASTSourceDescriptor(Module &M); + + std::string getModuleName() const; + StringRef getPath() const { return Path; } + StringRef getASTFile() const { return ASTFile; } + ASTFileSignature getSignature() const { return Signature; } + Module *getModuleOrNull() const { return ClangModule; } +}; + +} // namespace clang + +#endif // LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7008bea483c8723ee70efce35f207972fcaadea3..17d9a710d948b24d9e8781b1611bdf8f920b5cbc 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1060,18 +1060,10 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { .Case("ShaderModel", "shadermodel") .Default(Platform); } -static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) { - return llvm::StringSwitch(Environment) - .Case("pixel", "pixel shader") - .Case("vertex", "vertex shader") - .Case("geometry", "geometry shader") - .Case("hull", "hull shader") - .Case("domain", "domain shader") - .Case("compute", "compute shader") - .Case("mesh", "mesh shader") - .Case("amplification", "amplification shader") - .Case("library", "shader library") - .Default(Environment); +static llvm::StringRef getPrettyEnviromentName(llvm::Triple::EnvironmentType EnvironmentType) { + if (EnvironmentType >= llvm::Triple::Pixel && EnvironmentType <= llvm::Triple::Amplification) + return llvm::Triple::getEnvironmentTypeName(EnvironmentType); + return ""; } static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) { return llvm::StringSwitch(Environment) @@ -1081,6 +1073,12 @@ static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environm .Case("hull", llvm::Triple::Hull) .Case("domain", llvm::Triple::Domain) .Case("compute", llvm::Triple::Compute) + .Case("raygeneration", llvm::Triple::RayGeneration) + .Case("intersection", llvm::Triple::Intersection) + .Case("anyhit", llvm::Triple::AnyHit) + .Case("closesthit", llvm::Triple::ClosestHit) + .Case("miss", llvm::Triple::Miss) + .Case("callable", llvm::Triple::Callable) .Case("mesh", llvm::Triple::Mesh) .Case("amplification", llvm::Triple::Amplification) .Case("library", llvm::Triple::Library) @@ -1640,10 +1638,11 @@ def Unlikely : StmtAttr { def : MutualExclusions<[Likely, Unlikely]>; def CXXAssume : StmtAttr { - let Spellings = [CXX11<"", "assume", 202207>]; + let Spellings = [CXX11<"", "assume", 202207>, Clang<"assume">]; let Subjects = SubjectList<[NullStmt], ErrorDiag, "empty statements">; let Args = [ExprArgument<"Assumption">]; let Documentation = [CXXAssumeDocs]; + let HasCustomParsing = 1; } def NoMerge : DeclOrStmtAttr { @@ -2024,9 +2023,12 @@ def Convergent : InheritableAttr { def NoInline : DeclOrStmtAttr { let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">, CXX11<"clang", "noinline">, C23<"clang", "noinline">, + CXX11<"msvc", "noinline">, C23<"msvc", "noinline">, Declspec<"noinline">]; - let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">, - C23<"clang", "noinline">]>]; + let Accessors = [Accessor<"isStmtNoInline", [CXX11<"clang", "noinline">, + C23<"clang", "noinline">, + CXX11<"msvc", "noinline">, + C23<"msvc", "noinline">]>]; let Documentation = [NoInlineDocs]; let Subjects = SubjectList<[Function, Stmt], WarnDiag, "functions and statements">; @@ -2256,7 +2258,8 @@ def TypeNullUnspecified : TypeAttr { def CountedBy : DeclOrTypeAttr { let Spellings = [Clang<"counted_by">]; let Subjects = SubjectList<[Field], ErrorDiag>; - let Args = [ExprArgument<"Count">, IntArgument<"NestedLevel">]; + let Args = [ExprArgument<"Count">, IntArgument<"NestedLevel", 1>]; + let LateParsed = LateAttrParseExperimentalExt; let ParseArgumentsAsUnevaluated = 1; let Documentation = [CountedByDocs]; let LangOpts = [COnly]; @@ -3065,7 +3068,8 @@ def M68kRTD: DeclOrTypeAttr { let Documentation = [M68kRTDDocs]; } -def PreserveNone : DeclOrTypeAttr, TargetSpecificAttr { +def PreserveNone : DeclOrTypeAttr, + TargetSpecificAttr> { let Spellings = [Clang<"preserve_none">]; let Subjects = SubjectList<[FunctionLike]>; let Documentation = [PreserveNoneDocs]; @@ -4255,7 +4259,7 @@ def OMPDeclareVariant : InheritableAttr { } def OMPAssume : InheritableAttr { - let Spellings = [Clang<"assume">, CXX11<"omp", "assume">]; + let Spellings = [CXX11<"omp", "assume">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let InheritEvenIfAlreadyPresent = 1; let Documentation = [OMPAssumeDocs]; @@ -4475,6 +4479,30 @@ def HLSLShader : InheritableAttr { "Miss", "Callable", "Mesh", "Amplification"]> ]; let Documentation = [HLSLSV_ShaderTypeAttrDocs]; + let AdditionalMembers = +[{ + static const unsigned ShaderTypeMaxValue = (unsigned)HLSLShaderAttr::Amplification; + + static llvm::Triple::EnvironmentType getTypeAsEnvironment(HLSLShaderAttr::ShaderType ShaderType) { + switch (ShaderType) { + case HLSLShaderAttr::Pixel: return llvm::Triple::Pixel; + case HLSLShaderAttr::Vertex: return llvm::Triple::Vertex; + case HLSLShaderAttr::Geometry: return llvm::Triple::Geometry; + case HLSLShaderAttr::Hull: return llvm::Triple::Hull; + case HLSLShaderAttr::Domain: return llvm::Triple::Domain; + case HLSLShaderAttr::Compute: return llvm::Triple::Compute; + case HLSLShaderAttr::RayGeneration: return llvm::Triple::RayGeneration; + case HLSLShaderAttr::Intersection: return llvm::Triple::Intersection; + case HLSLShaderAttr::AnyHit: return llvm::Triple::AnyHit; + case HLSLShaderAttr::ClosestHit: return llvm::Triple::ClosestHit; + case HLSLShaderAttr::Miss: return llvm::Triple::Miss; + case HLSLShaderAttr::Callable: return llvm::Triple::Callable; + case HLSLShaderAttr::Mesh: return llvm::Triple::Mesh; + case HLSLShaderAttr::Amplification: return llvm::Triple::Amplification; + } + llvm_unreachable("unknown enumeration value"); + } +}]; } def HLSLResource : InheritableAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 54197d588eb45084e93e3d8b5eeec277feeee035..70d5dfa8aaf868c37bac59707c39f4e8a7df015d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2027,9 +2027,6 @@ Different optimisers are likely to react differently to the presence of this attribute; in some cases, adding ``assume`` may affect performance negatively. It should be used with parsimony and care. -Note that `clang::assume` is a different attribute. Always write ``assume`` -without a namespace if you intend to use the standard C++ attribute. - Example: .. code-block:: c++ @@ -4740,7 +4737,7 @@ def OMPAssumeDocs : Documentation { let Category = DocCatFunction; let Heading = "assume"; let Content = [{ -Clang supports the ``__attribute__((assume("assumption")))`` attribute to +Clang supports the ``[[omp::assume("assumption")]]`` attribute to provide additional information to the optimizer. The string-literal, here "assumption", will be attached to the function declaration such that later analysis and optimization passes can assume the "assumption" to hold. @@ -4752,7 +4749,7 @@ A function can have multiple assume attributes and they propagate from prior declarations to later definitions. Multiple assumptions are aggregated into a single comma separated string. Thus, one can provide multiple assumptions via a comma separated string, i.a., -``__attribute__((assume("assumption1,assumption2")))``. +``[[omp::assume("assumption1,assumption2")]]``. While LLVM plugins might provide more assumption strings, the default LLVM optimization passes are aware of the following assumptions: @@ -5663,18 +5660,21 @@ experimental at this time. def PreserveNoneDocs : Documentation { let Category = DocCatCallingConvs; let Content = [{ -On X86-64 target, this attribute changes the calling convention of a function. +On X86-64 and AArch64 targets, this attribute changes the calling convention of a function. The ``preserve_none`` calling convention tries to preserve as few general registers as possible. So all general registers are caller saved registers. It also uses more general registers to pass arguments. This attribute doesn't -impact floating-point registers (XMMs/YMMs). Floating-point registers still -follow the c calling convention. ``preserve_none``'s ABI is still unstable, and +impact floating-point registers. ``preserve_none``'s ABI is still unstable, and may be changed in the future. -- Only RSP and RBP are preserved by callee. - -- Register R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can - be used to pass function arguments. +- On X86-64, only RSP and RBP are preserved by the callee. + Registers R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can + be used to pass function arguments. Floating-point registers (XMMs/YMMs) still + follow the C calling convention. +- On AArch64, only LR and FP are preserved by the callee. + Registers X19-X28, X0-X7, and X9-X15 are used to pass function arguments. + X8, X16-X18, SIMD and floating-point registers follow the AAPCS calling + convention. }]; } diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index cf8711c6eaee37249f4a54effb379c733ab71d5e..5f53c98167dfb998fd10a69ce34c194d1a53fa2d 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -290,7 +290,7 @@ TARGET_HEADER_BUILTIN(_CountLeadingZeros64, "UiULLi", "nh", INTRIN_H, ALL_MS_LAN TARGET_HEADER_BUILTIN(_CountOneBits, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_CountOneBits64, "UiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__prefetch, "vv*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__prefetch, "vvC*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") #undef BUILTIN #undef LANGBUILTIN diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 3e21a2fe2ac6b31cc6bd09644884b2719c13fa3d..433c7795325f0c75c7418be4b9df8273bed172f3 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -68,7 +68,7 @@ BUILTIN(__builtin_amdgcn_sched_group_barrier, "vIiIiIi", "n") BUILTIN(__builtin_amdgcn_iglp_opt, "vIi", "n") BUILTIN(__builtin_amdgcn_s_dcache_inv, "v", "n") BUILTIN(__builtin_amdgcn_buffer_wbinvl1, "v", "n") -BUILTIN(__builtin_amdgcn_fence, "vUicC*", "n") +BUILTIN(__builtin_amdgcn_fence, "vUicC*.", "n") BUILTIN(__builtin_amdgcn_groupstaticsize, "Ui", "n") BUILTIN(__builtin_amdgcn_wavefrontsize, "Ui", "nc") @@ -240,6 +240,7 @@ TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2bf16, "V2sV2s*0V2s", "t", "at TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2bf16, "V2sV2s*1V2s", "t", "atomic-global-pk-add-bf16-inst") TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2bf16, "V2sV2s*3V2s", "t", "atomic-ds-pk-add-16-insts") TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2f16, "V2hV2h*3V2h", "t", "atomic-ds-pk-add-16-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_load_lds, "vv*1v*3UiiUi", "t", "gfx940-insts") //===----------------------------------------------------------------------===// // Deep learning builtins. diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def index 9e243d740ed7aec7e7b8b94f305478e6eba9011d..504314d8d96e91e72a8accf6bba8a6ac4c171aef 100644 --- a/clang/include/clang/Basic/BuiltinsNVPTX.def +++ b/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -62,7 +62,9 @@ #pragma push_macro("PTX82") #pragma push_macro("PTX83") #pragma push_macro("PTX84") -#define PTX84 "ptx84" +#pragma push_macro("PTX85") +#define PTX85 "ptx85" +#define PTX84 "ptx84|" PTX85 #define PTX83 "ptx83|" PTX84 #define PTX82 "ptx82|" PTX83 #define PTX81 "ptx81|" PTX82 @@ -1094,3 +1096,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78)) #pragma pop_macro("PTX82") #pragma pop_macro("PTX83") #pragma pop_macro("PTX84") +#pragma pop_macro("PTX85") diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index 8645cff1e8679f36d8595f19a165f9236014e71d..4e48ff48b60f5f0e9fc9f4176b62680af1fa7bb1 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -135,6 +135,10 @@ TARGET_BUILTIN(__builtin_wasm_min_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_pmin_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_pmax_f64x2, "V2dV2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_max_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_pmin_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_pmax_f16x8, "V8hV8hV8h", "nc", "half-precision") TARGET_BUILTIN(__builtin_wasm_ceil_f32x4, "V4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_floor_f32x4, "V4fV4f", "nc", "simd128") @@ -193,6 +197,8 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f" // Half-Precision (fp16) TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision") TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision") +TARGET_BUILTIN(__builtin_wasm_splat_f16x8, "V8hf", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_extract_lane_f16x8, "fV8hi", "nc", "half-precision") // Reference Types builtins // Some builtins are custom type-checked - see 't' as part of the third argument, diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index eafcc219c10966b8789182c486fb950c426c9e1d..7074479786b9730380ca13d2ec263220503fd6f0 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -832,23 +832,11 @@ TARGET_BUILTIN(__builtin_ia32_rsqrt14ss_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx TARGET_BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "ncV:512:", "avx512f,evex512") TARGET_BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "ncV:512:", "avx512f,evex512") -TARGET_BUILTIN(__builtin_ia32_rsqrt28sd_round_mask, "V2dV2dV2dV2dUcIi", "ncV:128:", "avx512er") -TARGET_BUILTIN(__builtin_ia32_rsqrt28ss_round_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512er") -TARGET_BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUcIi", "ncV:512:", "avx512er,evex512") -TARGET_BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsIi", "ncV:512:", "avx512er,evex512") - TARGET_BUILTIN(__builtin_ia32_rcp14sd_mask, "V2dV2dV2dV2dUc", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_rcp14ss_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "ncV:512:", "avx512f,evex512") TARGET_BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "ncV:512:", "avx512f,evex512") -TARGET_BUILTIN(__builtin_ia32_rcp28sd_round_mask, "V2dV2dV2dV2dUcIi", "ncV:128:", "avx512er") -TARGET_BUILTIN(__builtin_ia32_rcp28ss_round_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512er") -TARGET_BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUcIi", "ncV:512:", "avx512er,evex512") -TARGET_BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsIi", "ncV:512:", "avx512er,evex512") -TARGET_BUILTIN(__builtin_ia32_exp2pd_mask, "V8dV8dV8dUcIi", "ncV:512:", "avx512er,evex512") -TARGET_BUILTIN(__builtin_ia32_exp2ps_mask, "V16fV16fV16fUsIi", "ncV:512:", "avx512er,evex512") - TARGET_BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsIi", "ncV:512:", "avx512f,evex512") TARGET_BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsIi", "ncV:512:", "avx512f,evex512") TARGET_BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUcIi", "ncV:512:", "avx512f,evex512") @@ -960,15 +948,6 @@ TARGET_BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iIi", "nV:512:", "avx TARGET_BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8OiV8OiIi", "nV:512:", "avx512f,evex512") TARGET_BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8OiV8iIi", "nV:512:", "avx512f,evex512") -TARGET_BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8OivC*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8OivC*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8Oiv*IiIi", "nV:512:", "avx512pf,evex512") -TARGET_BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8Oiv*IiIi", "nV:512:", "avx512pf,evex512") - TARGET_BUILTIN(__builtin_ia32_knotqi, "UcUc", "nc", "avx512dq") TARGET_BUILTIN(__builtin_ia32_knothi, "UsUs", "nc", "avx512f") TARGET_BUILTIN(__builtin_ia32_knotsi, "UiUi", "nc", "avx512bw") diff --git a/clang/include/clang/Basic/CharInfo.h b/clang/include/clang/Basic/CharInfo.h index d80795531182871cef191348cac17b3978b789e7..87626eeb8a7004ea785a340f400a32072521d949 100644 --- a/clang/include/clang/Basic/CharInfo.h +++ b/clang/include/clang/Basic/CharInfo.h @@ -28,8 +28,7 @@ namespace charinfo { CHAR_LOWER = 0x0040, // a-z CHAR_UNDER = 0x0080, // _ CHAR_PERIOD = 0x0100, // . - CHAR_RAWDEL = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"' - CHAR_PUNCT = 0x0400 // `$@() + CHAR_PUNCT = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"'`$@() }; enum { @@ -152,7 +151,7 @@ LLVM_READONLY inline bool isHexDigit(unsigned char c) { /// Note that '_' is both a punctuation character and an identifier character! LLVM_READONLY inline bool isPunctuation(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0; + return (InfoTable[c] & (CHAR_UNDER | CHAR_PERIOD | CHAR_PUNCT)) != 0; } /// Return true if this character is an ASCII printable character; that is, a @@ -160,8 +159,8 @@ LLVM_READONLY inline bool isPunctuation(unsigned char c) { /// terminal. LLVM_READONLY inline bool isPrintable(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT| - CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0; + return (InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_PERIOD | CHAR_PUNCT | + CHAR_DIGIT | CHAR_UNDER | CHAR_SPACE)) != 0; } /// Return true if this is the body character of a C preprocessing number, @@ -175,8 +174,9 @@ LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) { /// Return true if this is the body character of a C++ raw string delimiter. LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD| - CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0; + return (InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_PERIOD | CHAR_DIGIT | + CHAR_UNDER | CHAR_PUNCT)) != 0 && + c != '(' && c != ')' && c != '\\'; } enum class EscapeChar { diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 2d67c4181d12957e0e1df2429e3c6a3f6935c40c..d15171d959c45abc4c92125743b91804d99f448b 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -42,9 +42,10 @@ enum class CudaVersion { CUDA_122, CUDA_123, CUDA_124, + CUDA_125, FULLY_SUPPORTED = CUDA_123, PARTIALLY_SUPPORTED = - CUDA_124, // Partially supported. Proceed with a warning. + CUDA_125, // Partially supported. Proceed with a warning. NEW = 10000, // Too new. Issue a warning, but allow using it. }; const char *CudaVersionToString(CudaVersion V); @@ -91,6 +92,7 @@ enum class CudaArch { GFX803, GFX805, GFX810, + GFX9_GENERIC, GFX900, GFX902, GFX904, @@ -102,10 +104,12 @@ enum class CudaArch { GFX940, GFX941, GFX942, + GFX10_1_GENERIC, GFX1010, GFX1011, GFX1012, GFX1013, + GFX10_3_GENERIC, GFX1030, GFX1031, GFX1032, @@ -113,12 +117,14 @@ enum class CudaArch { GFX1034, GFX1035, GFX1036, + GFX11_GENERIC, GFX1100, GFX1101, GFX1102, GFX1103, GFX1150, GFX1151, + GFX12_GENERIC, GFX1200, GFX1201, Generic, // A processor model named 'generic' if the target backend defines a diff --git a/clang/include/clang/Basic/CustomizableOptional.h b/clang/include/clang/Basic/CustomizableOptional.h index 84d40025ee41b15573f7815e2226f29c5f11c6c9..2d6ae6a781a550ce6350183392065ce97ac964a6 100644 --- a/clang/include/clang/Basic/CustomizableOptional.h +++ b/clang/include/clang/Basic/CustomizableOptional.h @@ -97,14 +97,6 @@ public: template T value_or(U &&alt) && { return has_value() ? std::move(operator*()) : std::forward(alt); } - - // Allow conversion to std::optional. - explicit operator std::optional &() const & { - return *this ? **this : std::optional(); - } - explicit operator std::optional &&() const && { - return *this ? std::move(**this) : std::optional(); - } }; template diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def index b94f6aef9ac60bf142d00a6be0c5c533107a80c9..bc96d5dfdf890bef53dfd79ec907bdf9e7b8197f 100644 --- a/clang/include/clang/Basic/DebugOptions.def +++ b/clang/include/clang/Basic/DebugOptions.def @@ -68,6 +68,8 @@ BENIGN_DEBUGOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain ///< inline line tables. DEBUGOPT(DebugStrictDwarf, 1, 1) ///< Whether or not to use strict DWARF info. +DEBUGOPT(DebugOmitUnreferencedMethods, 1, 0) ///< Omit unreferenced member + ///< functions in type debug info. /// Control the Assignment Tracking debug info feature. BENIGN_ENUM_DEBUGOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2, diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 0738f43ca555c8ecccbbf47bde2dba11afed4062..1e44bc4ad09b6b4e21a72b86f2114ca5e278dd3a 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -361,9 +361,6 @@ def warn_invalid_feature_combination : Warning< def warn_target_unrecognized_env : Warning< "mismatch between architecture and environment in target triple '%0'; did you mean '%1'?">, InGroup; -def warn_knl_knm_isa_support_removed : Warning< - "KNL, KNM related Intel Xeon Phi CPU's specific ISA's supports will be removed in LLVM 19.">, - InGroup>; def err_target_unsupported_abi_with_fpu : Error< "'%0' ABI is not supported with FPU">; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 9d97a75f696f668ac858ce08919b2f7339150d1f..773b234cd68fe57614c403750816f5ff5f479b0e 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -58,7 +58,7 @@ def warn_drv_avr_stdlib_not_linked: Warning< def err_drv_cuda_bad_gpu_arch : Error<"unsupported CUDA gpu architecture: %0">; def err_drv_offload_bad_gpu_arch : Error<"unsupported %0 gpu architecture: %1">; def err_drv_offload_missing_gpu_arch : Error< - "Must pass in an explicit %0 gpu architecture to '%1'">; + "must pass in an explicit %0 gpu architecture to '%1'">; def err_drv_no_cuda_installation : Error< "cannot find CUDA installation; provide its path via '--cuda-path', or pass " "'-nocudainc' to build without CUDA includes">; @@ -90,8 +90,8 @@ def err_drv_no_hipspv_device_lib : Error< "'--hip-path' or '--hip-device-lib-path', or pass '-nogpulib' to build " "without HIP device library">; def err_drv_hipspv_no_hip_path : Error< - "'--hip-path' must be specified when offloading to " - "SPIR-V%select{| unless %1 is given}0.">; + "'--hip-path' must be specified when offloading to SPIR-V unless '-nogpuinc' " + "is given">; // TODO: Remove when COV6 is fully supported by ROCm. def warn_drv_amdgpu_cov6: Warning< @@ -137,13 +137,13 @@ def warn_drv_unsupported_option_for_flang : Warning< "the argument '%0' is not supported for option '%1'. Mapping to '%1%2'">, InGroup; def warn_drv_unsupported_diag_option_for_flang : Warning< - "The warning option '-%0' is not supported">, + "the warning option '-%0' is not supported">, InGroup; def warn_drv_unsupported_option_for_processor : Warning< "ignoring '%0' option as it is not currently supported for processor '%1'">, InGroup; def warn_drv_unsupported_openmp_library : Warning< - "The library '%0=%1' is not supported, openmp is not be enabled">, + "the library '%0=%1' is not supported, OpenMP will not be enabled">, InGroup; def err_drv_invalid_thread_model_for_target : Error< @@ -356,7 +356,7 @@ def err_drv_expecting_fopenmp_with_fopenmp_targets : Error< "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">; def err_drv_failed_to_deduce_target_from_arch : Error< "failed to deduce triple for target architecture '%0'; specify the triple " - "using '-fopenmp-targets' and '-Xopenmp-target' instead.">; + "using '-fopenmp-targets' and '-Xopenmp-target' instead">; def err_drv_omp_offload_target_missingbcruntime : Error< "no library '%0' found in the default clang lib directory or in LIBRARY_PATH" "; use '--libomptarget-%1-bc-path' to specify %1 bitcode library">; @@ -515,14 +515,6 @@ def err_analyzer_checker_incompatible_analyzer_option : Error< def err_analyzer_not_built_with_z3 : Error< "analyzer constraint manager 'z3' is only available if LLVM was built with " "-DLLVM_ENABLE_Z3_SOLVER=ON">; -def warn_analyzer_deprecated_option : Warning< - "analyzer option '%0' is deprecated. This flag will be removed in %1, and " - "passing this option will be an error.">, - InGroup; -def warn_analyzer_deprecated_option_with_alternative : Warning< - "analyzer option '%0' is deprecated. This flag will be removed in %1, and " - "passing this option will be an error. Use '%2' instead.">, - InGroup; def warn_drv_needs_hvx : Warning< "%0 requires HVX, use -mhvx/-mhvx= to enable it">, @@ -555,10 +547,12 @@ def err_drv_extract_api_wrong_kind : Error< "in api extraction; use '-x %2' to override">; def err_drv_missing_symbol_graph_dir: Error< - "Must provide a symbol graph output directory using --symbol-graph-dir=">; + "must provide a symbol graph output directory using " + "'--symbol-graph-dir='">; def err_drv_unexpected_symbol_graph_output : Error< - "Unexpected output symbol graph '%1'; please provide --symbol-graph-dir= instead">; + "unexpected output symbol graph '%1'; please provide " + "'--symbol-graph-dir=' instead">; def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">, InGroup>; @@ -599,9 +593,6 @@ def warn_drv_unsupported_gpopt : Warning< "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" " usage of }0-mabicalls">, InGroup; -def warn_drv_unsupported_tocdata: Warning< - "ignoring '-mtocdata' as it is only supported for -mcmodel=small">, - InGroup; def warn_drv_unsupported_sdata : Warning< "ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">, InGroup; @@ -770,19 +761,19 @@ def err_drv_hlsl_16bit_types_unsupported: Error< "'%0' option requires target HLSL Version >= 2018%select{| and shader model >= 6.2}1, but HLSL Version is '%2'%select{| and shader model is '%3'}1">; def err_drv_hlsl_bad_shader_unsupported : Error< "%select{shader model|Vulkan environment|shader stage}0 '%1' in target '%2' is invalid for HLSL code generation">; -def warn_drv_dxc_missing_dxv : Warning<"dxv not found. " - "Resulting DXIL will not be validated or signed for use in release environments.">, - InGroup; +def warn_drv_dxc_missing_dxv : Warning< + "dxv not found; resulting DXIL will not be validated or signed for use in " + "release environment">, InGroup; def err_drv_invalid_range_dxil_validator_version : Error< - "invalid validator version : %0\n" - "Validator version must be less than or equal to current internal version.">; + "invalid validator version : %0; validator version must be less than or " + "equal to current internal version">; def err_drv_invalid_format_dxil_validator_version : Error< - "invalid validator version : %0\n" - "Format of validator version is \".\" (ex:\"1.4\").">; + "invalid validator version : %0; format of validator version is " + "\".\" (ex:\"1.4\")">; def err_drv_invalid_empty_dxil_validator_version : Error< - "invalid validator version : %0\n" - "If validator major version is 0, minor version must also be 0.">; + "invalid validator version : %0; if validator major version is 0, minor " + "version must also be 0">; def warn_drv_sarif_format_unstable : Warning< "diagnostic formatting in SARIF mode is currently unstable">, @@ -796,12 +787,10 @@ def warn_drv_loongarch_conflicting_implied_val : Warning< InGroup; def err_drv_loongarch_invalid_mfpu_EQ : Error< "invalid argument '%0' to -mfpu=; must be one of: 64, 32, none, 0 (alias for none)">; -def err_drv_loongarch_wrong_fpu_width_for_lsx : Error< - "wrong fpu width; LSX depends on 64-bit FPU.">; -def err_drv_loongarch_wrong_fpu_width_for_lasx : Error< - "wrong fpu width; LASX depends on 64-bit FPU.">; +def err_drv_loongarch_wrong_fpu_width : Error< + "wrong fpu width; %select{LSX|LASX}0 depends on 64-bit FPU">; def err_drv_loongarch_invalid_simd_option_combination : Error< - "invalid option combination; LASX depends on LSX.">; + "invalid option combination; LASX depends on LSX">; def err_drv_expand_response_file : Error< "failed to expand response file: %0">; @@ -813,9 +802,9 @@ def note_drv_available_multilibs : Note< "available multilibs are:%0">; def warn_android_unversioned_fallback : Warning< - "Using unversioned Android target directory %0 for target %1. Unversioned" - " directories will not be used in Clang 19. Provide a versioned directory" - " for the target version or lower instead.">, + "using unversioned Android target directory %0 for target %1; unversioned " + "directories will not be used in Clang 19 -- provide a versioned directory " + "for the target version or lower instead">, InGroup>; def err_drv_triple_version_invalid : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index e456ec2cac461c2bd39e67be8a87870ca7f23376..85c32e55bdab375f616fe5da3a17fbfe5c961a9b 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -71,14 +71,14 @@ def remark_fe_backend_optimization_remark_analysis : Remark<"%0">, BackendInfo, InGroup; def remark_fe_backend_optimization_remark_analysis_fpcommute : Remark<"%0; " "allow reordering by specifying '#pragma clang loop vectorize(enable)' " - "before the loop or by providing the compiler option '-ffast-math'.">, + "before the loop or by providing the compiler option '-ffast-math'">, BackendInfo, InGroup; def remark_fe_backend_optimization_remark_analysis_aliasing : Remark<"%0; " "allow reordering by specifying '#pragma clang loop vectorize(enable)' " - "before the loop. If the arrays will always be independent specify " + "before the loop; if the arrays will always be independent, specify " "'#pragma clang loop vectorize(assume_safety)' before the loop or provide " - "the '__restrict__' qualifier with the independent array arguments. " - "Erroneous results will occur if these options are incorrectly applied!">, + "the '__restrict__' qualifier with the independent array arguments -- " + "erroneous results will occur if these options are incorrectly applied">, BackendInfo, InGroup; def warn_fe_backend_optimization_failure : Warning<"%0">, BackendInfo, @@ -152,8 +152,8 @@ def warn_fe_serialized_diag_merge_failure : Warning< def warn_fe_serialized_diag_failure : Warning< "unable to open file %0 for serializing diagnostics (%1)">, InGroup; -def warn_fe_serialized_diag_failure_during_finalisation : Warning< - "Received warning after diagnostic serialization teardown was underway: %0">, +def warn_fe_serialized_diag_failure_during_finalization : Warning< + "received warning after diagnostic serialization teardown was underway: %0">, InGroup; def err_verify_missing_line : Error< @@ -337,7 +337,7 @@ def warn_atomic_op_oversized : Warning< InGroup; def warn_sync_op_misaligned : Warning< - "__sync builtin operation MUST have natural alignment (consider using __atomic).">, + "__sync builtin operation must have natural alignment (consider using __atomic)">, InGroup; def warn_alias_with_section : Warning< @@ -359,17 +359,16 @@ def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup; def warn_profile_data_misexpect : Warning< - "Potential performance regression from use of __builtin_expect(): " - "Annotation was correct on %0 of profiled executions.">, - BackendInfo, - InGroup; + "potential performance regression from use of __builtin_expect(): " + "annotation was correct on %0 of profiled executions">, + BackendInfo, InGroup; } // end of instrumentation issue category def err_extract_api_ignores_file_not_found : Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal; def warn_missing_symbol_graph_dir : Warning< - "Missing symbol graph output directory, defaulting to working directory">, + "missing symbol graph output directory, defaulting to working directory">, InGroup; def err_ast_action_on_llvm_ir : Error< diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 4cb4f3d999f7ab466de3794c11bb7692109ee801..7d5ba7869ec340a167cab2c2e4124c22145b3ad1 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -15,8 +15,6 @@ def Implicit : DiagGroup<"implicit", [ ImplicitInt ]>; -def DeprecatedStaticAnalyzerFlag : DiagGroup<"deprecated-static-analyzer-flag">; - // Empty DiagGroups are recognized by clang but ignored. def ODR : DiagGroup<"odr">; def : DiagGroup<"abi">; @@ -1447,6 +1445,10 @@ def FunctionMultiVersioning def NoDeref : DiagGroup<"noderef">; +// -fbounds-safety and bounds annotation related warnings +def BoundsSafetyCountedByEltTyUnknownSize : + DiagGroup<"bounds-safety-counted-by-elt-type-unknown-size">; + // A group for cross translation unit static analysis related warnings. def CrossTU : DiagGroup<"ctu">; @@ -1515,6 +1517,9 @@ def HLSLMixPackOffset : DiagGroup<"mix-packoffset">; // Warnings for DXIL validation def DXILValidation : DiagGroup<"dxil-validation">; +// Warning for HLSL API availability +def HLSLAvailability : DiagGroup<"hlsl-availability">; + // Warnings and notes related to const_var_decl_type attribute checks def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 944b2a38b6e9652c969c4e019d270dcd44ae6192..cdf27247602f2b02bcba384659604ebe16af5136 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -59,8 +59,8 @@ def err_platform_mismatch : Error<"platform does not match: '%0' (provided) vs ' def err_install_name_mismatch : Error<"install_name does not match: '%0' (provided) vs '%1' (found)">; def err_current_version_mismatch : Error<"current_version does not match: '%0' (provided) vs '%1' (found)">; def err_compatibility_version_mismatch : Error<"compatibility_version does not match: '%0' (provided) vs '%1' (found)">; -def err_appextension_safe_mismatch : Error<"ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">; -def err_shared_cache_eligiblity_mismatch : Error<"NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">; +def err_appextension_safe_mismatch : Error<"the ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">; +def err_shared_cache_eligiblity_mismatch : Error<"the NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">; def err_no_twolevel_namespace : Error<"flat namespace libraries are not supported">; def err_parent_umbrella_missing: Error<"parent umbrella missing from %0: '%1'">; def err_parent_umbrella_mismatch : Error<"parent umbrella does not match: '%0' (provided) vs '%1' (found)">; diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ad6bacfb118d49f26b60f8795ca3679406becccf..25fbfe83fa2bcf9b3491fa4af38f0d6612a40ed9 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -111,6 +111,14 @@ def warn_cxx98_compat_raw_string_literal : Warning< "raw string literals are incompatible with C++98">, InGroup, DefaultIgnore; +def warn_cxx26_compat_raw_string_literal_character_set : Warning< + " '%0' in a raw string literal delimiter is incompatible " + "with standards before C++2c">, + InGroup, DefaultIgnore; +def ext_cxx26_raw_string_literal_character_set : Extension< + " '%0' in a raw string literal delimiter is a C++2c extension">, + InGroup, DefaultIgnore; + def warn_multichar_character_literal : Warning< "multi-character character constant">, InGroup; def warn_four_char_character_literal : Warning< @@ -991,5 +999,5 @@ def err_pp_unclosed_pragma_unsafe_buffer_usage : Error<"'#pragma unsafe_buffer_usage' was not ended">; def err_pp_pragma_unsafe_buffer_usage_syntax : -Error<"Expected 'begin' or 'end'">; +Error<"expected 'begin' or 'end'">; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 46656fc66044d21d483f5679a74f1dd458c00806..d8c3fee7841f437eb461c5111140391d414f567b 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -887,6 +887,10 @@ def err_requires_expr_in_simple_requirement : Error< "requires expression in requirement body; did " "you intend to place it in a nested requirement? (add another 'requires' " "before the expression)">; +def missing_template_arg_list_after_template_kw : Extension< + "a template argument list is expected after a name prefixed by the template " + "keyword">, InGroup>, + DefaultError; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; @@ -1117,7 +1121,7 @@ def err_availability_expected_environment : Error< // objc_bridge_related attribute def err_objcbridge_related_expected_related_class : Error< - "expected a related ObjectiveC class name, e.g., 'NSColor'">; + "expected a related Objective-C class name, e.g., 'NSColor'">; def err_objcbridge_related_selector_name : Error< "expected a class method selector with single argument, e.g., 'colorWithCGColor:'">; @@ -1345,8 +1349,8 @@ def note_pragma_attribute_namespace_on_attribute : Note< "omit the namespace to add attributes to the most-recently" " pushed attribute group">; def warn_no_support_for_eval_method_source_on_m32 : Warning< - "Setting the floating point evaluation method to `source` on a target" - " without SSE is not supported.">, InGroup; + "setting the floating point evaluation method to `source` on a target " + "without SSE is not supported">, InGroup; // - #pragma __debug def warn_pragma_debug_dependent_argument : Warning< "%select{value|type}0-dependent expression passed as an argument to debug " diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c7dea1d54d06371a2750dbea666270d6685074e7..87745140cb0ebd187331eb463f611f463ae07663 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -310,7 +310,7 @@ def err_invalid_vector_long_double_decl_spec : Error< def err_invalid_vector_complex_decl_spec : Error< "cannot use '_Complex' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< - "Use of 'long' with '__vector' is deprecated">, InGroup; + "use of 'long' with '__vector' is deprecated">, InGroup; def err_redeclaration_different_type : Error< "redeclaration of %0 with a different type%diff{: $ vs $|}1,2">; @@ -754,7 +754,7 @@ def note_include_header_or_declare : Note< def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; def warn_implicit_decl_no_jmp_buf : Warning<"declaration of built-in function '%0' requires the declaration" - " of the 'jmp_buf' type, commonly provided in the header .">, + " of the 'jmp_buf' type, commonly provided in the header ">, InGroup>; def warn_implicit_decl_requires_sysheader : Warning< "declaration of built-in function '%1' requires inclusion of the header <%0>">, @@ -855,7 +855,7 @@ def note_strncat_wrong_size : Note< "the terminating null byte">; def warn_assume_side_effects : Warning< - "the argument to %0 has side effects that will be discarded">, + "assumption is ignored because it contains (potential) side-effects">, InGroup>; def warn_omp_assume_attribute_string_unknown : Warning< "unknown assumption string '%0'; attribute is potentially ignored">, @@ -3197,7 +3197,7 @@ def err_attribute_bad_sve_vector_size : Error< "'-msve-vector-bits' ('%1')">; def err_attribute_arm_feature_sve_bits_unsupported : Error< "%0 is only supported when '-msve-vector-bits=' is specified with a " - "value of 128, 256, 512, 1024 or 2048.">; + "value of 128, 256, 512, 1024 or 2048">; def warn_attribute_arm_sm_incompat_builtin : Warning< "builtin call has undefined behaviour when called from a %0 function">, InGroup>; @@ -3975,7 +3975,7 @@ def warn_acquired_before : Warning< "%0 '%1' must be acquired before '%2'">, InGroup, DefaultIgnore; def warn_acquired_before_after_cycle : Warning< - "Cycle in acquired_before/after dependencies, starting with '%0'">, + "cycle in acquired_before/after dependencies, starting with '%0'">, InGroup, DefaultIgnore; @@ -4526,7 +4526,7 @@ def err_objc_attr_typedef_not_void_pointer : Error< def err_objc_cf_bridged_not_interface : Error< "CF object of type %0 is bridged to %1, which is not an Objective-C class">; def err_objc_ns_bridged_invalid_cfobject : Error< - "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">; + "Objective-C object of type %0 is bridged to %1, which is not valid CF object">; def warn_objc_invalid_bridge : Warning< "%0 bridges to %1, not %2">, InGroup; def warn_objc_invalid_bridge_to_cf : Warning< @@ -6544,8 +6544,10 @@ def warn_superclass_variable_sized_type_not_at_end : Warning< def err_flexible_array_count_not_in_same_struct : Error< "'counted_by' field %0 isn't within the same struct as the flexible array">; -def err_counted_by_attr_not_on_flexible_array_member : Error< - "'counted_by' only applies to C99 flexible array members">; +def err_counted_by_attr_not_on_ptr_or_flexible_array_member : Error< + "'counted_by' only applies to pointers or C99 flexible array members">; +def err_counted_by_attr_on_array_not_flexible_array_member : Error< + "'counted_by' on arrays only applies to C99 flexible array members">; def err_counted_by_attr_refer_to_itself : Error< "'counted_by' cannot refer to the flexible array member %0">; def err_counted_by_must_be_in_structure : Error< @@ -6560,6 +6562,23 @@ def err_counted_by_attr_refer_to_union : Error< "'counted_by' argument cannot refer to a union member">; def note_flexible_array_counted_by_attr_field : Note< "field %0 declared here">; +def err_counted_by_attr_pointee_unknown_size : Error< + "'counted_by' %select{cannot|should not}3 be applied to %select{" + "a pointer with pointee|" // pointer + "an array with element}0" // array + " of unknown size because %1 is %select{" + "an incomplete type|" // CountedByInvalidPointeeTypeKind::INCOMPLETE + "a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS + "a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION + // CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER + "a struct type with a flexible array member" + "%select{|. This will be an error in a future compiler version}3" + "" + "}2">; + +def warn_counted_by_attr_elt_type_unknown_size : + Warning, + InGroup; let CategoryName = "ARC Semantic Issue" in { @@ -7525,6 +7544,11 @@ def err_explicit_object_parameter_mutable: Error< def err_invalid_explicit_object_type_in_lambda: Error< "invalid explicit object parameter type %0 in lambda with capture; " "the type must be the same as, or derived from, the lambda">; +def err_explicit_object_lambda_ambiguous_base : Error< + "lambda %0 is inaccessible due to ambiguity:%1">; +def err_explicit_object_lambda_inaccessible_base : Error< + "invalid explicit object parameter type %0 in lambda with capture; " + "the type must derive publicly from the lambda">; def err_ref_qualifier_overload : Error< "cannot overload a member function %select{without a ref-qualifier|with " @@ -7997,15 +8021,15 @@ def warn_deprecated_volatile_structured_binding : Warning< InGroup; def warn_deprecated_altivec_src_compat : Warning< - "Current handling of vector bool and vector pixel types in this context are " - "deprecated. The default behaviour will soon change to that implied by the " + "current handling of vector bool and vector pixel types in this context are " + "deprecated; the default behaviour will soon change to that implied by the " "'-altivec-compat=xl' option">, InGroup>; def warn_deprecated_lax_vec_conv_all : Warning< - "Implicit conversion between vector types ('%0' and '%1') is deprecated. " - "In the future, the behavior implied by '-fno-lax-vector-conversions' " - "will be the default.">, + "implicit conversion between vector types ('%0' and '%1') is deprecated; " + "in the future, the behavior implied by '-fno-lax-vector-conversions' " + "will be the default">, InGroup>; def err_catch_incomplete_ptr : Error< @@ -8836,8 +8860,10 @@ def err_builtin_fn_use : Error<"builtin functions must be directly called">; def warn_call_wrong_number_of_arguments : Warning< "too %select{few|many}0 arguments in call to %1">; + def err_atomic_builtin_must_be_pointer : Error< - "address argument to atomic builtin must be a pointer (%0 invalid)">; + "address argument to atomic builtin must be a pointer %select{|to a non-zero-sized object }1(%0 invalid)">; + def err_atomic_builtin_must_be_pointer_intptr : Error< "address argument to atomic builtin must be a pointer to integer or pointer" " (%0 invalid)">; @@ -8853,7 +8879,7 @@ def err_atomic_exclusive_builtin_pointer_size : Error< "address argument to load or store exclusive builtin must be a pointer to" " 1,2,4 or 8 byte type (%0 invalid)">; def err_atomic_builtin_ext_int_size : Error< - "Atomic memory operand must have a power-of-two size">; + "atomic memory operand must have a power-of-two size">; def err_atomic_builtin_bit_int_prohibit : Error< "argument to atomic builtin of type '_BitInt' is not supported">; def err_atomic_op_needs_atomic : Error< @@ -8961,8 +8987,8 @@ def err_va_arg_in_device : Error< def err_alias_not_supported_on_nvptx : Error<"CUDA older than 10.0 does not support .alias">; def err_cuda_unattributed_constexpr_cannot_overload_device : Error< "constexpr function %0 without __host__ or __device__ attributes cannot " - "overload __device__ function with same signature. Add a __host__ " - "attribute, or build with -fno-cuda-host-device-constexpr.">; + "overload __device__ function with the same signature; add a __host__ " + "attribute, or build with -fno-cuda-host-device-constexpr">; def note_cuda_conflicting_device_function_declared_here : Note< "conflicting __device__ function declared here">; def err_cuda_device_exceptions : Error< @@ -8970,9 +8996,9 @@ def err_cuda_device_exceptions : Error< "%select{__device__|__global__|__host__|__host__ __device__}1 function">; def err_dynamic_var_init : Error< "dynamic initialization is not supported for " - "__device__, __constant__, __shared__, and __managed__ variables.">; + "__device__, __constant__, __shared__, and __managed__ variables">; def err_shared_var_init : Error< - "initialization is not supported for __shared__ variables.">; + "initialization is not supported for __shared__ variables">; def err_cuda_vla : Error< "cannot use variable-length arrays in " "%select{__device__|__global__|__host__|__host__ __device__}0 functions">; @@ -10056,12 +10082,6 @@ def warn_new_dangling_initializer_list : Warning< "the allocated initializer list}0 " "will be destroyed at the end of the full-expression">, InGroup; -def warn_unsupported_lifetime_extension : Warning< - "lifetime extension of " - "%select{temporary|backing array of initializer list}0 created " - "by aggregate initialization using a default member initializer " - "is not yet supported; lifetime of %select{temporary|backing array}0 " - "will end at the end of the full-expression">, InGroup; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. @@ -10237,9 +10257,6 @@ def err_fallthrough_attr_outside_switch : Error< def err_fallthrough_attr_invalid_placement : Error< "fallthrough annotation does not directly precede switch label">; -def err_assume_attr_args : Error< - "attribute '%0' requires a single expression argument">; - def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, InGroup, DefaultIgnore; @@ -10365,12 +10382,12 @@ def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error< - "index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 not permitted in a constexpr context.">; + "index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 is not permitted in a constexpr context">; def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; def err_convertvector_constexpr_unsupported_vector_cast : Error< - "unsupported vector cast from %0 to %1 in a constant expression.">; + "unsupported vector cast from %0 to %1 in a constant expression">; def err_builtin_non_vector_type : Error< "%0 argument to %1 must be of vector type">; def err_convertvector_incompatible_vector : Error< @@ -10698,7 +10715,7 @@ def err_kernel_arg_address_space : Error< "pointer arguments to kernel functions must reside in '__global', " "'__constant' or '__local' address space">; def err_opencl_ext_vector_component_invalid_length : Error< - "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">; + "vector component access has invalid length %0; supported lengths are: 1,2,3,4,8,16">; def err_opencl_function_variable : Error< "%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">; def err_opencl_addrspace_scope : Error< @@ -11146,12 +11163,12 @@ def err_omp_atomic_compare : Error< "the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}'," " '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}'," " 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type," - " and 'ordop' is one of '<' or '>'.">; + " and 'ordop' is one of '<' or '>'">; def err_omp_atomic_compare_capture : Error< "the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}'," " '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}'," " 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x', 'r', and 'v' are lvalue expressions with scalar type, 'expr', 'e', and 'd' are expressions with scalar type," - " and 'ordop' is one of '<' or '>'.">; + " and 'ordop' is one of '<' or '>'">; def note_omp_atomic_compare: Note< "%select{expected compound statement|expected exactly one expression statement|expected assignment statement|expected conditional operator|expect result value to be at false expression|" "expect binary operator in conditional expression|expect '<', '>' or '==' as order operator|expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'|" @@ -11317,7 +11334,7 @@ def err_omp_expected_int_param : Error< def err_omp_at_least_one_motion_clause_required : Error< "expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'">; def err_omp_cannot_update_with_internal_linkage : Error< - "the host cannot update a declare target variable that is not externally visible.">; + "the host cannot update a declare target variable that is not externally visible">; def err_omp_usedeviceptr_not_a_pointer : Error< "expected pointer or reference to pointer in 'use_device_ptr' clause">; def err_omp_argument_type_isdeviceptr : Error < @@ -11338,10 +11355,10 @@ def err_omp_reduction_vla_unsupported : Error< def err_omp_linear_distribute_var_non_loop_iteration : Error< "only loop iteration variables are allowed in 'linear' clause in distribute directives">; def warn_omp_non_trivial_type_mapped : Warning< - "Type %0 is not trivially copyable and not guaranteed to be mapped correctly">, + "type %0 is not trivially copyable and not guaranteed to be mapped correctly">, InGroup; def err_omp_requires_clause_redeclaration : Error < - "Only one %0 clause can appear on a requires directive in a single translation unit">; + "only one %0 clause can appear on a requires directive in a single translation unit">; def note_omp_requires_previous_clause : Note < "%0 clause previously used here">; def err_omp_directive_before_requires : Error < @@ -11349,7 +11366,7 @@ def err_omp_directive_before_requires : Error < def note_omp_requires_encountered_directive : Note < "'%0' previously encountered here">; def err_omp_device_ancestor_without_requires_reverse_offload : Error < - "Device clause with ancestor device-modifier used without specifying 'requires reverse_offload'">; + "device clause with ancestor device-modifier used without specifying 'requires reverse_offload'">; def err_omp_invalid_scope : Error < "'#pragma omp %0' directive must appear only in file scope">; def note_omp_invalid_length_on_this_ptr_mapping : Note < @@ -11761,7 +11778,7 @@ def note_await_ready_no_bool_conversion : Note< "return type of 'await_ready' is required to be contextually convertible to 'bool'" >; def warn_coroutine_handle_address_invalid_return_type : Warning < - "return type of 'coroutine_handle<>::address should be 'void*' (have %0) in order to get capability with existing async C API.">, + "return type of 'coroutine_handle<>::address should be 'void*' (have %0) in order to get capability with existing async C API">, InGroup; def err_coroutine_promise_final_suspend_requires_nothrow : Error< "the expression 'co_await __promise.final_suspend()' is required to be non-throwing" @@ -11789,7 +11806,7 @@ def err_conflicting_aligned_options : Error < "conflicting option '-fcoro-aligned-allocation' and '-fno-aligned-allocation'" >; def err_coro_invalid_addr_of_label : Error< - "the GNU address of label extension is not allowed in coroutines." + "the GNU address of label extension is not allowed in coroutines" >; def err_coroutine_return_type : Error< "function returns a type %0 marked with [[clang::coro_return_type]] but is neither a coroutine nor a coroutine wrapper; " @@ -12222,6 +12239,13 @@ def err_hlsl_param_qualifier_mismatch : def warn_hlsl_impcast_vector_truncation : Warning< "implicit conversion truncates vector: %0 to %1">, InGroup; +def warn_hlsl_availability : Warning< + "%0 is only available %select{|in %4 environment }3on %1 %2 or newer">, + InGroup, DefaultError; +def warn_hlsl_availability_unavailable : + Warning, + InGroup, DefaultError; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; @@ -12374,7 +12398,10 @@ def err_acc_var_not_pointer_type def note_acc_expected_pointer_var : Note<"expected variable of pointer type">; def err_acc_clause_after_device_type : Error<"OpenACC clause '%0' may not follow a '%1' clause in a " - "compute construct">; + "%select{'%3'|compute}2 construct">; +def err_acc_clause_cannot_combine + : Error<"OpenACC clause '%0' may not appear on the same construct as a " + "'%1' clause on a 'loop' construct">; def err_acc_reduction_num_gangs_conflict : Error< "OpenACC 'reduction' clause may not appear on a 'parallel' construct " @@ -12389,4 +12416,14 @@ def err_acc_reduction_composite_type 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 'loop' construct can only be applied to a 'for' loop">; +def note_acc_construct_here : Note<"'%0' construct is here">; +def err_acc_loop_spec_conflict + : Error<"OpenACC clause '%0' on '%1' construct conflicts with previous " + "data dependence clause">; + +// AMDGCN builtins diagnostics +def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; +def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">; } // end of sema component. diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 8b4206e52cd482bc10ce449a176c447b1dcb0218..e1f33d57a898099e3366b11ac530e9882bdf872a 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -299,6 +299,8 @@ private: getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile, bool RequiresNullTerminator) const; + DirectoryEntry *&getRealDirEntry(const llvm::vfs::Status &Status); + public: /// Get the 'stat' information for the given \p Path. /// diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 09eb92d6f10d23028a4151c6fe675e3e16b5f120..2dea3cd4d795b4216599586bff2852c70eb234d8 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -300,6 +300,7 @@ LANGOPT(HIPStdParInterposeAlloc, 1, 0, "Replace allocations / deallocations with LANGOPT(OpenACC , 1, 0, "OpenACC Enabled") +LANGOPT(MSVCEnableStdcMacro , 1, 0, "Define __STDC__ with '-fms-compatibility'") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") @@ -504,6 +505,14 @@ COMPATIBLE_LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process sta BENIGN_LANGOPT(CheckNew, 1, 0, "Do not assume C++ operator new may not return NULL") +// FIXME: It would be better for us to find a way to encode the state of this +// diagnostic in tablegen so that we can specify a particular diagnostic option +// is disabled or enabled based on other language options or made it easier to +// do this from the compiler invocation without hitting option round-tripping +// issues. +BENIGN_LANGOPT(CheckConstexprFunctionBodies, 1, 1, + "Emit diagnostics for a constexpr function body that can never " + "be used in a constant expression.") #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 2d62d05cd91900da0c6f9da273a4d457c0adb306..e86f4303d732b8d497c90215450fe1108ea5723a 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -868,32 +868,6 @@ private: unsigned Generation = 0; }; -/// Abstracts clang modules and precompiled header files and holds -/// everything needed to generate debug info for an imported module -/// or PCH. -class ASTSourceDescriptor { - StringRef PCHModuleName; - StringRef Path; - StringRef ASTFile; - ASTFileSignature Signature; - Module *ClangModule = nullptr; - -public: - ASTSourceDescriptor() = default; - ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, - ASTFileSignature Signature) - : PCHModuleName(std::move(Name)), Path(std::move(Path)), - ASTFile(std::move(ASTFile)), Signature(Signature) {} - ASTSourceDescriptor(Module &M); - - std::string getModuleName() const; - StringRef getPath() const { return Path; } - StringRef getASTFile() const { return ASTFile; } - ASTFileSignature getSignature() const { return Signature; } - Module *getModuleOrNull() const { return ClangModule; } -}; - - } // namespace clang #endif // LLVM_CLANG_BASIC_MODULE_H diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index 3e464abaafd928a183acde5bc2ee677d35269899..53f4cd103d142ce6cf915e200e4ad9e9064ccd9e 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -21,6 +21,7 @@ #define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME) #endif +VISIT_CLAUSE(Auto) VISIT_CLAUSE(Async) VISIT_CLAUSE(Attach) VISIT_CLAUSE(Copy) @@ -41,6 +42,7 @@ VISIT_CLAUSE(DeviceType) CLAUSE_ALIAS(DType, DeviceType) VISIT_CLAUSE(FirstPrivate) VISIT_CLAUSE(If) +VISIT_CLAUSE(Independent) VISIT_CLAUSE(NoCreate) VISIT_CLAUSE(NumGangs) VISIT_CLAUSE(NumWorkers) @@ -48,6 +50,7 @@ VISIT_CLAUSE(Present) VISIT_CLAUSE(Private) VISIT_CLAUSE(Reduction) VISIT_CLAUSE(Self) +VISIT_CLAUSE(Seq) VISIT_CLAUSE(VectorLength) VISIT_CLAUSE(Wait) diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 305f19daa4a9238fff2d9a755fb163da2ff06dfc..6ca08abdb14f072d8f1d5a060737156e4c77bcd1 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -302,3 +302,4 @@ def OpenACCConstructStmt : StmtNode; def OpenACCAssociatedStmtConstruct : StmtNode; def OpenACCComputeConstruct : StmtNode; +def OpenACCLoopConstruct : StmtNode; diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index 80e635e4a57eca78ac1413ced1d49f5a5da7a22a..564a58e4eb6709eafad66e54da6ea502e9f7c3be 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -146,6 +146,25 @@ let TargetGuard = "sme" in { [IsOverloadNone, IsStreamingCompatible, IsOutZA]>; } +let TargetGuard = "sme2p1" in { + def SVZERO_ZA64_VG1x2 : SInst<"svzero_za64_vg1x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x2", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG1x4 : SInst<"svzero_za64_vg1x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x4", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG2x1 : SInst<"svzero_za64_vg2x1", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x1", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG2x2 : SInst<"svzero_za64_vg2x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x2", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG2x4 : SInst<"svzero_za64_vg2x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x4", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG4x1 : SInst<"svzero_za64_vg4x1", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x1", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG4x2 : SInst<"svzero_za64_vg4x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x2", + [IsOverloadNone, IsStreaming, IsInOutZA]>; + def SVZERO_ZA64_VG4x4 : SInst<"svzero_za64_vg4x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x4", + [IsOverloadNone, IsStreaming, IsInOutZA]>; +} + //////////////////////////////////////////////////////////////////////////////// // SME - Counting elements in a streaming vector diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index a9ea71cd077740d4fff1bb8f0d3951d14030addb..88938a981fd8ae12a3ad47cdd7d5d43cce5bd8f2 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -2151,6 +2151,11 @@ let TargetGuard = "sme2" in { def SVFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "hfd", MergeNone, "aarch64_sve_fclamp_single_x4", [IsStreaming], []>; } +let TargetGuard = "sme2,b16b16"in { + def SVBFCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x2", [IsStreaming], []>; + def SVBFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x4", [IsStreaming], []>; +} + let TargetGuard = "sme2" in { // == ADD (vectors) == def SVADD_SINGLE_X2 : SInst<"svadd[_single_{d}_x2]", "22d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_single_x2", [IsStreaming], []>; @@ -2186,9 +2191,6 @@ let TargetGuard = "sme2" in { def SVSQRSHRUN_X4 : SInst<"svqrshrun[_n]_{0}[_{d}_x4]", "b4i", "il", MergeNone, "aarch64_sve_sqrshrun_x4", [IsStreaming], [ImmCheck<1, ImmCheckShiftRight, 0>]>; - def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [IsStreamingCompatible], []>; - def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [IsStreamingCompatible], []>; - // SQDMULH def SVSQDMULH_SINGLE_X2 : SInst<"svqdmulh[_single_{d}_x2]", "22d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx2", [IsStreaming], []>; def SVSQDMULH_SINGLE_X4 : SInst<"svqdmulh[_single_{d}_x4]", "44d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx4", [IsStreaming], []>; @@ -2197,6 +2199,9 @@ let TargetGuard = "sme2" in { } let TargetGuard = "sve2p1|sme2" in { + def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [IsStreamingCompatible], []>; + def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [IsStreamingCompatible], []>; + // SQRSHRN / UQRSHRN def SVQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "h2i", "i", MergeNone, "aarch64_sve_sqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>; def SVUQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "e2i", "Ui", MergeNone, "aarch64_sve_uqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>; @@ -2265,6 +2270,10 @@ let TargetGuard = "sme2" in { def SVCVT_S32_F32_X4 : SInst<"svcvt_{d}[_f32_x4]", "4.d4.M", "i", MergeNone, "aarch64_sve_fcvtzs_x4", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>; } +let TargetGuard = "sme-f16f16" in { + def SVCVT_F32_X2 : SInst<"svcvt_{d}[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvt_widen_x2", [ IsStreaming],[]>; +} + // // Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16 // @@ -2273,6 +2282,13 @@ let TargetGuard = "sme2" in { def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>; } +// +//Multi-vector floating-point convert from half-precision to deinterleaved single-precision. +// +let TargetGuard = "sme-f16f16" in { + def SVCVTL_F32_X2 : SInst<"svcvtl_f32[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvtl_widen_x2", [ IsStreaming],[]>; +} + // // Multi-vector saturating extract narrow // diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7bb781667e926c1d7fbfc9dd9925d76596de496e..f04c220d6e1dbe6a8fa6202dd61d2edd7ccbebfa 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -557,6 +557,17 @@ multiclass BoolMOption; } +/// Creates a BoolOption where both of the flags are prefixed with "W", are in +/// the Group. +/// Used for -cc1 frontend options. Driver-only options do not map to +/// CompilerInvocation. +multiclass BoolWOption> { + defm NAME : BoolOption<"W", flag_base, kpm, default, flag1, flag2, both>, + Group; +} + // Works like BoolOption except without marshalling multiclass BoolOptionWithoutMarshalling // Key paths that are constant during parsing of options with the same key path prefix. defvar cplusplus = LangOpts<"CPlusPlus">; defvar cpp11 = LangOpts<"CPlusPlus11">; +defvar cpp14 = LangOpts<"CPlusPlus14">; defvar cpp17 = LangOpts<"CPlusPlus17">; defvar cpp20 = LangOpts<"CPlusPlus20">; +defvar cpp23 = LangOpts<"CPlusPlus23">; defvar c99 = LangOpts<"C99">; defvar c23 = LangOpts<"C23">; defvar lang_std = LangOpts<"LangStd">; @@ -960,6 +973,12 @@ def Wdeprecated : Flag<["-"], "Wdeprecated">, Group, HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">; def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group, Visibility<[ClangOption, CC1Option]>; +defm invalid_constexpr : BoolWOption<"invalid-constexpr", + LangOpts<"CheckConstexprFunctionBodies">, + Default, + NegFlag, + PosFlag, + BothFlags<[], [ClangOption, CC1Option], " checking of constexpr function bodies for validity within a constant expression context">>; def Wl_COMMA : CommaJoined<["-"], "Wl,">, Visibility<[ClangOption, FlangOption]>, Flags<[LinkerInput, RenderAsInput]>, HelpText<"Pass the comma separated arguments in to the linker">, @@ -2980,6 +2999,10 @@ def fms_compatibility : Flag<["-"], "fms-compatibility">, Group, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Enable full Microsoft Visual C++ compatibility">, MarshallingInfoFlag>; +def fms_define_stdc : Flag<["-"], "fms-define-stdc">, Group, + Visibility<[ClangOption, CC1Option, CLOption]>, + HelpText<"Define '__STDC__' to '1' in MSVC Compatibility mode">, + MarshallingInfoFlag>; def fms_extensions : Flag<["-"], "fms-extensions">, Group, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">, @@ -3388,10 +3411,9 @@ defm relaxed_template_template_args : BoolFOption<"relaxed-template-template-arg NegFlag, BothFlags<[], [ClangOption], " C++17 relaxed template template argument matching">>; defm sized_deallocation : BoolFOption<"sized-deallocation", - LangOpts<"SizedDeallocation">, DefaultFalse, - PosFlag, - NegFlag>; + LangOpts<"SizedDeallocation">, Default, + PosFlag, + NegFlag, BothFlags<[], [ClangOption, CC1Option]>>; defm aligned_allocation : BoolFOption<"aligned-allocation", LangOpts<"AlignedAllocation">, Default, PosFlag, @@ -3570,7 +3592,7 @@ def fopenmp_offload_mandatory : Flag<["-"], "fopenmp-offload-mandatory">, Group< HelpText<"Do not create a host fallback if offloading to the device fails.">, MarshallingInfoFlag>; def fopenmp_force_usm : Flag<["-"], "fopenmp-force-usm">, Group, - Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>, + Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Force behvaior as if the user specified pragma omp requires unified_shared_memory.">, MarshallingInfoFlag>; def fopenmp_target_jit : Flag<["-"], "fopenmp-target-jit">, Group, @@ -4341,6 +4363,10 @@ defm strict_dwarf : BoolOption<"g", "strict-dwarf", "the specified version, avoiding features from later versions.">, NegFlag, BothFlags<[], [ClangOption, CLOption, DXCOption]>>, Group; +defm omit_unreferenced_methods : BoolGOption<"omit-unreferenced-methods", + CodeGenOpts<"DebugOmitUnreferencedMethods">, DefaultFalse, + NegFlag, + PosFlag, BothFlags<[], [ClangOption, CLOption, DXCOption]>>; defm column_info : BoolOption<"g", "column-info", CodeGenOpts<"DebugColumnInfo">, DefaultTrue, NegFlag, @@ -6111,14 +6137,10 @@ def mavx512cd : Flag<["-"], "mavx512cd">, Group; def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group; def mavx512dq : Flag<["-"], "mavx512dq">, Group; def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group; -def mavx512er : Flag<["-"], "mavx512er">, Group; -def mno_avx512er : Flag<["-"], "mno-avx512er">, Group; def mavx512fp16 : Flag<["-"], "mavx512fp16">, Group; def mno_avx512fp16 : Flag<["-"], "mno-avx512fp16">, Group; def mavx512ifma : Flag<["-"], "mavx512ifma">, Group; def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group; -def mavx512pf : Flag<["-"], "mavx512pf">, Group; -def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group; def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group; def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group; def mavx512vbmi2 : Flag<["-"], "mavx512vbmi2">, Group; @@ -6209,8 +6231,6 @@ def mpopcnt : Flag<["-"], "mpopcnt">, Group; def mno_popcnt : Flag<["-"], "mno-popcnt">, Group; def mprefetchi : Flag<["-"], "mprefetchi">, Group; def mno_prefetchi : Flag<["-"], "mno-prefetchi">, Group; -def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group; -def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group; def mprfchw : Flag<["-"], "mprfchw">, Group; def mno_prfchw : Flag<["-"], "mno-prfchw">, Group; def mptwrite : Flag<["-"], "mptwrite">, Group; @@ -6279,11 +6299,11 @@ def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">; def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group, HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">; -// Features egpr, push2pop2, ppx and ndd are validated with llvm-test-suite && cpu2017 on Intel SDE. -// For stability, we turn on these features only for -mapxf. After a feature pass the validation, -// we will add it to -mapxf. -def mapxf : Flag<["-"], "mapxf">, Alias, AliasArgs<["egpr","push2pop2","ppx", "ndd"]>; -def mno_apxf : Flag<["-"], "mno-apxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd"]>; +// For stability, we only add a feature to -mapxf after it passes the validation of llvm-test-suite && cpu2017 on Intel SDE. +def mapxf : Flag<["-"], "mapxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; +def mno_apxf : Flag<["-"], "mno-apxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; +def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group, + HelpText<"Enable use of GPR32 in inline assembly for APX">; } // let Flags = [TargetSpecific] // VE feature flags @@ -8312,6 +8332,9 @@ def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">, Alias; def _SLASH_X : CLFlag<"X">, HelpText<"Do not add %INCLUDE% to include search path">, Alias; +def _SLASH_Zc___STDC__ : CLFlag<"Zc:__STDC__">, + HelpText<"Define __STDC__">, + Alias; def _SLASH_Zc_sizedDealloc : CLFlag<"Zc:sizedDealloc">, HelpText<"Enable C++14 sized global deallocation functions">, Alias; diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h index 8ccebe457ed530c486c7e78f0b0c29fd5fadd602..76d7fd798bed3a632b0d9045e2ad6d18516763b5 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -21,6 +21,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" @@ -127,7 +128,7 @@ public: protected: /// Collect API information for the enum constants and associate with the /// parent enum. - void recordEnumConstants(EnumRecord *EnumRecord, + void recordEnumConstants(SymbolReference Container, const EnumDecl::enumerator_range Constants); /// Collect API information for the Objective-C methods and associate with the @@ -248,12 +249,8 @@ protected: clang::index::generateUSRForDecl(Tag, TagUSR); if (auto *Record = llvm::dyn_cast_if_present( API.findRecordForUSR(TagUSR))) { - if (Record->IsEmbeddedInVarDeclarator) { + if (Record->IsEmbeddedInVarDeclarator) NewRecordContext->stealRecordChain(*Record); - auto *NewRecord = cast(NewRecordContext); - if (NewRecord->Comment.empty()) - NewRecord->Comment = Record->Comment; - } } } }; @@ -394,17 +391,6 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; - SmallString<128> QualifiedNameBuffer; - // Collect symbol information. - StringRef Name = Decl->getName(); - if (Name.empty()) - Name = getTypedefName(Decl); - if (Name.empty()) { - llvm::raw_svector_ostream OS(QualifiedNameBuffer); - Decl->printQualifiedName(OS); - Name = QualifiedNameBuffer; - } - SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = @@ -420,13 +406,29 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto *ER = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl)); + + // Collect symbol information. + SymbolReference ParentContainer; + + if (Decl->hasNameForLinkage()) { + StringRef Name = Decl->getName(); + if (Name.empty()) + Name = getTypedefName(Decl); + + auto *ER = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl), false); + ParentContainer = SymbolReference(ER); + } else { + // If this an anonymous enum then the parent scope of the constants is the + // top level namespace. + ParentContainer = {}; + } // Now collect information about the enumerators in this enum. - getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators()); + getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer, + Decl->enumerators()); return true; } @@ -1197,7 +1199,7 @@ bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( /// parent enum. template void ExtractAPIVisitorBase::recordEnumConstants( - EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) { + SymbolReference Container, const EnumDecl::enumerator_range Constants) { for (const auto *Constant : Constants) { // Collect symbol information. StringRef Name = Constant->getName(); @@ -1218,9 +1220,8 @@ void ExtractAPIVisitorBase::recordEnumConstants( DeclarationFragmentsBuilder::getSubHeading(Constant); API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Constant), Loc, - AvailabilityInfo::createFromDecl(Constant), Comment, Declaration, - SubHeading, isInSystemHeader(Constant)); + USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant), + Comment, Declaration, SubHeading, isInSystemHeader(Constant)); } } @@ -1469,7 +1470,17 @@ public: bool shouldDeclBeIncluded(const Decl *D) const { return true; } const RawComment *fetchRawCommentForDecl(const Decl *D) const { - return this->Context.getRawCommentForDeclNoCache(D); + if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D)) + return Comment; + + if (const auto *Declarator = dyn_cast(D)) { + const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl(); + if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() && + TagTypeDecl->isCompleteDefinition()) + return this->Context.getRawCommentForDeclNoCache(TagTypeDecl); + } + + return nullptr; } }; diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h index 27e9167ca1ad0222cc2a3d523576b2124ad20460..f8759bf2d8f25a01ed0282494d31f30a78ae525b 100644 --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -17,7 +17,6 @@ #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H -#include "clang/Basic/Module.h" #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/APIIgnoresList.h" #include "clang/ExtractAPI/Serialization/APISetVisitor.h" diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 274b45d1bc586555cf037024023b50d0188c68e1..4fd6e013df25bbba4443ec679c418993992d6dc4 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -480,15 +480,21 @@ struct FormatStyle { ENAS_DontAlign, /// Align escaped newlines as far left as possible. /// \code - /// true: /// #define A \ /// int aaaa; \ /// int b; \ /// int dddddddddd; - /// - /// false: /// \endcode ENAS_Left, + /// Align escaped newlines as far left as possible, using the last line of + /// the preprocessor directive as the reference if it's the longest. + /// \code + /// #define A \ + /// int aaaa; \ + /// int b; \ + /// int dddddddddd; + /// \endcode + ENAS_LeftWithLastLine, /// Align escaped newlines in the right-most column. /// \code /// #define A \ @@ -808,8 +814,8 @@ struct FormatStyle { enum ShortFunctionStyle : int8_t { /// Never merge functions into a single line. SFS_None, - /// Only merge functions defined inside a class. Same as "inline", - /// except it does not implies "empty": i.e. top level empty functions + /// Only merge functions defined inside a class. Same as ``inline``, + /// except it does not implies ``empty``: i.e. top level empty functions /// are not merged either. /// \code /// class Foo { @@ -830,7 +836,7 @@ struct FormatStyle { /// } /// \endcode SFS_Empty, - /// Only merge functions defined inside a class. Implies "empty". + /// Only merge functions defined inside a class. Implies ``empty``. /// \code /// class Foo { /// void f() { foo(); } @@ -1161,7 +1167,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// AttributeMacros: ['__capability', '__output', '__unused'] + /// AttributeMacros: [__capability, __output, __unused] /// \endcode /// /// \version 12 @@ -2625,7 +2631,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// ForEachMacros: ['RANGES_FOR', 'FOREACH'] + /// ForEachMacros: [RANGES_FOR, FOREACH] /// \endcode /// /// For example: BOOST_FOREACH. @@ -2647,7 +2653,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// IfMacros: ['IF'] + /// IfMacros: [IF] /// \endcode /// /// For example: `KJ_IF_MAYBE @@ -3024,7 +3030,7 @@ struct FormatStyle { /// in the following yaml example. This will result in imports being /// formatted as in the Java example below. /// \code{.yaml} - /// JavaImportGroups: ['com.example', 'com', 'org'] + /// JavaImportGroups: [com.example, com, org] /// \endcode /// /// \code{.java} @@ -3080,7 +3086,7 @@ struct FormatStyle { /// VeryLongImportsAreAnnoying, /// VeryLongImportsAreAnnoying, /// VeryLongImportsAreAnnoying, - /// } from 'some/module.js' + /// } from "some/module.js" /// /// false: /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" @@ -3609,7 +3615,7 @@ struct FormatStyle { /// Change specifiers/qualifiers to be aligned based on ``QualifierOrder``. /// With: /// \code{.yaml} - /// QualifierOrder: ['inline', 'static', 'type', 'const'] + /// QualifierOrder: [inline, static, type, const] /// \endcode /// /// \code @@ -3644,15 +3650,15 @@ struct FormatStyle { /// * type /// /// \note - /// it MUST contain 'type'. + /// It **must** contain ``type``. /// \endnote /// - /// Items to the left of 'type' will be placed to the left of the type and - /// aligned in the order supplied. Items to the right of 'type' will be + /// Items to the left of ``type`` will be placed to the left of the type and + /// aligned in the order supplied. Items to the right of ``type`` will be /// placed to the right of the type and aligned in the order supplied. /// /// \code{.yaml} - /// QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ] + /// QualifierOrder: [inline, static, type, const, volatile] /// \endcode /// \version 14 std::vector QualifierOrder; @@ -3686,10 +3692,10 @@ struct FormatStyle { /// name will be reformatted assuming the specified language based on the /// style for that language defined in the .clang-format file. If no style has /// been defined in the .clang-format file for the specific language, a - /// predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not - /// found, the formatting is based on llvm style. A matching delimiter takes - /// precedence over a matching enclosing function name for determining the - /// language of the raw string contents. + /// predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is + /// not found, the formatting is based on ``LLVM`` style. A matching delimiter + /// takes precedence over a matching enclosing function name for determining + /// the language of the raw string contents. /// /// If a canonical delimiter is specified, occurrences of other delimiters for /// the same language will be updated to the canonical if possible. @@ -3702,17 +3708,17 @@ struct FormatStyle { /// RawStringFormats: /// - Language: TextProto /// Delimiters: - /// - 'pb' - /// - 'proto' + /// - pb + /// - proto /// EnclosingFunctions: - /// - 'PARSE_TEXT_PROTO' + /// - PARSE_TEXT_PROTO /// BasedOnStyle: google /// - Language: Cpp /// Delimiters: - /// - 'cc' - /// - 'cpp' - /// BasedOnStyle: llvm - /// CanonicalDelimiter: 'cc' + /// - cc + /// - cpp + /// BasedOnStyle: LLVM + /// CanonicalDelimiter: cc /// \endcode /// \version 6 std::vector RawStringFormats; @@ -4040,7 +4046,7 @@ struct FormatStyle { /// /// This determines the maximum length of short namespaces by counting /// unwrapped lines (i.e. containing neither opening nor closing - /// namespace brace) and makes "FixNamespaceComments" omit adding + /// namespace brace) and makes ``FixNamespaceComments`` omit adding /// end comments for those. /// \code /// ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 @@ -4132,7 +4138,7 @@ struct FormatStyle { /// \endcode SUD_Never, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by "::" and discard any initial empty strings. Sort + /// Split the strings by ``::`` and discard any initial empty strings. Sort /// the lists of names lexicographically, and within those groups, names are /// in case-insensitive lexicographic order. /// \code @@ -4144,7 +4150,7 @@ struct FormatStyle { /// \endcode SUD_Lexicographic, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by "::" and discard any initial empty strings. The + /// Split the strings by ``::`` and discard any initial empty strings. The /// last element of each list is a non-namespace name; all others are /// namespace names. Sort the lists of names lexicographically, where the /// sort order of individual names is that all non-namespace names come @@ -4180,7 +4186,7 @@ struct FormatStyle { /// \version 9 bool SpaceAfterLogicalNot; - /// If \c true, a space will be inserted after the 'template' keyword. + /// If \c true, a space will be inserted after the ``template`` keyword. /// \code /// true: false: /// template void foo(); vs. template void foo(); @@ -4310,7 +4316,7 @@ struct FormatStyle { /// \endcode SBPO_ControlStatementsExceptControlMacros, /// Put a space before opening parentheses only if the parentheses are not - /// empty i.e. '()' + /// empty. /// \code /// void() { /// if (true) { @@ -4662,7 +4668,7 @@ struct FormatStyle { /// x = ( int32 )y vs. x = (int32)y /// \endcode bool InCStyleCasts; - /// Put a space in parentheses only if the parentheses are empty i.e. '()' + /// Insert a space in empty parentheses, i.e. ``()``. /// \code /// true: false: /// void f( ) { vs. void f() { @@ -4798,11 +4804,11 @@ struct FormatStyle { /// For example the configuration, /// \code{.yaml} /// TableGenBreakInsideDAGArg: BreakAll - /// TableGenBreakingDAGArgOperators: ['ins', 'outs'] + /// TableGenBreakingDAGArgOperators: [ins, outs] /// \endcode /// /// makes the line break only occurs inside DAGArgs beginning with the - /// specified identifiers 'ins' and 'outs'. + /// specified identifiers ``ins`` and ``outs``. /// /// \code /// let DAGArgIns = (ins @@ -4867,7 +4873,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// TypenameMacros: ['STACK_OF', 'LIST'] + /// TypenameMacros: [STACK_OF, LIST] /// \endcode /// /// For example: OpenSSL STACK_OF, BSD LIST_ENTRY. @@ -4923,7 +4929,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE'] + /// WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] /// \endcode /// /// For example: BOOST_PP_STRINGIZE diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 970e0245417b5198b03b32f5ba4ee20ffe218128..1234608bb58647148f4d37006e408919b4c63c0d 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -110,9 +110,9 @@ class Interpreter { RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr; protected: - // Derived classes can make use an extended interface of the Interpreter. - // That's useful for testing and out-of-tree clients. - Interpreter(std::unique_ptr CI, llvm::Error &Err); + // Derived classes can use an extended interface of the Interpreter. + Interpreter(std::unique_ptr CI, llvm::Error &Err, + std::unique_ptr JITBuilder = nullptr); // Create the internal IncrementalExecutor, or re-create it after calling // ResetExecutor(). @@ -128,13 +128,6 @@ protected: // custom runtime. virtual std::unique_ptr FindRuntimeInterface(); - // Lazily construct thev ORCv2 JITBuilder. This called when the internal - // IncrementalExecutor is created. The default implementation populates an - // in-process JIT with debugging support. Override this to configure the JIT - // engine used for execution. - virtual llvm::Expected> - CreateJITBuilder(CompilerInstance &CI); - public: virtual ~Interpreter(); @@ -189,6 +182,8 @@ private: llvm::DenseMap Dtors; llvm::SmallVector ValuePrintingInfo; + + std::unique_ptr JITBuilder; }; } // namespace clang diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 3c4ab649e3b4c12f67e61cc019e43a55a466b159..d054b8cf0d24057079bae53619d5dc7d8940328a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -467,15 +467,18 @@ class Parser : public CodeCompletionHandler { /// Flags describing a context in which we're parsing a statement. enum class ParsedStmtContext { + /// This context permits declarations in language modes where declarations + /// are not statements. + AllowDeclarationsInC = 0x1, /// This context permits standalone OpenMP directives. - AllowStandaloneOpenMPDirectives = 0x1, + AllowStandaloneOpenMPDirectives = 0x2, /// This context is at the top level of a GNU statement expression. - InStmtExpr = 0x2, + InStmtExpr = 0x4, /// The context of a regular substatement. SubStmt = 0, /// The context of a compound-statement. - Compound = AllowStandaloneOpenMPDirectives, + Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives, LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr) }; @@ -1646,8 +1649,12 @@ private: void ParseLexedAttributes(ParsingClass &Class); void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition); + void ParseLexedCAttributeList(LateParsedAttrList &LA, bool EnterScope, + ParsedAttributes *OutAttrs = nullptr); void ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope, bool OnDefinition); + void ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope, + ParsedAttributes *OutAttrs = nullptr); void ParseLexedMethodDeclarations(ParsingClass &Class); void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); void ParseLexedMethodDefs(ParsingClass &Class); @@ -2534,7 +2541,8 @@ private: void ParseStructDeclaration( ParsingDeclSpec &DS, - llvm::function_ref FieldsCallback); + llvm::function_ref FieldsCallback, + LateParsedAttrList *LateFieldAttrs = nullptr); DeclGroupPtrTy ParseTopLevelStmtDecl(); @@ -2814,7 +2822,7 @@ private: SourceLocation CorrectLocation); void stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, DeclSpec &DS, - Sema::TagUseKind TUK); + TagUseKind TUK); // FixItLoc = possible correct location for the attributes void ProhibitAttributes(ParsedAttributes &Attrs, @@ -2997,7 +3005,8 @@ private: bool ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, IdentifierInfo *AttrName, SourceLocation AttrNameLoc, - SourceLocation *EndLoc); + SourceLocation *EndLoc, + ParsedAttr::Form Form); IdentifierInfo *TryParseCXX11AttributeIdentifier( SourceLocation &Loc, @@ -3112,6 +3121,8 @@ private: SourceLocation ScopeLoc, ParsedAttr::Form Form); + void DistributeCLateParsedAttrs(Decl *Dcl, LateParsedAttrList *LateAttrs); + void ParseBoundsAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, @@ -3648,6 +3659,7 @@ private: struct OpenACCDirectiveParseInfo { OpenACCDirectiveKind DirKind; SourceLocation StartLoc; + SourceLocation DirLoc; SourceLocation EndLoc; SmallVector Clauses; // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and diff --git a/clang/include/clang/Sema/Attr.h b/clang/include/clang/Sema/Attr.h new file mode 100644 index 0000000000000000000000000000000000000000..3f0b10212789a4d9378067f3e56f0f65f2cb597d --- /dev/null +++ b/clang/include/clang/Sema/Attr.h @@ -0,0 +1,192 @@ +//===----- Attr.h --- Helper functions for attribute handling in Sema -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides helpers for Sema functions that handle attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ATTR_H +#define LLVM_CLANG_SEMA_ATTR_H + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/Support/Casting.h" + +namespace clang { + +/// isFuncOrMethodForAttrSubject - Return true if the given decl has function +/// type (function or function-typed variable) or an Objective-C +/// method. +inline bool isFuncOrMethodForAttrSubject(const Decl *D) { + return (D->getFunctionType() != nullptr) || llvm::isa(D); +} + +/// Return true if the given decl has function type (function or +/// function-typed variable) or an Objective-C method or a block. +inline bool isFunctionOrMethodOrBlockForAttrSubject(const Decl *D) { + return isFuncOrMethodForAttrSubject(D) || llvm::isa(D); +} + +/// Return true if the given decl has a declarator that should have +/// been processed by Sema::GetTypeForDeclarator. +inline bool hasDeclarator(const Decl *D) { + // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. + return isa(D) || isa(D) || + isa(D) || isa(D); +} + +/// hasFunctionProto - Return true if the given decl has a argument +/// information. This decl should have already passed +/// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject. +inline bool hasFunctionProto(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return isa(FnTy); + return isa(D) || isa(D); +} + +/// getFunctionOrMethodNumParams - Return number of function or method +/// parameters. It is an error to call this on a K&R function (use +/// hasFunctionProto first). +inline unsigned getFunctionOrMethodNumParams(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast(FnTy)->getNumParams(); + if (const auto *BD = dyn_cast(D)) + return BD->getNumParams(); + return cast(D)->param_size(); +} + +inline const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, + unsigned Idx) { + if (const auto *FD = dyn_cast(D)) + return FD->getParamDecl(Idx); + if (const auto *MD = dyn_cast(D)) + return MD->getParamDecl(Idx); + if (const auto *BD = dyn_cast(D)) + return BD->getParamDecl(Idx); + return nullptr; +} + +inline QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast(FnTy)->getParamType(Idx); + if (const auto *BD = dyn_cast(D)) + return BD->getParamDecl(Idx)->getType(); + + return cast(D)->parameters()[Idx]->getType(); +} + +inline SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { + if (auto *PVD = getFunctionOrMethodParam(D, Idx)) + return PVD->getSourceRange(); + return SourceRange(); +} + +inline QualType getFunctionOrMethodResultType(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return FnTy->getReturnType(); + return cast(D)->getReturnType(); +} + +inline SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { + if (const auto *FD = dyn_cast(D)) + return FD->getReturnTypeSourceRange(); + if (const auto *MD = dyn_cast(D)) + return MD->getReturnTypeSourceRange(); + return SourceRange(); +} + +inline bool isFunctionOrMethodVariadic(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast(FnTy)->isVariadic(); + if (const auto *BD = dyn_cast(D)) + return BD->isVariadic(); + return cast(D)->isVariadic(); +} + +inline bool isInstanceMethod(const Decl *D) { + if (const auto *MethodDecl = dyn_cast(D)) + return MethodDecl->isInstance(); + return false; +} + +/// Diagnose mutually exclusive attributes when present on a given +/// declaration. Returns true if diagnosed. +template +bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const ParsedAttr &AL) { + if (const auto *A = D->getAttr()) { + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); + S.Diag(A->getLocation(), diag::note_conflicting_attribute); + return true; + } + return false; +} + +template +bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const Attr &AL) { + if (const auto *A = D->getAttr()) { + S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) + << &AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); + Diag(A->getLocation(), diag::note_conflicting_attribute); + return true; + } + return false; +} + +template +const SemaBase::SemaDiagnosticBuilder & +appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr) { + return Bldr; +} + +template +const SemaBase::SemaDiagnosticBuilder & +appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, + DiagnosticArgs &&...ExtraArgs) { + return appendDiagnostics(Bldr << std::forward(ExtraArg), + std::forward(ExtraArgs)...); +} + +/// Applies the given attribute to the Decl without performing any +/// additional semantic checking. +template +void handleSimpleAttribute(SemaBase &S, Decl *D, + const AttributeCommonInfo &CI) { + D->addAttr(::new (S.getASTContext()) AttrType(S.getASTContext(), CI)); +} + +/// Add an attribute @c AttrType to declaration @c D, provided that +/// @c PassesCheck is true. +/// Otherwise, emit diagnostic @c DiagID, passing in all parameters +/// specified in @c ExtraArgs. +template +void handleSimpleAttributeOrDiagnose(SemaBase &S, Decl *D, + const AttributeCommonInfo &CI, + bool PassesCheck, unsigned DiagID, + DiagnosticArgs &&...ExtraArgs) { + if (!PassesCheck) { + SemaBase::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); + appendDiagnostics(DB, std::forward(ExtraArgs)...); + return; + } + handleSimpleAttribute(S, D, CI); +} + +} // namespace clang +#endif // LLVM_CLANG_SEMA_ATTR_H diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 76311b00d2fc586fc249b1a3e0456412ddc4b05e..4a5c9e8ca1229522ad57ede2486976fbae649e2b 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -899,6 +899,8 @@ class Sema; /// object argument. bool IgnoreObjectArgument : 1; + bool TookAddressOfOverload : 1; + /// True if the candidate was found using ADL. CallExpr::ADLCallKind IsADLCandidate : 1; @@ -999,6 +1001,10 @@ class Sema; /// Initialization of an object of class type by constructor, /// using either a parenthesized or braced list of arguments. CSK_InitByConstructor, + + /// C++ [over.match.call.general] + /// Resolve a call through the address of an overload set. + CSK_AddressOfOverloadSet, }; /// Information about operator rewrites to consider when adding operator diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 01ddba5eaf01dc23da66ddd250ced602479072c7..4d4579fcfd456befd9aea6977240db641627c07f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -47,6 +47,7 @@ #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/Sema/Attr.h" #include "clang/Sema/CleanupInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" @@ -67,6 +68,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/TinyPtrVector.h" #include #include @@ -168,14 +170,31 @@ class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; +class SemaAMDGPU; +class SemaARM; +class SemaAVR; +class SemaBPF; class SemaCodeCompletion; class SemaCUDA; class SemaHLSL; +class SemaHexagon; +class SemaLoongArch; +class SemaM68k; +class SemaMIPS; +class SemaMSP430; +class SemaNVPTX; class SemaObjC; class SemaOpenACC; +class SemaOpenCL; class SemaOpenMP; +class SemaPPC; class SemaPseudoObject; +class SemaRISCV; class SemaSYCL; +class SemaSwift; +class SemaSystemZ; +class SemaWasm; +class SemaX86; class StandardConversionSequence; class Stmt; class StringLiteral; @@ -447,6 +466,13 @@ enum class CheckedConversionKind { ForBuiltinOverloadedOp }; +enum class TagUseKind { + Reference, // Reference to a tag: 'struct foo *X;' + Declaration, // Fwd decl of a tag: 'struct foo;' + Definition, // Definition of a tag: 'struct foo { int X; } Y;' + Friend // Friend declaration: 'friend struct foo;' +}; + /// Sema - This implements semantic analysis and AST building for C. /// \nosubgrouping class Sema final : public SemaBase { @@ -484,7 +510,6 @@ class Sema final : public SemaBase { // 29. Constraints and Concepts (SemaConcept.cpp) // 30. Types (SemaType.cpp) // 31. FixIt Helpers (SemaFixItUtils.cpp) - // 32. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp) /// \name Semantic Analysis /// Implementations are in Sema.cpp @@ -876,9 +901,6 @@ public: void disable() { Active = false; } }; - /// Build a partial diagnostic. - PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h - sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.empty() ? nullptr : FunctionScopes.back(); } @@ -985,6 +1007,26 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + SemaAMDGPU &AMDGPU() { + assert(AMDGPUPtr); + return *AMDGPUPtr; + } + + SemaARM &ARM() { + assert(ARMPtr); + return *ARMPtr; + } + + SemaAVR &AVR() { + assert(AVRPtr); + return *AVRPtr; + } + + SemaBPF &BPF() { + assert(BPFPtr); + return *BPFPtr; + } + SemaCodeCompletion &CodeCompletion() { assert(CodeCompletionPtr); return *CodeCompletionPtr; @@ -1000,6 +1042,36 @@ public: return *HLSLPtr; } + SemaHexagon &Hexagon() { + assert(HexagonPtr); + return *HexagonPtr; + } + + SemaLoongArch &LoongArch() { + assert(LoongArchPtr); + return *LoongArchPtr; + } + + SemaM68k &M68k() { + assert(M68kPtr); + return *M68kPtr; + } + + SemaMIPS &MIPS() { + assert(MIPSPtr); + return *MIPSPtr; + } + + SemaMSP430 &MSP430() { + assert(MSP430Ptr); + return *MSP430Ptr; + } + + SemaNVPTX &NVPTX() { + assert(NVPTXPtr); + return *NVPTXPtr; + } + SemaObjC &ObjC() { assert(ObjCPtr); return *ObjCPtr; @@ -1010,21 +1082,56 @@ public: return *OpenACCPtr; } + SemaOpenCL &OpenCL() { + assert(OpenCLPtr); + return *OpenCLPtr; + } + SemaOpenMP &OpenMP() { assert(OpenMPPtr && "SemaOpenMP is dead"); return *OpenMPPtr; } + SemaPPC &PPC() { + assert(PPCPtr); + return *PPCPtr; + } + SemaPseudoObject &PseudoObject() { assert(PseudoObjectPtr); return *PseudoObjectPtr; } + SemaRISCV &RISCV() { + assert(RISCVPtr); + return *RISCVPtr; + } + SemaSYCL &SYCL() { assert(SYCLPtr); return *SYCLPtr; } + SemaSwift &Swift() { + assert(SwiftPtr); + return *SwiftPtr; + } + + SemaSystemZ &SystemZ() { + assert(SystemZPtr); + return *SystemZPtr; + } + + SemaWasm &Wasm() { + assert(WasmPtr); + return *WasmPtr; + } + + SemaX86 &X86() { + assert(X86Ptr); + return *X86Ptr; + } + /// Source of additional semantic information. IntrusiveRefCntPtr ExternalSource; @@ -1055,14 +1162,31 @@ private: mutable IdentifierInfo *Ident_super; + std::unique_ptr AMDGPUPtr; + std::unique_ptr ARMPtr; + std::unique_ptr AVRPtr; + std::unique_ptr BPFPtr; std::unique_ptr CodeCompletionPtr; std::unique_ptr CUDAPtr; std::unique_ptr HLSLPtr; + std::unique_ptr HexagonPtr; + std::unique_ptr LoongArchPtr; + std::unique_ptr M68kPtr; + std::unique_ptr MIPSPtr; + std::unique_ptr MSP430Ptr; + std::unique_ptr NVPTXPtr; std::unique_ptr ObjCPtr; std::unique_ptr OpenACCPtr; + std::unique_ptr OpenCLPtr; std::unique_ptr OpenMPPtr; + std::unique_ptr PPCPtr; std::unique_ptr PseudoObjectPtr; + std::unique_ptr RISCVPtr; std::unique_ptr SYCLPtr; + std::unique_ptr SwiftPtr; + std::unique_ptr SystemZPtr; + std::unique_ptr WasmPtr; + std::unique_ptr X86Ptr; ///@} @@ -2037,6 +2161,25 @@ public: void CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc); + bool BuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); + bool BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, + bool RangeIsError = true); + bool BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Multiple); + bool BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); + bool BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + + bool checkArgCountAtLeast(CallExpr *Call, unsigned MinArgCount); + bool checkArgCountAtMost(CallExpr *Call, unsigned MaxArgCount); + bool checkArgCountRange(CallExpr *Call, unsigned MinArgCount, + unsigned MaxArgCount); + bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount); + + bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); + private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE = nullptr, @@ -2050,8 +2193,6 @@ private: ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc); - void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg); - void CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl, StringRef ParamName, QualType ArgTy, QualType ParamTy); @@ -2065,68 +2206,13 @@ private: void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall); - bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, - unsigned MaxWidth); - bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool ParseSVEImmChecks(CallExpr *TheCall, - SmallVector, 3> &ImmChecks); - bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, - bool WantCDE); - bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - - bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); - bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); - bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, - ArrayRef ArgNums); - bool CheckX86BuiltinTileDuplicate(CallExpr *TheCall, ArrayRef ArgNums); - bool CheckX86BuiltinTileRangeAndDuplicate(CallExpr *TheCall, - ArrayRef ArgNums); - bool CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); - bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, - const llvm::StringMap &FeatureMap); - bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, CallExpr *TheCall); - bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall); - bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool BuiltinVAStartARMMicrosoft(CallExpr *Call); bool BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); bool BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, unsigned BuiltinID); bool BuiltinComplex(CallExpr *TheCall); - bool BuiltinVSX(CallExpr *TheCall); bool BuiltinOSLogFormat(CallExpr *TheCall); - bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); bool BuiltinPrefetch(CallExpr *TheCall); bool BuiltinAllocaWithAlign(CallExpr *TheCall); @@ -2139,23 +2225,6 @@ private: ExprResult BuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult AtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); - bool BuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); - bool BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, - bool RangeIsError = true); - bool BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, - unsigned Multiple); - bool BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); - bool BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, - unsigned ExpectedFieldNum, bool AllowName); - bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); - bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeDesc); - - bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); bool BuiltinElementwiseMath(CallExpr *TheCall); bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, @@ -2172,16 +2241,6 @@ private: ExprResult BuiltinMatrixColumnMajorStore(CallExpr *TheCall, ExprResult CallResult); - // WebAssembly builtin handling. - bool BuiltinWasmRefNullExtern(CallExpr *TheCall); - bool BuiltinWasmRefNullFunc(CallExpr *TheCall); - bool BuiltinWasmTableGet(CallExpr *TheCall); - bool BuiltinWasmTableSet(CallExpr *TheCall); - bool BuiltinWasmTableSize(CallExpr *TheCall); - bool BuiltinWasmTableGrow(CallExpr *TheCall); - bool BuiltinWasmTableFill(CallExpr *TheCall); - bool BuiltinWasmTableCopy(CallExpr *TheCall); - bool CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, @@ -3168,13 +3227,6 @@ public: bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name); - enum TagUseKind { - TUK_Reference, // Reference to a tag: 'struct foo *X;' - TUK_Declaration, // Fwd decl of a tag: 'struct foo;' - TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' - TUK_Friend // Friend declaration: 'friend struct foo;' - }; - enum OffsetOfKind { // Not parsing a type within __builtin_offsetof. OOK_Outside, @@ -3542,6 +3594,53 @@ public: BuiltinFunction }; + /// A helper function to provide Attribute Location for the Attr types + /// AND the ParsedAttr. + template + static std::enable_if_t, SourceLocation> + getAttrLoc(const AttrInfo &AL) { + return AL.getLocation(); + } + SourceLocation getAttrLoc(const ParsedAttr &AL); + + /// If Expr is a valid integer constant, get the value of the integer + /// expression and return success or failure. May output an error. + /// + /// Negative argument is implicitly converted to unsigned, unless + /// \p StrictlyUnsigned is true. + template + bool checkUInt32Argument(const AttrInfo &AI, const Expr *Expr, uint32_t &Val, + unsigned Idx = UINT_MAX, + bool StrictlyUnsigned = false) { + std::optional I = llvm::APSInt(32); + if (Expr->isTypeDependent() || + !(I = Expr->getIntegerConstantExpr(Context))) { + if (Idx != UINT_MAX) + Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << &AI << Idx << AANT_ArgumentIntegerConstant + << Expr->getSourceRange(); + else + Diag(getAttrLoc(AI), diag::err_attribute_argument_type) + << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); + return false; + } + + if (!I->isIntN(32)) { + Diag(Expr->getExprLoc(), diag::err_ice_too_large) + << toString(*I, 10, false) << 32 << /* Unsigned */ 1; + return false; + } + + if (StrictlyUnsigned && I->isSigned() && I->isNegative()) { + Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) + << &AI << /*non-negative*/ 1; + return false; + } + + Val = (uint32_t)I->getZExtValue(); + return true; + } + /// WeakTopLevelDecl - Translation-unit scoped declarations generated by /// \#pragma weak during processing of other Decls. /// I couldn't figure out a clean way to generate these in-line, so @@ -3648,8 +3747,6 @@ public: const AttributeCommonInfo &CI, const IdentifierInfo *Ident); MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI); - SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, - StringRef Name); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL); @@ -3663,8 +3760,6 @@ public: const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr, CUDAFunctionTarget CFT = CUDAFunctionTarget::InvalidTarget); - void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, - ParameterABI ABI); bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value); /// Create an CUDALaunchBoundsAttr attribute. @@ -3679,61 +3774,12 @@ public: Expr *MaxThreads, Expr *MinBlocks, Expr *MaxBlocks); enum class RetainOwnershipKind { NS, CF, OS }; - void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, - RetainOwnershipKind K, bool IsTemplateInstantiation); - - bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); - - /// Do a check to make sure \p Name looks like a legal argument for the - /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name - /// is invalid for the given declaration. - /// - /// \p AL is used to provide caret diagnostics in case of a malformed name. - /// - /// \returns true if the name is a valid swift name for \p D, false otherwise. - bool DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, - const ParsedAttr &AL, bool IsAsync); UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, StringRef UuidAsWritten, MSGuidDecl *GuidDecl); BTFDeclTagAttr *mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL); - WebAssemblyImportNameAttr * - mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL); - WebAssemblyImportModuleAttr * - mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL); - - /// Create an AMDGPUWavesPerEUAttr attribute. - AMDGPUFlatWorkGroupSizeAttr * - CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min, - Expr *Max); - - /// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size - /// attribute to a particular declaration. - void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *Min, Expr *Max); - - /// Create an AMDGPUWavesPerEUAttr attribute. - AMDGPUWavesPerEUAttr * - CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *Min, - Expr *Max); - - /// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a - /// particular declaration. - void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *Min, Expr *Max); - - /// Create an AMDGPUMaxNumWorkGroupsAttr attribute. - AMDGPUMaxNumWorkGroupsAttr * - CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, Expr *XExpr, - Expr *YExpr, Expr *ZExpr); - - /// addAMDGPUMaxNumWorkGroupsAttr - Adds an amdgpu_max_num_work_groups - /// attribute to a particular declaration. - void addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *XExpr, Expr *YExpr, Expr *ZExpr); - DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI); DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI); MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D, @@ -3797,6 +3843,52 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); + /// Check if IdxExpr is a valid parameter index for a function or + /// instance method D. May output an error. + /// + /// \returns true if IdxExpr is a valid index. + template + bool checkFunctionOrMethodParameterIndex(const Decl *D, const AttrInfo &AI, + unsigned AttrArgNum, + const Expr *IdxExpr, ParamIdx &Idx, + bool CanIndexImplicitThis = false) { + assert(isFunctionOrMethodOrBlockForAttrSubject(D)); + + // In C++ the implicit 'this' function parameter also counts. + // Parameters are counted from one. + bool HP = hasFunctionProto(D); + bool HasImplicitThisParam = isInstanceMethod(D); + bool IV = HP && isFunctionOrMethodVariadic(D); + unsigned NumParams = + (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; + + std::optional IdxInt; + if (IdxExpr->isTypeDependent() || + !(IdxInt = IdxExpr->getIntegerConstantExpr(Context))) { + Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << &AI << AttrArgNum << AANT_ArgumentIntegerConstant + << IdxExpr->getSourceRange(); + return false; + } + + unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); + if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { + Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) + << &AI << AttrArgNum << IdxExpr->getSourceRange(); + return false; + } + if (HasImplicitThisParam && !CanIndexImplicitThis) { + if (IdxSource == 1) { + Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) + << &AI << IdxExpr->getSourceRange(); + return false; + } + } + + Idx = ParamIdx(IdxSource, D); + return true; + } + ///@} // @@ -5106,6 +5198,13 @@ public: Context == ExpressionEvaluationContext::UnevaluatedList; } + bool isPotentiallyEvaluated() const { + return Context == ExpressionEvaluationContext::PotentiallyEvaluated || + Context == + ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed || + Context == ExpressionEvaluationContext::ConstantEvaluated; + } + bool isConstantEvaluated() const { return Context == ExpressionEvaluationContext::ConstantEvaluated || Context == ExpressionEvaluationContext::ImmediateFunctionContext; @@ -5140,6 +5239,16 @@ public: return ExprEvalContexts.back(); }; + ExpressionEvaluationContextRecord &parentEvaluationContext() { + assert(ExprEvalContexts.size() >= 2 && + "Must be in an expression evaluation context"); + return ExprEvalContexts[ExprEvalContexts.size() - 2]; + }; + + const ExpressionEvaluationContextRecord &parentEvaluationContext() const { + return const_cast(this)->parentEvaluationContext(); + }; + bool isBoundsAttrContext() const { return ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::ExpressionKind:: @@ -5890,7 +5999,6 @@ public: SourceLocation Loc, bool IsCompAssign); bool isValidSveBitcast(QualType srcType, QualType destType); - bool isValidRVVBitcast(QualType srcType, QualType destType); bool areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy); @@ -6271,10 +6379,9 @@ public: /// flag from previous context. void keepInLifetimeExtendingContext() { if (ExprEvalContexts.size() > 2 && - ExprEvalContexts[ExprEvalContexts.size() - 2] - .InLifetimeExtendingContext) { + parentEvaluationContext().InLifetimeExtendingContext) { auto &LastRecord = ExprEvalContexts.back(); - auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2]; + auto &PrevRecord = parentEvaluationContext(); LastRecord.InLifetimeExtendingContext = PrevRecord.InLifetimeExtendingContext; } @@ -7063,7 +7170,9 @@ public: StorageClass SC, ArrayRef Params, bool HasExplicitResultType); - void DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method); + /// Returns true if the explicit object parameter was invalid. + bool DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method, + SourceLocation CallLoc); /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if @@ -8965,6 +9074,9 @@ public: const TemplateArgumentListInfo *TemplateArgs); void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); + void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS, + bool TemplateKeyword, TemplateDecl *TD, + SourceLocation Loc); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -10067,7 +10179,9 @@ public: bool SubstTemplateArgument(const TemplateArgumentLoc &Input, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentLoc &Output); + TemplateArgumentLoc &Output, + SourceLocation Loc = {}, + const DeclarationName &Entity = {}); bool SubstTemplateArguments(ArrayRef Args, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -11381,7 +11495,8 @@ public: QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns, SourceLocation AttrLoc); - QualType BuildCountAttributedArrayType(QualType WrappedTy, Expr *CountExpr); + QualType BuildCountAttributedArrayOrPointerType(QualType WrappedTy, + Expr *CountExpr); QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); @@ -11684,27 +11799,6 @@ public: /// Triggered by declaration-attribute processing. void ProcessAPINotes(Decl *D); - ///@} - // - // - // ------------------------------------------------------------------------- - // - // - - /// \name Name Lookup for RISC-V Vector Intrinsic - /// Implementations are in SemaRISCVVectorLookup.cpp - ///@{ - -public: - /// Indicate RISC-V vector builtin functions enabled or not. - bool DeclareRISCVVBuiltins = false; - - /// Indicate RISC-V SiFive vector builtin functions enabled or not. - bool DeclareRISCVSiFiveVectorBuiltins = false; - -private: - std::unique_ptr RVIntrinsicManager; - ///@} }; @@ -11727,9 +11821,6 @@ void Sema::PragmaStack::Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, AlignPackInfo Value); - -std::unique_ptr -CreateRISCVIntrinsicManager(Sema &S); } // end namespace clang #endif diff --git a/clang/include/clang/Sema/SemaAMDGPU.h b/clang/include/clang/Sema/SemaAMDGPU.h new file mode 100644 index 0000000000000000000000000000000000000000..969078f552c6ab7e48ac4046f41c2a6d0614386f --- /dev/null +++ b/clang/include/clang/Sema/SemaAMDGPU.h @@ -0,0 +1,68 @@ +//===----- SemaAMDGPU.h --- AMDGPU target-specific routines ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to AMDGPU. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAAMDGPU_H +#define LLVM_CLANG_SEMA_SEMAAMDGPU_H + +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaAMDGPU : public SemaBase { +public: + SemaAMDGPU(Sema &S); + + bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + + /// Create an AMDGPUWavesPerEUAttr attribute. + AMDGPUFlatWorkGroupSizeAttr * + CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min, + Expr *Max); + + /// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size + /// attribute to a particular declaration. + void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *Min, Expr *Max); + + /// Create an AMDGPUWavesPerEUAttr attribute. + AMDGPUWavesPerEUAttr * + CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *Min, + Expr *Max); + + /// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a + /// particular declaration. + void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *Min, Expr *Max); + + /// Create an AMDGPUMaxNumWorkGroupsAttr attribute. + AMDGPUMaxNumWorkGroupsAttr * + CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, Expr *XExpr, + Expr *YExpr, Expr *ZExpr); + + /// addAMDGPUMaxNumWorkGroupsAttr - Adds an amdgpu_max_num_work_groups + /// attribute to a particular declaration. + void addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *XExpr, Expr *YExpr, Expr *ZExpr); + + void handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL); + void handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL); + void handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL); + void handleAMDGPUMaxNumWorkGroupsAttr(Decl *D, const ParsedAttr &AL); + void handleAMDGPUFlatWorkGroupSizeAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAAMDGPU_H diff --git a/clang/include/clang/Sema/SemaARM.h b/clang/include/clang/Sema/SemaARM.h new file mode 100644 index 0000000000000000000000000000000000000000..6478c0beb715d3d32a6796a3e70dd6728e9edf5d --- /dev/null +++ b/clang/include/clang/Sema/SemaARM.h @@ -0,0 +1,74 @@ +//===----- SemaARM.h ------- ARM target-specific routines -----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to ARM. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAARM_H +#define LLVM_CLANG_SEMA_SEMAARM_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace clang { +class ParsedAttr; + +class SemaARM : public SemaBase { +public: + SemaARM(Sema &S); + + enum ArmStreamingType { + ArmNonStreaming, + ArmStreaming, + ArmStreamingCompatible, + ArmStreamingOrSVE2p1 + }; + + bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, + unsigned MaxWidth); + bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool + ParseSVEImmChecks(CallExpr *TheCall, + llvm::SmallVector, 3> &ImmChecks); + bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, + bool WantCDE); + bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + + bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, + unsigned ExpectedFieldNum, bool AllowName); + bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); + + bool MveAliasValid(unsigned BuiltinID, StringRef AliasName); + bool CdeAliasValid(unsigned BuiltinID, StringRef AliasName); + bool SveAliasValid(unsigned BuiltinID, StringRef AliasName); + bool SmeAliasValid(unsigned BuiltinID, StringRef AliasName); + void handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL); + void handleNewAttr(Decl *D, const ParsedAttr &AL); + void handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL); + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); +}; + +SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD); + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAARM_H diff --git a/clang/include/clang/Sema/SemaAVR.h b/clang/include/clang/Sema/SemaAVR.h new file mode 100644 index 0000000000000000000000000000000000000000..708da3a6026aceeca66d8f17a08ccaa0fc9f5806 --- /dev/null +++ b/clang/include/clang/Sema/SemaAVR.h @@ -0,0 +1,32 @@ +//===----- SemaAVR.h ------- AVR target-specific routines -----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to AVR. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAAVR_H +#define LLVM_CLANG_SEMA_SEMAAVR_H + +#include "clang/Sema/SemaBase.h" + +namespace clang { +class Decl; +class ParsedAttr; + +class SemaAVR : public SemaBase { +public: + SemaAVR(Sema &S); + + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); + void handleSignalAttr(Decl *D, const ParsedAttr &AL); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAAVR_H diff --git a/clang/include/clang/Sema/SemaBPF.h b/clang/include/clang/Sema/SemaBPF.h new file mode 100644 index 0000000000000000000000000000000000000000..0182ccfe508a7bea2ba9e38e20314f2dcb9cadcb --- /dev/null +++ b/clang/include/clang/Sema/SemaBPF.h @@ -0,0 +1,35 @@ +//===----- SemaBPF.h ------- BPF target-specific routines -----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to BPF. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMABPF_H +#define LLVM_CLANG_SEMA_SEMABPF_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class ParsedAttr; + +class SemaBPF : public SemaBase { +public: + SemaBPF(Sema &S); + + bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + + void handlePreserveAIRecord(RecordDecl *RD); + void handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMABPF_H diff --git a/clang/include/clang/Sema/SemaBase.h b/clang/include/clang/Sema/SemaBase.h index 3220f71dd797ed0a125a666a17ee85150e57c283..0b05245ab9686bf233d73b6c10d874953121f8db 100644 --- a/clang/include/clang/Sema/SemaBase.h +++ b/clang/include/clang/Sema/SemaBase.h @@ -217,6 +217,9 @@ public: /// Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, bool DeferHint = false); + + /// Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0); }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 34acaf19517f2a58be7fd54667d7b8a1a8e28ef1..e145f5e7f43f85da1b65193126f92f433697bb02 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -25,6 +25,7 @@ #include namespace clang { +class ParsedAttr; class SemaHLSL : public SemaBase { public: @@ -49,6 +50,14 @@ public: void DiagnoseAttrStageMismatch( const Attr *A, HLSLShaderAttr::ShaderType Stage, std::initializer_list AllowedStages); + void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); + + void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); + void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); + void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); + void handleShaderAttr(Decl *D, const ParsedAttr &AL); + void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); + void handleParamModifierAttr(Decl *D, const ParsedAttr &AL); }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaHexagon.h b/clang/include/clang/Sema/SemaHexagon.h new file mode 100644 index 0000000000000000000000000000000000000000..2d4a04f824bc2ef208c9f9fb52b1f7df1580ad75 --- /dev/null +++ b/clang/include/clang/Sema/SemaHexagon.h @@ -0,0 +1,29 @@ +//===----- SemaHexagon.h -- Hexagon target-specific routines --*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to Hexagon. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAHEXAGON_H +#define LLVM_CLANG_SEMA_SEMAHEXAGON_H + +#include "clang/AST/Expr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaHexagon : public SemaBase { +public: + SemaHexagon(Sema &S); + + bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAHEXAGON_H diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 842eec099540c3b84184e1a16fb067276eceaac6..d994d1819b44237533d1b0a90040bdd09e56abda 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -21,10 +21,6 @@ namespace clang { -inline PartialDiagnostic Sema::PDiag(unsigned DiagID) { - return PartialDiagnostic(DiagID, Context.getDiagAllocator()); -} - inline bool FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) { return FTI.NumParams == 1 && !FTI.isVariadic && diff --git a/clang/include/clang/Sema/SemaLoongArch.h b/clang/include/clang/Sema/SemaLoongArch.h new file mode 100644 index 0000000000000000000000000000000000000000..aef0df9e8710ff0e93ae2cac8541fe06d4c3ed03 --- /dev/null +++ b/clang/include/clang/Sema/SemaLoongArch.h @@ -0,0 +1,30 @@ +//===-- SemaLoongArch.h -- LoongArch target-specific routines --*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to LoongArch. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMALOONGARCH_H +#define LLVM_CLANG_SEMA_SEMALOONGARCH_H + +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaLoongArch : public SemaBase { +public: + SemaLoongArch(Sema &S); + + bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMALOONGARCH_H diff --git a/clang/include/clang/Sema/SemaM68k.h b/clang/include/clang/Sema/SemaM68k.h new file mode 100644 index 0000000000000000000000000000000000000000..5a9767d5ea52163b756fd7d9b65545aa0e2eaf58 --- /dev/null +++ b/clang/include/clang/Sema/SemaM68k.h @@ -0,0 +1,30 @@ +//===----- SemaM68k.h ------ M68k target-specific routines ----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to M68k. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAM68K_H +#define LLVM_CLANG_SEMA_SEMAM68K_H + +#include "clang/Sema/SemaBase.h" + +namespace clang { +class Decl; +class ParsedAttr; + +class SemaM68k : public SemaBase { +public: + SemaM68k(Sema &S); + + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAM68K_H diff --git a/clang/include/clang/Sema/SemaMIPS.h b/clang/include/clang/Sema/SemaMIPS.h new file mode 100644 index 0000000000000000000000000000000000000000..6366dce57626af8115da5bef9ab5a08de5d5b914 --- /dev/null +++ b/clang/include/clang/Sema/SemaMIPS.h @@ -0,0 +1,37 @@ +//===----- SemaMIPS.h ------ MIPS target-specific routines ----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to MIPS. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAMIPS_H +#define LLVM_CLANG_SEMA_SEMAMIPS_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class ParsedAttr; + +class SemaMIPS : public SemaBase { +public: + SemaMIPS(Sema &S); + + bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAMIPS_H diff --git a/clang/include/clang/Sema/SemaMSP430.h b/clang/include/clang/Sema/SemaMSP430.h new file mode 100644 index 0000000000000000000000000000000000000000..e1034aefe881640a8740ec3a9b631e428e1b1a5c --- /dev/null +++ b/clang/include/clang/Sema/SemaMSP430.h @@ -0,0 +1,30 @@ +//===----- SemaMSP430.h --- MSP430 target-specific routines ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to MSP430. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAMSP430_H +#define LLVM_CLANG_SEMA_SEMAMSP430_H + +#include "clang/Sema/SemaBase.h" + +namespace clang { +class Decl; +class ParsedAttr; + +class SemaMSP430 : public SemaBase { +public: + SemaMSP430(Sema &S); + + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAMSP430_H diff --git a/clang/include/clang/Sema/SemaNVPTX.h b/clang/include/clang/Sema/SemaNVPTX.h new file mode 100644 index 0000000000000000000000000000000000000000..a663c694179d98a9866073da01b47a4d0ff7c1aa --- /dev/null +++ b/clang/include/clang/Sema/SemaNVPTX.h @@ -0,0 +1,30 @@ +//===----- SemaNVPTX.h ----- NVPTX target-specific routines ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to NVPTX. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMANVPTX_H +#define LLVM_CLANG_SEMA_SEMANVPTX_H + +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaNVPTX : public SemaBase { +public: + SemaNVPTX(Sema &S); + + bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMANVPTX_H diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index a9a0d1678095694932f345bee62df8dc16d85484..91430797e5ed82517de07e28b4bc333432204b14 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -30,7 +30,6 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" -#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Redeclaration.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaBase.h" @@ -45,6 +44,7 @@ namespace clang { enum class CheckedConversionKind; +class ParsedAttr; struct SkipBodyInfo; class SemaObjC : public SemaBase { @@ -1007,6 +1007,56 @@ public: ObjCInterfaceDecl *IDecl); ///@} + + // + // + // ------------------------------------------------------------------------- + // + // + + /// \name ObjC Attributes + /// Implementations are in SemaObjC.cpp + ///@{ + + bool isNSStringType(QualType T, bool AllowNSAttributedString = false); + bool isCFStringType(QualType T); + + void handleIBOutlet(Decl *D, const ParsedAttr &AL); + void handleIBOutletCollection(Decl *D, const ParsedAttr &AL); + + void handleSuppresProtocolAttr(Decl *D, const ParsedAttr &AL); + void handleDirectAttr(Decl *D, const ParsedAttr &AL); + void handleDirectMembersAttr(Decl *D, const ParsedAttr &AL); + void handleMethodFamilyAttr(Decl *D, const ParsedAttr &AL); + void handleNSObject(Decl *D, const ParsedAttr &AL); + void handleIndependentClass(Decl *D, const ParsedAttr &AL); + void handleBlocksAttr(Decl *D, const ParsedAttr &AL); + void handleReturnsInnerPointerAttr(Decl *D, const ParsedAttr &Attrs); + void handleXReturnsXRetainedAttr(Decl *D, const ParsedAttr &AL); + void handleRequiresSuperAttr(Decl *D, const ParsedAttr &Attrs); + void handleNSErrorDomain(Decl *D, const ParsedAttr &Attr); + void handleBridgeAttr(Decl *D, const ParsedAttr &AL); + void handleBridgeMutableAttr(Decl *D, const ParsedAttr &AL); + void handleBridgeRelatedAttr(Decl *D, const ParsedAttr &AL); + void handleDesignatedInitializer(Decl *D, const ParsedAttr &AL); + void handleRuntimeName(Decl *D, const ParsedAttr &AL); + void handleBoxable(Decl *D, const ParsedAttr &AL); + void handleOwnershipAttr(Decl *D, const ParsedAttr &AL); + void handlePreciseLifetimeAttr(Decl *D, const ParsedAttr &AL); + void handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL); + + void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, + Sema::RetainOwnershipKind K, + bool IsTemplateInstantiation); + + /// \return whether the parameter is a pointer to OSObject pointer. + bool isValidOSObjectOutParameter(const Decl *D); + bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); + + Sema::RetainOwnershipKind + parsedAttrToRetainOwnershipKind(const ParsedAttr &AL); + + ///@} }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 6f69fa08939b82d3ed553fd0f255ed9bfbafbc45..a5f2a8bf74657770e057a2747cd5dc3a69754e02 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SEMA_SEMAOPENACC_H #include "clang/AST/DeclGroup.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Ownership.h" @@ -25,6 +26,15 @@ namespace clang { class OpenACCClause; class SemaOpenACC : public SemaBase { +private: + /// A collection of loop constructs in the compute construct scope that + /// haven't had their 'parent' compute construct set yet. Entires will only be + /// made to this list in the case where we know the loop isn't an orphan. + llvm::SmallVector ParentlessLoopConstructs; + /// Whether we are inside of a compute construct, and should add loops to the + /// above collection. + bool InsideComputeConstruct = false; + public: // Redeclaration of the version in OpenACCClause.h. using DeviceTypeArgument = std::pair; @@ -379,7 +389,7 @@ public: /// Called after the construct has been parsed, but clauses haven't been /// parsed. This allows us to diagnose not-implemented, as well as set up any /// state required for parsing the clauses. - void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); + void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc); /// Called after the directive, including its clauses, have been parsed and /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES @@ -394,12 +404,14 @@ public: bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); /// Called when we encounter an associated statement for our construct, this /// should check legality of the statement as it appertains to this Construct. - StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt); + StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc, + OpenACCDirectiveKind K, StmtResult AssocStmt); /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult AssocStmt); @@ -430,6 +442,20 @@ public: Expr *LowerBound, SourceLocation ColonLocFirst, Expr *Length, SourceLocation RBLoc); + + /// Helper type for the registration/assignment of constructs that need to + /// 'know' about their parent constructs and hold a reference to them, such as + /// Loop needing its parent construct. + class AssociatedStmtRAII { + SemaOpenACC &SemaRef; + bool WasInsideComputeConstruct; + OpenACCDirectiveKind DirKind; + llvm::SmallVector ParentlessLoopConstructs; + + public: + AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind); + ~AssociatedStmtRAII(); + }; }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaOpenCL.h b/clang/include/clang/Sema/SemaOpenCL.h new file mode 100644 index 0000000000000000000000000000000000000000..0d80c4b4c0b561c65d32e73b5ba8836bb9e4bf52 --- /dev/null +++ b/clang/include/clang/Sema/SemaOpenCL.h @@ -0,0 +1,35 @@ +//===----- SemaOpenCL.h --- Semantic Analysis for OpenCL constructs -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis routines for OpenCL. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAOPENCL_H +#define LLVM_CLANG_SEMA_SEMAOPENCL_H + +#include "clang/Sema/SemaBase.h" + +namespace clang { +class Decl; +class ParsedAttr; + +class SemaOpenCL : public SemaBase { +public: + SemaOpenCL(Sema &S); + + void handleNoSVMAttr(Decl *D, const ParsedAttr &AL); + void handleAccessAttr(Decl *D, const ParsedAttr &AL); + + // Handles intel_reqd_sub_group_size. + void handleSubGroupSize(Decl *D, const ParsedAttr &AL); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAOPENCL_H diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 9927459bbc594162012146e774fee3a8921cfa3c..3edf1cc7c12f2b8b135613f6ae66178b41cfef72 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -42,6 +42,7 @@ #include namespace clang { +class ParsedAttr; class SemaOpenMP : public SemaBase { public: @@ -1348,6 +1349,8 @@ public: SourceLocation LLoc, SourceLocation RLoc, ArrayRef Data); + void handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL); + private: void *VarDataSharingAttributesStack; @@ -1390,9 +1393,7 @@ private: bool checkTransformableLoopNest( OpenMPDirectiveKind Kind, Stmt *AStmt, int NumLoops, SmallVectorImpl &LoopHelpers, - Stmt *&Body, - SmallVectorImpl, 0>> - &OriginalInits); + Stmt *&Body, SmallVectorImpl> &OriginalInits); /// Helper to keep information about the current `omp begin/end declare /// variant` nesting. diff --git a/clang/include/clang/Sema/SemaPPC.h b/clang/include/clang/Sema/SemaPPC.h new file mode 100644 index 0000000000000000000000000000000000000000..3e8929d5b6dedab086ed2911b5a21dedb04618ef --- /dev/null +++ b/clang/include/clang/Sema/SemaPPC.h @@ -0,0 +1,58 @@ +//===----- SemaPPC.h ------- PPC target-specific routines -----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to PowerPC. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAPPC_H +#define LLVM_CLANG_SEMA_SEMAPPC_H + +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaPPC : public SemaBase { +public: + SemaPPC(Sema &S); + + bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + // 16 byte ByVal alignment not due to a vector member is not honoured by XL + // on AIX. Emit a warning here that users are generating binary incompatible + // code to be safe. + // Here we try to get information about the alignment of the struct member + // from the struct passed to the caller function. We only warn when the struct + // is passed byval, hence the series of checks and early returns if we are a + // not passing a struct byval. + void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg); + + /// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. + /// Emit an error and return true on failure; return false on success. + /// TypeStr is a string containing the type descriptor of the value returned + /// by the builtin and the descriptors of the expected type of the arguments. + bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeDesc); + + bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); + + // Customized Sema Checking for VSX builtins that have the following + // signature: vector [...] builtinName(vector [...], vector [...], const int); + // Which takes the same type of vectors (any legal vector type) for the first + // two arguments and takes compile time constant for the third argument. + // Example builtins are : + // vector double vec_xxpermdi(vector double, vector double, int); + // vector short vec_xxsldwi(vector short, vector short, int); + bool BuiltinVSX(CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAPPC_H diff --git a/clang/include/clang/Sema/SemaRISCV.h b/clang/include/clang/Sema/SemaRISCV.h new file mode 100644 index 0000000000000000000000000000000000000000..48d15c411bddde255ae68f60c175479b875fae97 --- /dev/null +++ b/clang/include/clang/Sema/SemaRISCV.h @@ -0,0 +1,57 @@ +//===----- SemaRISCV.h ---- RISC-V target-specific routines ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to RISC-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMARISCV_H +#define LLVM_CLANG_SEMA_SEMARISCV_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/RISCVIntrinsicManager.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/StringMap.h" +#include + +namespace clang { +class ParsedAttr; + +class SemaRISCV : public SemaBase { +public: + SemaRISCV(Sema &S); + + bool CheckLMUL(CallExpr *TheCall, unsigned ArgNum); + bool CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap); + + bool isValidRVVBitcast(QualType srcType, QualType destType); + + void handleInterruptAttr(Decl *D, const ParsedAttr &AL); + bool isAliasValid(unsigned BuiltinID, StringRef AliasName); + + /// Indicate RISC-V vector builtin functions enabled or not. + bool DeclareRVVBuiltins = false; + + /// Indicate RISC-V SiFive vector builtin functions enabled or not. + bool DeclareSiFiveVectorBuiltins = false; + + std::unique_ptr IntrinsicManager; +}; + +std::unique_ptr +CreateRISCVIntrinsicManager(Sema &S); +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMARISCV_H diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index f0dcb92ee9ab3e74a41a2d12c3287eb89e21666b..363178546a236c5c9ecdd229b13ce21e23b6cd18 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -21,6 +21,8 @@ #include "llvm/ADT/DenseSet.h" namespace clang { +class Decl; +class ParsedAttr; class SemaSYCL : public SemaBase { public: @@ -58,6 +60,8 @@ public: SourceLocation LParen, SourceLocation RParen, ParsedType ParsedTy); + + void handleKernelAttr(Decl *D, const ParsedAttr &AL); }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaSwift.h b/clang/include/clang/Sema/SemaSwift.h new file mode 100644 index 0000000000000000000000000000000000000000..a5561d756affd109237d2791cb19e1868d2028a2 --- /dev/null +++ b/clang/include/clang/Sema/SemaSwift.h @@ -0,0 +1,59 @@ +//===----- SemaSwift.h --- Swift language-specific routines ---*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to Swift. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMASWIFT_H +#define LLVM_CLANG_SEMA_SEMASWIFT_H + +#include "clang/AST/Attr.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class AttributeCommonInfo; +class Decl; +class ParsedAttr; +class SwiftNameAttr; + +class SemaSwift : public SemaBase { +public: + SemaSwift(Sema &S); + + SwiftNameAttr *mergeNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name); + + void handleAttrAttr(Decl *D, const ParsedAttr &AL); + void handleAsyncAttr(Decl *D, const ParsedAttr &AL); + void handleBridge(Decl *D, const ParsedAttr &AL); + void handleError(Decl *D, const ParsedAttr &AL); + void handleAsyncError(Decl *D, const ParsedAttr &AL); + void handleName(Decl *D, const ParsedAttr &AL); + void handleAsyncName(Decl *D, const ParsedAttr &AL); + void handleNewType(Decl *D, const ParsedAttr &AL); + + /// Do a check to make sure \p Name looks like a legal argument for the + /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name + /// is invalid for the given declaration. + /// + /// \p AL is used to provide caret diagnostics in case of a malformed name. + /// + /// \returns true if the name is a valid swift name for \p D, false otherwise. + bool DiagnoseName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL, bool IsAsync); + void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, + ParameterABI abi); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMASWIFT_H diff --git a/clang/include/clang/Sema/SemaSystemZ.h b/clang/include/clang/Sema/SemaSystemZ.h new file mode 100644 index 0000000000000000000000000000000000000000..8945471d53d638ff421a8f9fdb392081d05772ba --- /dev/null +++ b/clang/include/clang/Sema/SemaSystemZ.h @@ -0,0 +1,28 @@ +//===----- SemaSystemZ.h -- SystemZ target-specific routines --*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to SystemZ. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMASYSTEMZ_H +#define LLVM_CLANG_SEMA_SEMASYSTEMZ_H + +#include "clang/AST/Expr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaSystemZ : public SemaBase { +public: + SemaSystemZ(Sema &S); + + bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMASYSTEMZ_H diff --git a/clang/include/clang/Sema/SemaWasm.h b/clang/include/clang/Sema/SemaWasm.h new file mode 100644 index 0000000000000000000000000000000000000000..c3c781535024aefb50c886d9fd8e1b6a63e8e408 --- /dev/null +++ b/clang/include/clang/Sema/SemaWasm.h @@ -0,0 +1,52 @@ +//===----- SemaWasm.h ------ Wasm target-specific routines ----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to Wasm. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAWASM_H +#define LLVM_CLANG_SEMA_SEMAWASM_H + +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaWasm : public SemaBase { +public: + SemaWasm(Sema &S); + + bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall); + + bool BuiltinWasmRefNullExtern(CallExpr *TheCall); + bool BuiltinWasmRefNullFunc(CallExpr *TheCall); + bool BuiltinWasmTableGet(CallExpr *TheCall); + bool BuiltinWasmTableSet(CallExpr *TheCall); + bool BuiltinWasmTableSize(CallExpr *TheCall); + bool BuiltinWasmTableGrow(CallExpr *TheCall); + bool BuiltinWasmTableFill(CallExpr *TheCall); + bool BuiltinWasmTableCopy(CallExpr *TheCall); + + WebAssemblyImportNameAttr * + mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL); + WebAssemblyImportModuleAttr * + mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL); + + void handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL); + void handleWebAssemblyImportModuleAttr(Decl *D, const ParsedAttr &AL); + void handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAWASM_H diff --git a/clang/include/clang/Sema/SemaX86.h b/clang/include/clang/Sema/SemaX86.h new file mode 100644 index 0000000000000000000000000000000000000000..e53aaf229c38dda3641af729c3df4158835eaf5f --- /dev/null +++ b/clang/include/clang/Sema/SemaX86.h @@ -0,0 +1,44 @@ +//===----- SemaX86.h ------- X86 target-specific routines -----*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis functions specific to X86. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAX86_H +#define LLVM_CLANG_SEMA_SEMAX86_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class ParsedAttr; + +class SemaX86 : public SemaBase { +public: + SemaX86(Sema &S); + + bool CheckBuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); + bool CheckBuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); + bool CheckBuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall); + bool CheckBuiltinTileArgumentsRange(CallExpr *TheCall, ArrayRef ArgNums); + bool CheckBuiltinTileDuplicate(CallExpr *TheCall, ArrayRef ArgNums); + bool CheckBuiltinTileRangeAndDuplicate(CallExpr *TheCall, + ArrayRef ArgNums); + bool CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + + void handleAnyInterruptAttr(Decl *D, const ParsedAttr &AL); + void handleForceAlignArgPointerAttr(Decl *D, const ParsedAttr &AL); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAX86_H diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index fe1bd47348be1e77b1e3742cdf14a47bab8dead5..f59ff6af4c764ceb0144bbad64ea4e916fb9753d 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1946,6 +1946,7 @@ enum StmtCode { // OpenACC Constructs STMT_OPENACC_COMPUTE_CONSTRUCT, + STMT_OPENACC_LOOP_CONSTRUCT, }; /// The kinds of designators that can occur in a diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 1bb5fa27a2419e75e14baae1f4d625c171e91bf9..bea58d60d36c41c02ed926141b9bad313b239724 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -429,6 +429,9 @@ private: FileManager &FileMgr; const PCHContainerReader &PCHContainerRdr; DiagnosticsEngine &Diags; + // Sema has duplicate logic, but SemaObj can sometimes be null so ASTReader + // has its own version. + bool WarnedStackExhausted = false; /// The semantic analysis object that will be processing the /// AST files and the translation unit that uses it. @@ -601,11 +604,11 @@ private: /// An array of lexical contents of a declaration context, as a sequence of /// Decl::Kind, DeclID pairs. - using unalighed_decl_id_t = + using unaligned_decl_id_t = llvm::support::detail::packed_endian_specific_integral< serialization::DeclID, llvm::endianness::native, llvm::support::unaligned>; - using LexicalContents = ArrayRef; + using LexicalContents = ArrayRef; /// Map from a DeclContext to its lexical contents. llvm::DenseMap> @@ -2135,6 +2138,8 @@ public: /// Report a diagnostic. DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const; + void warnStackExhausted(SourceLocation Loc); + IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID); IdentifierInfo *readIdentifier(ModuleFile &M, const RecordData &Record, @@ -2246,7 +2251,7 @@ public: auto [Loc, ModuleFileIndex] = ReadUntranslatedSourceLocation(Raw, Seq); ModuleFile *OwningModuleFile = - ModuleFileIndex == 0 ? &MF : MF.DependentModules[ModuleFileIndex - 1]; + ModuleFileIndex == 0 ? &MF : MF.TransitiveImports[ModuleFileIndex - 1]; assert(!SourceMgr.isLoadedSourceLocation(Loc) && "Run out source location space"); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 88192e439a3f05cc72b4b14dc2def72a8b1da679..fcc007d6f8637e9810d4ccbbdced4bd9552c4a65 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -18,7 +18,6 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index 7d8cbe3d40f56437d8ef3c2320a63353b77cd6b9..992d26a8b88c12d4dabb666b8de65ce97ce884ba 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -513,11 +513,11 @@ public: /// List of modules which this modules dependent on. Different /// from `Imports`, this includes indirectly imported modules too. - /// The order of DependentModules is significant. It should keep + /// The order of TransitiveImports is significant. It should keep /// the same order with that module file manager when we write /// the current module file. The value of the member will be initialized /// in `ASTReader::ReadModuleOffsetMap`. - llvm::SmallVector DependentModules; + llvm::SmallVector TransitiveImports; /// Determine whether this module was directly imported at /// any point during translation. diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h index 3bd379acf7eda47336cd133a32b5f67994bafa39..d770bc52eaf4f734fcfc817d08176af497e7c1cc 100644 --- a/clang/include/clang/Serialization/ModuleManager.h +++ b/clang/include/clang/Serialization/ModuleManager.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H #include "clang/Basic/LLVM.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Serialization/ModuleFile.h" #include "llvm/ADT/DenseMap.h" diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 64414e3d37f7510d4b340c54c76dafa786e839b2..a7f62ef7f2d074ef9deca70c0e57d8595b354105 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -36,6 +36,7 @@ def CoreAlpha : Package<"core">, ParentPackage; // Note: OptIn is *not* intended for checkers that are too noisy to be on by // default. Such checkers belong in the alpha package. def OptIn : Package<"optin">; + def CoreOptIn : Package<"core">, ParentPackage; // In the Portability package reside checkers for finding code that relies on @@ -43,6 +44,9 @@ def CoreOptIn : Package<"core">, ParentPackage; // development, but unwanted for developers who target only a single platform. def PortabilityOptIn : Package<"portability">, ParentPackage; +// Optional checkers related to taint security analysis. +def TaintOptIn : Package<"taint">, ParentPackage; + def Nullability : Package<"nullability">, PackageOptions<[ CmdLineOption, HelpText<"Check calls to various UNIX/Posix functions">, Documentation; +def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">, + HelpText<"Check for calls to blocking functions inside a critical section">, + Documentation; + def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">, HelpText<"The base of several malloc() related checkers. On it's own it " "emits no reports, but adds valuable information to the analysis " @@ -619,10 +627,6 @@ def SimpleStreamChecker : Checker<"SimpleStream">, HelpText<"Check for misuses of stream APIs">, Documentation; -def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">, - HelpText<"Check for calls to blocking functions inside a critical section">, - Documentation; - } // end "alpha.unix" //===----------------------------------------------------------------------===// @@ -1011,6 +1015,16 @@ def FloatLoopCounter : Checker<"FloatLoopCounter">, Dependencies<[SecuritySyntaxChecker]>, Documentation; +def PutenvStackArray : Checker<"PutenvStackArray">, + HelpText<"Finds calls to the function 'putenv' which pass a pointer to " + "an automatic (stack-allocated) array as the argument.">, + Documentation; + +def SetgidSetuidOrderChecker : Checker<"SetgidSetuidOrder">, + HelpText<"Warn on possible reversed order of 'setgid(getgid()))' and " + "'setuid(getuid())' (CERT: POS36-C)">, + Documentation; + } // end "security" let ParentPackage = ENV in { @@ -1030,15 +1044,6 @@ let ParentPackage = ENV in { } // end "security.cert.env" -let ParentPackage = POSAlpha in { - - def PutenvWithAuto : Checker<"34c">, - HelpText<"Finds calls to the 'putenv' function which pass a pointer to " - "an automatic variable as the argument.">, - Documentation; - -} // end "alpha.cert.pos" - let ParentPackage = SecurityAlpha in { def ArrayBoundChecker : Checker<"ArrayBound">, @@ -1049,10 +1054,6 @@ def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">, HelpText<"Warn about buffer overflows (newer checker)">, Documentation; -def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, - HelpText<"Check for an out-of-bound pointer being returned to callers">, - Documentation; - def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, HelpText<"Check for overflows in the arguments to malloc()">, Documentation; @@ -1073,6 +1074,10 @@ def MmapWriteExecChecker : Checker<"MmapWriteExec">, ]>, Documentation; +def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, + HelpText<"Check for an out-of-bound pointer being returned to callers">, + Documentation; + } // end "alpha.security" //===----------------------------------------------------------------------===// @@ -1717,6 +1722,23 @@ def UnixAPIPortabilityChecker : Checker<"UnixAPI">, } // end optin.portability + +//===----------------------------------------------------------------------===// +// Taint checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = TaintOptIn in { + +def TaintedAllocChecker: Checker<"TaintedAlloc">, + HelpText<"Check for memory allocations, where the size parameter " + "might be a tainted (attacker controlled) value.">, + Dependencies<[DynamicMemoryModeling]>, + //FIXME: GenericTaintChecker should be a dependency, but only after it + //is transformed into a modeling checker + Documentation; + +} // end "optin.taint" + //===----------------------------------------------------------------------===// // NonDeterminism checkers. //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index da51292296a90fa0ee9bec7daac0b320c49061b6..3de19d756da00d729fba3b0da458040ca89bcdc2 100644 --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H #include "clang/Basic/LLVM.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/Utils.h" @@ -138,6 +139,10 @@ struct ModuleDeps { /// determined that the differences are benign for this compilation. std::vector ClangModuleDeps; + /// The set of libraries or frameworks to link against when + /// an entity from this module is used. + llvm::SmallVector LinkLibraries; + /// Get (or compute) the compiler invocation that can be used to build this /// module. Does not include argv[0]. const std::vector &getBuildArguments(); diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp index 789bb97d81de004724f759f16f0dc7a496909f9d..039d09fa7cf5753e6d23e1ebc725bffd01906ea6 100644 --- a/clang/lib/APINotes/APINotesManager.cpp +++ b/clang/lib/APINotes/APINotesManager.cpp @@ -12,6 +12,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceMgrAdapter.h" #include "clang/Basic/Version.h" diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 8c77b563657d9073aa6cde9035d47c52cd9c32f0..d8e33ff421c06c8da15d2635c8ad02da062f8afb 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -90,7 +90,7 @@ QualType APValue::LValueBase::getType() const { // For a materialized temporary, the type of the temporary we materialized // may not be the type of the expression. if (const MaterializeTemporaryExpr *MTE = - clang::dyn_cast(Base)) { + llvm::dyn_cast(Base)) { SmallVector CommaLHSs; SmallVector Adjustments; const Expr *Temp = MTE->getSubExpr(); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 52eab5feb062bc5c58d6dc19e3218643501a8c2e..bf74e56a14799c7ed1666bbb1b6ea7c315d49253 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5006,9 +5006,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); - // Look through qualified template names. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = QTN->getUnderlyingTemplate(); const auto *TD = Template.getAsTemplateDecl(); bool IsTypeAlias = TD && TD->isTypeAlias(); @@ -5044,10 +5041,6 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); - // Look through qualified template names. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getUnderlyingTemplate()); - // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); bool AnyNonCanonArgs = false; @@ -5262,10 +5255,12 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) { Arg = TemplateArgument(E); } else { auto *TTP = cast(Param); + TemplateName Name = getQualifiedTemplateName( + nullptr, /*TemplateKeyword=*/false, TemplateName(TTP)); if (TTP->isParameterPack()) - Arg = TemplateArgument(TemplateName(TTP), std::optional()); + Arg = TemplateArgument(Name, std::optional()); else - Arg = TemplateArgument(TemplateName(TTP)); + Arg = TemplateArgument(Name); } if (Param->isTemplateParameterPack()) @@ -6494,7 +6489,8 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X, if (!TTPX->hasDefaultArgument() || !TTPY->hasDefaultArgument()) return false; - return hasSameType(TTPX->getDefaultArgument(), TTPY->getDefaultArgument()); + return hasSameType(TTPX->getDefaultArgument().getArgument().getAsType(), + TTPY->getDefaultArgument().getArgument().getAsType()); } if (auto *NTTPX = dyn_cast(X)) { @@ -6502,8 +6498,10 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X, if (!NTTPX->hasDefaultArgument() || !NTTPY->hasDefaultArgument()) return false; - Expr *DefaultArgumentX = NTTPX->getDefaultArgument()->IgnoreImpCasts(); - Expr *DefaultArgumentY = NTTPY->getDefaultArgument()->IgnoreImpCasts(); + Expr *DefaultArgumentX = + NTTPX->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts(); + Expr *DefaultArgumentY = + NTTPY->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts(); llvm::FoldingSetNodeID XID, YID; DefaultArgumentX->Profile(XID, *this, /*Canonical=*/true); DefaultArgumentY->Profile(YID, *this, /*Canonical=*/true); @@ -6796,7 +6794,7 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { // Using shadow declarations with the same target match. if (const auto *USX = dyn_cast(X)) { const auto *USY = cast(Y); - return USX->getTargetDecl() == USY->getTargetDecl(); + return declaresSameEntity(USX->getTargetDecl(), USY->getTargetDecl()); } // Using declarations with the same qualifier match. (We already know that @@ -9301,7 +9299,8 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateName Template) const { - assert(NNS && "Missing nested-name-specifier in qualified template name"); + assert(Template.getKind() == TemplateName::Template || + Template.getKind() == TemplateName::UsingTemplate); // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; @@ -12019,7 +12018,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; // Variables in other module units shouldn't be forced to be emitted. - if (VD->isInAnotherModuleUnit()) + if (VD->shouldEmitInExternalSource()) return false; // Variables that can be needed in other TUs are required. diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 7b0d5f9cc1a93d57aab3474820567bee5a85c3ca..0680ff5e3a3851382e7f537a7fdc4ef04421070a 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -1215,46 +1215,19 @@ class TemplateDiff { bool &NeedAddressOf) { if (!Iter.isEnd()) { switch (Iter->getKind()) { - default: - llvm_unreachable("unknown ArgumentKind"); - case TemplateArgument::Integral: - Value = Iter->getAsIntegral(); - HasInt = true; - IntType = Iter->getIntegralType(); - return; - case TemplateArgument::Declaration: { - VD = Iter->getAsDecl(); - QualType ArgType = Iter->getParamTypeForDecl(); - QualType VDType = VD->getType(); - if (ArgType->isPointerType() && - Context.hasSameType(ArgType->getPointeeType(), VDType)) - NeedAddressOf = true; - return; - } - case TemplateArgument::NullPtr: - IsNullPtr = true; - return; - case TemplateArgument::Expression: - E = Iter->getAsExpr(); - } - } else if (!Default->isParameterPack()) { - E = Default->getDefaultArgument(); - } - - if (!Iter.hasDesugaredTA()) return; - - const TemplateArgument& TA = Iter.getDesugaredTA(); - switch (TA.getKind()) { - default: - llvm_unreachable("unknown ArgumentKind"); + case TemplateArgument::StructuralValue: + // FIXME: Diffing of structural values is not implemented. + // There is no possible fallback in this case, this will show up + // as '(no argument)'. + return; case TemplateArgument::Integral: - Value = TA.getAsIntegral(); + Value = Iter->getAsIntegral(); HasInt = true; - IntType = TA.getIntegralType(); + IntType = Iter->getIntegralType(); return; case TemplateArgument::Declaration: { - VD = TA.getAsDecl(); - QualType ArgType = TA.getParamTypeForDecl(); + VD = Iter->getAsDecl(); + QualType ArgType = Iter->getParamTypeForDecl(); QualType VDType = VD->getType(); if (ArgType->isPointerType() && Context.hasSameType(ArgType->getPointeeType(), VDType)) @@ -1265,13 +1238,62 @@ class TemplateDiff { IsNullPtr = true; return; case TemplateArgument::Expression: - // TODO: Sometimes, the desugared template argument Expr differs from - // the sugared template argument Expr. It may be useful in the future - // but for now, it is just discarded. - if (!E) - E = TA.getAsExpr(); - return; + E = Iter->getAsExpr(); + break; + case TemplateArgument::Null: + case TemplateArgument::Type: + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + llvm_unreachable("TemplateArgument kind is not expected for NTTP"); + case TemplateArgument::Pack: + llvm_unreachable("TemplateArgument kind should be handled elsewhere"); + } + } else if (!Default->isParameterPack()) { + E = Default->getDefaultArgument().getArgument().getAsExpr(); } + + if (!Iter.hasDesugaredTA()) + return; + + const TemplateArgument &TA = Iter.getDesugaredTA(); + switch (TA.getKind()) { + case TemplateArgument::StructuralValue: + // FIXME: Diffing of structural values is not implemented. + // Just fall back to the expression. + return; + case TemplateArgument::Integral: + Value = TA.getAsIntegral(); + HasInt = true; + IntType = TA.getIntegralType(); + return; + case TemplateArgument::Declaration: { + VD = TA.getAsDecl(); + QualType ArgType = TA.getParamTypeForDecl(); + QualType VDType = VD->getType(); + if (ArgType->isPointerType() && + Context.hasSameType(ArgType->getPointeeType(), VDType)) + NeedAddressOf = true; + return; + } + case TemplateArgument::NullPtr: + IsNullPtr = true; + return; + case TemplateArgument::Expression: + // TODO: Sometimes, the desugared template argument Expr differs from + // the sugared template argument Expr. It may be useful in the future + // but for now, it is just discarded. + if (!E) + E = TA.getAsExpr(); + return; + case TemplateArgument::Null: + case TemplateArgument::Type: + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + llvm_unreachable("TemplateArgument kind is not expected for NTTP"); + case TemplateArgument::Pack: + llvm_unreachable("TemplateArgument kind should be handled elsewhere"); + } + llvm_unreachable("Unexpected TemplateArgument kind"); } /// DiffNonTypes - Handles any template parameters not handled by DiffTypes @@ -1914,6 +1936,11 @@ class TemplateDiff { return; } + if (E) { + PrintExpr(E); + return; + } + OS << "(no argument)"; } diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 6efc5bb92e28d2b55759fea257725621faa5a84d..c8973fdeda352de04253a8e02629e0f0eda670aa 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclLookups.h" #include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/Builtins.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9ff8e1ea78d85282c57194162dc0c3c36c86f31b..3b9080e09b33139cc8c44a0078f6d7eda7a43025 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2929,7 +2929,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // We may already have an enum of the same name; try to find and match it. EnumDecl *PrevDecl = nullptr; - if (!DC->isFunctionOrMethod() && SearchName) { + if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, SearchName); @@ -5917,11 +5917,11 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { } if (D->hasDefaultArgument()) { - Expected ToDefaultArgOrErr = - import(D->getDefaultArgumentInfo()); + Expected ToDefaultArgOrErr = + import(D->getDefaultArgument()); if (!ToDefaultArgOrErr) return ToDefaultArgOrErr.takeError(); - ToD->setDefaultArgument(*ToDefaultArgOrErr); + ToD->setDefaultArgument(ToD->getASTContext(), *ToDefaultArgOrErr); } return ToD; @@ -5949,10 +5949,11 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { return ToD; if (D->hasDefaultArgument()) { - ExpectedExpr ToDefaultArgOrErr = import(D->getDefaultArgument()); + Expected ToDefaultArgOrErr = + import(D->getDefaultArgument()); if (!ToDefaultArgOrErr) return ToDefaultArgOrErr.takeError(); - ToD->setDefaultArgument(*ToDefaultArgOrErr); + ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr); } return ToD; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 41fbfe281ef65b3a82e46e8b0cd622fe0b7d4914..1f19dadafa44e8b1a020dba0ae380c742fc110da 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1174,13 +1174,6 @@ Linkage NamedDecl::getLinkageInternal() const { .getLinkage(); } -/// Determine whether D is attached to a named module. -static bool isInNamedModule(const NamedDecl *D) { - if (auto *M = D->getOwningModule()) - return M->isNamedModule(); - return false; -} - static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) { // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { @@ -1190,7 +1183,7 @@ static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) { return false; case Decl::ModuleOwnershipKind::Visible: case Decl::ModuleOwnershipKind::VisibleWhenImported: - return isInNamedModule(D); + return D->isInNamedModule(); } llvm_unreachable("unexpected module ownership kind"); } @@ -1208,7 +1201,7 @@ Linkage NamedDecl::getFormalLinkage() const { // [basic.namespace.general]/p2 // A namespace is never attached to a named module and never has a name with // module linkage. - if (isInNamedModule(this) && InternalLinkage == Linkage::External && + if (isInNamedModule() && InternalLinkage == Linkage::External && !isExportedFromModuleInterfaceUnit( cast(this->getCanonicalDecl())) && !isa(this)) @@ -2408,9 +2401,11 @@ Expr *VarDecl::getInit() { return cast(S); auto *Eval = getEvaluatedStmt(); - return cast(Eval->Value.isOffset() - ? Eval->Value.get(getASTContext().getExternalSource()) - : Eval->Value.get(nullptr)); + + return cast_if_present( + Eval->Value.isOffset() + ? Eval->Value.get(getASTContext().getExternalSource()) + : Eval->Value.get(nullptr)); } Stmt **VarDecl::getInitAddress() { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 65d5eeb6354eba8820b96f1377beb68cb1988074..1e9c879e371bc176a442d8ec0b3933c8eb9eddb0 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -669,7 +669,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, IdentifierInfo *IIEnv = A->getEnvironment(); StringRef TargetEnv = Context.getTargetInfo().getTriple().getEnvironmentName(); - StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv); + StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName( + Context.getTargetInfo().getTriple().getEnvironment()); // Matching environment or no environment on attribute if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) { if (Message) { @@ -1099,23 +1100,22 @@ bool Decl::isInExportDeclContext() const { bool Decl::isInAnotherModuleUnit() const { auto *M = getOwningModule(); - if (!M) + if (!M || !M->isNamedModule()) return false; - M = M->getTopLevelModule(); - // FIXME: It is problematic if the header module lives in another module - // unit. Consider to fix this by techniques like - // ExternalASTSource::hasExternalDefinitions. - if (M->isHeaderLikeModule()) - return false; + return M != getASTContext().getCurrentNamedModule(); +} - // A global module without parent implies that we're parsing the global - // module. So it can't be in another module unit. - if (M->isGlobalModule()) +bool Decl::shouldEmitInExternalSource() const { + ExternalASTSource *Source = getASTContext().getExternalSource(); + if (!Source) return false; - assert(M->isNamedModule() && "New module kind?"); - return M != getASTContext().getCurrentNamedModule(); + return Source->hasExternalDefinitions(this) == ExternalASTSource::EK_Always; +} + +bool Decl::isInNamedModule() const { + return getOwningModule() && getOwningModule()->isNamedModule(); } bool Decl::isFromExplicitGlobalModule() const { diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index c5868256b440d9dd8513131229c87e737d64246a..0cf4e64f83b8df51a56e60347195894e89d6fe05 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1883,7 +1883,8 @@ void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) { if (TTP->hasDefaultArgument()) { Out << " = "; - Out << TTP->getDefaultArgument().getAsString(Policy); + TTP->getDefaultArgument().getArgument().print(Policy, Out, + /*IncludeType=*/false); } } @@ -1897,7 +1898,7 @@ void DeclPrinter::VisitNonTypeTemplateParmDecl( if (NTTP->hasDefaultArgument()) { Out << " = "; - NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy, Indentation, - "\n", &Context); + NTTP->getDefaultArgument().getArgument().print(Policy, Out, + /*IncludeType=*/false); } } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 26765a5da1dc64b40f97ecb366462f0d8861bfab..d952f7e181848b4febc8383e90100e8567600f63 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -627,9 +627,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { TemplateParameterList *Params = getTemplateParameters(); SmallVector TemplateArgs; Context.getInjectedTemplateArgs(Params, TemplateArgs); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(TemplateName(this), - TemplateArgs); + TemplateName Name = Context.getQualifiedTemplateName( + /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); + CommonPtr->InjectedClassNameType = + Context.getTemplateSpecializationType(Name, TemplateArgs); return CommonPtr->InjectedClassNameType; } @@ -669,23 +670,30 @@ TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID, } SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { - return hasDefaultArgument() - ? getDefaultArgumentInfo()->getTypeLoc().getBeginLoc() - : SourceLocation(); + return hasDefaultArgument() ? getDefaultArgument().getLocation() + : SourceLocation(); } SourceRange TemplateTypeParmDecl::getSourceRange() const { if (hasDefaultArgument() && !defaultArgumentWasInherited()) return SourceRange(getBeginLoc(), - getDefaultArgumentInfo()->getTypeLoc().getEndLoc()); + getDefaultArgument().getSourceRange().getEnd()); // TypeDecl::getSourceRange returns a range containing name location, which is // wrong for unnamed template parameters. e.g: // it will return <[[typename>]] instead of <[[typename]]> - else if (getDeclName().isEmpty()) + if (getDeclName().isEmpty()) return SourceRange(getBeginLoc()); return TypeDecl::getSourceRange(); } +void TemplateTypeParmDecl::setDefaultArgument( + const ASTContext &C, const TemplateArgumentLoc &DefArg) { + if (DefArg.getArgument().isNull()) + DefaultArgument.set(nullptr); + else + DefaultArgument.set(new (C) TemplateArgumentLoc(DefArg)); +} + unsigned TemplateTypeParmDecl::getDepth() const { return getTypeForDecl()->castAs()->getDepth(); } @@ -788,14 +796,21 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, SourceRange NonTypeTemplateParmDecl::getSourceRange() const { if (hasDefaultArgument() && !defaultArgumentWasInherited()) return SourceRange(getOuterLocStart(), - getDefaultArgument()->getSourceRange().getEnd()); + getDefaultArgument().getSourceRange().getEnd()); return DeclaratorDecl::getSourceRange(); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { - return hasDefaultArgument() - ? getDefaultArgument()->getSourceRange().getBegin() - : SourceLocation(); + return hasDefaultArgument() ? getDefaultArgument().getSourceRange().getBegin() + : SourceLocation(); +} + +void NonTypeTemplateParmDecl::setDefaultArgument( + const ASTContext &C, const TemplateArgumentLoc &DefArg) { + if (DefArg.getArgument().isNull()) + DefaultArgument.set(nullptr); + else + DefaultArgument.set(new (C) TemplateArgumentLoc(DefArg)); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index ac0b1b38f0162f40303fa574be856e8a04a914b5..f9d634550dc06100a39221fe23bd31657411d838 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3618,12 +3618,10 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ConceptSpecializationExprClass: case RequiresExprClass: case SYCLUniqueStableNameExprClass: + case PackIndexingExprClass: // These never have a side-effect. return false; - case PackIndexingExprClass: - return cast(this)->getSelectedExpr()->HasSideEffects( - Ctx, IncludePossibleEffects); case ConstantExprClass: // FIXME: Move this into the "return false;" block above. return cast(this)->getSubExpr()->HasSideEffects( diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index e96a4749685115bd6d989d2ad07b159793ed5f62..a5b6f80bde694c2a4fcd9127cf1f0c8f6aec3cbe 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -15,10 +15,10 @@ #include "clang/AST/ExternalASTSource.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/ASTSourceDescriptor.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/ErrorHandling.h" #include diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 859a3fabea32b19282f8dd8bddb55a1d74d331e9..3671c41ae7039c655daeb27272763160f4ef53b6 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1050,34 +1050,85 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, if (T->isRecordType()) { const Record *R = getRecord(E->getType()); - if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) { + if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) return this->visitInitializer(Inits[0]); + + auto initPrimitiveField = [=](const Record::Field *FieldToInit, + const Expr *Init, PrimType T) -> bool { + if (!this->visit(Init)) + return false; + + if (FieldToInit->isBitField()) { + if (!this->emitInitBitField(T, FieldToInit, E)) + return false; + } else { + if (!this->emitInitField(T, FieldToInit->Offset, E)) + return false; + } + return this->emitPopPtr(E); + }; + + auto initCompositeField = [=](const Record::Field *FieldToInit, + const Expr *Init) -> bool { + // Non-primitive case. Get a pointer to the field-to-initialize + // on the stack and recurse into visitInitializer(). + if (!this->emitGetPtrField(FieldToInit->Offset, Init)) + return false; + if (!this->visitInitializer(Init)) + return false; + return this->emitPopPtr(E); + }; + + if (R->isUnion()) { + if (Inits.size() == 0) { + // Zero-initialize the first union field. + if (R->getNumFields() == 0) + return this->emitFinishInit(E); + const Record::Field *FieldToInit = R->getField(0u); + QualType FieldType = FieldToInit->Desc->getType(); + if (std::optional T = classify(FieldType)) { + if (!this->visitZeroInitializer(*T, FieldType, E)) + return false; + if (!this->emitInitField(*T, FieldToInit->Offset, E)) + return false; + } + // FIXME: Non-primitive case? + } else { + const Expr *Init = Inits[0]; + const FieldDecl *FToInit = nullptr; + if (const auto *ILE = dyn_cast(E)) + FToInit = ILE->getInitializedFieldInUnion(); + else + FToInit = cast(E)->getInitializedFieldInUnion(); + + if (!this->emitDupPtr(E)) + return false; + + const Record::Field *FieldToInit = R->getField(FToInit); + if (std::optional T = classify(Init)) { + if (!initPrimitiveField(FieldToInit, Init, *T)) + return false; + } else { + if (!initCompositeField(FieldToInit, Init)) + return false; + } + } + return this->emitFinishInit(E); } + assert(!R->isUnion()); unsigned InitIndex = 0; for (const Expr *Init : Inits) { // Skip unnamed bitfields. while (InitIndex < R->getNumFields() && R->getField(InitIndex)->Decl->isUnnamedBitField()) ++InitIndex; - if (!this->emitDupPtr(E)) return false; if (std::optional T = classify(Init)) { const Record::Field *FieldToInit = R->getField(InitIndex); - if (!this->visit(Init)) - return false; - - if (FieldToInit->isBitField()) { - if (!this->emitInitBitField(*T, FieldToInit, E)) - return false; - } else { - if (!this->emitInitField(*T, FieldToInit->Offset, E)) - return false; - } - - if (!this->emitPopPtr(E)) + if (!initPrimitiveField(FieldToInit, Init, *T)) return false; ++InitIndex; } else { @@ -1095,21 +1146,13 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, // into the Record's fields. } else { const Record::Field *FieldToInit = R->getField(InitIndex); - // Non-primitive case. Get a pointer to the field-to-initialize - // on the stack and recurse into visitInitializer(). - if (!this->emitGetPtrField(FieldToInit->Offset, Init)) - return false; - - if (!this->visitInitializer(Init)) - return false; - - if (!this->emitPopPtr(E)) + if (!initCompositeField(FieldToInit, Init)) return false; ++InitIndex; } } } - return true; + return this->emitFinishInit(E); } if (T->isArrayType()) { @@ -1133,7 +1176,7 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, } } - return true; + return this->emitFinishInit(E); } if (const auto *ComplexTy = E->getType()->getAs()) { @@ -1594,6 +1637,12 @@ bool ByteCodeExprGen::VisitStringLiteral(const StringLiteral *E) { return true; } +template +bool ByteCodeExprGen::VisitObjCStringLiteral( + const ObjCStringLiteral *E) { + return this->delegate(E->getString()); +} + template bool ByteCodeExprGen::VisitSYCLUniqueStableNameExpr( const SYCLUniqueStableNameExpr *E) { @@ -2600,6 +2649,14 @@ bool ByteCodeExprGen::VisitShuffleVectorExpr( return true; } +template +bool ByteCodeExprGen::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { + if (!E->isExpressibleAsConstantInitializer()) + return this->emitInvalid(E); + + return this->delegate(E->getSubExpr()); +} + template bool ByteCodeExprGen::discard(const Expr *E) { OptionScope Scope(this, /*NewDiscardResult=*/true, /*NewInitializing=*/false); @@ -2615,6 +2672,9 @@ bool ByteCodeExprGen::delegate(const Expr *E) { } template bool ByteCodeExprGen::visit(const Expr *E) { + if (E->getType().isNull()) + return false; + if (E->getType()->isVoidType()) return this->discard(E); @@ -3020,12 +3080,22 @@ bool ByteCodeExprGen::visitDecl(const VarDecl *VD) { } } - // Return the value - if (VarT) - return this->emitRet(*VarT, VD); - - // Return non-primitive values as pointers here. - return this->emitRet(PT_Ptr, VD); + // Return the value. + if (!this->emitRet(VarT.value_or(PT_Ptr), VD)) { + // If the Ret above failed and this is a global variable, mark it as + // uninitialized, even everything else succeeded. + if (Context::shouldBeGloballyIndexed(VD)) { + auto GlobalIndex = P.getGlobal(VD); + assert(GlobalIndex); + Block *GlobalBlock = P.getGlobal(*GlobalIndex); + InlineDescriptor &ID = + *reinterpret_cast(GlobalBlock->rawData()); + ID.IsInitialized = false; + GlobalBlock->invokeDtor(); + } + return false; + } + return true; } template @@ -3281,7 +3351,8 @@ bool ByteCodeExprGen::VisitCallExpr(const CallExpr *E) { // write the result into. if (IsVirtual && !HasQualifier) { uint32_t VarArgSize = 0; - unsigned NumParams = Func->getNumWrittenParams(); + unsigned NumParams = + Func->getNumWrittenParams() + isa(E); for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I) VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr))); @@ -3715,13 +3786,13 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { return this->emitGetPtrLocal(Offset, E); } else if (auto GlobalIndex = P.getGlobal(D)) { if (IsReference) - return this->emitGetGlobalPtr(*GlobalIndex, E); + return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); return this->emitGetPtrGlobal(*GlobalIndex, E); } else if (const auto *PVD = dyn_cast(D)) { if (auto It = this->Params.find(PVD); It != this->Params.end()) { if (IsReference || !It->second.IsPtr) - return this->emitGetParamPtr(It->second.Offset, E); + return this->emitGetParam(classifyPrim(E), It->second.Offset, E); return this->emitGetPtrParam(It->second.Offset, E); } @@ -3752,7 +3823,8 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { } } else { if (const auto *VD = dyn_cast(D); - VD && VD->getAnyInitializer() && VD->getType().isConstQualified()) { + VD && VD->getAnyInitializer() && VD->getType().isConstQualified() && + !VD->isWeak()) { if (!this->visitVarDecl(VD)) return false; // Retry. @@ -3763,6 +3835,8 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { if (std::optional I = P.getOrCreateDummy(D)) { if (!this->emitGetPtrGlobal(*I, E)) return false; + if (E->getType()->isVoidType()) + return true; // Convert the dummy pointer to another pointer type if we have to. if (PrimType PT = classifyPrim(E); PT != PT_Ptr) { if (!this->emitDecayPtr(PT_Ptr, PT, E)) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index a2e283c86633251f9d4e725c15c696716c40d4cb..44c495240289f8b7251c776120762c2670aaceea 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -90,6 +90,7 @@ public: bool VisitOpaqueValueExpr(const OpaqueValueExpr *E); bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); bool VisitStringLiteral(const StringLiteral *E); + bool VisitObjCStringLiteral(const ObjCStringLiteral *E); bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E); bool VisitCharacterLiteral(const CharacterLiteral *E); bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); @@ -126,6 +127,7 @@ public: bool VisitAddrLabelExpr(const AddrLabelExpr *E); bool VisitConvertVectorExpr(const ConvertVectorExpr *E); bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); + bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index ff92bc117f9efb4082701089bb29b7cb4e10361d..6ee7898f228de41654a919e4c27d8cfedfb19c57 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -687,26 +687,29 @@ bool ByteCodeStmtGen::visitDefaultStmt(const DefaultStmt *S) { template bool ByteCodeStmtGen::visitAttributedStmt(const AttributedStmt *S) { - for (const Attr *A : S->getAttrs()) { - auto *AA = dyn_cast(A); - if (!AA) - continue; + if (this->Ctx.getLangOpts().CXXAssumptions && + !this->Ctx.getLangOpts().MSVCCompat) { + for (const Attr *A : S->getAttrs()) { + auto *AA = dyn_cast(A); + if (!AA) + continue; - assert(isa(S->getSubStmt())); + assert(isa(S->getSubStmt())); - const Expr *Assumption = AA->getAssumption(); - if (Assumption->isValueDependent()) - return false; + const Expr *Assumption = AA->getAssumption(); + if (Assumption->isValueDependent()) + return false; - if (Assumption->HasSideEffects(this->Ctx.getASTContext())) - continue; + if (Assumption->HasSideEffects(this->Ctx.getASTContext())) + continue; - // Evaluate assumption. - if (!this->visitBool(Assumption)) - return false; + // Evaluate assumption. + if (!this->visitBool(Assumption)) + return false; - if (!this->emitAssume(Assumption)) - return false; + if (!this->emitAssume(Assumption)) + return false; + } } // Ignore other attributes. diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index d51a57e5e92eae17070b18116d16a1d59e9f486f..b0b22b059b77ad03fe671833da769bba72c91fb6 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -46,6 +46,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue()); if (Res.isInvalid()) { + C.cleanup(); Stk.clear(); return false; } @@ -70,6 +71,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { auto Res = C.interpretExpr(E); if (Res.isInvalid()) { + C.cleanup(); Stk.clear(); return false; } @@ -97,6 +99,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, (VD->getType()->isRecordType() || VD->getType()->isArrayType()); auto Res = C.interpretDecl(VD, CheckGlobalInitialized); if (Res.isInvalid()) { + C.cleanup(); Stk.clear(); return false; } @@ -164,7 +167,8 @@ std::optional Context::classify(QualType T) const { T->isFunctionType() || T->isSpecificBuiltinType(BuiltinType::BoundMember)) return PT_FnPtr; - if (T->isReferenceType() || T->isPointerType()) + if (T->isReferenceType() || T->isPointerType() || + T->isObjCObjectPointerType()) return PT_Ptr; if (const auto *AT = T->getAs()) diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index d0466902247b4bd33ab75b79e48391d260ab3aff..746b765ca421679b33a437b4ba1913c385efad26 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -137,9 +137,8 @@ static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst, } static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, - bool IsActive, const Descriptor *D, + bool IsActive, bool IsUnion, const Descriptor *D, unsigned FieldOffset) { - bool IsUnion = false; // FIXME auto *Desc = reinterpret_cast(Ptr + FieldOffset) - 1; Desc->Offset = FieldOffset; Desc->Desc = D; @@ -174,7 +173,7 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false); for (const auto &F : D->ElemRecord->fields()) - initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, F.Desc, + initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion, F.Desc, F.Offset); // If this is initializing a virtual base, we do NOT want to consider its @@ -193,7 +192,7 @@ static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, for (const auto &V : D->ElemRecord->bases()) initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false); for (const auto &F : D->ElemRecord->fields()) - initField(B, Ptr, IsConst, IsMutable, IsActive, F.Desc, F.Offset); + initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset); for (const auto &V : D->ElemRecord->virtual_bases()) initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true); } diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index ccdc96a79436dad25bcf595c537e7953b64fe042..3f8a92ed2f0bde33104cac48998ec017c87f40b1 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "Boolean.h" +#include "Context.h" +#include "EvaluationResult.h" #include "Floating.h" #include "Function.h" #include "FunctionPointer.h" @@ -150,7 +152,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const { } Desc->dump(OS); OS << "\n"; - if (Desc->isPrimitive() && !Desc->isDummy()) { + if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) { OS << " "; { ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false}); @@ -305,3 +307,43 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const { OS << " Extern: " << IsExtern << "\n"; OS << " Initialized: " << IsInitialized << "\n"; } + +LLVM_DUMP_METHOD void EvaluationResult::dump() const { + assert(Ctx); + auto &OS = llvm::errs(); + const ASTContext &ASTCtx = Ctx->getASTContext(); + + switch (Kind) { + case Empty: + OS << "Empty\n"; + break; + case RValue: + OS << "RValue: "; + std::get(Value).dump(OS, ASTCtx); + break; + case LValue: { + assert(Source); + QualType SourceType; + if (const auto *D = Source.dyn_cast()) { + if (const auto *VD = dyn_cast(D)) + SourceType = VD->getType(); + } else if (const auto *E = Source.dyn_cast()) { + SourceType = E->getType(); + } + + OS << "LValue: "; + if (const auto *P = std::get_if(&Value)) + P->toAPValue().printPretty(OS, ASTCtx, SourceType); + else if (const auto *FP = std::get_if(&Value)) // Nope + FP->toAPValue().printPretty(OS, ASTCtx, SourceType); + OS << "\n"; + break; + } + case Invalid: + OS << "Invalid\n"; + break; + case Valid: + OS << "Valid\n"; + break; + } +} diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 388c3612f292b099d41cf0888ceb1337159fc9bc..6d8aa3f20f01f51dd9e2b2f2e9161a5ad515161a 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -32,6 +32,11 @@ EvalEmitter::~EvalEmitter() { } } +/// Clean up all our resources. This needs to done in failed evaluations before +/// we call InterpStack::clear(), because there might be a Pointer on the stack +/// pointing into a Block in the EvalEmitter. +void EvalEmitter::cleanup() { S.cleanup(); } + EvaluationResult EvalEmitter::interpretExpr(const Expr *E, bool ConvertResultToRValue) { S.setEvalLocation(E->getExprLoc()); diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h index 116f1d6fc134a7a0657b9089ef080b7f17bde2d0..98d6026bbcce487f0ac99b491ee55b3e6fe442e8 100644 --- a/clang/lib/AST/Interp/EvalEmitter.h +++ b/clang/lib/AST/Interp/EvalEmitter.h @@ -38,6 +38,9 @@ public: bool ConvertResultToRValue = false); EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized); + /// Clean up all resources. + void cleanup(); + InterpState &getState() { return S; } protected: diff --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp index e92d686c724cc8898e70eb10077532f6f117655f..c04b0fc0a11212b2124c75f673d6261c6f611d0a 100644 --- a/clang/lib/AST/Interp/EvaluationResult.cpp +++ b/clang/lib/AST/Interp/EvaluationResult.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "EvaluationResult.h" -#include "Context.h" #include "InterpState.h" #include "Record.h" #include "clang/AST/ExprCXX.h" @@ -101,6 +100,10 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, Pointer FieldPtr = BasePtr.atField(F.Offset); QualType FieldType = F.Decl->getType(); + // Don't check inactive union members. + if (R->isUnion() && !FieldPtr.isActive()) + continue; + if (FieldType->isRecordType()) { Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord()); } else if (FieldType->isIncompleteArrayType()) { @@ -155,45 +158,5 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S, return CheckArrayInitialized(S, InitLoc, Ptr, CAT); } -void EvaluationResult::dump() const { - assert(Ctx); - auto &OS = llvm::errs(); - const ASTContext &ASTCtx = Ctx->getASTContext(); - - switch (Kind) { - case Empty: - OS << "Empty\n"; - break; - case RValue: - OS << "RValue: "; - std::get(Value).dump(OS, ASTCtx); - break; - case LValue: { - assert(Source); - QualType SourceType; - if (const auto *D = Source.dyn_cast()) { - if (const auto *VD = dyn_cast(D)) - SourceType = VD->getType(); - } else if (const auto *E = Source.dyn_cast()) { - SourceType = E->getType(); - } - - OS << "LValue: "; - if (const auto *P = std::get_if(&Value)) - P->toAPValue().printPretty(OS, ASTCtx, SourceType); - else if (const auto *FP = std::get_if(&Value)) // Nope - FP->toAPValue().printPretty(OS, ASTCtx, SourceType); - OS << "\n"; - break; - } - case Invalid: - OS << "Invalid\n"; - break; - case Valid: - OS << "Valid\n"; - break; - } -} - } // namespace interp } // namespace clang diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 3e4da487e43c34c7c62d076a777b2c781db7d47a..145fa65791da207a2534d04c9ea9085abdadac52 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "llvm/ADT/APSInt.h" @@ -76,18 +77,15 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, } else { S.FFDiag(E); } - } else if (const auto *VD = dyn_cast(D)) { - if (!VD->getType().isConstQualified()) { - diagnoseNonConstVariable(S, OpPC, VD); - return false; - } - - // const, but no initializer. - if (!VD->getAnyInitializer()) { - diagnoseMissingInitializer(S, OpPC, VD); - return false; - } + return false; } + + if (!D->getType().isConstQualified()) + diagnoseNonConstVariable(S, OpPC, D); + else if (const auto *VD = dyn_cast(D); + VD && !VD->getAnyInitializer()) + diagnoseMissingInitializer(S, OpPC, VD); + return false; } @@ -104,6 +102,11 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, return; } + // Rather random, but this is to match the diagnostic output of the current + // interpreter. + if (isa(VD)) + return; + if (VD->getType()->isIntegralOrEnumerationType()) { S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD; S.Note(VD->getLocation(), diag::note_declared_at); @@ -454,16 +457,16 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckConstant(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Read)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; if (!CheckRange(S, OpPC, Ptr, AK_Read)) return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) - return false; if (!CheckActive(S, OpPC, Ptr, AK_Read)) return false; + if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + return false; if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) return false; if (!CheckMutable(S, OpPC, Ptr)) @@ -474,7 +477,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckLive(S, OpPC, Ptr, AK_Assign)) return false; - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Assign)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; @@ -657,7 +660,8 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { return diagnoseUnknownDecl(S, OpPC, D); } -bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { +bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK) { if (!Ptr.isDummy()) return true; @@ -666,7 +670,15 @@ bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!D) return false; - return diagnoseUnknownDecl(S, OpPC, D); + if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement) + return diagnoseUnknownDecl(S, OpPC, D); + + assert(AK == AK_Assign); + if (S.getLangOpts().CPlusPlus11) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.FFDiag(E, diag::note_constexpr_modify_global); + } + return false; } bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index bc2ca126ce364982cc312d166d52c9773bbe2e29..eca1792e64718e024dfff24a9cd73a176272d049 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -56,7 +56,8 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); /// Checks if a pointer is a dummy pointer. -bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); /// Checks if a pointer is null. bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, @@ -588,7 +589,7 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { template ::T> bool Inc(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) return false; if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) return false; @@ -602,7 +603,7 @@ bool Inc(InterpState &S, CodePtr OpPC) { template ::T> bool IncPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) return false; if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) return false; @@ -617,7 +618,7 @@ bool IncPop(InterpState &S, CodePtr OpPC) { template ::T> bool Dec(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) return false; if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) return false; @@ -631,7 +632,7 @@ bool Dec(InterpState &S, CodePtr OpPC) { template ::T> bool DecPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr)) + if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) return false; if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) return false; @@ -1335,16 +1336,19 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { inline bool FinishInitPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (Ptr.canBeInitialized()) + if (Ptr.canBeInitialized()) { Ptr.initialize(); + Ptr.activate(); + } return true; } inline bool FinishInit(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek(); - - if (Ptr.canBeInitialized()) + if (Ptr.canBeInitialized()) { Ptr.initialize(); + Ptr.activate(); + } return true; } @@ -1370,9 +1374,6 @@ inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const Pointer &Ptr = S.Stk.pop(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; - if (Ptr.isDummy()) // FIXME: Once we have type info for dummy pointers, this - // needs to go. - return false; return VirtBaseHelper(S, OpPC, D, Ptr); } @@ -1538,9 +1539,6 @@ inline bool Memcpy(InterpState &S, CodePtr OpPC) { template bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr) { - if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) - return false; - // A zero offset does not change the pointer. if (Offset.isZero()) { S.Stk.push(Ptr); @@ -1558,8 +1556,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, if (!CheckArray(S, OpPC, Ptr)) return false; - uint64_t Index = Ptr.getIndex(); uint64_t MaxIndex = static_cast(Ptr.getNumElems()); + uint64_t Index; + if (Ptr.isOnePastEnd()) + Index = MaxIndex; + else + Index = Ptr.getIndex(); bool Invalid = false; // Helper to report an invalid offset, computed as APSInt. diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h index 506034e880d0bd72252acc7be4497c4774f06633..2bb195648a9a9125959e06d2bc9fadada0375b2e 100644 --- a/clang/lib/AST/Interp/InterpBlock.h +++ b/clang/lib/AST/Interp/InterpBlock.h @@ -125,13 +125,15 @@ public: void dump() const { dump(llvm::errs()); } void dump(llvm::raw_ostream &OS) const; -protected: +private: friend class Pointer; friend class DeadBlock; friend class InterpState; Block(const Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) - : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {} + : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) { + assert(Desc); + } /// Deletes a dead block at the end of its lifetime. void cleanup(); diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 565c85bc2e0c218c8135b3cf68c0cc0af04eda7d..00206d09c113d9ef7a51dc17ce4a597299510942 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -214,7 +214,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, if (!CheckLive(S, OpPC, StrPtr, AK_Read)) return false; - if (!CheckDummy(S, OpPC, StrPtr)) + if (!CheckDummy(S, OpPC, StrPtr, AK_Read)) return false; assert(StrPtr.getFieldDesc()->isPrimitiveArray()); diff --git a/clang/lib/AST/Interp/InterpState.cpp b/clang/lib/AST/Interp/InterpState.cpp index 2cb87ef07fe5882c5fcb275d5c68c0e3a2e52f05..550bc9f1a84b975facdbfca3dc4dfd1fbd2bbe1b 100644 --- a/clang/lib/AST/Interp/InterpState.cpp +++ b/clang/lib/AST/Interp/InterpState.cpp @@ -33,6 +33,8 @@ InterpState::~InterpState() { } } +void InterpState::cleanup() {} + Frame *InterpState::getCurrentFrame() { if (Current && Current->Caller) return Current; diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index d483c60c58e248c6c45f65b027178b686c6d1b79..0938a723a76d093546ec272e3835b6ec6512bc89 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -39,6 +39,8 @@ public: ~InterpState(); + void cleanup(); + InterpState(const InterpState &) = delete; InterpState &operator=(const InterpState &) = delete; diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index ee8cedccb8d4bb9e4ec372c8cc78103e2dd8828d..252f7ea46086f9c742fd980c2b4e6a774bb0fcc2 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -144,13 +144,18 @@ APValue Pointer::toAPValue() const { // TODO: compute the offset into the object. CharUnits Offset = CharUnits::Zero(); - bool IsOnePastEnd = isOnePastEnd(); // Build the path into the object. Pointer Ptr = *this; while (Ptr.isField() || Ptr.isArrayElement()) { - if (Ptr.isArrayElement()) { - Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); + if (Ptr.isArrayRoot()) { + Path.push_back(APValue::LValuePathEntry::ArrayIndex(0)); + Ptr = Ptr.getBase(); + } else if (Ptr.isArrayElement()) { + if (Ptr.isOnePastEnd()) + Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getArray().getNumElems())); + else + Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); Ptr = Ptr.getArray(); } else { // TODO: figure out if base is virtual @@ -173,7 +178,7 @@ APValue Pointer::toAPValue() const { // Just invert the order of the elements. std::reverse(Path.begin(), Path.end()); - return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false); + return APValue(Base, Offset, Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); } void Pointer::print(llvm::raw_ostream &OS) const { @@ -346,6 +351,7 @@ std::optional Pointer::toRValue(const Context &Ctx) const { } else { Ok &= Composite(FieldTy, FP, Value); } + ActiveField = FP.getFieldDesc()->asFieldDecl(); break; } } diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 3ade5756e580ef9a50c4055304af42e98938666a..93ca754d04a644a119dc3893296dd668de3240a9 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -314,12 +314,14 @@ public: /// Returns the type of the innermost field. QualType getType() const { if (inPrimitiveArray() && Offset != asBlockPointer().Base) { - // Unfortunately, complex types are not array types in clang, but they are - // for us. + // Unfortunately, complex and vector types are not array types in clang, + // but they are for us. if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) return AT->getElementType(); if (const auto *CT = getFieldDesc()->getType()->getAs()) return CT->getElementType(); + if (const auto *CT = getFieldDesc()->getType()->getAs()) + return CT->getElementType(); } return getFieldDesc()->getType(); } @@ -535,9 +537,6 @@ public: if (isZero()) return 0; - if (isElementPastEnd()) - return 1; - // narrow()ed element in a composite array. if (asBlockPointer().Base > sizeof(InlineDescriptor) && asBlockPointer().Base == Offset) diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h index 05a094d0c5b1ff122160b900448d89373d0668f9..604fb5dfde1e416983fb7028bc3d3b7c71e23ca9 100644 --- a/clang/lib/AST/Interp/PrimType.h +++ b/clang/lib/AST/Interp/PrimType.h @@ -30,20 +30,20 @@ template class Integral; /// Enumeration of the primitive types of the VM. enum PrimType : unsigned { - PT_Sint8, - PT_Uint8, - PT_Sint16, - PT_Uint16, - PT_Sint32, - PT_Uint32, - PT_Sint64, - PT_Uint64, - PT_IntAP, - PT_IntAPS, - PT_Bool, - PT_Float, - PT_Ptr, - PT_FnPtr, + PT_Sint8 = 0, + PT_Uint8 = 1, + PT_Sint16 = 2, + PT_Uint16 = 3, + PT_Sint32 = 4, + PT_Uint32 = 5, + PT_Sint64 = 6, + PT_Uint64 = 7, + PT_IntAP = 8, + PT_IntAPS = 9, + PT_Bool = 10, + PT_Float = 11, + PT_Ptr = 12, + PT_FnPtr = 13, }; inline constexpr bool isPtrType(PrimType T) { diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index 36b5a1faa513a913e7908a457778ffb204b97eb2..ec7c0744b8856a1801be540b64807ca4c0bab2cb 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -45,7 +45,8 @@ public: // but primitive arrays might have an InitMap* heap allocated and // that needs to be freed. for (Global *G : Globals) - G->block()->invokeDtor(); + if (Block *B = G->block(); B->isInitialized()) + B->invokeDtor(); // Records might actually allocate memory themselves, but they // are allocated using a BumpPtrAllocator. Call their desctructors diff --git a/clang/lib/AST/Interp/Record.cpp b/clang/lib/AST/Interp/Record.cpp index 6a0a28bc9124bcc15e7a7dc00a3cb7ac132a2aa1..8ded765fc1c41bc83ec5891f7c1342e4b4db1111 100644 --- a/clang/lib/AST/Interp/Record.cpp +++ b/clang/lib/AST/Interp/Record.cpp @@ -16,7 +16,7 @@ Record::Record(const RecordDecl *Decl, BaseList &&SrcBases, FieldList &&SrcFields, VirtualBaseList &&SrcVirtualBases, unsigned VirtualSize, unsigned BaseSize) : Decl(Decl), Bases(std::move(SrcBases)), Fields(std::move(SrcFields)), - BaseSize(BaseSize), VirtualSize(VirtualSize) { + BaseSize(BaseSize), VirtualSize(VirtualSize), IsUnion(Decl->isUnion()) { for (Base &V : SrcVirtualBases) VirtualBases.push_back({ V.Decl, V.Offset + BaseSize, V.Desc, V.R }); diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h index cf0480b3f62fa668ceff6a442c728b5ff653c3ed..83e15b125f77a96e698b5ce1c5ecc2c51d282816 100644 --- a/clang/lib/AST/Interp/Record.h +++ b/clang/lib/AST/Interp/Record.h @@ -53,7 +53,7 @@ public: /// Returns the name of the underlying declaration. const std::string getName() const; /// Checks if the record is a union. - bool isUnion() const { return getDecl()->isUnion(); } + bool isUnion() const { return IsUnion; } /// Returns the size of the record. unsigned getSize() const { return BaseSize; } /// Returns the full size of the record, including records. @@ -132,6 +132,8 @@ private: unsigned BaseSize; /// Size of all virtual bases. unsigned VirtualSize; + /// If this record is a union. + bool IsUnion; }; } // namespace interp diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 42608476b1c195ca9c23bd0b91b7cfb822316857..3bbb3a905e9b91caacf658c9c608982b8afac6c6 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1028,7 +1028,7 @@ void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->hasDefaultArgument()) JOS.attributeObject("defaultArg", [=] { - Visit(D->getDefaultArgument(), SourceRange(), + Visit(D->getDefaultArgument().getArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), D->defaultArgumentWasInherited() ? "inherited from" : "previous"); }); @@ -1044,7 +1044,7 @@ void JSONNodeDumper::VisitNonTypeTemplateParmDecl( if (D->hasDefaultArgument()) JOS.attributeObject("defaultArg", [=] { - Visit(D->getDefaultArgument(), SourceRange(), + Visit(D->getDefaultArgument().getArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), D->defaultArgumentWasInherited() ? "inherited from" : "previous"); }); diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp index 5b1cdc16e2ea2cfbac2d21ff32910306ee930b89..37f0f68c92355f13f24a248cd21cb130dd58dceb 100644 --- a/clang/lib/AST/ODRDiagsEmitter.cpp +++ b/clang/lib/AST/ODRDiagsEmitter.cpp @@ -1409,13 +1409,15 @@ bool ODRDiagsEmitter::diagnoseMismatch( } if (HasFirstDefaultArgument && HasSecondDefaultArgument) { - QualType FirstType = FirstTTPD->getDefaultArgument(); - QualType SecondType = SecondTTPD->getDefaultArgument(); - if (computeODRHash(FirstType) != computeODRHash(SecondType)) { + TemplateArgument FirstTA = + FirstTTPD->getDefaultArgument().getArgument(); + TemplateArgument SecondTA = + SecondTTPD->getDefaultArgument().getArgument(); + if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) { DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument) - << (i + 1) << FirstType; + << (i + 1) << FirstTA; DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument) - << (i + 1) << SecondType; + << (i + 1) << SecondTA; return true; } } @@ -1521,8 +1523,11 @@ bool ODRDiagsEmitter::diagnoseMismatch( } if (HasFirstDefaultArgument && HasSecondDefaultArgument) { - Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument(); - Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument(); + TemplateArgument FirstDefaultArgument = + FirstNTTPD->getDefaultArgument().getArgument(); + TemplateArgument SecondDefaultArgument = + SecondNTTPD->getDefaultArgument().getArgument(); + if (computeODRHash(FirstDefaultArgument) != computeODRHash(SecondDefaultArgument)) { DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument) diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 6f04739cf6693d612d9464075b7699624568bad9..1249531eab09fcda73741cf0a63af4ff022c7a75 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -146,10 +146,17 @@ void ODRHash::AddTemplateName(TemplateName Name) { case TemplateName::Template: AddDecl(Name.getAsTemplateDecl()); break; + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); + if (NestedNameSpecifier *NNS = QTN->getQualifier()) + AddNestedNameSpecifier(NNS); + AddBoolean(QTN->hasTemplateKeyword()); + AddTemplateName(QTN->getUnderlyingTemplate()); + break; + } // TODO: Support these cases. case TemplateName::OverloadedTemplate: case TemplateName::AssumedTemplate: - case TemplateName::QualifiedTemplate: case TemplateName::DependentTemplate: case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: @@ -462,7 +469,7 @@ public: D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Hash.AddBoolean(hasDefaultArgument); if (hasDefaultArgument) { - AddTemplateArgument(D->getDefaultArgument()); + AddTemplateArgument(D->getDefaultArgument().getArgument()); } Hash.AddBoolean(D->isParameterPack()); @@ -480,7 +487,7 @@ public: D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Hash.AddBoolean(hasDefaultArgument); if (hasDefaultArgument) { - AddStmt(D->getDefaultArgument()); + AddTemplateArgument(D->getDefaultArgument().getArgument()); } Hash.AddBoolean(D->isParameterPack()); diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index cb2c7f98be75cb171a4e88065ecf45af27f59e6d..403ce9a2215713a8849d27f786e3ecabf02582ce 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -320,6 +320,48 @@ OpenACCReductionClause *OpenACCReductionClause::Create( OpenACCReductionClause(BeginLoc, LParenLoc, Operator, VarList, EndLoc); } +OpenACCAutoClause *OpenACCAutoClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCAutoClause)); + return new (Mem) OpenACCAutoClause(BeginLoc, EndLoc); +} + +OpenACCIndependentClause * +OpenACCIndependentClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCIndependentClause)); + return new (Mem) OpenACCIndependentClause(BeginLoc, EndLoc); +} + +OpenACCSeqClause *OpenACCSeqClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCSeqClause)); + return new (Mem) OpenACCSeqClause(BeginLoc, EndLoc); +} + +OpenACCGangClause *OpenACCGangClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCGangClause)); + return new (Mem) OpenACCGangClause(BeginLoc, EndLoc); +} + +OpenACCWorkerClause *OpenACCWorkerClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCWorkerClause)); + return new (Mem) OpenACCWorkerClause(BeginLoc, EndLoc); +} + +OpenACCVectorClause *OpenACCVectorClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCVectorClause)); + return new (Mem) OpenACCVectorClause(BeginLoc, EndLoc); +} + //===----------------------------------------------------------------------===// // OpenACC clauses printing methods //===----------------------------------------------------------------------===// @@ -495,3 +537,16 @@ void OpenACCClausePrinter::VisitDeviceTypeClause( }); OS << ")"; } + +void OpenACCClausePrinter::VisitAutoClause(const OpenACCAutoClause &C) { + OS << "auto"; +} + +void OpenACCClausePrinter::VisitIndependentClause( + const OpenACCIndependentClause &C) { + OS << "independent"; +} + +void OpenACCClausePrinter::VisitSeqClause(const OpenACCSeqClause &C) { + OS << "seq"; +} diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp index 3d6a1cc84c7b10616ac4d87952a6157df4964f18..534793b837bbb7aa5060a555c6a3d17f58325198 100644 --- a/clang/lib/AST/ParentMap.cpp +++ b/clang/lib/AST/ParentMap.cpp @@ -97,6 +97,22 @@ static void BuildParentMap(MapTy& M, Stmt* S, BuildParentMap(M, SubStmt, OVMode); } break; + case Stmt::CXXDefaultArgExprClass: + if (auto *Arg = dyn_cast(S)) { + if (Arg->hasRewrittenInit()) { + M[Arg->getExpr()] = S; + BuildParentMap(M, Arg->getExpr(), OVMode); + } + } + break; + case Stmt::CXXDefaultInitExprClass: + if (auto *Init = dyn_cast(S)) { + if (Init->hasRewrittenInit()) { + M[Init->getExpr()] = S; + BuildParentMap(M, Init->getExpr(), OVMode); + } + } + break; default: for (Stmt *SubStmt : S->children()) { if (SubStmt) { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 066377423df76eaf35318fd87288d9c8bf8ee0f9..18ac4b1eb57e780f3b1f683be8ca67febe49b29f 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -65,8 +65,9 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, assert(ArgTDecl != nullptr); QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); - if (QTName && !QTName->hasTemplateKeyword()) { - NNS = QTName->getQualifier(); + if (QTName && + !QTName->hasTemplateKeyword() && + (NNS = QTName->getQualifier())) { NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( Ctx, NNS, WithGlobalNsPrefix); if (QNNS != NNS) { diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index a381a8dd7b62c30a1fb0fdf7ddd5e3b24f0eb9b0..2d864a28857966970ec5c666baf4cf4faaca4c0f 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -12,6 +12,8 @@ #include "clang/AST/StmtOpenACC.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/StmtCXX.h" using namespace clang; OpenACCComputeConstruct * @@ -23,15 +25,101 @@ OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) { return Inst; } -OpenACCComputeConstruct * -OpenACCComputeConstruct::Create(const ASTContext &C, OpenACCDirectiveKind K, - SourceLocation BeginLoc, SourceLocation EndLoc, - ArrayRef Clauses, - Stmt *StructuredBlock) { +OpenACCComputeConstruct *OpenACCComputeConstruct::Create( + const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *StructuredBlock, + ArrayRef AssociatedLoopConstructs) { void *Mem = C.Allocate( OpenACCComputeConstruct::totalSizeToAlloc( Clauses.size())); - auto *Inst = new (Mem) - OpenACCComputeConstruct(K, BeginLoc, EndLoc, Clauses, StructuredBlock); + auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, DirLoc, EndLoc, + Clauses, StructuredBlock); + + llvm::for_each(AssociatedLoopConstructs, [&](OpenACCLoopConstruct *C) { + C->setParentComputeConstruct(Inst); + }); + + return Inst; +} + +void OpenACCComputeConstruct::findAndSetChildLoops() { + struct LoopConstructFinder : RecursiveASTVisitor { + OpenACCComputeConstruct *Construct = nullptr; + + LoopConstructFinder(OpenACCComputeConstruct *Construct) + : Construct(Construct) {} + + bool TraverseOpenACCComputeConstruct(OpenACCComputeConstruct *C) { + // Stop searching if we find a compute construct. + return true; + } + bool TraverseOpenACCLoopConstruct(OpenACCLoopConstruct *C) { + // Stop searching if we find a loop construct, after taking ownership of + // it. + C->setParentComputeConstruct(Construct); + return true; + } + }; + + LoopConstructFinder f(this); + f.TraverseStmt(getAssociatedStmt()); +} + +OpenACCLoopConstruct::OpenACCLoopConstruct(unsigned NumClauses) + : OpenACCAssociatedStmtConstruct( + OpenACCLoopConstructClass, OpenACCDirectiveKind::Loop, + SourceLocation{}, SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList( + MutableArrayRef(getTrailingObjects(), NumClauses)); +} + +OpenACCLoopConstruct::OpenACCLoopConstruct( + SourceLocation Start, SourceLocation DirLoc, SourceLocation End, + ArrayRef Clauses, Stmt *Loop) + : OpenACCAssociatedStmtConstruct(OpenACCLoopConstructClass, + OpenACCDirectiveKind::Loop, Start, DirLoc, + End, Loop) { + // accept 'nullptr' for the loop. This is diagnosed somewhere, but this gives + // us some level of AST fidelity in the error case. + assert((Loop == nullptr || isa(Loop)) && + "Associated Loop not a for loop?"); + // Initialize the trailing storage. + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); +} + +void OpenACCLoopConstruct::setLoop(Stmt *Loop) { + assert((isa(Loop)) && + "Associated Loop not a for loop?"); + setAssociatedStmt(Loop); +} + +OpenACCLoopConstruct *OpenACCLoopConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = + C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCLoopConstruct(NumClauses); + return Inst; +} + +OpenACCLoopConstruct * +OpenACCLoopConstruct::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *Loop) { + void *Mem = + C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCLoopConstruct(BeginLoc, DirLoc, EndLoc, Clauses, Loop); return Inst; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index be2d5a2eb6b46d1bf63df77bbdc7dd2cdd085fe5..7e030e0551269077388b8cc24a8f7fd72e90b92c 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1156,6 +1156,19 @@ void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { PrintStmt(S->getStructuredBlock()); } +void StmtPrinter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) { + Indent() << "#pragma acc loop"; + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; + + PrintStmt(S->getLoop()); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 00b8c43af035c74e66cfb13070cad734ba7deaef..d1655905a665662064c40c0b69b4acb585a2844d 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2589,6 +2589,13 @@ void OpenACCClauseProfiler::VisitWaitClause(const OpenACCWaitClause &Clause) { void OpenACCClauseProfiler::VisitDeviceTypeClause( const OpenACCDeviceTypeClause &Clause) {} +void OpenACCClauseProfiler::VisitAutoClause(const OpenACCAutoClause &Clause) {} + +void OpenACCClauseProfiler::VisitIndependentClause( + const OpenACCIndependentClause &Clause) {} + +void OpenACCClauseProfiler::VisitSeqClause(const OpenACCSeqClause &Clause) {} + void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { for (auto *E : Clause.getVarList()) @@ -2605,6 +2612,14 @@ void StmtProfiler::VisitOpenACCComputeConstruct( P.VisitOpenACCClauseList(S->clauses()); } +void StmtProfiler::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) { + // VisitStmt handles children, so the Loop is handled. + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical, bool ProfileLambdaExpr) const { StmtProfilerWithPointers Profiler(ID, Context, Canonical, ProfileLambdaExpr); diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 3310d7dc24c59d2ef6690d090c4c1f7826e31918..46f7b79b272ef3f791205df30409a2d750caac9b 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -221,8 +221,13 @@ static const ValueDecl *getAsSimpleValueDeclRef(const ASTContext &Ctx, // We model class non-type template parameters as their template parameter // object declaration. - if (V.isStruct() || V.isUnion()) + if (V.isStruct() || V.isUnion()) { + // Dependent types are not supposed to be described as + // TemplateParamObjectDecls. + if (T->isDependentType() || T->isInstantiationDependentType()) + return nullptr; return Ctx.getTemplateParamObjectDecl(T, V); + } // Pointers and references with an empty path use the special 'Declaration' // representation. @@ -538,9 +543,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, Out << "nullptr"; break; - case Template: - getAsTemplate().print(Out, Policy, TemplateName::Qualified::Fully); + case Template: { + getAsTemplate().print(Out, Policy); break; + } case TemplateExpansion: getAsTemplateOrTemplatePattern().print(Out, Policy); diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 2f0e4181e9408668e360ea5697e3f771793697d0..4fc25cb34803e06b9bee607db56e6eaab3159cb3 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -214,29 +214,12 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { return nullptr; } -TemplateName TemplateName::getNameToSubstitute() const { - TemplateDecl *Decl = getAsTemplateDecl(); - - // Substituting a dependent template name: preserve it as written. - if (!Decl) - return *this; - - // If we have a template declaration, use the most recent non-friend - // declaration of that template. - Decl = cast(Decl->getMostRecentDecl()); - while (Decl->getFriendObjectKind()) { - Decl = cast(Decl->getPreviousDecl()); - assert(Decl && "all declarations of template are friends"); - } - return TemplateName(Decl); -} - TemplateNameDependence TemplateName::getDependence() const { auto D = TemplateNameDependence::None; switch (getKind()) { case TemplateName::NameKind::QualifiedTemplate: - D |= toTemplateNameDependence( - getAsQualifiedTemplateName()->getQualifier()->getDependence()); + if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier()) + D |= toTemplateNameDependence(NNS->getDependence()); break; case TemplateName::NameKind::DependentTemplate: D |= toTemplateNameDependence( @@ -292,9 +275,16 @@ void TemplateName::Profile(llvm::FoldingSetNodeID &ID) { void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Qualified Qual) const { - auto Kind = getKind(); - TemplateDecl *Template = nullptr; - if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) { + auto handleAnonymousTTP = [](TemplateDecl *TD, raw_ostream &OS) { + if (TemplateTemplateParmDecl *TTP = dyn_cast(TD); + TTP && TTP->getIdentifier() == nullptr) { + OS << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex(); + return true; + } + return false; + }; + if (NameKind Kind = getKind(); + Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) { // After `namespace ns { using std::vector }`, what is the fully-qualified // name of the UsingTemplateName `vector` within ns? // @@ -304,46 +294,49 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, // Similar to the UsingType behavior, using declarations are used to import // names more often than to export them, thus using the original name is // most useful in this case. - Template = getAsTemplateDecl(); - } - - if (Template) - if (Policy.CleanUglifiedParameters && - isa(Template) && Template->getIdentifier()) - OS << Template->getIdentifier()->deuglifiedName(); - else if (Qual == Qualified::Fully && - getDependence() != - TemplateNameDependenceScope::DependentInstantiation) - Template->printQualifiedName(OS, Policy); - else - OS << *Template; - else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { - if (Qual == Qualified::Fully && - getDependence() != - TemplateNameDependenceScope::DependentInstantiation) { - QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName( - OS, Policy); + TemplateDecl *Template = getAsTemplateDecl(); + if (handleAnonymousTTP(Template, OS)) return; - } - if (Qual == Qualified::AsWritten) - QTN->getQualifier()->print(OS, Policy); + if (Qual == Qualified::None) + OS << *Template; + else + Template->printQualifiedName(OS, Policy); + } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + if (NestedNameSpecifier *NNS = QTN->getQualifier(); + Qual != Qualified::None && NNS) + NNS->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl(); + + TemplateName Underlying = QTN->getUnderlyingTemplate(); + assert(Underlying.getKind() == TemplateName::Template || + Underlying.getKind() == TemplateName::UsingTemplate); + + TemplateDecl *UTD = Underlying.getAsTemplateDecl(); + + if (handleAnonymousTTP(UTD, OS)) + return; + + if (IdentifierInfo *II = UTD->getIdentifier(); + Policy.CleanUglifiedParameters && II && + isa(UTD)) + OS << II->deuglifiedName(); + else + OS << *UTD; } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { - if (Qual == Qualified::AsWritten && DTN->getQualifier()) - DTN->getQualifier()->print(OS, Policy); + if (NestedNameSpecifier *NNS = DTN->getQualifier()) + NNS->print(OS, Policy); OS << "template "; if (DTN->isIdentifier()) OS << DTN->getIdentifier()->getName(); else OS << "operator " << getOperatorSpelling(DTN->getOperator()); - } else if (SubstTemplateTemplateParmStorage *subst - = getAsSubstTemplateTemplateParm()) { + } else if (SubstTemplateTemplateParmStorage *subst = + getAsSubstTemplateTemplateParm()) { subst->getReplacement().print(OS, Policy, Qual); - } else if (SubstTemplateTemplateParmPackStorage *SubstPack - = getAsSubstTemplateTemplateParmPack()) + } else if (SubstTemplateTemplateParmPackStorage *SubstPack = + getAsSubstTemplateTemplateParmPack()) OS << *SubstPack->getParameterPack(); else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { Assumed->getDeclName().print(OS, Policy); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 4a1e94ffe283ba3eebc78f595b06c40cd4b113a8..8bacceea0f22b48622cdcfacc4a6556eb0fbc446 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -398,11 +398,13 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { OS << '(' << cast(C)->getDefaultClauseKind() << ')'; break; case OpenACCClauseKind::Async: + case OpenACCClauseKind::Auto: case OpenACCClauseKind::Attach: case OpenACCClauseKind::Copy: case OpenACCClauseKind::PCopy: case OpenACCClauseKind::PresentOrCopy: case OpenACCClauseKind::If: + case OpenACCClauseKind::Independent: case OpenACCClauseKind::DevicePtr: case OpenACCClauseKind::FirstPrivate: case OpenACCClauseKind::NoCreate: @@ -411,6 +413,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::Present: case OpenACCClauseKind::Private: case OpenACCClauseKind::Self: + case OpenACCClauseKind::Seq: case OpenACCClauseKind::VectorLength: // The condition expression will be printed as a part of the 'children', // but print 'clause' here so it is clear what is happening from the dump. @@ -947,6 +950,26 @@ void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { }); } +void TextNodeDumper::dumpTemplateArgument(const TemplateArgument &TA) { + llvm::SmallString<128> Str; + { + llvm::raw_svector_ostream SS(Str); + TA.print(PrintPolicy, SS, /*IncludeType=*/true); + } + OS << " '" << Str << "'"; + + if (TemplateArgument CanonTA = Context->getCanonicalTemplateArgument(TA); + !CanonTA.structurallyEquals(TA)) { + llvm::SmallString<128> CanonStr; + { + llvm::raw_svector_ostream SS(CanonStr); + CanonTA.print(PrintPolicy, SS, /*IncludeType=*/true); + } + if (CanonStr != Str) + OS << ":'" << CanonStr << "'"; + } +} + const char *TextNodeDumper::getCommandName(unsigned CommandID) { if (Traits) return Traits->getCommandInfo(CommandID)->Name; @@ -1086,45 +1109,126 @@ void TextNodeDumper::VisitNullTemplateArgument(const TemplateArgument &) { void TextNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) { OS << " type"; - dumpType(TA.getAsType()); + dumpTemplateArgument(TA); } void TextNodeDumper::VisitDeclarationTemplateArgument( const TemplateArgument &TA) { OS << " decl"; + dumpTemplateArgument(TA); dumpDeclRef(TA.getAsDecl()); } -void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) { OS << " nullptr"; + dumpTemplateArgument(TA); } void TextNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) { - OS << " integral " << TA.getAsIntegral(); + OS << " integral"; + dumpTemplateArgument(TA); +} + +void TextNodeDumper::dumpTemplateName(TemplateName TN, StringRef Label) { + AddChild(Label, [=] { + { + llvm::SmallString<128> Str; + { + llvm::raw_svector_ostream SS(Str); + TN.print(SS, PrintPolicy); + } + OS << " '" << Str << "'"; + + if (TemplateName CanonTN = Context->getCanonicalTemplateName(TN); + CanonTN != TN) { + llvm::SmallString<128> CanonStr; + { + llvm::raw_svector_ostream SS(CanonStr); + CanonTN.print(SS, PrintPolicy); + } + if (CanonStr != Str) + OS << ":'" << CanonStr << "'"; + } + } + dumpBareTemplateName(TN); + }); +} + +void TextNodeDumper::dumpBareTemplateName(TemplateName TN) { + switch (TN.getKind()) { + case TemplateName::Template: + AddChild([=] { Visit(TN.getAsTemplateDecl()); }); + return; + case TemplateName::UsingTemplate: { + const UsingShadowDecl *USD = TN.getAsUsingShadowDecl(); + AddChild([=] { Visit(USD); }); + AddChild("target", [=] { Visit(USD->getTargetDecl()); }); + return; + } + case TemplateName::QualifiedTemplate: { + OS << " qualified"; + const QualifiedTemplateName *QTN = TN.getAsQualifiedTemplateName(); + if (QTN->hasTemplateKeyword()) + OS << " keyword"; + dumpNestedNameSpecifier(QTN->getQualifier()); + dumpBareTemplateName(QTN->getUnderlyingTemplate()); + return; + } + case TemplateName::DependentTemplate: { + OS << " dependent"; + const DependentTemplateName *DTN = TN.getAsDependentTemplateName(); + dumpNestedNameSpecifier(DTN->getQualifier()); + return; + } + case TemplateName::SubstTemplateTemplateParm: { + OS << " subst"; + const SubstTemplateTemplateParmStorage *STS = + TN.getAsSubstTemplateTemplateParm(); + OS << " index " << STS->getIndex(); + if (std::optional PackIndex = STS->getPackIndex()) + OS << " pack_index " << *PackIndex; + if (const TemplateTemplateParmDecl *P = STS->getParameter()) + AddChild("parameter", [=] { Visit(P); }); + dumpDeclRef(STS->getAssociatedDecl(), "associated"); + dumpTemplateName(STS->getReplacement(), "replacement"); + return; + } + // FIXME: Implement these. + case TemplateName::OverloadedTemplate: + OS << " overloaded"; + return; + case TemplateName::AssumedTemplate: + OS << " assumed"; + return; + case TemplateName::SubstTemplateTemplateParmPack: + OS << " subst_pack"; + return; + } + llvm_unreachable("Unexpected TemplateName Kind"); } void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) { - if (TA.getAsTemplate().getKind() == TemplateName::UsingTemplate) - OS << " using"; - OS << " template "; - TA.getAsTemplate().dump(OS); + OS << " template"; + dumpTemplateArgument(TA); + dumpBareTemplateName(TA.getAsTemplate()); } void TextNodeDumper::VisitTemplateExpansionTemplateArgument( const TemplateArgument &TA) { - if (TA.getAsTemplateOrTemplatePattern().getKind() == - TemplateName::UsingTemplate) - OS << " using"; - OS << " template expansion "; - TA.getAsTemplateOrTemplatePattern().dump(OS); + OS << " template expansion"; + dumpTemplateArgument(TA); + dumpBareTemplateName(TA.getAsTemplateOrTemplatePattern()); } -void TextNodeDumper::VisitExpressionTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitExpressionTemplateArgument( + const TemplateArgument &TA) { OS << " expr"; + dumpTemplateArgument(TA); } -void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) { OS << " pack"; + dumpTemplateArgument(TA); } static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { @@ -1913,18 +2017,14 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) { void TextNodeDumper::VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *T) { - if (T->getTemplateName().getKind() == TemplateName::UsingTemplate) - OS << " using"; + dumpTemplateName(T->getTemplateName(), "name"); } void TextNodeDumper::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { if (T->isTypeAlias()) OS << " alias"; - if (T->getTemplateName().getKind() == TemplateName::UsingTemplate) - OS << " using"; - OS << " "; - T->getTemplateName().dump(OS); + dumpTemplateName(T->getTemplateName(), "name"); } void TextNodeDumper::VisitInjectedClassNameType( @@ -2772,3 +2872,10 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) { void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) { OS << " " << S->getDirectiveKind(); } +void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) { + + if (S->isOrphanedLoopConstruct()) + OS << " "; + else + OS << " parent: " << S->getParentComputeConstruct(); +} diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 3b90b8229dd1866812a70d316b8119eb10c944ab..2097b29b7e0b6d972ea562938ddc375c9af2a414 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -632,6 +632,16 @@ bool Type::isStructureType() const { return false; } +bool Type::isStructureTypeWithFlexibleArrayMember() const { + const auto *RT = getAs(); + if (!RT) + return false; + const auto *Decl = RT->getDecl(); + if (!Decl->isStruct()) + return false; + return Decl->hasFlexibleArrayMember(); +} + bool Type::isObjCBoxableRecordType() const { if (const auto *RT = getAs()) return RT->getDecl()->hasAttr(); @@ -4241,7 +4251,8 @@ TemplateSpecializationType::TemplateSpecializationType( assert((T.getKind() == TemplateName::Template || T.getKind() == TemplateName::SubstTemplateTemplateParm || T.getKind() == TemplateName::SubstTemplateTemplateParmPack || - T.getKind() == TemplateName::UsingTemplate) && + T.getKind() == TemplateName::UsingTemplate || + T.getKind() == TemplateName::QualifiedTemplate) && "Unexpected template name for TemplateSpecializationType"); auto *TemplateArgs = reinterpret_cast(this + 1); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 87f0a8728d85062dcc3553a9410b3a4d7a24e00b..58d01705d607b27825d6824201c43fd1f6d07b06 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1586,14 +1586,14 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, IncludeStrongLifetimeRAII Strong(Policy); TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(); - // FIXME: Null TD never excercised in test suite. + // FIXME: Null TD never exercised in test suite. if (FullyQualify && TD) { if (!Policy.SuppressScope) AppendScope(TD->getDeclContext(), OS, TD->getDeclName()); OS << TD->getName(); } else { - T->getTemplateName().print(OS, Policy); + T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None); } DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); @@ -2273,16 +2273,17 @@ bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg, if (auto *TTPD = dyn_cast(Param)) { return TTPD->hasDefaultArgument() && - isSubstitutedTemplateArgument(Ctx, Arg, TTPD->getDefaultArgument(), - Args, Depth); + isSubstitutedTemplateArgument( + Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth); } else if (auto *TTPD = dyn_cast(Param)) { return TTPD->hasDefaultArgument() && isSubstitutedTemplateArgument( Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth); } else if (auto *NTTPD = dyn_cast(Param)) { return NTTPD->hasDefaultArgument() && - isSubstitutedTemplateArgument(Ctx, Arg, NTTPD->getDefaultArgument(), - Args, Depth); + isSubstitutedTemplateArgument( + Ctx, Arg, NTTPD->getDefaultArgument().getArgument(), Args, + Depth); } return false; } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 64e6155de090c5f3e0626968485ca104baa00f9e..02317257c2740523b8a3747464659de9842fe6b5 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -556,6 +556,10 @@ public: private: // Visitors to walk an AST and construct the CFG. + CFGBlock *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Default, + AddStmtChoice asc); + CFGBlock *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Default, + AddStmtChoice asc); CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc); CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc); @@ -2254,16 +2258,10 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc, asc, ExternallyDestructed); case Stmt::CXXDefaultArgExprClass: + return VisitCXXDefaultArgExpr(cast(S), asc); + case Stmt::CXXDefaultInitExprClass: - // FIXME: The expression inside a CXXDefaultArgExpr is owned by the - // called function's declaration, not by the caller. If we simply add - // this expression to the CFG, we could end up with the same Expr - // appearing multiple times (PR13385). - // - // It's likewise possible for multiple CXXDefaultInitExprs for the same - // expression to be used in the same function (through aggregate - // initialization). - return VisitStmt(S, asc); + return VisitCXXDefaultInitExpr(cast(S), asc); case Stmt::CXXBindTemporaryExprClass: return VisitCXXBindTemporaryExpr(cast(S), asc); @@ -2433,6 +2431,40 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) { return B; } +CFGBlock *CFGBuilder::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Arg, + AddStmtChoice asc) { + if (Arg->hasRewrittenInit()) { + if (asc.alwaysAdd(*this, Arg)) { + autoCreateBlock(); + appendStmt(Block, Arg); + } + return VisitStmt(Arg->getExpr(), asc); + } + + // We can't add the default argument if it's not rewritten because the + // expression inside a CXXDefaultArgExpr is owned by the called function's + // declaration, not by the caller, we could end up with the same expression + // appearing multiple times. + return VisitStmt(Arg, asc); +} + +CFGBlock *CFGBuilder::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Init, + AddStmtChoice asc) { + if (Init->hasRewrittenInit()) { + if (asc.alwaysAdd(*this, Init)) { + autoCreateBlock(); + appendStmt(Block, Init); + } + return VisitStmt(Init->getExpr(), asc); + } + + // We can't add the default initializer if it's not rewritten because multiple + // CXXDefaultInitExprs for the same sub-expression to be used in the same + // function (through aggregate initialization). we could end up with the same + // expression appearing multiple times. + return VisitStmt(Init, asc); +} + CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) { if (asc.alwaysAdd(*this, ILE)) { autoCreateBlock(); diff --git a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp index bd1676583ecccdec2c1d262c4bba9c4d6e2878ae..38b5f51b7b2f0280b5747d28cd508771c7463587 100644 --- a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp +++ b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp @@ -188,90 +188,96 @@ static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) { return nullptr; } -static void getReferencedDecls(const Decl &D, ReferencedDecls &Referenced) { - insertIfGlobal(D, Referenced.Globals); - insertIfFunction(D, Referenced.Functions); - if (const auto *Decomp = dyn_cast(&D)) - for (const auto *B : Decomp->bindings()) - if (auto *ME = dyn_cast_or_null(B->getBinding())) - // FIXME: should we be using `E->getFoundDecl()`? - if (const auto *FD = dyn_cast(ME->getMemberDecl())) - Referenced.Fields.insert(FD); -} +class ReferencedDeclsVisitor + : public AnalysisASTVisitor { +public: + ReferencedDeclsVisitor(ReferencedDecls &Referenced) + : Referenced(Referenced) {} + + void TraverseConstructorInits(const CXXConstructorDecl *Ctor) { + for (const CXXCtorInitializer *Init : Ctor->inits()) { + if (Init->isMemberInitializer()) { + Referenced.Fields.insert(Init->getMember()); + } else if (Init->isIndirectMemberInitializer()) { + for (const auto *I : Init->getIndirectMember()->chain()) + Referenced.Fields.insert(cast(I)); + } + + Expr *InitExpr = Init->getInit(); + + // Also collect declarations referenced in `InitExpr`. + TraverseStmt(InitExpr); -/// Traverses `S` and inserts into `Referenced` any declarations that are -/// declared in or referenced from sub-statements. -static void getReferencedDecls(const Stmt &S, ReferencedDecls &Referenced) { - for (auto *Child : S.children()) - if (Child != nullptr) - getReferencedDecls(*Child, Referenced); - if (const auto *DefaultArg = dyn_cast(&S)) - getReferencedDecls(*DefaultArg->getExpr(), Referenced); - if (const auto *DefaultInit = dyn_cast(&S)) - getReferencedDecls(*DefaultInit->getExpr(), Referenced); - - if (auto *DS = dyn_cast(&S)) { - if (DS->isSingleDecl()) - getReferencedDecls(*DS->getSingleDecl(), Referenced); - else - for (auto *D : DS->getDeclGroup()) - getReferencedDecls(*D, Referenced); - } else if (auto *E = dyn_cast(&S)) { + // If this is a `CXXDefaultInitExpr`, also collect declarations referenced + // within the default expression. + if (auto *DefaultInit = dyn_cast(InitExpr)) + TraverseStmt(DefaultInit->getExpr()); + } + } + + bool VisitDecl(Decl *D) { + insertIfGlobal(*D, Referenced.Globals); + insertIfFunction(*D, Referenced.Functions); + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { insertIfGlobal(*E->getDecl(), Referenced.Globals); insertIfFunction(*E->getDecl(), Referenced.Functions); - } else if (const auto *C = dyn_cast(&S)) { + return true; + } + + bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) { // If this is a method that returns a member variable but does nothing else, // model the field of the return value. if (MemberExpr *E = getMemberForAccessor(*C)) if (const auto *FD = dyn_cast(E->getMemberDecl())) Referenced.Fields.insert(FD); - } else if (auto *E = dyn_cast(&S)) { + return true; + } + + bool VisitMemberExpr(MemberExpr *E) { // FIXME: should we be using `E->getFoundDecl()`? const ValueDecl *VD = E->getMemberDecl(); insertIfGlobal(*VD, Referenced.Globals); insertIfFunction(*VD, Referenced.Functions); if (const auto *FD = dyn_cast(VD)) Referenced.Fields.insert(FD); - } else if (auto *InitList = dyn_cast(&S)) { + return true; + } + + bool VisitInitListExpr(InitListExpr *InitList) { if (InitList->getType()->isRecordType()) for (const auto *FD : getFieldsForInitListExpr(InitList)) Referenced.Fields.insert(FD); - } else if (auto *ParenInitList = dyn_cast(&S)) { + return true; + } + + bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) { if (ParenInitList->getType()->isRecordType()) for (const auto *FD : getFieldsForInitListExpr(ParenInitList)) Referenced.Fields.insert(FD); + return true; } -} + +private: + ReferencedDecls &Referenced; +}; ReferencedDecls getReferencedDecls(const FunctionDecl &FD) { ReferencedDecls Result; - // Look for global variable and field references in the - // constructor-initializers. - if (const auto *CtorDecl = dyn_cast(&FD)) { - for (const auto *Init : CtorDecl->inits()) { - if (Init->isMemberInitializer()) { - Result.Fields.insert(Init->getMember()); - } else if (Init->isIndirectMemberInitializer()) { - for (const auto *I : Init->getIndirectMember()->chain()) - Result.Fields.insert(cast(I)); - } - const Expr *E = Init->getInit(); - assert(E != nullptr); - getReferencedDecls(*E, Result); - } - // Add all fields mentioned in default member initializers. - for (const FieldDecl *F : CtorDecl->getParent()->fields()) - if (const auto *I = F->getInClassInitializer()) - getReferencedDecls(*I, Result); - } - getReferencedDecls(*FD.getBody(), Result); + ReferencedDeclsVisitor Visitor(Result); + Visitor.TraverseStmt(FD.getBody()); + if (const auto *CtorDecl = dyn_cast(&FD)) + Visitor.TraverseConstructorInits(CtorDecl); return Result; } ReferencedDecls getReferencedDecls(const Stmt &S) { ReferencedDecls Result; - getReferencedDecls(S, Result); + ReferencedDeclsVisitor Visitor(Result); + Visitor.TraverseStmt(const_cast(&S)); return Result; } diff --git a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt index f89d4e57e58199b74adf5cbedddf65d3643d8e49..05cdaa7e27823d573c56dfa94b9a6b96f6491ea3 100644 --- a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt @@ -37,3 +37,4 @@ add_custom_command(OUTPUT HTMLLogger.inc DEPENDS ${CLANG_SOURCE_DIR}/utils/bundle_resources.py HTMLLogger.html HTMLLogger.css HTMLLogger.js VERBATIM) add_custom_target(clangAnalysisFlowSensitiveResources DEPENDS HTMLLogger.inc) +set_target_properties(clangAnalysisFlowSensitiveResources PROPERTIES FOLDER "Clang/Misc") diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 338a85525b38485201d677c3b294453d897f5fd0..0d7967c8b934497e032ed7803c19044029482c77 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -297,7 +297,7 @@ namespace { // Visitor that builds a map from record prvalues to result objects. // For each result object that it encounters, it propagates the storage location // of the result object to all record prvalues that can initialize it. -class ResultObjectVisitor : public RecursiveASTVisitor { +class ResultObjectVisitor : public AnalysisASTVisitor { public: // `ResultObjectMap` will be filled with a map from record prvalues to result // object. If this visitor will traverse a function that returns a record by @@ -310,10 +310,6 @@ public: : ResultObjectMap(ResultObjectMap), LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {} - bool shouldVisitImplicitCode() { return true; } - - bool shouldVisitLambdaBody() const { return false; } - // Traverse all member and base initializers of `Ctor`. This function is not // called by `RecursiveASTVisitor`; it should be called manually if we are // analyzing a constructor. `ThisPointeeLoc` is the storage location that @@ -342,37 +338,6 @@ public: } } - bool TraverseDecl(Decl *D) { - // Don't traverse nested record or function declarations. - // - We won't be analyzing code contained in these anyway - // - We don't model fields that are used only in these nested declaration, - // so trying to propagate a result object to initializers of such fields - // would cause an error. - if (isa_and_nonnull(D) || isa_and_nonnull(D)) - return true; - - return RecursiveASTVisitor::TraverseDecl(D); - } - - // Don't traverse expressions in unevaluated contexts, as we don't model - // fields that are only used in these. - // Note: The operand of the `noexcept` operator is an unevaluated operand, but - // nevertheless it appears in the Clang CFG, so we don't exclude it here. - bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; } - bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; } - bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; } - bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) { - return true; - } - - bool TraverseBindingDecl(BindingDecl *BD) { - // `RecursiveASTVisitor` doesn't traverse holding variables for - // `BindingDecl`s by itself, so we need to tell it to. - if (VarDecl *HoldingVar = BD->getHoldingVar()) - TraverseDecl(HoldingVar); - return RecursiveASTVisitor::TraverseBindingDecl(BD); - } - bool VisitVarDecl(VarDecl *VD) { if (VD->getType()->isRecordType() && VD->hasInit()) PropagateResultObject( diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 4214488c98e5debe634c3f395954420a2d9e4b58..8109ac6a781e737504befad00533d23fba766f9c 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -147,6 +147,13 @@ public: const Expr *RHS = S->getRHS(); assert(RHS != nullptr); + // Do compound assignments up-front, as there are so many of them and we + // don't want to list all of them in the switch statement below. + // To avoid generating unnecessary values, we don't create a new value but + // instead leave it to the specific analysis to do this if desired. + if (S->isCompoundAssignmentOp()) + propagateStorageLocation(*S->getLHS(), *S, Env); + switch (S->getOpcode()) { case BO_Assign: { auto *LHSLoc = Env.getStorageLocation(*LHS); @@ -382,6 +389,20 @@ public: Env.setValue(*S, Env.makeNot(*SubExprVal)); break; } + case UO_PreInc: + case UO_PreDec: + // Propagate the storage location, but don't create a new value; to + // avoid generating unnecessary values, we leave it to the specific + // analysis to do this if desired. + propagateStorageLocation(*S->getSubExpr(), *S, Env); + break; + case UO_PostInc: + case UO_PostDec: + // Propagate the old value, but don't create a new value; to avoid + // generating unnecessary values, we leave it to the specific analysis + // to do this if desired. + propagateValue(*S->getSubExpr(), *S, Env); + break; default: break; } diff --git a/clang/lib/Analysis/MacroExpansionContext.cpp b/clang/lib/Analysis/MacroExpansionContext.cpp index 564e359668a5106a6d00dd5c81b7ce4e458ab262..b212b7f2457927c9affae19963a97251b688fa7e 100644 --- a/clang/lib/Analysis/MacroExpansionContext.cpp +++ b/clang/lib/Analysis/MacroExpansionContext.cpp @@ -12,7 +12,7 @@ #define DEBUG_TYPE "macro-expansion-context" -static void dumpTokenInto(const clang::Preprocessor &PP, clang::raw_ostream &OS, +static void dumpTokenInto(const clang::Preprocessor &PP, llvm::raw_ostream &OS, clang::Token Tok); namespace clang { diff --git a/clang/lib/Basic/ASTSourceDescriptor.cpp b/clang/lib/Basic/ASTSourceDescriptor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8072c08a51d3a3b37c73ec5e3ec14aa281a71ece --- /dev/null +++ b/clang/lib/Basic/ASTSourceDescriptor.cpp @@ -0,0 +1,33 @@ +//===- ASTSourceDescriptor.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// Defines the clang::ASTSourceDescriptor class, which abstracts clang modules +/// and precompiled header files +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/ASTSourceDescriptor.h" + +namespace clang { + +ASTSourceDescriptor::ASTSourceDescriptor(Module &M) + : Signature(M.Signature), ClangModule(&M) { + if (M.Directory) + Path = M.Directory->getName(); + if (auto File = M.getASTFile()) + ASTFile = File->getName(); +} + +std::string ASTSourceDescriptor::getModuleName() const { + if (ClangModule) + return ClangModule->Name; + else + return std::string(PCHModuleName); +} + +} // namespace clang diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 824d4a0e2eee57732132b0c33a61876113ca74a5..f30680552e0f5bb1ef615a4c4c5805c6ce2dfe9e 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -55,6 +55,7 @@ if(CLANG_VENDOR) endif() add_clang_library(clangBasic + ASTSourceDescriptor.cpp Attributes.cpp Builtins.cpp CLWarnings.cpp diff --git a/clang/lib/Basic/CharInfo.cpp b/clang/lib/Basic/CharInfo.cpp index d02054c9718f5fba694de81aa8faa33fe3642f5d..26d693b8e9b943f9e1f44810e7dbff4d07011e41 100644 --- a/clang/lib/Basic/CharInfo.cpp +++ b/clang/lib/Basic/CharInfo.cpp @@ -31,20 +31,20 @@ const uint16_t clang::charinfo::InfoTable[256] = { 0 , 0 , 0 , 0 , //32 SP 33 ! 34 " 35 # //36 $ 37 % 38 & 39 ' - CHAR_SPACE , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_SPACE , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , //40 ( 41 ) 42 * 43 + //44 , 45 - 46 . 47 / - CHAR_PUNCT , CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PERIOD , CHAR_PUNCT , //48 0 49 1 50 2 51 3 //52 4 53 5 54 6 55 7 CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , //56 8 57 9 58 : 59 ; //60 < 61 = 62 > 63 ? - CHAR_DIGIT , CHAR_DIGIT , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_DIGIT , CHAR_DIGIT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , //64 @ 65 A 66 B 67 C //68 D 69 E 70 F 71 G CHAR_PUNCT , CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , @@ -59,8 +59,8 @@ const uint16_t clang::charinfo::InfoTable[256] = { CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , //88 X 89 Y 90 Z 91 [ //92 \ 93 ] 94 ^ 95 _ - CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_RAWDEL , - CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER , + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_UNDER , //96 ` 97 a 98 b 99 c //100 d 101 e 102 f 103 g CHAR_PUNCT , CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , @@ -75,6 +75,6 @@ const uint16_t clang::charinfo::InfoTable[256] = { CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , //120 x 121 y 122 z 123 { //124 | 125 } 126 ~ 127 DEL - CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0 + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , 0 }; diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index e8ce15eb0decb784ab8f508b7c0bef092c33e3d2..e2609b9573cca5e3e0b1202645cb474ef320850a 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -42,6 +42,7 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = { CUDA_ENTRY(12, 2), CUDA_ENTRY(12, 3), CUDA_ENTRY(12, 4), + CUDA_ENTRY(12, 5), {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits::max())}, {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. }; @@ -111,6 +112,7 @@ static const CudaArchToStringMap arch_names[] = { GFX(803), // gfx803 GFX(805), // gfx805 GFX(810), // gfx810 + {CudaArch::GFX9_GENERIC, "gfx9-generic", "compute_amdgcn"}, GFX(900), // gfx900 GFX(902), // gfx902 GFX(904), // gfx903 @@ -122,10 +124,12 @@ static const CudaArchToStringMap arch_names[] = { GFX(940), // gfx940 GFX(941), // gfx941 GFX(942), // gfx942 + {CudaArch::GFX10_1_GENERIC, "gfx10-1-generic", "compute_amdgcn"}, GFX(1010), // gfx1010 GFX(1011), // gfx1011 GFX(1012), // gfx1012 GFX(1013), // gfx1013 + {CudaArch::GFX10_3_GENERIC, "gfx10-3-generic", "compute_amdgcn"}, GFX(1030), // gfx1030 GFX(1031), // gfx1031 GFX(1032), // gfx1032 @@ -133,12 +137,14 @@ static const CudaArchToStringMap arch_names[] = { GFX(1034), // gfx1034 GFX(1035), // gfx1035 GFX(1036), // gfx1036 + {CudaArch::GFX11_GENERIC, "gfx11-generic", "compute_amdgcn"}, GFX(1100), // gfx1100 GFX(1101), // gfx1101 GFX(1102), // gfx1102 GFX(1103), // gfx1103 GFX(1150), // gfx1150 GFX(1151), // gfx1151 + {CudaArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"}, GFX(1200), // gfx1200 GFX(1201), // gfx1201 {CudaArch::Generic, "generic", ""}, diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 143c04309d0753d114c36120c689e4e6b7e36489..1dc51deb829870f1291085db624aebc0e9d27480 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -82,6 +82,22 @@ getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, return FileMgr.getDirectoryRef(DirName, CacheFailure); } +DirectoryEntry *&FileManager::getRealDirEntry(const llvm::vfs::Status &Status) { + assert(Status.isDirectory() && "The directory should exist!"); + // See if we have already opened a directory with the + // same inode (this occurs on Unix-like systems when one dir is + // symlinked to another, for example) or the same path (on + // Windows). + DirectoryEntry *&UDE = UniqueRealDirs[Status.getUniqueID()]; + + if (!UDE) { + // We don't have this directory yet, add it. We use the string + // key from the SeenDirEntries map as the string. + UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); + } + return UDE; +} + /// Add all ancestors of the given path (pointing to either a file or /// a directory) as virtual directories. void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { @@ -99,10 +115,21 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { if (NamedDirEnt.second) return; - // Add the virtual directory to the cache. - auto *UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); - NamedDirEnt.second = *UDE; - VirtualDirectoryEntries.push_back(UDE); + // Check to see if the directory exists. + llvm::vfs::Status Status; + auto statError = + getStatValue(DirName, Status, false, nullptr /*directory lookup*/); + if (statError) { + // There's no real directory at the given path. + // Add the virtual directory to the cache. + auto *UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); + NamedDirEnt.second = *UDE; + VirtualDirectoryEntries.push_back(UDE); + } else { + // There is the real directory + DirectoryEntry *&UDE = getRealDirEntry(Status); + NamedDirEnt.second = *UDE; + } // Recursively add the other ancestors. addAncestorsAsVirtualDirs(DirName); @@ -162,17 +189,8 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { return llvm::errorCodeToError(statError); } - // It exists. See if we have already opened a directory with the - // same inode (this occurs on Unix-like systems when one dir is - // symlinked to another, for example) or the same path (on - // Windows). - DirectoryEntry *&UDE = UniqueRealDirs[Status.getUniqueID()]; - - if (!UDE) { - // We don't have this directory yet, add it. We use the string - // key from the SeenDirEntries map as the string. - UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); - } + // It exists. + DirectoryEntry *&UDE = getRealDirEntry(Status); NamedDirEnt.second = *UDE; return DirectoryEntryRef(NamedDirEnt); diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 045ef580f9c330ad29a13e62606546975b1cffdc..90b7b0d24bb6a0aa5ef3e512010c11a90bae562e 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -724,18 +724,3 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, }; VisitModule({M, nullptr}); } - -ASTSourceDescriptor::ASTSourceDescriptor(Module &M) - : Signature(M.Signature), ClangModule(&M) { - if (M.Directory) - Path = M.Directory->getName(); - if (auto File = M.getASTFile()) - ASTFile = File->getName(); -} - -std::string ASTSourceDescriptor::getModuleName() const { - if (ClangModule) - return ClangModule->Name; - else - return std::string(PCHModuleName); -} diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 5db1ce78c657fdcb2508efe13fcc434bce448b0b..0db16d4a8971abff969d2ce8770157c1b8c99241 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1203,6 +1203,7 @@ AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { case CC_SwiftAsync: case CC_PreserveMost: case CC_PreserveAll: + case CC_PreserveNone: case CC_OpenCLKernel: case CC_AArch64VectorCall: case CC_AArch64SVEPCS: diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index 3a65f53c524851b1188b9d7afb8597b2364fb9e0..174bc9d2ab99674a726abb49a985df5cf0af69d4 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -273,6 +273,34 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const { Diags.Report(diag::err_mips_fp64_req) << "-mfp64"; return false; } + // FPXX requires mips2+ + if (FPMode == FPXX && CPU == "mips1") { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfpxx" << CPU; + return false; + } + // -mmsa with -msoft-float makes nonsense + if (FloatABI == SoftFloat && HasMSA) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-msoft-float" + << "-mmsa"; + return false; + } + // Option -mmsa permitted on Mips32 iff revision 2 or higher is present + if (HasMSA && (CPU == "mips1" || CPU == "mips2" || getISARev() < 2) && + ABI == "o32") { + Diags.Report(diag::err_mips_fp64_req) << "-mmsa"; + return false; + } + // MSA requires FP64 + if (FPMode == FPXX && HasMSA) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfpxx" + << "-mmsa"; + return false; + } + if (FPMode == FP32 && HasMSA) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfp32" + << "-mmsa"; + return false; + } return true; } diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 8ad9e6e5f58916c4912af36becba62ca7e0bbc1b..fc6ef1119e9cf788847f3a2117c90f73e6e68d21 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -196,6 +196,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX803: case CudaArch::GFX805: case CudaArch::GFX810: + case CudaArch::GFX9_GENERIC: case CudaArch::GFX900: case CudaArch::GFX902: case CudaArch::GFX904: @@ -207,10 +208,12 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX940: case CudaArch::GFX941: case CudaArch::GFX942: + case CudaArch::GFX10_1_GENERIC: case CudaArch::GFX1010: case CudaArch::GFX1011: case CudaArch::GFX1012: case CudaArch::GFX1013: + case CudaArch::GFX10_3_GENERIC: case CudaArch::GFX1030: case CudaArch::GFX1031: case CudaArch::GFX1032: @@ -218,12 +221,14 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX1034: case CudaArch::GFX1035: case CudaArch::GFX1036: + case CudaArch::GFX11_GENERIC: case CudaArch::GFX1100: case CudaArch::GFX1101: case CudaArch::GFX1102: case CudaArch::GFX1103: case CudaArch::GFX1150: case CudaArch::GFX1151: + case CudaArch::GFX12_GENERIC: case CudaArch::GFX1200: case CudaArch::GFX1201: case CudaArch::Generic: diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 4db97867df607025942106f04b70382a2e2998d4..e4a449d1ff30417d989e4b0c7ce4d1e144610988 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -90,6 +90,9 @@ public: StringRef getABI() const override; bool setABI(const std::string &Name) override; + bool useFP16ConversionIntrinsics() const override { + return !HasHalfPrecision; + } protected: void getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index b823eaf6ce3365fa28decc9bacb8146232f44d0d..036a655a4d073f45de80e50ec3a90862e970d9be 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -310,15 +310,9 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasAVX512VNNI = true; } else if (Feature == "+avx512bf16") { HasAVX512BF16 = true; - } else if (Feature == "+avx512er") { - HasAVX512ER = true; - Diags.Report(diag::warn_knl_knm_isa_support_removed); } else if (Feature == "+avx512fp16") { HasAVX512FP16 = true; HasLegalHalfType = true; - } else if (Feature == "+avx512pf") { - HasAVX512PF = true; - Diags.Report(diag::warn_knl_knm_isa_support_removed); } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bitalg") { @@ -375,9 +369,6 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasWBNOINVD = true; } else if (Feature == "+prefetchi") { HasPREFETCHI = true; - } else if (Feature == "+prefetchwt1") { - HasPREFETCHWT1 = true; - Diags.Report(diag::warn_knl_knm_isa_support_removed); } else if (Feature == "+clzero") { HasCLZERO = true; } else if (Feature == "+cldemote") { @@ -450,6 +441,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasFullBFloat16 = true; } else if (Feature == "+egpr") { HasEGPR = true; + } else if (Feature == "+inline-asm-use-gpr32") { + HasInlineAsmUseGPR32 = true; } else if (Feature == "+push2pop2") { HasPush2Pop2 = true; } else if (Feature == "+ppx") { @@ -840,12 +833,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__AVX512VNNI__"); if (HasAVX512BF16) Builder.defineMacro("__AVX512BF16__"); - if (HasAVX512ER) - Builder.defineMacro("__AVX512ER__"); if (HasAVX512FP16) Builder.defineMacro("__AVX512FP16__"); - if (HasAVX512PF) - Builder.defineMacro("__AVX512PF__"); if (HasAVX512DQ) Builder.defineMacro("__AVX512DQ__"); if (HasAVX512BITALG) @@ -897,8 +886,6 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__SM4__"); if (HasPREFETCHI) Builder.defineMacro("__PREFETCHI__"); - if (HasPREFETCHWT1) - Builder.defineMacro("__PREFETCHWT1__"); if (HasCLZERO) Builder.defineMacro("__CLZERO__"); if (HasKL) @@ -976,8 +963,10 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasCF) Builder.defineMacro("__CF__"); // Condition here is aligned with the feature set of mapxf in Options.td - if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD) + if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD && HasCCMP && HasNF) Builder.defineMacro("__APX_F__"); + if (HasEGPR && HasInlineAsmUseGPR32) + Builder.defineMacro("__APX_INLINE_ASM_USE_GPR32__"); // Each case falls through to the previous one here. switch (SSELevel) { @@ -1084,9 +1073,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("avx512vpopcntdq", true) .Case("avx512vnni", true) .Case("avx512bf16", true) - .Case("avx512er", true) .Case("avx512fp16", true) - .Case("avx512pf", true) .Case("avx512dq", true) .Case("avx512bitalg", true) .Case("avx512bw", true) @@ -1134,7 +1121,6 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("pku", true) .Case("popcnt", true) .Case("prefetchi", true) - .Case("prefetchwt1", true) .Case("prfchw", true) .Case("ptwrite", true) .Case("raoint", true) @@ -1201,9 +1187,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) .Case("avx512vnni", HasAVX512VNNI) .Case("avx512bf16", HasAVX512BF16) - .Case("avx512er", HasAVX512ER) .Case("avx512fp16", HasAVX512FP16) - .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) .Case("avx512bitalg", HasAVX512BITALG) .Case("avx512bw", HasAVX512BW) @@ -1253,7 +1237,6 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("pku", HasPKU) .Case("popcnt", HasPOPCNT) .Case("prefetchi", HasPREFETCHI) - .Case("prefetchwt1", HasPREFETCHWT1) .Case("prfchw", HasPRFCHW) .Case("ptwrite", HasPTWRITE) .Case("raoint", HasRAOINT) @@ -1499,6 +1482,18 @@ bool X86TargetInfo::validateAsmConstraint( case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; + case 'j': + Name++; + switch (*Name) { + default: + return false; + case 'r': + Info.setAllowsRegister(); + return true; + case 'R': + Info.setAllowsRegister(); + return true; + } case '@': // CC condition changes. if (auto Len = matchAsmCCConstraint(Name)) { @@ -1771,6 +1766,21 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { return std::string("^") + std::string(Constraint++, 2); } [[fallthrough]]; + case 'j': + switch (Constraint[1]) { + default: + // Break from inner switch and fall through (copy single char), + // continue parsing after copying the current constraint into + // the return string. + break; + case 'r': + case 'R': + // "^" hints llvm that this is a 2 letter constraint. + // "Constraint++" is used to promote the string iterator + // to the next constraint. + return std::string("^") + std::string(Constraint++, 2); + } + [[fallthrough]]; default: return std::string(1, *Constraint); } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 6a0a6cb84203da183320d1cabc6d9270649d7b59..9b2ae87adb2e742551a07a8f76e667b2fb1d2cbf 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -103,8 +103,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasAVX512VNNI = false; bool HasAVX512FP16 = false; bool HasAVX512BF16 = false; - bool HasAVX512ER = false; - bool HasAVX512PF = false; bool HasAVX512DQ = false; bool HasAVX512BITALG = false; bool HasAVX512BW = false; @@ -136,7 +134,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasCLWB = false; bool HasMOVBE = false; bool HasPREFETCHI = false; - bool HasPREFETCHWT1 = false; bool HasRDPID = false; bool HasRDPRU = false; bool HasRetpolineExternalThunk = false; @@ -175,6 +172,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasCCMP = false; bool HasNF = false; bool HasCF = false; + bool HasInlineAsmUseGPR32 = false; protected: llvm::X86::CPUKind CPU = llvm::X86::CK_None; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 90985c08fe7f8178cb27508d433c72f6fe2ec49d..b09680086248d02cd61f1e0d83eee84a3230c845 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -85,7 +85,6 @@ #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Utils/Debugify.h" -#include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include #include @@ -983,22 +982,6 @@ void EmitAssemblyHelper::RunOptimizationPipeline( /*DropTypeTests=*/true)); }); - if (CodeGenOpts.InstrumentFunctions || - CodeGenOpts.InstrumentFunctionEntryBare || - CodeGenOpts.InstrumentFunctionsAfterInlining || - CodeGenOpts.InstrumentForProfiling) { - PB.registerPipelineStartEPCallback( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(createModuleToFunctionPassAdaptor( - EntryExitInstrumenterPass(/*PostInlining=*/false))); - }); - PB.registerOptimizerLastEPCallback( - [](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(createModuleToFunctionPassAdaptor( - EntryExitInstrumenterPass(/*PostInlining=*/true))); - }); - } - // Register callbacks to schedule sanitizer passes at the appropriate part // of the pipeline. if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ba94bf89e475118a3469d999452b9dd4e431d437..37d0c478e03308cf1713f5ffef3a9f3b1e08582e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -57,6 +57,7 @@ #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/MatrixBuilder.h" +#include "llvm/IR/MemoryModelRelaxationAnnotations.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/ScopedPrinter.h" @@ -5977,11 +5978,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto Name = CGM.getCUDARuntime().getDeviceSideName( cast(E->getArg(0)->IgnoreImpCasts())->getDecl()); auto Str = CGM.GetAddrOfConstantCString(Name, ""); - llvm::Constant *Zeros[] = {llvm::ConstantInt::get(SizeTy, 0), - llvm::ConstantInt::get(SizeTy, 0)}; - auto *Ptr = llvm::ConstantExpr::getGetElementPtr(Str.getElementType(), - Str.getPointer(), Zeros); - return RValue::get(Ptr); + return RValue::get(Str.getPointer()); } } @@ -14073,7 +14070,7 @@ Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) { // Grab the appropriate field from __cpu_model. llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, Index)}; - llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs); + llvm::Value *CpuValue = Builder.CreateInBoundsGEP(STy, CpuModel, Idxs); CpuValue = Builder.CreateAlignedLoad(Int32Ty, CpuValue, CharUnits::fromQuantity(4)); @@ -14115,7 +14112,7 @@ CodeGenFunction::EmitX86CpuSupports(std::array FeatureMask) { // global in the struct STy. Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(3), Builder.getInt32(0)}; - Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); + Value *CpuFeatures = Builder.CreateInBoundsGEP(STy, CpuModel, Idxs); Value *Features = Builder.CreateAlignedLoad(Int32Ty, CpuFeatures, CharUnits::fromQuantity(4)); @@ -14136,7 +14133,7 @@ CodeGenFunction::EmitX86CpuSupports(std::array FeatureMask) { continue; Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(i - 1)}; Value *Features = Builder.CreateAlignedLoad( - Int32Ty, Builder.CreateGEP(ATy, CpuFeatures2, Idxs), + Int32Ty, Builder.CreateInBoundsGEP(ATy, CpuFeatures2, Idxs), CharUnits::fromQuantity(4)); // Check the value of the bit corresponding to the feature requested. Value *Mask = Builder.getInt32(M); @@ -16723,7 +16720,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, FieldIdx)}; - FieldValue = Builder.CreateGEP(STy, SysConf, Idxs); + FieldValue = Builder.CreateInBoundsGEP(STy, SysConf, Idxs); FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue, CharUnits::fromQuantity(4)); } else if (SupportMethod == SYS_CALL) { @@ -18327,6 +18324,29 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return nullptr; } +void CodeGenFunction::AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst, + const CallExpr *E) { + constexpr const char *Tag = "amdgpu-as"; + + LLVMContext &Ctx = Inst->getContext(); + SmallVector MMRAs; + for (unsigned K = 2; K < E->getNumArgs(); ++K) { + llvm::Value *V = EmitScalarExpr(E->getArg(K)); + StringRef AS; + if (llvm::getConstantStringInfo(V, AS)) { + MMRAs.push_back({Tag, AS}); + // TODO: Delete the resulting unused constant? + continue; + } + CGM.Error(E->getExprLoc(), + "expected an address space name as a string literal"); + } + + llvm::sort(MMRAs); + MMRAs.erase(llvm::unique(MMRAs), MMRAs.end()); + Inst->setMetadata(LLVMContext::MD_mmra, MMRAMetadata::getMD(Ctx, MMRAs)); +} + Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { llvm::AtomicOrdering AO = llvm::AtomicOrdering::SequentiallyConsistent; @@ -18997,7 +19017,10 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_fence: { ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), AO, SSID); - return Builder.CreateFence(AO, SSID); + FenceInst *Fence = Builder.CreateFence(AO, SSID); + if (E->getNumArgs() > 2) + AddAMDGPUFenceAddressSpaceMMRA(Fence, E); + return Fence; } case AMDGPU::BI__builtin_amdgcn_atomic_inc32: case AMDGPU::BI__builtin_amdgcn_atomic_inc64: @@ -20779,6 +20802,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_min_f32: case WebAssembly::BI__builtin_wasm_min_f64: + case WebAssembly::BI__builtin_wasm_min_f16x8: case WebAssembly::BI__builtin_wasm_min_f32x4: case WebAssembly::BI__builtin_wasm_min_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20789,6 +20813,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_max_f32: case WebAssembly::BI__builtin_wasm_max_f64: + case WebAssembly::BI__builtin_wasm_max_f16x8: case WebAssembly::BI__builtin_wasm_max_f32x4: case WebAssembly::BI__builtin_wasm_max_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20797,6 +20822,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_pmin_f16x8: case WebAssembly::BI__builtin_wasm_pmin_f32x4: case WebAssembly::BI__builtin_wasm_pmin_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20805,6 +20831,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_pmax_f16x8: case WebAssembly::BI__builtin_wasm_pmax_f32x4: case WebAssembly::BI__builtin_wasm_pmax_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -21230,6 +21257,17 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32); return Builder.CreateCall(Callee, {Val, Addr}); } + case WebAssembly::BI__builtin_wasm_splat_f16x8: { + Value *Val = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8); + return Builder.CreateCall(Callee, {Val}); + } + case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: { + Value *Vector = EmitScalarExpr(E->getArg(0)); + Value *Index = EmitScalarExpr(E->getArg(1)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8); + return Builder.CreateCall(Callee, {Vector, Index}); + } case WebAssembly::BI__builtin_wasm_table_get: { assert(E->getArg(0)->getType()->isArrayType()); Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 670bc4bf72cecb906ca912164cdfc79307ef9e8f..43dfbbb90dd522bf62fc9b3339f4712709ffc8c1 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -71,8 +71,6 @@ private: bool RelocatableDeviceCode; /// Mangle context for device. std::unique_ptr DeviceMC; - /// Some zeros used for GEPs. - llvm::Constant *Zeros[2]; llvm::FunctionCallee getSetupArgumentFn() const; llvm::FunctionCallee getLaunchFn() const; @@ -91,9 +89,7 @@ private: /// where the C code specifies const char*. llvm::Constant *makeConstantString(const std::string &Str, const std::string &Name = "") { - auto ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); - return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(), - ConstStr.getPointer(), Zeros); + return CGM.GetAddrOfConstantCString(Str, Name.c_str()).getPointer(); } /// Helper function which generates an initialized constant array from Str, @@ -117,7 +113,7 @@ private: } if (Alignment) GV->setAlignment(llvm::Align(Alignment)); - return llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros); + return GV; } /// Helper function that generates an empty dummy function returning void. @@ -230,8 +226,6 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) IntTy = CGM.IntTy; SizeTy = CGM.SizeTy; VoidTy = CGM.VoidTy; - Zeros[0] = llvm::ConstantInt::get(SizeTy, 0); - Zeros[1] = Zeros[0]; PtrTy = CGM.UnqualPtrTy; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index fac278f0e20a438102c913384af3e48185e11c96..5f6f911c7a6d698d44324e94a85c0259f6ed7084 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2836,7 +2836,7 @@ CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { // Collect data fields (including static variables and any initializers). CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); - if (CXXDecl) + if (CXXDecl && !CGM.getCodeGenOpts().DebugOmitUnreferencedMethods) CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); LexicalBlockStack.pop_back(); @@ -5737,6 +5737,90 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, Var->addDebugInfo(GVE); } +void CGDebugInfo::EmitPseudoVariable(CGBuilderTy &Builder, + llvm::Instruction *Value, QualType Ty) { + // Only when -g2 or above is specified, debug info for variables will be + // generated. + if (CGM.getCodeGenOpts().getDebugInfo() <= + llvm::codegenoptions::DebugLineTablesOnly) + return; + + llvm::DebugLoc SaveDebugLoc = Builder.getCurrentDebugLocation(); + if (!SaveDebugLoc.get()) + return; + + llvm::DIFile *Unit = SaveDebugLoc->getFile(); + llvm::DIType *Type = getOrCreateType(Ty, Unit); + + // Check if Value is already a declared variable and has debug info, in this + // case we have nothing to do. Clang emits declared variable as alloca, and + // it is loaded upon use, so we identify such pattern here. + if (llvm::LoadInst *Load = dyn_cast(Value)) { + llvm::Value *Var = Load->getPointerOperand(); + if (llvm::Metadata *MDValue = llvm::ValueAsMetadata::getIfExists(Var)) { + if (llvm::Value *DbgValue = llvm::MetadataAsValue::getIfExists( + CGM.getLLVMContext(), MDValue)) { + for (llvm::User *U : DbgValue->users()) { + if (llvm::CallInst *DbgDeclare = dyn_cast(U)) { + if (DbgDeclare->getCalledFunction()->getIntrinsicID() == + llvm::Intrinsic::dbg_declare && + DbgDeclare->getArgOperand(0) == DbgValue) { + // There can be implicit type cast applied on a variable if it is + // an opaque ptr, in this case its debug info may not match the + // actual type of object being used as in the next instruction, so + // we will need to emit a pseudo variable for type-casted value. + llvm::DILocalVariable *MDNode = cast( + cast(DbgDeclare->getOperand(1)) + ->getMetadata()); + if (MDNode->getType() == Type) + return; + } + } + } + } + } + } + + // Find the correct location to insert a sequence of instructions to + // materialize Value on the stack. + auto SaveInsertionPoint = Builder.saveIP(); + if (llvm::InvokeInst *Invoke = dyn_cast(Value)) + Builder.SetInsertPoint(Invoke->getNormalDest()->begin()); + else if (llvm::Instruction *Next = Value->getIterator()->getNextNode()) + Builder.SetInsertPoint(Next); + else + Builder.SetInsertPoint(Value->getParent()); + llvm::DebugLoc DL = Value->getDebugLoc(); + if (DL.get()) + Builder.SetCurrentDebugLocation(DL); + else if (!Builder.getCurrentDebugLocation().get()) + Builder.SetCurrentDebugLocation(SaveDebugLoc); + + llvm::AllocaInst *PseudoVar = Builder.CreateAlloca(Value->getType()); + Address PseudoVarAddr(PseudoVar, Value->getType(), + CharUnits::fromQuantity(PseudoVar->getAlign())); + llvm::LoadInst *Load = Builder.CreateLoad(PseudoVarAddr); + Value->replaceAllUsesWith(Load); + Builder.SetInsertPoint(Load); + Builder.CreateStore(Value, PseudoVarAddr); + + // Emit debug info for materialized Value. + unsigned Line = Builder.getCurrentDebugLocation().getLine(); + unsigned Column = Builder.getCurrentDebugLocation().getCol(); + llvm::DILocalVariable *D = DBuilder.createAutoVariable( + LexicalBlockStack.back(), "", nullptr, 0, Type, false, + llvm::DINode::FlagArtificial); + llvm::DILocation *DIL = + llvm::DILocation::get(CGM.getLLVMContext(), Line, Column, + LexicalBlockStack.back(), CurInlinedAt); + SmallVector Expr; + DBuilder.insertDeclare(PseudoVar, D, DBuilder.createExpression(Expr), DIL, + Load); + + Builder.restoreIP(SaveInsertionPoint); + Builder.SetCurrentDebugLocation(SaveDebugLoc); +} + void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl GD) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index d6db4d711366accf43100ef70628bbb9f2d345e5..da466837aa3c34f7df8d1676799e96bd9fb8b825 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -20,8 +20,8 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/ASTSourceDescriptor.h" #include "clang/Basic/CodeGenOptions.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -38,6 +38,7 @@ class MDNode; namespace clang { class ClassTemplateSpecializationDecl; class GlobalDecl; +class Module; class ModuleMap; class ObjCInterfaceDecl; class UsingDecl; @@ -529,6 +530,12 @@ public: /// Emit information about an external variable. void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); + /// Emit a pseudo variable and debug info for an intermediate value if it does + /// not correspond to a variable in the source code, so that a profiler can + /// track more accurate usage of certain instructions of interest. + void EmitPseudoVariable(CGBuilderTy &Builder, llvm::Instruction *Value, + QualType Ty); + /// Emit information about global variable alias. void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index cd1c48b42038212d4265bb4347640fd12f2c5508..d6478cc6835d82dac585180a366b13852af8d2b8 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -317,8 +317,8 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, CleanupKind CleanupKind; if (Lifetime == Qualifiers::OCL_Strong) { const ValueDecl *VD = M->getExtendingDecl(); - bool Precise = - VD && isa(VD) && VD->hasAttr(); + bool Precise = isa_and_nonnull(VD) && + VD->hasAttr(); CleanupKind = CGF.getARCCleanupKind(); Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise : &CodeGenFunction::destroyARCStrongImprecise; @@ -4180,7 +4180,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // If the base is a vector type, then we are forming a vector element lvalue // with this subscript. - if (E->getBase()->getType()->isVectorType() && + if (E->getBase()->getType()->isSubscriptableVectorType() && !isa(E->getBase())) { // Emit the vector as an lvalue to get its address. LValue LHS = EmitLValue(E->getBase()); @@ -4676,7 +4676,8 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field, llvm::Value *ThisValue) { bool HasExplicitObjectParameter = false; - if (const auto *MD = dyn_cast_if_present(CurCodeDecl)) { + const auto *MD = dyn_cast_if_present(CurCodeDecl); + if (MD) { HasExplicitObjectParameter = MD->isExplicitObjectMemberFunction(); assert(MD->getParent()->isLambda()); assert(MD->getParent() == Field->getParent()); @@ -4693,6 +4694,17 @@ LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field, else LambdaLV = MakeAddrLValue(AddrOfExplicitObject, D->getType().getNonReferenceType()); + + // Make sure we have an lvalue to the lambda itself and not a derived class. + auto *ThisTy = D->getType().getNonReferenceType()->getAsCXXRecordDecl(); + auto *LambdaTy = cast(Field->getParent()); + if (ThisTy != LambdaTy) { + const CXXCastPath &BasePathArray = getContext().LambdaCastPaths.at(MD); + Address Base = GetAddressOfBaseClass( + LambdaLV.getAddress(), ThisTy, BasePathArray.begin(), + BasePathArray.end(), /*NullCheckValue=*/false, SourceLocation()); + LambdaLV = MakeAddrLValue(Base, QualType{LambdaTy->getTypeForDecl(), 0}); + } } else { QualType LambdaTagType = getContext().getTagDeclType(Field->getParent()); LambdaLV = MakeNaturalAlignAddrLValue(ThisValue, LambdaTagType); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index bba00257fd4f0aab44c479467597f3706e0c257f..5b2039af6128bf0de90e324608566b63d3ea8b65 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -448,11 +448,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { AggValueSlot Dest = EnsureSlot(E->getType()); LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType()); LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field); - llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); - llvm::Value *IdxStart[] = { Zero, Zero }; - llvm::Value *ArrayStart = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxStart, - "arraystart"); + llvm::Value *ArrayStart = ArrayPtr.emitRawPointer(CGF); CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); ++Field; @@ -467,6 +463,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { Ctx.hasSameType(Field->getType()->getPointeeType(), ArrayType->getElementType())) { // End pointer. + llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); llvm::Value *IdxEnd[] = { Zero, Size }; llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP( ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd, @@ -1789,7 +1786,6 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // Push a destructor if necessary. // FIXME: if we have an array of structures, all explicitly // initialized, we can end up pushing a linear number of cleanups. - bool pushedCleanup = false; if (QualType::DestructionKind dtorKind = field->getType().isDestructedType()) { assert(LV.isSimple()); @@ -1797,17 +1793,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, LV.getAddress(), field->getType(), CGF.getDestroyer(dtorKind), false); - pushedCleanup = true; } } - - // If the GEP didn't get used because of a dead zero init or something - // else, clean it up for -O0 builds and general tidiness. - if (!pushedCleanup && LV.isSimple()) - if (llvm::GetElementPtrInst *GEP = - dyn_cast(LV.emitRawPointer(CGF))) - if (GEP->use_empty()) - GEP->eraseFromParent(); } } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 1b144c178ce960656144793741b737e02f58b2b0..58f0a3113b4f8133741f659dce3fdc61b44fa54d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1937,7 +1937,26 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { } } - return EmitLoadOfLValue(E); + llvm::Value *Result = EmitLoadOfLValue(E); + + // If -fdebug-info-for-profiling is specified, emit a pseudo variable and its + // debug info for the pointer, even if there is no variable associated with + // the pointer's expression. + if (CGF.CGM.getCodeGenOpts().DebugInfoForProfiling && CGF.getDebugInfo()) { + if (llvm::LoadInst *Load = dyn_cast(Result)) { + if (llvm::GetElementPtrInst *GEP = + dyn_cast(Load->getPointerOperand())) { + if (llvm::Instruction *Pointer = + dyn_cast(GEP->getPointerOperand())) { + QualType Ty = E->getBase()->getType(); + if (!E->isArrow()) + Ty = CGF.getContext().getPointerType(Ty); + CGF.getDebugInfo()->EmitPseudoVariable(Builder, Pointer, Ty); + } + } + } + } + return Result; } Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 43dd38659518d11616bd3abfe2d466aff0fc178a..6540ac69f2d9b08abd16fbc9327ca935f3a3ffcf 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -199,8 +199,7 @@ protected: llvm::Constant *MakeConstantString(StringRef Str, const char *Name = "") { ConstantAddress Array = CGM.GetAddrOfConstantCString(std::string(Str), Name); - return llvm::ConstantExpr::getGetElementPtr(Array.getElementType(), - Array.getPointer(), Zeros); + return Array.getPointer(); } /// Emits a linkonce_odr string, whose name is the prefix followed by the @@ -221,8 +220,7 @@ protected: GV->setVisibility(llvm::GlobalValue::HiddenVisibility); ConstStr = GV; } - return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(), - ConstStr, Zeros); + return ConstStr; } /// Returns a property name and encoding string. @@ -1477,8 +1475,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { GV->setVisibility(llvm::GlobalValue::HiddenVisibility); TypesGlobal = GV; } - return llvm::ConstantExpr::getGetElementPtr(TypesGlobal->getValueType(), - TypesGlobal, Zeros); + return TypesGlobal; } llvm::Constant *GetConstantSelector(Selector Sel, const std::string &TypeEncoding) override { diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 28da8662f5f6178b37476b646ea46b3c82777638..191bd757831fc75f161e0d0c8071b6033065c7c0 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -3505,6 +3505,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective( case CudaArch::GFX803: case CudaArch::GFX805: case CudaArch::GFX810: + case CudaArch::GFX9_GENERIC: case CudaArch::GFX900: case CudaArch::GFX902: case CudaArch::GFX904: @@ -3516,10 +3517,12 @@ void CGOpenMPRuntimeGPU::processRequiresDirective( case CudaArch::GFX940: case CudaArch::GFX941: case CudaArch::GFX942: + case CudaArch::GFX10_1_GENERIC: case CudaArch::GFX1010: case CudaArch::GFX1011: case CudaArch::GFX1012: case CudaArch::GFX1013: + case CudaArch::GFX10_3_GENERIC: case CudaArch::GFX1030: case CudaArch::GFX1031: case CudaArch::GFX1032: @@ -3527,12 +3530,14 @@ void CGOpenMPRuntimeGPU::processRequiresDirective( case CudaArch::GFX1034: case CudaArch::GFX1035: case CudaArch::GFX1036: + case CudaArch::GFX11_GENERIC: case CudaArch::GFX1100: case CudaArch::GFX1101: case CudaArch::GFX1102: case CudaArch::GFX1103: case CudaArch::GFX1150: case CudaArch::GFX1151: + case CudaArch::GFX12_GENERIC: case CudaArch::GFX1200: case CudaArch::GFX1201: case CudaArch::Generic: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 99daaa14cf3fec7a721df5e2c97f9c97ca9f2cbd..41ac511c52f51b887c916dd8cdfb8d1e7611e775 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -442,6 +442,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::OpenACCComputeConstructClass: EmitOpenACCComputeConstruct(cast(*S)); break; + case Stmt::OpenACCLoopConstructClass: + EmitOpenACCLoopConstruct(cast(*S)); + break; } } diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index eac5ef32629378a5fc72d7af3880cb3d85167a25..6410f9e102c907ab81f2561feb1ac01a7bf08d44 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -142,7 +142,7 @@ public: /// of used expression from loop statement. class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopBasedDirective &S) { - const DeclStmt *PreInits; + const Stmt *PreInits; CodeGenFunction::OMPMapVars PreCondVars; if (auto *LD = dyn_cast(&S)) { llvm::DenseSet EmittedAsPrivate; @@ -182,17 +182,34 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { } return false; }); - PreInits = cast_or_null(LD->getPreInits()); + PreInits = LD->getPreInits(); } else if (const auto *Tile = dyn_cast(&S)) { - PreInits = cast_or_null(Tile->getPreInits()); + PreInits = Tile->getPreInits(); } else if (const auto *Unroll = dyn_cast(&S)) { - PreInits = cast_or_null(Unroll->getPreInits()); + PreInits = Unroll->getPreInits(); } else { llvm_unreachable("Unknown loop-based directive kind."); } if (PreInits) { - for (const auto *I : PreInits->decls()) - CGF.EmitVarDecl(cast(*I)); + // CompoundStmts and DeclStmts are used as lists of PreInit statements and + // declarations. Since declarations must be visible in the the following + // that they initialize, unpack the ComboundStmt they are nested in. + SmallVector PreInitStmts; + if (auto *PreInitCompound = dyn_cast(PreInits)) + llvm::append_range(PreInitStmts, PreInitCompound->body()); + else + PreInitStmts.push_back(PreInits); + + for (const Stmt *S : PreInitStmts) { + // EmitStmt skips any OMPCapturedExprDecls, but needs to be emitted + // here. + if (auto *PreInitDecl = dyn_cast(S)) { + for (Decl *I : PreInitDecl->decls()) + CGF.EmitVarDecl(cast(*I)); + continue; + } + CGF.EmitStmt(S); + } } PreCondVars.restore(CGF); } diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 8d9c22546b42080dd8a36fd3c3dbf9c305b12494..001633453f2426348af0905901284ec129375266 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -1200,7 +1200,7 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) { assert(Def && "The body of the key function is not assigned to Def?"); // If the non-inline key function comes from another module unit, the vtable // must be defined there. - return Def->isInAnotherModuleUnit() && !Def->isInlineSpecified(); + return Def->shouldEmitInExternalSource() && !Def->isInlineSpecified(); } /// Given that we're currently at the end of the translation unit, and diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 5f3ee7eb943f9e17aa7a5a20579f6324228d1eda..5739fbaaa919400e5c4e9e2d958eba1e81cb3e04 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4062,6 +4062,13 @@ public: EmitStmt(S.getStructuredBlock()); } + void EmitOpenACCLoopConstruct(const OpenACCLoopConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // simply emitting its loop, but in the future we will implement + // some sort of IR. + EmitStmt(S.getLoop()); + } + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// @@ -4635,6 +4642,9 @@ public: llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + + void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst, + const CallExpr *E); void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope, llvm::AtomicOrdering &AO, llvm::SyncScope::ID &SSID); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 227813ad44e8b8feaed2c4bb7dfbeadad61c8261..be7bf0b72dc0c1563e8d15acafa11f8281b9b0d3 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1853,18 +1853,24 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, break; case MultiVersionKind::Target: { auto *Attr = FD->getAttr(); + assert(Attr && "Expected TargetAttr to be present " + "for attribute mangling"); const ABIInfo &Info = CGM.getTargetCodeGenInfo().getABIInfo(); Info.appendAttributeMangling(Attr, Out); break; } case MultiVersionKind::TargetVersion: { auto *Attr = FD->getAttr(); + assert(Attr && "Expected TargetVersionAttr to be present " + "for attribute mangling"); const ABIInfo &Info = CGM.getTargetCodeGenInfo().getABIInfo(); Info.appendAttributeMangling(Attr, Out); break; } case MultiVersionKind::TargetClones: { auto *Attr = FD->getAttr(); + assert(Attr && "Expected TargetClonesAttr to be present " + "for attribute mangling"); unsigned Index = GD.getMultiVersionIndex(); const ABIInfo &Info = CGM.getTargetCodeGenInfo().getABIInfo(); Info.appendAttributeMangling(Attr, Index, Out); @@ -4150,7 +4156,7 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, } static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) { - DeclContext *DeclCtx = FD->getASTContext().getTranslationUnitDecl(); + auto *DeclCtx = const_cast(FD->getDeclContext()); TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); StorageClass SC = FD->getStorageClass(); DeclarationName Name = FD->getNameInfo().getName(); @@ -5341,6 +5347,18 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, !IsDefinitionAvailableExternally && D->needsDestruction(getContext()) == QualType::DK_cxx_destructor; + // It is helpless to emit the definition for an available_externally variable + // which can't be marked as const. + // We don't need to check if it needs global ctor or dtor. See the above + // comment for ideas. + if (IsDefinitionAvailableExternally && + (!D->hasConstantInitialization() || + // TODO: Update this when we have interface to check constexpr + // destructor. + D->needsDestruction(getContext()) || + !D->getType().isConstantStorage(getContext(), true, true))) + return; + const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); @@ -5740,15 +5758,17 @@ CodeGenModule::getLLVMLinkageVarDefinition(const VarDecl *VD) { static void replaceUsesOfNonProtoConstant(llvm::Constant *old, llvm::Function *newFn) { // Fast path. - if (old->use_empty()) return; + if (old->use_empty()) + return; llvm::Type *newRetTy = newFn->getReturnType(); - SmallVector newArgs; + SmallVector newArgs; + + SmallVector callSitesToBeRemovedFromParent; for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end(); - ui != ue; ) { - llvm::Value::use_iterator use = ui++; // Increment before the use is erased. - llvm::User *user = use->getUser(); + ui != ue; ui++) { + llvm::User *user = ui->getUser(); // Recognize and replace uses of bitcasts. Most calls to // unprototyped functions will use bitcasts. @@ -5760,8 +5780,9 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, // Recognize calls to the function. llvm::CallBase *callSite = dyn_cast(user); - if (!callSite) continue; - if (!callSite->isCallee(&*use)) + if (!callSite) + continue; + if (!callSite->isCallee(&*ui)) continue; // If the return types don't match exactly, then we can't @@ -5830,6 +5851,10 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, if (callSite->getDebugLoc()) newCall->setDebugLoc(callSite->getDebugLoc()); + callSitesToBeRemovedFromParent.push_back(callSite); + } + + for (auto *callSite : callSitesToBeRemovedFromParent) { callSite->eraseFromParent(); } } @@ -6112,9 +6137,6 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { return ConstantAddress( C, C->getValueType(), CharUnits::fromQuantity(C->getAlignment())); - llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); - llvm::Constant *Zeros[] = { Zero, Zero }; - const ASTContext &Context = getContext(); const llvm::Triple &Triple = getTriple(); @@ -6185,8 +6207,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { // Decay array -> ptr CFConstantStringClassRef = - IsSwiftABI ? llvm::ConstantExpr::getPtrToInt(C, Ty) - : llvm::ConstantExpr::getGetElementPtr(Ty, C, Zeros); + IsSwiftABI ? llvm::ConstantExpr::getPtrToInt(C, Ty) : C; } QualType CFTy = Context.getCFConstantStringType(); @@ -6242,10 +6263,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { GV->setSection(".rodata"); // String. - llvm::Constant *Str = - llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros); - - Fields.add(Str); + Fields.add(GV); // String length. llvm::IntegerType *LengthTy = diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 0f68418130ead7019908db68b2d49f5ff58087ec..dc24971a3c1862b69311ad7441fc4799b06db295 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -24,7 +24,6 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" -#include "clang/Basic/Module.h" #include "clang/Basic/NoSanitizeList.h" #include "clang/Basic/ProfileList.h" #include "clang/Basic/TargetInfo.h" diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 76704c4d7be4a49de647c9f64aac615724215bb7..db8e6f55302adcb4b3f065e01a3dfcb409b98824 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -1340,7 +1340,7 @@ void CodeGenPGO::setProfileVersion(llvm::Module &M) { llvm::APInt(64, ProfileVersion)), VarName); - IRLevelVersionVariable->setVisibility(llvm::GlobalValue::DefaultVisibility); + IRLevelVersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility); llvm::Triple TT(M.getTargetTriple()); if (TT.supportsCOMDAT()) { IRLevelVersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f4de21bac4b466e943c9fefb042fff3858e801a6..6ce2d32dd292ed90c11d55569fed26869ec9cbe6 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -191,6 +191,10 @@ public: bool isBranch() const { return FalseCount.has_value(); } + bool isMCDCBranch() const { + return std::holds_alternative(MCDCParams); + } + bool isMCDCDecision() const { return std::holds_alternative(MCDCParams); } @@ -290,10 +294,36 @@ public: return SM.getLocForEndOfFile(SM.getFileID(Loc)); } - /// Find out where the current file is included or macro is expanded. - SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) { - return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin() - : SM.getIncludeLoc(SM.getFileID(Loc)); + /// Find out where a macro is expanded. If the immediate result is a + /// , keep looking until the result isn't. Return a pair of + /// \c SourceLocation. The first object is always the begin sloc of found + /// result. The second should be checked by the caller: if it has value, it's + /// the end sloc of the found result. Otherwise the while loop didn't get + /// executed, which means the location wasn't changed and the caller has to + /// learn the end sloc from somewhere else. + std::pair> + getNonScratchExpansionLoc(SourceLocation Loc) { + std::optional EndLoc = std::nullopt; + while (Loc.isMacroID() && + SM.isWrittenInScratchSpace(SM.getSpellingLoc(Loc))) { + auto ExpansionRange = SM.getImmediateExpansionRange(Loc); + Loc = ExpansionRange.getBegin(); + EndLoc = ExpansionRange.getEnd(); + } + return std::make_pair(Loc, EndLoc); + } + + /// Find out where the current file is included or macro is expanded. If + /// \c AcceptScratch is set to false, keep looking for expansions until the + /// found sloc is not a . + SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc, + bool AcceptScratch = true) { + if (!Loc.isMacroID()) + return SM.getIncludeLoc(SM.getFileID(Loc)); + Loc = SM.getImmediateExpansionRange(Loc).getBegin(); + if (AcceptScratch) + return Loc; + return getNonScratchExpansionLoc(Loc).first; } /// Return true if \c Loc is a location in a built-in macro. @@ -340,6 +370,15 @@ public: for (auto &Region : SourceRegions) { SourceLocation Loc = Region.getBeginLoc(); + // Replace Region with its definition if it is in . + auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc); + auto EndLoc = NonScratchExpansionLoc.second; + if (EndLoc.has_value()) { + Loc = NonScratchExpansionLoc.first; + Region.setStartLoc(Loc); + Region.setEndLoc(EndLoc.value()); + } + // Replace Loc with FileLoc if it is expanded with system headers. if (!SystemHeadersCoverage && SM.isInSystemMacro(Loc)) { auto BeginLoc = SM.getSpellingLoc(Loc); @@ -472,13 +511,19 @@ public: // Ignore regions from system headers unless collecting coverage from // system headers is explicitly enabled. if (!SystemHeadersCoverage && - SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) + SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) { + assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && + "Don't suppress the condition in system headers"); continue; + } auto CovFileID = getCoverageFileID(LocStart); // Ignore regions that don't have a file, such as builtin macros. - if (!CovFileID) + if (!CovFileID) { + assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && + "Don't suppress the condition in non-file regions"); continue; + } SourceLocation LocEnd = Region.getEndLoc(); assert(SM.isWrittenInSameFile(LocStart, LocEnd) && @@ -488,8 +533,11 @@ public: // This not only suppresses redundant regions, but sometimes prevents // creating regions with wrong counters if, for example, a statement's // body ends at the end of a nested macro. - if (Filter.count(std::make_pair(LocStart, LocEnd))) + if (Filter.count(std::make_pair(LocStart, LocEnd))) { + assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && + "Don't suppress the condition"); continue; + } // Find the spelling locations for the mapping region. SpellingRegion SR{SM, LocStart, LocEnd}; @@ -525,7 +573,7 @@ public: SourceRegionFilter Filter; for (const auto &FM : FileIDMapping) { SourceLocation ExpandedLoc = FM.second.second; - SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc); + SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc, false); if (ParentLoc.isInvalid()) continue; @@ -2223,7 +2271,8 @@ struct CounterCoverageMappingBuilder } void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) { - Visit(OVE->getSourceExpr()); + if (OVE->isUnique()) + Visit(OVE->getSourceExpr()); } }; diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 18acf7784f714b4c8d083c086185efd1e45bdec2..8427286dee8875925107b399aac930ef8e89af7c 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1793,6 +1793,37 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF, ThisTy, VTT, VTTTy, nullptr); } +// Check if any non-inline method has the specified attribute. +template +static bool CXXRecordNonInlineHasAttr(const CXXRecordDecl *RD) { + for (const auto *D : RD->noload_decls()) { + if (const auto *FD = dyn_cast(D)) { + if (FD->isInlined() || FD->doesThisDeclarationHaveABody() || + FD->isPureVirtual()) + continue; + if (D->hasAttr()) + return true; + } + } + + return false; +} + +static void setVTableSelectiveDLLImportExport(CodeGenModule &CGM, + llvm::GlobalVariable *VTable, + const CXXRecordDecl *RD) { + if (VTable->getDLLStorageClass() != + llvm::GlobalVariable::DefaultStorageClass || + RD->hasAttr() || RD->hasAttr()) + return; + + if (CGM.getVTables().isVTableExternal(RD)) { + if (CXXRecordNonInlineHasAttr(RD)) + VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + } else if (CXXRecordNonInlineHasAttr(RD)) + VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); +} + void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD) { llvm::GlobalVariable *VTable = getAddrOfVTable(RD, CharUnits()); @@ -1818,6 +1849,9 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, if (CGM.supportsCOMDAT() && VTable->isWeakForLinker()) VTable->setComdat(CGM.getModule().getOrInsertComdat(VTable->getName())); + if (CGM.getTarget().hasPS4DLLImportExport()) + setVTableSelectiveDLLImportExport(CGM, VTable, RD); + // Set the right visibility. CGM.setGVProperties(VTable, RD); @@ -1905,29 +1939,6 @@ ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base, VTable->getValueType(), VTable, Indices, /*InBounds=*/true, InRange); } -// Check whether all the non-inline virtual methods for the class have the -// specified attribute. -template -static bool CXXRecordAllNonInlineVirtualsHaveAttr(const CXXRecordDecl *RD) { - bool FoundNonInlineVirtualMethodWithAttr = false; - for (const auto *D : RD->noload_decls()) { - if (const auto *FD = dyn_cast(D)) { - if (!FD->isVirtualAsWritten() || FD->isInlineSpecified() || - FD->doesThisDeclarationHaveABody()) - continue; - if (!D->hasAttr()) - return false; - FoundNonInlineVirtualMethodWithAttr = true; - } - } - - // We didn't find any non-inline virtual methods missing the attribute. We - // will return true when we found at least one non-inline virtual with the - // attribute. (This lets our caller know that the attribute needs to be - // propagated up to the vtable.) - return FoundNonInlineVirtualMethodWithAttr; -} - llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, const CXXRecordDecl *NearestVBase) { @@ -1981,26 +1992,10 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, getContext().toCharUnitsFromBits(PAlign).getAsAlign()); VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - // In MS C++ if you have a class with virtual functions in which you are using - // selective member import/export, then all virtual functions must be exported - // unless they are inline, otherwise a link error will result. To match this - // behavior, for such classes, we dllimport the vtable if it is defined - // externally and all the non-inline virtual methods are marked dllimport, and - // we dllexport the vtable if it is defined in this TU and all the non-inline - // virtual methods are marked dllexport. - if (CGM.getTarget().hasPS4DLLImportExport()) { - if ((!RD->hasAttr()) && (!RD->hasAttr())) { - if (CGM.getVTables().isVTableExternal(RD)) { - if (CXXRecordAllNonInlineVirtualsHaveAttr(RD)) - VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); - } else { - if (CXXRecordAllNonInlineVirtualsHaveAttr(RD)) - VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); - } - } - } - CGM.setGVProperties(VTable, RD); + if (CGM.getTarget().hasPS4DLLImportExport()) + setVTableSelectiveDLLImportExport(CGM, VTable, RD); + CGM.setGVProperties(VTable, RD); return VTable; } @@ -3285,7 +3280,7 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { // Import the typeinfo symbol when all non-inline virtual methods are // imported. if (CGM.getTarget().hasPS4DLLImportExport()) { - if (RD && CXXRecordAllNonInlineVirtualsHaveAttr(RD)) { + if (RD && CXXRecordNonInlineHasAttr(RD)) { GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); CGM.setDSOLocal(GV); } @@ -3938,13 +3933,13 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( // Export the typeinfo in the same circumstances as the vtable is exported. auto GVDLLStorageClass = DLLStorageClass; - if (CGM.getTarget().hasPS4DLLImportExport()) { + if (CGM.getTarget().hasPS4DLLImportExport() && + GVDLLStorageClass != llvm::GlobalVariable::DLLExportStorageClass) { if (const RecordType *RecordTy = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(RecordTy->getDecl()); if (RD->hasAttr() || - CXXRecordAllNonInlineVirtualsHaveAttr(RD)) { + CXXRecordNonInlineHasAttr(RD)) GVDLLStorageClass = llvm::GlobalVariable::DLLExportStorageClass; - } } } @@ -3984,9 +3979,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( CGM.setDSOLocal(GV); TypeName->setDLLStorageClass(DLLStorageClass); - GV->setDLLStorageClass(CGM.getTarget().hasPS4DLLImportExport() - ? GVDLLStorageClass - : DLLStorageClass); + GV->setDLLStorageClass(GVDLLStorageClass); TypeName->setPartition(CGM.getCodeGenOpts().SymbolPartition); GV->setPartition(CGM.getCodeGenOpts().SymbolPartition); diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 44e86c0b40f6864e00893968e420a5127b2add63..d1ff8b4b62f1570ed545946bf0e198cf1661346a 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -45,7 +45,8 @@ public: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyKernelArgumentType(QualType Ty) const; - ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const; + ABIArgInfo classifyArgumentType(QualType Ty, bool Variadic, + unsigned &NumRegsLeft) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, @@ -103,12 +104,16 @@ void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + unsigned ArgumentIndex = 0; + const unsigned numFixedArguments = FI.getNumRequiredArgs(); + unsigned NumRegsLeft = MaxNumRegsForArgsRet; for (auto &Arg : FI.arguments()) { if (CC == llvm::CallingConv::AMDGPU_KERNEL) { Arg.info = classifyKernelArgumentType(Arg.type); } else { - Arg.info = classifyArgumentType(Arg.type, NumRegsLeft); + bool FixedArgument = ArgumentIndex++ < numFixedArguments; + Arg.info = classifyArgumentType(Arg.type, !FixedArgument, NumRegsLeft); } } } @@ -197,12 +202,20 @@ ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(LTy, 0, nullptr, false); } -ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, +ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, bool Variadic, unsigned &NumRegsLeft) const { assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); + if (Variadic) { + return ABIArgInfo::getDirect(/*T=*/nullptr, + /*Offset=*/0, + /*Padding=*/nullptr, + /*CanBeFlattened=*/false, + /*Align=*/0); + } + if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 2868b4f2b02e9122eb11ceaa3d49cd8e37b25bd2..f5ea73a04ae5cbefd8258bd19cd072eaab808cbd 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -2653,22 +2653,13 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Diag(clang::diag::note_drv_t_option_is_global); } - // CUDA/HIP and their preprocessor expansions can be accepted by CL mode. // Warn -x after last input file has no effect - auto LastXArg = Args.getLastArgValue(options::OPT_x); - const llvm::StringSet<> ValidXArgs = {"cuda", "hip", "cui", "hipi"}; - if (!IsCLMode() || ValidXArgs.contains(LastXArg)) { + { Arg *LastXArg = Args.getLastArgNoClaim(options::OPT_x); Arg *LastInputArg = Args.getLastArgNoClaim(options::OPT_INPUT); if (LastXArg && LastInputArg && LastInputArg->getIndex() < LastXArg->getIndex()) Diag(clang::diag::warn_drv_unused_x) << LastXArg->getValue(); - } else { - // In CL mode suggest /TC or /TP since -x doesn't make sense if passed via - // /clang:. - if (auto *A = Args.getLastArg(options::OPT_x)) - Diag(diag::err_drv_unsupported_opt_with_suggestion) - << A->getAsString(Args) << "/TC' or '/TP"; } for (Arg *A : Args) { diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 85825e1ea65b1596da6cee092bc1165b0682740d..381d72e045b950ba09ba9fe3033c102baaba8adf 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -479,14 +479,6 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, return false; }(); - // Currently only supported for small code model. - if (TOCDataGloballyinEffect && - (Args.getLastArgValue(options::OPT_mcmodel_EQ) == "large" || - Args.getLastArgValue(options::OPT_mcmodel_EQ) == "medium")) { - D.Diag(clang::diag::warn_drv_unsupported_tocdata); - return; - } - enum TOCDataSetting { AddressInTOC = 0, // Address of the symbol stored in the TOC. DataInTOC = 1 // Symbol defined in the TOC. diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp index d23f9b36efb9acf0591afe18b133de4a762260b9..9ea4cc3f7cb95b0084c0b555dc75b9c99015a3bf 100644 --- a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp +++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -181,7 +181,7 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, // -m*-float and -mfpu=none/0/32 conflict with -mlsx. if (A->getOption().matches(options::OPT_mlsx)) { if (llvm::find(Features, "-d") != Features.end()) - D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx); + D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0; else /*-mlsx*/ Features.push_back("+lsx"); } else /*-mno-lsx*/ { @@ -196,7 +196,7 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, // -mno-lsx conflicts with -mlasx. if (A->getOption().matches(options::OPT_mlasx)) { if (llvm::find(Features, "-d") != Features.end()) - D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx); + D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1; else if (llvm::find(Features, "-lsx") != Features.end()) D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination); else { /*-mlasx*/ diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 8295d001ec6f7882ac699a64ccc541d4fd7c3c33..75f9c99d5d0bf485e67ec819725e13a6a8d76e6e 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -310,4 +310,6 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back("+prefer-no-gather"); if (Args.hasArg(options::OPT_mno_scatter)) Features.push_back("+prefer-no-scatter"); + if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32)) + Features.push_back("+inline-asm-use-gpr32"); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6d2015b2cd15660c0f4908e864998316fa3b3580..4e1c52462e5842c8cce009195ab37e9fd9ff1e71 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -45,6 +45,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Frontend/Debug/Options.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" @@ -1030,7 +1031,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // If user provided -o, that is the dependency target, except // when we are only generating a dependency file. - Arg *OutputOpt = Args.getLastArg(options::OPT_o); + Arg *OutputOpt = Args.getLastArg(options::OPT_o, options::OPT__SLASH_Fo); if (OutputOpt && Output.getType() != types::TY_Dependencies) { DepTarget = OutputOpt->getValue(); } else { @@ -4642,6 +4643,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame, options::OPT_fno_force_dwarf_frame); + bool EnableTypeUnits = false; if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { if (!(T.isOSBinFormatELF() || T.isOSBinFormatWasm())) { @@ -4652,11 +4654,24 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, } else if (checkDebugInfoOption( Args.getLastArg(options::OPT_fdebug_types_section), Args, D, TC)) { + EnableTypeUnits = true; CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-generate-type-units"); } } + if (const Arg *A = + Args.getLastArg(options::OPT_gomit_unreferenced_methods, + options::OPT_gno_omit_unreferenced_methods)) + (void)checkDebugInfoOption(A, Args, D, TC); + if (Args.hasFlag(options::OPT_gomit_unreferenced_methods, + options::OPT_gno_omit_unreferenced_methods, false) && + (DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor || + DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo) && + !EnableTypeUnits) { + CmdArgs.push_back("-gomit-unreferenced-methods"); + } + // To avoid join/split of directory+filename, the integrated assembler prefers // the directory form of .file on all DWARF versions. GNU as doesn't allow the // form before DWARF v5. @@ -5681,11 +5696,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // enabled. This alias option is being used to simplify the hasFlag logic. OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; - // We turn strict aliasing off by default if we're in CL mode, since MSVC + // We turn strict aliasing off by default if we're Windows MSVC since MSVC // doesn't do any TBAA. - bool TBAAOnByDefault = !D.IsCLMode(); if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, - options::OPT_fno_strict_aliasing, TBAAOnByDefault)) + options::OPT_fno_strict_aliasing, !IsWindowsMSVC)) CmdArgs.push_back("-relaxed-aliasing"); if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, options::OPT_fno_struct_path_tbaa, true)) @@ -7027,8 +7041,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, true))); - if (IsMSVCCompat) + if (IsMSVCCompat) { CmdArgs.push_back("-fms-compatibility"); + if (!types::isCXX(Input.getType()) && + Args.hasArg(options::OPT_fms_define_stdc)) + CmdArgs.push_back("-fms-define-stdc"); + } if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() && Args.hasArg(options::OPT_fms_runtime_lib_EQ)) @@ -7263,10 +7281,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // -fsized-deallocation is off by default, as it is an ABI-breaking change for - // most platforms. - Args.addOptInFlag(CmdArgs, options::OPT_fsized_deallocation, - options::OPT_fno_sized_deallocation); + // -fsized-deallocation is on by default in C++14 onwards and otherwise off + // by default. + Args.addLastArg(CmdArgs, options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation); // -faligned-allocation is on by default in C++17 onwards and otherwise off // by default. diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index d5f93c9c830faa06238b2dc85d179bfa98526a16..bbc8be91fd70b701cb00f1f8bd61ec22cb149a9f 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -84,6 +84,8 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_123; if (raw_version < 12050) return CudaVersion::CUDA_124; + if (raw_version < 12060) + return CudaVersion::CUDA_125; return CudaVersion::NEW; } @@ -690,6 +692,7 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(125, 85); CASE_CUDA_VERSION(124, 84); CASE_CUDA_VERSION(123, 83); CASE_CUDA_VERSION(122, 82); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index caf6c4a444fdcec76007c09ffc73c15bc4d3002c..593b403a1e3f057e82c5f7ce42f9963c1057f228 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -2912,9 +2912,54 @@ static bool sdkSupportsBuiltinModules(const Darwin::DarwinPlatformKind &TargetPl } } -void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const { +static inline llvm::VersionTuple +sizedDeallocMinVersion(llvm::Triple::OSType OS) { + switch (OS) { + default: + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.12. + return llvm::VersionTuple(10U, 12U); + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 10.0.0. + return llvm::VersionTuple(10U); + case llvm::Triple::WatchOS: // Earliest supporting version is 3.0.0. + return llvm::VersionTuple(3U); + } + + llvm_unreachable("Unexpected OS"); +} + +bool Darwin::isSizedDeallocationUnavailable() const { + llvm::Triple::OSType OS; + + if (isTargetMacCatalyst()) + return TargetVersion < sizedDeallocMinVersion(llvm::Triple::MacOSX); + switch (TargetPlatform) { + case MacOS: // Earlier than 10.12. + OS = llvm::Triple::MacOSX; + break; + case IPhoneOS: + OS = llvm::Triple::IOS; + break; + case TvOS: // Earlier than 10.0. + OS = llvm::Triple::TvOS; + break; + case WatchOS: // Earlier than 3.0. + OS = llvm::Triple::WatchOS; + break; + case DriverKit: + case XROS: + // Always available. + return false; + } + + return TargetVersion < sizedDeallocMinVersion(OS); +} + +void Darwin::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { // Pass "-faligned-alloc-unavailable" only when the user hasn't manually // enabled or disabled aligned allocations. if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation, @@ -2922,6 +2967,13 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); + // Pass "-fno-sized-deallocation" only when the user hasn't manually enabled + // or disabled sized deallocations. + if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation) && + isSizedDeallocationUnavailable()) + CC1Args.push_back("-fno-sized-deallocation"); + addClangCC1ASTargetOptions(DriverArgs, CC1Args); // Enable compatibility mode for NSItemProviderCompletionHandler in diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 10d4b69e5d5f10dacd40442f20930ca0aeca719f..b45279ecedeb250af0c123007745221e17509e7d 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -511,6 +511,10 @@ protected: /// targeting. bool isAlignedAllocationUnavailable() const; + /// Return true if c++14 sized deallocation functions are not implemented in + /// the c++ standard library of the deployment target we are targeting. + bool isSizedDeallocationUnavailable() const; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 42ca060186fd8bdce79a4cda14a54305a9ad3127..9609a1dc65c095a79bf567dabb050ec223395bad 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -765,6 +765,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fopenmp"); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + if (Args.hasArg(options::OPT_fopenmp_force_usm)) + CmdArgs.push_back("-fopenmp-force-usm"); + // FIXME: Clang supports a whole bunch more flags here. break; default: diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 9849c59685cca78b6e1645ed7aa3d8a05cd9f182..b141e5f2adfab13276153795e43caf22307f40f6 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2227,10 +2227,19 @@ void Generic_GCC::GCCInstallationDetector::init( SmallVector CandidateBiarchTripleAliases; // Add some triples that we want to check first. CandidateTripleAliases.push_back(TargetTriple.str()); - std::string TripleNoVendor = TargetTriple.getArchName().str() + "-" + - TargetTriple.getOSAndEnvironmentName().str(); - if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) + std::string TripleNoVendor, BiarchTripleNoVendor; + if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) { + StringRef OSEnv = TargetTriple.getOSAndEnvironmentName(); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) + OSEnv = "linux-gnu"; + TripleNoVendor = (TargetTriple.getArchName().str() + '-' + OSEnv).str(); CandidateTripleAliases.push_back(TripleNoVendor); + if (BiarchVariantTriple.getArch() != llvm::Triple::UnknownArch) { + BiarchTripleNoVendor = + (BiarchVariantTriple.getArchName().str() + '-' + OSEnv).str(); + CandidateBiarchTripleAliases.push_back(BiarchTripleNoVendor); + } + } CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, @@ -2453,11 +2462,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // lists should shrink over time. Please don't add more elements to *Triples. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", - "aarch64-suse-linux"}; + "aarch64-none-linux-gnu", "aarch64-redhat-linux", "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; - static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", - "aarch64_be-linux-gnu"}; + static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; @@ -2482,9 +2489,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", - "x86_64-slackware-linux", "x86_64-unknown-linux", - "x86_64-amazon-linux"}; + "x86_64-manbo-linux-gnu", "x86_64-slackware-linux", + "x86_64-unknown-linux", "x86_64-amazon-linux"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; static const char *const X32LibDirs[] = {"/libx32", "/lib"}; @@ -2500,26 +2506,24 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"}; static const char *const M68kLibDirs[] = {"/lib"}; - static const char *const M68kTriples[] = { - "m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"}; + static const char *const M68kTriples[] = {"m68k-unknown-linux-gnu", + "m68k-suse-linux"}; static const char *const MIPSLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSTriples[] = { "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/libo32", "/lib"}; - static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu"}; + static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", + "mips-img-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { - "mips64-linux-gnu", "mips-mti-linux-gnu", - "mips-img-linux-gnu", "mips64-linux-gnuabi64", + "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64-linux-gnuabi64", "mipsisa64r6-linux-gnu", "mipsisa64r6-linux-gnuabi64"}; static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64ELTriples[] = { - "mips64el-linux-gnu", "mips-mti-linux-gnu", - "mips-img-linux-gnu", "mips64el-linux-gnuabi64", + "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64", "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64"}; static const char *const MIPSN32LibDirs[] = {"/lib32"}; @@ -2534,46 +2538,39 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { - "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", + "powerpc-unknown-linux-gnu", // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux". "powerpc64-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPCLELibDirs[] = {"/lib32", "/lib"}; - static const char *const PPCLETriples[] = {"powerpcle-linux-gnu", - "powerpcle-unknown-linux-gnu", + static const char *const PPCLETriples[] = {"powerpcle-unknown-linux-gnu", "powerpcle-linux-musl"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; - static const char *const PPC64Triples[] = { - "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", - "powerpc64-suse-linux", "ppc64-redhat-linux"}; + static const char *const PPC64Triples[] = {"powerpc64-unknown-linux-gnu", + "powerpc64-suse-linux", + "ppc64-redhat-linux"}; static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64LETriples[] = { - "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", - "powerpc64le-none-linux-gnu", "powerpc64le-suse-linux", - "ppc64le-redhat-linux"}; + "powerpc64le-unknown-linux-gnu", "powerpc64le-none-linux-gnu", + "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"}; static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu", - "riscv32-linux-gnu", "riscv32-unknown-elf"}; static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", - "riscv64-linux-gnu", "riscv64-unknown-elf"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; - static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", - "sparcv8-linux-gnu"}; + static const char *const SPARCv8Triples[] = {"sparcv8-linux-gnu"}; static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; - static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", - "sparcv9-linux-gnu"}; + static const char *const SPARCv9Triples[] = {"sparcv9-linux-gnu"}; static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; static const char *const SystemZTriples[] = { - "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", - "s390x-suse-linux", "s390x-redhat-linux"}; - + "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", + "s390x-redhat-linux"}; using std::begin; using std::end; diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp index a144b28057f4c20dceda3560fe4e1caac567f245..bdbcf9109129dd27178cfa8321c95da584a78079 100644 --- a/clang/lib/Driver/ToolChains/HIPSPV.cpp +++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -193,7 +193,7 @@ void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, StringRef hipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ); if (hipPath.empty()) { - getDriver().Diag(diag::err_drv_hipspv_no_hip_path) << 1 << "'-nogpuinc'"; + getDriver().Diag(diag::err_drv_hipspv_no_hip_path); return; } SmallString<128> P(hipPath); diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index b1ff697b368b135d662ed08e6acd60fe1a264750..f32a23f111e4bf9736b642afc8da4c896383bb67 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -106,9 +106,9 @@ private: std::string ID = IA->getId().str(); if (!ID.empty()) { ID = llvm::utohexstr(llvm::MD5Hash(ID), /*LowerCase=*/true); - FatBinSymbols.insert(Twine(FatBinPrefix + "_" + ID).str()); + FatBinSymbols.insert((FatBinPrefix + Twine('_') + ID).str()); GPUBinHandleSymbols.insert( - Twine(GPUBinHandlePrefix + "_" + ID).str()); + (GPUBinHandlePrefix + Twine('_') + ID).str()); continue; } if (IA->getInputArg().getNumValues() == 0) diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 48369e030aade2f79f374a9c22a363b08f30d202..3950a8ed38e8b43d62901b71a8b94279c96bbd9e 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -61,9 +61,8 @@ public: /// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to /// override the default. llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { - return getTriple().isOSBinFormatMachO() - ? llvm::codegenoptions::DIF_DWARF - : llvm::codegenoptions::DIF_CodeView; + return getTriple().isOSBinFormatCOFF() ? llvm::codegenoptions::DIF_CodeView + : llvm::codegenoptions::DIF_DWARF; } /// Set the debugger tuning to "default", since we're definitely not tuning diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp index 27de69550853cf9a61d24d2055cd7cd896befd1d..ce900600cbee5153a486fbc81f48e8f1b84d736e 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.cpp +++ b/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SPIRV.h" #include "CommonArgs.h" +#include "clang/Basic/Version.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/InputInfo.h" @@ -32,8 +33,15 @@ void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T, CmdArgs.append({"-o", Output.getFilename()}); - const char *Exec = - C.getArgs().MakeArgString(T.getToolChain().GetProgramPath("llvm-spirv")); + // Try to find "llvm-spirv-". Otherwise, fall back to + // plain "llvm-spirv". + using namespace std::string_literals; + auto VersionedTool = "llvm-spirv-"s + std::to_string(LLVM_VERSION_MAJOR); + std::string ExeCand = T.getToolChain().GetProgramPath(VersionedTool.c_str()); + if (!llvm::sys::fs::can_execute(ExeCand)) + ExeCand = T.getToolChain().GetProgramPath("llvm-spirv"); + + const char *Exec = C.getArgs().MakeArgString(ExeCand); C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), Exec, CmdArgs, Input, Output)); } diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp b/clang/lib/Driver/ToolChains/ZOS.cpp index d5fc7b8ef562a66870c15838cbd2ff60d90127a7..074e0556ecd2ad2a60bba85539ad58bcd1d49965 100644 --- a/clang/lib/Driver/ToolChains/ZOS.cpp +++ b/clang/lib/Driver/ToolChains/ZOS.cpp @@ -36,6 +36,12 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs, if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation, options::OPT_fno_aligned_allocation)) CC1Args.push_back("-faligned-alloc-unavailable"); + + // Pass "-fno-sized-deallocation" only when the user hasn't manually enabled + // or disabled sized deallocations. + if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation)) + CC1Args.push_back("-fno-sized-deallocation"); } void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp index 96bef967d8591a248f384e330fa7948d3e3269fb..ab1108f663deaccb802f713f3aa26e663a468b44 100644 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -14,7 +14,6 @@ #include "clang/ExtractAPI/API.h" #include "clang/AST/RawCommentList.h" -#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 98b9343924a835675dbedd4f4e37c87afab56329..8c7c0f8a147260503900251a44c75366bc0b824d 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -999,11 +999,11 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters( DeclarationFragments::FragmentKind::GenericParameter); if (TemplateParam->hasDefaultArgument()) { - DeclarationFragments After; + const auto Default = TemplateParam->getDefaultArgument(); Fragments.append(" = ", DeclarationFragments::FragmentKind::Text) - .append(getFragmentsForType(TemplateParam->getDefaultArgument(), - TemplateParam->getASTContext(), After)); - Fragments.append(std::move(After)); + .append(getFragmentsForTemplateArguments( + {Default.getArgument()}, TemplateParam->getASTContext(), + {Default})); } } else if (const auto *NTP = dyn_cast(ParameterArray[i])) { @@ -1023,8 +1023,9 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters( if (NTP->hasDefaultArgument()) { SmallString<8> ExprStr; raw_svector_ostream Output(ExprStr); - NTP->getDefaultArgument()->printPretty( - Output, nullptr, NTP->getASTContext().getPrintingPolicy()); + NTP->getDefaultArgument().getArgument().print( + NTP->getASTContext().getPrintingPolicy(), Output, + /*IncludeType=*/false); Fragments.append(" = ", DeclarationFragments::FragmentKind::Text) .append(ExprStr, DeclarationFragments::FragmentKind::Text); } @@ -1083,12 +1084,22 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateArguments( if (StringRef(ArgumentFragment.begin()->Spelling) .starts_with("type-parameter")) { - std::string ProperArgName = TemplateArgumentLocs.value()[i] - .getTypeSourceInfo() - ->getType() - .getAsString(); - ArgumentFragment.begin()->Spelling.swap(ProperArgName); + if (TemplateArgumentLocs.has_value() && + TemplateArgumentLocs->size() > i) { + std::string ProperArgName = TemplateArgumentLocs.value()[i] + .getTypeSourceInfo() + ->getType() + .getAsString(); + ArgumentFragment.begin()->Spelling.swap(ProperArgName); + } else { + auto &Spelling = ArgumentFragment.begin()->Spelling; + Spelling.clear(); + raw_string_ostream OutStream(Spelling); + CTA.print(Context.getPrintingPolicy(), OutStream, false); + OutStream.flush(); + } } + Fragments.append(std::move(ArgumentFragment)); break; } @@ -1211,9 +1222,9 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( cast(Decl))) .pop_back() // there is an extra semicolon now .append("<", DeclarationFragments::FragmentKind::Text) - .append( - getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), - Decl->getASTContext(), std::nullopt)) + .append(getFragmentsForTemplateArguments( + Decl->getTemplateArgs().asArray(), Decl->getASTContext(), + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) .appendSemicolon(); } @@ -1254,9 +1265,9 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(Decl)) .pop_back() // there is an extra semicolon now .append("<", DeclarationFragments::FragmentKind::Text) - .append( - getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), - Decl->getASTContext(), std::nullopt)) + .append(getFragmentsForTemplateArguments( + Decl->getTemplateArgs().asArray(), Decl->getASTContext(), + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) .appendSemicolon(); } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 9cba0c2614eef7b3c10a797ec33551ddeae66377..c015e03fa15e72576a73e8e630026a8df2821c29 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -308,6 +308,7 @@ struct ScalarEnumerationTraits { FormatStyle::EscapedNewlineAlignmentStyle &Value) { IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign); IO.enumCase(Value, "Left", FormatStyle::ENAS_Left); + IO.enumCase(Value, "LeftWithLastLine", FormatStyle::ENAS_LeftWithLastLine); IO.enumCase(Value, "Right", FormatStyle::ENAS_Right); // For backward compatibility. diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 8792f4c750748fbbf4487e0a11bd880365fd9922..e4a4f27e502b1c83530a9bfffbc85fb9f9565803 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -727,6 +727,29 @@ public: return isOneOf(tok::star, tok::amp, tok::ampamp); } + bool isCppAlternativeOperatorKeyword() const { + assert(!TokenText.empty()); + if (!isalpha(TokenText[0])) + return false; + + switch (Tok.getKind()) { + case tok::ampamp: + case tok::ampequal: + case tok::amp: + case tok::pipe: + case tok::tilde: + case tok::exclaim: + case tok::exclaimequal: + case tok::pipepipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: + return true; + default: + return false; + } + } + bool isUnaryOperator() const { switch (Tok.getKind()) { case tok::plus: diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 7c4c76a91f2c55223324ede7eb880b83d00f60bb..26c0aa36bdcb64f9cfc98efd5a8cb139df179607 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4846,8 +4846,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } - if (Left.Tok.getIdentifierInfo() && Right.is(tok::numeric_constant)) + // C++ Core Guidelines suppression tag, e.g. `[[suppress(type.5)]]`. + if (Left.is(tok::identifier) && Right.is(tok::numeric_constant)) return Right.TokenText[0] != '.'; + // `Left` is a keyword (including C++ alternative operator) or identifier. + if (Left.Tok.getIdentifierInfo() && Right.Tok.isLiteral()) + return true; } else if (Style.isProto()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 3dd10f6bd2b316e2c2c00e03d05e7ec85291c6a7..d6061c2666c2ad87f606eb39768c580822d75823 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1689,9 +1689,15 @@ void UnwrappedLineParser::parseStructuralElement( break; } - const bool InRequiresExpression = - OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); - do { + for (const bool InRequiresExpression = + OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); + !eof();) { + if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) { + if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true); + Next && Next->isBinaryOperator()) { + FormatTok->Tok.setKind(tok::identifier); + } + } const FormatToken *Previous = FormatTok->Previous; switch (FormatTok->Tok.getKind()) { case tok::at: @@ -2122,7 +2128,7 @@ void UnwrappedLineParser::parseStructuralElement( nextToken(); break; } - } while (!eof()); + } } bool UnwrappedLineParser::tryToParsePropertyAccessor() { @@ -2230,7 +2236,7 @@ bool UnwrappedLineParser::tryToParseLambda() { bool InTemplateParameterList = false; while (FormatTok->isNot(tok::l_brace)) { - if (FormatTok->isTypeName(LangOpts)) { + if (FormatTok->isTypeName(LangOpts) || FormatTok->isAttribute()) { nextToken(); continue; } @@ -3987,8 +3993,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { case tok::coloncolon: break; default: - if (!ClassName && Previous->is(tok::identifier)) + if (!ClassName && Previous->is(tok::identifier) && + Previous->isNot(TT_AttributeMacro)) { ClassName = Previous; + } } } @@ -4013,6 +4021,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { if (AngleNestingLevel == 0) { if (FormatTok->is(tok::colon)) { IsDerived = true; + } else if (FormatTok->is(tok::identifier) && + FormatTok->Previous->is(tok::coloncolon)) { + ClassName = FormatTok; } else if (FormatTok->is(tok::l_paren) && IsNonMacroIdentifier(FormatTok->Previous)) { break; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index ed06d6098a9f20ae0b831bbe15fa4914b2f9fccf..50531aee9d597800a933a0a21b94c08a7338cdd1 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -1245,22 +1245,29 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, } void WhitespaceManager::alignEscapedNewlines() { - if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign) + const auto Align = Style.AlignEscapedNewlines; + if (Align == FormatStyle::ENAS_DontAlign) return; - bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left; - unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; + const bool WithLastLine = Align == FormatStyle::ENAS_LeftWithLastLine; + const bool AlignLeft = Align == FormatStyle::ENAS_Left || WithLastLine; + const auto MaxColumn = Style.ColumnLimit; + unsigned MaxEndOfLine = AlignLeft ? 0 : MaxColumn; unsigned StartOfMacro = 0; for (unsigned i = 1, e = Changes.size(); i < e; ++i) { Change &C = Changes[i]; - if (C.NewlinesBefore > 0) { - if (C.ContinuesPPDirective) { - MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine); - } else { - alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); - MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; - StartOfMacro = i; - } + if (C.NewlinesBefore == 0 && (!WithLastLine || C.Tok->isNot(tok::eof))) + continue; + const bool InPPDirective = C.ContinuesPPDirective; + const auto BackslashColumn = C.PreviousEndOfTokenColumn + 2; + if (InPPDirective || + (WithLastLine && (MaxColumn == 0 || BackslashColumn <= MaxColumn))) { + MaxEndOfLine = std::max(BackslashColumn, MaxEndOfLine); + } + if (!InPPDirective) { + alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); + MaxEndOfLine = AlignLeft ? 0 : MaxColumn; + StartOfMacro = i; } } alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 14ee02c4cd5821a1ef7e4f7f4d2bd8d9fb4f0061..58694e5399d58ca143f30ad313a9bff08c3a9cb8 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2407,6 +2407,9 @@ void CompilerInvocationBase::GenerateDiagnosticArgs( // This option is automatically generated from UndefPrefixes. if (Warning == "undef-prefix") continue; + // This option is automatically generated from CheckConstexprFunctionBodies. + if (Warning == "invalid-constexpr" || Warning == "no-invalid-constexpr") + continue; Consumer(StringRef("-W") + Warning); } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 454653a31534cd3ef7d22d2dbf51aed94314b547..4f064321997a2268047b7634e09a803ce0ab8fb0 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -273,9 +273,6 @@ std::unique_ptr GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::vector> Consumers; - Consumers.push_back(std::make_unique( - CI.getPreprocessor(), CI.getModuleCache(), - CI.getFrontendOpts().OutputFile)); if (CI.getFrontendOpts().GenReducedBMI && !CI.getFrontendOpts().ModuleOutputPath.empty()) { @@ -284,6 +281,10 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, CI.getFrontendOpts().ModuleOutputPath)); } + Consumers.push_back(std::make_unique( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().OutputFile)); + return std::make_unique(std::move(Consumers)); } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 68760e00003e03d71617dcba906104f195159483..e8c8a5175f8f4164d932ab4d4b7fb945fa004f5f 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -432,7 +432,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // [C++] Whether __STDC__ is predefined and if so, what its value is, // are implementation-defined. // (Removed in C++20.) - if (!LangOpts.MSVCCompat && !LangOpts.TraditionalCPP) + if ((!LangOpts.MSVCCompat || LangOpts.MSVCEnableStdcMacro) && + !LangOpts.TraditionalCPP) Builder.defineMacro("__STDC__"); // -- __STDC_HOSTED__ // The integer literal 1 if the implementation is a hosted diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp index b76728acb90778efa4972074531b9c31b797d9f1..0887b5a504f05a3383c239fc44226745650e9e3e 100644 --- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -574,7 +574,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, SmallString<256> diagnostic; Info.FormatDiagnostic(diagnostic); getMetaDiags()->Report( - diag::warn_fe_serialized_diag_failure_during_finalisation) + diag::warn_fe_serialized_diag_failure_during_finalization) << diagnostic; return; } diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 5f02c71f6ca51a6b0d4511d108270f3c812ba7cd..d3090e488306f0b739fe9fdcd5cea4ab39078f81 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -153,12 +153,10 @@ set(x86_files avx512bwintrin.h avx512cdintrin.h avx512dqintrin.h - avx512erintrin.h avx512fintrin.h avx512fp16intrin.h avx512ifmaintrin.h avx512ifmavlintrin.h - avx512pfintrin.h avx512vbmi2intrin.h avx512vbmiintrin.h avx512vbmivlintrin.h @@ -445,14 +443,14 @@ endforeach( f ) function(add_header_target target_name file_list) add_library(${target_name} INTERFACE ${file_list}) set_target_properties(${target_name} PROPERTIES - FOLDER "Misc" + FOLDER "Clang/Resources" RUNTIME_OUTPUT_DIRECTORY "${output_dir}") endfunction() # The catch-all clang-resource-headers target add_library(clang-resource-headers INTERFACE ${out_files}) set_target_properties("clang-resource-headers" PROPERTIES - FOLDER "Misc" + FOLDER "Clang/Resources" RUNTIME_OUTPUT_DIRECTORY "${output_dir}") add_dependencies("clang-resource-headers" "core-resource-headers" diff --git a/clang/lib/Headers/avx512erintrin.h b/clang/lib/Headers/avx512erintrin.h deleted file mode 100644 index 1c5a2d2d208ff4223811a8ff4d0654d5f533614a..0000000000000000000000000000000000000000 --- a/clang/lib/Headers/avx512erintrin.h +++ /dev/null @@ -1,271 +0,0 @@ -/*===---- avx512erintrin.h - AVX512ER intrinsics ---------------------------=== - * - * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://llvm.org/LICENSE.txt for license information. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - *===-----------------------------------------------------------------------=== - */ -#ifndef __IMMINTRIN_H -#error "Never use directly; include instead." -#endif - -#ifndef __AVX512ERINTRIN_H -#define __AVX512ERINTRIN_H - -/* exp2a23 */ -#define _mm512_exp2a23_round_pd(A, R) \ - ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R))) - -#define _mm512_mask_exp2a23_round_pd(S, M, A, R) \ - ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R))) - -#define _mm512_maskz_exp2a23_round_pd(M, A, R) \ - ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R))) - -#define _mm512_exp2a23_pd(A) \ - _mm512_exp2a23_round_pd((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_exp2a23_pd(S, M, A) \ - _mm512_mask_exp2a23_round_pd((S), (M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_exp2a23_pd(M, A) \ - _mm512_maskz_exp2a23_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_exp2a23_round_ps(A, R) \ - ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R))) - -#define _mm512_mask_exp2a23_round_ps(S, M, A, R) \ - ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R))) - -#define _mm512_maskz_exp2a23_round_ps(M, A, R) \ - ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R))) - -#define _mm512_exp2a23_ps(A) \ - _mm512_exp2a23_round_ps((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_exp2a23_ps(S, M, A) \ - _mm512_mask_exp2a23_round_ps((S), (M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_exp2a23_ps(M, A) \ - _mm512_maskz_exp2a23_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION) - -/* rsqrt28 */ -#define _mm512_rsqrt28_round_pd(A, R) \ - ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R))) - -#define _mm512_mask_rsqrt28_round_pd(S, M, A, R) \ - ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R))) - -#define _mm512_maskz_rsqrt28_round_pd(M, A, R) \ - ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R))) - -#define _mm512_rsqrt28_pd(A) \ - _mm512_rsqrt28_round_pd((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_rsqrt28_pd(S, M, A) \ - _mm512_mask_rsqrt28_round_pd((S), (M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_rsqrt28_pd(M, A) \ - _mm512_maskz_rsqrt28_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_rsqrt28_round_ps(A, R) \ - ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R))) - -#define _mm512_mask_rsqrt28_round_ps(S, M, A, R) \ - ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R))) - -#define _mm512_maskz_rsqrt28_round_ps(M, A, R) \ - ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R))) - -#define _mm512_rsqrt28_ps(A) \ - _mm512_rsqrt28_round_ps((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_rsqrt28_ps(S, M, A) \ - _mm512_mask_rsqrt28_round_ps((S), (M), A, _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_rsqrt28_ps(M, A) \ - _mm512_maskz_rsqrt28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm_rsqrt28_round_ss(A, B, R) \ - ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R))) - -#define _mm_mask_rsqrt28_round_ss(S, M, A, B, R) \ - ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(S), \ - (__mmask8)(M), (int)(R))) - -#define _mm_maskz_rsqrt28_round_ss(M, A, B, R) \ - ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(M), (int)(R))) - -#define _mm_rsqrt28_ss(A, B) \ - _mm_rsqrt28_round_ss((A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_rsqrt28_ss(S, M, A, B) \ - _mm_mask_rsqrt28_round_ss((S), (M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_rsqrt28_ss(M, A, B) \ - _mm_maskz_rsqrt28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_rsqrt28_round_sd(A, B, R) \ - ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R))) - -#define _mm_mask_rsqrt28_round_sd(S, M, A, B, R) \ - ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(S), \ - (__mmask8)(M), (int)(R))) - -#define _mm_maskz_rsqrt28_round_sd(M, A, B, R) \ - ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(M), (int)(R))) - -#define _mm_rsqrt28_sd(A, B) \ - _mm_rsqrt28_round_sd((A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_rsqrt28_sd(S, M, A, B) \ - _mm_mask_rsqrt28_round_sd((S), (M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_rsqrt28_sd(M, A, B) \ - _mm_maskz_rsqrt28_round_sd((M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -/* rcp28 */ -#define _mm512_rcp28_round_pd(A, R) \ - ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R))) - -#define _mm512_mask_rcp28_round_pd(S, M, A, R) \ - ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R))) - -#define _mm512_maskz_rcp28_round_pd(M, A, R) \ - ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R))) - -#define _mm512_rcp28_pd(A) \ - _mm512_rcp28_round_pd((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_rcp28_pd(S, M, A) \ - _mm512_mask_rcp28_round_pd((S), (M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_rcp28_pd(M, A) \ - _mm512_maskz_rcp28_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_rcp28_round_ps(A, R) \ - ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R))) - -#define _mm512_mask_rcp28_round_ps(S, M, A, R) \ - ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R))) - -#define _mm512_maskz_rcp28_round_ps(M, A, R) \ - ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R))) - -#define _mm512_rcp28_ps(A) \ - _mm512_rcp28_round_ps((A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_mask_rcp28_ps(S, M, A) \ - _mm512_mask_rcp28_round_ps((S), (M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm512_maskz_rcp28_ps(M, A) \ - _mm512_maskz_rcp28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION) - -#define _mm_rcp28_round_ss(A, B, R) \ - ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R))) - -#define _mm_mask_rcp28_round_ss(S, M, A, B, R) \ - ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(S), \ - (__mmask8)(M), (int)(R))) - -#define _mm_maskz_rcp28_round_ss(M, A, B, R) \ - ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(M), (int)(R))) - -#define _mm_rcp28_ss(A, B) \ - _mm_rcp28_round_ss((A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_rcp28_ss(S, M, A, B) \ - _mm_mask_rcp28_round_ss((S), (M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_rcp28_ss(M, A, B) \ - _mm_maskz_rcp28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_rcp28_round_sd(A, B, R) \ - ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R))) - -#define _mm_mask_rcp28_round_sd(S, M, A, B, R) \ - ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(S), \ - (__mmask8)(M), (int)(R))) - -#define _mm_maskz_rcp28_round_sd(M, A, B, R) \ - ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(M), (int)(R))) - -#define _mm_rcp28_sd(A, B) \ - _mm_rcp28_round_sd((A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_rcp28_sd(S, M, A, B) \ - _mm_mask_rcp28_round_sd((S), (M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_rcp28_sd(M, A, B) \ - _mm_maskz_rcp28_round_sd((M), (A), (B), _MM_FROUND_CUR_DIRECTION) - -#endif /* __AVX512ERINTRIN_H */ diff --git a/clang/lib/Headers/avx512pfintrin.h b/clang/lib/Headers/avx512pfintrin.h deleted file mode 100644 index f853be021a2dd3786cab95676f7c4ab398c29d8d..0000000000000000000000000000000000000000 --- a/clang/lib/Headers/avx512pfintrin.h +++ /dev/null @@ -1,92 +0,0 @@ -/*===------------- avx512pfintrin.h - PF intrinsics ------------------------=== - * - * - * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://llvm.org/LICENSE.txt for license information. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - *===-----------------------------------------------------------------------=== - */ -#ifndef __IMMINTRIN_H -#error "Never use directly; include instead." -#endif - -#ifndef __AVX512PFINTRIN_H -#define __AVX512PFINTRIN_H - -#define _mm512_mask_prefetch_i32gather_pd(index, mask, addr, scale, hint) \ - __builtin_ia32_gatherpfdpd((__mmask8)(mask), (__v8si)(__m256i)(index), \ - (void const *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_prefetch_i32gather_pd(index, addr, scale, hint) \ - __builtin_ia32_gatherpfdpd((__mmask8) -1, (__v8si)(__m256i)(index), \ - (void const *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_mask_prefetch_i32gather_ps(index, mask, addr, scale, hint) \ - __builtin_ia32_gatherpfdps((__mmask16)(mask), \ - (__v16si)(__m512i)(index), (void const *)(addr), \ - (int)(scale), (int)(hint)) - -#define _mm512_prefetch_i32gather_ps(index, addr, scale, hint) \ - __builtin_ia32_gatherpfdps((__mmask16) -1, \ - (__v16si)(__m512i)(index), (void const *)(addr), \ - (int)(scale), (int)(hint)) - -#define _mm512_mask_prefetch_i64gather_pd(index, mask, addr, scale, hint) \ - __builtin_ia32_gatherpfqpd((__mmask8)(mask), (__v8di)(__m512i)(index), \ - (void const *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_prefetch_i64gather_pd(index, addr, scale, hint) \ - __builtin_ia32_gatherpfqpd((__mmask8) -1, (__v8di)(__m512i)(index), \ - (void const *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_mask_prefetch_i64gather_ps(index, mask, addr, scale, hint) \ - __builtin_ia32_gatherpfqps((__mmask8)(mask), (__v8di)(__m512i)(index), \ - (void const *)(addr), (int)(scale), (int)(hint)) - -#define _mm512_prefetch_i64gather_ps(index, addr, scale, hint) \ - __builtin_ia32_gatherpfqps((__mmask8) -1, (__v8di)(__m512i)(index), \ - (void const *)(addr), (int)(scale), (int)(hint)) - -#define _mm512_prefetch_i32scatter_pd(addr, index, scale, hint) \ - __builtin_ia32_scatterpfdpd((__mmask8)-1, (__v8si)(__m256i)(index), \ - (void *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_mask_prefetch_i32scatter_pd(addr, mask, index, scale, hint) \ - __builtin_ia32_scatterpfdpd((__mmask8)(mask), (__v8si)(__m256i)(index), \ - (void *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_prefetch_i32scatter_ps(addr, index, scale, hint) \ - __builtin_ia32_scatterpfdps((__mmask16)-1, (__v16si)(__m512i)(index), \ - (void *)(addr), (int)(scale), (int)(hint)) - -#define _mm512_mask_prefetch_i32scatter_ps(addr, mask, index, scale, hint) \ - __builtin_ia32_scatterpfdps((__mmask16)(mask), \ - (__v16si)(__m512i)(index), (void *)(addr), \ - (int)(scale), (int)(hint)) - -#define _mm512_prefetch_i64scatter_pd(addr, index, scale, hint) \ - __builtin_ia32_scatterpfqpd((__mmask8)-1, (__v8di)(__m512i)(index), \ - (void *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_mask_prefetch_i64scatter_pd(addr, mask, index, scale, hint) \ - __builtin_ia32_scatterpfqpd((__mmask8)(mask), (__v8di)(__m512i)(index), \ - (void *)(addr), (int)(scale), \ - (int)(hint)) - -#define _mm512_prefetch_i64scatter_ps(addr, index, scale, hint) \ - __builtin_ia32_scatterpfqps((__mmask8)-1, (__v8di)(__m512i)(index), \ - (void *)(addr), (int)(scale), (int)(hint)) - -#define _mm512_mask_prefetch_i64scatter_ps(addr, mask, index, scale, hint) \ - __builtin_ia32_scatterpfqps((__mmask8)(mask), (__v8di)(__m512i)(index), \ - (void *)(addr), (int)(scale), (int)(hint)) - -#endif diff --git a/clang/lib/Headers/cuda_wrappers/algorithm b/clang/lib/Headers/cuda_wrappers/algorithm index f14a0b00bb046621270b4e8ab71e5e9a40a2fb81..3f59f28ae35b35bf48d51a4a65c29876447d7ba4 100644 --- a/clang/lib/Headers/cuda_wrappers/algorithm +++ b/clang/lib/Headers/cuda_wrappers/algorithm @@ -99,7 +99,7 @@ template __attribute__((enable_if(true, ""))) inline _CPP14_CONSTEXPR __host__ __device__ const __T & min(const __T &__a, const __T &__b) { - return __a < __b ? __a : __b; + return __b < __a ? __b : __a; } #pragma pop_macro("_CPP14_CONSTEXPR") diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index 508696d3725b9a4351d00ad35a76577e93bc4e2b..cd6cf09b90cad6ebc93e2835af48479581742fbc 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -151,10 +151,6 @@ #include #endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512ER__) -#include -#endif - #if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512IFMA__) #include #endif @@ -186,10 +182,6 @@ #include #endif -#if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512PF__) -#include -#endif - #if !defined(__SCE__) || __has_feature(modules) || defined(__AVX512FP16__) #include #endif diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index 7eb6dceaabfaeb611123945343d43d15bfece664..1227f45d5432b9c20f9fd01b01f09c70d209491b 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -329,6 +329,25 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst, static __inline__ void __DEFAULT_FN_ATTRS __halt(void) { __asm__ volatile("hlt"); } + +static inline int _inp(unsigned short port) { + int ret; + __asm__ volatile("inb %w1, %b0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline unsigned short _inpw(unsigned short port) { + unsigned short ret; + __asm__ volatile("inw %w1, %w0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline unsigned long _inpd(unsigned short port) { + unsigned long ret; + __asm__ volatile("inl %w1, %k0" : "=a"(ret) : "Nd"(port)); + return ret; +} + #endif #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) @@ -378,7 +397,7 @@ unsigned int _CountLeadingSigns64(__int64); unsigned int _CountOneBits(unsigned long); unsigned int _CountOneBits64(unsigned __int64); -void __cdecl __prefetch(void *); +void __cdecl __prefetch(const void *); #endif /*----------------------------------------------------------------------------*\ diff --git a/clang/lib/Headers/module.modulemap b/clang/lib/Headers/module.modulemap index 4abfd1d98a6351c71c04899acbce6a9adaa50fe9..9ffc249c8d1a23961f2c044e2319abe63960810d 100644 --- a/clang/lib/Headers/module.modulemap +++ b/clang/lib/Headers/module.modulemap @@ -44,7 +44,6 @@ module _Builtin_intrinsics [system] [extern_c] { textual header "avxintrin.h" textual header "avx2intrin.h" textual header "avx512fintrin.h" - textual header "avx512erintrin.h" textual header "fmaintrin.h" header "x86intrin.h" diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 56c3c3636c9bcd9f76819ef9fb62777a79889b71..a9d182aa24470a0f013f8522b5f20d09995f0345 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -15,6 +15,19 @@ typedef enum { ptrauth_key_asib = 1, ptrauth_key_asda = 2, ptrauth_key_asdb = 3, + + /* A process-independent key which can be used to sign code pointers. */ + ptrauth_key_process_independent_code = ptrauth_key_asia, + + /* A process-specific key which can be used to sign code pointers. */ + ptrauth_key_process_dependent_code = ptrauth_key_asib, + + /* A process-independent key which can be used to sign data pointers. */ + ptrauth_key_process_independent_data = ptrauth_key_asda, + + /* A process-specific key which can be used to sign data pointers. */ + ptrauth_key_process_dependent_data = ptrauth_key_asdb, + } ptrauth_key; /* An integer type of the appropriate size for a discriminator argument. */ diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index 8eb88f5a1e94ee999a138f3a7ac59fdd54da687f..a7fa6c5e6898ecbb9a8eb80aa9729188853f607b 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -703,14 +703,16 @@ public: IndexCtx.handleDecl(TP); if (const auto *TTP = dyn_cast(TP)) { if (TTP->hasDefaultArgument()) - IndexCtx.indexTypeSourceInfo(TTP->getDefaultArgumentInfo(), Parent); + handleTemplateArgumentLoc(TTP->getDefaultArgument(), Parent, + TP->getLexicalDeclContext()); if (auto *C = TTP->getTypeConstraint()) IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(), Parent, TTP->getLexicalDeclContext()); } else if (const auto *NTTP = dyn_cast(TP)) { IndexCtx.indexTypeSourceInfo(NTTP->getTypeSourceInfo(), Parent); if (NTTP->hasDefaultArgument()) - IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent); + handleTemplateArgumentLoc(NTTP->getDefaultArgument(), Parent, + TP->getLexicalDeclContext()); } else if (const auto *TTPD = dyn_cast(TP)) { if (TTPD->hasDefaultArgument()) handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index ef90fe9e6f5451701d6b2fd01639c70cad9839bc..5bc8385d874a16869edd75fdd22088237a834671 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -387,8 +387,7 @@ std::unique_ptr IncrementalParser::GenModule() { void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { TranslationUnitDecl *MostRecentTU = PTU.TUPart; - TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); - if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) { + if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) { for (auto &&[Key, List] : *Map) { DeclContextLookupResult R = List.getLookupResult(); std::vector NamedDeclsToRemove; @@ -407,6 +406,16 @@ void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { } } } + + // FIXME: We should de-allocate MostRecentTU + for (Decl *D : MostRecentTU->decls()) { + auto *ND = dyn_cast(D); + if (!ND) + continue; + // Check if we need to clean up the IdResolver chain. + if (ND->getDeclName().getFETokenInfo()) + getCI()->getSema().IdResolver.RemoveDecl(ND); + } } llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index b20e6efcebfd10fb944e1a1b5961aa681ed7d8aa..683f87e8c8c79e36ed90da00151fc400708f3e87 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -229,12 +229,32 @@ IncrementalCompilerBuilder::CreateCudaHost() { } Interpreter::Interpreter(std::unique_ptr CI, - llvm::Error &Err) { - llvm::ErrorAsOutParameter EAO(&Err); + llvm::Error &ErrOut, + std::unique_ptr JITBuilder) + : JITBuilder(std::move(JITBuilder)) { + llvm::ErrorAsOutParameter EAO(&ErrOut); auto LLVMCtx = std::make_unique(); TSCtx = std::make_unique(std::move(LLVMCtx)); - IncrParser = std::make_unique(*this, std::move(CI), - *TSCtx->getContext(), Err); + IncrParser = std::make_unique( + *this, std::move(CI), *TSCtx->getContext(), ErrOut); + if (ErrOut) + return; + + // Not all frontends support code-generation, e.g. ast-dump actions don't + if (IncrParser->getCodeGen()) { + if (llvm::Error Err = CreateExecutor()) { + ErrOut = joinErrors(std::move(ErrOut), std::move(Err)); + return; + } + + // Process the PTUs that came from initialization. For example -include will + // give us a header that's processed at initialization of the preprocessor. + for (PartialTranslationUnit &PTU : IncrParser->getPTUs()) + if (llvm::Error Err = Execute(PTU)) { + ErrOut = joinErrors(std::move(ErrOut), std::move(Err)); + return; + } + } } Interpreter::~Interpreter() { @@ -382,25 +402,29 @@ createJITTargetMachineBuilder(const std::string &TT) { return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT)); } -llvm::Expected> -Interpreter::CreateJITBuilder(CompilerInstance &CI) { - auto JTMB = createJITTargetMachineBuilder(CI.getTargetOpts().Triple); - if (!JTMB) - return JTMB.takeError(); - return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB)); -} - llvm::Error Interpreter::CreateExecutor() { if (IncrExecutor) return llvm::make_error("Operation failed. " "Execution engine exists", std::error_code()); - llvm::Expected> JB = - CreateJITBuilder(*getCompilerInstance()); - if (!JB) - return JB.takeError(); + if (!IncrParser->getCodeGen()) + return llvm::make_error("Operation failed. " + "No code generator available", + std::error_code()); + if (!JITBuilder) { + const std::string &TT = getCompilerInstance()->getTargetOpts().Triple; + auto JTMB = createJITTargetMachineBuilder(TT); + if (!JTMB) + return JTMB.takeError(); + auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB)); + if (!JB) + return JB.takeError(); + JITBuilder = std::move(*JB); + } + llvm::Error Err = llvm::Error::success(); - auto Executor = std::make_unique(*TSCtx, **JB, Err); + auto Executor = + std::make_unique(*TSCtx, *JITBuilder, Err); if (!Err) IncrExecutor = std::move(Executor); diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index c98645993abe076a4481d0ca837f20c9778ffc9b..c7543a48c0b50e2f2a9ad480298de93138689d9a 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2261,8 +2261,17 @@ bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, unsigned PrefixLen = 0; - while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) + while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) { ++PrefixLen; + if (!isLexingRawMode() && + llvm::is_contained({'$', '@', '`'}, CurPtr[PrefixLen])) { + const char *Pos = &CurPtr[PrefixLen]; + Diag(Pos, LangOpts.CPlusPlus26 + ? diag::warn_cxx26_compat_raw_string_literal_character_set + : diag::ext_cxx26_raw_string_literal_character_set) + << StringRef(Pos, 1); + } + } // If the last character was not a '(', then we didn't lex a valid delimiter. if (CurPtr[PrefixLen] != '(') { diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 445d3fd66e38792f670e9046f479209282316426..c528917437332756e90101dd917af145de3337d1 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -467,6 +467,11 @@ bool Parser::ParseAttributeArgumentList( break; } + if (Actions.DiagnoseUnexpandedParameterPack(Expr.get())) { + SawError = true; + break; + } + Exprs.push_back(Expr.get()); if (Tok.isNot(tok::comma)) @@ -666,6 +671,9 @@ void Parser::ParseGNUAttributeArgs( ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; + } else if (AttrKind == ParsedAttr::AT_CXXAssume) { + ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); + return; } // These may refer to the function arguments, but need to be parsed early to @@ -720,6 +728,10 @@ unsigned Parser::ParseClangAttributeArgs( ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Form); break; + + case ParsedAttr::AT_CXXAssume: + ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); + break; } return !Attrs.empty() ? Attrs.begin()->getNumArgs() : 0; } @@ -1923,9 +1935,8 @@ void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) { // variable. // This function moves attributes that should apply to the type off DS to Attrs. void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, - DeclSpec &DS, - Sema::TagUseKind TUK) { - if (TUK == Sema::TUK_Reference) + DeclSpec &DS, TagUseKind TUK) { + if (TUK == TagUseKind::Reference) return; llvm::SmallVector ToBeMoved; @@ -3306,6 +3317,19 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, } } +void Parser::DistributeCLateParsedAttrs(Decl *Dcl, + LateParsedAttrList *LateAttrs) { + if (!LateAttrs) + return; + + if (Dcl) { + for (auto *LateAttr : *LateAttrs) { + if (LateAttr->Decls.empty()) + LateAttr->addDecl(Dcl); + } + } +} + /// Bounds attributes (e.g., counted_by): /// AttrName '(' expression ')' void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, @@ -4843,13 +4867,14 @@ static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS, /// void Parser::ParseStructDeclaration( ParsingDeclSpec &DS, - llvm::function_ref FieldsCallback) { + llvm::function_ref FieldsCallback, + LateParsedAttrList *LateFieldAttrs) { if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseStructDeclaration(DS, FieldsCallback); + return ParseStructDeclaration(DS, FieldsCallback, LateFieldAttrs); } // Parse leading attributes. @@ -4914,10 +4939,12 @@ void Parser::ParseStructDeclaration( } // If attributes exist after the declarator, parse them. - MaybeParseGNUAttributes(DeclaratorInfo.D); + MaybeParseGNUAttributes(DeclaratorInfo.D, LateFieldAttrs); // We're done with this declarator; invoke the callback. - FieldsCallback(DeclaratorInfo); + Decl *Field = FieldsCallback(DeclaratorInfo); + if (Field) + DistributeCLateParsedAttrs(Field, LateFieldAttrs); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. @@ -4928,6 +4955,73 @@ void Parser::ParseStructDeclaration( } } +// TODO: All callers of this function should be moved to +// `Parser::ParseLexedAttributeList`. +void Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope, + ParsedAttributes *OutAttrs) { + assert(LAs.parseSoon() && + "Attribute list should be marked for immediate parsing."); + for (auto *LA : LAs) { + ParseLexedCAttribute(*LA, EnterScope, OutAttrs); + delete LA; + } + LAs.clear(); +} + +/// Finish parsing an attribute for which parsing was delayed. +/// This will be called at the end of parsing a class declaration +/// for each LateParsedAttribute. We consume the saved tokens and +/// create an attribute with the arguments filled in. We add this +/// to the Attribute list for the decl. +void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope, + ParsedAttributes *OutAttrs) { + // Create a fake EOF so that attribute parsing won't go off the end of the + // attribute. + Token AttrEnd; + AttrEnd.startToken(); + AttrEnd.setKind(tok::eof); + AttrEnd.setLocation(Tok.getLocation()); + AttrEnd.setEofData(LA.Toks.data()); + LA.Toks.push_back(AttrEnd); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LA.Toks.push_back(Tok); + PP.EnterTokenStream(LA.Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/true); + // Drop the current token and bring the first cached one. It's the same token + // as when we entered this function. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + // TODO: Use `EnterScope` + (void)EnterScope; + + ParsedAttributes Attrs(AttrFactory); + + assert(LA.Decls.size() <= 1 && + "late field attribute expects to have at most one declaration."); + + // Dispatch based on the attribute and parse it + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr, + SourceLocation(), ParsedAttr::Form::GNU(), nullptr); + + for (auto *D : LA.Decls) + Actions.ActOnFinishDelayedAttribute(getCurScope(), D, Attrs); + + // Due to a parsing error, we either went over the cached tokens or + // there are still cached tokens left, so we skip the leftover tokens. + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + + // Consume the fake EOF token if it's there + if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData()) + ConsumeAnyToken(); + + if (OutAttrs) { + OutAttrs->takeAllFrom(Attrs); + } +} + /// ParseStructUnionBody /// struct-contents: /// struct-declaration-list @@ -4951,6 +5045,11 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); + // `LateAttrParseExperimentalExtOnly=true` requests that only attributes + // marked with `LateAttrParseExperimentalExt` are late parsed. + LateParsedAttrList LateFieldAttrs(/*PSoon=*/true, + /*LateAttrParseExperimentalExtOnly=*/true); + // While we still have something to read, read the declarations in the struct. while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -5001,18 +5100,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } if (!Tok.is(tok::at)) { - auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { + auto CFieldCallback = [&](ParsingFieldDeclarator &FD) -> Decl * { // Install the declarator into the current TagDecl. Decl *Field = Actions.ActOnField(getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FD.complete(Field); + return Field; }; // Parse all the comma separated declarators. ParsingDeclSpec DS(*this); - ParseStructDeclaration(DS, CFieldCallback); + ParseStructDeclaration(DS, CFieldCallback, &LateFieldAttrs); } else { // Handle @defs ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { @@ -5053,7 +5153,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(attrs, &LateFieldAttrs); + + // Late parse field attributes if necessary. + ParseLexedCAttributeList(LateFieldAttrs, /*EnterScope=*/false); SmallVector FieldDecls(TagDecl->fields()); @@ -5287,9 +5390,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // - Sema::TagUseKind TUK; + TagUseKind TUK; if (AllowEnumSpecifier == AllowDefiningTypeSpec::No) - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; else if (Tok.is(tok::l_brace)) { if (DS.isFriendSpecified()) { Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) @@ -5301,9 +5404,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ScopedEnumKWLoc = SourceLocation(); IsScopedUsingClassTag = false; BaseType = TypeResult(); - TUK = Sema::TUK_Friend; + TUK = TagUseKind::Friend; } else { - TUK = Sema::TUK_Definition; + TUK = TagUseKind::Definition; } } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || @@ -5312,7 +5415,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // An opaque-enum-declaration is required to be standalone (no preceding or // following tokens in the declaration). Sema enforces this separately by // diagnosing anything else in the DeclSpec. - TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; + TUK = DS.isFriendSpecified() ? TagUseKind::Friend : TagUseKind::Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); @@ -5320,21 +5423,21 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Tok.setKind(tok::semi); } } else { - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; } bool IsElaboratedTypeSpecifier = - TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend; + TUK == TagUseKind::Reference || TUK == TagUseKind::Friend; // If this is an elaborated type specifier nested in a larger declaration, // and we delayed diagnostics before, just merge them into the current pool. - if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) { + if (TUK == TagUseKind::Reference && shouldDelayDiagsInTag) { diagsFromTag.redelay(); } MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && - TUK != Sema::TUK_Reference) { + TUK != TagUseKind::Reference) { if (!getLangOpts().CPlusPlus11 || !SS.isSet()) { // Skip the rest of this declarator, up until the comma or semicolon. Diag(Tok, diag::err_enum_template); @@ -5355,7 +5458,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SS.setTemplateParamLists(TParams); } - if (!Name && TUK != Sema::TUK_Definition) { + if (!Name && TUK != TagUseKind::Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); DS.SetTypeSpecError(); @@ -5388,7 +5491,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, stripTypeAttributesOffDeclSpec(attrs, DS, TUK); SkipBodyInfo SkipBody; - if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) && + if (!Name && TUK == TagUseKind::Definition && Tok.is(tok::l_brace) && NextToken().is(tok::identifier)) SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(), NextToken().getIdentifierInfo(), @@ -5409,7 +5512,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, OffsetOfState, &SkipBody).get(); if (SkipBody.ShouldSkip) { - assert(TUK == Sema::TUK_Definition && "can only skip a definition"); + assert(TUK == TagUseKind::Definition && "can only skip a definition"); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); @@ -5451,7 +5554,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!TagDecl) { // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. - if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + if (Tok.is(tok::l_brace) && TUK != TagUseKind::Reference) { ConsumeBrace(); SkipUntil(tok::r_brace, StopAtSemi); } @@ -5460,7 +5563,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (Tok.is(tok::l_brace) && TUK == Sema::TUK_Definition) { + if (Tok.is(tok::l_brace) && TUK == TagUseKind::Definition) { Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl; ParseEnumBody(StartLoc, D); if (SkipBody.CheckSameAsPrevious && diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5eaec2b621e6fd6e51061dc41f701d731a4afcd1..9a4a777f575b2533eaf2c9a1dd3b05ace2f7f757 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1961,11 +1961,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, MaybeParseCXX11Attributes(Attributes); const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); - Sema::TagUseKind TUK; + TagUseKind TUK; if (isDefiningTypeSpecifierContext(DSC, getLangOpts().CPlusPlus) == AllowDefiningTypeSpec::No || (getLangOpts().OpenMP && OpenMPDirectiveParsing)) - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; else if (Tok.is(tok::l_brace) || (DSC != DeclSpecContext::DSC_association && getLangOpts().CPlusPlus && Tok.is(tok::colon)) || @@ -1980,10 +1980,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Skip everything up to the semicolon, so that this looks like a proper // friend class (or template thereof) declaration. SkipUntil(tok::semi, StopBeforeMatch); - TUK = Sema::TUK_Friend; + TUK = TagUseKind::Friend; } else { // Okay, this is a class definition. - TUK = Sema::TUK_Definition; + TUK = TagUseKind::Definition; } } else if (isClassCompatibleKeyword() && (NextToken().is(tok::l_square) || @@ -2024,15 +2024,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } if (Tok.isOneOf(tok::l_brace, tok::colon)) - TUK = Sema::TUK_Definition; + TUK = TagUseKind::Definition; else - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; PA.Revert(); } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { - TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; + TUK = DS.isFriendSpecified() ? TagUseKind::Friend : TagUseKind::Declaration; if (Tok.isNot(tok::semi)) { const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy(); // A semicolon was missing after this declaration. Diagnose and recover. @@ -2042,11 +2042,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.setKind(tok::semi); } } else - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; // Forbid misplaced attributes. In cases of a reference, we pass attributes // to caller to handle. - if (TUK != Sema::TUK_Reference) { + if (TUK != TagUseKind::Reference) { // If this is not a reference, then the only possible // valid place for C++11 attributes to appear here // is between class-key and class-name. If there are @@ -2072,7 +2072,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || - TUK != Sema::TUK_Definition)) { + TUK != TagUseKind::Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { // We have a declaration or reference to an anonymous class. Diag(StartLoc, diag::err_anon_type_definition) @@ -2082,7 +2082,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If we are parsing a definition and stop at a base-clause, continue on // until the semicolon. Continuing from the comma will just trick us into // thinking we are seeing a variable declaration. - if (TUK == Sema::TUK_Definition && Tok.is(tok::colon)) + if (TUK == TagUseKind::Definition && Tok.is(tok::colon)) SkipUntil(tok::semi, StopBeforeMatch); else SkipUntil(tok::comma, StopAtSemi); @@ -2103,7 +2103,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TemplateId->isInvalid()) { // Can't build the declaration. } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Sema::TUK_Declaration) { + TUK == TagUseKind::Declaration) { // This is an explicit instantiation of a class template. ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, diag::err_keyword_not_allowed, @@ -2119,8 +2119,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // they have template headers, in which case they're ill-formed // (FIXME: "template friend class A::B;"). // We diagnose this error in ActOnClassTemplateSpecialization. - } else if (TUK == Sema::TUK_Reference || - (TUK == Sema::TUK_Friend && + } else if (TUK == TagUseKind::Reference || + (TUK == TagUseKind::Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, diag::err_keyword_not_allowed, @@ -2145,10 +2145,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // It this is friend declaration however, since it cannot have a // template header, it is most likely that the user meant to // remove the 'template' keyword. - assert((TUK == Sema::TUK_Definition || TUK == Sema::TUK_Friend) && + assert((TUK == TagUseKind::Definition || TUK == TagUseKind::Friend) && "Expected a definition here"); - if (TUK == Sema::TUK_Friend) { + if (TUK == TagUseKind::Friend) { Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation); TemplateParams = nullptr; } else { @@ -2179,7 +2179,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, &SkipBody); } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Sema::TUK_Declaration) { + TUK == TagUseKind::Declaration) { // Explicit instantiation of a member of a class template // specialization, e.g., // @@ -2190,7 +2190,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagOrTempResult = Actions.ActOnExplicitInstantiation( getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, Name, NameLoc, attrs); - } else if (TUK == Sema::TUK_Friend && + } else if (TUK == TagUseKind::Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, diag::err_keyword_not_allowed, @@ -2202,12 +2202,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : nullptr, TemplateParams ? TemplateParams->size() : 0)); } else { - if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) + if (TUK != TagUseKind::Declaration && TUK != TagUseKind::Definition) ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, diag::err_keyword_not_allowed, /* DiagnoseEmptyAttrs=*/true); - if (TUK == Sema::TUK_Definition && + if (TUK == TagUseKind::Definition && TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // If the declarator-id is not a template-id, issue a diagnostic and // recover by ignoring the 'template' keyword. @@ -2222,7 +2222,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // reference. For example, we don't need the template parameters here: // template class A *makeA(T t); MultiTemplateParamsArg TParams; - if (TUK != Sema::TUK_Reference && TemplateParams) + if (TUK != TagUseKind::Reference && TemplateParams) TParams = MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); @@ -2241,7 +2241,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If ActOnTag said the type was dependent, try again with the // less common call. if (IsDependent) { - assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend); + assert(TUK == TagUseKind::Reference || TUK == TagUseKind::Friend); TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK, SS, Name, StartLoc, NameLoc); } @@ -2252,13 +2252,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // just merge them into the current pool. if (shouldDelayDiagsInTag) { diagsFromTag.done(); - if (TUK == Sema::TUK_Reference && + if (TUK == TagUseKind::Reference && TemplateInfo.Kind == ParsedTemplateInfo::Template) diagsFromTag.redelay(); } // If there is a body, parse it and inform the actions module. - if (TUK == Sema::TUK_Definition) { + if (TUK == TagUseKind::Definition) { assert(Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || isClassCompatibleKeyword()); @@ -2316,7 +2316,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // // After a type-specifier, we don't expect a semicolon. This only happens in // C, since definitions are not permitted in this context in C++. - if (TUK == Sema::TUK_Definition && + if (TUK == TagUseKind::Definition && (getLangOpts().CPlusPlus || !isTypeSpecifier(DSC)) && (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { if (Tok.isNot(tok::semi)) { @@ -4560,7 +4560,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, IdentifierInfo *AttrName, SourceLocation AttrNameLoc, - SourceLocation *EndLoc) { + SourceLocation *EndLoc, + ParsedAttr::Form Form) { assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list"); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -4603,7 +4604,7 @@ bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, auto RParen = Tok.getLocation(); T.consumeClose(); Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr, - SourceLocation(), &Assumption, 1, ParsedAttr::Form::CXX11()); + SourceLocation(), &Assumption, 1, Form); if (EndLoc) *EndLoc = RParen; @@ -4683,7 +4684,7 @@ bool Parser::ParseCXX11AttributeArgs( ScopeName, ScopeLoc, Form); // So does C++23's assume() attribute. else if (!ScopeName && AttrName->isStr("assume")) { - if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc)) + if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form)) return true; NumArgs = 1; } else diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e149b1a0fb5efc94ce61ef7802af9332c28c7b17..1d364f77a81464aba85c47cac9cf9bb6f8b20bd2 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" @@ -1580,7 +1581,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( TrailingReturnTypeLoc, &DS), std::move(Attributes), DeclEndLoc); - Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); + // We have called ActOnLambdaClosureQualifiers for parentheses-less cases + // above. + if (HasParentheses) + Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); if (HasParentheses && Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); @@ -3026,13 +3030,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SS, ObjectType, ObjectHadErrors, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, EnteringContext, Result, TemplateSpecified); - else if (TemplateSpecified && - Actions.ActOnTemplateName( - getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, - EnteringContext, Template, - /*AllowInjectedClassName*/ true) == TNK_Non_template) - return true; + if (TemplateSpecified) { + TemplateNameKind TNK = + Actions.ActOnTemplateName(getCurScope(), SS, *TemplateKWLoc, Result, + ObjectType, EnteringContext, Template, + /*AllowInjectedClassName=*/true); + if (TNK == TNK_Non_template) + return true; + + // C++2c [tem.names]p6 + // A name prefixed by the keyword template shall be followed by a template + // argument list or refer to a class template or an alias template. + if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name || + TNK == TNK_Var_template) && + !Tok.is(tok::less)) + Diag(IdLoc, diag::missing_template_arg_list_after_template_kw); + } return false; } @@ -4000,6 +4014,9 @@ ExprResult Parser::ParseArrayTypeTrait() { ExprResult DimExpr = ParseExpression(); T.consumeClose(); + if (DimExpr.isInvalid()) + return ExprError(); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), T.getCloseLocation()); } diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 89f4acbd25e4936066853cefb2cc511eae306552..6a2088a73c55b91c14a9aa7fd3e968d54a675430 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -780,16 +780,16 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, } bool addedToDeclSpec = false; - auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) { + auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) -> Decl * { if (FD.D.getIdentifier() == nullptr) { Diag(AtLoc, diag::err_objc_property_requires_field_name) << FD.D.getSourceRange(); - return; + return nullptr; } if (FD.BitfieldSize) { Diag(AtLoc, diag::err_objc_property_bitfield) << FD.D.getSourceRange(); - return; + return nullptr; } // Map a nullability property attribute to a context-sensitive keyword @@ -818,6 +818,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, MethodImplKind); FD.complete(Property); + return Property; }; // Parse all the comma separated declarators. @@ -2013,7 +2014,7 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl, continue; } - auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) { + auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) -> Decl * { assert(getObjCDeclContext() == interfaceDecl && "Ivar should have interfaceDecl as its decl context"); // Install the declarator into the interface decl. @@ -2024,6 +2025,7 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl, if (Field) AllIvarDecls.push_back(Field); FD.complete(Field); + return Field; }; // Parse all the comma separated declarators. diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index e9c60f76165b68077c9e9737a306e83514cefc25..0261e8ea3c9b76ab4e081ba08de3dc0bd4a1d3e3 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -571,6 +571,7 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) { case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Loop: return true; } llvm_unreachable("Unhandled directive->assoc stmt"); @@ -1131,6 +1132,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( // clause, as we are a 'single token' clause. ParsedClause.setEndLoc(ClauseLoc); } + } else { + ParsedClause.setEndLoc(ClauseLoc); } return OpenACCSuccess( Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause)); @@ -1347,11 +1350,13 @@ void Parser::ParseOpenACCCacheVarList() { ParseOpenACCVarList(OpenACCClauseKind::Invalid); } -Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { - SourceLocation StartLoc = getCurToken().getLocation(); +Parser::OpenACCDirectiveParseInfo +Parser::ParseOpenACCDirective() { + SourceLocation StartLoc = ConsumeAnnotationToken(); + SourceLocation DirLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); - getActions().OpenACC().ActOnConstruct(DirKind, StartLoc); + getActions().OpenACC().ActOnConstruct(DirKind, DirLoc); // Once we've parsed the construct/directive name, some have additional // specifiers that need to be taken care of. Atomic has an 'atomic-clause' @@ -1390,7 +1395,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { break; case OpenACCDirectiveKind::Wait: // OpenACC has an optional paren-wrapped 'wait-argument'. - if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed) + if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed) T.skipToEnd(); else T.consumeClose(); @@ -1404,7 +1409,8 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present, plus set up return value. - OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, SourceLocation{}, + OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc, + SourceLocation{}, ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && @@ -1421,7 +1427,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); ParsingOpenACCDirectiveRAII DirScope(*this); - ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); @@ -1438,7 +1443,6 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); ParsingOpenACCDirectiveRAII DirScope(*this); - ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind, @@ -1446,16 +1450,17 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { return StmtError(); StmtResult AssocStmt; - + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(), + DirInfo.DirKind); if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) { ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false); ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind)); - AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(DirInfo.DirKind, - ParseStatement()); + AssocStmt = getActions().OpenACC().ActOnAssociatedStmt( + DirInfo.StartLoc, DirInfo.DirKind, ParseStatement()); } return getActions().OpenACC().ActOnEndStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, DirInfo.Clauses, - AssocStmt); + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc, + DirInfo.Clauses, AssocStmt); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index e959dd6378f46b21da506c67633b55d7c128b9fb..50a872fedebf7cfc7da91cf179de0067ff1795d5 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -21,13 +21,13 @@ #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaOpenMP.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/UniqueVector.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" +#include #include using namespace clang; @@ -1646,19 +1646,17 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind, SmallVectorImpl &Clauses, SourceLocation Loc) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - DKind, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2114,19 +2112,17 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /*AllowScopeSpecifier=*/true)) { SmallVector Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2150,9 +2146,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_requires: { SourceLocation StartLoc = ConsumeToken(); SmallVector Clauses; - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; if (Tok.is(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); @@ -2163,11 +2157,11 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_requires, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2510,9 +2504,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector Clauses; - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ReadDirectiveWithinMetadirective @@ -2717,19 +2709,17 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( /*AllowScopeSpecifier=*/false)) { SmallVector Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2926,13 +2916,11 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( ImplicitClauseAllowed = false; Actions.OpenMP().StartOpenMPClause(CKind); HasImplicitClause = false; - OMPClause *Clause = ParseOpenMPClause( - DKind, CKind, !FirstClauses[unsigned(CKind)].getInt()); - FirstClauses[unsigned(CKind)].setInt(true); - if (Clause) { - FirstClauses[unsigned(CKind)].setPointer(Clause); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); + SeenClauses[unsigned(CKind)] = true; + if (Clause) Clauses.push_back(Clause); - } // Skip ',' if any. if (Tok.is(tok::comma)) @@ -2948,7 +2936,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( // If the depend or doacross clause is specified, the ordered construct // is a stand-alone directive. for (auto CK : {OMPC_depend, OMPC_doacross}) { - if (FirstClauses[unsigned(CK)].getInt()) { + if (SeenClauses[unsigned(CK)]) { if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Loc, diag::err_omp_immediate_directive) @@ -2960,7 +2948,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } } - if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) { + if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { Diag(Loc, diag::err_omp_required_clause) << getOpenMPDirectiveName(OMPD_tile) << "sizes"; } @@ -3758,7 +3746,7 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: if (!PA.checkExactlyNumArgs(Actions, 2)) continue; - if (auto *A = Actions.CreateAMDGPUFlatWorkGroupSizeAttr( + if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr( PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1))) Attrs.push_back(A); continue; @@ -3766,7 +3754,7 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { if (!PA.checkAtLeastNumArgs(Actions, 1) || !PA.checkAtMostNumArgs(Actions, 2)) continue; - if (auto *A = Actions.CreateAMDGPUWavesPerEUAttr( + if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr( PA, PA.getArgAsExpr(0), PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr)) Attrs.push_back(A); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 643fdac287d18eac5ac4e6d24753ad2d425710a1..cc6f18b5b319f95acfbbc9a8e7fd2a63abee8f10 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -23,6 +23,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaCodeCompletion.h" +#include "clang/Sema/SemaRISCV.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSwitch.h" #include @@ -4154,7 +4155,7 @@ void PragmaRISCVHandler::HandlePragma(Preprocessor &PP, } if (II->isStr("vector")) - Actions.DeclareRISCVVBuiltins = true; + Actions.RISCV().DeclareRVVBuiltins = true; else if (II->isStr("sifive_vector")) - Actions.DeclareRISCVSiFiveVectorBuiltins = true; + Actions.RISCV().DeclareSiFiveVectorBuiltins = true; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index b0af04451166ca20febe0cf6c1e2b78ef0ce5750..c25203243ee49bccf6f78f68eb5a02f242a0722e 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -239,7 +239,15 @@ Retry: auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) && llvm::all_of(GNUAttrs, IsStmtAttr); - if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || + // In C, the grammar production for statement (C23 6.8.1p1) does not allow + // for declarations, which is different from C++ (C++23 [stmt.pre]p1). So + // in C++, we always allow a declaration, but in C we need to check whether + // we're in a statement context that allows declarations. e.g., in C, the + // following is invalid: if (1) int x; + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != + ParsedStmtContext()) && + ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 6b7742cae2db9badba93c3b39645bc5cc080c198..f152d243d39a5bda058551ce8ba9322a2fcb622b 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -26,10 +26,14 @@ add_clang_library(clangSema Scope.cpp ScopeInfo.cpp Sema.cpp + SemaAMDGPU.cpp + SemaARM.cpp + SemaAVR.cpp SemaAccess.cpp SemaAttr.cpp SemaAPINotes.cpp SemaAvailability.cpp + SemaBPF.cpp SemaBase.cpp SemaCXXScopeSpec.cpp SemaCast.cpp @@ -50,27 +54,39 @@ add_clang_library(clangSema SemaExprObjC.cpp SemaFixItUtils.cpp SemaHLSL.cpp + SemaHexagon.cpp SemaInit.cpp SemaLambda.cpp SemaLookup.cpp + SemaLoongArch.cpp + SemaM68k.cpp + SemaMIPS.cpp + SemaMSP430.cpp SemaModule.cpp + SemaNVPTX.cpp SemaObjC.cpp SemaObjCProperty.cpp SemaOpenACC.cpp + SemaOpenCL.cpp SemaOpenMP.cpp SemaOverload.cpp + SemaPPC.cpp SemaPseudoObject.cpp SemaRISCV.cpp SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp SemaSYCL.cpp + SemaSwift.cpp + SemaSystemZ.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaTemplateVariadic.cpp SemaType.cpp + SemaWasm.cpp + SemaX86.cpp TypeLocBuilder.cpp DEPENDS diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index bb283c54b3d29c13f2de137a5e42d3fe3e282a63..a2b29a7bdf505cd1eaac9e8f8a388252f7e88f0a 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -308,17 +308,18 @@ struct BuiltinTypeDeclBuilder { return *this; } - TemplateParameterListBuilder addTemplateArgumentList(); - BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef Names); + TemplateParameterListBuilder addTemplateArgumentList(Sema &S); + BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S, + ArrayRef Names); }; struct TemplateParameterListBuilder { BuiltinTypeDeclBuilder &Builder; - ASTContext &AST; + Sema &S; llvm::SmallVector Params; - TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) - : Builder(RB), AST(RB.Record->getASTContext()) {} + TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB) + : Builder(RB), S(S) {} ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } @@ -328,12 +329,15 @@ struct TemplateParameterListBuilder { return *this; unsigned Position = static_cast(Params.size()); auto *Decl = TemplateTypeParmDecl::Create( - AST, Builder.Record->getDeclContext(), SourceLocation(), + S.Context, Builder.Record->getDeclContext(), SourceLocation(), SourceLocation(), /* TemplateDepth */ 0, Position, - &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false, + &S.Context.Idents.get(Name, tok::TokenKind::identifier), + /* Typename */ false, /* ParameterPack */ false); if (!DefaultValue.isNull()) - Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue)); + Decl->setDefaultArgument( + S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(), + SourceLocation())); Params.emplace_back(Decl); return *this; @@ -342,11 +346,11 @@ struct TemplateParameterListBuilder { BuiltinTypeDeclBuilder &finalizeTemplateArgs() { if (Params.empty()) return Builder; - auto *ParamList = - TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), - Params, SourceLocation(), nullptr); + auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(), + SourceLocation(), Params, + SourceLocation(), nullptr); Builder.Template = ClassTemplateDecl::Create( - AST, Builder.Record->getDeclContext(), SourceLocation(), + S.Context, Builder.Record->getDeclContext(), SourceLocation(), DeclarationName(Builder.Record->getIdentifier()), ParamList, Builder.Record); Builder.Record->setDescribedClassTemplate(Builder.Template); @@ -359,20 +363,22 @@ struct TemplateParameterListBuilder { Params.clear(); QualType T = Builder.Template->getInjectedClassNameSpecialization(); - T = AST.getInjectedClassNameType(Builder.Record, T); + T = S.Context.getInjectedClassNameType(Builder.Record, T); return Builder; } }; } // namespace -TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() { - return TemplateParameterListBuilder(*this); +TemplateParameterListBuilder +BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) { + return TemplateParameterListBuilder(S, *this); } BuiltinTypeDeclBuilder & -BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef Names) { - TemplateParameterListBuilder Builder = this->addTemplateArgumentList(); +BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S, + ArrayRef Names) { + TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S); for (StringRef Name : Names) Builder.addTypeParameter(Name); return Builder.finalizeTemplateArgs(); @@ -426,7 +432,9 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() { auto *TypeParam = TemplateTypeParmDecl::Create( AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0, &AST.Idents.get("element", tok::TokenKind::identifier), false, false); - TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy)); + TypeParam->setDefaultArgument( + AST, SemaPtr->getTrivialTemplateArgumentLoc( + TemplateArgument(AST.FloatTy), QualType(), SourceLocation())); TemplateParams.emplace_back(TypeParam); @@ -434,10 +442,12 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() { AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1, &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy, false, AST.getTrivialTypeSourceInfo(AST.IntTy)); - Expr *LiteralExpr = - IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4), - AST.IntTy, SourceLocation()); - SizeParam->setDefaultArgument(LiteralExpr); + llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4); + TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy, + /*IsDefaulted=*/true); + SizeParam->setDefaultArgument( + AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy, + SourceLocation(), SizeParam)); TemplateParams.emplace_back(SizeParam); auto *ParamList = @@ -492,7 +502,7 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { CXXRecordDecl *Decl; Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams(*SemaPtr, {"element_type"}) .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, @@ -503,7 +513,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams(*SemaPtr, {"element_type"}) .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2c5774da3f666c2df731e9a9281c01c2f5694f5f..a612dcd4b4d0313fee8a98d27b9a20fcaab36989 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -41,16 +41,33 @@ #include "clang/Sema/RISCVIntrinsicManager.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaAMDGPU.h" +#include "clang/Sema/SemaARM.h" +#include "clang/Sema/SemaAVR.h" +#include "clang/Sema/SemaBPF.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/SemaHLSL.h" +#include "clang/Sema/SemaHexagon.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaLoongArch.h" +#include "clang/Sema/SemaM68k.h" +#include "clang/Sema/SemaMIPS.h" +#include "clang/Sema/SemaMSP430.h" +#include "clang/Sema/SemaNVPTX.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenACC.h" +#include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaPseudoObject.h" +#include "clang/Sema/SemaRISCV.h" #include "clang/Sema/SemaSYCL.h" +#include "clang/Sema/SemaSwift.h" +#include "clang/Sema/SemaSystemZ.h" +#include "clang/Sema/SemaWasm.h" +#include "clang/Sema/SemaX86.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" #include "clang/Sema/TypoCorrection.h" @@ -204,15 +221,32 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr), Ident_super(nullptr), + AMDGPUPtr(std::make_unique(*this)), + ARMPtr(std::make_unique(*this)), + AVRPtr(std::make_unique(*this)), + BPFPtr(std::make_unique(*this)), CodeCompletionPtr( std::make_unique(*this, CodeCompleter)), CUDAPtr(std::make_unique(*this)), HLSLPtr(std::make_unique(*this)), + HexagonPtr(std::make_unique(*this)), + LoongArchPtr(std::make_unique(*this)), + M68kPtr(std::make_unique(*this)), + MIPSPtr(std::make_unique(*this)), + MSP430Ptr(std::make_unique(*this)), + NVPTXPtr(std::make_unique(*this)), ObjCPtr(std::make_unique(*this)), OpenACCPtr(std::make_unique(*this)), + OpenCLPtr(std::make_unique(*this)), OpenMPPtr(std::make_unique(*this)), + PPCPtr(std::make_unique(*this)), PseudoObjectPtr(std::make_unique(*this)), + RISCVPtr(std::make_unique(*this)), SYCLPtr(std::make_unique(*this)), + SwiftPtr(std::make_unique(*this)), + SystemZPtr(std::make_unique(*this)), + WasmPtr(std::make_unique(*this)), + X86Ptr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()), @@ -1353,6 +1387,10 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteExternalDeclaration(D); } + if (LangOpts.HLSL) + HLSL().DiagnoseAvailabilityViolations( + getASTContext().getTranslationUnitDecl()); + // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the @@ -2051,7 +2089,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType() && FD) { llvm::StringMap CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); - checkRVVTypeSupport(Ty, Loc, D, CallerFeatureMap); + RISCV().checkRVVTypeSupport(Ty, Loc, D, CallerFeatureMap); } // Don't allow SVE types in functions without a SVE target. diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c446cc1d042a4a60b0c68ec5212228fb49c180e8 --- /dev/null +++ b/clang/lib/Sema/SemaAMDGPU.cpp @@ -0,0 +1,311 @@ +//===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to AMDGPU. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaAMDGPU.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/Sema.h" +#include "llvm/Support/AtomicOrdering.h" +#include + +namespace clang { + +SemaAMDGPU::SemaAMDGPU(Sema &S) : SemaBase(S) {} + +bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + // position of memory order and scope arguments in the builtin + unsigned OrderIndex, ScopeIndex; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_global_load_lds: { + constexpr const int SizeIdx = 2; + llvm::APSInt Size; + Expr *ArgExpr = TheCall->getArg(SizeIdx); + ExprResult R = SemaRef.VerifyIntegerConstantExpression(ArgExpr, &Size); + if (R.isInvalid()) + return true; + switch (Size.getSExtValue()) { + case 1: + case 2: + case 4: + return false; + default: + Diag(ArgExpr->getExprLoc(), + diag::err_amdgcn_global_load_lds_size_invalid_value) + << ArgExpr->getSourceRange(); + Diag(ArgExpr->getExprLoc(), + diag::note_amdgcn_global_load_lds_size_valid_value) + << ArgExpr->getSourceRange(); + return true; + } + } + case AMDGPU::BI__builtin_amdgcn_get_fpenv: + case AMDGPU::BI__builtin_amdgcn_set_fpenv: + return false; + case AMDGPU::BI__builtin_amdgcn_atomic_inc32: + case AMDGPU::BI__builtin_amdgcn_atomic_inc64: + case AMDGPU::BI__builtin_amdgcn_atomic_dec32: + case AMDGPU::BI__builtin_amdgcn_atomic_dec64: + OrderIndex = 2; + ScopeIndex = 3; + break; + case AMDGPU::BI__builtin_amdgcn_fence: + OrderIndex = 0; + ScopeIndex = 1; + break; + default: + return false; + } + + ExprResult Arg = TheCall->getArg(OrderIndex); + auto ArgExpr = Arg.get(); + Expr::EvalResult ArgResult; + + if (!ArgExpr->EvaluateAsInt(ArgResult, getASTContext())) + return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int) + << ArgExpr->getType(); + auto Ord = ArgResult.Val.getInt().getZExtValue(); + + // Check validity of memory ordering as per C11 / C++11's memody model. + // Only fence needs check. Atomic dec/inc allow all memory orders. + if (!llvm::isValidAtomicOrderingCABI(Ord)) + return Diag(ArgExpr->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << 0 << ArgExpr->getSourceRange(); + switch (static_cast(Ord)) { + case llvm::AtomicOrderingCABI::relaxed: + case llvm::AtomicOrderingCABI::consume: + if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence) + return Diag(ArgExpr->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << 0 << ArgExpr->getSourceRange(); + break; + case llvm::AtomicOrderingCABI::acquire: + case llvm::AtomicOrderingCABI::release: + case llvm::AtomicOrderingCABI::acq_rel: + case llvm::AtomicOrderingCABI::seq_cst: + break; + } + + Arg = TheCall->getArg(ScopeIndex); + ArgExpr = Arg.get(); + Expr::EvalResult ArgResult1; + // Check that sync scope is a constant literal + if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, getASTContext())) + return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal) + << ArgExpr->getType(); + + return false; +} + +static bool +checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, + const AMDGPUFlatWorkGroupSizeAttr &Attr) { + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || MaxExpr->isValueDependent()) + return false; + + uint32_t Min = 0; + if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0)) + return true; + + uint32_t Max = 0; + if (!S.checkUInt32Argument(Attr, MaxExpr, Max, 1)) + return true; + + if (Min == 0 && Max != 0) { + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; + } + if (Min > Max) { + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; + } + + return false; +} + +AMDGPUFlatWorkGroupSizeAttr * +SemaAMDGPU::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + ASTContext &Context = getASTContext(); + AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr); + + if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef, MinExpr, MaxExpr, TmpAttr)) + return nullptr; + return ::new (Context) + AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr); +} + +void SemaAMDGPU::addAMDGPUFlatWorkGroupSizeAttr(Decl *D, + const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr)) + D->addAttr(Attr); +} + +void SemaAMDGPU::handleAMDGPUFlatWorkGroupSizeAttr(Decl *D, + const ParsedAttr &AL) { + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = AL.getArgAsExpr(1); + + addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr); +} + +static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, + Expr *MaxExpr, + const AMDGPUWavesPerEUAttr &Attr) { + if (S.DiagnoseUnexpandedParameterPack(MinExpr) || + (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr))) + return true; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent())) + return false; + + uint32_t Min = 0; + if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0)) + return true; + + uint32_t Max = 0; + if (MaxExpr && !S.checkUInt32Argument(Attr, MaxExpr, Max, 1)) + return true; + + if (Min == 0 && Max != 0) { + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; + } + if (Max != 0 && Min > Max) { + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; + } + + return false; +} + +AMDGPUWavesPerEUAttr * +SemaAMDGPU::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + ASTContext &Context = getASTContext(); + AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr); + + if (checkAMDGPUWavesPerEUArguments(SemaRef, MinExpr, MaxExpr, TmpAttr)) + return nullptr; + + return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr); +} + +void SemaAMDGPU::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr)) + D->addAttr(Attr); +} + +void SemaAMDGPU::handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.checkAtLeastNumArgs(SemaRef, 1) || !AL.checkAtMostNumArgs(SemaRef, 2)) + return; + + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; + + addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr); +} + +void SemaAMDGPU::handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL) { + uint32_t NumSGPR = 0; + Expr *NumSGPRExpr = AL.getArgAsExpr(0); + if (!SemaRef.checkUInt32Argument(AL, NumSGPRExpr, NumSGPR)) + return; + + D->addAttr(::new (getASTContext()) + AMDGPUNumSGPRAttr(getASTContext(), AL, NumSGPR)); +} + +void SemaAMDGPU::handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL) { + uint32_t NumVGPR = 0; + Expr *NumVGPRExpr = AL.getArgAsExpr(0); + if (!SemaRef.checkUInt32Argument(AL, NumVGPRExpr, NumVGPR)) + return; + + D->addAttr(::new (getASTContext()) + AMDGPUNumVGPRAttr(getASTContext(), AL, NumVGPR)); +} + +static bool +checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr, + Expr *ZExpr, + const AMDGPUMaxNumWorkGroupsAttr &Attr) { + if (S.DiagnoseUnexpandedParameterPack(XExpr) || + (YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) || + (ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr))) + return true; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) || + (ZExpr && ZExpr->isValueDependent())) + return false; + + uint32_t NumWG = 0; + Expr *Exprs[3] = {XExpr, YExpr, ZExpr}; + for (int i = 0; i < 3; i++) { + if (Exprs[i]) { + if (!S.checkUInt32Argument(Attr, Exprs[i], NumWG, i, + /*StrictlyUnsigned=*/true)) + return true; + if (NumWG == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) + << &Attr << Exprs[i]->getSourceRange(); + return true; + } + } + } + + return false; +} + +AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr( + const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) { + ASTContext &Context = getASTContext(); + AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr); + + if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr, + TmpAttr)) + return nullptr; + + return ::new (Context) + AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr); +} + +void SemaAMDGPU::addAMDGPUMaxNumWorkGroupsAttr(Decl *D, + const AttributeCommonInfo &CI, + Expr *XExpr, Expr *YExpr, + Expr *ZExpr) { + if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr)) + D->addAttr(Attr); +} + +void SemaAMDGPU::handleAMDGPUMaxNumWorkGroupsAttr(Decl *D, + const ParsedAttr &AL) { + Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; + Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr; + addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index c80b08e361cfa60255b57a0d49cc34601f1ae48d..bc1628f5b71636b92b1a6167e0386ecaeaf57d1f 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -17,6 +17,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaSwift.h" using namespace clang; @@ -303,8 +304,8 @@ static void ProcessAPINotes(Sema &S, Decl *D, SourceLocation(), nullptr, nullptr, nullptr, ParsedAttr::Form::GNU()); - if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA, - /*IsAsync=*/false)) + if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA, + /*IsAsync=*/false)) return nullptr; return new (S.Context) diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02e68dbdb2e9dc26b4d7779fada6e23f75bf9cf6 --- /dev/null +++ b/clang/lib/Sema/SemaARM.cpp @@ -0,0 +1,1284 @@ +//===------ SemaARM.cpp ---------- ARM target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to ARM. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaARM.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaARM::SemaARM(Sema &S) : SemaBase(S) {} + +/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, + CallExpr *TheCall) { + ASTContext &Context = getASTContext(); + + if (BuiltinID == AArch64::BI__builtin_arm_irg) { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1); + if (SecArg.isInvalid()) + return true; + QualType SecArgType = SecArg.get()->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_addg) { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + + // Second arg must be an constant in range [0,15] + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + if (BuiltinID == AArch64::BI__builtin_arm_gmi) { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + + QualType SecArgType = Arg1->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + TheCall->setType(Context.IntTy); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg) { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + if (BuiltinID == AArch64::BI__builtin_arm_ldg) + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_subp) { + Expr *ArgA = TheCall->getArg(0); + Expr *ArgB = TheCall->getArg(1); + + ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA); + ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(ArgB); + + if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) + return true; + + QualType ArgTypeA = ArgExprA.get()->getType(); + QualType ArgTypeB = ArgExprB.get()->getType(); + + auto isNull = [&](Expr *E) -> bool { + return E->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull); + }; + + // argument should be either a pointer or null + if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "first" << ArgTypeA << ArgA->getSourceRange(); + + if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "second" << ArgTypeB << ArgB->getSourceRange(); + + // Ensure Pointee types are compatible + if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && + ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { + QualType pointeeA = ArgTypeA->getPointeeType(); + QualType pointeeB = ArgTypeB->getPointeeType(); + if (!Context.typesAreCompatible( + Context.getCanonicalType(pointeeA).getUnqualifiedType(), + Context.getCanonicalType(pointeeB).getUnqualifiedType())) { + return Diag(TheCall->getBeginLoc(), + diag::err_typecheck_sub_ptr_compatible) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange() + << ArgB->getSourceRange(); + } + } + + // at least one argument should be pointer type + if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); + + if (isNull(ArgA)) // adopt type of the other pointer + ArgExprA = + SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); + + if (isNull(ArgB)) + ArgExprB = + SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); + + TheCall->setArg(0, ArgExprA.get()); + TheCall->setArg(1, ArgExprB.get()); + TheCall->setType(Context.LongLongTy); + return false; + } + assert(false && "Unhandled ARM MTE intrinsic"); + return true; +} + +/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr +/// TheCall is an ARM/AArch64 special register string literal. +bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName) { + bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64 || + BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp; + bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128 || + BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp; + assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check if the argument is a string literal. + if (!isa(Arg->IgnoreParenImpCasts())) + return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the type of special register given. + StringRef Reg = cast(Arg->IgnoreParenImpCasts())->getString(); + SmallVector Fields; + Reg.split(Fields, ":"); + + if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) + return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + + // If the string is the name of a register then we cannot check that it is + // valid here but if the string is of one the forms described in ACLE then we + // can check that the supplied fields are integers and within the valid + // ranges. + if (Fields.size() > 1) { + bool FiveFields = Fields.size() == 5; + + bool ValidString = true; + if (IsARMBuiltin) { + ValidString &= Fields[0].starts_with_insensitive("cp") || + Fields[0].starts_with_insensitive("p"); + if (ValidString) + Fields[0] = Fields[0].drop_front( + Fields[0].starts_with_insensitive("cp") ? 2 : 1); + + ValidString &= Fields[2].starts_with_insensitive("c"); + if (ValidString) + Fields[2] = Fields[2].drop_front(1); + + if (FiveFields) { + ValidString &= Fields[3].starts_with_insensitive("c"); + if (ValidString) + Fields[3] = Fields[3].drop_front(1); + } + } + + SmallVector Ranges; + if (FiveFields) + Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); + else + Ranges.append({15, 7, 15}); + + for (unsigned i = 0; i < Fields.size(); ++i) { + int IntField; + ValidString &= !Fields[i].getAsInteger(10, IntField); + ValidString &= (IntField >= 0 && IntField <= Ranges[i]); + } + + if (!ValidString) + return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + } else if (IsAArch64Builtin && Fields.size() == 1) { + // This code validates writes to PSTATE registers. + + // Not a write. + if (TheCall->getNumArgs() != 2) + return false; + + // The 128-bit system register accesses do not touch PSTATE. + if (BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128) + return false; + + // These are the named PSTATE accesses using "MSR (immediate)" instructions, + // along with the upper limit on the immediates allowed. + auto MaxLimit = llvm::StringSwitch>(Reg) + .CaseLower("spsel", 15) + .CaseLower("daifclr", 15) + .CaseLower("daifset", 15) + .CaseLower("pan", 15) + .CaseLower("uao", 15) + .CaseLower("dit", 15) + .CaseLower("ssbs", 15) + .CaseLower("tco", 15) + .CaseLower("allint", 1) + .CaseLower("pm", 1) + .Default(std::nullopt); + + // If this is not a named PSTATE, just continue without validating, as this + // will be lowered to an "MSR (register)" instruction directly + if (!MaxLimit) + return false; + + // Here we only allow constants in the range for that pstate, as required by + // the ACLE. + // + // While clang also accepts the names of system registers in its ACLE + // intrinsics, we prevent this with the PSTATE names used in MSR (immediate) + // as the value written via a register is different to the value used as an + // immediate to have the same effect. e.g., for the instruction `msr tco, + // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but + // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO. + // + // If a programmer wants to codegen the MSR (register) form of `msr tco, + // xN`, they can still do so by specifying the register using five + // colon-separated numbers in a string. + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); + } + + return false; +} + +// Get the valid immediate range for the specified NEON type code. +static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { + NeonTypeFlags Type(t); + int IsQuad = ForceQuad ? true : Type.isQuad(); + switch (Type.getEltType()) { + case NeonTypeFlags::Int8: + case NeonTypeFlags::Poly8: + return shift ? 7 : (8 << IsQuad) - 1; + case NeonTypeFlags::Int16: + case NeonTypeFlags::Poly16: + return shift ? 15 : (4 << IsQuad) - 1; + case NeonTypeFlags::Int32: + return shift ? 31 : (2 << IsQuad) - 1; + case NeonTypeFlags::Int64: + case NeonTypeFlags::Poly64: + return shift ? 63 : (1 << IsQuad) - 1; + case NeonTypeFlags::Poly128: + return shift ? 127 : (1 << IsQuad) - 1; + case NeonTypeFlags::Float16: + assert(!shift && "cannot shift float types!"); + return (4 << IsQuad) - 1; + case NeonTypeFlags::Float32: + assert(!shift && "cannot shift float types!"); + return (2 << IsQuad) - 1; + case NeonTypeFlags::Float64: + assert(!shift && "cannot shift float types!"); + return (1 << IsQuad) - 1; + case NeonTypeFlags::BFloat16: + assert(!shift && "cannot shift float types!"); + return (4 << IsQuad) - 1; + } + llvm_unreachable("Invalid NeonTypeFlag!"); +} + +/// getNeonEltType - Return the QualType corresponding to the elements of +/// the vector type specified by the NeonTypeFlags. This is used to check +/// the pointer arguments for Neon load/store intrinsics. +static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, + bool IsPolyUnsigned, bool IsInt64Long) { + switch (Flags.getEltType()) { + case NeonTypeFlags::Int8: + return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy; + case NeonTypeFlags::Int16: + return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy; + case NeonTypeFlags::Int32: + return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy; + case NeonTypeFlags::Int64: + if (IsInt64Long) + return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy; + else + return Flags.isUnsigned() ? Context.UnsignedLongLongTy + : Context.LongLongTy; + case NeonTypeFlags::Poly8: + return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy; + case NeonTypeFlags::Poly16: + return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; + case NeonTypeFlags::Poly64: + if (IsInt64Long) + return Context.UnsignedLongTy; + else + return Context.UnsignedLongLongTy; + case NeonTypeFlags::Poly128: + break; + case NeonTypeFlags::Float16: + return Context.HalfTy; + case NeonTypeFlags::Float32: + return Context.FloatTy; + case NeonTypeFlags::Float64: + return Context.DoubleTy; + case NeonTypeFlags::BFloat16: + return Context.BFloat16Ty; + } + llvm_unreachable("Invalid NeonTypeFlag!"); +} + +enum ArmSMEState : unsigned { + ArmNoState = 0, + + ArmInZA = 0b01, + ArmOutZA = 0b10, + ArmInOutZA = 0b11, + ArmZAMask = 0b11, + + ArmInZT0 = 0b01 << 2, + ArmOutZT0 = 0b10 << 2, + ArmInOutZT0 = 0b11 << 2, + ArmZT0Mask = 0b11 << 2 +}; + +bool SemaARM::ParseSVEImmChecks( + CallExpr *TheCall, SmallVector, 3> &ImmChecks) { + // Perform all the immediate checks for this builtin call. + bool HasError = false; + for (auto &I : ImmChecks) { + int ArgNum, CheckTy, ElementSizeInBits; + std::tie(ArgNum, CheckTy, ElementSizeInBits) = I; + + typedef bool (*OptionSetCheckFnTy)(int64_t Value); + + // Function that checks whether the operand (ArgNum) is an immediate + // that is one of the predefined values. + auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm, + int ErrDiag) -> bool { + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + llvm::APSInt Imm; + if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Imm)) + return true; + + if (!CheckImm(Imm.getSExtValue())) + return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange(); + return false; + }; + + switch ((SVETypeFlags::ImmCheckType)CheckTy) { + case SVETypeFlags::ImmCheck0_31: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_13: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) + HasError = true; + break; + case SVETypeFlags::ImmCheck1_16: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_7: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) + HasError = true; + break; + case SVETypeFlags::ImmCheck1_1: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheck1_3: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) + HasError = true; + break; + case SVETypeFlags::ImmCheck1_7: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) + HasError = true; + break; + case SVETypeFlags::ImmCheckExtract: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, + (2048 / ElementSizeInBits) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftRight: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, + ElementSizeInBits)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftRightNarrow: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, + ElementSizeInBits / 2)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftLeft: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, + ElementSizeInBits - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndex: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (1 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndexCompRotate: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (2 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndexDot: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (4 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckComplexRot90_270: + if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; }, + diag::err_rotation_argument_to_cadd)) + HasError = true; + break; + case SVETypeFlags::ImmCheckComplexRotAll90: + if (CheckImmediateInSet( + [](int64_t V) { + return V == 0 || V == 90 || V == 180 || V == 270; + }, + diag::err_rotation_argument_to_cmla)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_1: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_2: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_3: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_0: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_15: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_255: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) + HasError = true; + break; + case SVETypeFlags::ImmCheck2_4_Mul2: + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || + SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) + HasError = true; + break; + } + } + + return HasError; +} + +SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) { + if (FD->hasAttr()) + return SemaARM::ArmStreaming; + if (const Type *Ty = FD->getType().getTypePtrOrNull()) { + if (const auto *FPT = Ty->getAs()) { + if (FPT->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMEnabledMask) + return SemaARM::ArmStreaming; + if (FPT->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) + return SemaARM::ArmStreamingCompatible; + } + } + return SemaARM::ArmNonStreaming; +} + +static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall, + const FunctionDecl *FD, + SemaARM::ArmStreamingType BuiltinType) { + SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD); + if (BuiltinType == SemaARM::ArmStreamingOrSVE2p1) { + // Check intrinsics that are available in [sve2p1 or sme/sme2]. + llvm::StringMap CallerFeatureMap; + S.Context.getFunctionFeatureMap(CallerFeatureMap, FD); + if (Builtin::evaluateRequiredTargetFeatures("sve2p1", CallerFeatureMap)) + BuiltinType = SemaARM::ArmStreamingCompatible; + else + BuiltinType = SemaARM::ArmStreaming; + } + + if (FnType == SemaARM::ArmStreaming && + BuiltinType == SemaARM::ArmNonStreaming) + S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) + << TheCall->getSourceRange() << "streaming"; + else if (FnType == SemaARM::ArmNonStreaming && BuiltinType == SemaARM::ArmStreaming) + S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) + << TheCall->getSourceRange() << "non-streaming"; + else if (FnType == SemaARM::ArmStreamingCompatible && + BuiltinType != SemaARM::ArmStreamingCompatible) + S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) + << TheCall->getSourceRange() << "streaming compatible"; +} + +static bool hasArmZAState(const FunctionDecl *FD) { + const auto *T = FD->getType()->getAs(); + return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) != + FunctionType::ARM_None) || + (FD->hasAttr() && FD->getAttr()->isNewZA()); +} + +static bool hasArmZT0State(const FunctionDecl *FD) { + const auto *T = FD->getType()->getAs(); + return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) != + FunctionType::ARM_None) || + (FD->hasAttr() && FD->getAttr()->isNewZT0()); +} + +static ArmSMEState getSMEState(unsigned BuiltinID) { + switch (BuiltinID) { + default: + return ArmNoState; +#define GET_SME_BUILTIN_GET_STATE +#include "clang/Basic/arm_sme_builtins_za_state.inc" +#undef GET_SME_BUILTIN_GET_STATE + } +} + +bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { + std::optional BuiltinType; + + switch (BuiltinID) { +#define GET_SME_STREAMING_ATTRS +#include "clang/Basic/arm_sme_streaming_attrs.inc" +#undef GET_SME_STREAMING_ATTRS + } + + if (BuiltinType) + checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType); + + if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD)) + Diag(TheCall->getBeginLoc(), + diag::warn_attribute_arm_za_builtin_no_za_state) + << TheCall->getSourceRange(); + + if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD)) + Diag(TheCall->getBeginLoc(), + diag::warn_attribute_arm_zt0_builtin_no_zt0_state) + << TheCall->getSourceRange(); + } + + // Range check SME intrinsics that take immediate values. + SmallVector, 3> ImmChecks; + + switch (BuiltinID) { + default: + return false; +#define GET_SME_IMMEDIATE_CHECK +#include "clang/Basic/arm_sme_sema_rangechecks.inc" +#undef GET_SME_IMMEDIATE_CHECK + } + + return ParseSVEImmChecks(TheCall, ImmChecks); +} + +bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { + std::optional BuiltinType; + + switch (BuiltinID) { +#define GET_SVE_STREAMING_ATTRS +#include "clang/Basic/arm_sve_streaming_attrs.inc" +#undef GET_SVE_STREAMING_ATTRS + } + if (BuiltinType) + checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType); + } + // Range check SVE intrinsics that take immediate values. + SmallVector, 3> ImmChecks; + + switch (BuiltinID) { + default: + return false; +#define GET_SVE_IMMEDIATE_CHECK +#include "clang/Basic/arm_sve_sema_rangechecks.inc" +#undef GET_SVE_IMMEDIATE_CHECK + } + + return ParseSVEImmChecks(TheCall, ImmChecks); +} + +bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { + + switch (BuiltinID) { + default: + break; +#define GET_NEON_BUILTINS +#define TARGET_BUILTIN(id, ...) case NEON::BI##id: +#define BUILTIN(id, ...) case NEON::BI##id: +#include "clang/Basic/arm_neon.inc" + checkArmStreamingBuiltin(SemaRef, TheCall, FD, ArmNonStreaming); + break; +#undef TARGET_BUILTIN +#undef BUILTIN +#undef GET_NEON_BUILTINS + } + } + + llvm::APSInt Result; + uint64_t mask = 0; + unsigned TV = 0; + int PtrArgNum = -1; + bool HasConstPtr = false; + switch (BuiltinID) { +#define GET_NEON_OVERLOAD_CHECK +#include "clang/Basic/arm_fp16.inc" +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_OVERLOAD_CHECK + } + + // For NEON intrinsics which are overloaded on vector element type, validate + // the immediate which specifies which variant to emit. + unsigned ImmArg = TheCall->getNumArgs() - 1; + if (mask) { + if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result)) + return true; + + TV = Result.getLimitedValue(64); + if ((TV > 63) || (mask & (1ULL << TV)) == 0) + return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code) + << TheCall->getArg(ImmArg)->getSourceRange(); + } + + if (PtrArgNum >= 0) { + // Check that pointer arguments have the specified type. + Expr *Arg = TheCall->getArg(PtrArgNum); + if (ImplicitCastExpr *ICE = dyn_cast(Arg)) + Arg = ICE->getSubExpr(); + ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg); + QualType RHSTy = RHS.get()->getType(); + + llvm::Triple::ArchType Arch = TI.getTriple().getArch(); + bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || + Arch == llvm::Triple::aarch64_32 || + Arch == llvm::Triple::aarch64_be; + bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong; + QualType EltTy = getNeonEltType(NeonTypeFlags(TV), getASTContext(), + IsPolyUnsigned, IsInt64Long); + if (HasConstPtr) + EltTy = EltTy.withConst(); + QualType LHSTy = getASTContext().getPointerType(EltTy); + Sema::AssignConvertType ConvTy; + ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS); + if (RHS.isInvalid()) + return true; + if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy, + RHSTy, RHS.get(), Sema::AA_Assigning)) + return true; + } + + // For NEON intrinsics which take an immediate value as part of the + // instruction, range check them here. + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: + return false; +#define GET_NEON_IMMEDIATE_CHECK +#include "clang/Basic/arm_fp16.inc" +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_IMMEDIATE_CHECK + } + + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l); +} + +bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; +#include "clang/Basic/arm_mve_builtin_sema.inc" + } +} + +bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + bool Err = false; + switch (BuiltinID) { + default: + return false; +#include "clang/Basic/arm_cde_builtin_sema.inc" + } + + if (Err) + return true; + + return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true); +} + +bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI, + const Expr *CoprocArg, + bool WantCDE) { + ASTContext &Context = getASTContext(); + if (SemaRef.isConstantEvaluatedContext()) + return false; + + // We can't check the value of a dependent argument. + if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent()) + return false; + + llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context); + int64_t CoprocNo = CoprocNoAP.getExtValue(); + assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative"); + + uint32_t CDECoprocMask = TI.getARMCDECoprocMask(); + bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo)); + + if (IsCDECoproc != WantCDE) + return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc) + << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange(); + + return false; +} + +bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, + CallExpr *TheCall, + unsigned MaxWidth) { + assert((BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldaex || + BuiltinID == ARM::BI__builtin_arm_strex || + BuiltinID == ARM::BI__builtin_arm_stlex || + BuiltinID == AArch64::BI__builtin_arm_ldrex || + BuiltinID == AArch64::BI__builtin_arm_ldaex || + BuiltinID == AArch64::BI__builtin_arm_strex || + BuiltinID == AArch64::BI__builtin_arm_stlex) && + "unexpected ARM builtin"); + bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldaex || + BuiltinID == AArch64::BI__builtin_arm_ldrex || + BuiltinID == AArch64::BI__builtin_arm_ldaex; + + ASTContext &Context = getASTContext(); + DeclRefExpr *DRE = + cast(TheCall->getCallee()->IgnoreParenCasts()); + + // Ensure that we have the proper number of arguments. + if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2)) + return true; + + // Inspect the pointer argument of the atomic builtin. This should always be + // a pointer type, whose element is an integral scalar or pointer type. + // Because it is a pointer type, we don't have to worry about any implicit + // casts here. + Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1); + ExprResult PointerArgRes = + SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg); + if (PointerArgRes.isInvalid()) + return true; + PointerArg = PointerArgRes.get(); + + const PointerType *pointerType = PointerArg->getType()->getAs(); + if (!pointerType) { + Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) + << PointerArg->getType() << 0 << PointerArg->getSourceRange(); + return true; + } + + // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next + // task is to insert the appropriate casts into the AST. First work out just + // what the appropriate type is. + QualType ValType = pointerType->getPointeeType(); + QualType AddrType = ValType.getUnqualifiedType().withVolatile(); + if (IsLdrex) + AddrType.addConst(); + + // Issue a warning if the cast is dodgy. + CastKind CastNeeded = CK_NoOp; + if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { + CastNeeded = CK_BitCast; + Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) + << PointerArg->getType() << Context.getPointerType(AddrType) + << Sema::AA_Passing << PointerArg->getSourceRange(); + } + + // Finally, do the cast and replace the argument with the corrected version. + AddrType = Context.getPointerType(AddrType); + PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded); + if (PointerArgRes.isInvalid()) + return true; + PointerArg = PointerArgRes.get(); + + TheCall->setArg(IsLdrex ? 0 : 1, PointerArg); + + // In general, we allow ints, floats and pointers to be loaded and stored. + if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && + !ValType->isBlockPointerType() && !ValType->isFloatingType()) { + Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr) + << PointerArg->getType() << 0 << PointerArg->getSourceRange(); + return true; + } + + // But ARM doesn't have instructions to deal with 128-bit versions. + if (Context.getTypeSize(ValType) > MaxWidth) { + assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); + Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size) + << PointerArg->getType() << PointerArg->getSourceRange(); + return true; + } + + switch (ValType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + // okay + break; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Autoreleasing: + Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) + << ValType << PointerArg->getSourceRange(); + return true; + } + + if (IsLdrex) { + TheCall->setType(ValType); + return false; + } + + // Initialize the argument to be stored. + ExprResult ValArg = TheCall->getArg(0); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, ValType, /*consume*/ false); + ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg); + if (ValArg.isInvalid()) + return true; + TheCall->setArg(0, ValArg.get()); + + // __builtin_arm_strex always returns an int. It's marked as such in the .def, + // but the custom checker bypasses all default analysis. + TheCall->setType(Context.IntTy); + return false; +} + +bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + if (BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldaex || + BuiltinID == ARM::BI__builtin_arm_strex || + BuiltinID == ARM::BI__builtin_arm_stlex) { + return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); + } + + if (BuiltinID == ARM::BI__builtin_arm_prefetch) { + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1); + } + + if (BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64) + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); + + if (BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp) + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + + if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) + return true; + if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) + return true; + if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall)) + return true; + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + // FIXME: VFP Intrinsics should error if VFP not present. + switch (BuiltinID) { + default: + return false; + case ARM::BI__builtin_arm_ssat: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32); + case ARM::BI__builtin_arm_usat: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case ARM::BI__builtin_arm_ssat16: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16); + case ARM::BI__builtin_arm_usat16: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case ARM::BI__builtin_arm_vcvtr_f: + case ARM::BI__builtin_arm_vcvtr_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); + case ARM::BI__builtin_arm_dmb: + case ARM::BI__builtin_arm_dsb: + case ARM::BI__builtin_arm_isb: + case ARM::BI__builtin_arm_dbg: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15); + case ARM::BI__builtin_arm_cdp: + case ARM::BI__builtin_arm_cdp2: + case ARM::BI__builtin_arm_mcr: + case ARM::BI__builtin_arm_mcr2: + case ARM::BI__builtin_arm_mrc: + case ARM::BI__builtin_arm_mrc2: + case ARM::BI__builtin_arm_mcrr: + case ARM::BI__builtin_arm_mcrr2: + case ARM::BI__builtin_arm_mrrc: + case ARM::BI__builtin_arm_mrrc2: + case ARM::BI__builtin_arm_ldc: + case ARM::BI__builtin_arm_ldcl: + case ARM::BI__builtin_arm_ldc2: + case ARM::BI__builtin_arm_ldc2l: + case ARM::BI__builtin_arm_stc: + case ARM::BI__builtin_arm_stcl: + case ARM::BI__builtin_arm_stc2: + case ARM::BI__builtin_arm_stc2l: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) || + CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), + /*WantCDE*/ false); + } +} + +bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + if (BuiltinID == AArch64::BI__builtin_arm_ldrex || + BuiltinID == AArch64::BI__builtin_arm_ldaex || + BuiltinID == AArch64::BI__builtin_arm_strex || + BuiltinID == AArch64::BI__builtin_arm_stlex) { + return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); + } + + if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) || + SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1); + } + + if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128) + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + + // Memory Tagging Extensions (MTE) Intrinsics + if (BuiltinID == AArch64::BI__builtin_arm_irg || + BuiltinID == AArch64::BI__builtin_arm_addg || + BuiltinID == AArch64::BI__builtin_arm_gmi || + BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg || + BuiltinID == AArch64::BI__builtin_arm_subp) { + return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + } + + if (BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp) + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + + // Only check the valid encoding range. Any constant in this range would be + // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw + // an exception for incorrect registers. This matches MSVC behavior. + if (BuiltinID == AArch64::BI_ReadStatusReg || + BuiltinID == AArch64::BI_WriteStatusReg) + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); + + if (BuiltinID == AArch64::BI__getReg) + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31); + + if (BuiltinID == AArch64::BI__break) + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); + + if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) + return true; + + if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall)) + return true; + + if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall)) + return true; + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: return false; + case AArch64::BI__builtin_arm_dmb: + case AArch64::BI__builtin_arm_dsb: + case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; + case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; + } + + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l); +} + +namespace { +struct IntrinToName { + uint32_t Id; + int32_t FullName; + int32_t ShortName; +}; +} // unnamed namespace + +static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, + ArrayRef Map, + const char *IntrinNames) { + AliasName.consume_front("__arm_"); + const IntrinToName *It = + llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { + return L.Id < Id; + }); + if (It == Map.end() || It->Id != BuiltinID) + return false; + StringRef FullName(&IntrinNames[It->FullName]); + if (AliasName == FullName) + return true; + if (It->ShortName == -1) + return false; + StringRef ShortName(&IntrinNames[It->ShortName]); + return AliasName == ShortName; +} + +bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) { +#include "clang/Basic/arm_mve_builtin_aliases.inc" + // The included file defines: + // - ArrayRef Map + // - const char IntrinNames[] + return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); +} + +bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) { +#include "clang/Basic/arm_cde_builtin_aliases.inc" + return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); +} + +bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) { + if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) + BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID); + return BuiltinID >= AArch64::FirstSVEBuiltin && + BuiltinID <= AArch64::LastSVEBuiltin; +} + +bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) { + if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) + BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID); + return BuiltinID >= AArch64::FirstSMEBuiltin && + BuiltinID <= AArch64::LastSMEBuiltin; +} + +void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) { + ASTContext &Context = getASTContext(); + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; + unsigned BuiltinID = Ident->getBuiltinID(); + StringRef AliasName = cast(D)->getIdentifier()->getName(); + + bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64(); + if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) && + !SmeAliasValid(BuiltinID, AliasName)) || + (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) && + !CdeAliasValid(BuiltinID, AliasName))) { + Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); + return; + } + + D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident)); +} + +static bool checkNewAttrMutualExclusion( + Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT, + FunctionType::ArmStateValue CurrentState, StringRef StateName) { + auto CheckForIncompatibleAttr = + [&](FunctionType::ArmStateValue IncompatibleState, + StringRef IncompatibleStateName) { + if (CurrentState == IncompatibleState) { + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << (std::string("'__arm_new(\"") + StateName.str() + "\")'") + << (std::string("'") + IncompatibleStateName.str() + "(\"" + + StateName.str() + "\")'") + << true; + AL.setInvalid(); + } + }; + + CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in"); + CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out"); + CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout"); + CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves"); + return AL.isInvalid(); +} + +void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.getNumArgs()) { + Diag(AL.getLoc(), diag::err_missing_arm_state) << AL; + AL.setInvalid(); + return; + } + + std::vector NewState; + if (const auto *ExistingAttr = D->getAttr()) { + for (StringRef S : ExistingAttr->newArgs()) + NewState.push_back(S); + } + + bool HasZA = false; + bool HasZT0 = false; + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef StateName; + SourceLocation LiteralLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc)) + return; + + if (StateName == "za") + HasZA = true; + else if (StateName == "zt0") + HasZT0 = true; + else { + Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName; + AL.setInvalid(); + return; + } + + if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates. + NewState.push_back(StateName); + } + + if (auto *FPT = dyn_cast(D->getFunctionType())) { + FunctionType::ArmStateValue ZAState = + FunctionType::getArmZAState(FPT->getAArch64SMEAttributes()); + if (HasZA && ZAState != FunctionType::ARM_None && + checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za")) + return; + FunctionType::ArmStateValue ZT0State = + FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes()); + if (HasZT0 && ZT0State != FunctionType::ARM_None && + checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0")) + return; + } + + D->dropAttr(); + D->addAttr(::new (getASTContext()) ArmNewAttr( + getASTContext(), AL, NewState.data(), NewState.size())); +} + +void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) { + if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) { + Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL; + return; + } + + const auto *FD = cast(D); + if (!FD->isExternallyVisible()) { + Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static); + return; + } + + D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL)); +} + +void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + // Check the attribute arguments. + if (AL.getNumArgs() > 1) { + Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (AL.getNumArgs() == 0) + Str = ""; + else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + ARMInterruptAttr::InterruptType Kind; + if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Str << ArgLoc; + return; + } + + D->addAttr(::new (getASTContext()) + ARMInterruptAttr(getASTContext(), AL, Kind)); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaAVR.cpp b/clang/lib/Sema/SemaAVR.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47368780b620379a582b34b49e553e0d477dce9d --- /dev/null +++ b/clang/lib/Sema/SemaAVR.cpp @@ -0,0 +1,49 @@ +//===------ SemaAVR.cpp ---------- AVR target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to AVR. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaAVR.h" +#include "clang/AST/DeclBase.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" + +namespace clang { +SemaAVR::SemaAVR(Sema &S) : SemaBase(S) {} + +void SemaAVR::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + if (!isFuncOrMethodForAttrSubject(D)) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + if (!AL.checkExactlyNumArgs(SemaRef, 0)) + return; + + handleSimpleAttribute(*this, D, AL); +} + +void SemaAVR::handleSignalAttr(Decl *D, const ParsedAttr &AL) { + if (!isFuncOrMethodForAttrSubject(D)) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + if (!AL.checkExactlyNumArgs(SemaRef, 0)) + return; + + handleSimpleAttribute(*this, D, AL); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 663b6f35b869d5a434a876272d03ebe457f45003..330cd602297d46d7914180b4789e6a33887c6a79 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -15,6 +15,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DelayedDiagnostic.h" @@ -228,8 +229,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); break; case llvm::Triple::ShaderModel: - // Always enable availability diagnostics for shader models. - return true; + // FIXME: This will be updated when HLSL strict diagnostic mode + // is implemented (issue #90096) + return false; default: // New targets should always warn about availability. return Triple.getVendor() == llvm::Triple::Apple; @@ -409,10 +411,11 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, std::string PlatformName( AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( - TI.getTriple().getEnvironmentName())); + TI.getTriple().getEnvironment())); llvm::StringRef AttrEnvironment = AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName( - AA->getEnvironment()->getName()) + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) : ""; bool UseEnvironment = (!AttrEnvironment.empty() && !TargetEnvironment.empty()); @@ -438,6 +441,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, << S.Context.getTargetInfo().getPlatformMinVersion().getAsString() << UseEnvironment << AttrEnvironment << TargetEnvironment; + // Do not offer to silence the warning or fixits for HLSL + if (S.getLangOpts().HLSL) + return; + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { if (const auto *TD = dyn_cast(Enclosing)) if (TD->getDeclName().isEmpty()) { @@ -839,10 +846,11 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( std::string PlatformName( AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( - TI.getTriple().getEnvironmentName())); + TI.getTriple().getEnvironment())); llvm::StringRef AttrEnvironment = AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName( - AA->getEnvironment()->getName()) + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) : ""; bool UseEnvironment = (!AttrEnvironment.empty() && !TargetEnvironment.empty()); @@ -865,6 +873,10 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() << UseEnvironment << AttrEnvironment << TargetEnvironment; + // Do not offer to silence the warning or fixits for HLSL + if (SemaRef.getLangOpts().HLSL) + return; + auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) << Range << D @@ -987,11 +999,6 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { Stmt *Body = nullptr; if (auto *FD = D->getAsFunction()) { - // FIXME: We only examine the pattern decl for availability violations now, - // but we should also examine instantiated templates. - if (FD->isTemplateInstantiation()) - return; - Body = FD->getBody(); if (auto *CD = dyn_cast(FD)) diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c00084d62dd9ae860db1f891f38b622a9b5c00d --- /dev/null +++ b/clang/lib/Sema/SemaBPF.cpp @@ -0,0 +1,194 @@ +//===------ SemaBPF.cpp ---------- BPF target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to BPF. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaBPF.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/APSInt.h" +#include + +namespace clang { + +SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {} + +static bool isValidPreserveFieldInfoArg(Expr *Arg) { + if (Arg->getType()->getAsPlaceholderType()) + return false; + + // The first argument needs to be a record field access. + // If it is an array element access, we delay decision + // to BPF backend to check whether the access is a + // field access or not. + return (Arg->IgnoreParens()->getObjectKind() == OK_BitField || + isa(Arg->IgnoreParens()) || + isa(Arg->IgnoreParens())); +} + +static bool isValidPreserveTypeInfoArg(Expr *Arg) { + QualType ArgType = Arg->getType(); + if (ArgType->getAsPlaceholderType()) + return false; + + // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type + // format: + // 1. __builtin_preserve_type_info(*( *)0, flag); + // 2. var; + // __builtin_preserve_type_info(var, flag); + if (!isa(Arg->IgnoreParens()) && + !isa(Arg->IgnoreParens())) + return false; + + // Typedef type. + if (ArgType->getAs()) + return true; + + // Record type or Enum type. + const Type *Ty = ArgType->getUnqualifiedDesugaredType(); + if (const auto *RT = Ty->getAs()) { + if (!RT->getDecl()->getDeclName().isEmpty()) + return true; + } else if (const auto *ET = Ty->getAs()) { + if (!ET->getDecl()->getDeclName().isEmpty()) + return true; + } + + return false; +} + +static bool isValidPreserveEnumValueArg(Expr *Arg) { + QualType ArgType = Arg->getType(); + if (ArgType->getAsPlaceholderType()) + return false; + + // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type + // format: + // __builtin_preserve_enum_value(*( *), + // flag); + const auto *UO = dyn_cast(Arg->IgnoreParens()); + if (!UO) + return false; + + const auto *CE = dyn_cast(UO->getSubExpr()); + if (!CE) + return false; + if (CE->getCastKind() != CK_IntegralToPointer && + CE->getCastKind() != CK_NullToPointer) + return false; + + // The integer must be from an EnumConstantDecl. + const auto *DR = dyn_cast(CE->getSubExpr()); + if (!DR) + return false; + + const EnumConstantDecl *Enumerator = + dyn_cast(DR->getDecl()); + if (!Enumerator) + return false; + + // The type must be EnumType. + const Type *Ty = ArgType->getUnqualifiedDesugaredType(); + const auto *ET = Ty->getAs(); + if (!ET) + return false; + + // The enum value must be supported. + return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator); +} + +bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + assert((BuiltinID == BPF::BI__builtin_preserve_field_info || + BuiltinID == BPF::BI__builtin_btf_type_id || + BuiltinID == BPF::BI__builtin_preserve_type_info || + BuiltinID == BPF::BI__builtin_preserve_enum_value) && + "unexpected BPF builtin"); + ASTContext &Context = getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + // The second argument needs to be a constant int + Expr *Arg = TheCall->getArg(1); + std::optional Value = Arg->getIntegerConstantExpr(Context); + diag::kind kind; + if (!Value) { + if (BuiltinID == BPF::BI__builtin_preserve_field_info) + kind = diag::err_preserve_field_info_not_const; + else if (BuiltinID == BPF::BI__builtin_btf_type_id) + kind = diag::err_btf_type_id_not_const; + else if (BuiltinID == BPF::BI__builtin_preserve_type_info) + kind = diag::err_preserve_type_info_not_const; + else + kind = diag::err_preserve_enum_value_not_const; + Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange(); + return true; + } + + // The first argument + Arg = TheCall->getArg(0); + bool InvalidArg = false; + bool ReturnUnsignedInt = true; + if (BuiltinID == BPF::BI__builtin_preserve_field_info) { + if (!isValidPreserveFieldInfoArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_field_info_not_field; + } + } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) { + if (!isValidPreserveTypeInfoArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_type_info_invalid; + } + } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) { + if (!isValidPreserveEnumValueArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_enum_value_invalid; + } + ReturnUnsignedInt = false; + } else if (BuiltinID == BPF::BI__builtin_btf_type_id) { + ReturnUnsignedInt = false; + } + + if (InvalidArg) { + Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange(); + return true; + } + + if (ReturnUnsignedInt) + TheCall->setType(Context.UnsignedIntTy); + else + TheCall->setType(Context.UnsignedLongTy); + return false; +} + +void SemaBPF::handlePreserveAIRecord(RecordDecl *RD) { + // Add preserve_access_index attribute to all fields and inner records. + for (auto *D : RD->decls()) { + if (D->hasAttr()) + continue; + + D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext())); + if (auto *Rec = dyn_cast(D)) + handlePreserveAIRecord(Rec); + } +} + +void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) { + auto *Rec = cast(D); + handlePreserveAIRecord(Rec); + Rec->addAttr(::new (getASTContext()) + BPFPreserveAccessIndexAttr(getASTContext(), AL)); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaBase.cpp b/clang/lib/Sema/SemaBase.cpp index 0442fb2929e3c647f94a4f3a927fe8af960d05d4..a2f12d622e8ccc270b16dd9b992000dd0aeac172 100644 --- a/clang/lib/Sema/SemaBase.cpp +++ b/clang/lib/Sema/SemaBase.cpp @@ -29,6 +29,10 @@ SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() { SemaRef.EmitCurrentDiagnostic(DiagID); } +PartialDiagnostic SemaBase::PDiag(unsigned DiagID) { + return PartialDiagnostic(DiagID, SemaRef.Context.getDiagAllocator()); +} + const SemaBase::SemaDiagnosticBuilder & operator<<(const SemaBase::SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 483ec7e36eaed729af4fd6533fe199b362c8b8a1..f03dcf05411dfc871dd25c9afa8398fea4a45adb 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaRISCV.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include @@ -1092,9 +1093,10 @@ static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType, return true; // Allow integral type mismatch if their size are equal. - if (SrcType->isIntegralType(Context) && DestType->isIntegralType(Context)) - if (Context.getTypeInfoInChars(SrcType).Width == - Context.getTypeInfoInChars(DestType).Width) + if ((SrcType->isIntegralType(Context) || SrcType->isEnumeralType()) && + (DestType->isIntegralType(Context) || DestType->isEnumeralType())) + if (Context.getTypeSizeInChars(SrcType) == + Context.getTypeSizeInChars(DestType)) return true; return Context.hasSameUnqualifiedType(SrcType, DestType); @@ -2391,7 +2393,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } // Allow bitcasting between SVE VLATs and VLSTs, and vice-versa. - if (Self.isValidRVVBitcast(SrcType, DestType)) { + if (Self.RISCV().isValidRVVBitcast(SrcType, DestType)) { Kind = CK_BitCast; return TC_Success; } @@ -3002,7 +3004,7 @@ void CastOperation::CheckCStyleCast() { // Allow bitcasting between compatible RVV vector types. if ((SrcType->isVectorType() || DestType->isVectorType()) && - Self.isValidRVVBitcast(SrcType, DestType)) { + Self.RISCV().isValidRVVBitcast(SrcType, DestType)) { Kind = CK_BitCast; return; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index f2dc8e9dd005068601511d95d9129df6ca3e19d8..300af02239779f57b309351eece6a9cdcbfee796 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -61,8 +61,20 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaAMDGPU.h" +#include "clang/Sema/SemaARM.h" +#include "clang/Sema/SemaBPF.h" +#include "clang/Sema/SemaHexagon.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaLoongArch.h" +#include "clang/Sema/SemaMIPS.h" +#include "clang/Sema/SemaNVPTX.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaPPC.h" +#include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSystemZ.h" +#include "clang/Sema/SemaWasm.h" +#include "clang/Sema/SemaX86.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" @@ -120,13 +132,12 @@ static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A, /// Checks that a call expression's argument count is at least the desired /// number. This is useful when doing custom type-checking on a variadic /// function. Returns true on error. -static bool checkArgCountAtLeast(Sema &S, CallExpr *Call, - unsigned MinArgCount) { +bool Sema::checkArgCountAtLeast(CallExpr *Call, unsigned MinArgCount) { unsigned ArgCount = Call->getNumArgs(); if (ArgCount >= MinArgCount) return false; - return S.Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args) + return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args) << 0 /*function call*/ << MinArgCount << ArgCount << /*is non object*/ 0 << Call->getSourceRange(); } @@ -134,12 +145,11 @@ static bool checkArgCountAtLeast(Sema &S, CallExpr *Call, /// Checks that a call expression's argument count is at most the desired /// number. This is useful when doing custom type-checking on a variadic /// function. Returns true on error. -static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) { +bool Sema::checkArgCountAtMost(CallExpr *Call, unsigned MaxArgCount) { unsigned ArgCount = Call->getNumArgs(); if (ArgCount <= MaxArgCount) return false; - return S.Diag(Call->getEndLoc(), - diag::err_typecheck_call_too_many_args_at_most) + return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most) << 0 /*function call*/ << MaxArgCount << ArgCount << /*is non object*/ 0 << Call->getSourceRange(); } @@ -147,20 +157,20 @@ static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) { /// Checks that a call expression's argument count is in the desired range. This /// is useful when doing custom type-checking on a variadic function. Returns /// true on error. -static bool checkArgCountRange(Sema &S, CallExpr *Call, unsigned MinArgCount, - unsigned MaxArgCount) { - return checkArgCountAtLeast(S, Call, MinArgCount) || - checkArgCountAtMost(S, Call, MaxArgCount); +bool Sema::checkArgCountRange(CallExpr *Call, unsigned MinArgCount, + unsigned MaxArgCount) { + return checkArgCountAtLeast(Call, MinArgCount) || + checkArgCountAtMost(Call, MaxArgCount); } /// Checks that a call expression's argument count is the desired number. /// This is useful when doing custom type-checking. Returns true on error. -static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) { +bool Sema::checkArgCount(CallExpr *Call, unsigned DesiredArgCount) { unsigned ArgCount = Call->getNumArgs(); if (ArgCount == DesiredArgCount) return false; - if (checkArgCountAtLeast(S, Call, DesiredArgCount)) + if (checkArgCountAtLeast(Call, DesiredArgCount)) return true; assert(ArgCount > DesiredArgCount && "should have diagnosed this"); @@ -168,7 +178,7 @@ static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) { SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(), Call->getArg(ArgCount - 1)->getEndLoc()); - return S.Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args) + return Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << DesiredArgCount << ArgCount << /*is non object*/ 0 << Call->getArg(1)->getSourceRange(); } @@ -190,7 +200,7 @@ static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { /// Check that the first argument to __builtin_annotation is an integer /// and the second argument is a non-wide string literal. static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 2)) + if (S.checkArgCount(TheCall, 2)) return true; // First argument should be an integer. @@ -240,7 +250,7 @@ static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { /// Check that the argument to __builtin_addressof is a glvalue, and set the /// result type to the corresponding pointer type. static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return true; ExprResult Arg(TheCall->getArg(0)); @@ -255,7 +265,7 @@ static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) { /// Check that the argument to __builtin_function_start is a function. static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return true; ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); @@ -279,7 +289,7 @@ static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { /// Check the number of arguments and set the result type to /// the argument type. static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return true; TheCall->setType(TheCall->getArg(0)->getType()); @@ -290,7 +300,7 @@ static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) { /// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer /// type (but not a function pointer) and that the alignment is a power-of-two. static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { - if (checkArgCount(S, TheCall, 2)) + if (S.checkArgCount(TheCall, 2)) return true; clang::Expr *Source = TheCall->getArg(0); @@ -368,7 +378,7 @@ static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { } static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) { - if (checkArgCount(S, TheCall, 3)) + if (S.checkArgCount(TheCall, 3)) return true; std::pair Builtins[] = { @@ -696,7 +706,7 @@ struct BuiltinDumpStructGenerator { } // namespace static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) { - if (checkArgCountAtLeast(S, TheCall, 2)) + if (S.checkArgCountAtLeast(TheCall, 2)) return ExprError(); ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0)); @@ -762,7 +772,7 @@ static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) { } static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { - if (checkArgCount(S, BuiltinCall, 2)) + if (S.checkArgCount(BuiltinCall, 2)) return true; SourceLocation BuiltinLoc = BuiltinCall->getBeginLoc(); @@ -1504,7 +1514,7 @@ static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { } static bool OpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 2)) + if (S.checkArgCount(TheCall, 2)) return true; if (checkOpenCLSubgroupExt(S, TheCall)) @@ -1531,7 +1541,7 @@ static bool OpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. static bool OpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return true; Expr *BlockArg = TheCall->getArg(0); @@ -1861,7 +1871,7 @@ static bool BuiltinRWPipe(Sema &S, CallExpr *Call) { // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool BuiltinReserveRWPipe(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) + if (S.checkArgCount(Call, 2)) return true; if (checkOpenCLPipeArg(S, Call)) @@ -1890,7 +1900,7 @@ static bool BuiltinReserveRWPipe(Sema &S, CallExpr *Call) { // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool BuiltinCommitRWPipe(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) + if (S.checkArgCount(Call, 2)) return true; if (checkOpenCLPipeArg(S, Call)) @@ -1913,7 +1923,7 @@ static bool BuiltinCommitRWPipe(Sema &S, CallExpr *Call) { // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool BuiltinPipePackets(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 1)) + if (S.checkArgCount(Call, 1)) return true; if (!Call->getArg(0)->getType()->isPipeType()) { @@ -1932,7 +1942,7 @@ static bool BuiltinPipePackets(Sema &S, CallExpr *Call) { // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. static bool OpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { - if (checkArgCount(S, Call, 1)) + if (S.checkArgCount(Call, 1)) return true; auto RT = Call->getArg(0)->getType(); @@ -2087,7 +2097,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, } static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) + if (S.checkArgCount(Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2100,7 +2110,7 @@ static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) { } static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) + if (S.checkArgCount(Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2113,7 +2123,7 @@ static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { } static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) + if (S.checkArgCount(Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2127,7 +2137,7 @@ static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) { static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call, PointerAuthOpKind OpKind) { - if (checkArgCount(S, Call, 3)) + if (S.checkArgCount(Call, 3)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2141,7 +2151,7 @@ static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call, } static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 5)) + if (S.checkArgCount(Call, 5)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2157,7 +2167,7 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { } static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return ExprError(); // Compute __builtin_launder's parameter type from the argument. @@ -2259,45 +2269,46 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - return CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); + return ARM().CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: - return CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); + return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::bpfeb: case llvm::Triple::bpfel: - return CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); + return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::hexagon: - return CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); + return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: - return CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); + return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::systemz: - return CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); + return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::x86: case llvm::Triple::x86_64: - return CheckX86BuiltinFunctionCall(TI, BuiltinID, TheCall); + return X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::ppc: case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: - return CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); + return PPC().CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::amdgcn: - return CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); + return AMDGPU().CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::riscv32: case llvm::Triple::riscv64: - return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall); + return RISCV().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::loongarch32: case llvm::Triple::loongarch64: - return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall); + return LoongArch().CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, + TheCall); case llvm::Triple::wasm32: case llvm::Triple::wasm64: - return CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); + return Wasm().CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::nvptx: case llvm::Triple::nvptx64: - return CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); + return NVPTX().CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); } } @@ -2377,7 +2388,7 @@ static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, /// Checks that __builtin_popcountg was called with a single argument, which is /// an unsigned integer. static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { - if (checkArgCount(S, TheCall, 1)) + if (S.checkArgCount(TheCall, 1)) return true; ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0)); @@ -2401,7 +2412,7 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { /// an unsigned integer, and an optional second argument, which is promoted to /// an 'int'. static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { - if (checkArgCountRange(S, TheCall, 1, 2)) + if (S.checkArgCountRange(TheCall, 1, 2)) return true; ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0)); @@ -2625,7 +2636,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_classify_type: - if (checkArgCount(*this, TheCall, 1)) return true; + if (checkArgCount(TheCall, 1)) + return true; TheCall->setType(Context.IntTy); break; case Builtin::BI__builtin_complex: @@ -2633,7 +2645,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_constant_p: { - if (checkArgCount(*this, TheCall, 1)) return true; + if (checkArgCount(TheCall, 1)) + return true; ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); if (Arg.isInvalid()) return true; TheCall->setArg(0, Arg.get()); @@ -2822,7 +2835,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return BuiltinDumpStruct(*this, TheCall); case Builtin::BI__builtin_expect_with_probability: { // We first want to ensure we are called with 3 arguments - if (checkArgCount(*this, TheCall, 3)) + if (checkArgCount(TheCall, 3)) return ExprError(); // then check probability is constant float in range [0.0, 1.0] const Expr *ProbArg = TheCall->getArg(2); @@ -2870,7 +2883,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__GetExceptionInfo: - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return ExprError(); if (CheckCXXThrowOperand( @@ -2891,7 +2904,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // These are all expected to be of the form // T &/&&/* f(U &/&&) // where T and U only differ in qualification. - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return ExprError(); QualType Param = FDecl->getParamDecl(0)->getType(); QualType Result = FDecl->getReturnType(); @@ -3129,7 +3142,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_elementwise_copysign: { - if (checkArgCount(*this, TheCall, 2)) + if (checkArgCount(TheCall, 2)) return ExprError(); ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0)); @@ -3285,4323 +3298,250 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return TheCallResult; } -// Get the valid immediate range for the specified NEON type code. -static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { - NeonTypeFlags Type(t); - int IsQuad = ForceQuad ? true : Type.isQuad(); - switch (Type.getEltType()) { - case NeonTypeFlags::Int8: - case NeonTypeFlags::Poly8: - return shift ? 7 : (8 << IsQuad) - 1; - case NeonTypeFlags::Int16: - case NeonTypeFlags::Poly16: - return shift ? 15 : (4 << IsQuad) - 1; - case NeonTypeFlags::Int32: - return shift ? 31 : (2 << IsQuad) - 1; - case NeonTypeFlags::Int64: - case NeonTypeFlags::Poly64: - return shift ? 63 : (1 << IsQuad) - 1; - case NeonTypeFlags::Poly128: - return shift ? 127 : (1 << IsQuad) - 1; - case NeonTypeFlags::Float16: - assert(!shift && "cannot shift float types!"); - return (4 << IsQuad) - 1; - case NeonTypeFlags::Float32: - assert(!shift && "cannot shift float types!"); - return (2 << IsQuad) - 1; - case NeonTypeFlags::Float64: - assert(!shift && "cannot shift float types!"); - return (1 << IsQuad) - 1; - case NeonTypeFlags::BFloat16: - assert(!shift && "cannot shift float types!"); - return (4 << IsQuad) - 1; - } - llvm_unreachable("Invalid NeonTypeFlag!"); -} - -/// getNeonEltType - Return the QualType corresponding to the elements of -/// the vector type specified by the NeonTypeFlags. This is used to check -/// the pointer arguments for Neon load/store intrinsics. -static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, - bool IsPolyUnsigned, bool IsInt64Long) { - switch (Flags.getEltType()) { - case NeonTypeFlags::Int8: - return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy; - case NeonTypeFlags::Int16: - return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy; - case NeonTypeFlags::Int32: - return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy; - case NeonTypeFlags::Int64: - if (IsInt64Long) - return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy; - else - return Flags.isUnsigned() ? Context.UnsignedLongLongTy - : Context.LongLongTy; - case NeonTypeFlags::Poly8: - return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy; - case NeonTypeFlags::Poly16: - return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; - case NeonTypeFlags::Poly64: - if (IsInt64Long) - return Context.UnsignedLongTy; - else - return Context.UnsignedLongLongTy; - case NeonTypeFlags::Poly128: - break; - case NeonTypeFlags::Float16: - return Context.HalfTy; - case NeonTypeFlags::Float32: - return Context.FloatTy; - case NeonTypeFlags::Float64: - return Context.DoubleTy; - case NeonTypeFlags::BFloat16: - return Context.BFloat16Ty; - } - llvm_unreachable("Invalid NeonTypeFlag!"); -} - -enum ArmStreamingType { - ArmNonStreaming, - ArmStreaming, - ArmStreamingCompatible, - ArmStreamingOrSVE2p1 -}; +/// Returns true if the argument consists of one contiguous run of 1s with any +/// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so +/// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, +/// since all 1s are not contiguous. +bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { + llvm::APSInt Result; + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; -enum ArmSMEState : unsigned { - ArmNoState = 0, + // Check constant-ness first. + if (BuiltinConstantArg(TheCall, ArgNum, Result)) + return true; - ArmInZA = 0b01, - ArmOutZA = 0b10, - ArmInOutZA = 0b11, - ArmZAMask = 0b11, + // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s. + if (Result.isShiftedMask() || (~Result).isShiftedMask()) + return false; - ArmInZT0 = 0b01 << 2, - ArmOutZT0 = 0b10 << 2, - ArmInOutZT0 = 0b11 << 2, - ArmZT0Mask = 0b11 << 2 -}; + return Diag(TheCall->getBeginLoc(), + diag::err_argument_not_contiguous_bit_field) + << ArgNum << Arg->getSourceRange(); +} -bool Sema::ParseSVEImmChecks( - CallExpr *TheCall, SmallVector, 3> &ImmChecks) { - // Perform all the immediate checks for this builtin call. - bool HasError = false; - for (auto &I : ImmChecks) { - int ArgNum, CheckTy, ElementSizeInBits; - std::tie(ArgNum, CheckTy, ElementSizeInBits) = I; - - typedef bool (*OptionSetCheckFnTy)(int64_t Value); - - // Function that checks whether the operand (ArgNum) is an immediate - // that is one of the predefined values. - auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm, - int ErrDiag) -> bool { - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; +// Helper function for CheckHLSLBuiltinFunctionCall +bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() > 1); + ExprResult A = TheCall->getArg(0); - // Check constant-ness first. - llvm::APSInt Imm; - if (BuiltinConstantArg(TheCall, ArgNum, Imm)) - return true; + QualType ArgTyA = A.get()->getType(); + + auto *VecTyA = ArgTyA->getAs(); + SourceLocation BuiltinLoc = TheCall->getBeginLoc(); - if (!CheckImm(Imm.getSExtValue())) - return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange(); + for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) { + ExprResult B = TheCall->getArg(i); + QualType ArgTyB = B.get()->getType(); + auto *VecTyB = ArgTyB->getAs(); + if (VecTyA == nullptr && VecTyB == nullptr) return false; - }; - switch ((SVETypeFlags::ImmCheckType)CheckTy) { - case SVETypeFlags::ImmCheck0_31: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_13: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_16: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_7: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_1: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_3: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_7: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) - HasError = true; - break; - case SVETypeFlags::ImmCheckExtract: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (2048 / ElementSizeInBits) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftRight: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftRightNarrow: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits / 2)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftLeft: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, ElementSizeInBits - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndex: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (1 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndexCompRotate: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (2 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndexDot: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (4 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckComplexRot90_270: - if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; }, - diag::err_rotation_argument_to_cadd)) - HasError = true; - break; - case SVETypeFlags::ImmCheckComplexRotAll90: - if (CheckImmediateInSet( - [](int64_t V) { - return V == 0 || V == 90 || V == 180 || V == 270; - }, - diag::err_rotation_argument_to_cmla)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_1: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_2: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_3: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_0: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_15: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_255: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) - HasError = true; - break; - case SVETypeFlags::ImmCheck2_4_Mul2: - if (BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || - BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) - HasError = true; - break; + if (VecTyA && VecTyB) { + bool retValue = false; + if (VecTyA->getElementType() != VecTyB->getElementType()) { + // Note: type promotion is intended to be handeled via the intrinsics + // and not the builtin itself. + S->Diag(TheCall->getBeginLoc(), + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); + retValue = true; + } + if (VecTyA->getNumElements() != VecTyB->getNumElements()) { + // You should only be hitting this case if you are calling the builtin + // directly. HLSL intrinsics should avoid this case via a + // HLSLVectorTruncation. + S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + retValue = true; + } + return retValue; } } - return HasError; + // Note: if we get here one of the args is a scalar which + // requires a VectorSplat on Arg0 or Arg1 + S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + return true; } -static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) { - if (FD->hasAttr()) - return ArmStreaming; - if (const Type *Ty = FD->getType().getTypePtrOrNull()) { - if (const auto *FPT = Ty->getAs()) { - if (FPT->getAArch64SMEAttributes() & - FunctionType::SME_PStateSMEnabledMask) - return ArmStreaming; - if (FPT->getAArch64SMEAttributes() & - FunctionType::SME_PStateSMCompatibleMask) - return ArmStreamingCompatible; +bool CheckArgsTypesAreCorrect( + Sema *S, CallExpr *TheCall, QualType ExpectedType, + llvm::function_ref Check) { + for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { + QualType PassedType = TheCall->getArg(i)->getType(); + if (Check(PassedType)) { + if (auto *VecTyA = PassedType->getAs()) + ExpectedType = S->Context.getVectorType( + ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); + S->Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << PassedType << ExpectedType << 1 << 0 << 0; + return true; } } - return ArmNonStreaming; + return false; } -static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall, - const FunctionDecl *FD, - ArmStreamingType BuiltinType) { - ArmStreamingType FnType = getArmStreamingFnType(FD); - if (BuiltinType == ArmStreamingOrSVE2p1) { - // Check intrinsics that are available in [sve2p1 or sme/sme2]. - llvm::StringMap CallerFeatureMap; - S.Context.getFunctionFeatureMap(CallerFeatureMap, FD); - if (Builtin::evaluateRequiredTargetFeatures("sve2p1", CallerFeatureMap)) - BuiltinType = ArmStreamingCompatible; - else - BuiltinType = ArmStreaming; - } - - if (FnType == ArmStreaming && BuiltinType == ArmNonStreaming) { - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "streaming"; - } - - if (FnType == ArmStreamingCompatible && - BuiltinType != ArmStreamingCompatible) { - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "streaming compatible"; - return; - } - - if (FnType == ArmNonStreaming && BuiltinType == ArmStreaming) { - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "non-streaming"; - } +bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasFloatingRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkAllFloatTypes); } -static bool hasArmZAState(const FunctionDecl *FD) { - const auto *T = FD->getType()->getAs(); - return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) != - FunctionType::ARM_None) || - (FD->hasAttr() && FD->getAttr()->isNewZA()); +bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { + auto checkFloatorHalf = [](clang::QualType PassedType) -> bool { + clang::QualType BaseType = + PassedType->isVectorType() + ? PassedType->getAs()->getElementType() + : PassedType; + return !BaseType->isHalfType() && !BaseType->isFloat32Type(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkFloatorHalf); } -static bool hasArmZT0State(const FunctionDecl *FD) { - const auto *T = FD->getType()->getAs(); - return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) != - FunctionType::ARM_None) || - (FD->hasAttr() && FD->getAttr()->isNewZT0()); +bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { + auto checkDoubleVector = [](clang::QualType PassedType) -> bool { + if (const auto *VecTy = PassedType->getAs()) + return VecTy->getElementType()->isDoubleType(); + return false; + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkDoubleVector); } -static ArmSMEState getSMEState(unsigned BuiltinID) { - switch (BuiltinID) { - default: - return ArmNoState; -#define GET_SME_BUILTIN_GET_STATE -#include "clang/Basic/arm_sme_builtins_za_state.inc" -#undef GET_SME_BUILTIN_GET_STATE - } +bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasUnsignedIntegerRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, + checkAllUnsignedTypes); } -bool Sema::CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - std::optional BuiltinType; - - switch (BuiltinID) { -#define GET_SME_STREAMING_ATTRS -#include "clang/Basic/arm_sme_streaming_attrs.inc" -#undef GET_SME_STREAMING_ATTRS - } - - if (BuiltinType) - checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType); - - if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD)) - Diag(TheCall->getBeginLoc(), - diag::warn_attribute_arm_za_builtin_no_za_state) - << TheCall->getSourceRange(); - - if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD)) - Diag(TheCall->getBeginLoc(), - diag::warn_attribute_arm_zt0_builtin_no_zt0_state) - << TheCall->getSourceRange(); - } - - // Range check SME intrinsics that take immediate values. - SmallVector, 3> ImmChecks; - - switch (BuiltinID) { - default: - return false; -#define GET_SME_IMMEDIATE_CHECK -#include "clang/Basic/arm_sme_sema_rangechecks.inc" -#undef GET_SME_IMMEDIATE_CHECK - } - - return ParseSVEImmChecks(TheCall, ImmChecks); +void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, + QualType ReturnType) { + auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); + if (VecTyA) + ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), + VectorKind::Generic); + TheCall->setType(ReturnType); } -bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - std::optional BuiltinType; - - switch (BuiltinID) { -#define GET_SVE_STREAMING_ATTRS -#include "clang/Basic/arm_sve_streaming_attrs.inc" -#undef GET_SVE_STREAMING_ATTRS - } - if (BuiltinType) - checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType); - } - // Range check SVE intrinsics that take immediate values. - SmallVector, 3> ImmChecks; - +// Note: returning true in this case results in CheckBuiltinFunctionCall +// returning an ExprError +bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { - default: - return false; -#define GET_SVE_IMMEDIATE_CHECK -#include "clang/Basic/arm_sve_sema_rangechecks.inc" -#undef GET_SVE_IMMEDIATE_CHECK - } - - return ParseSVEImmChecks(TheCall, ImmChecks); -} - -bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - - switch (BuiltinID) { - default: - break; -#define GET_NEON_BUILTINS -#define TARGET_BUILTIN(id, ...) case NEON::BI##id: -#define BUILTIN(id, ...) case NEON::BI##id: -#include "clang/Basic/arm_neon.inc" - checkArmStreamingBuiltin(*this, TheCall, FD, ArmNonStreaming); - break; -#undef TARGET_BUILTIN -#undef BUILTIN -#undef GET_NEON_BUILTINS - } + case Builtin::BI__builtin_hlsl_elementwise_all: + case Builtin::BI__builtin_hlsl_elementwise_any: { + if (checkArgCount(TheCall, 1)) + return true; + break; } - - llvm::APSInt Result; - uint64_t mask = 0; - unsigned TV = 0; - int PtrArgNum = -1; - bool HasConstPtr = false; - switch (BuiltinID) { -#define GET_NEON_OVERLOAD_CHECK -#include "clang/Basic/arm_neon.inc" -#include "clang/Basic/arm_fp16.inc" -#undef GET_NEON_OVERLOAD_CHECK + case Builtin::BI__builtin_hlsl_elementwise_clamp: { + if (checkArgCount(TheCall, 3)) + return true; + if (CheckVectorElementCallArgs(this, TheCall)) + return true; + if (BuiltinElementwiseTernaryMath( + TheCall, /*CheckForFloatArgs*/ + TheCall->getArg(0)->getType()->hasFloatingRepresentation())) + return true; + break; } - - // For NEON intrinsics which are overloaded on vector element type, validate - // the immediate which specifies which variant to emit. - unsigned ImmArg = TheCall->getNumArgs()-1; - if (mask) { - if (BuiltinConstantArg(TheCall, ImmArg, Result)) + case Builtin::BI__builtin_hlsl_dot: { + if (checkArgCount(TheCall, 2)) return true; - - TV = Result.getLimitedValue(64); - if ((TV > 63) || (mask & (1ULL << TV)) == 0) - return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code) - << TheCall->getArg(ImmArg)->getSourceRange(); - } - - if (PtrArgNum >= 0) { - // Check that pointer arguments have the specified type. - Expr *Arg = TheCall->getArg(PtrArgNum); - if (ImplicitCastExpr *ICE = dyn_cast(Arg)) - Arg = ICE->getSubExpr(); - ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg); - QualType RHSTy = RHS.get()->getType(); - - llvm::Triple::ArchType Arch = TI.getTriple().getArch(); - bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || - Arch == llvm::Triple::aarch64_32 || - Arch == llvm::Triple::aarch64_be; - bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong; - QualType EltTy = - getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long); - if (HasConstPtr) - EltTy = EltTy.withConst(); - QualType LHSTy = Context.getPointerType(EltTy); - AssignConvertType ConvTy; - ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); - if (RHS.isInvalid()) + if (CheckVectorElementCallArgs(this, TheCall)) + return true; + if (BuiltinVectorToScalarMath(TheCall)) return true; - if (DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy, RHSTy, - RHS.get(), AA_Assigning)) + if (CheckNoDoubleVectors(this, TheCall)) return true; + break; } - - // For NEON intrinsics which take an immediate value as part of the - // instruction, range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: - return false; - #define GET_NEON_IMMEDIATE_CHECK - #include "clang/Basic/arm_neon.inc" - #include "clang/Basic/arm_fp16.inc" - #undef GET_NEON_IMMEDIATE_CHECK + case Builtin::BI__builtin_hlsl_elementwise_rcp: { + if (CheckAllArgsHaveFloatRepresentation(this, TheCall)) + return true; + if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + break; } - - return BuiltinConstantArgRange(TheCall, i, l, u + l); -} - -bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - default: - return false; - #include "clang/Basic/arm_mve_builtin_sema.inc" + case Builtin::BI__builtin_hlsl_elementwise_rsqrt: + case Builtin::BI__builtin_hlsl_elementwise_frac: { + if (CheckFloatOrHalfRepresentations(this, TheCall)) + return true; + if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + break; } -} - -bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - bool Err = false; - switch (BuiltinID) { - default: - return false; -#include "clang/Basic/arm_cde_builtin_sema.inc" - } - - if (Err) - return true; - - return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true); -} - -bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI, - const Expr *CoprocArg, bool WantCDE) { - if (isConstantEvaluatedContext()) - return false; - - // We can't check the value of a dependent argument. - if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent()) - return false; - - llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context); - int64_t CoprocNo = CoprocNoAP.getExtValue(); - assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative"); - - uint32_t CDECoprocMask = TI.getARMCDECoprocMask(); - bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo)); - - if (IsCDECoproc != WantCDE) - return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc) - << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange(); - - return false; -} - -bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, - unsigned MaxWidth) { - assert((BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == ARM::BI__builtin_arm_strex || - BuiltinID == ARM::BI__builtin_arm_stlex || - BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) && - "unexpected ARM builtin"); - bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex; - - DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); - - // Ensure that we have the proper number of arguments. - if (checkArgCount(*this, TheCall, IsLdrex ? 1 : 2)) - return true; - - // Inspect the pointer argument of the atomic builtin. This should always be - // a pointer type, whose element is an integral scalar or pointer type. - // Because it is a pointer type, we don't have to worry about any implicit - // casts here. - Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1); - ExprResult PointerArgRes = DefaultFunctionArrayLvalueConversion(PointerArg); - if (PointerArgRes.isInvalid()) - return true; - PointerArg = PointerArgRes.get(); - - const PointerType *pointerType = PointerArg->getType()->getAs(); - if (!pointerType) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next - // task is to insert the appropriate casts into the AST. First work out just - // what the appropriate type is. - QualType ValType = pointerType->getPointeeType(); - QualType AddrType = ValType.getUnqualifiedType().withVolatile(); - if (IsLdrex) - AddrType.addConst(); - - // Issue a warning if the cast is dodgy. - CastKind CastNeeded = CK_NoOp; - if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { - CastNeeded = CK_BitCast; - Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) - << PointerArg->getType() << Context.getPointerType(AddrType) - << AA_Passing << PointerArg->getSourceRange(); - } - - // Finally, do the cast and replace the argument with the corrected version. - AddrType = Context.getPointerType(AddrType); - PointerArgRes = ImpCastExprToType(PointerArg, AddrType, CastNeeded); - if (PointerArgRes.isInvalid()) - return true; - PointerArg = PointerArgRes.get(); - - TheCall->setArg(IsLdrex ? 0 : 1, PointerArg); - - // In general, we allow ints, floats and pointers to be loaded and stored. - if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && - !ValType->isBlockPointerType() && !ValType->isFloatingType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - // But ARM doesn't have instructions to deal with 128-bit versions. - if (Context.getTypeSize(ValType) > MaxWidth) { - assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); - Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - switch (ValType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - // okay - break; - - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Autoreleasing: - Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) - << ValType << PointerArg->getSourceRange(); - return true; - } - - if (IsLdrex) { - TheCall->setType(ValType); - return false; - } - - // Initialize the argument to be stored. - ExprResult ValArg = TheCall->getArg(0); - InitializedEntity Entity = InitializedEntity::InitializeParameter( - Context, ValType, /*consume*/ false); - ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); - if (ValArg.isInvalid()) - return true; - TheCall->setArg(0, ValArg.get()); - - // __builtin_arm_strex always returns an int. It's marked as such in the .def, - // but the custom checker bypasses all default analysis. - TheCall->setType(Context.IntTy); - return false; -} - -bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == ARM::BI__builtin_arm_strex || - BuiltinID == ARM::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); - } - - if (BuiltinID == ARM::BI__builtin_arm_prefetch) { - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 1); - } - - if (BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_wsr64) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); - - if (BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsr || - BuiltinID == ARM::BI__builtin_arm_wsrp) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - // FIXME: VFP Intrinsics should error if VFP not present. - switch (BuiltinID) { - default: return false; - case ARM::BI__builtin_arm_ssat: - return BuiltinConstantArgRange(TheCall, 1, 1, 32); - case ARM::BI__builtin_arm_usat: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case ARM::BI__builtin_arm_ssat16: - return BuiltinConstantArgRange(TheCall, 1, 1, 16); - case ARM::BI__builtin_arm_usat16: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case ARM::BI__builtin_arm_vcvtr_f: - case ARM::BI__builtin_arm_vcvtr_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case ARM::BI__builtin_arm_dmb: - case ARM::BI__builtin_arm_dsb: - case ARM::BI__builtin_arm_isb: - case ARM::BI__builtin_arm_dbg: - return BuiltinConstantArgRange(TheCall, 0, 0, 15); - case ARM::BI__builtin_arm_cdp: - case ARM::BI__builtin_arm_cdp2: - case ARM::BI__builtin_arm_mcr: - case ARM::BI__builtin_arm_mcr2: - case ARM::BI__builtin_arm_mrc: - case ARM::BI__builtin_arm_mrc2: - case ARM::BI__builtin_arm_mcrr: - case ARM::BI__builtin_arm_mcrr2: - case ARM::BI__builtin_arm_mrrc: - case ARM::BI__builtin_arm_mrrc2: - case ARM::BI__builtin_arm_ldc: - case ARM::BI__builtin_arm_ldcl: - case ARM::BI__builtin_arm_ldc2: - case ARM::BI__builtin_arm_ldc2l: - case ARM::BI__builtin_arm_stc: - case ARM::BI__builtin_arm_stcl: - case ARM::BI__builtin_arm_stc2: - case ARM::BI__builtin_arm_stc2l: - return BuiltinConstantArgRange(TheCall, 0, 0, 15) || - CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), - /*WantCDE*/ false); - } -} - -bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); - } - - if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 3) || - BuiltinConstantArgRange(TheCall, 3, 0, 1) || - BuiltinConstantArgRange(TheCall, 4, 0, 1); - } - - if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - // Memory Tagging Extensions (MTE) Intrinsics - if (BuiltinID == AArch64::BI__builtin_arm_irg || - BuiltinID == AArch64::BI__builtin_arm_addg || - BuiltinID == AArch64::BI__builtin_arm_gmi || - BuiltinID == AArch64::BI__builtin_arm_ldg || - BuiltinID == AArch64::BI__builtin_arm_stg || - BuiltinID == AArch64::BI__builtin_arm_subp) { - return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); - } - - if (BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsr || - BuiltinID == AArch64::BI__builtin_arm_wsrp) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - // Only check the valid encoding range. Any constant in this range would be - // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw - // an exception for incorrect registers. This matches MSVC behavior. - if (BuiltinID == AArch64::BI_ReadStatusReg || - BuiltinID == AArch64::BI_WriteStatusReg) - return BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); - - if (BuiltinID == AArch64::BI__getReg) - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - - if (BuiltinID == AArch64::BI__break) - return BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); - - if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - - if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - - if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: return false; - case AArch64::BI__builtin_arm_dmb: - case AArch64::BI__builtin_arm_dsb: - case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; - case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; - } - - return BuiltinConstantArgRange(TheCall, i, l, u + l); -} - -static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { - if (Arg->getType()->getAsPlaceholderType()) - return false; - - // The first argument needs to be a record field access. - // If it is an array element access, we delay decision - // to BPF backend to check whether the access is a - // field access or not. - return (Arg->IgnoreParens()->getObjectKind() == OK_BitField || - isa(Arg->IgnoreParens()) || - isa(Arg->IgnoreParens())); -} - -static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) { - QualType ArgType = Arg->getType(); - if (ArgType->getAsPlaceholderType()) - return false; - - // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type - // format: - // 1. __builtin_preserve_type_info(*( *)0, flag); - // 2. var; - // __builtin_preserve_type_info(var, flag); - if (!isa(Arg->IgnoreParens()) && - !isa(Arg->IgnoreParens())) - return false; - - // Typedef type. - if (ArgType->getAs()) - return true; - - // Record type or Enum type. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - if (const auto *RT = Ty->getAs()) { - if (!RT->getDecl()->getDeclName().isEmpty()) - return true; - } else if (const auto *ET = Ty->getAs()) { - if (!ET->getDecl()->getDeclName().isEmpty()) - return true; - } - - return false; -} - -static bool isValidBPFPreserveEnumValueArg(Expr *Arg) { - QualType ArgType = Arg->getType(); - if (ArgType->getAsPlaceholderType()) - return false; - - // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type - // format: - // __builtin_preserve_enum_value(*( *), - // flag); - const auto *UO = dyn_cast(Arg->IgnoreParens()); - if (!UO) - return false; - - const auto *CE = dyn_cast(UO->getSubExpr()); - if (!CE) - return false; - if (CE->getCastKind() != CK_IntegralToPointer && - CE->getCastKind() != CK_NullToPointer) - return false; - - // The integer must be from an EnumConstantDecl. - const auto *DR = dyn_cast(CE->getSubExpr()); - if (!DR) - return false; - - const EnumConstantDecl *Enumerator = - dyn_cast(DR->getDecl()); - if (!Enumerator) - return false; - - // The type must be EnumType. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - const auto *ET = Ty->getAs(); - if (!ET) - return false; - - // The enum value must be supported. - return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator); -} - -bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id || - BuiltinID == BPF::BI__builtin_preserve_type_info || - BuiltinID == BPF::BI__builtin_preserve_enum_value) && - "unexpected BPF builtin"); - - if (checkArgCount(*this, TheCall, 2)) - return true; - - // The second argument needs to be a constant int - Expr *Arg = TheCall->getArg(1); - std::optional Value = Arg->getIntegerConstantExpr(Context); - diag::kind kind; - if (!Value) { - if (BuiltinID == BPF::BI__builtin_preserve_field_info) - kind = diag::err_preserve_field_info_not_const; - else if (BuiltinID == BPF::BI__builtin_btf_type_id) - kind = diag::err_btf_type_id_not_const; - else if (BuiltinID == BPF::BI__builtin_preserve_type_info) - kind = diag::err_preserve_type_info_not_const; - else - kind = diag::err_preserve_enum_value_not_const; - Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange(); - return true; - } - - // The first argument - Arg = TheCall->getArg(0); - bool InvalidArg = false; - bool ReturnUnsignedInt = true; - if (BuiltinID == BPF::BI__builtin_preserve_field_info) { - if (!isValidBPFPreserveFieldInfoArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_field_info_not_field; - } - } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) { - if (!isValidBPFPreserveTypeInfoArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_type_info_invalid; - } - } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) { - if (!isValidBPFPreserveEnumValueArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_enum_value_invalid; - } - ReturnUnsignedInt = false; - } else if (BuiltinID == BPF::BI__builtin_btf_type_id) { - ReturnUnsignedInt = false; - } - - if (InvalidArg) { - Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange(); - return true; - } - - if (ReturnUnsignedInt) - TheCall->setType(Context.UnsignedIntTy); - else - TheCall->setType(Context.UnsignedLongTy); - return false; -} - -bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { - struct ArgInfo { - uint8_t OpNum; - bool IsSigned; - uint8_t BitWidth; - uint8_t Align; - }; - struct BuiltinInfo { - unsigned BuiltinID; - ArgInfo Infos[2]; - }; - - static BuiltinInfo Infos[] = { - { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, - { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, - { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, - { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, - { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, - { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, - { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, - - { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, - - { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, - {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, - {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, - { 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, - { 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, - { 3, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, - { 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, - { 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, - {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, - {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, - {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, - {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, - {{ 3, false, 1, 0 }} }, - - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B, - {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B, - {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, - {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, - {{ 3, false, 3, 0 }} }, - }; - - // Use a dynamically initialized static to sort the table exactly once on - // first run. - static const bool SortOnce = - (llvm::sort(Infos, - [](const BuiltinInfo &LHS, const BuiltinInfo &RHS) { - return LHS.BuiltinID < RHS.BuiltinID; - }), - true); - (void)SortOnce; - - const BuiltinInfo *F = llvm::partition_point( - Infos, [=](const BuiltinInfo &BI) { return BI.BuiltinID < BuiltinID; }); - if (F == std::end(Infos) || F->BuiltinID != BuiltinID) - return false; - - bool Error = false; - - for (const ArgInfo &A : F->Infos) { - // Ignore empty ArgInfo elements. - if (A.BitWidth == 0) - continue; - - int32_t Min = A.IsSigned ? -(1 << (A.BitWidth - 1)) : 0; - int32_t Max = (1 << (A.IsSigned ? A.BitWidth - 1 : A.BitWidth)) - 1; - if (!A.Align) { - Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - } else { - unsigned M = 1 << A.Align; - Min *= M; - Max *= M; - Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - Error |= BuiltinConstantArgMultiple(TheCall, A.OpNum, M); - } - } - return Error; -} - -bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - return CheckHexagonBuiltinArgument(BuiltinID, TheCall); -} - -bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - default: - break; - // Basic intrinsics. - case LoongArch::BI__builtin_loongarch_cacop_d: - case LoongArch::BI__builtin_loongarch_cacop_w: { - BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); - BuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), llvm::maxIntN(12)); - break; - } - case LoongArch::BI__builtin_loongarch_break: - case LoongArch::BI__builtin_loongarch_dbar: - case LoongArch::BI__builtin_loongarch_ibar: - case LoongArch::BI__builtin_loongarch_syscall: - // Check if immediate is in [0, 32767]. - return BuiltinConstantArgRange(TheCall, 0, 0, 32767); - case LoongArch::BI__builtin_loongarch_csrrd_w: - case LoongArch::BI__builtin_loongarch_csrrd_d: - return BuiltinConstantArgRange(TheCall, 0, 0, 16383); - case LoongArch::BI__builtin_loongarch_csrwr_w: - case LoongArch::BI__builtin_loongarch_csrwr_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 16383); - case LoongArch::BI__builtin_loongarch_csrxchg_w: - case LoongArch::BI__builtin_loongarch_csrxchg_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 16383); - case LoongArch::BI__builtin_loongarch_lddir_d: - case LoongArch::BI__builtin_loongarch_ldpte_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_loongarch_movfcsr2gr: - case LoongArch::BI__builtin_loongarch_movgr2fcsr: - return BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); - - // LSX intrinsics. - case LoongArch::BI__builtin_lsx_vbitclri_b: - case LoongArch::BI__builtin_lsx_vbitrevi_b: - case LoongArch::BI__builtin_lsx_vbitseti_b: - case LoongArch::BI__builtin_lsx_vsat_b: - case LoongArch::BI__builtin_lsx_vsat_bu: - case LoongArch::BI__builtin_lsx_vslli_b: - case LoongArch::BI__builtin_lsx_vsrai_b: - case LoongArch::BI__builtin_lsx_vsrari_b: - case LoongArch::BI__builtin_lsx_vsrli_b: - case LoongArch::BI__builtin_lsx_vsllwil_h_b: - case LoongArch::BI__builtin_lsx_vsllwil_hu_bu: - case LoongArch::BI__builtin_lsx_vrotri_b: - case LoongArch::BI__builtin_lsx_vsrlri_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lsx_vbitclri_h: - case LoongArch::BI__builtin_lsx_vbitrevi_h: - case LoongArch::BI__builtin_lsx_vbitseti_h: - case LoongArch::BI__builtin_lsx_vsat_h: - case LoongArch::BI__builtin_lsx_vsat_hu: - case LoongArch::BI__builtin_lsx_vslli_h: - case LoongArch::BI__builtin_lsx_vsrai_h: - case LoongArch::BI__builtin_lsx_vsrari_h: - case LoongArch::BI__builtin_lsx_vsrli_h: - case LoongArch::BI__builtin_lsx_vsllwil_w_h: - case LoongArch::BI__builtin_lsx_vsllwil_wu_hu: - case LoongArch::BI__builtin_lsx_vrotri_h: - case LoongArch::BI__builtin_lsx_vsrlri_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lsx_vssrarni_b_h: - case LoongArch::BI__builtin_lsx_vssrarni_bu_h: - case LoongArch::BI__builtin_lsx_vssrani_b_h: - case LoongArch::BI__builtin_lsx_vssrani_bu_h: - case LoongArch::BI__builtin_lsx_vsrarni_b_h: - case LoongArch::BI__builtin_lsx_vsrlni_b_h: - case LoongArch::BI__builtin_lsx_vsrlrni_b_h: - case LoongArch::BI__builtin_lsx_vssrlni_b_h: - case LoongArch::BI__builtin_lsx_vssrlni_bu_h: - case LoongArch::BI__builtin_lsx_vssrlrni_b_h: - case LoongArch::BI__builtin_lsx_vssrlrni_bu_h: - case LoongArch::BI__builtin_lsx_vsrani_b_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lsx_vslei_bu: - case LoongArch::BI__builtin_lsx_vslei_hu: - case LoongArch::BI__builtin_lsx_vslei_wu: - case LoongArch::BI__builtin_lsx_vslei_du: - case LoongArch::BI__builtin_lsx_vslti_bu: - case LoongArch::BI__builtin_lsx_vslti_hu: - case LoongArch::BI__builtin_lsx_vslti_wu: - case LoongArch::BI__builtin_lsx_vslti_du: - case LoongArch::BI__builtin_lsx_vmaxi_bu: - case LoongArch::BI__builtin_lsx_vmaxi_hu: - case LoongArch::BI__builtin_lsx_vmaxi_wu: - case LoongArch::BI__builtin_lsx_vmaxi_du: - case LoongArch::BI__builtin_lsx_vmini_bu: - case LoongArch::BI__builtin_lsx_vmini_hu: - case LoongArch::BI__builtin_lsx_vmini_wu: - case LoongArch::BI__builtin_lsx_vmini_du: - case LoongArch::BI__builtin_lsx_vaddi_bu: - case LoongArch::BI__builtin_lsx_vaddi_hu: - case LoongArch::BI__builtin_lsx_vaddi_wu: - case LoongArch::BI__builtin_lsx_vaddi_du: - case LoongArch::BI__builtin_lsx_vbitclri_w: - case LoongArch::BI__builtin_lsx_vbitrevi_w: - case LoongArch::BI__builtin_lsx_vbitseti_w: - case LoongArch::BI__builtin_lsx_vsat_w: - case LoongArch::BI__builtin_lsx_vsat_wu: - case LoongArch::BI__builtin_lsx_vslli_w: - case LoongArch::BI__builtin_lsx_vsrai_w: - case LoongArch::BI__builtin_lsx_vsrari_w: - case LoongArch::BI__builtin_lsx_vsrli_w: - case LoongArch::BI__builtin_lsx_vsllwil_d_w: - case LoongArch::BI__builtin_lsx_vsllwil_du_wu: - case LoongArch::BI__builtin_lsx_vsrlri_w: - case LoongArch::BI__builtin_lsx_vrotri_w: - case LoongArch::BI__builtin_lsx_vsubi_bu: - case LoongArch::BI__builtin_lsx_vsubi_hu: - case LoongArch::BI__builtin_lsx_vbsrl_v: - case LoongArch::BI__builtin_lsx_vbsll_v: - case LoongArch::BI__builtin_lsx_vsubi_wu: - case LoongArch::BI__builtin_lsx_vsubi_du: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_lsx_vssrarni_h_w: - case LoongArch::BI__builtin_lsx_vssrarni_hu_w: - case LoongArch::BI__builtin_lsx_vssrani_h_w: - case LoongArch::BI__builtin_lsx_vssrani_hu_w: - case LoongArch::BI__builtin_lsx_vsrarni_h_w: - case LoongArch::BI__builtin_lsx_vsrani_h_w: - case LoongArch::BI__builtin_lsx_vfrstpi_b: - case LoongArch::BI__builtin_lsx_vfrstpi_h: - case LoongArch::BI__builtin_lsx_vsrlni_h_w: - case LoongArch::BI__builtin_lsx_vsrlrni_h_w: - case LoongArch::BI__builtin_lsx_vssrlni_h_w: - case LoongArch::BI__builtin_lsx_vssrlni_hu_w: - case LoongArch::BI__builtin_lsx_vssrlrni_h_w: - case LoongArch::BI__builtin_lsx_vssrlrni_hu_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 31); - case LoongArch::BI__builtin_lsx_vbitclri_d: - case LoongArch::BI__builtin_lsx_vbitrevi_d: - case LoongArch::BI__builtin_lsx_vbitseti_d: - case LoongArch::BI__builtin_lsx_vsat_d: - case LoongArch::BI__builtin_lsx_vsat_du: - case LoongArch::BI__builtin_lsx_vslli_d: - case LoongArch::BI__builtin_lsx_vsrai_d: - case LoongArch::BI__builtin_lsx_vsrli_d: - case LoongArch::BI__builtin_lsx_vsrari_d: - case LoongArch::BI__builtin_lsx_vrotri_d: - case LoongArch::BI__builtin_lsx_vsrlri_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 63); - case LoongArch::BI__builtin_lsx_vssrarni_w_d: - case LoongArch::BI__builtin_lsx_vssrarni_wu_d: - case LoongArch::BI__builtin_lsx_vssrani_w_d: - case LoongArch::BI__builtin_lsx_vssrani_wu_d: - case LoongArch::BI__builtin_lsx_vsrarni_w_d: - case LoongArch::BI__builtin_lsx_vsrlni_w_d: - case LoongArch::BI__builtin_lsx_vsrlrni_w_d: - case LoongArch::BI__builtin_lsx_vssrlni_w_d: - case LoongArch::BI__builtin_lsx_vssrlni_wu_d: - case LoongArch::BI__builtin_lsx_vssrlrni_w_d: - case LoongArch::BI__builtin_lsx_vssrlrni_wu_d: - case LoongArch::BI__builtin_lsx_vsrani_w_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 63); - case LoongArch::BI__builtin_lsx_vssrarni_d_q: - case LoongArch::BI__builtin_lsx_vssrarni_du_q: - case LoongArch::BI__builtin_lsx_vssrani_d_q: - case LoongArch::BI__builtin_lsx_vssrani_du_q: - case LoongArch::BI__builtin_lsx_vsrarni_d_q: - case LoongArch::BI__builtin_lsx_vssrlni_d_q: - case LoongArch::BI__builtin_lsx_vssrlni_du_q: - case LoongArch::BI__builtin_lsx_vssrlrni_d_q: - case LoongArch::BI__builtin_lsx_vssrlrni_du_q: - case LoongArch::BI__builtin_lsx_vsrani_d_q: - case LoongArch::BI__builtin_lsx_vsrlrni_d_q: - case LoongArch::BI__builtin_lsx_vsrlni_d_q: - return BuiltinConstantArgRange(TheCall, 2, 0, 127); - case LoongArch::BI__builtin_lsx_vseqi_b: - case LoongArch::BI__builtin_lsx_vseqi_h: - case LoongArch::BI__builtin_lsx_vseqi_w: - case LoongArch::BI__builtin_lsx_vseqi_d: - case LoongArch::BI__builtin_lsx_vslti_b: - case LoongArch::BI__builtin_lsx_vslti_h: - case LoongArch::BI__builtin_lsx_vslti_w: - case LoongArch::BI__builtin_lsx_vslti_d: - case LoongArch::BI__builtin_lsx_vslei_b: - case LoongArch::BI__builtin_lsx_vslei_h: - case LoongArch::BI__builtin_lsx_vslei_w: - case LoongArch::BI__builtin_lsx_vslei_d: - case LoongArch::BI__builtin_lsx_vmaxi_b: - case LoongArch::BI__builtin_lsx_vmaxi_h: - case LoongArch::BI__builtin_lsx_vmaxi_w: - case LoongArch::BI__builtin_lsx_vmaxi_d: - case LoongArch::BI__builtin_lsx_vmini_b: - case LoongArch::BI__builtin_lsx_vmini_h: - case LoongArch::BI__builtin_lsx_vmini_w: - case LoongArch::BI__builtin_lsx_vmini_d: - return BuiltinConstantArgRange(TheCall, 1, -16, 15); - case LoongArch::BI__builtin_lsx_vandi_b: - case LoongArch::BI__builtin_lsx_vnori_b: - case LoongArch::BI__builtin_lsx_vori_b: - case LoongArch::BI__builtin_lsx_vshuf4i_b: - case LoongArch::BI__builtin_lsx_vshuf4i_h: - case LoongArch::BI__builtin_lsx_vshuf4i_w: - case LoongArch::BI__builtin_lsx_vxori_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 255); - case LoongArch::BI__builtin_lsx_vbitseli_b: - case LoongArch::BI__builtin_lsx_vshuf4i_d: - case LoongArch::BI__builtin_lsx_vextrins_b: - case LoongArch::BI__builtin_lsx_vextrins_h: - case LoongArch::BI__builtin_lsx_vextrins_w: - case LoongArch::BI__builtin_lsx_vextrins_d: - case LoongArch::BI__builtin_lsx_vpermi_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 255); - case LoongArch::BI__builtin_lsx_vpickve2gr_b: - case LoongArch::BI__builtin_lsx_vpickve2gr_bu: - case LoongArch::BI__builtin_lsx_vreplvei_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lsx_vinsgr2vr_b: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lsx_vpickve2gr_h: - case LoongArch::BI__builtin_lsx_vpickve2gr_hu: - case LoongArch::BI__builtin_lsx_vreplvei_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lsx_vinsgr2vr_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case LoongArch::BI__builtin_lsx_vpickve2gr_w: - case LoongArch::BI__builtin_lsx_vpickve2gr_wu: - case LoongArch::BI__builtin_lsx_vreplvei_w: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case LoongArch::BI__builtin_lsx_vinsgr2vr_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case LoongArch::BI__builtin_lsx_vpickve2gr_d: - case LoongArch::BI__builtin_lsx_vpickve2gr_du: - case LoongArch::BI__builtin_lsx_vreplvei_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case LoongArch::BI__builtin_lsx_vinsgr2vr_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 1); - case LoongArch::BI__builtin_lsx_vstelm_b: - return BuiltinConstantArgRange(TheCall, 2, -128, 127) || - BuiltinConstantArgRange(TheCall, 3, 0, 15); - case LoongArch::BI__builtin_lsx_vstelm_h: - return BuiltinConstantArgRange(TheCall, 2, -256, 254) || - BuiltinConstantArgRange(TheCall, 3, 0, 7); - case LoongArch::BI__builtin_lsx_vstelm_w: - return BuiltinConstantArgRange(TheCall, 2, -512, 508) || - BuiltinConstantArgRange(TheCall, 3, 0, 3); - case LoongArch::BI__builtin_lsx_vstelm_d: - return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - BuiltinConstantArgRange(TheCall, 3, 0, 1); - case LoongArch::BI__builtin_lsx_vldrepl_b: - case LoongArch::BI__builtin_lsx_vld: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); - case LoongArch::BI__builtin_lsx_vldrepl_h: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); - case LoongArch::BI__builtin_lsx_vldrepl_w: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); - case LoongArch::BI__builtin_lsx_vldrepl_d: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); - case LoongArch::BI__builtin_lsx_vst: - return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); - case LoongArch::BI__builtin_lsx_vldi: - return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); - case LoongArch::BI__builtin_lsx_vrepli_b: - case LoongArch::BI__builtin_lsx_vrepli_h: - case LoongArch::BI__builtin_lsx_vrepli_w: - case LoongArch::BI__builtin_lsx_vrepli_d: - return BuiltinConstantArgRange(TheCall, 0, -512, 511); - - // LASX intrinsics. - case LoongArch::BI__builtin_lasx_xvbitclri_b: - case LoongArch::BI__builtin_lasx_xvbitrevi_b: - case LoongArch::BI__builtin_lasx_xvbitseti_b: - case LoongArch::BI__builtin_lasx_xvsat_b: - case LoongArch::BI__builtin_lasx_xvsat_bu: - case LoongArch::BI__builtin_lasx_xvslli_b: - case LoongArch::BI__builtin_lasx_xvsrai_b: - case LoongArch::BI__builtin_lasx_xvsrari_b: - case LoongArch::BI__builtin_lasx_xvsrli_b: - case LoongArch::BI__builtin_lasx_xvsllwil_h_b: - case LoongArch::BI__builtin_lasx_xvsllwil_hu_bu: - case LoongArch::BI__builtin_lasx_xvrotri_b: - case LoongArch::BI__builtin_lasx_xvsrlri_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lasx_xvbitclri_h: - case LoongArch::BI__builtin_lasx_xvbitrevi_h: - case LoongArch::BI__builtin_lasx_xvbitseti_h: - case LoongArch::BI__builtin_lasx_xvsat_h: - case LoongArch::BI__builtin_lasx_xvsat_hu: - case LoongArch::BI__builtin_lasx_xvslli_h: - case LoongArch::BI__builtin_lasx_xvsrai_h: - case LoongArch::BI__builtin_lasx_xvsrari_h: - case LoongArch::BI__builtin_lasx_xvsrli_h: - case LoongArch::BI__builtin_lasx_xvsllwil_w_h: - case LoongArch::BI__builtin_lasx_xvsllwil_wu_hu: - case LoongArch::BI__builtin_lasx_xvrotri_h: - case LoongArch::BI__builtin_lasx_xvsrlri_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lasx_xvssrarni_b_h: - case LoongArch::BI__builtin_lasx_xvssrarni_bu_h: - case LoongArch::BI__builtin_lasx_xvssrani_b_h: - case LoongArch::BI__builtin_lasx_xvssrani_bu_h: - case LoongArch::BI__builtin_lasx_xvsrarni_b_h: - case LoongArch::BI__builtin_lasx_xvsrlni_b_h: - case LoongArch::BI__builtin_lasx_xvsrlrni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlni_bu_h: - case LoongArch::BI__builtin_lasx_xvssrlrni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlrni_bu_h: - case LoongArch::BI__builtin_lasx_xvsrani_b_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lasx_xvslei_bu: - case LoongArch::BI__builtin_lasx_xvslei_hu: - case LoongArch::BI__builtin_lasx_xvslei_wu: - case LoongArch::BI__builtin_lasx_xvslei_du: - case LoongArch::BI__builtin_lasx_xvslti_bu: - case LoongArch::BI__builtin_lasx_xvslti_hu: - case LoongArch::BI__builtin_lasx_xvslti_wu: - case LoongArch::BI__builtin_lasx_xvslti_du: - case LoongArch::BI__builtin_lasx_xvmaxi_bu: - case LoongArch::BI__builtin_lasx_xvmaxi_hu: - case LoongArch::BI__builtin_lasx_xvmaxi_wu: - case LoongArch::BI__builtin_lasx_xvmaxi_du: - case LoongArch::BI__builtin_lasx_xvmini_bu: - case LoongArch::BI__builtin_lasx_xvmini_hu: - case LoongArch::BI__builtin_lasx_xvmini_wu: - case LoongArch::BI__builtin_lasx_xvmini_du: - case LoongArch::BI__builtin_lasx_xvaddi_bu: - case LoongArch::BI__builtin_lasx_xvaddi_hu: - case LoongArch::BI__builtin_lasx_xvaddi_wu: - case LoongArch::BI__builtin_lasx_xvaddi_du: - case LoongArch::BI__builtin_lasx_xvbitclri_w: - case LoongArch::BI__builtin_lasx_xvbitrevi_w: - case LoongArch::BI__builtin_lasx_xvbitseti_w: - case LoongArch::BI__builtin_lasx_xvsat_w: - case LoongArch::BI__builtin_lasx_xvsat_wu: - case LoongArch::BI__builtin_lasx_xvslli_w: - case LoongArch::BI__builtin_lasx_xvsrai_w: - case LoongArch::BI__builtin_lasx_xvsrari_w: - case LoongArch::BI__builtin_lasx_xvsrli_w: - case LoongArch::BI__builtin_lasx_xvsllwil_d_w: - case LoongArch::BI__builtin_lasx_xvsllwil_du_wu: - case LoongArch::BI__builtin_lasx_xvsrlri_w: - case LoongArch::BI__builtin_lasx_xvrotri_w: - case LoongArch::BI__builtin_lasx_xvsubi_bu: - case LoongArch::BI__builtin_lasx_xvsubi_hu: - case LoongArch::BI__builtin_lasx_xvsubi_wu: - case LoongArch::BI__builtin_lasx_xvsubi_du: - case LoongArch::BI__builtin_lasx_xvbsrl_v: - case LoongArch::BI__builtin_lasx_xvbsll_v: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_lasx_xvssrarni_h_w: - case LoongArch::BI__builtin_lasx_xvssrarni_hu_w: - case LoongArch::BI__builtin_lasx_xvssrani_h_w: - case LoongArch::BI__builtin_lasx_xvssrani_hu_w: - case LoongArch::BI__builtin_lasx_xvsrarni_h_w: - case LoongArch::BI__builtin_lasx_xvsrani_h_w: - case LoongArch::BI__builtin_lasx_xvfrstpi_b: - case LoongArch::BI__builtin_lasx_xvfrstpi_h: - case LoongArch::BI__builtin_lasx_xvsrlni_h_w: - case LoongArch::BI__builtin_lasx_xvsrlrni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlni_hu_w: - case LoongArch::BI__builtin_lasx_xvssrlrni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlrni_hu_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 31); - case LoongArch::BI__builtin_lasx_xvbitclri_d: - case LoongArch::BI__builtin_lasx_xvbitrevi_d: - case LoongArch::BI__builtin_lasx_xvbitseti_d: - case LoongArch::BI__builtin_lasx_xvsat_d: - case LoongArch::BI__builtin_lasx_xvsat_du: - case LoongArch::BI__builtin_lasx_xvslli_d: - case LoongArch::BI__builtin_lasx_xvsrai_d: - case LoongArch::BI__builtin_lasx_xvsrli_d: - case LoongArch::BI__builtin_lasx_xvsrari_d: - case LoongArch::BI__builtin_lasx_xvrotri_d: - case LoongArch::BI__builtin_lasx_xvsrlri_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 63); - case LoongArch::BI__builtin_lasx_xvssrarni_w_d: - case LoongArch::BI__builtin_lasx_xvssrarni_wu_d: - case LoongArch::BI__builtin_lasx_xvssrani_w_d: - case LoongArch::BI__builtin_lasx_xvssrani_wu_d: - case LoongArch::BI__builtin_lasx_xvsrarni_w_d: - case LoongArch::BI__builtin_lasx_xvsrlni_w_d: - case LoongArch::BI__builtin_lasx_xvsrlrni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlni_wu_d: - case LoongArch::BI__builtin_lasx_xvssrlrni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlrni_wu_d: - case LoongArch::BI__builtin_lasx_xvsrani_w_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 63); - case LoongArch::BI__builtin_lasx_xvssrarni_d_q: - case LoongArch::BI__builtin_lasx_xvssrarni_du_q: - case LoongArch::BI__builtin_lasx_xvssrani_d_q: - case LoongArch::BI__builtin_lasx_xvssrani_du_q: - case LoongArch::BI__builtin_lasx_xvsrarni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlni_du_q: - case LoongArch::BI__builtin_lasx_xvssrlrni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlrni_du_q: - case LoongArch::BI__builtin_lasx_xvsrani_d_q: - case LoongArch::BI__builtin_lasx_xvsrlni_d_q: - case LoongArch::BI__builtin_lasx_xvsrlrni_d_q: - return BuiltinConstantArgRange(TheCall, 2, 0, 127); - case LoongArch::BI__builtin_lasx_xvseqi_b: - case LoongArch::BI__builtin_lasx_xvseqi_h: - case LoongArch::BI__builtin_lasx_xvseqi_w: - case LoongArch::BI__builtin_lasx_xvseqi_d: - case LoongArch::BI__builtin_lasx_xvslti_b: - case LoongArch::BI__builtin_lasx_xvslti_h: - case LoongArch::BI__builtin_lasx_xvslti_w: - case LoongArch::BI__builtin_lasx_xvslti_d: - case LoongArch::BI__builtin_lasx_xvslei_b: - case LoongArch::BI__builtin_lasx_xvslei_h: - case LoongArch::BI__builtin_lasx_xvslei_w: - case LoongArch::BI__builtin_lasx_xvslei_d: - case LoongArch::BI__builtin_lasx_xvmaxi_b: - case LoongArch::BI__builtin_lasx_xvmaxi_h: - case LoongArch::BI__builtin_lasx_xvmaxi_w: - case LoongArch::BI__builtin_lasx_xvmaxi_d: - case LoongArch::BI__builtin_lasx_xvmini_b: - case LoongArch::BI__builtin_lasx_xvmini_h: - case LoongArch::BI__builtin_lasx_xvmini_w: - case LoongArch::BI__builtin_lasx_xvmini_d: - return BuiltinConstantArgRange(TheCall, 1, -16, 15); - case LoongArch::BI__builtin_lasx_xvandi_b: - case LoongArch::BI__builtin_lasx_xvnori_b: - case LoongArch::BI__builtin_lasx_xvori_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_h: - case LoongArch::BI__builtin_lasx_xvshuf4i_w: - case LoongArch::BI__builtin_lasx_xvxori_b: - case LoongArch::BI__builtin_lasx_xvpermi_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 255); - case LoongArch::BI__builtin_lasx_xvbitseli_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_d: - case LoongArch::BI__builtin_lasx_xvextrins_b: - case LoongArch::BI__builtin_lasx_xvextrins_h: - case LoongArch::BI__builtin_lasx_xvextrins_w: - case LoongArch::BI__builtin_lasx_xvextrins_d: - case LoongArch::BI__builtin_lasx_xvpermi_q: - case LoongArch::BI__builtin_lasx_xvpermi_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 255); - case LoongArch::BI__builtin_lasx_xvrepl128vei_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lasx_xvrepl128vei_h: - case LoongArch::BI__builtin_lasx_xvpickve2gr_w: - case LoongArch::BI__builtin_lasx_xvpickve2gr_wu: - case LoongArch::BI__builtin_lasx_xvpickve_w_f: - case LoongArch::BI__builtin_lasx_xvpickve_w: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lasx_xvinsgr2vr_w: - case LoongArch::BI__builtin_lasx_xvinsve0_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case LoongArch::BI__builtin_lasx_xvrepl128vei_w: - case LoongArch::BI__builtin_lasx_xvpickve2gr_d: - case LoongArch::BI__builtin_lasx_xvpickve2gr_du: - case LoongArch::BI__builtin_lasx_xvpickve_d_f: - case LoongArch::BI__builtin_lasx_xvpickve_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case LoongArch::BI__builtin_lasx_xvinsve0_d: - case LoongArch::BI__builtin_lasx_xvinsgr2vr_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case LoongArch::BI__builtin_lasx_xvstelm_b: - return BuiltinConstantArgRange(TheCall, 2, -128, 127) || - BuiltinConstantArgRange(TheCall, 3, 0, 31); - case LoongArch::BI__builtin_lasx_xvstelm_h: - return BuiltinConstantArgRange(TheCall, 2, -256, 254) || - BuiltinConstantArgRange(TheCall, 3, 0, 15); - case LoongArch::BI__builtin_lasx_xvstelm_w: - return BuiltinConstantArgRange(TheCall, 2, -512, 508) || - BuiltinConstantArgRange(TheCall, 3, 0, 7); - case LoongArch::BI__builtin_lasx_xvstelm_d: - return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - BuiltinConstantArgRange(TheCall, 3, 0, 3); - case LoongArch::BI__builtin_lasx_xvrepl128vei_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case LoongArch::BI__builtin_lasx_xvldrepl_b: - case LoongArch::BI__builtin_lasx_xvld: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); - case LoongArch::BI__builtin_lasx_xvldrepl_h: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); - case LoongArch::BI__builtin_lasx_xvldrepl_w: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); - case LoongArch::BI__builtin_lasx_xvldrepl_d: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); - case LoongArch::BI__builtin_lasx_xvst: - return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); - case LoongArch::BI__builtin_lasx_xvldi: - return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); - case LoongArch::BI__builtin_lasx_xvrepli_b: - case LoongArch::BI__builtin_lasx_xvrepli_h: - case LoongArch::BI__builtin_lasx_xvrepli_w: - case LoongArch::BI__builtin_lasx_xvrepli_d: - return BuiltinConstantArgRange(TheCall, 0, -512, 511); - } - return false; -} - -bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, CallExpr *TheCall) { - return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) || - CheckMipsBuiltinArgument(BuiltinID, TheCall); -} - -bool Sema::CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - - if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && - BuiltinID <= Mips::BI__builtin_mips_lwx) { - if (!TI.hasFeature("dsp")) - return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp); - } - - if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID && - BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) { - if (!TI.hasFeature("dspr2")) - return Diag(TheCall->getBeginLoc(), - diag::err_mips_builtin_requires_dspr2); - } - - if (Mips::BI__builtin_msa_add_a_b <= BuiltinID && - BuiltinID <= Mips::BI__builtin_msa_xori_b) { - if (!TI.hasFeature("msa")) - return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa); - } - - return false; -} - -// CheckMipsBuiltinArgument - Checks the constant value passed to the -// intrinsic is correct. The switch statement is ordered by DSP, MSA. The -// ordering for DSP is unspecified. MSA is ordered by the data format used -// by the underlying instruction i.e., df/m, df/n and then by size. -// -// FIXME: The size tests here should instead be tablegen'd along with the -// definitions from include/clang/Basic/BuiltinsMips.def. -// FIXME: GCC is strict on signedness for some of these intrinsics, we should -// be too. -bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0, m = 0; - switch (BuiltinID) { - default: return false; - case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; - case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break; - case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break; - case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; - // MSA intrinsics. Instructions (which the intrinsics maps to) which use the - // df/m field. - // These intrinsics take an unsigned 3 bit immediate. - case Mips::BI__builtin_msa_bclri_b: - case Mips::BI__builtin_msa_bnegi_b: - case Mips::BI__builtin_msa_bseti_b: - case Mips::BI__builtin_msa_sat_s_b: - case Mips::BI__builtin_msa_sat_u_b: - case Mips::BI__builtin_msa_slli_b: - case Mips::BI__builtin_msa_srai_b: - case Mips::BI__builtin_msa_srari_b: - case Mips::BI__builtin_msa_srli_b: - case Mips::BI__builtin_msa_srlri_b: i = 1; l = 0; u = 7; break; - case Mips::BI__builtin_msa_binsli_b: - case Mips::BI__builtin_msa_binsri_b: i = 2; l = 0; u = 7; break; - // These intrinsics take an unsigned 4 bit immediate. - case Mips::BI__builtin_msa_bclri_h: - case Mips::BI__builtin_msa_bnegi_h: - case Mips::BI__builtin_msa_bseti_h: - case Mips::BI__builtin_msa_sat_s_h: - case Mips::BI__builtin_msa_sat_u_h: - case Mips::BI__builtin_msa_slli_h: - case Mips::BI__builtin_msa_srai_h: - case Mips::BI__builtin_msa_srari_h: - case Mips::BI__builtin_msa_srli_h: - case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; - case Mips::BI__builtin_msa_binsli_h: - case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 5 bit immediate. - // The first block of intrinsics actually have an unsigned 5 bit field, - // not a df/n field. - case Mips::BI__builtin_msa_cfcmsa: - case Mips::BI__builtin_msa_ctcmsa: i = 0; l = 0; u = 31; break; - case Mips::BI__builtin_msa_clei_u_b: - case Mips::BI__builtin_msa_clei_u_h: - case Mips::BI__builtin_msa_clei_u_w: - case Mips::BI__builtin_msa_clei_u_d: - case Mips::BI__builtin_msa_clti_u_b: - case Mips::BI__builtin_msa_clti_u_h: - case Mips::BI__builtin_msa_clti_u_w: - case Mips::BI__builtin_msa_clti_u_d: - case Mips::BI__builtin_msa_maxi_u_b: - case Mips::BI__builtin_msa_maxi_u_h: - case Mips::BI__builtin_msa_maxi_u_w: - case Mips::BI__builtin_msa_maxi_u_d: - case Mips::BI__builtin_msa_mini_u_b: - case Mips::BI__builtin_msa_mini_u_h: - case Mips::BI__builtin_msa_mini_u_w: - case Mips::BI__builtin_msa_mini_u_d: - case Mips::BI__builtin_msa_addvi_b: - case Mips::BI__builtin_msa_addvi_h: - case Mips::BI__builtin_msa_addvi_w: - case Mips::BI__builtin_msa_addvi_d: - case Mips::BI__builtin_msa_bclri_w: - case Mips::BI__builtin_msa_bnegi_w: - case Mips::BI__builtin_msa_bseti_w: - case Mips::BI__builtin_msa_sat_s_w: - case Mips::BI__builtin_msa_sat_u_w: - case Mips::BI__builtin_msa_slli_w: - case Mips::BI__builtin_msa_srai_w: - case Mips::BI__builtin_msa_srari_w: - case Mips::BI__builtin_msa_srli_w: - case Mips::BI__builtin_msa_srlri_w: - case Mips::BI__builtin_msa_subvi_b: - case Mips::BI__builtin_msa_subvi_h: - case Mips::BI__builtin_msa_subvi_w: - case Mips::BI__builtin_msa_subvi_d: i = 1; l = 0; u = 31; break; - case Mips::BI__builtin_msa_binsli_w: - case Mips::BI__builtin_msa_binsri_w: i = 2; l = 0; u = 31; break; - // These intrinsics take an unsigned 6 bit immediate. - case Mips::BI__builtin_msa_bclri_d: - case Mips::BI__builtin_msa_bnegi_d: - case Mips::BI__builtin_msa_bseti_d: - case Mips::BI__builtin_msa_sat_s_d: - case Mips::BI__builtin_msa_sat_u_d: - case Mips::BI__builtin_msa_slli_d: - case Mips::BI__builtin_msa_srai_d: - case Mips::BI__builtin_msa_srari_d: - case Mips::BI__builtin_msa_srli_d: - case Mips::BI__builtin_msa_srlri_d: i = 1; l = 0; u = 63; break; - case Mips::BI__builtin_msa_binsli_d: - case Mips::BI__builtin_msa_binsri_d: i = 2; l = 0; u = 63; break; - // These intrinsics take a signed 5 bit immediate. - case Mips::BI__builtin_msa_ceqi_b: - case Mips::BI__builtin_msa_ceqi_h: - case Mips::BI__builtin_msa_ceqi_w: - case Mips::BI__builtin_msa_ceqi_d: - case Mips::BI__builtin_msa_clti_s_b: - case Mips::BI__builtin_msa_clti_s_h: - case Mips::BI__builtin_msa_clti_s_w: - case Mips::BI__builtin_msa_clti_s_d: - case Mips::BI__builtin_msa_clei_s_b: - case Mips::BI__builtin_msa_clei_s_h: - case Mips::BI__builtin_msa_clei_s_w: - case Mips::BI__builtin_msa_clei_s_d: - case Mips::BI__builtin_msa_maxi_s_b: - case Mips::BI__builtin_msa_maxi_s_h: - case Mips::BI__builtin_msa_maxi_s_w: - case Mips::BI__builtin_msa_maxi_s_d: - case Mips::BI__builtin_msa_mini_s_b: - case Mips::BI__builtin_msa_mini_s_h: - case Mips::BI__builtin_msa_mini_s_w: - case Mips::BI__builtin_msa_mini_s_d: i = 1; l = -16; u = 15; break; - // These intrinsics take an unsigned 8 bit immediate. - case Mips::BI__builtin_msa_andi_b: - case Mips::BI__builtin_msa_nori_b: - case Mips::BI__builtin_msa_ori_b: - case Mips::BI__builtin_msa_shf_b: - case Mips::BI__builtin_msa_shf_h: - case Mips::BI__builtin_msa_shf_w: - case Mips::BI__builtin_msa_xori_b: i = 1; l = 0; u = 255; break; - case Mips::BI__builtin_msa_bseli_b: - case Mips::BI__builtin_msa_bmnzi_b: - case Mips::BI__builtin_msa_bmzi_b: i = 2; l = 0; u = 255; break; - // df/n format - // These intrinsics take an unsigned 4 bit immediate. - case Mips::BI__builtin_msa_copy_s_b: - case Mips::BI__builtin_msa_copy_u_b: - case Mips::BI__builtin_msa_insve_b: - case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break; - case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 3 bit immediate. - case Mips::BI__builtin_msa_copy_s_h: - case Mips::BI__builtin_msa_copy_u_h: - case Mips::BI__builtin_msa_insve_h: - case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break; - case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break; - // These intrinsics take an unsigned 2 bit immediate. - case Mips::BI__builtin_msa_copy_s_w: - case Mips::BI__builtin_msa_copy_u_w: - case Mips::BI__builtin_msa_insve_w: - case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break; - case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break; - // These intrinsics take an unsigned 1 bit immediate. - case Mips::BI__builtin_msa_copy_s_d: - case Mips::BI__builtin_msa_copy_u_d: - case Mips::BI__builtin_msa_insve_d: - case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break; - case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break; - // Memory offsets and immediate loads. - // These intrinsics take a signed 10 bit immediate. - case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 255; break; - case Mips::BI__builtin_msa_ldi_h: - case Mips::BI__builtin_msa_ldi_w: - case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break; - case Mips::BI__builtin_msa_ld_b: i = 1; l = -512; u = 511; m = 1; break; - case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 2; break; - case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_ldr_d: i = 1; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_ldr_w: i = 1; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 1; break; - case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 2; break; - case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_str_d: i = 2; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_str_w: i = 2; l = -2048; u = 2044; m = 4; break; - } - - if (!m) - return BuiltinConstantArgRange(TheCall, i, l, u); - - return BuiltinConstantArgRange(TheCall, i, l, u) || - BuiltinConstantArgMultiple(TheCall, i, m); -} - -/// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, -/// advancing the pointer over the consumed characters. The decoded type is -/// returned. If the decoded type represents a constant integer with a -/// constraint on its value then Mask is set to that value. The type descriptors -/// used in Str are specific to PPC MMA builtins and are documented in the file -/// defining the PPC builtins. -static QualType DecodePPCMMATypeFromStr(ASTContext &Context, const char *&Str, - unsigned &Mask) { - bool RequireICE = false; - ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; - switch (*Str++) { - case 'V': - return Context.getVectorType(Context.UnsignedCharTy, 16, - VectorKind::AltiVecVector); - case 'i': { - char *End; - unsigned size = strtoul(Str, &End, 10); - assert(End != Str && "Missing constant parameter constraint"); - Str = End; - Mask = size; - return Context.IntTy; - } - case 'W': { - char *End; - unsigned size = strtoul(Str, &End, 10); - assert(End != Str && "Missing PowerPC MMA type size"); - Str = End; - QualType Type; - switch (size) { - #define PPC_VECTOR_TYPE(typeName, Id, size) \ - case size: Type = Context.Id##Ty; break; - #include "clang/Basic/PPCTypes.def" - default: llvm_unreachable("Invalid PowerPC MMA vector type"); - } - bool CheckVectorArgs = false; - while (!CheckVectorArgs) { - switch (*Str++) { - case '*': - Type = Context.getPointerType(Type); - break; - case 'C': - Type = Type.withConst(); - break; - default: - CheckVectorArgs = true; - --Str; - break; - } - } - return Type; - } - default: - return Context.DecodeTypeStr(--Str, Context, Error, RequireICE, true); - } -} - -static bool isPPC_64Builtin(unsigned BuiltinID) { - // These builtins only work on PPC 64bit targets. - switch (BuiltinID) { - case PPC::BI__builtin_divde: - case PPC::BI__builtin_divdeu: - case PPC::BI__builtin_bpermd: - case PPC::BI__builtin_pdepd: - case PPC::BI__builtin_pextd: - case PPC::BI__builtin_ppc_ldarx: - case PPC::BI__builtin_ppc_stdcx: - case PPC::BI__builtin_ppc_tdw: - case PPC::BI__builtin_ppc_trapd: - case PPC::BI__builtin_ppc_cmpeqb: - case PPC::BI__builtin_ppc_setb: - case PPC::BI__builtin_ppc_mulhd: - case PPC::BI__builtin_ppc_mulhdu: - case PPC::BI__builtin_ppc_maddhd: - case PPC::BI__builtin_ppc_maddhdu: - case PPC::BI__builtin_ppc_maddld: - case PPC::BI__builtin_ppc_load8r: - case PPC::BI__builtin_ppc_store8r: - case PPC::BI__builtin_ppc_insert_exp: - case PPC::BI__builtin_ppc_extract_sig: - case PPC::BI__builtin_ppc_addex: - case PPC::BI__builtin_darn: - case PPC::BI__builtin_darn_raw: - case PPC::BI__builtin_ppc_compare_and_swaplp: - case PPC::BI__builtin_ppc_fetch_and_addlp: - case PPC::BI__builtin_ppc_fetch_and_andlp: - case PPC::BI__builtin_ppc_fetch_and_orlp: - case PPC::BI__builtin_ppc_fetch_and_swaplp: - return true; - } - return false; -} - -/// Returns true if the argument consists of one contiguous run of 1s with any -/// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so -/// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, -/// since all 1s are not contiguous. -bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { - llvm::APSInt Result; - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check constant-ness first. - if (BuiltinConstantArg(TheCall, ArgNum, Result)) - return true; - - // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s. - if (Result.isShiftedMask() || (~Result).isShiftedMask()) - return false; - - return Diag(TheCall->getBeginLoc(), - diag::err_argument_not_contiguous_bit_field) - << ArgNum << Arg->getSourceRange(); -} - -bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; - bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; - llvm::APSInt Result; - - if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit) - return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) - << TheCall->getSourceRange(); - - switch (BuiltinID) { - default: return false; - case PPC::BI__builtin_altivec_crypto_vshasigmaw: - case PPC::BI__builtin_altivec_crypto_vshasigmad: - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 15); - case PPC::BI__builtin_altivec_dss: - return BuiltinConstantArgRange(TheCall, 0, 0, 3); - case PPC::BI__builtin_tbegin: - case PPC::BI__builtin_tend: - return BuiltinConstantArgRange(TheCall, 0, 0, 1); - case PPC::BI__builtin_tsr: - return BuiltinConstantArgRange(TheCall, 0, 0, 7); - case PPC::BI__builtin_tabortwc: - case PPC::BI__builtin_tabortdc: - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - case PPC::BI__builtin_tabortwci: - case PPC::BI__builtin_tabortdci: - return BuiltinConstantArgRange(TheCall, 0, 0, 31) || - BuiltinConstantArgRange(TheCall, 2, 0, 31); - // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', - // __builtin_(un)pack_longdouble are available only if long double uses IBM - // extended double representation. - case PPC::BI__builtin_unpack_longdouble: - if (BuiltinConstantArgRange(TheCall, 1, 0, 1)) - return true; - [[fallthrough]]; - case PPC::BI__builtin_pack_longdouble: - if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) - return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) - << "ibmlongdouble"; - return false; - case PPC::BI__builtin_altivec_dst: - case PPC::BI__builtin_altivec_dstt: - case PPC::BI__builtin_altivec_dstst: - case PPC::BI__builtin_altivec_dststt: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case PPC::BI__builtin_vsx_xxpermdi: - case PPC::BI__builtin_vsx_xxsldwi: - return BuiltinVSX(TheCall); - case PPC::BI__builtin_unpack_vector_int128: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_altivec_vgnb: - return BuiltinConstantArgRange(TheCall, 1, 2, 7); - case PPC::BI__builtin_vsx_xxeval: - return BuiltinConstantArgRange(TheCall, 3, 0, 255); - case PPC::BI__builtin_altivec_vsldbi: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case PPC::BI__builtin_altivec_vsrdbi: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case PPC::BI__builtin_vsx_xxpermx: - return BuiltinConstantArgRange(TheCall, 3, 0, 7); - case PPC::BI__builtin_ppc_tw: - case PPC::BI__builtin_ppc_tdw: - return BuiltinConstantArgRange(TheCall, 2, 1, 31); - case PPC::BI__builtin_ppc_cmprb: - return BuiltinConstantArgRange(TheCall, 0, 0, 1); - // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must - // be a constant that represents a contiguous bit field. - case PPC::BI__builtin_ppc_rlwnm: - return ValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_ppc_rlwimi: - return BuiltinConstantArgRange(TheCall, 2, 0, 31) || - ValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_rldimi: - return BuiltinConstantArgRange(TheCall, 2, 0, 63) || - ValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_addex: { - if (BuiltinConstantArgRange(TheCall, 2, 0, 3)) - return true; - // Output warning for reserved values 1 to 3. - int ArgValue = - TheCall->getArg(2)->getIntegerConstantExpr(Context)->getSExtValue(); - if (ArgValue != 0) - Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour) - << ArgValue; - return false; - } - case PPC::BI__builtin_ppc_mtfsb0: - case PPC::BI__builtin_ppc_mtfsb1: - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - case PPC::BI__builtin_ppc_mtfsf: - return BuiltinConstantArgRange(TheCall, 0, 0, 255); - case PPC::BI__builtin_ppc_mtfsfi: - return BuiltinConstantArgRange(TheCall, 0, 0, 7) || - BuiltinConstantArgRange(TheCall, 1, 0, 15); - case PPC::BI__builtin_ppc_alignx: - return BuiltinConstantArgPower2(TheCall, 0); - case PPC::BI__builtin_ppc_rdlam: - return ValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_vsx_ldrmb: - case PPC::BI__builtin_vsx_strmb: - return BuiltinConstantArgRange(TheCall, 1, 1, 16); - case PPC::BI__builtin_altivec_vcntmbb: - case PPC::BI__builtin_altivec_vcntmbh: - case PPC::BI__builtin_altivec_vcntmbw: - case PPC::BI__builtin_altivec_vcntmbd: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_vsx_xxgenpcvbm: - case PPC::BI__builtin_vsx_xxgenpcvhm: - case PPC::BI__builtin_vsx_xxgenpcvwm: - case PPC::BI__builtin_vsx_xxgenpcvdm: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case PPC::BI__builtin_ppc_test_data_class: { - // Check if the first argument of the __builtin_ppc_test_data_class call is - // valid. The argument must be 'float' or 'double' or '__float128'. - QualType ArgType = TheCall->getArg(0)->getType(); - if (ArgType != QualType(Context.FloatTy) && - ArgType != QualType(Context.DoubleTy) && - ArgType != QualType(Context.Float128Ty)) - return Diag(TheCall->getBeginLoc(), - diag::err_ppc_invalid_test_data_class_type); - return BuiltinConstantArgRange(TheCall, 1, 0, 127); - } - case PPC::BI__builtin_ppc_maxfe: - case PPC::BI__builtin_ppc_minfe: - case PPC::BI__builtin_ppc_maxfl: - case PPC::BI__builtin_ppc_minfl: - case PPC::BI__builtin_ppc_maxfs: - case PPC::BI__builtin_ppc_minfs: { - if (Context.getTargetInfo().getTriple().isOSAIX() && - (BuiltinID == PPC::BI__builtin_ppc_maxfe || - BuiltinID == PPC::BI__builtin_ppc_minfe)) - return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type) - << "builtin" << true << 128 << QualType(Context.LongDoubleTy) - << false << Context.getTargetInfo().getTriple().str(); - // Argument type should be exact. - QualType ArgType = QualType(Context.LongDoubleTy); - if (BuiltinID == PPC::BI__builtin_ppc_maxfl || - BuiltinID == PPC::BI__builtin_ppc_minfl) - ArgType = QualType(Context.DoubleTy); - else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || - BuiltinID == PPC::BI__builtin_ppc_minfs) - ArgType = QualType(Context.FloatTy); - for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) - if (TheCall->getArg(I)->getType() != ArgType) - return Diag(TheCall->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; - return false; - } -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ - case PPC::BI__builtin_##Name: \ - return BuiltinPPCMMACall(TheCall, BuiltinID, Types); -#include "clang/Basic/BuiltinsPPC.def" - } - return BuiltinConstantArgRange(TheCall, i, l, u); -} - -// Check if the given type is a non-pointer PPC MMA type. This function is used -// in Sema to prevent invalid uses of restricted PPC MMA types. -bool Sema::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) { - if (Type->isPointerType() || Type->isArrayType()) - return false; - - QualType CoreType = Type.getCanonicalType().getUnqualifiedType(); -#define PPC_VECTOR_TYPE(Name, Id, Size) || CoreType == Context.Id##Ty - if (false -#include "clang/Basic/PPCTypes.def" - ) { - Diag(TypeLoc, diag::err_ppc_invalid_use_mma_type); - return true; - } - return false; -} - -// Helper function for CheckHLSLBuiltinFunctionCall -bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { - assert(TheCall->getNumArgs() > 1); - ExprResult A = TheCall->getArg(0); - - QualType ArgTyA = A.get()->getType(); - - auto *VecTyA = ArgTyA->getAs(); - SourceLocation BuiltinLoc = TheCall->getBeginLoc(); - - for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) { - ExprResult B = TheCall->getArg(i); - QualType ArgTyB = B.get()->getType(); - auto *VecTyB = ArgTyB->getAs(); - if (VecTyA == nullptr && VecTyB == nullptr) - return false; - - if (VecTyA && VecTyB) { - bool retValue = false; - if (VecTyA->getElementType() != VecTyB->getElementType()) { - // Note: type promotion is intended to be handeled via the intrinsics - // and not the builtin itself. - S->Diag(TheCall->getBeginLoc(), - diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); - retValue = true; - } - if (VecTyA->getNumElements() != VecTyB->getNumElements()) { - // You should only be hitting this case if you are calling the builtin - // directly. HLSL intrinsics should avoid this case via a - // HLSLVectorTruncation. - S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - retValue = true; - } - return retValue; - } - } - - // Note: if we get here one of the args is a scalar which - // requires a VectorSplat on Arg0 or Arg1 - S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - return true; -} - -bool CheckArgsTypesAreCorrect( - Sema *S, CallExpr *TheCall, QualType ExpectedType, - llvm::function_ref Check) { - for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { - QualType PassedType = TheCall->getArg(i)->getType(); - if (Check(PassedType)) { - if (auto *VecTyA = PassedType->getAs()) - ExpectedType = S->Context.getVectorType( - ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); - S->Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << PassedType << ExpectedType << 1 << 0 << 0; - return true; - } - } - return false; -} - -bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { - auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { - return !PassedType->hasFloatingRepresentation(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkAllFloatTypes); -} - -bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { - auto checkFloatorHalf = [](clang::QualType PassedType) -> bool { - clang::QualType BaseType = - PassedType->isVectorType() - ? PassedType->getAs()->getElementType() - : PassedType; - return !BaseType->isHalfType() && !BaseType->isFloat32Type(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkFloatorHalf); -} - -bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { - auto checkDoubleVector = [](clang::QualType PassedType) -> bool { - if (const auto *VecTy = PassedType->getAs()) - return VecTy->getElementType()->isDoubleType(); - return false; - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkDoubleVector); -} - -bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { - auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { - return !PassedType->hasUnsignedIntegerRepresentation(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, - checkAllUnsignedTypes); -} - -void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, - QualType ReturnType) { - auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); - if (VecTyA) - ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), - VectorKind::Generic); - TheCall->setType(ReturnType); -} - -// Note: returning true in this case results in CheckBuiltinFunctionCall -// returning an ExprError -bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - case Builtin::BI__builtin_hlsl_elementwise_all: - case Builtin::BI__builtin_hlsl_elementwise_any: { - if (checkArgCount(*this, TheCall, 1)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_clamp: { - if (checkArgCount(*this, TheCall, 3)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinElementwiseTernaryMath( - TheCall, /*CheckForFloatArgs*/ - TheCall->getArg(0)->getType()->hasFloatingRepresentation())) - return true; - break; - } - case Builtin::BI__builtin_hlsl_dot: { - if (checkArgCount(*this, TheCall, 2)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinVectorToScalarMath(TheCall)) - return true; - if (CheckNoDoubleVectors(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_rcp: { - if (CheckAllArgsHaveFloatRepresentation(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_rsqrt: - case Builtin::BI__builtin_hlsl_elementwise_frac: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_isinf: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy); - break; + case Builtin::BI__builtin_hlsl_elementwise_isinf: { + if (CheckFloatOrHalfRepresentations(this, TheCall)) + return true; + if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy); + break; } case Builtin::BI__builtin_hlsl_lerp: { - if (checkArgCount(*this, TheCall, 3)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinElementwiseTernaryMath(TheCall)) - return true; - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_mad: { - if (checkArgCount(*this, TheCall, 3)) + if (checkArgCount(TheCall, 3)) return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (BuiltinElementwiseTernaryMath( - TheCall, /*CheckForFloatArgs*/ - TheCall->getArg(0)->getType()->hasFloatingRepresentation())) - return true; - break; - } - // Note these are llvm builtins that we want to catch invalid intrinsic - // generation. Normal handling of these builitns will occur elsewhere. - case Builtin::BI__builtin_elementwise_bitreverse: { - if (CheckUnsignedIntRepresentation(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_elementwise_ceil: - case Builtin::BI__builtin_elementwise_cos: - case Builtin::BI__builtin_elementwise_exp: - case Builtin::BI__builtin_elementwise_exp2: - case Builtin::BI__builtin_elementwise_floor: - case Builtin::BI__builtin_elementwise_log: - case Builtin::BI__builtin_elementwise_log2: - case Builtin::BI__builtin_elementwise_log10: - case Builtin::BI__builtin_elementwise_pow: - case Builtin::BI__builtin_elementwise_roundeven: - case Builtin::BI__builtin_elementwise_sin: - case Builtin::BI__builtin_elementwise_sqrt: - case Builtin::BI__builtin_elementwise_tan: - case Builtin::BI__builtin_elementwise_trunc: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - break; - } - } - return false; -} - -bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - // position of memory order and scope arguments in the builtin - unsigned OrderIndex, ScopeIndex; - switch (BuiltinID) { - case AMDGPU::BI__builtin_amdgcn_get_fpenv: - case AMDGPU::BI__builtin_amdgcn_set_fpenv: - return false; - case AMDGPU::BI__builtin_amdgcn_atomic_inc32: - case AMDGPU::BI__builtin_amdgcn_atomic_inc64: - case AMDGPU::BI__builtin_amdgcn_atomic_dec32: - case AMDGPU::BI__builtin_amdgcn_atomic_dec64: - OrderIndex = 2; - ScopeIndex = 3; - break; - case AMDGPU::BI__builtin_amdgcn_fence: - OrderIndex = 0; - ScopeIndex = 1; - break; - default: - return false; - } - - ExprResult Arg = TheCall->getArg(OrderIndex); - auto ArgExpr = Arg.get(); - Expr::EvalResult ArgResult; - - if (!ArgExpr->EvaluateAsInt(ArgResult, Context)) - return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int) - << ArgExpr->getType(); - auto Ord = ArgResult.Val.getInt().getZExtValue(); - - // Check validity of memory ordering as per C11 / C++11's memody model. - // Only fence needs check. Atomic dec/inc allow all memory orders. - if (!llvm::isValidAtomicOrderingCABI(Ord)) - return Diag(ArgExpr->getBeginLoc(), - diag::warn_atomic_op_has_invalid_memory_order) - << 0 << ArgExpr->getSourceRange(); - switch (static_cast(Ord)) { - case llvm::AtomicOrderingCABI::relaxed: - case llvm::AtomicOrderingCABI::consume: - if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence) - return Diag(ArgExpr->getBeginLoc(), - diag::warn_atomic_op_has_invalid_memory_order) - << 0 << ArgExpr->getSourceRange(); - break; - case llvm::AtomicOrderingCABI::acquire: - case llvm::AtomicOrderingCABI::release: - case llvm::AtomicOrderingCABI::acq_rel: - case llvm::AtomicOrderingCABI::seq_cst: - break; - } - - Arg = TheCall->getArg(ScopeIndex); - ArgExpr = Arg.get(); - Expr::EvalResult ArgResult1; - // Check that sync scope is a constant literal - if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, Context)) - return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal) - << ArgExpr->getType(); - - return false; -} - -bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) { - llvm::APSInt Result; - - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check constant-ness first. - if (BuiltinConstantArg(TheCall, ArgNum, Result)) - return true; - - int64_t Val = Result.getSExtValue(); - if ((Val >= 0 && Val <= 3) || (Val >= 5 && Val <= 7)) - return false; - - return Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_invalid_lmul) - << Arg->getSourceRange(); -} - -static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall, - Sema &S, QualType Type, int EGW) { - assert((EGW == 128 || EGW == 256) && "EGW can only be 128 or 256 bits"); - - // LMUL * VLEN >= EGW - ASTContext::BuiltinVectorTypeInfo Info = - S.Context.getBuiltinVectorTypeInfo(Type->castAs()); - unsigned ElemSize = S.Context.getTypeSize(Info.ElementType); - unsigned MinElemCount = Info.EC.getKnownMinValue(); - - unsigned EGS = EGW / ElemSize; - // If EGS is less than or equal to the minimum number of elements, then the - // type is valid. - if (EGS <= MinElemCount) - return false; - - // Otherwise, we need vscale to be at least EGS / MinElemCont. - assert(EGS % MinElemCount == 0); - unsigned VScaleFactor = EGS / MinElemCount; - // Vscale is VLEN/RVVBitsPerBlock. - unsigned MinRequiredVLEN = VScaleFactor * llvm::RISCV::RVVBitsPerBlock; - std::string RequiredExt = "zvl" + std::to_string(MinRequiredVLEN) + "b"; - if (!TI.hasFeature(RequiredExt)) - return S.Diag(TheCall->getBeginLoc(), - diag::err_riscv_type_requires_extension) << Type << RequiredExt; - - return false; -} - -bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, - // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. - switch (BuiltinID) { - default: - break; - case RISCVVector::BI__builtin_rvv_vmulhsu_vv: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx: - case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tu: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tu: - case RISCVVector::BI__builtin_rvv_vmulhsu_vv_m: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx_m: - case RISCVVector::BI__builtin_rvv_vmulhsu_vv_mu: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx_mu: - case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tum: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tum: - case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tumu: - case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tumu: - case RISCVVector::BI__builtin_rvv_vmulhu_vv: - case RISCVVector::BI__builtin_rvv_vmulhu_vx: - case RISCVVector::BI__builtin_rvv_vmulhu_vv_tu: - case RISCVVector::BI__builtin_rvv_vmulhu_vx_tu: - case RISCVVector::BI__builtin_rvv_vmulhu_vv_m: - case RISCVVector::BI__builtin_rvv_vmulhu_vx_m: - case RISCVVector::BI__builtin_rvv_vmulhu_vv_mu: - case RISCVVector::BI__builtin_rvv_vmulhu_vx_mu: - case RISCVVector::BI__builtin_rvv_vmulhu_vv_tum: - case RISCVVector::BI__builtin_rvv_vmulhu_vx_tum: - case RISCVVector::BI__builtin_rvv_vmulhu_vv_tumu: - case RISCVVector::BI__builtin_rvv_vmulhu_vx_tumu: - case RISCVVector::BI__builtin_rvv_vmulh_vv: - case RISCVVector::BI__builtin_rvv_vmulh_vx: - case RISCVVector::BI__builtin_rvv_vmulh_vv_tu: - case RISCVVector::BI__builtin_rvv_vmulh_vx_tu: - case RISCVVector::BI__builtin_rvv_vmulh_vv_m: - case RISCVVector::BI__builtin_rvv_vmulh_vx_m: - case RISCVVector::BI__builtin_rvv_vmulh_vv_mu: - case RISCVVector::BI__builtin_rvv_vmulh_vx_mu: - case RISCVVector::BI__builtin_rvv_vmulh_vv_tum: - case RISCVVector::BI__builtin_rvv_vmulh_vx_tum: - case RISCVVector::BI__builtin_rvv_vmulh_vv_tumu: - case RISCVVector::BI__builtin_rvv_vmulh_vx_tumu: - case RISCVVector::BI__builtin_rvv_vsmul_vv: - case RISCVVector::BI__builtin_rvv_vsmul_vx: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: - case RISCVVector::BI__builtin_rvv_vsmul_vv_m: - case RISCVVector::BI__builtin_rvv_vsmul_vx_m: - case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: { - ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo( - TheCall->getType()->castAs()); - - if (Context.getTypeSize(Info.ElementType) == 64 && !TI.hasFeature("v")) - return Diag(TheCall->getBeginLoc(), - diag::err_riscv_builtin_requires_extension) - << /* IsExtension */ true << TheCall->getSourceRange() << "v"; - - break; - } - } - - switch (BuiltinID) { - case RISCVVector::BI__builtin_rvv_vsetvli: - return BuiltinConstantArgRange(TheCall, 1, 0, 3) || - CheckRISCVLMUL(TheCall, 2); - case RISCVVector::BI__builtin_rvv_vsetvlimax: - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - CheckRISCVLMUL(TheCall, 1); - case RISCVVector::BI__builtin_rvv_vget_v: { - ASTContext::BuiltinVectorTypeInfo ResVecInfo = - Context.getBuiltinVectorTypeInfo(cast( - TheCall->getType().getCanonicalType().getTypePtr())); - ASTContext::BuiltinVectorTypeInfo VecInfo = - Context.getBuiltinVectorTypeInfo(cast( - TheCall->getArg(0)->getType().getCanonicalType().getTypePtr())); - unsigned MaxIndex; - if (VecInfo.NumVectors != 1) // vget for tuple type - MaxIndex = VecInfo.NumVectors; - else // vget for non-tuple type - MaxIndex = (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / - (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); - return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); - } - case RISCVVector::BI__builtin_rvv_vset_v: { - ASTContext::BuiltinVectorTypeInfo ResVecInfo = - Context.getBuiltinVectorTypeInfo(cast( - TheCall->getType().getCanonicalType().getTypePtr())); - ASTContext::BuiltinVectorTypeInfo VecInfo = - Context.getBuiltinVectorTypeInfo(cast( - TheCall->getArg(2)->getType().getCanonicalType().getTypePtr())); - unsigned MaxIndex; - if (ResVecInfo.NumVectors != 1) // vset for tuple type - MaxIndex = ResVecInfo.NumVectors; - else // vset fo non-tuple type - MaxIndex = (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / - (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); - return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); - } - // Vector Crypto - case RISCVVector::BI__builtin_rvv_vaeskf1_vi_tu: - case RISCVVector::BI__builtin_rvv_vaeskf2_vi_tu: - case RISCVVector::BI__builtin_rvv_vaeskf2_vi: - case RISCVVector::BI__builtin_rvv_vsm4k_vi_tu: { - QualType Op1Type = TheCall->getArg(0)->getType(); - QualType Op2Type = TheCall->getArg(1)->getType(); - return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || - CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, 128) || - BuiltinConstantArgRange(TheCall, 2, 0, 31); - } - case RISCVVector::BI__builtin_rvv_vsm3c_vi_tu: - case RISCVVector::BI__builtin_rvv_vsm3c_vi: { - QualType Op1Type = TheCall->getArg(0)->getType(); - return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 256) || - BuiltinConstantArgRange(TheCall, 2, 0, 31); - } - case RISCVVector::BI__builtin_rvv_vaeskf1_vi: - case RISCVVector::BI__builtin_rvv_vsm4k_vi: { - QualType Op1Type = TheCall->getArg(0)->getType(); - return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || - BuiltinConstantArgRange(TheCall, 1, 0, 31); - } - case RISCVVector::BI__builtin_rvv_vaesdf_vv: - case RISCVVector::BI__builtin_rvv_vaesdf_vs: - case RISCVVector::BI__builtin_rvv_vaesdm_vv: - case RISCVVector::BI__builtin_rvv_vaesdm_vs: - case RISCVVector::BI__builtin_rvv_vaesef_vv: - case RISCVVector::BI__builtin_rvv_vaesef_vs: - case RISCVVector::BI__builtin_rvv_vaesem_vv: - case RISCVVector::BI__builtin_rvv_vaesem_vs: - case RISCVVector::BI__builtin_rvv_vaesz_vs: - case RISCVVector::BI__builtin_rvv_vsm4r_vv: - case RISCVVector::BI__builtin_rvv_vsm4r_vs: - case RISCVVector::BI__builtin_rvv_vaesdf_vv_tu: - case RISCVVector::BI__builtin_rvv_vaesdf_vs_tu: - case RISCVVector::BI__builtin_rvv_vaesdm_vv_tu: - case RISCVVector::BI__builtin_rvv_vaesdm_vs_tu: - case RISCVVector::BI__builtin_rvv_vaesef_vv_tu: - case RISCVVector::BI__builtin_rvv_vaesef_vs_tu: - case RISCVVector::BI__builtin_rvv_vaesem_vv_tu: - case RISCVVector::BI__builtin_rvv_vaesem_vs_tu: - case RISCVVector::BI__builtin_rvv_vaesz_vs_tu: - case RISCVVector::BI__builtin_rvv_vsm4r_vv_tu: - case RISCVVector::BI__builtin_rvv_vsm4r_vs_tu: { - QualType Op1Type = TheCall->getArg(0)->getType(); - QualType Op2Type = TheCall->getArg(1)->getType(); - return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || - CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, 128); - } - case RISCVVector::BI__builtin_rvv_vsha2ch_vv: - case RISCVVector::BI__builtin_rvv_vsha2cl_vv: - case RISCVVector::BI__builtin_rvv_vsha2ms_vv: - case RISCVVector::BI__builtin_rvv_vsha2ch_vv_tu: - case RISCVVector::BI__builtin_rvv_vsha2cl_vv_tu: - case RISCVVector::BI__builtin_rvv_vsha2ms_vv_tu: { - QualType Op1Type = TheCall->getArg(0)->getType(); - QualType Op2Type = TheCall->getArg(1)->getType(); - QualType Op3Type = TheCall->getArg(2)->getType(); - ASTContext::BuiltinVectorTypeInfo Info = - Context.getBuiltinVectorTypeInfo(Op1Type->castAs()); - uint64_t ElemSize = Context.getTypeSize(Info.ElementType); - if (ElemSize == 64 && !TI.hasFeature("zvknhb")) - return Diag(TheCall->getBeginLoc(), - diag::err_riscv_builtin_requires_extension) - << /* IsExtension */ true << TheCall->getSourceRange() << "zvknb"; - - return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, ElemSize * 4) || - CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, ElemSize * 4) || - CheckInvalidVLENandLMUL(TI, TheCall, *this, Op3Type, ElemSize * 4); - } - - case RISCVVector::BI__builtin_rvv_sf_vc_i_se: - // bit_27_26, bit_24_20, bit_11_7, simm5, sew, log2lmul - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 1, 0, 31) || - BuiltinConstantArgRange(TheCall, 2, 0, 31) || - BuiltinConstantArgRange(TheCall, 3, -16, 15) || - CheckRISCVLMUL(TheCall, 5); - case RISCVVector::BI__builtin_rvv_sf_vc_iv_se: - // bit_27_26, bit_11_7, vs2, simm5 - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 1, 0, 31) || - BuiltinConstantArgRange(TheCall, 3, -16, 15); - case RISCVVector::BI__builtin_rvv_sf_vc_v_i: - case RISCVVector::BI__builtin_rvv_sf_vc_v_i_se: - // bit_27_26, bit_24_20, simm5 - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 1, 0, 31) || - BuiltinConstantArgRange(TheCall, 2, -16, 15); - case RISCVVector::BI__builtin_rvv_sf_vc_v_iv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_iv_se: - // bit_27_26, vs2, simm5 - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 2, -16, 15); - case RISCVVector::BI__builtin_rvv_sf_vc_ivv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_ivw_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw: - case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw_se: - // bit_27_26, vd, vs2, simm5 - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 3, -16, 15); - case RISCVVector::BI__builtin_rvv_sf_vc_x_se: - // bit_27_26, bit_24_20, bit_11_7, xs1, sew, log2lmul - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 1, 0, 31) || - BuiltinConstantArgRange(TheCall, 2, 0, 31) || - CheckRISCVLMUL(TheCall, 5); - case RISCVVector::BI__builtin_rvv_sf_vc_xv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_vv_se: - // bit_27_26, bit_11_7, vs2, xs1/vs1 - case RISCVVector::BI__builtin_rvv_sf_vc_v_x: - case RISCVVector::BI__builtin_rvv_sf_vc_v_x_se: - // bit_27_26, bit_24-20, xs1 - return BuiltinConstantArgRange(TheCall, 0, 0, 3) || - BuiltinConstantArgRange(TheCall, 1, 0, 31); - case RISCVVector::BI__builtin_rvv_sf_vc_vvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_xvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_vvw_se: - case RISCVVector::BI__builtin_rvv_sf_vc_xvw_se: - // bit_27_26, vd, vs2, xs1 - case RISCVVector::BI__builtin_rvv_sf_vc_v_xv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_xv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vv_se: - // bit_27_26, vs2, xs1/vs1 - case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw: - case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw_se: - // bit_27_26, vd, vs2, xs1/vs1 - return BuiltinConstantArgRange(TheCall, 0, 0, 3); - case RISCVVector::BI__builtin_rvv_sf_vc_fv_se: - // bit_26, bit_11_7, vs2, fs1 - return BuiltinConstantArgRange(TheCall, 0, 0, 1) || - BuiltinConstantArgRange(TheCall, 1, 0, 31); - case RISCVVector::BI__builtin_rvv_sf_vc_fvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_fvw_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw: - case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv_se: - case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw_se: - // bit_26, vd, vs2, fs1 - case RISCVVector::BI__builtin_rvv_sf_vc_v_fv: - case RISCVVector::BI__builtin_rvv_sf_vc_v_fv_se: - // bit_26, vs2, fs1 - return BuiltinConstantArgRange(TheCall, 0, 0, 1); - // Check if byteselect is in [0, 3] - case RISCV::BI__builtin_riscv_aes32dsi: - case RISCV::BI__builtin_riscv_aes32dsmi: - case RISCV::BI__builtin_riscv_aes32esi: - case RISCV::BI__builtin_riscv_aes32esmi: - case RISCV::BI__builtin_riscv_sm4ks: - case RISCV::BI__builtin_riscv_sm4ed: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - // Check if rnum is in [0, 10] - case RISCV::BI__builtin_riscv_aes64ks1i: - return BuiltinConstantArgRange(TheCall, 1, 0, 10); - // Check if value range for vxrm is in [0, 3] - case RISCVVector::BI__builtin_rvv_vaaddu_vv: - case RISCVVector::BI__builtin_rvv_vaaddu_vx: - case RISCVVector::BI__builtin_rvv_vaadd_vv: - case RISCVVector::BI__builtin_rvv_vaadd_vx: - case RISCVVector::BI__builtin_rvv_vasubu_vv: - case RISCVVector::BI__builtin_rvv_vasubu_vx: - case RISCVVector::BI__builtin_rvv_vasub_vv: - case RISCVVector::BI__builtin_rvv_vasub_vx: - case RISCVVector::BI__builtin_rvv_vsmul_vv: - case RISCVVector::BI__builtin_rvv_vsmul_vx: - case RISCVVector::BI__builtin_rvv_vssra_vv: - case RISCVVector::BI__builtin_rvv_vssra_vx: - case RISCVVector::BI__builtin_rvv_vssrl_vv: - case RISCVVector::BI__builtin_rvv_vssrl_vx: - case RISCVVector::BI__builtin_rvv_vnclip_wv: - case RISCVVector::BI__builtin_rvv_vnclip_wx: - case RISCVVector::BI__builtin_rvv_vnclipu_wv: - case RISCVVector::BI__builtin_rvv_vnclipu_wx: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case RISCVVector::BI__builtin_rvv_vaaddu_vv_tu: - case RISCVVector::BI__builtin_rvv_vaaddu_vx_tu: - case RISCVVector::BI__builtin_rvv_vaadd_vv_tu: - case RISCVVector::BI__builtin_rvv_vaadd_vx_tu: - case RISCVVector::BI__builtin_rvv_vasubu_vv_tu: - case RISCVVector::BI__builtin_rvv_vasubu_vx_tu: - case RISCVVector::BI__builtin_rvv_vasub_vv_tu: - case RISCVVector::BI__builtin_rvv_vasub_vx_tu: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: - case RISCVVector::BI__builtin_rvv_vssra_vv_tu: - case RISCVVector::BI__builtin_rvv_vssra_vx_tu: - case RISCVVector::BI__builtin_rvv_vssrl_vv_tu: - case RISCVVector::BI__builtin_rvv_vssrl_vx_tu: - case RISCVVector::BI__builtin_rvv_vnclip_wv_tu: - case RISCVVector::BI__builtin_rvv_vnclip_wx_tu: - case RISCVVector::BI__builtin_rvv_vnclipu_wv_tu: - case RISCVVector::BI__builtin_rvv_vnclipu_wx_tu: - case RISCVVector::BI__builtin_rvv_vaaddu_vv_m: - case RISCVVector::BI__builtin_rvv_vaaddu_vx_m: - case RISCVVector::BI__builtin_rvv_vaadd_vv_m: - case RISCVVector::BI__builtin_rvv_vaadd_vx_m: - case RISCVVector::BI__builtin_rvv_vasubu_vv_m: - case RISCVVector::BI__builtin_rvv_vasubu_vx_m: - case RISCVVector::BI__builtin_rvv_vasub_vv_m: - case RISCVVector::BI__builtin_rvv_vasub_vx_m: - case RISCVVector::BI__builtin_rvv_vsmul_vv_m: - case RISCVVector::BI__builtin_rvv_vsmul_vx_m: - case RISCVVector::BI__builtin_rvv_vssra_vv_m: - case RISCVVector::BI__builtin_rvv_vssra_vx_m: - case RISCVVector::BI__builtin_rvv_vssrl_vv_m: - case RISCVVector::BI__builtin_rvv_vssrl_vx_m: - case RISCVVector::BI__builtin_rvv_vnclip_wv_m: - case RISCVVector::BI__builtin_rvv_vnclip_wx_m: - case RISCVVector::BI__builtin_rvv_vnclipu_wv_m: - case RISCVVector::BI__builtin_rvv_vnclipu_wx_m: - return BuiltinConstantArgRange(TheCall, 3, 0, 3); - case RISCVVector::BI__builtin_rvv_vaaddu_vv_tum: - case RISCVVector::BI__builtin_rvv_vaaddu_vv_tumu: - case RISCVVector::BI__builtin_rvv_vaaddu_vv_mu: - case RISCVVector::BI__builtin_rvv_vaaddu_vx_tum: - case RISCVVector::BI__builtin_rvv_vaaddu_vx_tumu: - case RISCVVector::BI__builtin_rvv_vaaddu_vx_mu: - case RISCVVector::BI__builtin_rvv_vaadd_vv_tum: - case RISCVVector::BI__builtin_rvv_vaadd_vv_tumu: - case RISCVVector::BI__builtin_rvv_vaadd_vv_mu: - case RISCVVector::BI__builtin_rvv_vaadd_vx_tum: - case RISCVVector::BI__builtin_rvv_vaadd_vx_tumu: - case RISCVVector::BI__builtin_rvv_vaadd_vx_mu: - case RISCVVector::BI__builtin_rvv_vasubu_vv_tum: - case RISCVVector::BI__builtin_rvv_vasubu_vv_tumu: - case RISCVVector::BI__builtin_rvv_vasubu_vv_mu: - case RISCVVector::BI__builtin_rvv_vasubu_vx_tum: - case RISCVVector::BI__builtin_rvv_vasubu_vx_tumu: - case RISCVVector::BI__builtin_rvv_vasubu_vx_mu: - case RISCVVector::BI__builtin_rvv_vasub_vv_tum: - case RISCVVector::BI__builtin_rvv_vasub_vv_tumu: - case RISCVVector::BI__builtin_rvv_vasub_vv_mu: - case RISCVVector::BI__builtin_rvv_vasub_vx_tum: - case RISCVVector::BI__builtin_rvv_vasub_vx_tumu: - case RISCVVector::BI__builtin_rvv_vasub_vx_mu: - case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: - case RISCVVector::BI__builtin_rvv_vssra_vv_mu: - case RISCVVector::BI__builtin_rvv_vssra_vx_mu: - case RISCVVector::BI__builtin_rvv_vssrl_vv_mu: - case RISCVVector::BI__builtin_rvv_vssrl_vx_mu: - case RISCVVector::BI__builtin_rvv_vnclip_wv_mu: - case RISCVVector::BI__builtin_rvv_vnclip_wx_mu: - case RISCVVector::BI__builtin_rvv_vnclipu_wv_mu: - case RISCVVector::BI__builtin_rvv_vnclipu_wx_mu: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: - case RISCVVector::BI__builtin_rvv_vssra_vv_tum: - case RISCVVector::BI__builtin_rvv_vssra_vx_tum: - case RISCVVector::BI__builtin_rvv_vssrl_vv_tum: - case RISCVVector::BI__builtin_rvv_vssrl_vx_tum: - case RISCVVector::BI__builtin_rvv_vnclip_wv_tum: - case RISCVVector::BI__builtin_rvv_vnclip_wx_tum: - case RISCVVector::BI__builtin_rvv_vnclipu_wv_tum: - case RISCVVector::BI__builtin_rvv_vnclipu_wx_tum: - case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: - case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: - case RISCVVector::BI__builtin_rvv_vssra_vv_tumu: - case RISCVVector::BI__builtin_rvv_vssra_vx_tumu: - case RISCVVector::BI__builtin_rvv_vssrl_vv_tumu: - case RISCVVector::BI__builtin_rvv_vssrl_vx_tumu: - case RISCVVector::BI__builtin_rvv_vnclip_wv_tumu: - case RISCVVector::BI__builtin_rvv_vnclip_wx_tumu: - case RISCVVector::BI__builtin_rvv_vnclipu_wv_tumu: - case RISCVVector::BI__builtin_rvv_vnclipu_wx_tumu: - return BuiltinConstantArgRange(TheCall, 4, 0, 3); - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: - return BuiltinConstantArgRange(TheCall, 1, 0, 4); - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm: - case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm: - case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm: - case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm: - case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm: - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tu: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tu: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tu: - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_m: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_m: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_m: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: - return BuiltinConstantArgRange(TheCall, 2, 0, 4); - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tu: - case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm: - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tu: - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_m: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_m: - case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_m: - case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_m: - case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_m: - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tum: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tum: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tum: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tum: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tum: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tum: - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_mu: - case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_mu: - case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_mu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: - case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: - return BuiltinConstantArgRange(TheCall, 3, 0, 4); - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_m: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_m: - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tum: - case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tum: - case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tum: - case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tum: - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tumu: - case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: - case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: - return BuiltinConstantArgRange(TheCall, 4, 0, 4); - case RISCV::BI__builtin_riscv_ntl_load: - case RISCV::BI__builtin_riscv_ntl_store: - DeclRefExpr *DRE = - cast(TheCall->getCallee()->IgnoreParenCasts()); - assert((BuiltinID == RISCV::BI__builtin_riscv_ntl_store || - BuiltinID == RISCV::BI__builtin_riscv_ntl_load) && - "Unexpected RISC-V nontemporal load/store builtin!"); - bool IsStore = BuiltinID == RISCV::BI__builtin_riscv_ntl_store; - unsigned NumArgs = IsStore ? 3 : 2; - - if (checkArgCountAtLeast(*this, TheCall, NumArgs - 1)) - return true; - - if (checkArgCountAtMost(*this, TheCall, NumArgs)) - return true; - - // Domain value should be compile-time constant. - // 2 <= domain <= 5 - if (TheCall->getNumArgs() == NumArgs && - BuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) - return true; - - Expr *PointerArg = TheCall->getArg(0); - ExprResult PointerArgResult = - DefaultFunctionArrayLvalueConversion(PointerArg); - - if (PointerArgResult.isInvalid()) - return true; - PointerArg = PointerArgResult.get(); - - const PointerType *PtrType = PointerArg->getType()->getAs(); - if (!PtrType) { - Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - QualType ValType = PtrType->getPointeeType(); - ValType = ValType.getUnqualifiedType(); - if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && - !ValType->isBlockPointerType() && !ValType->isFloatingType() && - !ValType->isVectorType() && !ValType->isRVVSizelessBuiltinType()) { - Diag(DRE->getBeginLoc(), - diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - if (!IsStore) { - TheCall->setType(ValType); - return false; - } - - ExprResult ValArg = TheCall->getArg(1); - InitializedEntity Entity = InitializedEntity::InitializeParameter( - Context, ValType, /*consume*/ false); - ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); - if (ValArg.isInvalid()) - return true; - - TheCall->setArg(1, ValArg.get()); - TheCall->setType(Context.VoidTy); - return false; - } - - return false; -} - -bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == SystemZ::BI__builtin_tabort) { - Expr *Arg = TheCall->getArg(0); - if (std::optional AbortCode = - Arg->getIntegerConstantExpr(Context)) - if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256) - return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code) - << Arg->getSourceRange(); - } - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: return false; - case SystemZ::BI__builtin_s390_lcbb: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_verimb: - case SystemZ::BI__builtin_s390_verimh: - case SystemZ::BI__builtin_s390_verimf: - case SystemZ::BI__builtin_s390_verimg: i = 3; l = 0; u = 255; break; - case SystemZ::BI__builtin_s390_vfaeb: - case SystemZ::BI__builtin_s390_vfaeh: - case SystemZ::BI__builtin_s390_vfaef: - case SystemZ::BI__builtin_s390_vfaebs: - case SystemZ::BI__builtin_s390_vfaehs: - case SystemZ::BI__builtin_s390_vfaefs: - case SystemZ::BI__builtin_s390_vfaezb: - case SystemZ::BI__builtin_s390_vfaezh: - case SystemZ::BI__builtin_s390_vfaezf: - case SystemZ::BI__builtin_s390_vfaezbs: - case SystemZ::BI__builtin_s390_vfaezhs: - case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vfisb: - case SystemZ::BI__builtin_s390_vfidb: - return BuiltinConstantArgRange(TheCall, 1, 0, 15) || - BuiltinConstantArgRange(TheCall, 2, 0, 15); - case SystemZ::BI__builtin_s390_vftcisb: - case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; - case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vsldb: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vstrcb: - case SystemZ::BI__builtin_s390_vstrch: - case SystemZ::BI__builtin_s390_vstrcf: - case SystemZ::BI__builtin_s390_vstrczb: - case SystemZ::BI__builtin_s390_vstrczh: - case SystemZ::BI__builtin_s390_vstrczf: - case SystemZ::BI__builtin_s390_vstrcbs: - case SystemZ::BI__builtin_s390_vstrchs: - case SystemZ::BI__builtin_s390_vstrcfs: - case SystemZ::BI__builtin_s390_vstrczbs: - case SystemZ::BI__builtin_s390_vstrczhs: - case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vmslg: i = 3; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vfminsb: - case SystemZ::BI__builtin_s390_vfmaxsb: - case SystemZ::BI__builtin_s390_vfmindb: - case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vsld: i = 2; l = 0; u = 7; break; - case SystemZ::BI__builtin_s390_vsrd: i = 2; l = 0; u = 7; break; - case SystemZ::BI__builtin_s390_vclfnhs: - case SystemZ::BI__builtin_s390_vclfnls: - case SystemZ::BI__builtin_s390_vcfn: - case SystemZ::BI__builtin_s390_vcnf: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vcrnfs: i = 2; l = 0; u = 15; break; - } - return BuiltinConstantArgRange(TheCall, i, l, u); -} - -bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - case WebAssembly::BI__builtin_wasm_ref_null_extern: - return BuiltinWasmRefNullExtern(TheCall); - case WebAssembly::BI__builtin_wasm_ref_null_func: - return BuiltinWasmRefNullFunc(TheCall); - case WebAssembly::BI__builtin_wasm_table_get: - return BuiltinWasmTableGet(TheCall); - case WebAssembly::BI__builtin_wasm_table_set: - return BuiltinWasmTableSet(TheCall); - case WebAssembly::BI__builtin_wasm_table_size: - return BuiltinWasmTableSize(TheCall); - case WebAssembly::BI__builtin_wasm_table_grow: - return BuiltinWasmTableGrow(TheCall); - case WebAssembly::BI__builtin_wasm_table_fill: - return BuiltinWasmTableFill(TheCall); - case WebAssembly::BI__builtin_wasm_table_copy: - return BuiltinWasmTableCopy(TheCall); - } - - return false; -} - -void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, - const llvm::StringMap &FeatureMap) { - ASTContext::BuiltinVectorTypeInfo Info = - Context.getBuiltinVectorTypeInfo(Ty->castAs()); - unsigned EltSize = Context.getTypeSize(Info.ElementType); - unsigned MinElts = Info.EC.getKnownMinValue(); - - if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) && - !FeatureMap.lookup("zve64d")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; - // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at - // least zve64x - else if (((EltSize == 64 && Info.ElementType->isIntegerType()) || - MinElts == 1) && - !FeatureMap.lookup("zve64x")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; - else if (Info.ElementType->isFloat16Type() && !FeatureMap.lookup("zvfh") && - !FeatureMap.lookup("zvfhmin")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) - << Ty << "zvfh or zvfhmin"; - else if (Info.ElementType->isBFloat16Type() && - !FeatureMap.lookup("experimental-zvfbfmin")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin"; - else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) && - !FeatureMap.lookup("zve32f")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; - // Given that caller already checked isRVVType() before calling this function, - // if we don't have at least zve32x supported, then we need to emit error. - else if (!FeatureMap.lookup("zve32x")) - Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; -} - -bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - case NVPTX::BI__nvvm_cp_async_ca_shared_global_4: - case NVPTX::BI__nvvm_cp_async_ca_shared_global_8: - case NVPTX::BI__nvvm_cp_async_ca_shared_global_16: - case NVPTX::BI__nvvm_cp_async_cg_shared_global_16: - return checkArgCountAtMost(*this, TheCall, 3); - } - - return false; -} - -// Check if the rounding mode is legal. -bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { - // Indicates if this instruction has rounding control or just SAE. - bool HasRC = false; - - unsigned ArgNum = 0; - switch (BuiltinID) { - default: - return false; - case X86::BI__builtin_ia32_vcvttsd2si32: - case X86::BI__builtin_ia32_vcvttsd2si64: - case X86::BI__builtin_ia32_vcvttsd2usi32: - case X86::BI__builtin_ia32_vcvttsd2usi64: - case X86::BI__builtin_ia32_vcvttss2si32: - case X86::BI__builtin_ia32_vcvttss2si64: - case X86::BI__builtin_ia32_vcvttss2usi32: - case X86::BI__builtin_ia32_vcvttss2usi64: - case X86::BI__builtin_ia32_vcvttsh2si32: - case X86::BI__builtin_ia32_vcvttsh2si64: - case X86::BI__builtin_ia32_vcvttsh2usi32: - case X86::BI__builtin_ia32_vcvttsh2usi64: - ArgNum = 1; - break; - case X86::BI__builtin_ia32_maxpd512: - case X86::BI__builtin_ia32_maxps512: - case X86::BI__builtin_ia32_minpd512: - case X86::BI__builtin_ia32_minps512: - case X86::BI__builtin_ia32_maxph512: - case X86::BI__builtin_ia32_minph512: - ArgNum = 2; - break; - case X86::BI__builtin_ia32_vcvtph2pd512_mask: - case X86::BI__builtin_ia32_vcvtph2psx512_mask: - case X86::BI__builtin_ia32_cvtps2pd512_mask: - case X86::BI__builtin_ia32_cvttpd2dq512_mask: - case X86::BI__builtin_ia32_cvttpd2qq512_mask: - case X86::BI__builtin_ia32_cvttpd2udq512_mask: - case X86::BI__builtin_ia32_cvttpd2uqq512_mask: - case X86::BI__builtin_ia32_cvttps2dq512_mask: - case X86::BI__builtin_ia32_cvttps2qq512_mask: - case X86::BI__builtin_ia32_cvttps2udq512_mask: - case X86::BI__builtin_ia32_cvttps2uqq512_mask: - case X86::BI__builtin_ia32_vcvttph2w512_mask: - case X86::BI__builtin_ia32_vcvttph2uw512_mask: - case X86::BI__builtin_ia32_vcvttph2dq512_mask: - case X86::BI__builtin_ia32_vcvttph2udq512_mask: - case X86::BI__builtin_ia32_vcvttph2qq512_mask: - case X86::BI__builtin_ia32_vcvttph2uqq512_mask: - case X86::BI__builtin_ia32_exp2pd_mask: - case X86::BI__builtin_ia32_exp2ps_mask: - case X86::BI__builtin_ia32_getexppd512_mask: - case X86::BI__builtin_ia32_getexpps512_mask: - case X86::BI__builtin_ia32_getexpph512_mask: - case X86::BI__builtin_ia32_rcp28pd_mask: - case X86::BI__builtin_ia32_rcp28ps_mask: - case X86::BI__builtin_ia32_rsqrt28pd_mask: - case X86::BI__builtin_ia32_rsqrt28ps_mask: - case X86::BI__builtin_ia32_vcomisd: - case X86::BI__builtin_ia32_vcomiss: - case X86::BI__builtin_ia32_vcomish: - case X86::BI__builtin_ia32_vcvtph2ps512_mask: - ArgNum = 3; - break; - case X86::BI__builtin_ia32_cmppd512_mask: - case X86::BI__builtin_ia32_cmpps512_mask: - case X86::BI__builtin_ia32_cmpsd_mask: - case X86::BI__builtin_ia32_cmpss_mask: - case X86::BI__builtin_ia32_cmpsh_mask: - case X86::BI__builtin_ia32_vcvtsh2sd_round_mask: - case X86::BI__builtin_ia32_vcvtsh2ss_round_mask: - case X86::BI__builtin_ia32_cvtss2sd_round_mask: - case X86::BI__builtin_ia32_getexpsd128_round_mask: - case X86::BI__builtin_ia32_getexpss128_round_mask: - case X86::BI__builtin_ia32_getexpsh128_round_mask: - case X86::BI__builtin_ia32_getmantpd512_mask: - case X86::BI__builtin_ia32_getmantps512_mask: - case X86::BI__builtin_ia32_getmantph512_mask: - case X86::BI__builtin_ia32_maxsd_round_mask: - case X86::BI__builtin_ia32_maxss_round_mask: - case X86::BI__builtin_ia32_maxsh_round_mask: - case X86::BI__builtin_ia32_minsd_round_mask: - case X86::BI__builtin_ia32_minss_round_mask: - case X86::BI__builtin_ia32_minsh_round_mask: - case X86::BI__builtin_ia32_rcp28sd_round_mask: - case X86::BI__builtin_ia32_rcp28ss_round_mask: - case X86::BI__builtin_ia32_reducepd512_mask: - case X86::BI__builtin_ia32_reduceps512_mask: - case X86::BI__builtin_ia32_reduceph512_mask: - case X86::BI__builtin_ia32_rndscalepd_mask: - case X86::BI__builtin_ia32_rndscaleps_mask: - case X86::BI__builtin_ia32_rndscaleph_mask: - case X86::BI__builtin_ia32_rsqrt28sd_round_mask: - case X86::BI__builtin_ia32_rsqrt28ss_round_mask: - ArgNum = 4; - break; - case X86::BI__builtin_ia32_fixupimmpd512_mask: - case X86::BI__builtin_ia32_fixupimmpd512_maskz: - case X86::BI__builtin_ia32_fixupimmps512_mask: - case X86::BI__builtin_ia32_fixupimmps512_maskz: - case X86::BI__builtin_ia32_fixupimmsd_mask: - case X86::BI__builtin_ia32_fixupimmsd_maskz: - case X86::BI__builtin_ia32_fixupimmss_mask: - case X86::BI__builtin_ia32_fixupimmss_maskz: - case X86::BI__builtin_ia32_getmantsd_round_mask: - case X86::BI__builtin_ia32_getmantss_round_mask: - case X86::BI__builtin_ia32_getmantsh_round_mask: - case X86::BI__builtin_ia32_rangepd512_mask: - case X86::BI__builtin_ia32_rangeps512_mask: - case X86::BI__builtin_ia32_rangesd128_round_mask: - case X86::BI__builtin_ia32_rangess128_round_mask: - case X86::BI__builtin_ia32_reducesd_mask: - case X86::BI__builtin_ia32_reducess_mask: - case X86::BI__builtin_ia32_reducesh_mask: - case X86::BI__builtin_ia32_rndscalesd_round_mask: - case X86::BI__builtin_ia32_rndscaless_round_mask: - case X86::BI__builtin_ia32_rndscalesh_round_mask: - ArgNum = 5; - break; - case X86::BI__builtin_ia32_vcvtsd2si64: - case X86::BI__builtin_ia32_vcvtsd2si32: - case X86::BI__builtin_ia32_vcvtsd2usi32: - case X86::BI__builtin_ia32_vcvtsd2usi64: - case X86::BI__builtin_ia32_vcvtss2si32: - case X86::BI__builtin_ia32_vcvtss2si64: - case X86::BI__builtin_ia32_vcvtss2usi32: - case X86::BI__builtin_ia32_vcvtss2usi64: - case X86::BI__builtin_ia32_vcvtsh2si32: - case X86::BI__builtin_ia32_vcvtsh2si64: - case X86::BI__builtin_ia32_vcvtsh2usi32: - case X86::BI__builtin_ia32_vcvtsh2usi64: - case X86::BI__builtin_ia32_sqrtpd512: - case X86::BI__builtin_ia32_sqrtps512: - case X86::BI__builtin_ia32_sqrtph512: - ArgNum = 1; - HasRC = true; - break; - case X86::BI__builtin_ia32_addph512: - case X86::BI__builtin_ia32_divph512: - case X86::BI__builtin_ia32_mulph512: - case X86::BI__builtin_ia32_subph512: - case X86::BI__builtin_ia32_addpd512: - case X86::BI__builtin_ia32_addps512: - case X86::BI__builtin_ia32_divpd512: - case X86::BI__builtin_ia32_divps512: - case X86::BI__builtin_ia32_mulpd512: - case X86::BI__builtin_ia32_mulps512: - case X86::BI__builtin_ia32_subpd512: - case X86::BI__builtin_ia32_subps512: - case X86::BI__builtin_ia32_cvtsi2sd64: - case X86::BI__builtin_ia32_cvtsi2ss32: - case X86::BI__builtin_ia32_cvtsi2ss64: - case X86::BI__builtin_ia32_cvtusi2sd64: - case X86::BI__builtin_ia32_cvtusi2ss32: - case X86::BI__builtin_ia32_cvtusi2ss64: - case X86::BI__builtin_ia32_vcvtusi2sh: - case X86::BI__builtin_ia32_vcvtusi642sh: - case X86::BI__builtin_ia32_vcvtsi2sh: - case X86::BI__builtin_ia32_vcvtsi642sh: - ArgNum = 2; - HasRC = true; - break; - case X86::BI__builtin_ia32_cvtdq2ps512_mask: - case X86::BI__builtin_ia32_cvtudq2ps512_mask: - case X86::BI__builtin_ia32_vcvtpd2ph512_mask: - case X86::BI__builtin_ia32_vcvtps2phx512_mask: - case X86::BI__builtin_ia32_cvtpd2ps512_mask: - case X86::BI__builtin_ia32_cvtpd2dq512_mask: - case X86::BI__builtin_ia32_cvtpd2qq512_mask: - case X86::BI__builtin_ia32_cvtpd2udq512_mask: - case X86::BI__builtin_ia32_cvtpd2uqq512_mask: - case X86::BI__builtin_ia32_cvtps2dq512_mask: - case X86::BI__builtin_ia32_cvtps2qq512_mask: - case X86::BI__builtin_ia32_cvtps2udq512_mask: - case X86::BI__builtin_ia32_cvtps2uqq512_mask: - case X86::BI__builtin_ia32_cvtqq2pd512_mask: - case X86::BI__builtin_ia32_cvtqq2ps512_mask: - case X86::BI__builtin_ia32_cvtuqq2pd512_mask: - case X86::BI__builtin_ia32_cvtuqq2ps512_mask: - case X86::BI__builtin_ia32_vcvtdq2ph512_mask: - case X86::BI__builtin_ia32_vcvtudq2ph512_mask: - case X86::BI__builtin_ia32_vcvtw2ph512_mask: - case X86::BI__builtin_ia32_vcvtuw2ph512_mask: - case X86::BI__builtin_ia32_vcvtph2w512_mask: - case X86::BI__builtin_ia32_vcvtph2uw512_mask: - case X86::BI__builtin_ia32_vcvtph2dq512_mask: - case X86::BI__builtin_ia32_vcvtph2udq512_mask: - case X86::BI__builtin_ia32_vcvtph2qq512_mask: - case X86::BI__builtin_ia32_vcvtph2uqq512_mask: - case X86::BI__builtin_ia32_vcvtqq2ph512_mask: - case X86::BI__builtin_ia32_vcvtuqq2ph512_mask: - ArgNum = 3; - HasRC = true; - break; - case X86::BI__builtin_ia32_addsh_round_mask: - case X86::BI__builtin_ia32_addss_round_mask: - case X86::BI__builtin_ia32_addsd_round_mask: - case X86::BI__builtin_ia32_divsh_round_mask: - case X86::BI__builtin_ia32_divss_round_mask: - case X86::BI__builtin_ia32_divsd_round_mask: - case X86::BI__builtin_ia32_mulsh_round_mask: - case X86::BI__builtin_ia32_mulss_round_mask: - case X86::BI__builtin_ia32_mulsd_round_mask: - case X86::BI__builtin_ia32_subsh_round_mask: - case X86::BI__builtin_ia32_subss_round_mask: - case X86::BI__builtin_ia32_subsd_round_mask: - case X86::BI__builtin_ia32_scalefph512_mask: - case X86::BI__builtin_ia32_scalefpd512_mask: - case X86::BI__builtin_ia32_scalefps512_mask: - case X86::BI__builtin_ia32_scalefsd_round_mask: - case X86::BI__builtin_ia32_scalefss_round_mask: - case X86::BI__builtin_ia32_scalefsh_round_mask: - case X86::BI__builtin_ia32_cvtsd2ss_round_mask: - case X86::BI__builtin_ia32_vcvtss2sh_round_mask: - case X86::BI__builtin_ia32_vcvtsd2sh_round_mask: - case X86::BI__builtin_ia32_sqrtsd_round_mask: - case X86::BI__builtin_ia32_sqrtss_round_mask: - case X86::BI__builtin_ia32_sqrtsh_round_mask: - case X86::BI__builtin_ia32_vfmaddsd3_mask: - case X86::BI__builtin_ia32_vfmaddsd3_maskz: - case X86::BI__builtin_ia32_vfmaddsd3_mask3: - case X86::BI__builtin_ia32_vfmaddss3_mask: - case X86::BI__builtin_ia32_vfmaddss3_maskz: - case X86::BI__builtin_ia32_vfmaddss3_mask3: - case X86::BI__builtin_ia32_vfmaddsh3_mask: - case X86::BI__builtin_ia32_vfmaddsh3_maskz: - case X86::BI__builtin_ia32_vfmaddsh3_mask3: - case X86::BI__builtin_ia32_vfmaddpd512_mask: - case X86::BI__builtin_ia32_vfmaddpd512_maskz: - case X86::BI__builtin_ia32_vfmaddpd512_mask3: - case X86::BI__builtin_ia32_vfmsubpd512_mask3: - case X86::BI__builtin_ia32_vfmaddps512_mask: - case X86::BI__builtin_ia32_vfmaddps512_maskz: - case X86::BI__builtin_ia32_vfmaddps512_mask3: - case X86::BI__builtin_ia32_vfmsubps512_mask3: - case X86::BI__builtin_ia32_vfmaddph512_mask: - case X86::BI__builtin_ia32_vfmaddph512_maskz: - case X86::BI__builtin_ia32_vfmaddph512_mask3: - case X86::BI__builtin_ia32_vfmsubph512_mask3: - case X86::BI__builtin_ia32_vfmaddsubpd512_mask: - case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: - case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: - case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: - case X86::BI__builtin_ia32_vfmaddsubps512_mask: - case X86::BI__builtin_ia32_vfmaddsubps512_maskz: - case X86::BI__builtin_ia32_vfmaddsubps512_mask3: - case X86::BI__builtin_ia32_vfmsubaddps512_mask3: - case X86::BI__builtin_ia32_vfmaddsubph512_mask: - case X86::BI__builtin_ia32_vfmaddsubph512_maskz: - case X86::BI__builtin_ia32_vfmaddsubph512_mask3: - case X86::BI__builtin_ia32_vfmsubaddph512_mask3: - case X86::BI__builtin_ia32_vfmaddcsh_mask: - case X86::BI__builtin_ia32_vfmaddcsh_round_mask: - case X86::BI__builtin_ia32_vfmaddcsh_round_mask3: - case X86::BI__builtin_ia32_vfmaddcph512_mask: - case X86::BI__builtin_ia32_vfmaddcph512_maskz: - case X86::BI__builtin_ia32_vfmaddcph512_mask3: - case X86::BI__builtin_ia32_vfcmaddcsh_mask: - case X86::BI__builtin_ia32_vfcmaddcsh_round_mask: - case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3: - case X86::BI__builtin_ia32_vfcmaddcph512_mask: - case X86::BI__builtin_ia32_vfcmaddcph512_maskz: - case X86::BI__builtin_ia32_vfcmaddcph512_mask3: - case X86::BI__builtin_ia32_vfmulcsh_mask: - case X86::BI__builtin_ia32_vfmulcph512_mask: - case X86::BI__builtin_ia32_vfcmulcsh_mask: - case X86::BI__builtin_ia32_vfcmulcph512_mask: - ArgNum = 4; - HasRC = true; - break; - } - - llvm::APSInt Result; - - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check constant-ness first. - if (BuiltinConstantArg(TheCall, ArgNum, Result)) - return true; - - // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit - // is set. If the intrinsic has rounding control(bits 1:0), make sure its only - // combined with ROUND_NO_EXC. If the intrinsic does not have rounding - // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together. - if (Result == 4/*ROUND_CUR_DIRECTION*/ || - Result == 8/*ROUND_NO_EXC*/ || - (!HasRC && Result == 12/*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) || - (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) - return false; - - return Diag(TheCall->getBeginLoc(), diag::err_x86_builtin_invalid_rounding) - << Arg->getSourceRange(); -} - -// Check if the gather/scatter scale is legal. -bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, - CallExpr *TheCall) { - unsigned ArgNum = 0; - switch (BuiltinID) { - default: - return false; - case X86::BI__builtin_ia32_gatherpfdpd: - case X86::BI__builtin_ia32_gatherpfdps: - case X86::BI__builtin_ia32_gatherpfqpd: - case X86::BI__builtin_ia32_gatherpfqps: - case X86::BI__builtin_ia32_scatterpfdpd: - case X86::BI__builtin_ia32_scatterpfdps: - case X86::BI__builtin_ia32_scatterpfqpd: - case X86::BI__builtin_ia32_scatterpfqps: - ArgNum = 3; - break; - case X86::BI__builtin_ia32_gatherd_pd: - case X86::BI__builtin_ia32_gatherd_pd256: - case X86::BI__builtin_ia32_gatherq_pd: - case X86::BI__builtin_ia32_gatherq_pd256: - case X86::BI__builtin_ia32_gatherd_ps: - case X86::BI__builtin_ia32_gatherd_ps256: - case X86::BI__builtin_ia32_gatherq_ps: - case X86::BI__builtin_ia32_gatherq_ps256: - case X86::BI__builtin_ia32_gatherd_q: - case X86::BI__builtin_ia32_gatherd_q256: - case X86::BI__builtin_ia32_gatherq_q: - case X86::BI__builtin_ia32_gatherq_q256: - case X86::BI__builtin_ia32_gatherd_d: - case X86::BI__builtin_ia32_gatherd_d256: - case X86::BI__builtin_ia32_gatherq_d: - case X86::BI__builtin_ia32_gatherq_d256: - case X86::BI__builtin_ia32_gather3div2df: - case X86::BI__builtin_ia32_gather3div2di: - case X86::BI__builtin_ia32_gather3div4df: - case X86::BI__builtin_ia32_gather3div4di: - case X86::BI__builtin_ia32_gather3div4sf: - case X86::BI__builtin_ia32_gather3div4si: - case X86::BI__builtin_ia32_gather3div8sf: - case X86::BI__builtin_ia32_gather3div8si: - case X86::BI__builtin_ia32_gather3siv2df: - case X86::BI__builtin_ia32_gather3siv2di: - case X86::BI__builtin_ia32_gather3siv4df: - case X86::BI__builtin_ia32_gather3siv4di: - case X86::BI__builtin_ia32_gather3siv4sf: - case X86::BI__builtin_ia32_gather3siv4si: - case X86::BI__builtin_ia32_gather3siv8sf: - case X86::BI__builtin_ia32_gather3siv8si: - case X86::BI__builtin_ia32_gathersiv8df: - case X86::BI__builtin_ia32_gathersiv16sf: - case X86::BI__builtin_ia32_gatherdiv8df: - case X86::BI__builtin_ia32_gatherdiv16sf: - case X86::BI__builtin_ia32_gathersiv8di: - case X86::BI__builtin_ia32_gathersiv16si: - case X86::BI__builtin_ia32_gatherdiv8di: - case X86::BI__builtin_ia32_gatherdiv16si: - case X86::BI__builtin_ia32_scatterdiv2df: - case X86::BI__builtin_ia32_scatterdiv2di: - case X86::BI__builtin_ia32_scatterdiv4df: - case X86::BI__builtin_ia32_scatterdiv4di: - case X86::BI__builtin_ia32_scatterdiv4sf: - case X86::BI__builtin_ia32_scatterdiv4si: - case X86::BI__builtin_ia32_scatterdiv8sf: - case X86::BI__builtin_ia32_scatterdiv8si: - case X86::BI__builtin_ia32_scattersiv2df: - case X86::BI__builtin_ia32_scattersiv2di: - case X86::BI__builtin_ia32_scattersiv4df: - case X86::BI__builtin_ia32_scattersiv4di: - case X86::BI__builtin_ia32_scattersiv4sf: - case X86::BI__builtin_ia32_scattersiv4si: - case X86::BI__builtin_ia32_scattersiv8sf: - case X86::BI__builtin_ia32_scattersiv8si: - case X86::BI__builtin_ia32_scattersiv8df: - case X86::BI__builtin_ia32_scattersiv16sf: - case X86::BI__builtin_ia32_scatterdiv8df: - case X86::BI__builtin_ia32_scatterdiv16sf: - case X86::BI__builtin_ia32_scattersiv8di: - case X86::BI__builtin_ia32_scattersiv16si: - case X86::BI__builtin_ia32_scatterdiv8di: - case X86::BI__builtin_ia32_scatterdiv16si: - ArgNum = 4; - break; - } - - llvm::APSInt Result; - - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check constant-ness first. - if (BuiltinConstantArg(TheCall, ArgNum, Result)) - return true; - - if (Result == 1 || Result == 2 || Result == 4 || Result == 8) - return false; - - return Diag(TheCall->getBeginLoc(), diag::err_x86_builtin_invalid_scale) - << Arg->getSourceRange(); -} - -enum { TileRegLow = 0, TileRegHigh = 7 }; - -bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, - ArrayRef ArgNums) { - for (int ArgNum : ArgNums) { - if (BuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) - return true; - } - return false; -} - -bool Sema::CheckX86BuiltinTileDuplicate(CallExpr *TheCall, - ArrayRef ArgNums) { - // Because the max number of tile register is TileRegHigh + 1, so here we use - // each bit to represent the usage of them in bitset. - std::bitset ArgValues; - for (int ArgNum : ArgNums) { - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - continue; - - llvm::APSInt Result; - if (BuiltinConstantArg(TheCall, ArgNum, Result)) - return true; - int ArgExtValue = Result.getExtValue(); - assert((ArgExtValue >= TileRegLow && ArgExtValue <= TileRegHigh) && - "Incorrect tile register num."); - if (ArgValues.test(ArgExtValue)) - return Diag(TheCall->getBeginLoc(), - diag::err_x86_builtin_tile_arg_duplicate) - << TheCall->getArg(ArgNum)->getSourceRange(); - ArgValues.set(ArgExtValue); - } - return false; -} - -bool Sema::CheckX86BuiltinTileRangeAndDuplicate(CallExpr *TheCall, - ArrayRef ArgNums) { - return CheckX86BuiltinTileArgumentsRange(TheCall, ArgNums) || - CheckX86BuiltinTileDuplicate(TheCall, ArgNums); -} - -bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - default: - return false; - case X86::BI__builtin_ia32_tileloadd64: - case X86::BI__builtin_ia32_tileloaddt164: - case X86::BI__builtin_ia32_tilestored64: - case X86::BI__builtin_ia32_tilezero: - return CheckX86BuiltinTileArgumentsRange(TheCall, 0); - case X86::BI__builtin_ia32_tdpbssd: - case X86::BI__builtin_ia32_tdpbsud: - case X86::BI__builtin_ia32_tdpbusd: - case X86::BI__builtin_ia32_tdpbuud: - case X86::BI__builtin_ia32_tdpbf16ps: - case X86::BI__builtin_ia32_tdpfp16ps: - case X86::BI__builtin_ia32_tcmmimfp16ps: - case X86::BI__builtin_ia32_tcmmrlfp16ps: - return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2}); - } -} -static bool isX86_32Builtin(unsigned BuiltinID) { - // These builtins only work on x86-32 targets. - switch (BuiltinID) { - case X86::BI__builtin_ia32_readeflags_u32: - case X86::BI__builtin_ia32_writeeflags_u32: - return true; - } - - return false; -} - -bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - // Check for 32-bit only builtins on a 64-bit target. - const llvm::Triple &TT = TI.getTriple(); - if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) - return Diag(TheCall->getCallee()->getBeginLoc(), - diag::err_32_bit_builtin_64_bit_tgt); - - // If the intrinsic has rounding or SAE make sure its valid. - if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) - return true; - - // If the intrinsic has a gather/scatter scale immediate make sure its valid. - if (CheckX86BuiltinGatherScatterScale(BuiltinID, TheCall)) - return true; - - // If the intrinsic has a tile arguments, make sure they are valid. - if (CheckX86BuiltinTileArguments(BuiltinID, TheCall)) - return true; - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - int i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: - return false; - case X86::BI__builtin_ia32_vec_ext_v2si: - case X86::BI__builtin_ia32_vec_ext_v2di: - case X86::BI__builtin_ia32_vextractf128_pd256: - case X86::BI__builtin_ia32_vextractf128_ps256: - case X86::BI__builtin_ia32_vextractf128_si256: - case X86::BI__builtin_ia32_extract128i256: - case X86::BI__builtin_ia32_extractf64x4_mask: - case X86::BI__builtin_ia32_extracti64x4_mask: - case X86::BI__builtin_ia32_extractf32x8_mask: - case X86::BI__builtin_ia32_extracti32x8_mask: - case X86::BI__builtin_ia32_extractf64x2_256_mask: - case X86::BI__builtin_ia32_extracti64x2_256_mask: - case X86::BI__builtin_ia32_extractf32x4_256_mask: - case X86::BI__builtin_ia32_extracti32x4_256_mask: - i = 1; l = 0; u = 1; - break; - case X86::BI__builtin_ia32_vec_set_v2di: - case X86::BI__builtin_ia32_vinsertf128_pd256: - case X86::BI__builtin_ia32_vinsertf128_ps256: - case X86::BI__builtin_ia32_vinsertf128_si256: - case X86::BI__builtin_ia32_insert128i256: - case X86::BI__builtin_ia32_insertf32x8: - case X86::BI__builtin_ia32_inserti32x8: - case X86::BI__builtin_ia32_insertf64x4: - case X86::BI__builtin_ia32_inserti64x4: - case X86::BI__builtin_ia32_insertf64x2_256: - case X86::BI__builtin_ia32_inserti64x2_256: - case X86::BI__builtin_ia32_insertf32x4_256: - case X86::BI__builtin_ia32_inserti32x4_256: - i = 2; l = 0; u = 1; - break; - case X86::BI__builtin_ia32_vpermilpd: - case X86::BI__builtin_ia32_vec_ext_v4hi: - case X86::BI__builtin_ia32_vec_ext_v4si: - case X86::BI__builtin_ia32_vec_ext_v4sf: - case X86::BI__builtin_ia32_vec_ext_v4di: - case X86::BI__builtin_ia32_extractf32x4_mask: - case X86::BI__builtin_ia32_extracti32x4_mask: - case X86::BI__builtin_ia32_extractf64x2_512_mask: - case X86::BI__builtin_ia32_extracti64x2_512_mask: - i = 1; l = 0; u = 3; - break; - case X86::BI_mm_prefetch: - case X86::BI__builtin_ia32_vec_ext_v8hi: - case X86::BI__builtin_ia32_vec_ext_v8si: - i = 1; l = 0; u = 7; - break; - case X86::BI__builtin_ia32_sha1rnds4: - case X86::BI__builtin_ia32_blendpd: - case X86::BI__builtin_ia32_shufpd: - case X86::BI__builtin_ia32_vec_set_v4hi: - case X86::BI__builtin_ia32_vec_set_v4si: - case X86::BI__builtin_ia32_vec_set_v4di: - case X86::BI__builtin_ia32_shuf_f32x4_256: - case X86::BI__builtin_ia32_shuf_f64x2_256: - case X86::BI__builtin_ia32_shuf_i32x4_256: - case X86::BI__builtin_ia32_shuf_i64x2_256: - case X86::BI__builtin_ia32_insertf64x2_512: - case X86::BI__builtin_ia32_inserti64x2_512: - case X86::BI__builtin_ia32_insertf32x4: - case X86::BI__builtin_ia32_inserti32x4: - i = 2; l = 0; u = 3; - break; - case X86::BI__builtin_ia32_vpermil2pd: - case X86::BI__builtin_ia32_vpermil2pd256: - case X86::BI__builtin_ia32_vpermil2ps: - case X86::BI__builtin_ia32_vpermil2ps256: - i = 3; l = 0; u = 3; - break; - case X86::BI__builtin_ia32_cmpb128_mask: - case X86::BI__builtin_ia32_cmpw128_mask: - case X86::BI__builtin_ia32_cmpd128_mask: - case X86::BI__builtin_ia32_cmpq128_mask: - case X86::BI__builtin_ia32_cmpb256_mask: - case X86::BI__builtin_ia32_cmpw256_mask: - case X86::BI__builtin_ia32_cmpd256_mask: - case X86::BI__builtin_ia32_cmpq256_mask: - case X86::BI__builtin_ia32_cmpb512_mask: - case X86::BI__builtin_ia32_cmpw512_mask: - case X86::BI__builtin_ia32_cmpd512_mask: - case X86::BI__builtin_ia32_cmpq512_mask: - case X86::BI__builtin_ia32_ucmpb128_mask: - case X86::BI__builtin_ia32_ucmpw128_mask: - case X86::BI__builtin_ia32_ucmpd128_mask: - case X86::BI__builtin_ia32_ucmpq128_mask: - case X86::BI__builtin_ia32_ucmpb256_mask: - case X86::BI__builtin_ia32_ucmpw256_mask: - case X86::BI__builtin_ia32_ucmpd256_mask: - case X86::BI__builtin_ia32_ucmpq256_mask: - case X86::BI__builtin_ia32_ucmpb512_mask: - case X86::BI__builtin_ia32_ucmpw512_mask: - case X86::BI__builtin_ia32_ucmpd512_mask: - case X86::BI__builtin_ia32_ucmpq512_mask: - case X86::BI__builtin_ia32_vpcomub: - case X86::BI__builtin_ia32_vpcomuw: - case X86::BI__builtin_ia32_vpcomud: - case X86::BI__builtin_ia32_vpcomuq: - case X86::BI__builtin_ia32_vpcomb: - case X86::BI__builtin_ia32_vpcomw: - case X86::BI__builtin_ia32_vpcomd: - case X86::BI__builtin_ia32_vpcomq: - case X86::BI__builtin_ia32_vec_set_v8hi: - case X86::BI__builtin_ia32_vec_set_v8si: - i = 2; l = 0; u = 7; - break; - case X86::BI__builtin_ia32_vpermilpd256: - case X86::BI__builtin_ia32_roundps: - case X86::BI__builtin_ia32_roundpd: - case X86::BI__builtin_ia32_roundps256: - case X86::BI__builtin_ia32_roundpd256: - case X86::BI__builtin_ia32_getmantpd128_mask: - case X86::BI__builtin_ia32_getmantpd256_mask: - case X86::BI__builtin_ia32_getmantps128_mask: - case X86::BI__builtin_ia32_getmantps256_mask: - case X86::BI__builtin_ia32_getmantpd512_mask: - case X86::BI__builtin_ia32_getmantps512_mask: - case X86::BI__builtin_ia32_getmantph128_mask: - case X86::BI__builtin_ia32_getmantph256_mask: - case X86::BI__builtin_ia32_getmantph512_mask: - case X86::BI__builtin_ia32_vec_ext_v16qi: - case X86::BI__builtin_ia32_vec_ext_v16hi: - i = 1; l = 0; u = 15; - break; - case X86::BI__builtin_ia32_pblendd128: - case X86::BI__builtin_ia32_blendps: - case X86::BI__builtin_ia32_blendpd256: - case X86::BI__builtin_ia32_shufpd256: - case X86::BI__builtin_ia32_roundss: - case X86::BI__builtin_ia32_roundsd: - case X86::BI__builtin_ia32_rangepd128_mask: - case X86::BI__builtin_ia32_rangepd256_mask: - case X86::BI__builtin_ia32_rangepd512_mask: - case X86::BI__builtin_ia32_rangeps128_mask: - case X86::BI__builtin_ia32_rangeps256_mask: - case X86::BI__builtin_ia32_rangeps512_mask: - case X86::BI__builtin_ia32_getmantsd_round_mask: - case X86::BI__builtin_ia32_getmantss_round_mask: - case X86::BI__builtin_ia32_getmantsh_round_mask: - case X86::BI__builtin_ia32_vec_set_v16qi: - case X86::BI__builtin_ia32_vec_set_v16hi: - i = 2; l = 0; u = 15; - break; - case X86::BI__builtin_ia32_vec_ext_v32qi: - i = 1; l = 0; u = 31; - break; - case X86::BI__builtin_ia32_cmpps: - case X86::BI__builtin_ia32_cmpss: - case X86::BI__builtin_ia32_cmppd: - case X86::BI__builtin_ia32_cmpsd: - case X86::BI__builtin_ia32_cmpps256: - case X86::BI__builtin_ia32_cmppd256: - case X86::BI__builtin_ia32_cmpps128_mask: - case X86::BI__builtin_ia32_cmppd128_mask: - case X86::BI__builtin_ia32_cmpps256_mask: - case X86::BI__builtin_ia32_cmppd256_mask: - case X86::BI__builtin_ia32_cmpps512_mask: - case X86::BI__builtin_ia32_cmppd512_mask: - case X86::BI__builtin_ia32_cmpsd_mask: - case X86::BI__builtin_ia32_cmpss_mask: - case X86::BI__builtin_ia32_vec_set_v32qi: - i = 2; l = 0; u = 31; - break; - case X86::BI__builtin_ia32_permdf256: - case X86::BI__builtin_ia32_permdi256: - case X86::BI__builtin_ia32_permdf512: - case X86::BI__builtin_ia32_permdi512: - case X86::BI__builtin_ia32_vpermilps: - case X86::BI__builtin_ia32_vpermilps256: - case X86::BI__builtin_ia32_vpermilpd512: - case X86::BI__builtin_ia32_vpermilps512: - case X86::BI__builtin_ia32_pshufd: - case X86::BI__builtin_ia32_pshufd256: - case X86::BI__builtin_ia32_pshufd512: - case X86::BI__builtin_ia32_pshufhw: - case X86::BI__builtin_ia32_pshufhw256: - case X86::BI__builtin_ia32_pshufhw512: - case X86::BI__builtin_ia32_pshuflw: - case X86::BI__builtin_ia32_pshuflw256: - case X86::BI__builtin_ia32_pshuflw512: - case X86::BI__builtin_ia32_vcvtps2ph: - case X86::BI__builtin_ia32_vcvtps2ph_mask: - case X86::BI__builtin_ia32_vcvtps2ph256: - case X86::BI__builtin_ia32_vcvtps2ph256_mask: - case X86::BI__builtin_ia32_vcvtps2ph512_mask: - case X86::BI__builtin_ia32_rndscaleps_128_mask: - case X86::BI__builtin_ia32_rndscalepd_128_mask: - case X86::BI__builtin_ia32_rndscaleps_256_mask: - case X86::BI__builtin_ia32_rndscalepd_256_mask: - case X86::BI__builtin_ia32_rndscaleps_mask: - case X86::BI__builtin_ia32_rndscalepd_mask: - case X86::BI__builtin_ia32_rndscaleph_mask: - case X86::BI__builtin_ia32_reducepd128_mask: - case X86::BI__builtin_ia32_reducepd256_mask: - case X86::BI__builtin_ia32_reducepd512_mask: - case X86::BI__builtin_ia32_reduceps128_mask: - case X86::BI__builtin_ia32_reduceps256_mask: - case X86::BI__builtin_ia32_reduceps512_mask: - case X86::BI__builtin_ia32_reduceph128_mask: - case X86::BI__builtin_ia32_reduceph256_mask: - case X86::BI__builtin_ia32_reduceph512_mask: - case X86::BI__builtin_ia32_prold512: - case X86::BI__builtin_ia32_prolq512: - case X86::BI__builtin_ia32_prold128: - case X86::BI__builtin_ia32_prold256: - case X86::BI__builtin_ia32_prolq128: - case X86::BI__builtin_ia32_prolq256: - case X86::BI__builtin_ia32_prord512: - case X86::BI__builtin_ia32_prorq512: - case X86::BI__builtin_ia32_prord128: - case X86::BI__builtin_ia32_prord256: - case X86::BI__builtin_ia32_prorq128: - case X86::BI__builtin_ia32_prorq256: - case X86::BI__builtin_ia32_fpclasspd128_mask: - case X86::BI__builtin_ia32_fpclasspd256_mask: - case X86::BI__builtin_ia32_fpclassps128_mask: - case X86::BI__builtin_ia32_fpclassps256_mask: - case X86::BI__builtin_ia32_fpclassps512_mask: - case X86::BI__builtin_ia32_fpclasspd512_mask: - case X86::BI__builtin_ia32_fpclassph128_mask: - case X86::BI__builtin_ia32_fpclassph256_mask: - case X86::BI__builtin_ia32_fpclassph512_mask: - case X86::BI__builtin_ia32_fpclasssd_mask: - case X86::BI__builtin_ia32_fpclassss_mask: - case X86::BI__builtin_ia32_fpclasssh_mask: - case X86::BI__builtin_ia32_pslldqi128_byteshift: - case X86::BI__builtin_ia32_pslldqi256_byteshift: - case X86::BI__builtin_ia32_pslldqi512_byteshift: - case X86::BI__builtin_ia32_psrldqi128_byteshift: - case X86::BI__builtin_ia32_psrldqi256_byteshift: - case X86::BI__builtin_ia32_psrldqi512_byteshift: - case X86::BI__builtin_ia32_kshiftliqi: - case X86::BI__builtin_ia32_kshiftlihi: - case X86::BI__builtin_ia32_kshiftlisi: - case X86::BI__builtin_ia32_kshiftlidi: - case X86::BI__builtin_ia32_kshiftriqi: - case X86::BI__builtin_ia32_kshiftrihi: - case X86::BI__builtin_ia32_kshiftrisi: - case X86::BI__builtin_ia32_kshiftridi: - i = 1; l = 0; u = 255; - break; - case X86::BI__builtin_ia32_vperm2f128_pd256: - case X86::BI__builtin_ia32_vperm2f128_ps256: - case X86::BI__builtin_ia32_vperm2f128_si256: - case X86::BI__builtin_ia32_permti256: - case X86::BI__builtin_ia32_pblendw128: - case X86::BI__builtin_ia32_pblendw256: - case X86::BI__builtin_ia32_blendps256: - case X86::BI__builtin_ia32_pblendd256: - case X86::BI__builtin_ia32_palignr128: - case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr512: - case X86::BI__builtin_ia32_alignq512: - case X86::BI__builtin_ia32_alignd512: - case X86::BI__builtin_ia32_alignd128: - case X86::BI__builtin_ia32_alignd256: - case X86::BI__builtin_ia32_alignq128: - case X86::BI__builtin_ia32_alignq256: - case X86::BI__builtin_ia32_vcomisd: - case X86::BI__builtin_ia32_vcomiss: - case X86::BI__builtin_ia32_shuf_f32x4: - case X86::BI__builtin_ia32_shuf_f64x2: - case X86::BI__builtin_ia32_shuf_i32x4: - case X86::BI__builtin_ia32_shuf_i64x2: - case X86::BI__builtin_ia32_shufpd512: - case X86::BI__builtin_ia32_shufps: - case X86::BI__builtin_ia32_shufps256: - case X86::BI__builtin_ia32_shufps512: - case X86::BI__builtin_ia32_dbpsadbw128: - case X86::BI__builtin_ia32_dbpsadbw256: - case X86::BI__builtin_ia32_dbpsadbw512: - case X86::BI__builtin_ia32_vpshldd128: - case X86::BI__builtin_ia32_vpshldd256: - case X86::BI__builtin_ia32_vpshldd512: - case X86::BI__builtin_ia32_vpshldq128: - case X86::BI__builtin_ia32_vpshldq256: - case X86::BI__builtin_ia32_vpshldq512: - case X86::BI__builtin_ia32_vpshldw128: - case X86::BI__builtin_ia32_vpshldw256: - case X86::BI__builtin_ia32_vpshldw512: - case X86::BI__builtin_ia32_vpshrdd128: - case X86::BI__builtin_ia32_vpshrdd256: - case X86::BI__builtin_ia32_vpshrdd512: - case X86::BI__builtin_ia32_vpshrdq128: - case X86::BI__builtin_ia32_vpshrdq256: - case X86::BI__builtin_ia32_vpshrdq512: - case X86::BI__builtin_ia32_vpshrdw128: - case X86::BI__builtin_ia32_vpshrdw256: - case X86::BI__builtin_ia32_vpshrdw512: - i = 2; l = 0; u = 255; - break; - case X86::BI__builtin_ia32_fixupimmpd512_mask: - case X86::BI__builtin_ia32_fixupimmpd512_maskz: - case X86::BI__builtin_ia32_fixupimmps512_mask: - case X86::BI__builtin_ia32_fixupimmps512_maskz: - case X86::BI__builtin_ia32_fixupimmsd_mask: - case X86::BI__builtin_ia32_fixupimmsd_maskz: - case X86::BI__builtin_ia32_fixupimmss_mask: - case X86::BI__builtin_ia32_fixupimmss_maskz: - case X86::BI__builtin_ia32_fixupimmpd128_mask: - case X86::BI__builtin_ia32_fixupimmpd128_maskz: - case X86::BI__builtin_ia32_fixupimmpd256_mask: - case X86::BI__builtin_ia32_fixupimmpd256_maskz: - case X86::BI__builtin_ia32_fixupimmps128_mask: - case X86::BI__builtin_ia32_fixupimmps128_maskz: - case X86::BI__builtin_ia32_fixupimmps256_mask: - case X86::BI__builtin_ia32_fixupimmps256_maskz: - case X86::BI__builtin_ia32_pternlogd512_mask: - case X86::BI__builtin_ia32_pternlogd512_maskz: - case X86::BI__builtin_ia32_pternlogq512_mask: - case X86::BI__builtin_ia32_pternlogq512_maskz: - case X86::BI__builtin_ia32_pternlogd128_mask: - case X86::BI__builtin_ia32_pternlogd128_maskz: - case X86::BI__builtin_ia32_pternlogd256_mask: - case X86::BI__builtin_ia32_pternlogd256_maskz: - case X86::BI__builtin_ia32_pternlogq128_mask: - case X86::BI__builtin_ia32_pternlogq128_maskz: - case X86::BI__builtin_ia32_pternlogq256_mask: - case X86::BI__builtin_ia32_pternlogq256_maskz: - case X86::BI__builtin_ia32_vsm3rnds2: - i = 3; l = 0; u = 255; + if (BuiltinElementwiseTernaryMath(TheCall)) + return true; + if (CheckFloatOrHalfRepresentations(this, TheCall)) + return true; break; - case X86::BI__builtin_ia32_gatherpfdpd: - case X86::BI__builtin_ia32_gatherpfdps: - case X86::BI__builtin_ia32_gatherpfqpd: - case X86::BI__builtin_ia32_gatherpfqps: - case X86::BI__builtin_ia32_scatterpfdpd: - case X86::BI__builtin_ia32_scatterpfdps: - case X86::BI__builtin_ia32_scatterpfqpd: - case X86::BI__builtin_ia32_scatterpfqps: - i = 4; l = 2; u = 3; + } + case Builtin::BI__builtin_hlsl_mad: { + if (checkArgCount(TheCall, 3)) + return true; + if (CheckVectorElementCallArgs(this, TheCall)) + return true; + if (BuiltinElementwiseTernaryMath( + TheCall, /*CheckForFloatArgs*/ + TheCall->getArg(0)->getType()->hasFloatingRepresentation())) + return true; break; - case X86::BI__builtin_ia32_reducesd_mask: - case X86::BI__builtin_ia32_reducess_mask: - case X86::BI__builtin_ia32_rndscalesd_round_mask: - case X86::BI__builtin_ia32_rndscaless_round_mask: - case X86::BI__builtin_ia32_rndscalesh_round_mask: - case X86::BI__builtin_ia32_reducesh_mask: - i = 4; l = 0; u = 255; + } + // Note these are llvm builtins that we want to catch invalid intrinsic + // generation. Normal handling of these builitns will occur elsewhere. + case Builtin::BI__builtin_elementwise_bitreverse: { + if (CheckUnsignedIntRepresentation(this, TheCall)) + return true; break; - case X86::BI__builtin_ia32_cmpccxadd32: - case X86::BI__builtin_ia32_cmpccxadd64: - i = 3; l = 0; u = 15; + } + case Builtin::BI__builtin_elementwise_ceil: + case Builtin::BI__builtin_elementwise_cos: + case Builtin::BI__builtin_elementwise_exp: + case Builtin::BI__builtin_elementwise_exp2: + case Builtin::BI__builtin_elementwise_floor: + case Builtin::BI__builtin_elementwise_log: + case Builtin::BI__builtin_elementwise_log2: + case Builtin::BI__builtin_elementwise_log10: + case Builtin::BI__builtin_elementwise_pow: + case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_sin: + case Builtin::BI__builtin_elementwise_sqrt: + case Builtin::BI__builtin_elementwise_tan: + case Builtin::BI__builtin_elementwise_trunc: { + if (CheckFloatOrHalfRepresentations(this, TheCall)) + return true; break; } - - // Note that we don't force a hard error on the range check here, allowing - // template-generated or macro-generated dead code to potentially have out-of- - // range values. These need to code generate, but don't need to necessarily - // make any sense. We use a warning that defaults to an error. - return BuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); + } + return false; } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -7831,40 +3771,6 @@ static void CheckNonNullArguments(Sema &S, } } -// 16 byte ByVal alignment not due to a vector member is not honoured by XL -// on AIX. Emit a warning here that users are generating binary incompatible -// code to be safe. -// Here we try to get information about the alignment of the struct member -// from the struct passed to the caller function. We only warn when the struct -// is passed byval, hence the series of checks and early returns if we are a not -// passing a struct byval. -void Sema::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { - const auto *ICE = dyn_cast(Arg->IgnoreParens()); - if (!ICE) - return; - - const auto *DR = dyn_cast(ICE->getSubExpr()); - if (!DR) - return; - - const auto *PD = dyn_cast(DR->getDecl()); - if (!PD || !PD->getType()->isRecordType()) - return; - - QualType ArgType = Arg->getType(); - for (const FieldDecl *FD : - ArgType->castAs()->getDecl()->fields()) { - if (const auto *AA = FD->getAttr()) { - CharUnits Alignment = - Context.toCharUnitsFromBits(AA->getAlignment(Context)); - if (Alignment.getQuantity() == 16) { - Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD; - Diag(Loc, diag::note_misaligned_member_used_here) << PD; - } - } - } -} - /// Warn if a pointer or reference argument passed to a function points to an /// object that is less aligned than the parameter. This can happen when /// creating a typedef with a lower alignment than the original type and then @@ -7981,7 +3887,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, FDecl->hasLinkage() && FDecl->getFormalLinkage() != Linkage::Internal && CallType == VariadicDoesNotApply) - checkAIXMemberAlignment((Arg->getExprLoc()), Arg); + PPC().checkAIXMemberAlignment((Arg->getExprLoc()), Arg); QualType ParamTy = Proto->getParamType(ArgIdx); if (ParamTy->isSizelessVectorType()) @@ -8017,10 +3923,10 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, bool IsCalleeStreamingCompatible = ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMCompatibleMask; - ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); + SemaARM::ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); if (!IsCalleeStreamingCompatible && - (CallerFnType == ArmStreamingCompatible || - ((CallerFnType == ArmStreaming) ^ IsCalleeStreaming))) { + (CallerFnType == SemaARM::ArmStreamingCompatible || + ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) { if (IsScalableArg) Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) << /*IsArg=*/true; @@ -8521,7 +4427,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, const PointerType *pointerType = Ptr->getType()->getAs(); if (!pointerType) { Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) - << Ptr->getType() << Ptr->getSourceRange(); + << Ptr->getType() << 0 << Ptr->getSourceRange(); return ExprError(); } @@ -8550,6 +4456,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } } + // Pointer to object of size zero is not allowed. + if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { + Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) + << Ptr->getType() << 1 << Ptr->getSourceRange(); + return ExprError(); + } + // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // GCC does not enforce these rules for GNU atomics, but we do to help catch @@ -8876,35 +4789,6 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { return false; } -bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) { - if (TheCall->getNumArgs() != 0) - return true; - - TheCall->setType(Context.getWebAssemblyExternrefType()); - - return false; -} - -bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) { - if (TheCall->getNumArgs() != 0) { - Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs() - << /*is non object*/ 0; - return true; - } - - // This custom type checking code ensures that the nodes are as expected - // in order to later on generate the necessary builtin. - QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {}); - QualType Type = Context.getPointerType(Pointee); - Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref); - Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type, - Context.getPointerType(Pointee)); - TheCall->setType(Type); - - return false; -} - /// We have a call to a function like __sync_fetch_and_add, which is an /// overloaded function based on the pointer type of its first argument. /// The main BuildCallExpr routines have already promoted the types of @@ -8941,7 +4825,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { const PointerType *pointerType = FirstArg->getType()->getAs(); if (!pointerType) { Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) - << FirstArg->getType() << FirstArg->getSourceRange(); + << FirstArg->getType() << 0 << FirstArg->getSourceRange(); return ExprError(); } @@ -8949,7 +4833,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType()) { Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr) - << FirstArg->getType() << FirstArg->getSourceRange(); + << FirstArg->getType() << 0 << FirstArg->getSourceRange(); return ExprError(); } @@ -9302,7 +5186,7 @@ ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) { unsigned numArgs = isStore ? 2 : 1; // Ensure that we have the proper number of arguments. - if (checkArgCount(*this, TheCall, numArgs)) + if (checkArgCount(TheCall, numArgs)) return ExprError(); // Inspect the last argument of the nontemporal builtin. This should always @@ -9467,7 +5351,7 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { // In C23 mode, va_start only needs one argument. However, the builtin still // requires two arguments (which matches the behavior of the GCC builtin), // passes `0` as the second argument in C23 mode. - if (checkArgCount(*this, TheCall, 2)) + if (checkArgCount(TheCall, 2)) return true; // Type-check the first argument normally. @@ -9598,7 +5482,7 @@ bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) { /// BuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { - if (checkArgCount(*this, TheCall, 2)) + if (checkArgCount(TheCall, 2)) return true; if (BuiltinID == Builtin::BI__builtin_isunordered && @@ -9642,7 +5526,7 @@ bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { /// to check everything. bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, unsigned BuiltinID) { - if (checkArgCount(*this, TheCall, NumArgs)) + if (checkArgCount(TheCall, NumArgs)) return true; FPOptions FPO = TheCall->getFPFeaturesInEffect(getLangOpts()); @@ -9727,7 +5611,7 @@ bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, /// Perform semantic analysis for a call to __builtin_complex. bool Sema::BuiltinComplex(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 2)) + if (checkArgCount(TheCall, 2)) return true; bool Dependent = false; @@ -9780,55 +5664,6 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) { return false; } -// Customized Sema Checking for VSX builtins that have the following signature: -// vector [...] builtinName(vector [...], vector [...], const int); -// Which takes the same type of vectors (any legal vector type) for the first -// two arguments and takes compile time constant for the third argument. -// Example builtins are : -// vector double vec_xxpermdi(vector double, vector double, int); -// vector short vec_xxsldwi(vector short, vector short, int); -bool Sema::BuiltinVSX(CallExpr *TheCall) { - unsigned ExpectedNumArgs = 3; - if (checkArgCount(*this, TheCall, ExpectedNumArgs)) - return true; - - // Check the third argument is a compile time constant - if (!TheCall->getArg(2)->isIntegerConstantExpr(Context)) - return Diag(TheCall->getBeginLoc(), - diag::err_vsx_builtin_nonconstant_argument) - << 3 /* argument index */ << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(2)->getBeginLoc(), - TheCall->getArg(2)->getEndLoc()); - - QualType Arg1Ty = TheCall->getArg(0)->getType(); - QualType Arg2Ty = TheCall->getArg(1)->getType(); - - // Check the type of argument 1 and argument 2 are vectors. - SourceLocation BuiltinLoc = TheCall->getBeginLoc(); - if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || - (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { - return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - } - - // Check the first two arguments are the same type. - if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { - return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - } - - // When default clang type checking is turned off and the customized type - // checking is used, the returning type of the function must be explicitly - // set. Otherwise it is _Bool by default. - TheCall->setType(Arg1Ty); - - return false; -} - /// BuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { @@ -9976,7 +5811,7 @@ bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) { if (!Context.getTargetInfo().checkArithmeticFenceSupported()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return true; Expr *Arg = TheCall->getArg(0); if (Arg->isInstantiationDependent()) @@ -10046,7 +5881,7 @@ bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) { /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { - if (checkArgCountRange(*this, TheCall, 2, 3)) + if (checkArgCountRange(TheCall, 2, 3)) return true; unsigned NumArgs = TheCall->getNumArgs(); @@ -10346,360 +6181,6 @@ bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, << Arg->getSourceRange(); } -/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions -bool Sema::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { - if (BuiltinID == AArch64::BI__builtin_arm_irg) { - if (checkArgCount(*this, TheCall, 2)) - return true; - Expr *Arg0 = TheCall->getArg(0); - Expr *Arg1 = TheCall->getArg(1); - - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - ExprResult SecArg = DefaultLvalueConversion(Arg1); - if (SecArg.isInvalid()) - return true; - QualType SecArgType = SecArg.get()->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); - - // Derive the return type from the pointer argument. - TheCall->setType(FirstArgType); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_addg) { - if (checkArgCount(*this, TheCall, 2)) - return true; - - Expr *Arg0 = TheCall->getArg(0); - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - // Derive the return type from the pointer argument. - TheCall->setType(FirstArgType); - - // Second arg must be an constant in range [0,15] - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - } - - if (BuiltinID == AArch64::BI__builtin_arm_gmi) { - if (checkArgCount(*this, TheCall, 2)) - return true; - Expr *Arg0 = TheCall->getArg(0); - Expr *Arg1 = TheCall->getArg(1); - - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - - QualType SecArgType = Arg1->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); - TheCall->setType(Context.IntTy); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_ldg || - BuiltinID == AArch64::BI__builtin_arm_stg) { - if (checkArgCount(*this, TheCall, 1)) - return true; - Expr *Arg0 = TheCall->getArg(0); - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - // Derive the return type from the pointer argument. - if (BuiltinID == AArch64::BI__builtin_arm_ldg) - TheCall->setType(FirstArgType); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_subp) { - Expr *ArgA = TheCall->getArg(0); - Expr *ArgB = TheCall->getArg(1); - - ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA); - ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB); - - if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) - return true; - - QualType ArgTypeA = ArgExprA.get()->getType(); - QualType ArgTypeB = ArgExprB.get()->getType(); - - auto isNull = [&] (Expr *E) -> bool { - return E->isNullPointerConstant( - Context, Expr::NPC_ValueDependentIsNotNull); }; - - // argument should be either a pointer or null - if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) - << "first" << ArgTypeA << ArgA->getSourceRange(); - - if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) - << "second" << ArgTypeB << ArgB->getSourceRange(); - - // Ensure Pointee types are compatible - if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && - ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { - QualType pointeeA = ArgTypeA->getPointeeType(); - QualType pointeeB = ArgTypeB->getPointeeType(); - if (!Context.typesAreCompatible( - Context.getCanonicalType(pointeeA).getUnqualifiedType(), - Context.getCanonicalType(pointeeB).getUnqualifiedType())) { - return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible) - << ArgTypeA << ArgTypeB << ArgA->getSourceRange() - << ArgB->getSourceRange(); - } - } - - // at least one argument should be pointer type - if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) - << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); - - if (isNull(ArgA)) // adopt type of the other pointer - ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); - - if (isNull(ArgB)) - ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); - - TheCall->setArg(0, ArgExprA.get()); - TheCall->setArg(1, ArgExprB.get()); - TheCall->setType(Context.LongLongTy); - return false; - } - assert(false && "Unhandled ARM MTE intrinsic"); - return true; -} - -/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr -/// TheCall is an ARM/AArch64 special register string literal. -bool Sema::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName) { - bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_wsr64 || - BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsr || - BuiltinID == ARM::BI__builtin_arm_wsrp; - bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128 || - BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsr || - BuiltinID == AArch64::BI__builtin_arm_wsrp; - assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); - - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check if the argument is a string literal. - if (!isa(Arg->IgnoreParenImpCasts())) - return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) - << Arg->getSourceRange(); - - // Check the type of special register given. - StringRef Reg = cast(Arg->IgnoreParenImpCasts())->getString(); - SmallVector Fields; - Reg.split(Fields, ":"); - - if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) - return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) - << Arg->getSourceRange(); - - // If the string is the name of a register then we cannot check that it is - // valid here but if the string is of one the forms described in ACLE then we - // can check that the supplied fields are integers and within the valid - // ranges. - if (Fields.size() > 1) { - bool FiveFields = Fields.size() == 5; - - bool ValidString = true; - if (IsARMBuiltin) { - ValidString &= Fields[0].starts_with_insensitive("cp") || - Fields[0].starts_with_insensitive("p"); - if (ValidString) - Fields[0] = Fields[0].drop_front( - Fields[0].starts_with_insensitive("cp") ? 2 : 1); - - ValidString &= Fields[2].starts_with_insensitive("c"); - if (ValidString) - Fields[2] = Fields[2].drop_front(1); - - if (FiveFields) { - ValidString &= Fields[3].starts_with_insensitive("c"); - if (ValidString) - Fields[3] = Fields[3].drop_front(1); - } - } - - SmallVector Ranges; - if (FiveFields) - Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); - else - Ranges.append({15, 7, 15}); - - for (unsigned i=0; i= 0 && IntField <= Ranges[i]); - } - - if (!ValidString) - return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) - << Arg->getSourceRange(); - } else if (IsAArch64Builtin && Fields.size() == 1) { - // This code validates writes to PSTATE registers. - - // Not a write. - if (TheCall->getNumArgs() != 2) - return false; - - // The 128-bit system register accesses do not touch PSTATE. - if (BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128) - return false; - - // These are the named PSTATE accesses using "MSR (immediate)" instructions, - // along with the upper limit on the immediates allowed. - auto MaxLimit = llvm::StringSwitch>(Reg) - .CaseLower("spsel", 15) - .CaseLower("daifclr", 15) - .CaseLower("daifset", 15) - .CaseLower("pan", 15) - .CaseLower("uao", 15) - .CaseLower("dit", 15) - .CaseLower("ssbs", 15) - .CaseLower("tco", 15) - .CaseLower("allint", 1) - .CaseLower("pm", 1) - .Default(std::nullopt); - - // If this is not a named PSTATE, just continue without validating, as this - // will be lowered to an "MSR (register)" instruction directly - if (!MaxLimit) - return false; - - // Here we only allow constants in the range for that pstate, as required by - // the ACLE. - // - // While clang also accepts the names of system registers in its ACLE - // intrinsics, we prevent this with the PSTATE names used in MSR (immediate) - // as the value written via a register is different to the value used as an - // immediate to have the same effect. e.g., for the instruction `msr tco, - // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but - // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO. - // - // If a programmer wants to codegen the MSR (register) form of `msr tco, - // xN`, they can still do so by specifying the register using five - // colon-separated numbers in a string. - return BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); - } - - return false; -} - -/// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. -/// Emit an error and return true on failure; return false on success. -/// TypeStr is a string containing the type descriptor of the value returned by -/// the builtin and the descriptors of the expected type of the arguments. -bool Sema::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeStr) { - - assert((TypeStr[0] != '\0') && - "Invalid types in PPC MMA builtin declaration"); - - unsigned Mask = 0; - unsigned ArgNum = 0; - - // The first type in TypeStr is the type of the value returned by the - // builtin. So we first read that type and change the type of TheCall. - QualType type = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - TheCall->setType(type); - - while (*TypeStr != '\0') { - Mask = 0; - QualType ExpectedType = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - if (ArgNum >= TheCall->getNumArgs()) { - ArgNum++; - break; - } - - Expr *Arg = TheCall->getArg(ArgNum); - QualType PassedType = Arg->getType(); - QualType StrippedRVType = PassedType.getCanonicalType(); - - // Strip Restrict/Volatile qualifiers. - if (StrippedRVType.isRestrictQualified() || - StrippedRVType.isVolatileQualified()) - StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType(); - - // The only case where the argument type and expected type are allowed to - // mismatch is if the argument type is a non-void pointer (or array) and - // expected type is a void pointer. - if (StrippedRVType != ExpectedType) - if (!(ExpectedType->isVoidPointerType() && - (StrippedRVType->isPointerType() || StrippedRVType->isArrayType()))) - return Diag(Arg->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << PassedType << ExpectedType << 1 << 0 << 0; - - // If the value of the Mask is not 0, we have a constraint in the size of - // the integer argument so here we ensure the argument is a constant that - // is in the valid range. - if (Mask != 0 && BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) - return true; - - ArgNum++; - } - - // In case we exited early from the previous loop, there are other types to - // read from TypeStr. So we need to read them all to ensure we have the right - // number of arguments in TheCall and if it is not the case, to display a - // better error message. - while (*TypeStr != '\0') { - (void) DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - ArgNum++; - } - if (checkArgCount(*this, TheCall, ArgNum)) - return true; - - return false; -} - /// BuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. @@ -14429,7 +9910,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, // PPC MMA non-pointer types are not allowed as return type. Checking the type // here prevent the user from using a PPC MMA type as trailing return type. if (Context.getTargetInfo().getTriple().isPPC64()) - CheckPPCMMAType(RetValExp->getType(), ReturnLoc); + PPC().CheckPPCMMAType(RetValExp->getType(), ReturnLoc); } /// Check for comparisons of floating-point values using == and !=. Issue a @@ -19706,7 +15187,7 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) { } bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return true; ExprResult A = UsualUnaryConversions(TheCall->getArg(0)); @@ -19745,7 +15226,7 @@ bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) { } bool Sema::BuiltinVectorMath(CallExpr *TheCall, QualType &Res) { - if (checkArgCount(*this, TheCall, 2)) + if (checkArgCount(TheCall, 2)) return true; ExprResult A = TheCall->getArg(0); @@ -19774,7 +15255,7 @@ bool Sema::BuiltinVectorMath(CallExpr *TheCall, QualType &Res) { bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall, bool CheckForFloatArgs) { - if (checkArgCount(*this, TheCall, 3)) + if (checkArgCount(TheCall, 3)) return true; Expr *Args[3]; @@ -19817,7 +15298,7 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall, } bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return true; ExprResult A = UsualUnaryConversions(TheCall->getArg(0)); @@ -19829,7 +15310,7 @@ bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { } bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return true; ExprResult Arg = TheCall->getArg(0); @@ -19845,7 +15326,7 @@ bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) { ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult) { - if (checkArgCount(*this, TheCall, 1)) + if (checkArgCount(TheCall, 1)) return ExprError(); ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0)); @@ -19900,7 +15381,7 @@ ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, return ExprError(); } - if (checkArgCount(*this, TheCall, 4)) + if (checkArgCount(TheCall, 4)) return ExprError(); unsigned PtrArgIdx = 0; @@ -20011,7 +15492,7 @@ ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, ExprResult CallResult) { - if (checkArgCount(*this, TheCall, 3)) + if (checkArgCount(TheCall, 3)) return ExprError(); unsigned PtrArgIdx = 1; @@ -20107,168 +15588,6 @@ ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, return CallResult; } -/// Checks the argument at the given index is a WebAssembly table and if it -/// is, sets ElTy to the element type. -static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, - QualType &ElTy) { - Expr *ArgExpr = E->getArg(ArgIndex); - const auto *ATy = dyn_cast(ArgExpr->getType()); - if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) { - return S.Diag(ArgExpr->getBeginLoc(), - diag::err_wasm_builtin_arg_must_be_table_type) - << ArgIndex + 1 << ArgExpr->getSourceRange(); - } - ElTy = ATy->getElementType(); - return false; -} - -/// Checks the argument at the given index is an integer. -static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, - unsigned ArgIndex) { - Expr *ArgExpr = E->getArg(ArgIndex); - if (!ArgExpr->getType()->isIntegerType()) { - return S.Diag(ArgExpr->getBeginLoc(), - diag::err_wasm_builtin_arg_must_be_integer_type) - << ArgIndex + 1 << ArgExpr->getSourceRange(); - } - return false; -} - -/// Check that the first argument is a WebAssembly table, and the second -/// is an index to use as index into the table. -bool Sema::BuiltinWasmTableGet(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 2)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - // If all is well, we set the type of TheCall to be the type of the - // element of the table. - // i.e. a table.get on an externref table has type externref, - // or whatever the type of the table element is. - TheCall->setType(ElTy); - - return false; -} - -/// Check that the first argumnet is a WebAssembly table, the second is -/// an index to use as index into the table and the third is the reference -/// type to set into the table. -bool Sema::BuiltinWasmTableSet(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 3)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - if (!Context.hasSameType(ElTy, TheCall->getArg(2)->getType())) - return true; - - return false; -} - -/// Check that the argument is a WebAssembly table. -bool Sema::BuiltinWasmTableSize(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 1)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is the -/// value to use for new elements (of a type matching the table type), the -/// third value is an integer. -bool Sema::BuiltinWasmTableGrow(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 3)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - Expr *NewElemArg = TheCall->getArg(1); - if (!Context.hasSameType(ElTy, NewElemArg->getType())) { - return Diag(NewElemArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 2 << 1 << NewElemArg->getSourceRange(); - } - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 2)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is an -/// integer, the third is the value to use to fill the table (of a type -/// matching the table type), and the fourth is an integer. -bool Sema::BuiltinWasmTableFill(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 4)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - Expr *NewElemArg = TheCall->getArg(2); - if (!Context.hasSameType(ElTy, NewElemArg->getType())) { - return Diag(NewElemArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 3 << 1 << NewElemArg->getSourceRange(); - } - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 3)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is also a -/// WebAssembly table (of the same element type), and the third to fifth -/// arguments are integers. -bool Sema::BuiltinWasmTableCopy(CallExpr *TheCall) { - if (checkArgCount(*this, TheCall, 5)) - return true; - - QualType XElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, XElTy)) - return true; - - QualType YElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 1, YElTy)) - return true; - - Expr *TableYArg = TheCall->getArg(1); - if (!Context.hasSameType(XElTy, YElTy)) { - return Diag(TableYArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 2 << 1 << TableYArg->getSourceRange(); - } - - for (int I = 2; I <= 4; I++) { - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, I)) - return true; - } - - return false; -} - /// \brief Enforce the bounds of a TCB /// CheckTCBEnforcement - Enforces that every function in a named TCB only /// directly calls other functions in the same TCB as marked by the enforce_tcb diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index ad3ca4cc94ca638a34c03b2bfa2b42049d736ac3..cd1c5f9391ccd45baeb85243f5dd7607452adbae 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5692,8 +5692,15 @@ QualType getApproximateType(const Expr *E) { } } if (const auto *UO = llvm::dyn_cast(E)) { - if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) - return UO->getSubExpr()->getType()->getPointeeType(); + if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) { + // We recurse into the subexpression because it could be of dependent + // type. + if (auto Pointee = getApproximateType(UO->getSubExpr())->getPointeeType(); + !Pointee.isNull()) + return Pointee; + // Our caller expects a non-null result, even though the SubType is + // supposed to have a pointee. Fall through to Unresolved anyway. + } } return Unresolved; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6764a979168d6e91aba8e951240f9ce5ca508dfc..a6734ef8c30aa8b6c35b29d8239089ea32d09e7d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -50,6 +50,10 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaPPC.h" +#include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSwift.h" +#include "clang/Sema/SemaWasm.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallString.h" @@ -537,8 +541,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); - TemplateName Template = - FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); + TemplateName Template = Context.getQualifiedTemplateName( + SS ? SS->getScopeRep() : nullptr, /*TemplateKeyword=*/false, + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD)); T = Context.getDeducedTemplateSpecializationType(Template, QualType(), false); // Don't wrap in a further UsingType. @@ -1136,12 +1141,10 @@ Corrected: dyn_cast(*Result.begin()); assert(!FoundUsingShadow || TD == cast(FoundUsingShadow->getTargetDecl())); - Template = - FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); - if (SS.isNotEmpty()) - Template = Context.getQualifiedTemplateName(SS.getScopeRep(), - /*TemplateKeyword=*/false, - Template); + Template = Context.getQualifiedTemplateName( + SS.getScopeRep(), + /*TemplateKeyword=*/false, + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD)); } else { // All results were non-template functions. This is a function template // name. @@ -2282,9 +2285,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (LabelDecl *LD = dyn_cast(D)) CheckPoppedLabel(LD, *this, addDiag); - // Remove this name from our lexical scope, and warn on it if we haven't - // already. - IdResolver.RemoveDecl(D); + // Partial translation units that are created in incremental processing must + // not clean up the IdResolver because PTUs should take into account the + // declarations that came from previous PTUs. + if (!PP.isIncrementalProcessingEnabled() || getLangOpts().ObjC) + IdResolver.RemoveDecl(D); + + // Warn on it if we are shadowing a declaration. auto ShadowI = ShadowingDecls.find(D); if (ShadowI != ShadowingDecls.end()) { if (const auto *FD = dyn_cast(ShadowI->second)) { @@ -2912,7 +2919,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, } else if (const auto *MA = dyn_cast(Attr)) NewAttr = S.mergeMinSizeAttr(D, *MA); else if (const auto *SNA = dyn_cast(Attr)) - NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName()); + NewAttr = S.Swift().mergeNameAttr(D, *SNA, SNA->getName()); else if (const auto *OA = dyn_cast(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, *OA); else if (const auto *InternalLinkageA = dyn_cast(Attr)) @@ -2929,9 +2936,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, else if (const auto *UA = dyn_cast(Attr)) NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl()); else if (const auto *IMA = dyn_cast(Attr)) - NewAttr = S.mergeImportModuleAttr(D, *IMA); + NewAttr = S.Wasm().mergeImportModuleAttr(D, *IMA); else if (const auto *INA = dyn_cast(Attr)) - NewAttr = S.mergeImportNameAttr(D, *INA); + NewAttr = S.Wasm().mergeImportNameAttr(D, *INA); else if (const auto *TCBA = dyn_cast(Attr)) NewAttr = S.mergeEnforceTCBAttr(D, *TCBA); else if (const auto *TCBLA = dyn_cast(Attr)) @@ -4985,7 +4992,7 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, if (TagFromDeclSpec->hasNameForLinkage()) return; - // A well-formed anonymous tag must always be a TUK_Definition. + // A well-formed anonymous tag must always be a TagUseKind::Definition. assert(TagFromDeclSpec->isThisDeclarationADefinition()); // The type must match the tag exactly; no qualifiers allowed. @@ -8895,7 +8902,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // PPC MMA non-pointer types are not allowed as non-local variable types. if (Context.getTargetInfo().getTriple().isPPC64() && !NewVD->isLocalVarDecl() && - CheckPPCMMAType(T, NewVD->getLocation())) { + PPC().CheckPPCMMAType(T, NewVD->getLocation())) { NewVD->setInvalidDecl(); return; } @@ -8926,8 +8933,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { const FunctionDecl *FD = cast(CurContext); llvm::StringMap CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); - checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext), - CallerFeatureMap); + RISCV().checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext), + CallerFeatureMap); } } @@ -10242,7 +10249,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // check at the end of the TU (or when the PMF starts) to see that we // have a definition at that point. if (isInline && !D.isFunctionDefinition() && getLangOpts().CPlusPlus20 && - NewFD->hasOwningModule() && NewFD->getOwningModule()->isNamedModule()) { + NewFD->isInNamedModule()) { PendingInlineFuncDecls.insert(NewFD); } } @@ -11867,8 +11874,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, return false; if (!OldDecl || !OldDecl->getAsFunction() || - OldDecl->getDeclContext()->getRedeclContext() != - NewFD->getDeclContext()->getRedeclContext()) { + !OldDecl->getDeclContext()->getRedeclContext()->Equals( + NewFD->getDeclContext()->getRedeclContext())) { // If there's no previous declaration, AND this isn't attempting to cause // multiversioning, this isn't an error condition. if (MVKind == MultiVersionKind::None) @@ -12056,7 +12063,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // PPC MMA non-pointer types are not allowed as function return types. if (Context.getTargetInfo().getTriple().isPPC64() && - CheckPPCMMAType(NewFD->getReturnType(), NewFD->getLocation())) { + PPC().CheckPPCMMAType(NewFD->getReturnType(), NewFD->getLocation())) { NewFD->setInvalidDecl(); } @@ -15348,7 +15355,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // PPC MMA non-pointer types are not allowed as function argument types. if (Context.getTargetInfo().getTriple().isPPC64() && - CheckPPCMMAType(New->getOriginalType(), New->getLocation())) { + PPC().CheckPPCMMAType(New->getOriginalType(), New->getLocation())) { New->setInvalidDecl(); } @@ -17238,9 +17245,9 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, OffsetOfKind OOK, SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; - assert((Name != nullptr || TUK == TUK_Definition) && + assert((Name != nullptr || TUK == TagUseKind::Definition) && "Nameless record must be a definition!"); - assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); + assert(TemplateParameterLists.size() == 0 || TUK != TagUseKind::Reference); OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); @@ -17254,11 +17261,11 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // or a scope specifier, which also conveniently avoids this work // for non-C++ cases. if (TemplateParameterLists.size() > 0 || - (SS.isNotEmpty() && TUK != TUK_Reference)) { + (SS.isNotEmpty() && TUK != TagUseKind::Reference)) { TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( KWLoc, NameLoc, SS, nullptr, TemplateParameterLists, - TUK == TUK_Friend, isMemberSpecialization, Invalid); + TUK == TagUseKind::Friend, isMemberSpecialization, Invalid); // C++23 [dcl.type.elab] p2: // If an elaborated-type-specifier is the sole constituent of a @@ -17273,7 +17280,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // FIXME: Class template partial specializations can be forward declared // per CWG2213, but the resolution failed to allow qualified forward // declarations. This is almost certainly unintentional, so we allow them. - if (TUK == TUK_Declaration && SS.isNotEmpty() && !isMemberSpecialization) + if (TUK == TagUseKind::Declaration && SS.isNotEmpty() && + !isMemberSpecialization) Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) << TypeWithKeyword::getTagTypeKindName(Kind) << SS.getRange(); @@ -17310,7 +17318,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, return true; } - if (TUK == TUK_Friend && Kind == TagTypeKind::Enum) { + if (TUK == TagUseKind::Friend && Kind == TagTypeKind::Enum) { // C++23 [dcl.type.elab]p4: // If an elaborated-type-specifier appears with the friend specifier as // an entire member-declaration, the member-declaration shall have one @@ -17361,7 +17369,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // of 'int'. However, if this is an unfixed forward declaration, don't set // the underlying type unless the user enables -fms-compatibility. This // makes unfixed forward declared enums incomplete and is more conforming. - if (TUK == TUK_Definition || getLangOpts().MSVCCompat) + if (TUK == TagUseKind::Definition || getLangOpts().MSVCCompat) EnumUnderlying = Context.IntTy.getTypePtr(); } } @@ -17372,7 +17380,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, bool isStdAlignValT = false; RedeclarationKind Redecl = forRedeclarationInCurContext(); - if (TUK == TUK_Friend || TUK == TUK_Reference) + if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) Redecl = RedeclarationKind::NotForRedeclaration; /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C @@ -17390,7 +17398,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr, ScopedEnum, ScopedEnumUsesClassTag, IsFixed); // If this is an undefined enum, bail. - if (TUK != TUK_Definition && !Invalid) + if (TUK != TagUseKind::Definition && !Invalid) return nullptr; if (EnumUnderlying) { EnumDecl *ED = cast(New); @@ -17418,7 +17426,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) { + if (TUK == TagUseKind::Definition && + (!SkipBody || !SkipBody->ShouldSkip)) { AddAlignmentAttributesForRecord(RD); AddMsStructLayoutForRecord(RD); } @@ -17439,7 +17448,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // If this is a friend or a reference to a class in a dependent // context, don't try to make a decl for it. - if (TUK == TUK_Friend || TUK == TUK_Reference) { + if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) { DC = computeDeclContext(SS, false); if (!DC) { IsDependent = true; @@ -17472,7 +17481,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // this as a dependent elaborated-type-specifier. // But this only makes any sense for reference-like lookups. if (Previous.wasNotFoundInCurrentInstantiation() && - (TUK == TUK_Reference || TUK == TUK_Friend)) { + (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend)) { IsDependent = true; return true; } @@ -17489,7 +17498,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // If T is the name of a class, then each of the following shall have a // name different from T: // -- every member of class T that is itself a type - if (TUK != TUK_Reference && TUK != TUK_Friend && + if (TUK != TagUseKind::Reference && TUK != TagUseKind::Friend && DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc))) return true; @@ -17503,7 +17512,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // When declaring or defining a tag, ignore ambiguities introduced // by types using'ed into this scope. if (Previous.isAmbiguous() && - (TUK == TUK_Definition || TUK == TUK_Declaration)) { + (TUK == TagUseKind::Definition || TUK == TagUseKind::Declaration)) { LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *ND = F.next(); @@ -17527,7 +17536,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // // Does it matter that this should be by scope instead of by // semantic context? - if (!Previous.empty() && TUK == TUK_Friend) { + if (!Previous.empty() && TUK == TagUseKind::Friend) { DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext(); LookupResult::Filter F = Previous.makeFilter(); bool FriendSawTagOutsideEnclosingNamespace = false; @@ -17557,7 +17566,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, if (Previous.isAmbiguous()) return true; - if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) { + if (!getLangOpts().CPlusPlus && TUK != TagUseKind::Reference) { // FIXME: This makes sure that we ignore the contexts associated // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak @@ -17609,11 +17618,12 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // also need to do a redeclaration lookup there, just in case // there's a shadow friend decl. if (Name && Previous.empty() && - (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) { + (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend || + IsTemplateParamOrArg)) { if (Invalid) goto CreateNewDecl; assert(SS.isEmpty()); - if (TUK == TUK_Reference || IsTemplateParamOrArg) { + if (TUK == TagUseKind::Reference || IsTemplateParamOrArg) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // @@ -17647,7 +17657,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // Find the scope where we'll be declaring the tag. S = getTagInjectionScope(S, getLangOpts()); } else { - assert(TUK == TUK_Friend); + assert(TUK == TagUseKind::Friend); CXXRecordDecl *RD = dyn_cast(SearchDC); // C++ [namespace.memdef]p3: @@ -17712,7 +17722,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // redefinition if either context is within the other. if (auto *Shadow = dyn_cast(DirectPrevDecl)) { auto *OldTag = dyn_cast(PrevDecl); - if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && + if (SS.isEmpty() && TUK != TagUseKind::Reference && + TUK != TagUseKind::Friend && isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) && !(OldTag && isAcceptableTagRedeclContext( *this, OldTag->getDeclContext(), SearchDC))) { @@ -17731,13 +17742,13 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. - if (TUK == TUK_Reference || TUK == TUK_Friend || + if (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend || isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isMemberSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, - TUK == TUK_Definition, KWLoc, + TUK == TagUseKind::Definition, KWLoc, Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TagTypeKind::Enum && @@ -17764,7 +17775,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, if (Kind == TagTypeKind::Enum && PrevTagDecl->getTagKind() == TagTypeKind::Enum) { const EnumDecl *PrevEnum = cast(PrevTagDecl); - if (TUK == TUK_Reference || TUK == TUK_Friend) + if (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend) return PrevTagDecl; QualType EnumUnderlyingTy; @@ -17779,14 +17790,14 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc, ScopedEnum, EnumUnderlyingTy, IsFixed, PrevEnum)) - return TUK == TUK_Declaration ? PrevTagDecl : nullptr; + return TUK == TagUseKind::Declaration ? PrevTagDecl : nullptr; } // C++11 [class.mem]p1: // A member shall not be declared twice in the member-specification, // except that a nested class or member class template can be declared // and then later defined. - if (TUK == TUK_Declaration && PrevDecl->isCXXClassMember() && + if (TUK == TagUseKind::Declaration && PrevDecl->isCXXClassMember() && S->isDeclScope(PrevDecl)) { Diag(NameLoc, diag::ext_member_redeclared); Diag(PrevTagDecl->getLocation(), diag::note_previous_declaration); @@ -17795,11 +17806,11 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, if (!Invalid) { // If this is a use, just return the declaration we found, unless // we have attributes. - if (TUK == TUK_Reference || TUK == TUK_Friend) { + if (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend) { if (!Attrs.empty()) { // FIXME: Diagnose these attributes. For now, we create a new // declaration to hold them. - } else if (TUK == TUK_Reference && + } else if (TUK == TagUseKind::Reference && (PrevTagDecl->getFriendObjectKind() == Decl::FOK_Undeclared || PrevDecl->getOwningModule() != getCurrentModule()) && @@ -17823,7 +17834,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, } // Diagnose attempts to redefine a tag. - if (TUK == TUK_Definition) { + if (TUK == TagUseKind::Definition) { if (NamedDecl *Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error @@ -17903,7 +17914,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // Okay, we're going to make a redeclaration. If this is some kind // of reference, make sure we build the redeclaration in the same DC // as the original, and ignore the current access specifier. - if (TUK == TUK_Friend || TUK == TUK_Reference) { + if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) { SearchDC = PrevTagDecl->getDeclContext(); AS = AS_none; } @@ -17929,7 +17940,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // Use a better diagnostic if an elaborated-type-specifier // found the wrong kind of type on the first // (non-redeclaration) lookup. - if ((TUK == TUK_Reference || TUK == TUK_Friend) && + if ((TUK == TagUseKind::Reference || TUK == TagUseKind::Friend) && !Previous.isForRedeclaration()) { NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); Diag(NameLoc, diag::err_tag_reference_non_tag) @@ -17943,7 +17954,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // do nothing // Diagnose implicit declarations introduced by elaborated types. - } else if (TUK == TUK_Reference || TUK == TUK_Friend) { + } else if (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend) { NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); Diag(NameLoc, diag::err_tag_reference_conflict) << NTK; Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; @@ -18002,7 +18013,7 @@ CreateNewDecl: StdAlignValT = cast(New); // If this is an undefined enum, warn. - if (TUK != TUK_Definition && !Invalid) { + if (TUK != TagUseKind::Definition && !Invalid) { TagDecl *Def; if (IsFixed && cast(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. @@ -18052,21 +18063,22 @@ CreateNewDecl: } // Only C23 and later allow defining new types in 'offsetof()'. - if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus && - !getLangOpts().C23) + if (OOK != OOK_Outside && TUK == TagUseKind::Definition && + !getLangOpts().CPlusPlus && !getLangOpts().C23) Diag(New->getLocation(), diag::ext_type_defined_in_offsetof) << (OOK == OOK_Macro) << New->getSourceRange(); // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration [...]. if (!Invalid && getLangOpts().CPlusPlus && - (IsTypeSpecifier || IsTemplateParamOrArg) && TUK == TUK_Definition) { + (IsTypeSpecifier || IsTemplateParamOrArg) && + TUK == TagUseKind::Definition) { Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTagDeclType(New); Invalid = true; } - if (!Invalid && getLangOpts().CPlusPlus && TUK == TUK_Definition && + if (!Invalid && getLangOpts().CPlusPlus && TUK == TagUseKind::Definition && DC->getDeclKind() == Decl::Enum) { Diag(New->getLocation(), diag::err_type_defined_in_enum) << Context.getTagDeclType(New); @@ -18078,7 +18090,7 @@ CreateNewDecl: if (SS.isSet()) { // If this is either a declaration or a definition, check the // nested-name-specifier against the current context. - if ((TUK == TUK_Definition || TUK == TUK_Declaration) && + if ((TUK == TagUseKind::Definition || TUK == TagUseKind::Declaration) && diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc, /*TemplateId=*/nullptr, isMemberSpecialization)) @@ -18103,7 +18115,7 @@ CreateNewDecl: // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) { + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) { AddAlignmentAttributesForRecord(RD); AddMsStructLayoutForRecord(RD); } @@ -18134,7 +18146,7 @@ CreateNewDecl: if (getLangOpts().CPlusPlus) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. - if (TUK == TUK_Definition && !IsTypeSpecifier) { + if (TUK == TagUseKind::Definition && !IsTypeSpecifier) { Diag(Loc, diag::err_type_defined_in_param_type) << Name; Invalid = true; @@ -18155,7 +18167,7 @@ CreateNewDecl: // In Microsoft mode, a friend declaration also acts as a forward // declaration so we always pass true to setObjectOfFriendDecl to make // the tag name visible. - if (TUK == TUK_Friend) + if (TUK == TagUseKind::Friend) New->setObjectOfFriendDecl(getLangOpts().MSVCCompat); // Set the access specifier. @@ -18165,14 +18177,14 @@ CreateNewDecl: if (PrevDecl) CheckRedeclarationInModule(New, PrevDecl); - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) New->startDefinition(); ProcessDeclAttributeList(S, New, Attrs); AddPragmaAttributes(S, New); // If this has an identifier, add it to the scope stack. - if (TUK == TUK_Friend) { + if (TUK == TagUseKind::Friend) { // We might be replacing an existing declaration in the lookup tables; // if so, borrow its access specifier. if (PrevDecl) @@ -18758,7 +18770,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // PPC MMA non-pointer types are not allowed as field types. if (Context.getTargetInfo().getTriple().isPPC64() && - CheckPPCMMAType(T, NewFD->getLocation())) + PPC().CheckPPCMMAType(T, NewFD->getLocation())) NewFD->setInvalidDecl(); NewFD->setAccess(AS); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ca5938083917f72bedcfb57252bdcc3cfb60d151..ce6b5b1ff6f931442f9e3b27a2c66dd01f9d7dfb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -33,6 +33,7 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Attr.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" @@ -40,10 +41,24 @@ #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaAMDGPU.h" +#include "clang/Sema/SemaARM.h" +#include "clang/Sema/SemaAVR.h" +#include "clang/Sema/SemaBPF.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaM68k.h" +#include "clang/Sema/SemaMIPS.h" +#include "clang/Sema/SemaMSP430.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaOpenCL.h" +#include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSYCL.h" +#include "clang/Sema/SemaSwift.h" +#include "clang/Sema/SemaWasm.h" +#include "clang/Sema/SemaX86.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" @@ -67,192 +82,12 @@ namespace AttributeLangSupport { }; } // end namespace AttributeLangSupport -//===----------------------------------------------------------------------===// -// Helper functions -//===----------------------------------------------------------------------===// - -/// isFunctionOrMethod - Return true if the given decl has function -/// type (function or function-typed variable) or an Objective-C -/// method. -static bool isFunctionOrMethod(const Decl *D) { - return (D->getFunctionType() != nullptr) || isa(D); -} - -/// Return true if the given decl has function type (function or -/// function-typed variable) or an Objective-C method or a block. -static bool isFunctionOrMethodOrBlock(const Decl *D) { - return isFunctionOrMethod(D) || isa(D); -} - -/// Return true if the given decl has a declarator that should have -/// been processed by Sema::GetTypeForDeclarator. -static bool hasDeclarator(const Decl *D) { - // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. - return isa(D) || isa(D) || isa(D) || - isa(D); -} - -/// hasFunctionProto - Return true if the given decl has a argument -/// information. This decl should have already passed -/// isFunctionOrMethod or isFunctionOrMethodOrBlock. -static bool hasFunctionProto(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) - return isa(FnTy); - return isa(D) || isa(D); -} - -/// getFunctionOrMethodNumParams - Return number of function or method -/// parameters. It is an error to call this on a K&R function (use -/// hasFunctionProto first). -static unsigned getFunctionOrMethodNumParams(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) - return cast(FnTy)->getNumParams(); - if (const auto *BD = dyn_cast(D)) - return BD->getNumParams(); - return cast(D)->param_size(); -} - -static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, - unsigned Idx) { - if (const auto *FD = dyn_cast(D)) - return FD->getParamDecl(Idx); - if (const auto *MD = dyn_cast(D)) - return MD->getParamDecl(Idx); - if (const auto *BD = dyn_cast(D)) - return BD->getParamDecl(Idx); - return nullptr; -} - -static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { - if (const FunctionType *FnTy = D->getFunctionType()) - return cast(FnTy)->getParamType(Idx); - if (const auto *BD = dyn_cast(D)) - return BD->getParamDecl(Idx)->getType(); - - return cast(D)->parameters()[Idx]->getType(); -} - -static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { - if (auto *PVD = getFunctionOrMethodParam(D, Idx)) - return PVD->getSourceRange(); - return SourceRange(); -} - -static QualType getFunctionOrMethodResultType(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) - return FnTy->getReturnType(); - return cast(D)->getReturnType(); -} - -static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { - if (const auto *FD = dyn_cast(D)) - return FD->getReturnTypeSourceRange(); - if (const auto *MD = dyn_cast(D)) - return MD->getReturnTypeSourceRange(); - return SourceRange(); -} - -static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) - return cast(FnTy)->isVariadic(); - if (const auto *BD = dyn_cast(D)) - return BD->isVariadic(); - return cast(D)->isVariadic(); -} - -static bool isInstanceMethod(const Decl *D) { - if (const auto *MethodDecl = dyn_cast(D)) - return MethodDecl->isInstance(); - return false; -} - -static inline bool isNSStringType(QualType T, ASTContext &Ctx, - bool AllowNSAttributedString = false) { - const auto *PT = T->getAs(); - if (!PT) - return false; - - ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); - if (!Cls) - return false; - - IdentifierInfo* ClsName = Cls->getIdentifier(); - - if (AllowNSAttributedString && - ClsName == &Ctx.Idents.get("NSAttributedString")) - return true; - // FIXME: Should we walk the chain of classes? - return ClsName == &Ctx.Idents.get("NSString") || - ClsName == &Ctx.Idents.get("NSMutableString"); -} - -static inline bool isCFStringType(QualType T, ASTContext &Ctx) { - const auto *PT = T->getAs(); - if (!PT) - return false; - - const auto *RT = PT->getPointeeType()->getAs(); - if (!RT) - return false; - - const RecordDecl *RD = RT->getDecl(); - if (RD->getTagKind() != TagTypeKind::Struct) - return false; - - return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); -} - static unsigned getNumAttributeArgs(const ParsedAttr &AL) { // FIXME: Include the type in the argument list. return AL.getNumArgs() + AL.hasParsedType(); } -/// A helper function to provide Attribute Location for the Attr types -/// AND the ParsedAttr. -template -static std::enable_if_t, SourceLocation> -getAttrLoc(const AttrInfo &AL) { - return AL.getLocation(); -} -static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } - -/// If Expr is a valid integer constant, get the value of the integer -/// expression and return success or failure. May output an error. -/// -/// Negative argument is implicitly converted to unsigned, unless -/// \p StrictlyUnsigned is true. -template -static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, - uint32_t &Val, unsigned Idx = UINT_MAX, - bool StrictlyUnsigned = false) { - std::optional I = llvm::APSInt(32); - if (Expr->isTypeDependent() || - !(I = Expr->getIntegerConstantExpr(S.Context))) { - if (Idx != UINT_MAX) - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << &AI << Idx << AANT_ArgumentIntegerConstant - << Expr->getSourceRange(); - else - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) - << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); - return false; - } - - if (!I->isIntN(32)) { - S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) - << toString(*I, 10, false) << 32 << /* Unsigned */ 1; - return false; - } - - if (StrictlyUnsigned && I->isSigned() && I->isNegative()) { - S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) - << &AI << /*non-negative*/ 1; - return false; - } - - Val = (uint32_t)I->getZExtValue(); - return true; -} +SourceLocation Sema::getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } /// Wrapper around checkUInt32Argument, with an extra check to be sure /// that the result will fit into a regular (signed) int. All args have the same @@ -261,7 +96,7 @@ template static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, int &Val, unsigned Idx = UINT_MAX) { uint32_t UVal; - if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) + if (!S.checkUInt32Argument(AI, Expr, UVal, Idx)) return false; if (UVal > (uint32_t)std::numeric_limits::max()) { @@ -276,77 +111,6 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Ex return true; } -/// Diagnose mutually exclusive attributes when present on a given -/// declaration. Returns true if diagnosed. -template -static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { - if (const auto *A = D->getAttr()) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << A - << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); - S.Diag(A->getLocation(), diag::note_conflicting_attribute); - return true; - } - return false; -} - -template -static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { - if (const auto *A = D->getAttr()) { - S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) - << &AL << A - << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); - S.Diag(A->getLocation(), diag::note_conflicting_attribute); - return true; - } - return false; -} - -/// Check if IdxExpr is a valid parameter index for a function or -/// instance method D. May output an error. -/// -/// \returns true if IdxExpr is a valid index. -template -static bool checkFunctionOrMethodParameterIndex( - Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, - const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { - assert(isFunctionOrMethodOrBlock(D)); - - // In C++ the implicit 'this' function parameter also counts. - // Parameters are counted from one. - bool HP = hasFunctionProto(D); - bool HasImplicitThisParam = isInstanceMethod(D); - bool IV = HP && isFunctionOrMethodVariadic(D); - unsigned NumParams = - (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; - - std::optional IdxInt; - if (IdxExpr->isTypeDependent() || - !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << &AI << AttrArgNum << AANT_ArgumentIntegerConstant - << IdxExpr->getSourceRange(); - return false; - } - - unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); - if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) - << &AI << AttrArgNum << IdxExpr->getSourceRange(); - return false; - } - if (HasImplicitThisParam && !CanIndexImplicitThis) { - if (IdxSource == 1) { - S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) - << &AI << IdxExpr->getSourceRange(); - return false; - } - } - - Idx = ParamIdx(IdxSource, D); - return true; -} - /// Check if the argument \p E is a ASCII string literal. If not emit an error /// and return false, otherwise set \p Str to the value of the string literal /// and return true. @@ -402,45 +166,6 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation); } -/// Applies the given attribute to the Decl without performing any -/// additional semantic checking. -template -static void handleSimpleAttribute(Sema &S, Decl *D, - const AttributeCommonInfo &CI) { - D->addAttr(::new (S.Context) AttrType(S.Context, CI)); -} - -template -static const Sema::SemaDiagnosticBuilder& -appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { - return Bldr; -} - -template -static const Sema::SemaDiagnosticBuilder& -appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, - DiagnosticArgs &&... ExtraArgs) { - return appendDiagnostics(Bldr << std::forward(ExtraArg), - std::forward(ExtraArgs)...); -} - -/// Add an attribute @c AttrType to declaration @c D, provided that -/// @c PassesCheck is true. -/// Otherwise, emit diagnostic @c DiagID, passing in all parameters -/// specified in @c ExtraArgs. -template -static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, - const AttributeCommonInfo &CI, - bool PassesCheck, unsigned DiagID, - DiagnosticArgs &&... ExtraArgs) { - if (!PassesCheck) { - Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); - appendDiagnostics(DB, std::forward(ExtraArgs)...); - return; - } - handleSimpleAttribute(S, D, CI); -} - /// Check if the passed-in expression is of type int or bool. static bool isIntOrBool(Expr *Exp) { QualType QT = Exp->getType(); @@ -827,8 +552,8 @@ static bool checkParamIsIntegerType(Sema &S, const Decl *D, const AttrInfo &AI, assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); ParamIdx Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, AI, AttrArgNo + 1, AttrArg, - Idx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AI, AttrArgNo + 1, AttrArg, + Idx)) return false; QualType ParamTy = getFunctionOrMethodParamType(D, Idx.getASTIndex()); @@ -845,7 +570,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) return; - assert(isFunctionOrMethod(D) && hasFunctionProto(D)); + assert(isFuncOrMethodForAttrSubject(D) && hasFunctionProto(D)); QualType RetTy = getFunctionOrMethodResultType(D); if (!RetTy->isPointerType()) { @@ -1100,7 +825,7 @@ static void handleDiagnoseAsBuiltinAttr(Sema &S, Decl *D, const Expr *IndexExpr = AL.getArgAsExpr(I); uint32_t Index; - if (!checkUInt32Argument(S, AL, IndexExpr, Index, I + 1, false)) + if (!S.checkUInt32Argument(AL, IndexExpr, Index, I + 1, false)) return; if (Index > DeclFD->getNumParams()) { @@ -1210,7 +935,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0); uint32_t Type; - if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1)) + if (!S.checkUInt32Argument(AL, E, Type, /*Idx=*/1)) return; // pass_object_size's argument is passed in as the second argument of @@ -1497,82 +1222,6 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) { << TT->getDecl(); } -static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { - // The IBOutlet/IBOutletCollection attributes only apply to instance - // variables or properties of Objective-C classes. The outlet must also - // have an object reference type. - if (const auto *VD = dyn_cast(D)) { - if (!VD->getType()->getAs()) { - S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) - << AL << VD->getType() << 0; - return false; - } - } - else if (const auto *PD = dyn_cast(D)) { - if (!PD->getType()->getAs()) { - S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) - << AL << PD->getType() << 1; - return false; - } - } - else { - S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL; - return false; - } - - return true; -} - -static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkIBOutletCommon(S, D, AL)) - return; - - D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL)); -} - -static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { - - // The iboutletcollection attribute can have zero or one arguments. - if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; - return; - } - - if (!checkIBOutletCommon(S, D, AL)) - return; - - ParsedType PT; - - if (AL.hasParsedType()) - PT = AL.getTypeArg(); - else { - PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(), - S.getScopeForContext(D->getDeclContext()->getParent())); - if (!PT) { - S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; - return; - } - } - - TypeSourceInfo *QTLoc = nullptr; - QualType QT = S.GetTypeFromParser(PT, &QTLoc); - if (!QTLoc) - QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc()); - - // Diagnose use of non-object type in iboutletcollection attribute. - // FIXME. Gnu attribute extension ignores use of builtin types in - // attributes. So, __attribute__((iboutletcollection(char))) will be - // treated as __attribute__((iboutletcollection())). - if (!QT->isObjCIdType() && !QT->isObjCObjectType()) { - S.Diag(AL.getLoc(), - QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype - : diag::err_iboutletcollection_type) << QT; - return; - } - - D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc)); -} - bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { if (RefOkay) { if (T->isReferenceType()) @@ -1618,7 +1267,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { for (unsigned I = 0; I < AL.getNumArgs(); ++I) { Expr *Ex = AL.getArgAsExpr(I); ParamIdx Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? @@ -1776,7 +1425,7 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, ParamIdx Idx; const auto *FuncDecl = cast(D); - if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, + if (!checkFunctionOrMethodParameterIndex(FuncDecl, TmpAttr, /*AttrArgNum=*/1, ParamExpr, Idx)) return; @@ -1792,43 +1441,6 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx)); } -/// Check if \p AssumptionStr is a known assumption and warn if not. -static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc, - StringRef AssumptionStr) { - if (llvm::KnownAssumptionStrings.count(AssumptionStr)) - return; - - unsigned BestEditDistance = 3; - StringRef Suggestion; - for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) { - unsigned EditDistance = - AssumptionStr.edit_distance(KnownAssumptionIt.getKey()); - if (EditDistance < BestEditDistance) { - Suggestion = KnownAssumptionIt.getKey(); - BestEditDistance = EditDistance; - } - } - - if (!Suggestion.empty()) - S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown_suggested) - << AssumptionStr << Suggestion; - else - S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown) - << AssumptionStr; -} - -static void handleOMPAssumeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Handle the case where the attribute has a text message. - StringRef Str; - SourceLocation AttrStrLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc)) - return; - - checkOMPAssumeAttr(S, AttrStrLoc, Str); - - D->addAttr(::new (S.Context) OMPAssumeAttr(S.Context, AL, Str)); -} - /// Normalize the attribute, __foo__ becomes foo. /// Returns true if normalization was applied. static bool normalizeName(StringRef &AttrName) { @@ -1887,7 +1499,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { for (unsigned i = 1; i < AL.getNumArgs(); ++i) { Expr *Ex = AL.getArgAsExpr(i); ParamIdx Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, i, Ex, Idx)) return; // Is the function argument a pointer type? @@ -2195,21 +1807,6 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) CommonAttr(S.Context, AL)); } -static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) { - S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL; - return; - } - - const auto *FD = cast(D); - if (!FD->isExternallyVisible()) { - S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static); - return; - } - - D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL)); -} - static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isDeclspecAttribute()) { const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); @@ -2295,7 +1892,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. - if (!isFunctionOrMethodOrBlock(D)) { + if (!isFunctionOrMethodOrBlockForAttrSubject(D)) { ValueDecl *VD = dyn_cast(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { @@ -2399,7 +1996,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } if (AL.getNumArgs() && - !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) + !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); @@ -2408,7 +2005,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = DestructorAttr::DefaultPriority; if (AL.getNumArgs() && - !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) + !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); @@ -2424,17 +2021,6 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str)); } -static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - if (!cast(D)->isThisDeclarationADefinition()) { - S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) - << AL << AL.getRange(); - return; - } - - D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL)); -} - static bool checkAvailabilityAttr(Sema &S, SourceRange Range, IdentifierInfo *Platform, VersionTuple Introduced, @@ -3021,113 +2607,6 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, D->addAttr(newAttr); } -static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // objc_direct cannot be set on methods declared in the context of a protocol - if (isa(D->getDeclContext())) { - S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; - return; - } - - if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { - handleSimpleAttribute(S, D, AL); - } else { - S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; - } -} - -static void handleObjCDirectMembersAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { - handleSimpleAttribute(S, D, AL); - } else { - S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; - } -} - -static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - const auto *M = cast(D); - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL << 1 << AANT_ArgumentIdentifier; - return; - } - - IdentifierLoc *IL = AL.getArgAsIdent(0); - ObjCMethodFamilyAttr::FamilyKind F; - if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident; - return; - } - - if (F == ObjCMethodFamilyAttr::OMF_init && - !M->getReturnType()->isObjCObjectPointerType()) { - S.Diag(M->getLocation(), diag::err_init_method_bad_return_type) - << M->getReturnType(); - // Ignore the attribute. - return; - } - - D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F)); -} - -static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { - if (const auto *TD = dyn_cast(D)) { - QualType T = TD->getUnderlyingType(); - if (!T->isCARCBridgableType()) { - S.Diag(TD->getLocation(), diag::err_nsobject_attribute); - return; - } - } - else if (const auto *PD = dyn_cast(D)) { - QualType T = PD->getType(); - if (!T->isCARCBridgableType()) { - S.Diag(PD->getLocation(), diag::err_nsobject_attribute); - return; - } - } - else { - // It is okay to include this attribute on properties, e.g.: - // - // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); - // - // In this case it follows tradition and suppresses an error in the above - // case. - S.Diag(D->getLocation(), diag::warn_nsobject_attribute); - } - D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL)); -} - -static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { - if (const auto *TD = dyn_cast(D)) { - QualType T = TD->getUnderlyingType(); - if (!T->isObjCObjectPointerType()) { - S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); - return; - } - } else { - S.Diag(D->getLocation(), diag::warn_independentclass_attribute); - return; - } - D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL)); -} - -static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL << 1 << AANT_ArgumentIdentifier; - return; - } - - IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; - BlocksAttr::BlockType type; - if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; - return; - } - - D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type)); -} - static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (AL.getNumArgs() > 0) { @@ -3297,8 +2776,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { const Expr *E = AL.getArgAsExpr(i); - if (!checkUInt32Argument(S, AL, E, WGSize[i], i, - /*StrictlyUnsigned=*/true)) + if (!S.checkUInt32Argument(AL, E, WGSize[i], i, + /*StrictlyUnsigned=*/true)) return; if (WGSize[i] == 0) { S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) @@ -3317,27 +2796,6 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2])); } -// Handles intel_reqd_sub_group_size. -static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t SGSize; - const Expr *E = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, E, SGSize)) - return; - if (SGSize == 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) - << AL << E->getSourceRange(); - return; - } - - OpenCLIntelReqdSubGroupSizeAttr *Existing = - D->getAttr(); - if (Existing && Existing->getSubGroupSize() != SGSize) - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; - - D->addAttr(::new (S.Context) - OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize)); -} - static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.hasParsedType()) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -3790,7 +3248,7 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0); uint32_t VecWidth; - if (!checkUInt32Argument(S, AL, E, VecWidth)) { + if (!S.checkUInt32Argument(AL, E, VecWidth)) { AL.setInvalid(); return; } @@ -3908,15 +3366,14 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D, static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { const Expr *IdxExpr = AL.getArgAsExpr(0); ParamIdx Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, 1, IdxExpr, Idx)) return; // Make sure the format string is really a string. QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); - bool NotNSStringTy = !isNSStringType(Ty, S.Context); - if (NotNSStringTy && - !isCFStringType(Ty, S.Context) && + bool NotNSStringTy = !S.ObjC().isNSStringType(Ty); + if (NotNSStringTy && !S.ObjC().isCFStringType(Ty) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) @@ -3931,8 +3388,8 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (auto *Interface = OMD->getClassInterface()) Ty = S.Context.getObjCObjectPointerType( QualType(Interface->getTypeForDecl(), 0)); - if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) && - !isCFStringType(Ty, S.Context) && + if (!S.ObjC().isNSStringType(Ty, /*AllowNSAttributedString=*/true) && + !S.ObjC().isCFStringType(Ty) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) @@ -4003,7 +3460,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0); uint32_t prioritynum; - if (!checkUInt32Argument(S, AL, E, prioritynum)) { + if (!S.checkUInt32Argument(AL, E, prioritynum)) { AL.setInvalid(); return; } @@ -4102,7 +3559,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // checks for the 2nd argument Expr *IdxExpr = AL.getArgAsExpr(1); uint32_t Idx; - if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2)) + if (!S.checkUInt32Argument(AL, IdxExpr, Idx, 2)) return; if (Idx < 1 || Idx > NumArgs) { @@ -4127,8 +3584,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // make sure the format string is really a string QualType Ty = getFunctionOrMethodParamType(D, ArgIdx); - if (!isNSStringType(Ty, S.Context, true) && - !isCFStringType(Ty, S.Context) && + if (!S.ObjC().isNSStringType(Ty, true) && !S.ObjC().isCFStringType(Ty) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) @@ -4139,7 +3595,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the 3rd argument Expr *FirstArgExpr = AL.getArgAsExpr(2); uint32_t FirstArg; - if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) + if (!S.checkUInt32Argument(AL, FirstArgExpr, FirstArg, 3)) return; // FirstArg == 0 is is always valid. @@ -4227,8 +3683,8 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *IdxExpr = AL.getArgAsExpr(I); // If the expression is not parseable as an int32_t we have a problem. - if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1, - false)) { + if (!S.checkUInt32Argument(AL, IdxExpr, (uint32_t &)ArgIdx, I + 1, + false)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << (I + 1) << IdxExpr->getSourceRange(); return; @@ -5088,22 +4544,6 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) { return ::new (Context) MinSizeAttr(Context, CI); } -SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, - StringRef Name) { - if (const auto *PrevSNA = D->getAttr()) { - if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { - Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) - << PrevSNA << &SNA - << (PrevSNA->isRegularKeywordAttribute() || - SNA.isRegularKeywordAttribute()); - Diag(SNA.getLoc(), diag::note_conflicting_attribute); - } - - D->dropAttr(); - } - return ::new (Context) SwiftNameAttr(Context, SNA, Name); -} - OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI) { if (AlwaysInlineAttr *Inline = D->getAttr()) { @@ -5626,99 +5066,11 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, return false; } -/// Pointer-like types in the default address space. -static bool isValidSwiftContextType(QualType Ty) { - if (!Ty->hasPointerRepresentation()) - return Ty->isDependentType(); - return Ty->getPointeeType().getAddressSpace() == LangAS::Default; -} - -/// Pointers and references in the default address space. -static bool isValidSwiftIndirectResultType(QualType Ty) { - if (const auto *PtrType = Ty->getAs()) { - Ty = PtrType->getPointeeType(); - } else if (const auto *RefType = Ty->getAs()) { - Ty = RefType->getPointeeType(); - } else { - return Ty->isDependentType(); - } - return Ty.getAddressSpace() == LangAS::Default; -} - -/// Pointers and references to pointers in the default address space. -static bool isValidSwiftErrorResultType(QualType Ty) { - if (const auto *PtrType = Ty->getAs()) { - Ty = PtrType->getPointeeType(); - } else if (const auto *RefType = Ty->getAs()) { - Ty = RefType->getPointeeType(); - } else { - return Ty->isDependentType(); - } - if (!Ty.getQualifiers().empty()) - return false; - return isValidSwiftContextType(Ty); -} - -void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, - ParameterABI abi) { - - QualType type = cast(D)->getType(); - - if (auto existingAttr = D->getAttr()) { - if (existingAttr->getABI() != abi) { - Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) - << getParameterABISpelling(abi) << existingAttr - << (CI.isRegularKeywordAttribute() || - existingAttr->isRegularKeywordAttribute()); - Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); - return; - } - } - - switch (abi) { - case ParameterABI::Ordinary: - llvm_unreachable("explicit attribute for ordinary parameter ABI?"); - - case ParameterABI::SwiftContext: - if (!isValidSwiftContextType(type)) { - Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type; - } - D->addAttr(::new (Context) SwiftContextAttr(Context, CI)); - return; - - case ParameterABI::SwiftAsyncContext: - if (!isValidSwiftContextType(type)) { - Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type; - } - D->addAttr(::new (Context) SwiftAsyncContextAttr(Context, CI)); - return; - - case ParameterABI::SwiftErrorResult: - if (!isValidSwiftErrorResultType(type)) { - Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type; - } - D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI)); - return; - - case ParameterABI::SwiftIndirectResult: - if (!isValidSwiftIndirectResultType(type)) { - Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) << /*pointer*/ 0 << type; - } - D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI)); - return; - } - llvm_unreachable("bad parameter ABI attribute"); -} - -/// Checks a regparm attribute, returning true if it is ill-formed and -/// otherwise setting numParams to the appropriate value. -bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { - if (AL.isInvalid()) - return true; +/// Checks a regparm attribute, returning true if it is ill-formed and +/// otherwise setting numParams to the appropriate value. +bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { + if (AL.isInvalid()) + return true; if (!AL.checkExactlyNumArgs(*this, 1)) { AL.setInvalid(); @@ -5727,7 +5079,7 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { uint32_t NP; Expr *NumParamsExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) { + if (!checkUInt32Argument(AL, NumParamsExpr, NP)) { AL.setInvalid(); return true; } @@ -5857,13 +5209,13 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, } ParamIdx ArgumentIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1), - ArgumentIdx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, 2, AL.getArgAsExpr(1), + ArgumentIdx)) return; ParamIdx TypeTagIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2), - TypeTagIdx)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, 3, AL.getArgAsExpr(2), + TypeTagIdx)) return; bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag"; @@ -5910,9 +5262,9 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamIdx ArgCount; - if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0), - ArgCount, - true /* CanIndexImplicitThis */)) + if (!S.checkFunctionOrMethodParameterIndex(D, AL, 1, AL.getArgAsExpr(0), + ArgCount, + true /* CanIndexImplicitThis */)) return; // ArgCount isn't a parameter index [0;n), it's a count [1;n] @@ -5923,14 +5275,14 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Count = 0, Offset = 0; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Count, 0, true)) return; if (AL.getNumArgs() == 2) { Expr *Arg = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) + if (!S.checkUInt32Argument(AL, Arg, Offset, 1, true)) return; if (Count < Offset) { - S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) + S.Diag(S.getAttrLoc(AL), diag::err_attribute_argument_out_of_range) << &AL << 0 << Count << Arg->getBeginLoc(); return; } @@ -5939,92 +5291,7 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); } -namespace { -struct IntrinToName { - uint32_t Id; - int32_t FullName; - int32_t ShortName; -}; -} // unnamed namespace - -static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, - ArrayRef Map, - const char *IntrinNames) { - AliasName.consume_front("__arm_"); - const IntrinToName *It = - llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { - return L.Id < Id; - }); - if (It == Map.end() || It->Id != BuiltinID) - return false; - StringRef FullName(&IntrinNames[It->FullName]); - if (AliasName == FullName) - return true; - if (It->ShortName == -1) - return false; - StringRef ShortName(&IntrinNames[It->ShortName]); - return AliasName == ShortName; -} - -static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { -#include "clang/Basic/arm_mve_builtin_aliases.inc" - // The included file defines: - // - ArrayRef Map - // - const char IntrinNames[] - return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); -} - -static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) { -#include "clang/Basic/arm_cde_builtin_aliases.inc" - return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); -} - -static bool ArmSveAliasValid(ASTContext &Context, unsigned BuiltinID, - StringRef AliasName) { - if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) - BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID); - return BuiltinID >= AArch64::FirstSVEBuiltin && - BuiltinID <= AArch64::LastSVEBuiltin; -} - -static bool ArmSmeAliasValid(ASTContext &Context, unsigned BuiltinID, - StringRef AliasName) { - if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) - BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID); - return BuiltinID >= AArch64::FirstSMEBuiltin && - BuiltinID <= AArch64::LastSMEBuiltin; -} - -static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL << 1 << AANT_ArgumentIdentifier; - return; - } - - IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; - unsigned BuiltinID = Ident->getBuiltinID(); - StringRef AliasName = cast(D)->getIdentifier()->getName(); - - bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64(); - if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName) && - !ArmSmeAliasValid(S.Context, BuiltinID, AliasName)) || - (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) && - !ArmCdeAliasValid(BuiltinID, AliasName))) { - S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); - return; - } - - D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident)); -} - -static bool RISCVAliasValid(unsigned BuiltinID, StringRef AliasName) { - return BuiltinID >= RISCV::FirstRVVBuiltin && - BuiltinID <= RISCV::LastRVVBuiltin; -} - -static void handleBuiltinAliasAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { +static void handleBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIdentifier; @@ -6039,10 +5306,10 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D, bool IsARM = S.Context.getTargetInfo().getTriple().isARM(); bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV(); bool IsHLSL = S.Context.getLangOpts().HLSL; - if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) || - (IsARM && !ArmMveAliasValid(BuiltinID, AliasName) && - !ArmCdeAliasValid(BuiltinID, AliasName)) || - (IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) || + if ((IsAArch64 && !S.ARM().SveAliasValid(BuiltinID, AliasName)) || + (IsARM && !S.ARM().MveAliasValid(BuiltinID, AliasName) && + !S.ARM().CdeAliasValid(BuiltinID, AliasName)) || + (IsRISCV && !S.RISCV().isAliasValid(BuiltinID, AliasName)) || (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) { S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL; return; @@ -6081,1475 +5348,144 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } //===----------------------------------------------------------------------===// -// Checker-specific attribute handlers. +// Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// -static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { - return QT->isDependentType() || QT->isObjCRetainableType(); -} - -static bool isValidSubjectOfNSAttribute(QualType QT) { - return QT->isDependentType() || QT->isObjCObjectPointerType() || - QT->isObjCNSObjectType(); -} - -static bool isValidSubjectOfCFAttribute(QualType QT) { - return QT->isDependentType() || QT->isPointerType() || - isValidSubjectOfNSAttribute(QT); -} - -static bool isValidSubjectOfOSAttribute(QualType QT) { - if (QT->isDependentType()) - return true; - QualType PT = QT->getPointeeType(); - return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr; -} - -void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, - RetainOwnershipKind K, - bool IsTemplateInstantiation) { - ValueDecl *VD = cast(D); - switch (K) { - case RetainOwnershipKind::OS: - handleSimpleAttributeOrDiagnose( - *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()), - diag::warn_ns_attribute_wrong_parameter_type, - /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1); - return; - case RetainOwnershipKind::NS: - handleSimpleAttributeOrDiagnose( - *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()), - - // These attributes are normally just advisory, but in ARC, ns_consumed - // is significant. Allow non-dependent code to contain inappropriate - // attributes even in ARC, but require template instantiations to be - // set up correctly. - ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount) - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type), - /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0); - return; - case RetainOwnershipKind::CF: - handleSimpleAttributeOrDiagnose( - *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()), - diag::warn_ns_attribute_wrong_parameter_type, - /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1); - return; - } -} -static Sema::RetainOwnershipKind -parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) { - switch (AL.getKind()) { - case ParsedAttr::AT_CFConsumed: - case ParsedAttr::AT_CFReturnsRetained: - case ParsedAttr::AT_CFReturnsNotRetained: - return Sema::RetainOwnershipKind::CF; - case ParsedAttr::AT_OSConsumesThis: - case ParsedAttr::AT_OSConsumed: - case ParsedAttr::AT_OSReturnsRetained: - case ParsedAttr::AT_OSReturnsNotRetained: - case ParsedAttr::AT_OSReturnsRetainedOnZero: - case ParsedAttr::AT_OSReturnsRetainedOnNonZero: - return Sema::RetainOwnershipKind::OS; - case ParsedAttr::AT_NSConsumesSelf: - case ParsedAttr::AT_NSConsumed: - case ParsedAttr::AT_NSReturnsRetained: - case ParsedAttr::AT_NSReturnsNotRetained: - case ParsedAttr::AT_NSReturnsAutoreleased: - return Sema::RetainOwnershipKind::NS; - default: - llvm_unreachable("Wrong argument supplied"); +UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef UuidAsWritten, MSGuidDecl *GuidDecl) { + if (const auto *UA = D->getAttr()) { + if (declaresSameEntity(UA->getGuidDecl(), GuidDecl)) + return nullptr; + if (!UA->getGuid().empty()) { + Diag(UA->getLocation(), diag::err_mismatched_uuid); + Diag(CI.getLoc(), diag::note_previous_uuid); + D->dropAttr(); + } } -} - -bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { - if (isValidSubjectOfNSReturnsRetainedAttribute(QT)) - return false; - Diag(Loc, diag::warn_ns_attribute_wrong_return_type) - << "'ns_returns_retained'" << 0 << 0; - return true; -} - -/// \return whether the parameter is a pointer to OSObject pointer. -static bool isValidOSObjectOutParameter(const Decl *D) { - const auto *PVD = dyn_cast(D); - if (!PVD) - return false; - QualType QT = PVD->getType(); - QualType PT = QT->getPointeeType(); - return !PT.isNull() && isValidSubjectOfOSAttribute(PT); + return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl); } -static void handleXReturnsXRetainedAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - QualType ReturnType; - Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL); - - if (const auto *MD = dyn_cast(D)) { - ReturnType = MD->getReturnType(); - } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) { - return; // ignore: was handled as a type attribute - } else if (const auto *PD = dyn_cast(D)) { - ReturnType = PD->getType(); - } else if (const auto *FD = dyn_cast(D)) { - ReturnType = FD->getReturnType(); - } else if (const auto *Param = dyn_cast(D)) { - // Attributes on parameters are used for out-parameters, - // passed as pointers-to-pointers. - unsigned DiagID = K == Sema::RetainOwnershipKind::CF - ? /*pointer-to-CF-pointer*/2 - : /*pointer-to-OSObject-pointer*/3; - ReturnType = Param->getType()->getPointeeType(); - if (ReturnType.isNull()) { - S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) - << AL << DiagID << AL.getRange(); - return; - } - } else if (AL.isUsedAsTypeAttr()) { - return; - } else { - AttributeDeclKind ExpectedDeclKind; - switch (AL.getKind()) { - default: llvm_unreachable("invalid ownership attribute"); - case ParsedAttr::AT_NSReturnsRetained: - case ParsedAttr::AT_NSReturnsAutoreleased: - case ParsedAttr::AT_NSReturnsNotRetained: - ExpectedDeclKind = ExpectedFunctionOrMethod; - break; - - case ParsedAttr::AT_OSReturnsRetained: - case ParsedAttr::AT_OSReturnsNotRetained: - case ParsedAttr::AT_CFReturnsRetained: - case ParsedAttr::AT_CFReturnsNotRetained: - ExpectedDeclKind = ExpectedFunctionMethodOrParameter; - break; - } - S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getRange() << AL << AL.isRegularKeywordAttribute() - << ExpectedDeclKind; +static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!S.LangOpts.CPlusPlus) { + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL << AttributeLangSupport::C; return; } - bool TypeOK; - bool Cf; - unsigned ParmDiagID = 2; // Pointer-to-CF-pointer - switch (AL.getKind()) { - default: llvm_unreachable("invalid ownership attribute"); - case ParsedAttr::AT_NSReturnsRetained: - TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); - Cf = false; - break; - - case ParsedAttr::AT_NSReturnsAutoreleased: - case ParsedAttr::AT_NSReturnsNotRetained: - TypeOK = isValidSubjectOfNSAttribute(ReturnType); - Cf = false; - break; + StringRef OrigStrRef; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc)) + return; - case ParsedAttr::AT_CFReturnsRetained: - case ParsedAttr::AT_CFReturnsNotRetained: - TypeOK = isValidSubjectOfCFAttribute(ReturnType); - Cf = true; - break; + // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or + // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former. + StringRef StrRef = OrigStrRef; + if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}') + StrRef = StrRef.drop_front().drop_back(); - case ParsedAttr::AT_OSReturnsRetained: - case ParsedAttr::AT_OSReturnsNotRetained: - TypeOK = isValidSubjectOfOSAttribute(ReturnType); - Cf = true; - ParmDiagID = 3; // Pointer-to-OSObject-pointer - break; + // Validate GUID length. + if (StrRef.size() != 36) { + S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); + return; } - if (!TypeOK) { - if (AL.isUsedAsTypeAttr()) + for (unsigned i = 0; i < 36; ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (StrRef[i] != '-') { + S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); + return; + } + } else if (!isHexDigit(StrRef[i])) { + S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); return; - - if (isa(D)) { - S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) - << AL << ParmDiagID << AL.getRange(); - } else { - // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. - enum : unsigned { - Function, - Method, - Property - } SubjectKind = Function; - if (isa(D)) - SubjectKind = Method; - else if (isa(D)) - SubjectKind = Property; - S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) - << AL << SubjectKind << Cf << AL.getRange(); } - return; } - switch (AL.getKind()) { - default: - llvm_unreachable("invalid ownership attribute"); - case ParsedAttr::AT_NSReturnsAutoreleased: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - }; -} - -static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, - const ParsedAttr &Attrs) { - const int EP_ObjCMethod = 1; - const int EP_ObjCProperty = 2; - - SourceLocation loc = Attrs.getLoc(); - QualType resultType; - if (isa(D)) - resultType = cast(D)->getReturnType(); - else - resultType = cast(D)->getType(); - - if (!resultType->isReferenceType() && - (!resultType->isPointerType() || resultType->isObjCRetainableType())) { - S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(loc) << Attrs - << (isa(D) ? EP_ObjCMethod : EP_ObjCProperty) - << /*non-retainable pointer*/ 2; + // Convert to our parsed format and canonicalize. + MSGuidDecl::Parts Parsed; + StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1); + StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2); + StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3); + for (unsigned i = 0; i != 8; ++i) + StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2) + .getAsInteger(16, Parsed.Part4And5[i]); + MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed); - // Drop the attribute. - return; - } + // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's + // the only thing in the [] list, the [] too), and add an insertion of + // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas + // separating attributes nor of the [ and the ] are in the AST. + // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" + // on cfe-dev. + if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. + S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs)); + UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid); + if (UA) + D->addAttr(UA); } -static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, - const ParsedAttr &Attrs) { - const auto *Method = cast(D); - - const DeclContext *DC = Method->getDeclContext(); - if (const auto *PDecl = dyn_cast_if_present(DC)) { - S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs - << 0; - S.Diag(PDecl->getLocation(), diag::note_protocol_decl); +static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!S.LangOpts.CPlusPlus) { + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL << AttributeLangSupport::C; return; } - if (Method->getMethodFamily() == OMF_dealloc) { - S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs - << 1; - return; + MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( + D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling()); + if (IA) { + D->addAttr(IA); + S.Consumer.AssignInheritanceModel(cast(D)); } - - D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } -static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { - if (!isa(D)) { - S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; +static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *VD = cast(D); + if (!S.Context.getTargetInfo().isTLSSupported()) { + S.Diag(AL.getLoc(), diag::err_thread_unsupported); return; } - - IdentifierLoc *IdentLoc = - Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; - if (!IdentLoc || !IdentLoc->Ident) { - // Try to locate the argument directly. - SourceLocation Loc = Attr.getLoc(); - if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) - Loc = Attr.getArgAsExpr(0)->getBeginLoc(); - - S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; + if (VD->getTSCSpec() != TSCS_unspecified) { + S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable); return; } - - // Verify that the identifier is a valid decl in the C decl namespace. - LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(), - Sema::LookupNameKind::LookupOrdinaryName); - if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle()) { - S.Diag(IdentLoc->Loc, diag::err_nserrordomain_invalid_decl) - << 1 << IdentLoc->Ident; + if (VD->hasLocalStorage()) { + S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; return; } - - D->addAttr(::new (S.Context) - NSErrorDomainAttr(S.Context, Attr, IdentLoc->Ident)); + D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL)); } -static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; - - if (!Parm) { - S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; +static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!S.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3)) { + S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); return; } - - // Typedefs only allow objc_bridge(id) and have some additional checking. - if (const auto *TD = dyn_cast(D)) { - if (!Parm->Ident->isStr("id")) { - S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL; + auto *FD = cast(D); + if (FD->isConstexprSpecified() || FD->isConsteval()) { + S.Diag(AL.getLoc(), diag::err_ms_constexpr_cannot_be_applied) + << FD->isConsteval() << FD; + return; + } + if (auto *MD = dyn_cast(FD)) { + if (!S.getLangOpts().CPlusPlus20 && MD->isVirtual()) { + S.Diag(AL.getLoc(), diag::err_ms_constexpr_cannot_be_applied) + << /*virtual*/ 2 << MD; return; } + } + D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL)); +} - // Only allow 'cv void *'. - QualType T = TD->getUnderlyingType(); - if (!T->isVoidPointerType()) { - S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); +static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector Tags; + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef Tag; + if (!S.checkStringLiteralArgumentAttr(AL, I, Tag)) return; - } - } - - D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident)); -} - -static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; - - if (!Parm) { - S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; - return; - } - - D->addAttr(::new (S.Context) - ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident)); -} - -static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - IdentifierInfo *RelatedClass = - AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; - if (!RelatedClass) { - S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; - return; - } - IdentifierInfo *ClassMethod = - AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; - IdentifierInfo *InstanceMethod = - AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; - D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr( - S.Context, AL, RelatedClass, ClassMethod, InstanceMethod)); -} - -static void handleObjCDesignatedInitializer(Sema &S, Decl *D, - const ParsedAttr &AL) { - DeclContext *Ctx = D->getDeclContext(); - - // This attribute can only be applied to methods in interfaces or class - // extensions. - if (!isa(Ctx) && - !(isa(Ctx) && - cast(Ctx)->IsClassExtension())) { - S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init); - return; - } - - ObjCInterfaceDecl *IFace; - if (auto *CatDecl = dyn_cast(Ctx)) - IFace = CatDecl->getClassInterface(); - else - IFace = cast(Ctx); - - if (!IFace) - return; - - IFace->setHasDesignatedInitializers(); - D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL)); -} - -static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef MetaDataName; - if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) - return; - D->addAttr(::new (S.Context) - ObjCRuntimeNameAttr(S.Context, AL, MetaDataName)); -} - -// When a user wants to use objc_boxable with a union or struct -// but they don't have access to the declaration (legacy/third-party code) -// then they can 'enable' this feature with a typedef: -// typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; -static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { - bool notify = false; - - auto *RD = dyn_cast(D); - if (RD && RD->getDefinition()) { - RD = RD->getDefinition(); - notify = true; - } - - if (RD) { - ObjCBoxableAttr *BoxableAttr = - ::new (S.Context) ObjCBoxableAttr(S.Context, AL); - RD->addAttr(BoxableAttr); - if (notify) { - // we need to notify ASTReader/ASTWriter about - // modification of existing declaration - if (ASTMutationListener *L = S.getASTMutationListener()) - L->AddedAttributeToRecord(BoxableAttr, RD); - } - } -} - -static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (hasDeclarator(D)) - return; - - S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) - << AL.getRange() << AL << AL.isRegularKeywordAttribute() - << ExpectedVariable; -} - -static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - const auto *VD = cast(D); - QualType QT = VD->getType(); - - if (!QT->isDependentType() && - !QT->isObjCLifetimeType()) { - S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << QT; - return; - } - - Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime(); - - // If we have no lifetime yet, check the lifetime we're presumably - // going to infer. - if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) - Lifetime = QT->getObjCARCImplicitLifetime(); - - switch (Lifetime) { - case Qualifiers::OCL_None: - assert(QT->isDependentType() && - "didn't infer lifetime for non-dependent type?"); - break; - - case Qualifiers::OCL_Weak: // meaningful - case Qualifiers::OCL_Strong: // meaningful - break; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) - << (Lifetime == Qualifiers::OCL_Autoreleasing); - break; - } - - D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL)); -} - -static void handleSwiftAttrAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single - // argument. - StringRef Str; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) - return; - - D->addAttr(::new (S.Context) SwiftAttrAttr(S.Context, AL, Str)); -} - -static void handleSwiftBridge(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single - // argument. - StringRef BT; - if (!S.checkStringLiteralArgumentAttr(AL, 0, BT)) - return; - - // Warn about duplicate attributes if they have different arguments, but drop - // any duplicate attributes regardless. - if (const auto *Other = D->getAttr()) { - if (Other->getSwiftType() != BT) - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; - return; - } - - D->addAttr(::new (S.Context) SwiftBridgeAttr(S.Context, AL, BT)); -} - -static bool isErrorParameter(Sema &S, QualType QT) { - const auto *PT = QT->getAs(); - if (!PT) - return false; - - QualType Pointee = PT->getPointeeType(); - - // Check for NSError**. - if (const auto *OPT = Pointee->getAs()) - if (const auto *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) - return true; - - // Check for CFError**. - if (const auto *PT = Pointee->getAs()) - if (const auto *RT = PT->getPointeeType()->getAs()) - if (S.ObjC().isCFError(RT->getDecl())) - return true; - - return false; -} - -static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) { - auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { - for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { - if (isErrorParameter(S, getFunctionOrMethodParamType(D, I))) - return true; - } - - S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter) - << AL << isa(D); - return false; - }; - - auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { - // - C, ObjC, and block pointers are definitely okay. - // - References are definitely not okay. - // - nullptr_t is weird, but acceptable. - QualType RT = getFunctionOrMethodResultType(D); - if (RT->hasPointerRepresentation() && !RT->isReferenceType()) - return true; - - S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) - << AL << AL.getArgAsIdent(0)->Ident->getName() << isa(D) - << /*pointer*/ 1; - return false; - }; - - auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { - QualType RT = getFunctionOrMethodResultType(D); - if (RT->isIntegralType(S.Context)) - return true; - - S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) - << AL << AL.getArgAsIdent(0)->Ident->getName() << isa(D) - << /*integral*/ 0; - return false; - }; - - if (D->isInvalidDecl()) - return; - - IdentifierLoc *Loc = AL.getArgAsIdent(0); - SwiftErrorAttr::ConventionKind Convention; - if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(), - Convention)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL << Loc->Ident; - return; - } - - switch (Convention) { - case SwiftErrorAttr::None: - // No additional validation required. - break; - - case SwiftErrorAttr::NonNullError: - if (!hasErrorParameter(S, D, AL)) - return; - break; - - case SwiftErrorAttr::NullResult: - if (!hasErrorParameter(S, D, AL) || !hasPointerResult(S, D, AL)) - return; - break; - - case SwiftErrorAttr::NonZeroResult: - case SwiftErrorAttr::ZeroResult: - if (!hasErrorParameter(S, D, AL) || !hasIntegerResult(S, D, AL)) - return; - break; - } - - D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention)); -} - -static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D, - const SwiftAsyncErrorAttr *ErrorAttr, - const SwiftAsyncAttr *AsyncAttr) { - if (AsyncAttr->getKind() == SwiftAsyncAttr::None) { - if (ErrorAttr->getConvention() != SwiftAsyncErrorAttr::None) { - S.Diag(AsyncAttr->getLocation(), - diag::err_swift_async_error_without_swift_async) - << AsyncAttr << isa(D); - } - return; - } - - const ParmVarDecl *HandlerParam = getFunctionOrMethodParam( - D, AsyncAttr->getCompletionHandlerIndex().getASTIndex()); - // handleSwiftAsyncAttr already verified the type is correct, so no need to - // double-check it here. - const auto *FuncTy = HandlerParam->getType() - ->castAs() - ->getPointeeType() - ->getAs(); - ArrayRef BlockParams; - if (FuncTy) - BlockParams = FuncTy->getParamTypes(); - - switch (ErrorAttr->getConvention()) { - case SwiftAsyncErrorAttr::ZeroArgument: - case SwiftAsyncErrorAttr::NonZeroArgument: { - uint32_t ParamIdx = ErrorAttr->getHandlerParamIdx(); - if (ParamIdx == 0 || ParamIdx > BlockParams.size()) { - S.Diag(ErrorAttr->getLocation(), - diag::err_attribute_argument_out_of_bounds) << ErrorAttr << 2; - return; - } - QualType ErrorParam = BlockParams[ParamIdx - 1]; - if (!ErrorParam->isIntegralType(S.Context)) { - StringRef ConvStr = - ErrorAttr->getConvention() == SwiftAsyncErrorAttr::ZeroArgument - ? "zero_argument" - : "nonzero_argument"; - S.Diag(ErrorAttr->getLocation(), diag::err_swift_async_error_non_integral) - << ErrorAttr << ConvStr << ParamIdx << ErrorParam; - return; - } - break; - } - case SwiftAsyncErrorAttr::NonNullError: { - bool AnyErrorParams = false; - for (QualType Param : BlockParams) { - // Check for NSError *. - if (const auto *ObjCPtrTy = Param->getAs()) { - if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) { - if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) { - AnyErrorParams = true; - break; - } - } - } - // Check for CFError *. - if (const auto *PtrTy = Param->getAs()) { - if (const auto *RT = PtrTy->getPointeeType()->getAs()) { - if (S.ObjC().isCFError(RT->getDecl())) { - AnyErrorParams = true; - break; - } - } - } - } - - if (!AnyErrorParams) { - S.Diag(ErrorAttr->getLocation(), - diag::err_swift_async_error_no_error_parameter) - << ErrorAttr << isa(D); - return; - } - break; - } - case SwiftAsyncErrorAttr::None: - break; - } -} - -static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) { - IdentifierLoc *IDLoc = AL.getArgAsIdent(0); - SwiftAsyncErrorAttr::ConventionKind ConvKind; - if (!SwiftAsyncErrorAttr::ConvertStrToConventionKind(IDLoc->Ident->getName(), - ConvKind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL << IDLoc->Ident; - return; - } - - uint32_t ParamIdx = 0; - switch (ConvKind) { - case SwiftAsyncErrorAttr::ZeroArgument: - case SwiftAsyncErrorAttr::NonZeroArgument: { - if (!AL.checkExactlyNumArgs(S, 2)) - return; - - Expr *IdxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, IdxExpr, ParamIdx)) - return; - break; - } - case SwiftAsyncErrorAttr::NonNullError: - case SwiftAsyncErrorAttr::None: { - if (!AL.checkExactlyNumArgs(S, 1)) - return; - break; - } - } - - auto *ErrorAttr = - ::new (S.Context) SwiftAsyncErrorAttr(S.Context, AL, ConvKind, ParamIdx); - D->addAttr(ErrorAttr); - - if (auto *AsyncAttr = D->getAttr()) - checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr); -} - -// For a function, this will validate a compound Swift name, e.g. -// init(foo:bar:baz:) or controllerForName(_:), and -// the function will output the number of parameter names, and whether this is a -// single-arg initializer. -// -// For a type, enum constant, property, or variable declaration, this will -// validate either a simple identifier, or a qualified -// context.identifier name. -static bool -validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, - StringRef Name, unsigned &SwiftParamCount, - bool &IsSingleParamInit) { - SwiftParamCount = 0; - IsSingleParamInit = false; - - // Check whether this will be mapped to a getter or setter of a property. - bool IsGetter = false, IsSetter = false; - if (Name.consume_front("getter:")) - IsGetter = true; - else if (Name.consume_front("setter:")) - IsSetter = true; - - if (Name.back() != ')') { - S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; - return false; - } - - bool IsMember = false; - StringRef ContextName, BaseName, Parameters; - - std::tie(BaseName, Parameters) = Name.split('('); - - // Split at the first '.', if it exists, which separates the context name - // from the base name. - std::tie(ContextName, BaseName) = BaseName.split('.'); - if (BaseName.empty()) { - BaseName = ContextName; - ContextName = StringRef(); - } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) { - S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) - << AL << /*context*/ 1; - return false; - } else { - IsMember = true; - } - - if (!isValidAsciiIdentifier(BaseName) || BaseName == "_") { - S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) - << AL << /*basename*/ 0; - return false; - } - - bool IsSubscript = BaseName == "subscript"; - // A subscript accessor must be a getter or setter. - if (IsSubscript && !IsGetter && !IsSetter) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) - << AL << /* getter or setter */ 0; - return false; - } - - if (Parameters.empty()) { - S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL; - return false; - } - - assert(Parameters.back() == ')' && "expected ')'"); - Parameters = Parameters.drop_back(); // ')' - - if (Parameters.empty()) { - // Setters and subscripts must have at least one parameter. - if (IsSubscript) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) - << AL << /* have at least one parameter */1; - return false; - } - - if (IsSetter) { - S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL; - return false; - } - - return true; - } - - if (Parameters.back() != ':') { - S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; - return false; - } - - StringRef CurrentParam; - std::optional SelfLocation; - unsigned NewValueCount = 0; - std::optional NewValueLocation; - do { - std::tie(CurrentParam, Parameters) = Parameters.split(':'); - - if (!isValidAsciiIdentifier(CurrentParam)) { - S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) - << AL << /*parameter*/2; - return false; - } - - if (IsMember && CurrentParam == "self") { - // "self" indicates the "self" argument for a member. - - // More than one "self"? - if (SelfLocation) { - S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL; - return false; - } - - // The "self" location is the current parameter. - SelfLocation = SwiftParamCount; - } else if (CurrentParam == "newValue") { - // "newValue" indicates the "newValue" argument for a setter. - - // There should only be one 'newValue', but it's only significant for - // subscript accessors, so don't error right away. - ++NewValueCount; - - NewValueLocation = SwiftParamCount; - } - - ++SwiftParamCount; - } while (!Parameters.empty()); - - // Only instance subscripts are currently supported. - if (IsSubscript && !SelfLocation) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) - << AL << /*have a 'self:' parameter*/2; - return false; - } - - IsSingleParamInit = - SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_"; - - // Check the number of parameters for a getter/setter. - if (IsGetter || IsSetter) { - // Setters have one parameter for the new value. - unsigned NumExpectedParams = IsGetter ? 0 : 1; - unsigned ParamDiag = - IsGetter ? diag::warn_attr_swift_name_getter_parameters - : diag::warn_attr_swift_name_setter_parameters; - - // Instance methods have one parameter for "self". - if (SelfLocation) - ++NumExpectedParams; - - // Subscripts may have additional parameters beyond the expected params for - // the index. - if (IsSubscript) { - if (SwiftParamCount < NumExpectedParams) { - S.Diag(Loc, ParamDiag) << AL; - return false; - } - - // A subscript setter must explicitly label its newValue parameter to - // distinguish it from index parameters. - if (IsSetter) { - if (!NewValueLocation) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue) - << AL; - return false; - } - if (NewValueCount > 1) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues) - << AL; - return false; - } - } else { - // Subscript getters should have no 'newValue:' parameter. - if (NewValueLocation) { - S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue) - << AL; - return false; - } - } - } else { - // Property accessors must have exactly the number of expected params. - if (SwiftParamCount != NumExpectedParams) { - S.Diag(Loc, ParamDiag) << AL; - return false; - } - } - } - - return true; -} - -bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, - const ParsedAttr &AL, bool IsAsync) { - if (isa(D) || isa(D)) { - ArrayRef Params; - unsigned ParamCount; - - if (const auto *Method = dyn_cast(D)) { - ParamCount = Method->getSelector().getNumArgs(); - Params = Method->parameters().slice(0, ParamCount); - } else { - const auto *F = cast(D); - - ParamCount = F->getNumParams(); - Params = F->parameters(); - - if (!F->hasWrittenPrototype()) { - Diag(Loc, diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() - << ExpectedFunctionWithProtoType; - return false; - } - } - - // The async name drops the last callback parameter. - if (IsAsync) { - if (ParamCount == 0) { - Diag(Loc, diag::warn_attr_swift_name_decl_missing_params) - << AL << isa(D); - return false; - } - ParamCount -= 1; - } - - unsigned SwiftParamCount; - bool IsSingleParamInit; - if (!validateSwiftFunctionName(*this, AL, Loc, Name, - SwiftParamCount, IsSingleParamInit)) - return false; - - bool ParamCountValid; - if (SwiftParamCount == ParamCount) { - ParamCountValid = true; - } else if (SwiftParamCount > ParamCount) { - ParamCountValid = IsSingleParamInit && ParamCount == 0; - } else { - // We have fewer Swift parameters than Objective-C parameters, but that - // might be because we've transformed some of them. Check for potential - // "out" parameters and err on the side of not warning. - unsigned MaybeOutParamCount = - llvm::count_if(Params, [](const ParmVarDecl *Param) -> bool { - QualType ParamTy = Param->getType(); - if (ParamTy->isReferenceType() || ParamTy->isPointerType()) - return !ParamTy->getPointeeType().isConstQualified(); - return false; - }); - - ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount; - } - - if (!ParamCountValid) { - Diag(Loc, diag::warn_attr_swift_name_num_params) - << (SwiftParamCount > ParamCount) << AL << ParamCount - << SwiftParamCount; - return false; - } - } else if ((isa(D) || isa(D) || - isa(D) || isa(D) || - isa(D) || isa(D) || isa(D) || - isa(D) || isa(D)) && - !IsAsync) { - StringRef ContextName, BaseName; - - std::tie(ContextName, BaseName) = Name.split('.'); - if (BaseName.empty()) { - BaseName = ContextName; - ContextName = StringRef(); - } else if (!isValidAsciiIdentifier(ContextName)) { - Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL - << /*context*/1; - return false; - } - - if (!isValidAsciiIdentifier(BaseName)) { - Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL - << /*basename*/0; - return false; - } - } else { - Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL; - return false; - } - return true; -} - -static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef Name; - SourceLocation Loc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) - return; - - if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false)) - return; - - D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name)); -} - -static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef Name; - SourceLocation Loc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) - return; - - if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/true)) - return; - - D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name)); -} - -static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is an identifier as the annotation's single argument. - if (!AL.checkExactlyNumArgs(S, 1)) - return; - - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIdentifier; - return; - } - - SwiftNewTypeAttr::NewtypeKind Kind; - IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; - if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; - return; - } - - if (!isa(D)) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << AL.isRegularKeywordAttribute() << "typedefs"; - return; - } - - D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind)); -} - -static void handleSwiftAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL << 1 << AANT_ArgumentIdentifier; - return; - } - - SwiftAsyncAttr::Kind Kind; - IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; - if (!SwiftAsyncAttr::ConvertStrToKind(II->getName(), Kind)) { - S.Diag(AL.getLoc(), diag::err_swift_async_no_access) << AL << II; - return; - } - - ParamIdx Idx; - if (Kind == SwiftAsyncAttr::None) { - // If this is 'none', then there shouldn't be any additional arguments. - if (!AL.checkExactlyNumArgs(S, 1)) - return; - } else { - // Non-none swift_async requires a completion handler index argument. - if (!AL.checkExactlyNumArgs(S, 2)) - return; - - Expr *HandlerIdx = AL.getArgAsExpr(1); - if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, HandlerIdx, Idx)) - return; - - const ParmVarDecl *CompletionBlock = - getFunctionOrMethodParam(D, Idx.getASTIndex()); - QualType CompletionBlockType = CompletionBlock->getType(); - if (!CompletionBlockType->isBlockPointerType()) { - S.Diag(CompletionBlock->getLocation(), - diag::err_swift_async_bad_block_type) - << CompletionBlock->getType(); - return; - } - QualType BlockTy = - CompletionBlockType->castAs()->getPointeeType(); - if (!BlockTy->castAs()->getReturnType()->isVoidType()) { - S.Diag(CompletionBlock->getLocation(), - diag::err_swift_async_bad_block_type) - << CompletionBlock->getType(); - return; - } - } - - auto *AsyncAttr = - ::new (S.Context) SwiftAsyncAttr(S.Context, AL, Kind, Idx); - D->addAttr(AsyncAttr); - - if (auto *ErrorAttr = D->getAttr()) - checkSwiftAsyncErrorBlock(S, D, ErrorAttr, AsyncAttr); -} - -//===----------------------------------------------------------------------===// -// Microsoft specific attribute handlers. -//===----------------------------------------------------------------------===// - -UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef UuidAsWritten, MSGuidDecl *GuidDecl) { - if (const auto *UA = D->getAttr()) { - if (declaresSameEntity(UA->getGuidDecl(), GuidDecl)) - return nullptr; - if (!UA->getGuid().empty()) { - Diag(UA->getLocation(), diag::err_mismatched_uuid); - Diag(CI.getLoc(), diag::note_previous_uuid); - D->dropAttr(); - } - } - - return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl); -} - -static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!S.LangOpts.CPlusPlus) { - S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) - << AL << AttributeLangSupport::C; - return; - } - - StringRef OrigStrRef; - SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc)) - return; - - // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or - // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former. - StringRef StrRef = OrigStrRef; - if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}') - StrRef = StrRef.drop_front().drop_back(); - - // Validate GUID length. - if (StrRef.size() != 36) { - S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); - return; - } - - for (unsigned i = 0; i < 36; ++i) { - if (i == 8 || i == 13 || i == 18 || i == 23) { - if (StrRef[i] != '-') { - S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); - return; - } - } else if (!isHexDigit(StrRef[i])) { - S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid); - return; - } - } - - // Convert to our parsed format and canonicalize. - MSGuidDecl::Parts Parsed; - StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1); - StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2); - StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3); - for (unsigned i = 0; i != 8; ++i) - StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2) - .getAsInteger(16, Parsed.Part4And5[i]); - MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed); - - // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's - // the only thing in the [] list, the [] too), and add an insertion of - // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas - // separating attributes nor of the [ and the ] are in the AST. - // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" - // on cfe-dev. - if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. - S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - - UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid); - if (UA) - D->addAttr(UA); -} - -static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - llvm::VersionTuple SMVersion = - S.Context.getTargetInfo().getTriple().getOSVersion(); - uint32_t ZMax = 1024; - uint32_t ThreadMax = 1024; - if (SMVersion.getMajor() <= 4) { - ZMax = 1; - ThreadMax = 768; - } else if (SMVersion.getMajor() == 5) { - ZMax = 64; - ThreadMax = 1024; - } - - uint32_t X; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), X)) - return; - if (X > 1024) { - S.Diag(AL.getArgAsExpr(0)->getExprLoc(), - diag::err_hlsl_numthreads_argument_oor) << 0 << 1024; - return; - } - uint32_t Y; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Y)) - return; - if (Y > 1024) { - S.Diag(AL.getArgAsExpr(1)->getExprLoc(), - diag::err_hlsl_numthreads_argument_oor) << 1 << 1024; - return; - } - uint32_t Z; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(2), Z)) - return; - if (Z > ZMax) { - S.Diag(AL.getArgAsExpr(2)->getExprLoc(), - diag::err_hlsl_numthreads_argument_oor) << 2 << ZMax; - return; - } - - if (X * Y * Z > ThreadMax) { - S.Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax; - return; - } - - HLSLNumThreadsAttr *NewAttr = S.HLSL().mergeNumThreadsAttr(D, AL, X, Y, Z); - if (NewAttr) - D->addAttr(NewAttr); -} - -static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { - if (!T->hasUnsignedIntegerRepresentation()) - return false; - if (const auto *VT = T->getAs()) - return VT->getNumElements() <= 3; - return true; -} - -static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - // FIXME: support semantic on field. - // See https://github.com/llvm/llvm-project/issues/57889. - if (isa(D)) { - S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) - << AL << "parameter"; - return; - } - - auto *VD = cast(D); - if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) { - S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) - << AL << "uint/uint2/uint3"; - return; - } - - D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL)); -} - -static void handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isa(D) || !isa(D->getDeclContext())) { - S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) - << AL << "shader constant in a constant buffer"; - return; - } - - uint32_t SubComponent; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), SubComponent)) - return; - uint32_t Component; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Component)) - return; - - QualType T = cast(D)->getType().getCanonicalType(); - // Check if T is an array or struct type. - // TODO: mark matrix type as aggregate type. - bool IsAggregateTy = (T->isArrayType() || T->isStructureType()); - - // Check Component is valid for T. - if (Component) { - unsigned Size = S.getASTContext().getTypeSize(T); - if (IsAggregateTy || Size > 128) { - S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); - return; - } else { - // Make sure Component + sizeof(T) <= 4. - if ((Component * 32 + Size) > 128) { - S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); - return; - } - QualType EltTy = T; - if (const auto *VT = T->getAs()) - EltTy = VT->getElementType(); - unsigned Align = S.getASTContext().getTypeAlign(EltTy); - if (Align > 32 && Component == 1) { - // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary. - // So we only need to check Component 1 here. - S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch) - << Align << EltTy; - return; - } - } - } - - D->addAttr(::new (S.Context) - HLSLPackOffsetAttr(S.Context, AL, SubComponent, Component)); -} - -static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef Str; - SourceLocation ArgLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - - HLSLShaderAttr::ShaderType ShaderType; - if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL << Str << ArgLoc; - return; - } - - // FIXME: check function match the shader stage. - - HLSLShaderAttr *NewAttr = S.HLSL().mergeShaderAttr(D, AL, ShaderType); - if (NewAttr) - D->addAttr(NewAttr); -} - -static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - StringRef Space = "space0"; - StringRef Slot = ""; - - if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIdentifier; - return; - } - - IdentifierLoc *Loc = AL.getArgAsIdent(0); - StringRef Str = Loc->Ident->getName(); - SourceLocation ArgLoc = Loc->Loc; - - SourceLocation SpaceArgLoc; - if (AL.getNumArgs() == 2) { - Slot = Str; - if (!AL.isArgIdent(1)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIdentifier; - return; - } - - IdentifierLoc *Loc = AL.getArgAsIdent(1); - Space = Loc->Ident->getName(); - SpaceArgLoc = Loc->Loc; - } else { - Slot = Str; - } - - // Validate. - if (!Slot.empty()) { - switch (Slot[0]) { - case 'u': - case 'b': - case 's': - case 't': - break; - default: - S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type) - << Slot.substr(0, 1); - return; - } - - StringRef SlotNum = Slot.substr(1); - unsigned Num = 0; - if (SlotNum.getAsInteger(10, Num)) { - S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); - return; - } - } - - if (!Space.starts_with("space")) { - S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; - return; - } - StringRef SpaceNum = Space.substr(5); - unsigned Num = 0; - if (SpaceNum.getAsInteger(10, Num)) { - S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; - return; - } - - // FIXME: check reg type match decl. Issue - // https://github.com/llvm/llvm-project/issues/57886. - HLSLResourceBindingAttr *NewAttr = - HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL); - if (NewAttr) - D->addAttr(NewAttr); -} - -static void handleHLSLParamModifierAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - HLSLParamModifierAttr *NewAttr = S.HLSL().mergeParamModifierAttr( - D, AL, - static_cast(AL.getSemanticSpelling())); - if (NewAttr) - D->addAttr(NewAttr); -} - -static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!S.LangOpts.CPlusPlus) { - S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) - << AL << AttributeLangSupport::C; - return; - } - MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling()); - if (IA) { - D->addAttr(IA); - S.Consumer.AssignInheritanceModel(cast(D)); - } -} - -static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - const auto *VD = cast(D); - if (!S.Context.getTargetInfo().isTLSSupported()) { - S.Diag(AL.getLoc(), diag::err_thread_unsupported); - return; - } - if (VD->getTSCSpec() != TSCS_unspecified) { - S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable); - return; - } - if (VD->hasLocalStorage()) { - S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; - return; - } - D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL)); -} - -static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!S.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3)) { - S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); - return; - } - auto *FD = cast(D); - if (FD->isConstexprSpecified() || FD->isConsteval()) { - S.Diag(AL.getLoc(), diag::err_ms_constexpr_cannot_be_applied) - << FD->isConsteval() << FD; - return; - } - if (auto *MD = dyn_cast(FD)) { - if (!S.getLangOpts().CPlusPlus20 && MD->isVirtual()) { - S.Diag(AL.getLoc(), diag::err_ms_constexpr_cannot_be_applied) - << /*virtual*/ 2 << MD; - return; - } - } - D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL)); -} - -static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Tags; - for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { - StringRef Tag; - if (!S.checkStringLiteralArgumentAttr(AL, I, Tag)) - return; - Tags.push_back(Tag); + Tags.push_back(Tag); } if (const auto *NS = dyn_cast(D)) { @@ -7561,725 +5497,77 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; return; } - if (AL.getNumArgs() == 0) - Tags.push_back(NS->getName()); - } else if (!AL.checkAtLeastNumArgs(S, 1)) - return; - - // Store tags sorted and without duplicates. - llvm::sort(Tags); - Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); - - D->addAttr(::new (S.Context) - AbiTagAttr(S.Context, AL, Tags.data(), Tags.size())); -} - -static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Check the attribute arguments. - if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; - return; - } - - StringRef Str; - SourceLocation ArgLoc; - - if (AL.getNumArgs() == 0) - Str = ""; - else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - - ARMInterruptAttr::InterruptType Kind; - if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str - << ArgLoc; - return; - } - - D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind)); -} - -static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // MSP430 'interrupt' attribute is applied to - // a function with no parameters and void return type. - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; - return; - } - - if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*MSP430*/ 1 << 0; - return; - } - - if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*MSP430*/ 1 << 1; - return; - } - - // The attribute takes one integer argument. - if (!AL.checkExactlyNumArgs(S, 1)) - return; - - if (!AL.isArgExpr(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIntegerConstant; - return; - } - - Expr *NumParamsExpr = static_cast(AL.getArgAsExpr(0)); - std::optional NumParams = llvm::APSInt(32); - if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIntegerConstant - << NumParamsExpr->getSourceRange(); - return; - } - // The argument should be in range 0..63. - unsigned Num = NumParams->getLimitedValue(255); - if (Num > 63) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL << (int)NumParams->getSExtValue() - << NumParamsExpr->getSourceRange(); - return; - } - - D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num)); - D->addAttr(UsedAttr::CreateImplicit(S.Context)); -} - -static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Only one optional argument permitted. - if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; - return; - } - - StringRef Str; - SourceLocation ArgLoc; - - if (AL.getNumArgs() == 0) - Str = ""; - else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - - // Semantic checks for a function with the 'interrupt' attribute for MIPS: - // a) Must be a function. - // b) Must have no parameters. - // c) Must have the 'void' return type. - // d) Cannot have the 'mips16' attribute, as that instruction set - // lacks the 'eret' instruction. - // e) The attribute itself must either have no argument or one of the - // valid interrupt types, see [MipsInterruptDocs]. - - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; - return; - } - - if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*MIPS*/ 0 << 0; - return; - } - - if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*MIPS*/ 0 << 1; - return; - } - - // We still have to do this manually because the Interrupt attributes are - // a bit special due to sharing their spellings across targets. - if (checkAttrMutualExclusion(S, D, AL)) - return; - - MipsInterruptAttr::InterruptType Kind; - if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL << "'" + std::string(Str) + "'"; - return; - } - - D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind)); -} - -static void handleM68kInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkExactlyNumArgs(S, 1)) - return; - - if (!AL.isArgExpr(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIntegerConstant; - return; - } - - // FIXME: Check for decl - it should be void ()(void). - - Expr *NumParamsExpr = static_cast(AL.getArgAsExpr(0)); - auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(S.Context); - if (!MaybeNumParams) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentIntegerConstant - << NumParamsExpr->getSourceRange(); - return; - } - - unsigned Num = MaybeNumParams->getLimitedValue(255); - if ((Num & 1) || Num > 30) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL << (int)MaybeNumParams->getSExtValue() - << NumParamsExpr->getSourceRange(); - return; - } - - D->addAttr(::new (S.Context) M68kInterruptAttr(S.Context, AL, Num)); - D->addAttr(UsedAttr::CreateImplicit(S.Context)); -} - -static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Semantic checks for a function with the 'interrupt' attribute. - // a) Must be a function. - // b) Must have the 'void' return type. - // c) Must take 1 or 2 arguments. - // d) The 1st argument must be a pointer. - // e) The 2nd argument (if any) must be an unsigned integer. - if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || - CXXMethodDecl::isStaticOverloadedOperator( - cast(D)->getDeclName().getCXXOverloadedOperator())) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() - << ExpectedFunctionWithProtoType; - return; - } - // Interrupt handler must have void return type. - if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(), - diag::err_anyx86_interrupt_attribute) - << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 - ? 0 - : 1) - << 0; - return; - } - // Interrupt handler must have 1 or 2 parameters. - unsigned NumParams = getFunctionOrMethodNumParams(D); - if (NumParams < 1 || NumParams > 2) { - S.Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute) - << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 - ? 0 - : 1) - << 1; - return; - } - // The first argument must be a pointer. - if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) { - S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(), - diag::err_anyx86_interrupt_attribute) - << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 - ? 0 - : 1) - << 2; - return; - } - // The second argument, if present, must be an unsigned integer. - unsigned TypeSize = - S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64 - ? 64 - : 32; - if (NumParams == 2 && - (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() || - S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) { - S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(), - diag::err_anyx86_interrupt_attribute) - << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 - ? 0 - : 1) - << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false); - return; - } - D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL)); - D->addAttr(UsedAttr::CreateImplicit(S.Context)); -} - -static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; - return; - } - - if (!AL.checkExactlyNumArgs(S, 0)) - return; - - handleSimpleAttribute(S, D, AL); -} - -static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; - return; - } - - if (!AL.checkExactlyNumArgs(S, 0)) - return; - - handleSimpleAttribute(S, D, AL); -} - -static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) { - // Add preserve_access_index attribute to all fields and inner records. - for (auto *D : RD->decls()) { - if (D->hasAttr()) - continue; - - D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context)); - if (auto *Rec = dyn_cast(D)) - handleBPFPreserveAIRecord(S, Rec); - } -} - -static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - auto *Rec = cast(D); - handleBPFPreserveAIRecord(S, Rec); - Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); -} - -static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) { - for (const auto *I : D->specific_attrs()) { - if (I->getBTFDeclTag() == Tag) - return true; - } - return false; -} - -static void handleBTFDeclTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef Str; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) - return; - if (hasBTFDeclTagAttr(D, Str)) - return; - - D->addAttr(::new (S.Context) BTFDeclTagAttr(S.Context, AL, Str)); -} - -BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { - if (hasBTFDeclTagAttr(D, AL.getBTFDeclTag())) - return nullptr; - return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag()); -} - -static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; - return; - } - - auto *FD = cast(D); - if (FD->isThisDeclarationADefinition()) { - S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; - return; - } - - StringRef Str; - SourceLocation ArgLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - - D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str)); - D->addAttr(UsedAttr::CreateImplicit(S.Context)); -} - -WebAssemblyImportModuleAttr * -Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) { - auto *FD = cast(D); - - if (const auto *ExistingAttr = FD->getAttr()) { - if (ExistingAttr->getImportModule() == AL.getImportModule()) - return nullptr; - Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0 - << ExistingAttr->getImportModule() << AL.getImportModule(); - Diag(AL.getLoc(), diag::note_previous_attribute); - return nullptr; - } - if (FD->hasBody()) { - Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; - return nullptr; - } - return ::new (Context) WebAssemblyImportModuleAttr(Context, AL, - AL.getImportModule()); -} - -WebAssemblyImportNameAttr * -Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) { - auto *FD = cast(D); - - if (const auto *ExistingAttr = FD->getAttr()) { - if (ExistingAttr->getImportName() == AL.getImportName()) - return nullptr; - Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1 - << ExistingAttr->getImportName() << AL.getImportName(); - Diag(AL.getLoc(), diag::note_previous_attribute); - return nullptr; - } - if (FD->hasBody()) { - Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; - return nullptr; - } - return ::new (Context) WebAssemblyImportNameAttr(Context, AL, - AL.getImportName()); -} - -static void -handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *FD = cast(D); - - StringRef Str; - SourceLocation ArgLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - if (FD->hasBody()) { - S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; - return; - } - - FD->addAttr(::new (S.Context) - WebAssemblyImportModuleAttr(S.Context, AL, Str)); -} - -static void -handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - auto *FD = cast(D); - - StringRef Str; - SourceLocation ArgLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - if (FD->hasBody()) { - S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; + if (AL.getNumArgs() == 0) + Tags.push_back(NS->getName()); + } else if (!AL.checkAtLeastNumArgs(S, 1)) return; - } - FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); + // Store tags sorted and without duplicates. + llvm::sort(Tags); + Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); + + D->addAttr(::new (S.Context) + AbiTagAttr(S.Context, AL, Tags.data(), Tags.size())); } -static void handleRISCVInterruptAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - // Warn about repeated attributes. - if (const auto *A = D->getAttr()) { - S.Diag(AL.getRange().getBegin(), - diag::warn_riscv_repeated_interrupt_attribute); - S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); - return; +static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) { + for (const auto *I : D->specific_attrs()) { + if (I->getBTFDeclTag() == Tag) + return true; } + return false; +} - // Check the attribute argument. Argument is optional. - if (!AL.checkAtMostNumArgs(S, 1)) - return; - +static void handleBTFDeclTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - SourceLocation ArgLoc; - - // 'machine'is the default interrupt mode. - if (AL.getNumArgs() == 0) - Str = "machine"; - else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) - return; - - // Semantic checks for a function with the 'interrupt' attribute: - // - Must be a function. - // - Must have no parameters. - // - Must have the 'void' return type. - // - The attribute itself must either have no argument or one of the - // valid interrupt types, see [RISCVInterruptDocs]. - - if (D->getFunctionType() == nullptr) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; - return; - } - - if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*RISC-V*/ 2 << 0; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - } - - if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*RISC-V*/ 2 << 1; + if (hasBTFDeclTagAttr(D, Str)) return; - } - RISCVInterruptAttr::InterruptType Kind; - if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str - << ArgLoc; - return; - } + D->addAttr(::new (S.Context) BTFDeclTagAttr(S.Context, AL, Str)); +} - D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind)); +BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { + if (hasBTFDeclTagAttr(D, AL.getBTFDeclTag())) + return nullptr; + return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag()); } static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Dispatch the interrupt attribute based on the current target. switch (S.Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::msp430: - handleMSP430InterruptAttr(S, D, AL); + S.MSP430().handleInterruptAttr(D, AL); break; case llvm::Triple::mipsel: case llvm::Triple::mips: - handleMipsInterruptAttr(S, D, AL); + S.MIPS().handleInterruptAttr(D, AL); break; case llvm::Triple::m68k: - handleM68kInterruptAttr(S, D, AL); + S.M68k().handleInterruptAttr(D, AL); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - handleAnyX86InterruptAttr(S, D, AL); + S.X86().handleAnyInterruptAttr(D, AL); break; case llvm::Triple::avr: - handleAVRInterruptAttr(S, D, AL); + S.AVR().handleInterruptAttr(D, AL); break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: - handleRISCVInterruptAttr(S, D, AL); + S.RISCV().handleInterruptAttr(D, AL); break; default: - handleARMInterruptAttr(S, D, AL); + S.ARM().handleInterruptAttr(D, AL); break; } } -static bool -checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, - const AMDGPUFlatWorkGroupSizeAttr &Attr) { - // Accept template arguments for now as they depend on something else. - // We'll get to check them when they eventually get instantiated. - if (MinExpr->isValueDependent() || MaxExpr->isValueDependent()) - return false; - - uint32_t Min = 0; - if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) - return true; - - uint32_t Max = 0; - if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) - return true; - - if (Min == 0 && Max != 0) { - S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) - << &Attr << 0; - return true; - } - if (Min > Max) { - S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) - << &Attr << 1; - return true; - } - - return false; -} - -AMDGPUFlatWorkGroupSizeAttr * -Sema::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, - Expr *MinExpr, Expr *MaxExpr) { - AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr); - - if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr)) - return nullptr; - return ::new (Context) - AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr); -} - -void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D, - const AttributeCommonInfo &CI, - Expr *MinExpr, Expr *MaxExpr) { - if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr)) - D->addAttr(Attr); -} - -static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - Expr *MinExpr = AL.getArgAsExpr(0); - Expr *MaxExpr = AL.getArgAsExpr(1); - - S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr); -} - -static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, - Expr *MaxExpr, - const AMDGPUWavesPerEUAttr &Attr) { - if (S.DiagnoseUnexpandedParameterPack(MinExpr) || - (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr))) - return true; - - // Accept template arguments for now as they depend on something else. - // We'll get to check them when they eventually get instantiated. - if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent())) - return false; - - uint32_t Min = 0; - if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) - return true; - - uint32_t Max = 0; - if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) - return true; - - if (Min == 0 && Max != 0) { - S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) - << &Attr << 0; - return true; - } - if (Max != 0 && Min > Max) { - S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) - << &Attr << 1; - return true; - } - - return false; -} - -AMDGPUWavesPerEUAttr * -Sema::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *MinExpr, - Expr *MaxExpr) { - AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr); - - if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr)) - return nullptr; - - return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr); -} - -void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *MinExpr, Expr *MaxExpr) { - if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr)) - D->addAttr(Attr); -} - -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) - return; - - Expr *MinExpr = AL.getArgAsExpr(0); - Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; - - S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr); -} - -static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t NumSGPR = 0; - Expr *NumSGPRExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR)) - return; - - D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR)); -} - -static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t NumVGPR = 0; - Expr *NumVGPRExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR)) - return; - - D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR)); -} - -static bool -checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr, - Expr *ZExpr, - const AMDGPUMaxNumWorkGroupsAttr &Attr) { - if (S.DiagnoseUnexpandedParameterPack(XExpr) || - (YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) || - (ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr))) - return true; - - // Accept template arguments for now as they depend on something else. - // We'll get to check them when they eventually get instantiated. - if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) || - (ZExpr && ZExpr->isValueDependent())) - return false; - - uint32_t NumWG = 0; - Expr *Exprs[3] = {XExpr, YExpr, ZExpr}; - for (int i = 0; i < 3; i++) { - if (Exprs[i]) { - if (!checkUInt32Argument(S, Attr, Exprs[i], NumWG, i, - /*StrictlyUnsigned=*/true)) - return true; - if (NumWG == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << &Attr << Exprs[i]->getSourceRange(); - return true; - } - } - } - - return false; -} - -AMDGPUMaxNumWorkGroupsAttr * -Sema::CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, - Expr *XExpr, Expr *YExpr, Expr *ZExpr) { - AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr); - - if (checkAMDGPUMaxNumWorkGroupsArguments(*this, XExpr, YExpr, ZExpr, TmpAttr)) - return nullptr; - - return ::new (Context) - AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr); -} - -void Sema::addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *XExpr, Expr *YExpr, - Expr *ZExpr) { - if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr)) - D->addAttr(Attr); -} - -static void handleAMDGPUMaxNumWorkGroupsAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; - Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr; - S.addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr); -} - -static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - // If we try to apply it to a function pointer, don't warn, but don't - // do anything, either. It doesn't matter anyway, because there's nothing - // special about calling a force_align_arg_pointer function. - const auto *VD = dyn_cast(D); - if (VD && VD->getType()->isFunctionPointerType()) - return; - // Also don't warn on function pointer typedefs. - const auto *TD = dyn_cast(D); - if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || - TD->getUnderlyingType()->isFunctionType())) - return; - // Attribute can only be applied to function types. - if (!isa(D)) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; - return; - } - - D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL)); -} - static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Version; Expr *VersionExpr = static_cast(AL.getArgAsExpr(0)); - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Version)) return; // TODO: Investigate what happens with the next major version of MSVC. @@ -8573,62 +5861,6 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(Internal); } -static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (S.LangOpts.getOpenCLCompatibleVersion() < 200) - S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) - << AL << "2.0" << 1; - else - S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) - << AL << S.LangOpts.getOpenCLVersionString(); -} - -static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (D->isInvalidDecl()) - return; - - // Check if there is only one access qualifier. - if (D->hasAttr()) { - if (D->getAttr()->getSemanticSpelling() == - AL.getSemanticSpelling()) { - S.Diag(AL.getLoc(), diag::warn_duplicate_declspec) - << AL.getAttrName()->getName() << AL.getRange(); - } else { - S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) - << D->getSourceRange(); - D->setInvalidDecl(true); - return; - } - } - - // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that - // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel - // cannot read from and write to the same pipe object. Using the read_write - // (or __read_write) qualifier with the pipe qualifier is a compilation error. - // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the - // __opencl_c_read_write_images feature, image objects specified as arguments - // to a kernel can additionally be declared to be read-write. - // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0. - // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0. - if (const auto *PDecl = dyn_cast(D)) { - const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (AL.getAttrName()->getName().contains("read_write")) { - bool ReadWriteImagesUnsupported = - (S.getLangOpts().getOpenCLCompatibleVersion() < 200) || - (S.getLangOpts().getOpenCLCompatibleVersion() == 300 && - !S.getOpenCLOptions().isSupported("__opencl_c_read_write_images", - S.getLangOpts())); - if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) { - S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) - << AL << PDecl->getType() << DeclTy->isImageType(); - D->setInvalidDecl(true); - return; - } - } - } - - D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL)); -} - static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check that the argument is a string literal. StringRef KindStr; @@ -8663,31 +5895,95 @@ static const RecordDecl *GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) { return RD; } -static bool -CheckCountExpr(Sema &S, FieldDecl *FD, Expr *E, - llvm::SmallVectorImpl &Decls) { +enum class CountedByInvalidPointeeTypeKind { + INCOMPLETE, + SIZELESS, + FUNCTION, + FLEXIBLE_ARRAY_MEMBER, + VALID, +}; + +static bool CheckCountedByAttrOnField( + Sema &S, FieldDecl *FD, Expr *E, + llvm::SmallVectorImpl &Decls) { + // Check the context the attribute is used in + if (FD->getParent()->isUnion()) { S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_in_union) << FD->getSourceRange(); return true; } - if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) { - S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer) - << E->getSourceRange(); + const auto FieldTy = FD->getType(); + if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) { + S.Diag(FD->getBeginLoc(), + diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member) + << FD->getLocation(); return true; } LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = LangOptions::StrictFlexArraysLevelKind::IncompleteOnly; - - if (!Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FD->getType(), + if (FieldTy->isArrayType() && + !Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FieldTy, StrictFlexArraysLevel, true)) { - // The "counted_by" attribute must be on a flexible array member. - SourceRange SR = FD->getLocation(); - S.Diag(SR.getBegin(), - diag::err_counted_by_attr_not_on_flexible_array_member) - << SR; + S.Diag(FD->getBeginLoc(), + diag::err_counted_by_attr_on_array_not_flexible_array_member) + << FD->getLocation(); + return true; + } + + CountedByInvalidPointeeTypeKind InvalidTypeKind = + CountedByInvalidPointeeTypeKind::VALID; + QualType PointeeTy; + int SelectPtrOrArr = 0; + if (FieldTy->isPointerType()) { + PointeeTy = FieldTy->getPointeeType(); + SelectPtrOrArr = 0; + } else { + assert(FieldTy->isArrayType()); + const ArrayType *AT = S.getASTContext().getAsArrayType(FieldTy); + PointeeTy = AT->getElementType(); + SelectPtrOrArr = 1; + } + // Note: The `Decl::isFlexibleArrayMemberLike` check earlier on means + // only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable + // when `FieldTy->isArrayType()`. + bool ShouldWarn = false; + if (PointeeTy->isIncompleteType()) { + InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE; + } else if (PointeeTy->isSizelessType()) { + InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS; + } else if (PointeeTy->isFunctionType()) { + InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION; + } else if (PointeeTy->isStructureTypeWithFlexibleArrayMember()) { + if (FieldTy->isArrayType()) { + // This is a workaround for the Linux kernel that has already adopted + // `counted_by` on a FAM where the pointee is a struct with a FAM. This + // should be an error because computing the bounds of the array cannot be + // done correctly without manually traversing every struct object in the + // array at runtime. To allow the code to be built this error is + // downgraded to a warning. + ShouldWarn = true; + } + InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER; + } + + if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) { + unsigned DiagID = ShouldWarn + ? diag::warn_counted_by_attr_elt_type_unknown_size + : diag::err_counted_by_attr_pointee_unknown_size; + S.Diag(FD->getBeginLoc(), DiagID) + << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind + << (ShouldWarn ? 1 : 0) << FD->getSourceRange(); + return true; + } + + // Check the expression + + if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) { + S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer) + << E->getSourceRange(); return true; } @@ -8750,10 +6046,11 @@ static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) { return; llvm::SmallVector Decls; - if (CheckCountExpr(S, FD, CountExpr, Decls)) + if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls)) return; - QualType CAT = S.BuildCountAttributedArrayType(FD->getType(), CountExpr); + QualType CAT = + S.BuildCountAttributedArrayOrPointerType(FD->getType(), CountExpr); FD->setType(CAT); } @@ -8797,45 +6094,6 @@ static void handleNoUniqueAddressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NoUniqueAddressAttr::Create(S.Context, AL)); } -static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // The 'sycl_kernel' attribute applies only to function templates. - const auto *FD = cast(D); - const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate(); - assert(FT && "Function template is expected"); - - // Function template must have at least two template parameters. - const TemplateParameterList *TL = FT->getTemplateParameters(); - if (TL->size() < 2) { - S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params); - return; - } - - // Template parameters must be typenames. - for (unsigned I = 0; I < 2; ++I) { - const NamedDecl *TParam = TL->getParam(I); - if (isa(TParam)) { - S.Diag(FT->getLocation(), - diag::warn_sycl_kernel_invalid_template_param_type); - return; - } - } - - // Function must have at least one argument. - if (getFunctionOrMethodNumParams(D) != 1) { - S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params); - return; - } - - // Function must return void. - QualType RetTy = getFunctionOrMethodResultType(D); - if (!RetTy->isVoidType()) { - S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type); - return; - } - - handleSimpleAttribute(S, D, AL); -} - static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (!cast(D)->hasGlobalStorage()) { S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var) @@ -8855,81 +6113,6 @@ static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL)); } -static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD, - bool DiagnoseFailure) { - QualType Ty = VD->getType(); - if (!Ty->isObjCRetainableType()) { - if (DiagnoseFailure) { - S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) - << 0; - } - return false; - } - - Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime(); - - // SemaObjC::inferObjCARCLifetime must run after processing decl attributes - // (because __block lowers to an attribute), so if the lifetime hasn't been - // explicitly specified, infer it locally now. - if (LifetimeQual == Qualifiers::OCL_None) - LifetimeQual = Ty->getObjCARCImplicitLifetime(); - - // The attributes only really makes sense for __strong variables; ignore any - // attempts to annotate a parameter with any other lifetime qualifier. - if (LifetimeQual != Qualifiers::OCL_Strong) { - if (DiagnoseFailure) { - S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) - << 1; - } - return false; - } - - // Tampering with the type of a VarDecl here is a bit of a hack, but we need - // to ensure that the variable is 'const' so that we can error on - // modification, which can otherwise over-release. - VD->setType(Ty.withConst()); - VD->setARCPseudoStrong(true); - return true; -} - -static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { - if (auto *VD = dyn_cast(D)) { - assert(!isa(VD) && "should be diagnosed automatically"); - if (!VD->hasLocalStorage()) { - S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained) - << 0; - return; - } - - if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true)) - return; - - handleSimpleAttribute(S, D, AL); - return; - } - - // If D is a function-like declaration (method, block, or function), then we - // make every parameter psuedo-strong. - unsigned NumParams = - hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0; - for (unsigned I = 0; I != NumParams; ++I) { - auto *PVD = const_cast(getFunctionOrMethodParam(D, I)); - QualType Ty = PVD->getType(); - - // If a user wrote a parameter with __strong explicitly, then assume they - // want "real" strong semantics for that parameter. This works because if - // the parameter was written with __strong, then the strong qualifier will - // be non-local. - if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() == - Qualifiers::OCL_Strong) - continue; - - tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false); - } - handleSimpleAttribute(S, D, AL); -} - static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check that the return type is a `typedef int kern_return_t` or a typedef // around it, because otherwise MIG convention checks make no sense. @@ -9119,82 +6302,6 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) { return false; } -static bool checkArmNewAttrMutualExclusion( - Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT, - FunctionType::ArmStateValue CurrentState, StringRef StateName) { - auto CheckForIncompatibleAttr = - [&](FunctionType::ArmStateValue IncompatibleState, - StringRef IncompatibleStateName) { - if (CurrentState == IncompatibleState) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << (std::string("'__arm_new(\"") + StateName.str() + "\")'") - << (std::string("'") + IncompatibleStateName.str() + "(\"" + - StateName.str() + "\")'") - << true; - AL.setInvalid(); - } - }; - - CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in"); - CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out"); - CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout"); - CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves"); - return AL.isInvalid(); -} - -static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.getNumArgs()) { - S.Diag(AL.getLoc(), diag::err_missing_arm_state) << AL; - AL.setInvalid(); - return; - } - - std::vector NewState; - if (const auto *ExistingAttr = D->getAttr()) { - for (StringRef S : ExistingAttr->newArgs()) - NewState.push_back(S); - } - - bool HasZA = false; - bool HasZT0 = false; - for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { - StringRef StateName; - SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc)) - return; - - if (StateName == "za") - HasZA = true; - else if (StateName == "zt0") - HasZT0 = true; - else { - S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName; - AL.setInvalid(); - return; - } - - if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates. - NewState.push_back(StateName); - } - - if (auto *FPT = dyn_cast(D->getFunctionType())) { - FunctionType::ArmStateValue ZAState = - FunctionType::getArmZAState(FPT->getAArch64SMEAttributes()); - if (HasZA && ZAState != FunctionType::ARM_None && - checkArmNewAttrMutualExclusion(S, AL, FPT, ZAState, "za")) - return; - FunctionType::ArmStateValue ZT0State = - FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes()); - if (HasZT0 && ZT0State != FunctionType::ARM_None && - checkArmNewAttrMutualExclusion(S, AL, FPT, ZT0State, "zt0")) - return; - } - - D->dropAttr(); - D->addAttr(::new (S.Context) - ArmNewAttr(S.Context, AL, NewState.data(), NewState.size())); -} - /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. @@ -9317,7 +6424,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleInterruptAttr(S, D, AL); break; case ParsedAttr::AT_X86ForceAlignArgPointer: - handleX86ForceAlignArgPointerAttr(S, D, AL); + S.X86().handleForceAlignArgPointerAttr(D, AL); break; case ParsedAttr::AT_ReadOnlyPlacement: handleSimpleAttribute(S, D, AL); @@ -9327,25 +6434,25 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleDLLAttr(S, D, AL); break; case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: - handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL); + S.AMDGPU().handleAMDGPUFlatWorkGroupSizeAttr(D, AL); break; case ParsedAttr::AT_AMDGPUWavesPerEU: - handleAMDGPUWavesPerEUAttr(S, D, AL); + S.AMDGPU().handleAMDGPUWavesPerEUAttr(D, AL); break; case ParsedAttr::AT_AMDGPUNumSGPR: - handleAMDGPUNumSGPRAttr(S, D, AL); + S.AMDGPU().handleAMDGPUNumSGPRAttr(D, AL); break; case ParsedAttr::AT_AMDGPUNumVGPR: - handleAMDGPUNumVGPRAttr(S, D, AL); + S.AMDGPU().handleAMDGPUNumVGPRAttr(D, AL); break; case ParsedAttr::AT_AMDGPUMaxNumWorkGroups: - handleAMDGPUMaxNumWorkGroupsAttr(S, D, AL); + S.AMDGPU().handleAMDGPUMaxNumWorkGroupsAttr(D, AL); break; case ParsedAttr::AT_AVRSignal: - handleAVRSignalAttr(S, D, AL); + S.AVR().handleSignalAttr(D, AL); break; case ParsedAttr::AT_BPFPreserveAccessIndex: - handleBPFPreserveAccessIndexAttr(S, D, AL); + S.BPF().handlePreserveAccessIndexAttr(D, AL); break; case ParsedAttr::AT_BPFPreserveStaticOffset: handleSimpleAttribute(S, D, AL); @@ -9354,19 +6461,19 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleBTFDeclTagAttr(S, D, AL); break; case ParsedAttr::AT_WebAssemblyExportName: - handleWebAssemblyExportNameAttr(S, D, AL); + S.Wasm().handleWebAssemblyExportNameAttr(D, AL); break; case ParsedAttr::AT_WebAssemblyImportModule: - handleWebAssemblyImportModuleAttr(S, D, AL); + S.Wasm().handleWebAssemblyImportModuleAttr(D, AL); break; case ParsedAttr::AT_WebAssemblyImportName: - handleWebAssemblyImportNameAttr(S, D, AL); + S.Wasm().handleWebAssemblyImportNameAttr(D, AL); break; case ParsedAttr::AT_IBOutlet: - handleIBOutlet(S, D, AL); + S.ObjC().handleIBOutlet(D, AL); break; case ParsedAttr::AT_IBOutletCollection: - handleIBOutletCollection(S, D, AL); + S.ObjC().handleIBOutletCollection(D, AL); break; case ParsedAttr::AT_IFunc: handleIFuncAttr(S, D, AL); @@ -9457,7 +6564,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleEnumExtensibilityAttr(S, D, AL); break; case ParsedAttr::AT_SYCLKernel: - handleSYCLKernelAttr(S, D, AL); + S.SYCL().handleKernelAttr(D, AL); break; case ParsedAttr::AT_SYCLSpecialClass: handleSimpleAttribute(S, D, AL); @@ -9543,53 +6650,54 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleVecReturnAttr(S, D, AL); break; case ParsedAttr::AT_ObjCOwnership: - handleObjCOwnershipAttr(S, D, AL); + S.ObjC().handleOwnershipAttr(D, AL); break; case ParsedAttr::AT_ObjCPreciseLifetime: - handleObjCPreciseLifetimeAttr(S, D, AL); + S.ObjC().handlePreciseLifetimeAttr(D, AL); break; case ParsedAttr::AT_ObjCReturnsInnerPointer: - handleObjCReturnsInnerPointerAttr(S, D, AL); + S.ObjC().handleReturnsInnerPointerAttr(D, AL); break; case ParsedAttr::AT_ObjCRequiresSuper: - handleObjCRequiresSuperAttr(S, D, AL); + S.ObjC().handleRequiresSuperAttr(D, AL); break; case ParsedAttr::AT_ObjCBridge: - handleObjCBridgeAttr(S, D, AL); + S.ObjC().handleBridgeAttr(D, AL); break; case ParsedAttr::AT_ObjCBridgeMutable: - handleObjCBridgeMutableAttr(S, D, AL); + S.ObjC().handleBridgeMutableAttr(D, AL); break; case ParsedAttr::AT_ObjCBridgeRelated: - handleObjCBridgeRelatedAttr(S, D, AL); + S.ObjC().handleBridgeRelatedAttr(D, AL); break; case ParsedAttr::AT_ObjCDesignatedInitializer: - handleObjCDesignatedInitializer(S, D, AL); + S.ObjC().handleDesignatedInitializer(D, AL); break; case ParsedAttr::AT_ObjCRuntimeName: - handleObjCRuntimeName(S, D, AL); + S.ObjC().handleRuntimeName(D, AL); break; case ParsedAttr::AT_ObjCBoxable: - handleObjCBoxable(S, D, AL); + S.ObjC().handleBoxable(D, AL); break; case ParsedAttr::AT_NSErrorDomain: - handleNSErrorDomain(S, D, AL); + S.ObjC().handleNSErrorDomain(D, AL); break; case ParsedAttr::AT_CFConsumed: case ParsedAttr::AT_NSConsumed: case ParsedAttr::AT_OSConsumed: - S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL), - /*IsTemplateInstantiation=*/false); + S.ObjC().AddXConsumedAttr(D, AL, + S.ObjC().parsedAttrToRetainOwnershipKind(AL), + /*IsTemplateInstantiation=*/false); break; case ParsedAttr::AT_OSReturnsRetainedOnZero: handleSimpleAttributeOrDiagnose( - S, D, AL, isValidOSObjectOutParameter(D), + S, D, AL, S.ObjC().isValidOSObjectOutParameter(D), diag::warn_ns_attribute_wrong_parameter_type, /*Extra Args=*/AL, /*pointer-to-OSObject-pointer*/ 3, AL.getRange()); break; case ParsedAttr::AT_OSReturnsRetainedOnNonZero: handleSimpleAttributeOrDiagnose( - S, D, AL, isValidOSObjectOutParameter(D), + S, D, AL, S.ObjC().isValidOSObjectOutParameter(D), diag::warn_ns_attribute_wrong_parameter_type, /*Extra Args=*/AL, /*pointer-to-OSObject-poointer*/ 3, AL.getRange()); break; @@ -9600,7 +6708,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_CFReturnsRetained: case ParsedAttr::AT_OSReturnsNotRetained: case ParsedAttr::AT_OSReturnsRetained: - handleXReturnsXRetainedAttr(S, D, AL); + S.ObjC().handleXReturnsXRetainedAttr(D, AL); break; case ParsedAttr::AT_WorkGroupSizeHint: handleWorkGroupSize(S, D, AL); @@ -9609,7 +6717,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleWorkGroupSize(S, D, AL); break; case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize: - handleSubGroupSize(S, D, AL); + S.OpenCL().handleSubGroupSize(D, AL); break; case ParsedAttr::AT_VecTypeHint: handleVecTypeHint(S, D, AL); @@ -9654,17 +6762,17 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleAttrWithMessage(S, D, AL); break; case ParsedAttr::AT_OMPAssume: - handleOMPAssumeAttr(S, D, AL); + S.OpenMP().handleOMPAssumeAttr(D, AL); break; case ParsedAttr::AT_ObjCDirect: - handleObjCDirectAttr(S, D, AL); + S.ObjC().handleDirectAttr(D, AL); break; case ParsedAttr::AT_ObjCDirectMembers: - handleObjCDirectMembersAttr(S, D, AL); + S.ObjC().handleDirectMembersAttr(D, AL); handleSimpleAttribute(S, D, AL); break; case ParsedAttr::AT_ObjCExplicitProtocolImpl: - handleObjCSuppresProtocolAttr(S, D, AL); + S.ObjC().handleSuppresProtocolAttr(D, AL); break; case ParsedAttr::AT_Unused: handleUnusedAttr(S, D, AL); @@ -9688,16 +6796,16 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleTransparentUnionAttr(S, D, AL); break; case ParsedAttr::AT_ObjCMethodFamily: - handleObjCMethodFamilyAttr(S, D, AL); + S.ObjC().handleMethodFamilyAttr(D, AL); break; case ParsedAttr::AT_ObjCNSObject: - handleObjCNSObject(S, D, AL); + S.ObjC().handleNSObject(D, AL); break; case ParsedAttr::AT_ObjCIndependentClass: - handleObjCIndependentClass(S, D, AL); + S.ObjC().handleIndependentClass(D, AL); break; case ParsedAttr::AT_Blocks: - handleBlocksAttr(S, D, AL); + S.ObjC().handleBlocksAttr(D, AL); break; case ParsedAttr::AT_Sentinel: handleSentinelAttr(S, D, AL); @@ -9709,7 +6817,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleNoDebugAttr(S, D, AL); break; case ParsedAttr::AT_CmseNSEntry: - handleCmseNSEntryAttr(S, D, AL); + S.ARM().handleCmseNSEntryAttr(D, AL); break; case ParsedAttr::AT_StdCall: case ParsedAttr::AT_CDecl: @@ -9742,22 +6850,22 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleLifetimeCategoryAttr(S, D, AL); break; case ParsedAttr::AT_OpenCLAccess: - handleOpenCLAccessAttr(S, D, AL); + S.OpenCL().handleAccessAttr(D, AL); break; case ParsedAttr::AT_OpenCLNoSVM: - handleOpenCLNoSVMAttr(S, D, AL); + S.OpenCL().handleNoSVMAttr(D, AL); break; case ParsedAttr::AT_SwiftContext: - S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext); + S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftContext); break; case ParsedAttr::AT_SwiftAsyncContext: - S.AddParameterABIAttr(D, AL, ParameterABI::SwiftAsyncContext); + S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftAsyncContext); break; case ParsedAttr::AT_SwiftErrorResult: - S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult); + S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult); break; case ParsedAttr::AT_SwiftIndirectResult: - S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult); + S.Swift().AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult); break; case ParsedAttr::AT_InternalLinkage: handleInternalLinkageAttr(S, D, AL); @@ -9802,25 +6910,25 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, // HLSL attributes: case ParsedAttr::AT_HLSLNumThreads: - handleHLSLNumThreadsAttr(S, D, AL); + S.HLSL().handleNumThreadsAttr(D, AL); break; case ParsedAttr::AT_HLSLSV_GroupIndex: handleSimpleAttribute(S, D, AL); break; case ParsedAttr::AT_HLSLSV_DispatchThreadID: - handleHLSLSV_DispatchThreadIDAttr(S, D, AL); + S.HLSL().handleSV_DispatchThreadIDAttr(D, AL); break; case ParsedAttr::AT_HLSLPackOffset: - handleHLSLPackOffsetAttr(S, D, AL); + S.HLSL().handlePackOffsetAttr(D, AL); break; case ParsedAttr::AT_HLSLShader: - handleHLSLShaderAttr(S, D, AL); + S.HLSL().handleShaderAttr(D, AL); break; case ParsedAttr::AT_HLSLResourceBinding: - handleHLSLResourceBindingAttr(S, D, AL); + S.HLSL().handleResourceBindingAttr(D, AL); break; case ParsedAttr::AT_HLSLParamModifier: - handleHLSLParamModifierAttr(S, D, AL); + S.HLSL().handleParamModifierAttr(D, AL); break; case ParsedAttr::AT_AbiTag: @@ -9923,28 +7031,28 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, // Swift attributes. case ParsedAttr::AT_SwiftAsyncName: - handleSwiftAsyncName(S, D, AL); + S.Swift().handleAsyncName(D, AL); break; case ParsedAttr::AT_SwiftAttr: - handleSwiftAttrAttr(S, D, AL); + S.Swift().handleAttrAttr(D, AL); break; case ParsedAttr::AT_SwiftBridge: - handleSwiftBridge(S, D, AL); + S.Swift().handleBridge(D, AL); break; case ParsedAttr::AT_SwiftError: - handleSwiftError(S, D, AL); + S.Swift().handleError(D, AL); break; case ParsedAttr::AT_SwiftName: - handleSwiftName(S, D, AL); + S.Swift().handleName(D, AL); break; case ParsedAttr::AT_SwiftNewType: - handleSwiftNewType(S, D, AL); + S.Swift().handleNewType(D, AL); break; case ParsedAttr::AT_SwiftAsync: - handleSwiftAsyncAttr(S, D, AL); + S.Swift().handleAsyncAttr(D, AL); break; case ParsedAttr::AT_SwiftAsyncError: - handleSwiftAsyncError(S, D, AL); + S.Swift().handleAsyncError(D, AL); break; // XRay attributes. @@ -9966,7 +7074,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; case ParsedAttr::AT_ObjCExternallyRetained: - handleObjCExternallyRetainedAttr(S, D, AL); + S.ObjC().handleExternallyRetainedAttr(D, AL); break; case ParsedAttr::AT_MIGServerRoutine: @@ -9978,7 +7086,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; case ParsedAttr::AT_ArmBuiltinAlias: - handleArmBuiltinAliasAttr(S, D, AL); + S.ARM().handleBuiltinAliasAttr(D, AL); break; case ParsedAttr::AT_ArmLocallyStreaming: @@ -9986,7 +7094,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; case ParsedAttr::AT_ArmNew: - handleArmNewAttr(S, D, AL); + S.ARM().handleNewAttr(D, AL); break; case ParsedAttr::AT_AcquireHandle: @@ -10119,7 +7227,7 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D, // For BPFPreserveAccessIndexAttr, we want to populate the attributes // to fields and inner records as well. if (D && D->hasAttr()) - handleBPFPreserveAIRecord(*this, cast(D)); + BPF().handlePreserveAIRecord(cast(D)); } // Annotation attributes are the only attributes allowed after an access diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 104e27139fe479ea65080f8492d335f6e5b919cc..3c28da1b077cd5f6dab90ae998b9f78fedde432a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2469,11 +2469,18 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // base class sub-objects shall be a constexpr constructor. // // Note that this rule is distinct from the "requirements for a constexpr - // function", so is not checked in CheckValid mode. + // function", so is not checked in CheckValid mode. Because the check for + // constexpr potential is expensive, skip the check if the diagnostic is + // disabled, the function is declared in a system header, or we're in C++23 + // or later mode (see https://wg21.link/P2448). + bool SkipCheck = + !SemaRef.getLangOpts().CheckConstexprFunctionBodies || + SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) || + SemaRef.getDiagnostics().isIgnored( + diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation()); SmallVector Diags; - if (Kind == Sema::CheckConstexprKind::Diagnose && - !Expr::isPotentialConstantExpr(Dcl, Diags) && - !SemaRef.getLangOpts().CPlusPlus23) { + if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck && + !Expr::isPotentialConstantExpr(Dcl, Diags)) { SemaRef.Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr) << isa(Dcl) << Dcl->isConsteval() @@ -11547,12 +11554,12 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); bool TemplateMatches = Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); - auto TKind = SpecifiedName.getKind(); - // A Using TemplateName can't actually be valid (either it's qualified, or - // we're in the wrong scope). But we have diagnosed these problems - // already. - bool SimplyWritten = TKind == TemplateName::Template || - TKind == TemplateName::UsingTemplate; + + const QualifiedTemplateName *Qualifiers = + SpecifiedName.getAsQualifiedTemplateName(); + assert(Qualifiers && "expected QualifiedTemplate"); + bool SimplyWritten = !Qualifiers->hasTemplateKeyword() && + Qualifiers->getQualifier() == nullptr; if (SimplyWritten && TemplateMatches) AcceptableReturnType = true; else { @@ -17580,11 +17587,12 @@ DeclResult Sema::ActOnTemplatedFriendTag( if (Invalid) return true; - return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, - NameLoc, Attr, TemplateParams, AS_public, + return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS, + Name, NameLoc, Attr, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), FriendLoc, TempParamLists.size() - 1, - TempParamLists.data()).get(); + TempParamLists.data()) + .get(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) @@ -17612,8 +17620,8 @@ DeclResult Sema::ActOnTemplatedFriendTag( if (SS.isEmpty()) { bool Owned = false; bool IsDependent = false; - return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, - AS_public, + return ActOnTag(S, TagSpec, TagUseKind::Friend, TagLoc, SS, Name, NameLoc, + Attr, AS_public, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, /*ScopedEnumKWLoc=*/SourceLocation(), @@ -17728,7 +17736,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl - // for a TUK_Friend. + // for a TagUseKind::Friend. Declarator TheDeclarator(DS, ParsedAttributesView::none(), DeclaratorContext::Member); TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 6d4379283f198f03c7cbb779422a3c6a5609574c..807453400abdd0b188d09a441dee2d2a08645825 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -567,9 +567,8 @@ void SemaObjC::ActOnSuperClassOfClassInterface( if (TypoCorrection Corrected = SemaRef.CorrectTypo( DeclarationNameInfo(SuperName, SuperLoc), Sema::LookupOrdinaryName, SemaRef.TUScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { - SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::err_undef_superclass_suggest) - << SuperName << ClassName); + SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) + << SuperName << ClassName); PrevDecl = Corrected.getCorrectionDeclAs(); } } @@ -1322,9 +1321,9 @@ void SemaObjC::FindProtocolDeclaration(bool WarnOnDeclarations, Sema::LookupObjCProtocolName, SemaRef.TUScope, nullptr, CCC, Sema::CTK_ErrorRecovery); if ((PDecl = Corrected.getCorrectionDeclAs())) - SemaRef.diagnoseTypo( - Corrected, SemaRef.PDiag(diag::err_undeclared_protocol_suggest) - << Pair.first); + SemaRef.diagnoseTypo(Corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << Pair.first); } if (!PDecl) { @@ -1703,9 +1702,9 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers( if (corrected) { // Did we find a protocol? if (auto proto = corrected.getCorrectionDeclAs()) { - SemaRef.diagnoseTypo( - corrected, SemaRef.PDiag(diag::err_undeclared_protocol_suggest) - << identifiers[i]); + SemaRef.diagnoseTypo(corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << identifiers[i]); lookupKind = Sema::LookupObjCProtocolName; protocols[i] = proto; ++numProtocolsResolved; @@ -1715,7 +1714,7 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers( // Did we find a type? if (auto typeDecl = corrected.getCorrectionDeclAs()) { SemaRef.diagnoseTypo(corrected, - SemaRef.PDiag(diag::err_unknown_typename_suggest) + PDiag(diag::err_unknown_typename_suggest) << identifiers[i]); lookupKind = Sema::LookupOrdinaryName; typeDecls[i] = typeDecl; @@ -1725,10 +1724,9 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers( // Did we find an Objective-C class? if (auto objcClass = corrected.getCorrectionDeclAs()) { - SemaRef.diagnoseTypo( - corrected, - SemaRef.PDiag(diag::err_unknown_type_or_class_name_suggest) - << identifiers[i] << true); + SemaRef.diagnoseTypo(corrected, + PDiag(diag::err_unknown_type_or_class_name_suggest) + << identifiers[i] << true); lookupKind = Sema::LookupOrdinaryName; typeDecls[i] = objcClass; ++numTypeDeclsResolved; @@ -2009,10 +2007,9 @@ ObjCImplementationDecl *SemaObjC::ActOnStartClassImplementation( // Suggest the (potentially) correct interface name. Don't provide a // code-modification hint or use the typo name for recovery, because // this is just a warning. The program may actually be correct. - SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::warn_undef_interface_suggest) - << ClassName, - /*ErrorRecovery*/ false); + SemaRef.diagnoseTypo( + Corrected, PDiag(diag::warn_undef_interface_suggest) << ClassName, + /*ErrorRecovery*/ false); } else { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; } @@ -5439,8 +5436,7 @@ ObjCInterfaceDecl *SemaObjC::getObjCInterfaceDecl(const IdentifierInfo *&Id, if (TypoCorrection C = SemaRef.CorrectTypo( DeclarationNameInfo(Id, IdLoc), Sema::LookupOrdinaryName, SemaRef.TUScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { - SemaRef.diagnoseTypo(C, SemaRef.PDiag(diag::err_undef_interface_suggest) - << Id); + SemaRef.diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id); IDecl = C.getCorrectionDeclAs(); Id = IDecl->getIdentifier(); } @@ -5544,7 +5540,7 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { SemaRef.MarkFunctionReferenced(Field->getLocation(), Destructor); SemaRef.CheckDestructorAccess( Field->getLocation(), Destructor, - SemaRef.PDiag(diag::err_access_dtor_ivar) + PDiag(diag::err_access_dtor_ivar) << Context.getBaseElementType(Field->getType())); } } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 41bf273d12f2f32441253cb75eddb92419281deb..17acfca6b01126213027d3572b45744054b995fd 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1425,6 +1425,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // Most statements can throw if any substatement can throw. case Stmt::OpenACCComputeConstructClass: + case Stmt::OpenACCLoopConstructClass: case Stmt::AttributedStmtClass: case Stmt::BreakStmtClass: case Stmt::CapturedStmtClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 326879b0883fa114e798feafd067bcf74cb5b2ff..fb5ca199b3fc62d95fadb4ee39020a8c587fcda3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3284,10 +3284,10 @@ ExprResult Sema::BuildDeclarationNameExpr( return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}); } - if (TemplateDecl *Template = dyn_cast(D)) { + if (TemplateDecl *TD = dyn_cast(D)) { // Specifically diagnose references to class templates that are missing // a template argument list. - diagnoseMissingTemplateArguments(TemplateName(Template), Loc); + diagnoseMissingTemplateArguments(SS, /*TemplateKeyword=*/false, TD, Loc); return ExprError(); } @@ -5185,7 +5185,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } // Perform default conversions. - if (!LHSExp->getType()->getAs()) { + if (!LHSExp->getType()->isSubscriptableVectorType()) { ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp); if (Result.isInvalid()) return ExprError(); @@ -5506,6 +5506,15 @@ struct EnsureImmediateInvocationInDefaultArgs // cause it to incorrectly point it to the outermost class // in the case of nested struct initialization. ExprResult TransformCXXThisExpr(CXXThisExpr *E) { return E; } + + // Rewrite to source location to refer to the context in which they are used. + ExprResult TransformSourceLocExpr(SourceLocExpr *E) { + if (E->getParentContext() == SemaRef.CurContext) + return E; + return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getType(), + E->getBeginLoc(), E->getEndLoc(), + SemaRef.CurContext); + } }; ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -5563,10 +5572,9 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Res = Immediate.TransformInitializer(Param->getInit(), /*NotCopy=*/false); }); - if (Res.isInvalid()) - return ExprError(); - Res = ConvertParamDefaultArgument(Param, Res.get(), - Res.get()->getBeginLoc()); + if (Res.isUsable()) + Res = ConvertParamDefaultArgument(Param, Res.get(), + Res.get()->getBeginLoc()); if (Res.isInvalid()) return ExprError(); Init = Res.get(); @@ -5600,9 +5608,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { InitializationContext.emplace(Loc, Field, CurContext); Expr *Init = nullptr; + bool HasRewrittenInit = false; bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer(); - + bool InLifetimeExtendingContext = isInLifetimeExtendingContext(); EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field); @@ -5637,19 +5646,36 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { ImmediateCallVisitor V(getASTContext()); if (!NestedDefaultChecking) V.TraverseDecl(Field); - if (V.HasImmediateCalls) { + + // CWG1815 + // Support lifetime extension of temporary created by aggregate + // initialization using a default member initializer. We should always rebuild + // the initializer if it contains any temporaries (if the initializer + // expression is an ExprWithCleanups). Then make sure the normal lifetime + // extension code recurses into the default initializer and does lifetime + // extension when warranted. + bool ContainsAnyTemporaries = + isa_and_present(Field->getInClassInitializer()); + if (V.HasImmediateCalls || InLifetimeExtendingContext || + ContainsAnyTemporaries) { + HasRewrittenInit = true; ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field, CurContext}; ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = NestedDefaultChecking; - + // Pass down lifetime extending flag, and collect temporaries in + // CreateMaterializeTemporaryExpr when we rewrite the call argument. + keepInLifetimeExtendingContext(); EnsureImmediateInvocationInDefaultArgs Immediate(*this); ExprResult Res; + + // Rebuild CXXDefaultInitExpr might cause diagnostics. + SFINAETrap Trap(*this); runWithSufficientStackSpace(Loc, [&] { Res = Immediate.TransformInitializer(Field->getInClassInitializer(), /*CXXDirectInit=*/false); }); - if (!Res.isInvalid()) + if (Res.isUsable()) Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc); if (Res.isInvalid()) { Field->setInvalidDecl(); @@ -5676,7 +5702,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc, Field, InitializationContext->Context, - Init); + HasRewrittenInit ? Init : nullptr); } // DR1351: @@ -5787,6 +5813,27 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, return TypoCorrection(); } +// [C++26][[expr.unary.op]/p4 +// A pointer to member is only formed when an explicit & +// is used and its operand is a qualified-id not enclosed in parentheses. +static bool isParenthetizedAndQualifiedAddressOfExpr(Expr *Fn) { + if (!isa(Fn)) + return false; + + Fn = Fn->IgnoreParens(); + + auto *UO = dyn_cast(Fn); + if (!UO || UO->getOpcode() != clang::UO_AddrOf) + return false; + if (auto *DRE = dyn_cast(UO->getSubExpr()->IgnoreParens())) { + assert(isa(DRE->getDecl()) && "expected a function"); + return DRE->hasQualifier(); + } + if (auto *OVL = dyn_cast(UO->getSubExpr()->IgnoreParens())) + return OVL->getQualifier(); + return false; +} + /// ConvertArgumentsForCall - Converts the arguments specified in /// Args/NumArgs to the parameter types of the function FDecl with /// function prototype Proto. Call is the call expression itself, and @@ -5808,8 +5855,10 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... + + bool AddressOf = isParenthetizedAndQualifiedAddressOfExpr(Fn); bool HasExplicitObjectParameter = - FDecl && FDecl->hasCXXExplicitFunctionObjectParameter(); + !AddressOf && FDecl && FDecl->hasCXXExplicitFunctionObjectParameter(); unsigned ExplicitObjectParameterOffset = HasExplicitObjectParameter ? 1 : 0; unsigned NumParams = Proto->getNumParams(); bool Invalid = false; @@ -6520,7 +6569,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, OverloadExpr::FindResult find = OverloadExpr::find(Fn); // We aren't supposed to apply this logic if there's an '&' involved. - if (!find.HasFormOfMemberPointer) { + if (!find.HasFormOfMemberPointer || find.IsAddressOfOperandWithParen) { if (Expr::hasAnyTypeDependentArguments(ArgExprs)) return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_PRValue, RParenLoc, CurFPFeatureOverrides()); @@ -7527,27 +7576,6 @@ bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) { ValidScalableConversion(destTy, srcTy); } -/// Are the two types RVV-bitcast-compatible types? I.e. is bitcasting from the -/// first RVV type (e.g. an RVV scalable type) to the second type (e.g. an RVV -/// VLS type) allowed? -/// -/// This will also return false if the two given types do not make sense from -/// the perspective of RVV bitcasts. -bool Sema::isValidRVVBitcast(QualType srcTy, QualType destTy) { - assert(srcTy->isVectorType() || destTy->isVectorType()); - - auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { - if (!FirstType->isRVVSizelessBuiltinType()) - return false; - - const auto *VecTy = SecondType->getAs(); - return VecTy && VecTy->getVectorKind() == VectorKind::RVVFixedLengthData; - }; - - return ValidScalableConversion(srcTy, destTy) || - ValidScalableConversion(destTy, srcTy); -} - /// Are the two types matrix types and do they have the same dimensions i.e. /// do they have the same number of rows and the same number of columns? bool Sema::areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy) { @@ -17227,8 +17255,7 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { TypeSourceInfo *Sema::TransformToPotentiallyEvaluated(TypeSourceInfo *TInfo) { assert(isUnevaluatedContext() && "Should only transform unevaluated expressions"); - ExprEvalContexts.back().Context = - ExprEvalContexts[ExprEvalContexts.size() - 2].Context; + ExprEvalContexts.back().Context = parentEvaluationContext().Context; if (isUnevaluatedContext()) return TInfo; return TransformToPE(*this).TransformType(TInfo); @@ -17245,14 +17272,13 @@ Sema::PushExpressionEvaluationContext( // discarded statements or immediate context are themselves // a discarded statement or an immediate context, respectively. ExprEvalContexts.back().InDiscardedStatement = - ExprEvalContexts[ExprEvalContexts.size() - 2] - .isDiscardedStatementContext(); + parentEvaluationContext().isDiscardedStatementContext(); // C++23 [expr.const]/p15 // An expression or conversion is in an immediate function context if [...] // it is a subexpression of a manifestly constant-evaluated expression or // conversion. - const auto &Prev = ExprEvalContexts[ExprEvalContexts.size() - 2]; + const auto &Prev = parentEvaluationContext(); ExprEvalContexts.back().InImmediateFunctionContext = Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated(); @@ -17697,7 +17723,7 @@ void Sema::PopExpressionEvaluationContext() { // Append the collected materialized temporaries into previous context before // exit if the previous also is a lifetime extending context. - auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2]; + auto &PrevRecord = parentEvaluationContext(); if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext && PrevRecord.InLifetimeExtendingContext && !Rec.ForRangeLifetimeExtendTemps.empty()) { @@ -18765,6 +18791,10 @@ bool Sema::tryCaptureVariable( DeclContext *VarDC = Var->getDeclContext(); DeclContext *DC = CurContext; + // Skip past RequiresExprBodys because they don't constitute function scopes. + while (DC->isRequiresExprBody()) + DC = DC->getParent(); + // tryCaptureVariable is called every time a DeclRef is formed, // it can therefore have non-negigible impact on performances. // For local variables and when there is no capturing scope, @@ -18772,6 +18802,12 @@ bool Sema::tryCaptureVariable( if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC)) return true; + // Exception: Function parameters are not tied to the function's DeclContext + // until we enter the function definition. Capturing them anyway would result + // in an out-of-bounds error while traversing DC and its parents. + if (isa(Var) && !VarDC->isFunctionOrMethod()) + return true; + const auto *VD = dyn_cast(Var); if (VD) { if (VD->isInitCapture()) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index f543e006060d6214dfc76f7da28df55511f1778f..4487c618862c5e9efe37385dbad71eaa028c6b5d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -42,6 +42,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaPPC.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" @@ -931,7 +932,7 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, // PPC MMA non-pointer types are not allowed as throw expr types. if (Ex && Context.getTargetInfo().getTriple().isPPC64()) - CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc()); + PPC().CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc()); return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); @@ -1444,10 +1445,10 @@ bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) { // category are defined within such member functions as they are within // an implicit object member function). DeclContext *DC = getFunctionLevelDeclContext(); - if (const auto *Method = dyn_cast(DC); - Method && Method->isExplicitObjectMemberFunction()) { + const auto *Method = dyn_cast(DC); + if (Method && Method->isExplicitObjectMemberFunction()) { Diag(Loc, diag::err_invalid_this_use) << 1; - } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) { + } else if (Method && isLambdaCallWithExplicitObjectParameter(CurContext)) { Diag(Loc, diag::err_invalid_this_use) << 1; } else { Diag(Loc, diag::err_invalid_this_use) << 0; @@ -1554,9 +1555,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, bool ListInitialization) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); - - assert((!ListInitialization || Exprs.size() == 1) && - "List initialization must have exactly one expression."); SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 9aa60204bf29decff73a69fb0f9a0d5a60efa865..3ae1af26d0096fd54b5714bf7dae1afedfaf6e49 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1194,7 +1194,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { if (!TemplateArgs) { - diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc); + diagnoseMissingTemplateArguments( + SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc); return ExprError(); } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 462ab2c952b67054a4d577be3536df32674084dc..9c423529c80e77d0dbd14e3882738243865fbb1d 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2134,7 +2134,7 @@ ExprResult SemaObjC::HandleExprPropertyRefExpr( } } else { SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::err_property_not_found_suggest) + PDiag(diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0)); return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, TypoResult, MemberLoc, @@ -2369,15 +2369,15 @@ SemaObjC::getObjCMessageKind(Scope *S, IdentifierInfo *Name, if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be // returned by CorrectTypo), this is a send to super. - SemaRef.diagnoseTypo( - Corrected, SemaRef.PDiag(diag::err_unknown_receiver_suggest) << Name); + SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_unknown_receiver_suggest) + << Name); return ObjCSuperMessage; } else if (ObjCInterfaceDecl *Class = Corrected.getCorrectionDeclAs()) { // If we found a declaration, correct when it refers to an Objective-C // class. - SemaRef.diagnoseTypo( - Corrected, SemaRef.PDiag(diag::err_unknown_receiver_suggest) << Name); + SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_unknown_receiver_suggest) + << Name); QualType T = Context.getObjCInterfaceType(Class); TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); ReceiverType = SemaRef.CreateParsedType(T, TSInfo); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 6a12c417e2f3a486685f551815f9e03a5cdcd62b..0a2face7afe65a7048d1509d573f11ca9acbdc01 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -9,13 +9,18 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaHLSL.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TargetParser/Triple.h" #include @@ -290,3 +295,523 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) << (AllowedStages.size() != 1) << join(StageStrings, ", "); } + +void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { + llvm::VersionTuple SMVersion = + getASTContext().getTargetInfo().getTriple().getOSVersion(); + uint32_t ZMax = 1024; + uint32_t ThreadMax = 1024; + if (SMVersion.getMajor() <= 4) { + ZMax = 1; + ThreadMax = 768; + } else if (SMVersion.getMajor() == 5) { + ZMax = 64; + ThreadMax = 1024; + } + + uint32_t X; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X)) + return; + if (X > 1024) { + Diag(AL.getArgAsExpr(0)->getExprLoc(), + diag::err_hlsl_numthreads_argument_oor) + << 0 << 1024; + return; + } + uint32_t Y; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y)) + return; + if (Y > 1024) { + Diag(AL.getArgAsExpr(1)->getExprLoc(), + diag::err_hlsl_numthreads_argument_oor) + << 1 << 1024; + return; + } + uint32_t Z; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z)) + return; + if (Z > ZMax) { + SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(), + diag::err_hlsl_numthreads_argument_oor) + << 2 << ZMax; + return; + } + + if (X * Y * Z > ThreadMax) { + Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax; + return; + } + + HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z); + if (NewAttr) + D->addAttr(NewAttr); +} + +static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { + if (!T->hasUnsignedIntegerRepresentation()) + return false; + if (const auto *VT = T->getAs()) + return VT->getNumElements() <= 3; + return true; +} + +void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { + // FIXME: support semantic on field. + // See https://github.com/llvm/llvm-project/issues/57889. + if (isa(D)) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) + << AL << "parameter"; + return; + } + + auto *VD = cast(D); + if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "uint/uint2/uint3"; + return; + } + + D->addAttr(::new (getASTContext()) + HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); +} + +void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { + if (!isa(D) || !isa(D->getDeclContext())) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) + << AL << "shader constant in a constant buffer"; + return; + } + + uint32_t SubComponent; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent)) + return; + uint32_t Component; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component)) + return; + + QualType T = cast(D)->getType().getCanonicalType(); + // Check if T is an array or struct type. + // TODO: mark matrix type as aggregate type. + bool IsAggregateTy = (T->isArrayType() || T->isStructureType()); + + // Check Component is valid for T. + if (Component) { + unsigned Size = getASTContext().getTypeSize(T); + if (IsAggregateTy || Size > 128) { + Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); + return; + } else { + // Make sure Component + sizeof(T) <= 4. + if ((Component * 32 + Size) > 128) { + Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); + return; + } + QualType EltTy = T; + if (const auto *VT = T->getAs()) + EltTy = VT->getElementType(); + unsigned Align = getASTContext().getTypeAlign(EltTy); + if (Align > 32 && Component == 1) { + // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary. + // So we only need to check Component 1 here. + Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch) + << Align << EltTy; + return; + } + } + } + + D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr( + getASTContext(), AL, SubComponent, Component)); +} + +void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation ArgLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + HLSLShaderAttr::ShaderType ShaderType; + if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Str << ArgLoc; + return; + } + + // FIXME: check function match the shader stage. + + HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType); + if (NewAttr) + D->addAttr(NewAttr); +} + +void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) { + StringRef Space = "space0"; + StringRef Slot = ""; + + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + StringRef Str = Loc->Ident->getName(); + SourceLocation ArgLoc = Loc->Loc; + + SourceLocation SpaceArgLoc; + if (AL.getNumArgs() == 2) { + Slot = Str; + if (!AL.isArgIdent(1)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(1); + Space = Loc->Ident->getName(); + SpaceArgLoc = Loc->Loc; + } else { + Slot = Str; + } + + // Validate. + if (!Slot.empty()) { + switch (Slot[0]) { + case 'u': + case 'b': + case 's': + case 't': + break; + default: + Diag(ArgLoc, diag::err_hlsl_unsupported_register_type) + << Slot.substr(0, 1); + return; + } + + StringRef SlotNum = Slot.substr(1); + unsigned Num = 0; + if (SlotNum.getAsInteger(10, Num)) { + Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); + return; + } + } + + if (!Space.starts_with("space")) { + Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + StringRef SpaceNum = Space.substr(5); + unsigned Num = 0; + if (SpaceNum.getAsInteger(10, Num)) { + Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + + // FIXME: check reg type match decl. Issue + // https://github.com/llvm/llvm-project/issues/57886. + HLSLResourceBindingAttr *NewAttr = + HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL); + if (NewAttr) + D->addAttr(NewAttr); +} + +void SemaHLSL::handleParamModifierAttr(Decl *D, const ParsedAttr &AL) { + HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr( + D, AL, + static_cast(AL.getSemanticSpelling())); + if (NewAttr) + D->addAttr(NewAttr); +} + +namespace { + +/// This class implements HLSL availability diagnostics for default +/// and relaxed mode +/// +/// The goal of this diagnostic is to emit an error or warning when an +/// unavailable API is found in code that is reachable from the shader +/// entry function or from an exported function (when compiling a shader +/// library). +/// +/// This is done by traversing the AST of all shader entry point functions +/// and of all exported functions, and any functions that are refrenced +/// from this AST. In other words, any functions that are reachable from +/// the entry points. +class DiagnoseHLSLAvailability + : public RecursiveASTVisitor { + + Sema &SemaRef; + + // Stack of functions to be scaned + llvm::SmallVector DeclsToScan; + + // Tracks which environments functions have been scanned in. + // + // Maps FunctionDecl to an unsigned number that represents the set of shader + // environments the function has been scanned for. + // Since HLSLShaderAttr::ShaderType enum is generated from Attr.td and is + // defined without any assigned values, it is guaranteed to be numbered + // sequentially from 0 up and we can use it to 'index' individual bits + // in the set. + // The N'th bit in the set will be set if the function has been scanned + // in shader environment whose ShaderType integer value equals N. + // For example, if a function has been scanned in compute and pixel stage + // environment, the value will be 0x21 (100001 binary) because + // (int)HLSLShaderAttr::ShaderType::Pixel == 1 and + // (int)HLSLShaderAttr::ShaderType::Compute == 5. + // A FunctionDecl is mapped to 0 (or not included in the map) if it has not + // been scanned in any environment. + llvm::DenseMap ScannedDecls; + + // Do not access these directly, use the get/set methods below to make + // sure the values are in sync + llvm::Triple::EnvironmentType CurrentShaderEnvironment; + unsigned CurrentShaderStageBit; + + // True if scanning a function that was already scanned in a different + // shader stage context, and therefore we should not report issues that + // depend only on shader model version because they would be duplicate. + bool ReportOnlyShaderStageIssues; + + // Helper methods for dealing with current stage context / environment + void SetShaderStageContext(HLSLShaderAttr::ShaderType ShaderType) { + static_assert(sizeof(unsigned) >= 4); + assert((unsigned)ShaderType < 31); // 31 is reserved for "unknown" + + CurrentShaderEnvironment = HLSLShaderAttr::getTypeAsEnvironment(ShaderType); + CurrentShaderStageBit = (1 << ShaderType); + } + + void SetUnknownShaderStageContext() { + CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment; + CurrentShaderStageBit = (1 << 31); + } + + llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const { + return CurrentShaderEnvironment; + } + + bool InUnknownShaderStageContext() const { + return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment; + } + + // Helper methods for dealing with shader stage bitmap + void AddToScannedFunctions(const FunctionDecl *FD) { + unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD); + ScannedStages |= CurrentShaderStageBit; + } + + unsigned GetScannedStages(const FunctionDecl *FD) { + return ScannedDecls.getOrInsertDefault(FD); + } + + bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) { + return WasAlreadyScannedInCurrentStage(GetScannedStages(FD)); + } + + bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) { + return ScannerStages & CurrentShaderStageBit; + } + + static bool NeverBeenScanned(unsigned ScannedStages) { + return ScannedStages == 0; + } + + // Scanning methods + void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr); + void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA, + SourceRange Range); + const AvailabilityAttr *FindAvailabilityAttr(const Decl *D); + bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA); + +public: + DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {} + + // AST traversal methods + void RunOnTranslationUnit(const TranslationUnitDecl *TU); + void RunOnFunction(const FunctionDecl *FD); + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + FunctionDecl *FD = llvm::dyn_cast(DRE->getDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, DRE); + return true; + } + + bool VisitMemberExpr(MemberExpr *ME) { + FunctionDecl *FD = llvm::dyn_cast(ME->getMemberDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, ME); + return true; + } +}; + +void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD, + Expr *RefExpr) { + assert((isa(RefExpr) || isa(RefExpr)) && + "expected DeclRefExpr or MemberExpr"); + + // has a definition -> add to stack to be scanned + const FunctionDecl *FDWithBody = nullptr; + if (FD->hasBody(FDWithBody)) { + if (!WasAlreadyScannedInCurrentStage(FDWithBody)) + DeclsToScan.push_back(FDWithBody); + return; + } + + // no body -> diagnose availability + const AvailabilityAttr *AA = FindAvailabilityAttr(FD); + if (AA) + CheckDeclAvailability( + FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc())); +} + +void DiagnoseHLSLAvailability::RunOnTranslationUnit( + const TranslationUnitDecl *TU) { + // Iterate over all shader entry functions and library exports, and for those + // that have a body (definiton), run diag scan on each, setting appropriate + // shader environment context based on whether it is a shader entry function + // or an exported function. + for (auto &D : TU->decls()) { + const FunctionDecl *FD = llvm::dyn_cast(D); + if (!FD || !FD->isThisDeclarationADefinition()) + continue; + + // shader entry point + auto ShaderAttr = FD->getAttr(); + if (ShaderAttr) { + SetShaderStageContext(ShaderAttr->getType()); + RunOnFunction(FD); + continue; + } + // exported library function with definition + // FIXME: tracking issue #92073 +#if 0 + if (FD->getFormalLinkage() == Linkage::External) { + SetUnknownShaderStageContext(); + RunOnFunction(FD); + } +#endif + } +} + +void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) { + assert(DeclsToScan.empty() && "DeclsToScan should be empty"); + DeclsToScan.push_back(FD); + + while (!DeclsToScan.empty()) { + // Take one decl from the stack and check it by traversing its AST. + // For any CallExpr found during the traversal add it's callee to the top of + // the stack to be processed next. Functions already processed are stored in + // ScannedDecls. + const FunctionDecl *FD = DeclsToScan.back(); + DeclsToScan.pop_back(); + + // Decl was already scanned + const unsigned ScannedStages = GetScannedStages(FD); + if (WasAlreadyScannedInCurrentStage(ScannedStages)) + continue; + + ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages); + + AddToScannedFunctions(FD); + TraverseStmt(FD->getBody()); + } +} + +bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone( + const AvailabilityAttr *AA) { + IdentifierInfo *IIEnvironment = AA->getEnvironment(); + if (!IIEnvironment) + return true; + + llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment(); + if (CurrentEnv == llvm::Triple::UnknownEnvironment) + return false; + + llvm::Triple::EnvironmentType AttrEnv = + AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); + + return CurrentEnv == AttrEnv; +} + +const AvailabilityAttr * +DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) { + AvailabilityAttr const *PartialMatch = nullptr; + // Check each AvailabilityAttr to find the one for this platform. + // For multiple attributes with the same platform try to find one for this + // environment. + for (const auto *A : D->attrs()) { + if (const auto *Avail = dyn_cast(A)) { + StringRef AttrPlatform = Avail->getPlatform()->getName(); + StringRef TargetPlatform = + SemaRef.getASTContext().getTargetInfo().getPlatformName(); + + // Match the platform name. + if (AttrPlatform == TargetPlatform) { + // Find the best matching attribute for this environment + if (HasMatchingEnvironmentOrNone(Avail)) + return Avail; + PartialMatch = Avail; + } + } + } + return PartialMatch; +} + +// Check availability against target shader model version and current shader +// stage and emit diagnostic +void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D, + const AvailabilityAttr *AA, + SourceRange Range) { + if (ReportOnlyShaderStageIssues && !AA->getEnvironment()) + return; + + bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA); + VersionTuple Introduced = AA->getIntroduced(); + VersionTuple TargetVersion = + SemaRef.Context.getTargetInfo().getPlatformMinVersion(); + + if (TargetVersion >= Introduced && EnvironmentMatches) + return; + + // Do not diagnose shade-stage-specific availability when the shader stage + // context is unknown + if (InUnknownShaderStageContext() && AA->getEnvironment() != nullptr) + return; + + // Emit diagnostic message + const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); + llvm::StringRef PlatformName( + AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); + + llvm::StringRef CurrentEnvStr = + AvailabilityAttr::getPrettyEnviromentName(GetCurrentShaderEnvironment()); + + llvm::StringRef AttrEnvStr = AA->getEnvironment() + ? AvailabilityAttr::getPrettyEnviromentName( + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) + : ""; + bool UseEnvironment = !AttrEnvStr.empty(); + + if (EnvironmentMatches) { + SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability) + << Range << D << PlatformName << Introduced.getAsString() + << UseEnvironment << CurrentEnvStr; + } else { + SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable) + << Range << D; + } + + SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here) + << D << PlatformName << Introduced.getAsString() + << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() + << UseEnvironment << AttrEnvStr << CurrentEnvStr; +} + +} // namespace + +void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) { + DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU); +} diff --git a/clang/lib/Sema/SemaHexagon.cpp b/clang/lib/Sema/SemaHexagon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c921c0bc9e33f299f5ad4a3003e30966cda91ae --- /dev/null +++ b/clang/lib/Sema/SemaHexagon.cpp @@ -0,0 +1,290 @@ +//===------ SemaHexagon.cpp ------ Hexagon target-specific routines -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to Hexagon. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaHexagon.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/STLExtras.h" +#include +#include + +namespace clang { + +SemaHexagon::SemaHexagon(Sema &S) : SemaBase(S) {} + +bool SemaHexagon::CheckHexagonBuiltinArgument(unsigned BuiltinID, + CallExpr *TheCall) { + struct ArgInfo { + uint8_t OpNum; + bool IsSigned; + uint8_t BitWidth; + uint8_t Align; + }; + struct BuiltinInfo { + unsigned BuiltinID; + ArgInfo Infos[2]; + }; + + static BuiltinInfo Infos[] = { + { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, + + { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, + {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, + {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, + { 3, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, + {{ 3, false, 1, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B, + {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B, + {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, + {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, + {{ 3, false, 3, 0 }} }, + }; + + // Use a dynamically initialized static to sort the table exactly once on + // first run. + static const bool SortOnce = + (llvm::sort(Infos, + [](const BuiltinInfo &LHS, const BuiltinInfo &RHS) { + return LHS.BuiltinID < RHS.BuiltinID; + }), + true); + (void)SortOnce; + + const BuiltinInfo *F = llvm::partition_point( + Infos, [=](const BuiltinInfo &BI) { return BI.BuiltinID < BuiltinID; }); + if (F == std::end(Infos) || F->BuiltinID != BuiltinID) + return false; + + bool Error = false; + + for (const ArgInfo &A : F->Infos) { + // Ignore empty ArgInfo elements. + if (A.BitWidth == 0) + continue; + + int32_t Min = A.IsSigned ? -(1 << (A.BitWidth - 1)) : 0; + int32_t Max = (1 << (A.IsSigned ? A.BitWidth - 1 : A.BitWidth)) - 1; + if (!A.Align) { + Error |= SemaRef.BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + } else { + unsigned M = 1 << A.Align; + Min *= M; + Max *= M; + Error |= SemaRef.BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= SemaRef.BuiltinConstantArgMultiple(TheCall, A.OpNum, M); + } + } + return Error; +} + +bool SemaHexagon::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + return CheckHexagonBuiltinArgument(BuiltinID, TheCall); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 353e911c5cc337f3a0215d8d52f8db233b44e30d..9ed3e8a0df025227bbac7f817c101a9bff7d09af 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -814,19 +814,13 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (const RecordType *RType = ILE->getType()->getAs()) { const RecordDecl *RDecl = RType->getDecl(); - if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) - FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), - Entity, ILE, RequiresSecondPass, FillWithNoInit); - else if (RDecl->isUnion() && isa(RDecl) && - cast(RDecl)->hasInClassInitializer()) { - for (auto *Field : RDecl->fields()) { - if (Field->hasInClassInitializer()) { - FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass, - FillWithNoInit); - break; - } - } + if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) { + FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, + RequiresSecondPass, FillWithNoInit); } else { + assert((!RDecl->isUnion() || !isa(RDecl) || + !cast(RDecl)->hasInClassInitializer()) && + "We should have computed initialized fields already"); // The fields beyond ILE->getNumInits() are default initialized, so in // order to leave them uninitialized, the ILE is expanded and the extra // fields are then filled with NoInitExpr. @@ -2164,12 +2158,15 @@ void InitListChecker::CheckStructUnionTypes( return; for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { - if (Field->hasInClassInitializer()) { + if (Field->hasInClassInitializer() || + (Field->isAnonymousStructOrUnion() && + Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) { StructuredList->setInitializedFieldInUnion(*Field); // FIXME: Actually build a CXXDefaultInitExpr? return; } } + llvm_unreachable("Couldn't find in-class initializer"); } // Value-initialize the first member of the union that isn't an unnamed @@ -8066,11 +8063,6 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, enum PathLifetimeKind { /// Lifetime-extend along this path. Extend, - /// We should lifetime-extend, but we don't because (due to technical - /// limitations) we can't. This happens for default member initializers, - /// which we don't clone for every use, so we don't have a unique - /// MaterializeTemporaryExpr to update. - ShouldExtend, /// Do not lifetime extend along this path. NoExtend }; @@ -8082,7 +8074,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { PathLifetimeKind Kind = PathLifetimeKind::Extend; for (auto Elem : Path) { if (Elem.Kind == IndirectLocalPathEntry::DefaultInit) - Kind = PathLifetimeKind::ShouldExtend; + Kind = PathLifetimeKind::Extend; else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) return PathLifetimeKind::NoExtend; } @@ -8202,18 +8194,6 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, ExtendingEntity->allocateManglingNumber()); // Also visit the temporaries lifetime-extended by this initializer. return true; - - case PathLifetimeKind::ShouldExtend: - // We're supposed to lifetime-extend the temporary along this path (per - // the resolution of DR1815), but we don't support that yet. - // - // FIXME: Properly handle this situation. Perhaps the easiest approach - // would be to clone the initializer expression on each use that would - // lifetime extend its temporaries. - Diag(DiagLoc, diag::warn_unsupported_lifetime_extension) - << RK << DiagRange; - break; - case PathLifetimeKind::NoExtend: // If the path goes through the initialization of a variable or field, // it can't possibly reach a temporary created in this full-expression. diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 1743afaf15287fe51c24ec6be7df2cb83300c612..e9476a0c93c5d41885850cd6b806bdaba974cfe9 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -12,6 +12,7 @@ #include "clang/Sema/SemaLambda.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" @@ -386,30 +387,69 @@ buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class, // parameter, if any, of the lambda's function call operator (possibly // instantiated from a function call operator template) shall be either: // - the closure type, -// - class type derived from the closure type, or +// - class type publicly and unambiguously derived from the closure type, or // - a reference to a possibly cv-qualified such type. -void Sema::DiagnoseInvalidExplicitObjectParameterInLambda( - CXXMethodDecl *Method) { +bool Sema::DiagnoseInvalidExplicitObjectParameterInLambda( + CXXMethodDecl *Method, SourceLocation CallLoc) { if (!isLambdaCallWithExplicitObjectParameter(Method)) - return; + return false; CXXRecordDecl *RD = Method->getParent(); if (Method->getType()->isDependentType()) - return; + return false; if (RD->isCapturelessLambda()) - return; - QualType ExplicitObjectParameterType = Method->getParamDecl(0) - ->getType() + return false; + + ParmVarDecl *Param = Method->getParamDecl(0); + QualType ExplicitObjectParameterType = Param->getType() .getNonReferenceType() .getUnqualifiedType() .getDesugaredType(getASTContext()); QualType LambdaType = getASTContext().getRecordType(RD); if (LambdaType == ExplicitObjectParameterType) - return; - if (IsDerivedFrom(RD->getLocation(), ExplicitObjectParameterType, LambdaType)) - return; - Diag(Method->getParamDecl(0)->getLocation(), - diag::err_invalid_explicit_object_type_in_lambda) - << ExplicitObjectParameterType; + return false; + + // Don't check the same instantiation twice. + // + // If this call operator is ill-formed, there is no point in issuing + // a diagnostic every time it is called because the problem is in the + // definition of the derived type, not at the call site. + // + // FIXME: Move this check to where we instantiate the method? This should + // be possible, but the naive approach of just marking the method as invalid + // leads to us emitting more diagnostics than we should have to for this case + // (1 error here *and* 1 error about there being no matching overload at the + // call site). It might be possible to avoid that by also checking if there + // is an empty cast path for the method stored in the context (signalling that + // we've already diagnosed it) and then just not building the call, but that + // doesn't really seem any simpler than diagnosing it at the call site... + if (auto It = Context.LambdaCastPaths.find(Method); + It != Context.LambdaCastPaths.end()) + return It->second.empty(); + + CXXCastPath &Path = Context.LambdaCastPaths[Method]; + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (!IsDerivedFrom(RD->getLocation(), ExplicitObjectParameterType, LambdaType, + Paths)) { + Diag(Param->getLocation(), diag::err_invalid_explicit_object_type_in_lambda) + << ExplicitObjectParameterType; + return true; + } + + if (Paths.isAmbiguous(LambdaType->getCanonicalTypeUnqualified())) { + std::string PathsDisplay = getAmbiguousPathsDisplayString(Paths); + Diag(CallLoc, diag::err_explicit_object_lambda_ambiguous_base) + << LambdaType << PathsDisplay; + return true; + } + + if (CheckBaseClassAccess(CallLoc, LambdaType, ExplicitObjectParameterType, + Paths.front(), + diag::err_explicit_object_lambda_inaccessible_base)) + return true; + + BuildBasePathArray(Paths, Path); + return false; } void Sema::handleLambdaNumbering( @@ -1036,16 +1076,27 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, // be dependent, because there are template parameters in scope. CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind = CXXRecordDecl::LDK_Unknown; - if (LSI->NumExplicitTemplateParams > 0) { - Scope *TemplateParamScope = CurScope->getTemplateParamParent(); - assert(TemplateParamScope && - "Lambda with explicit template param list should establish a " - "template param scope"); - assert(TemplateParamScope->getParent()); - if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr) - LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; - } else if (CurScope->getTemplateParamParent() != nullptr) { + if (CurScope->getTemplateParamParent() != nullptr) { LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; + } else if (Scope *P = CurScope->getParent()) { + // Given a lambda defined inside a requires expression, + // + // struct S { + // S(auto var) requires requires { [&] -> decltype(var) { }; } + // {} + // }; + // + // The parameter var is not injected into the function Decl at the point of + // parsing lambda. In such scenarios, perceiving it as dependent could + // result in the constraint being evaluated, which matches what GCC does. + while (P->getEntity() && P->getEntity()->isRequiresExprBody()) + P = P->getParent(); + if (P->isFunctionDeclarationScope() && + llvm::any_of(P->decls(), [](Decl *D) { + return isa(D) && + cast(D)->getType()->isTemplateTypeParmType(); + })) + LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; } CXXRecordDecl *Class = createLambdaClosureType( diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e4d4cd7395ebf3ce02374c246865f822576f0bcf..be6ea20a956a393428d46e13be77bd46af6ca37e 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -34,6 +34,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaRISCV.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" @@ -945,13 +946,13 @@ bool Sema::LookupBuiltin(LookupResult &R) { } } - if (DeclareRISCVVBuiltins || DeclareRISCVSiFiveVectorBuiltins) { - if (!RVIntrinsicManager) - RVIntrinsicManager = CreateRISCVIntrinsicManager(*this); + if (RISCV().DeclareRVVBuiltins || RISCV().DeclareSiFiveVectorBuiltins) { + if (!RISCV().IntrinsicManager) + RISCV().IntrinsicManager = CreateRISCVIntrinsicManager(*this); - RVIntrinsicManager->InitIntrinsicList(); + RISCV().IntrinsicManager->InitIntrinsicList(); - if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP)) + if (RISCV().IntrinsicManager->CreateIntrinsicIfFound(R, II, PP)) return true; } @@ -5896,6 +5897,16 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, NamedDecl *ChosenDecl = Correction.isKeyword() ? nullptr : Correction.getFoundDecl(); + + // For builtin functions which aren't declared anywhere in source, + // don't emit the "declared here" note. + if (const auto *FD = dyn_cast_if_present(ChosenDecl); + FD && FD->getBuiltinID() && + PrevNote.getDiagID() == diag::note_previous_decl && + Correction.getCorrectionRange().getBegin() == FD->getBeginLoc()) { + ChosenDecl = nullptr; + } + if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); diff --git a/clang/lib/Sema/SemaLoongArch.cpp b/clang/lib/Sema/SemaLoongArch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a67bf2c7738601b55bde5e5d31643fc9dcacfe1 --- /dev/null +++ b/clang/lib/Sema/SemaLoongArch.cpp @@ -0,0 +1,515 @@ +//===------ SemaLoongArch.cpp ---- LoongArch target-specific routines -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to LoongArch. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaLoongArch.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" +#include "llvm/Support/MathExtras.h" + +namespace clang { + +SemaLoongArch::SemaLoongArch(Sema &S) : SemaBase(S) {} + +bool SemaLoongArch::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + default: + break; + // Basic intrinsics. + case LoongArch::BI__builtin_loongarch_cacop_d: + case LoongArch::BI__builtin_loongarch_cacop_w: { + SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); + SemaRef.BuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), + llvm::maxIntN(12)); + break; + } + case LoongArch::BI__builtin_loongarch_break: + case LoongArch::BI__builtin_loongarch_dbar: + case LoongArch::BI__builtin_loongarch_ibar: + case LoongArch::BI__builtin_loongarch_syscall: + // Check if immediate is in [0, 32767]. + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 32767); + case LoongArch::BI__builtin_loongarch_csrrd_w: + case LoongArch::BI__builtin_loongarch_csrrd_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrwr_w: + case LoongArch::BI__builtin_loongarch_csrwr_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrxchg_w: + case LoongArch::BI__builtin_loongarch_csrxchg_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 16383); + case LoongArch::BI__builtin_loongarch_lddir_d: + case LoongArch::BI__builtin_loongarch_ldpte_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case LoongArch::BI__builtin_loongarch_movfcsr2gr: + case LoongArch::BI__builtin_loongarch_movgr2fcsr: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); + + // LSX intrinsics. + case LoongArch::BI__builtin_lsx_vbitclri_b: + case LoongArch::BI__builtin_lsx_vbitrevi_b: + case LoongArch::BI__builtin_lsx_vbitseti_b: + case LoongArch::BI__builtin_lsx_vsat_b: + case LoongArch::BI__builtin_lsx_vsat_bu: + case LoongArch::BI__builtin_lsx_vslli_b: + case LoongArch::BI__builtin_lsx_vsrai_b: + case LoongArch::BI__builtin_lsx_vsrari_b: + case LoongArch::BI__builtin_lsx_vsrli_b: + case LoongArch::BI__builtin_lsx_vsllwil_h_b: + case LoongArch::BI__builtin_lsx_vsllwil_hu_bu: + case LoongArch::BI__builtin_lsx_vrotri_b: + case LoongArch::BI__builtin_lsx_vsrlri_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 7); + case LoongArch::BI__builtin_lsx_vbitclri_h: + case LoongArch::BI__builtin_lsx_vbitrevi_h: + case LoongArch::BI__builtin_lsx_vbitseti_h: + case LoongArch::BI__builtin_lsx_vsat_h: + case LoongArch::BI__builtin_lsx_vsat_hu: + case LoongArch::BI__builtin_lsx_vslli_h: + case LoongArch::BI__builtin_lsx_vsrai_h: + case LoongArch::BI__builtin_lsx_vsrari_h: + case LoongArch::BI__builtin_lsx_vsrli_h: + case LoongArch::BI__builtin_lsx_vsllwil_w_h: + case LoongArch::BI__builtin_lsx_vsllwil_wu_hu: + case LoongArch::BI__builtin_lsx_vrotri_h: + case LoongArch::BI__builtin_lsx_vsrlri_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case LoongArch::BI__builtin_lsx_vssrarni_b_h: + case LoongArch::BI__builtin_lsx_vssrarni_bu_h: + case LoongArch::BI__builtin_lsx_vssrani_b_h: + case LoongArch::BI__builtin_lsx_vssrani_bu_h: + case LoongArch::BI__builtin_lsx_vsrarni_b_h: + case LoongArch::BI__builtin_lsx_vsrlni_b_h: + case LoongArch::BI__builtin_lsx_vsrlrni_b_h: + case LoongArch::BI__builtin_lsx_vssrlni_b_h: + case LoongArch::BI__builtin_lsx_vssrlni_bu_h: + case LoongArch::BI__builtin_lsx_vssrlrni_b_h: + case LoongArch::BI__builtin_lsx_vssrlrni_bu_h: + case LoongArch::BI__builtin_lsx_vsrani_b_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15); + case LoongArch::BI__builtin_lsx_vslei_bu: + case LoongArch::BI__builtin_lsx_vslei_hu: + case LoongArch::BI__builtin_lsx_vslei_wu: + case LoongArch::BI__builtin_lsx_vslei_du: + case LoongArch::BI__builtin_lsx_vslti_bu: + case LoongArch::BI__builtin_lsx_vslti_hu: + case LoongArch::BI__builtin_lsx_vslti_wu: + case LoongArch::BI__builtin_lsx_vslti_du: + case LoongArch::BI__builtin_lsx_vmaxi_bu: + case LoongArch::BI__builtin_lsx_vmaxi_hu: + case LoongArch::BI__builtin_lsx_vmaxi_wu: + case LoongArch::BI__builtin_lsx_vmaxi_du: + case LoongArch::BI__builtin_lsx_vmini_bu: + case LoongArch::BI__builtin_lsx_vmini_hu: + case LoongArch::BI__builtin_lsx_vmini_wu: + case LoongArch::BI__builtin_lsx_vmini_du: + case LoongArch::BI__builtin_lsx_vaddi_bu: + case LoongArch::BI__builtin_lsx_vaddi_hu: + case LoongArch::BI__builtin_lsx_vaddi_wu: + case LoongArch::BI__builtin_lsx_vaddi_du: + case LoongArch::BI__builtin_lsx_vbitclri_w: + case LoongArch::BI__builtin_lsx_vbitrevi_w: + case LoongArch::BI__builtin_lsx_vbitseti_w: + case LoongArch::BI__builtin_lsx_vsat_w: + case LoongArch::BI__builtin_lsx_vsat_wu: + case LoongArch::BI__builtin_lsx_vslli_w: + case LoongArch::BI__builtin_lsx_vsrai_w: + case LoongArch::BI__builtin_lsx_vsrari_w: + case LoongArch::BI__builtin_lsx_vsrli_w: + case LoongArch::BI__builtin_lsx_vsllwil_d_w: + case LoongArch::BI__builtin_lsx_vsllwil_du_wu: + case LoongArch::BI__builtin_lsx_vsrlri_w: + case LoongArch::BI__builtin_lsx_vrotri_w: + case LoongArch::BI__builtin_lsx_vsubi_bu: + case LoongArch::BI__builtin_lsx_vsubi_hu: + case LoongArch::BI__builtin_lsx_vbsrl_v: + case LoongArch::BI__builtin_lsx_vbsll_v: + case LoongArch::BI__builtin_lsx_vsubi_wu: + case LoongArch::BI__builtin_lsx_vsubi_du: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case LoongArch::BI__builtin_lsx_vssrarni_h_w: + case LoongArch::BI__builtin_lsx_vssrarni_hu_w: + case LoongArch::BI__builtin_lsx_vssrani_h_w: + case LoongArch::BI__builtin_lsx_vssrani_hu_w: + case LoongArch::BI__builtin_lsx_vsrarni_h_w: + case LoongArch::BI__builtin_lsx_vsrani_h_w: + case LoongArch::BI__builtin_lsx_vfrstpi_b: + case LoongArch::BI__builtin_lsx_vfrstpi_h: + case LoongArch::BI__builtin_lsx_vsrlni_h_w: + case LoongArch::BI__builtin_lsx_vsrlrni_h_w: + case LoongArch::BI__builtin_lsx_vssrlni_h_w: + case LoongArch::BI__builtin_lsx_vssrlni_hu_w: + case LoongArch::BI__builtin_lsx_vssrlrni_h_w: + case LoongArch::BI__builtin_lsx_vssrlrni_hu_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31); + case LoongArch::BI__builtin_lsx_vbitclri_d: + case LoongArch::BI__builtin_lsx_vbitrevi_d: + case LoongArch::BI__builtin_lsx_vbitseti_d: + case LoongArch::BI__builtin_lsx_vsat_d: + case LoongArch::BI__builtin_lsx_vsat_du: + case LoongArch::BI__builtin_lsx_vslli_d: + case LoongArch::BI__builtin_lsx_vsrai_d: + case LoongArch::BI__builtin_lsx_vsrli_d: + case LoongArch::BI__builtin_lsx_vsrari_d: + case LoongArch::BI__builtin_lsx_vrotri_d: + case LoongArch::BI__builtin_lsx_vsrlri_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 63); + case LoongArch::BI__builtin_lsx_vssrarni_w_d: + case LoongArch::BI__builtin_lsx_vssrarni_wu_d: + case LoongArch::BI__builtin_lsx_vssrani_w_d: + case LoongArch::BI__builtin_lsx_vssrani_wu_d: + case LoongArch::BI__builtin_lsx_vsrarni_w_d: + case LoongArch::BI__builtin_lsx_vsrlni_w_d: + case LoongArch::BI__builtin_lsx_vsrlrni_w_d: + case LoongArch::BI__builtin_lsx_vssrlni_w_d: + case LoongArch::BI__builtin_lsx_vssrlni_wu_d: + case LoongArch::BI__builtin_lsx_vssrlrni_w_d: + case LoongArch::BI__builtin_lsx_vssrlrni_wu_d: + case LoongArch::BI__builtin_lsx_vsrani_w_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 63); + case LoongArch::BI__builtin_lsx_vssrarni_d_q: + case LoongArch::BI__builtin_lsx_vssrarni_du_q: + case LoongArch::BI__builtin_lsx_vssrani_d_q: + case LoongArch::BI__builtin_lsx_vssrani_du_q: + case LoongArch::BI__builtin_lsx_vsrarni_d_q: + case LoongArch::BI__builtin_lsx_vssrlni_d_q: + case LoongArch::BI__builtin_lsx_vssrlni_du_q: + case LoongArch::BI__builtin_lsx_vssrlrni_d_q: + case LoongArch::BI__builtin_lsx_vssrlrni_du_q: + case LoongArch::BI__builtin_lsx_vsrani_d_q: + case LoongArch::BI__builtin_lsx_vsrlrni_d_q: + case LoongArch::BI__builtin_lsx_vsrlni_d_q: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 127); + case LoongArch::BI__builtin_lsx_vseqi_b: + case LoongArch::BI__builtin_lsx_vseqi_h: + case LoongArch::BI__builtin_lsx_vseqi_w: + case LoongArch::BI__builtin_lsx_vseqi_d: + case LoongArch::BI__builtin_lsx_vslti_b: + case LoongArch::BI__builtin_lsx_vslti_h: + case LoongArch::BI__builtin_lsx_vslti_w: + case LoongArch::BI__builtin_lsx_vslti_d: + case LoongArch::BI__builtin_lsx_vslei_b: + case LoongArch::BI__builtin_lsx_vslei_h: + case LoongArch::BI__builtin_lsx_vslei_w: + case LoongArch::BI__builtin_lsx_vslei_d: + case LoongArch::BI__builtin_lsx_vmaxi_b: + case LoongArch::BI__builtin_lsx_vmaxi_h: + case LoongArch::BI__builtin_lsx_vmaxi_w: + case LoongArch::BI__builtin_lsx_vmaxi_d: + case LoongArch::BI__builtin_lsx_vmini_b: + case LoongArch::BI__builtin_lsx_vmini_h: + case LoongArch::BI__builtin_lsx_vmini_w: + case LoongArch::BI__builtin_lsx_vmini_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -16, 15); + case LoongArch::BI__builtin_lsx_vandi_b: + case LoongArch::BI__builtin_lsx_vnori_b: + case LoongArch::BI__builtin_lsx_vori_b: + case LoongArch::BI__builtin_lsx_vshuf4i_b: + case LoongArch::BI__builtin_lsx_vshuf4i_h: + case LoongArch::BI__builtin_lsx_vshuf4i_w: + case LoongArch::BI__builtin_lsx_vxori_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 255); + case LoongArch::BI__builtin_lsx_vbitseli_b: + case LoongArch::BI__builtin_lsx_vshuf4i_d: + case LoongArch::BI__builtin_lsx_vextrins_b: + case LoongArch::BI__builtin_lsx_vextrins_h: + case LoongArch::BI__builtin_lsx_vextrins_w: + case LoongArch::BI__builtin_lsx_vextrins_d: + case LoongArch::BI__builtin_lsx_vpermi_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 255); + case LoongArch::BI__builtin_lsx_vpickve2gr_b: + case LoongArch::BI__builtin_lsx_vpickve2gr_bu: + case LoongArch::BI__builtin_lsx_vreplvei_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case LoongArch::BI__builtin_lsx_vinsgr2vr_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15); + case LoongArch::BI__builtin_lsx_vpickve2gr_h: + case LoongArch::BI__builtin_lsx_vpickve2gr_hu: + case LoongArch::BI__builtin_lsx_vreplvei_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 7); + case LoongArch::BI__builtin_lsx_vinsgr2vr_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); + case LoongArch::BI__builtin_lsx_vpickve2gr_w: + case LoongArch::BI__builtin_lsx_vpickve2gr_wu: + case LoongArch::BI__builtin_lsx_vreplvei_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3); + case LoongArch::BI__builtin_lsx_vinsgr2vr_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3); + case LoongArch::BI__builtin_lsx_vpickve2gr_d: + case LoongArch::BI__builtin_lsx_vpickve2gr_du: + case LoongArch::BI__builtin_lsx_vreplvei_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); + case LoongArch::BI__builtin_lsx_vinsgr2vr_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1); + case LoongArch::BI__builtin_lsx_vstelm_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -128, 127) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 15); + case LoongArch::BI__builtin_lsx_vstelm_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -256, 254) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 7); + case LoongArch::BI__builtin_lsx_vstelm_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -512, 508) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 3); + case LoongArch::BI__builtin_lsx_vstelm_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1); + case LoongArch::BI__builtin_lsx_vldrepl_b: + case LoongArch::BI__builtin_lsx_vld: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2047); + case LoongArch::BI__builtin_lsx_vldrepl_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2046); + case LoongArch::BI__builtin_lsx_vldrepl_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2044); + case LoongArch::BI__builtin_lsx_vldrepl_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2040); + case LoongArch::BI__builtin_lsx_vst: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -2048, 2047); + case LoongArch::BI__builtin_lsx_vldi: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, -4096, 4095); + case LoongArch::BI__builtin_lsx_vrepli_b: + case LoongArch::BI__builtin_lsx_vrepli_h: + case LoongArch::BI__builtin_lsx_vrepli_w: + case LoongArch::BI__builtin_lsx_vrepli_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, -512, 511); + + // LASX intrinsics. + case LoongArch::BI__builtin_lasx_xvbitclri_b: + case LoongArch::BI__builtin_lasx_xvbitrevi_b: + case LoongArch::BI__builtin_lasx_xvbitseti_b: + case LoongArch::BI__builtin_lasx_xvsat_b: + case LoongArch::BI__builtin_lasx_xvsat_bu: + case LoongArch::BI__builtin_lasx_xvslli_b: + case LoongArch::BI__builtin_lasx_xvsrai_b: + case LoongArch::BI__builtin_lasx_xvsrari_b: + case LoongArch::BI__builtin_lasx_xvsrli_b: + case LoongArch::BI__builtin_lasx_xvsllwil_h_b: + case LoongArch::BI__builtin_lasx_xvsllwil_hu_bu: + case LoongArch::BI__builtin_lasx_xvrotri_b: + case LoongArch::BI__builtin_lasx_xvsrlri_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 7); + case LoongArch::BI__builtin_lasx_xvbitclri_h: + case LoongArch::BI__builtin_lasx_xvbitrevi_h: + case LoongArch::BI__builtin_lasx_xvbitseti_h: + case LoongArch::BI__builtin_lasx_xvsat_h: + case LoongArch::BI__builtin_lasx_xvsat_hu: + case LoongArch::BI__builtin_lasx_xvslli_h: + case LoongArch::BI__builtin_lasx_xvsrai_h: + case LoongArch::BI__builtin_lasx_xvsrari_h: + case LoongArch::BI__builtin_lasx_xvsrli_h: + case LoongArch::BI__builtin_lasx_xvsllwil_w_h: + case LoongArch::BI__builtin_lasx_xvsllwil_wu_hu: + case LoongArch::BI__builtin_lasx_xvrotri_h: + case LoongArch::BI__builtin_lasx_xvsrlri_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case LoongArch::BI__builtin_lasx_xvssrarni_b_h: + case LoongArch::BI__builtin_lasx_xvssrarni_bu_h: + case LoongArch::BI__builtin_lasx_xvssrani_b_h: + case LoongArch::BI__builtin_lasx_xvssrani_bu_h: + case LoongArch::BI__builtin_lasx_xvsrarni_b_h: + case LoongArch::BI__builtin_lasx_xvsrlni_b_h: + case LoongArch::BI__builtin_lasx_xvsrlrni_b_h: + case LoongArch::BI__builtin_lasx_xvssrlni_b_h: + case LoongArch::BI__builtin_lasx_xvssrlni_bu_h: + case LoongArch::BI__builtin_lasx_xvssrlrni_b_h: + case LoongArch::BI__builtin_lasx_xvssrlrni_bu_h: + case LoongArch::BI__builtin_lasx_xvsrani_b_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15); + case LoongArch::BI__builtin_lasx_xvslei_bu: + case LoongArch::BI__builtin_lasx_xvslei_hu: + case LoongArch::BI__builtin_lasx_xvslei_wu: + case LoongArch::BI__builtin_lasx_xvslei_du: + case LoongArch::BI__builtin_lasx_xvslti_bu: + case LoongArch::BI__builtin_lasx_xvslti_hu: + case LoongArch::BI__builtin_lasx_xvslti_wu: + case LoongArch::BI__builtin_lasx_xvslti_du: + case LoongArch::BI__builtin_lasx_xvmaxi_bu: + case LoongArch::BI__builtin_lasx_xvmaxi_hu: + case LoongArch::BI__builtin_lasx_xvmaxi_wu: + case LoongArch::BI__builtin_lasx_xvmaxi_du: + case LoongArch::BI__builtin_lasx_xvmini_bu: + case LoongArch::BI__builtin_lasx_xvmini_hu: + case LoongArch::BI__builtin_lasx_xvmini_wu: + case LoongArch::BI__builtin_lasx_xvmini_du: + case LoongArch::BI__builtin_lasx_xvaddi_bu: + case LoongArch::BI__builtin_lasx_xvaddi_hu: + case LoongArch::BI__builtin_lasx_xvaddi_wu: + case LoongArch::BI__builtin_lasx_xvaddi_du: + case LoongArch::BI__builtin_lasx_xvbitclri_w: + case LoongArch::BI__builtin_lasx_xvbitrevi_w: + case LoongArch::BI__builtin_lasx_xvbitseti_w: + case LoongArch::BI__builtin_lasx_xvsat_w: + case LoongArch::BI__builtin_lasx_xvsat_wu: + case LoongArch::BI__builtin_lasx_xvslli_w: + case LoongArch::BI__builtin_lasx_xvsrai_w: + case LoongArch::BI__builtin_lasx_xvsrari_w: + case LoongArch::BI__builtin_lasx_xvsrli_w: + case LoongArch::BI__builtin_lasx_xvsllwil_d_w: + case LoongArch::BI__builtin_lasx_xvsllwil_du_wu: + case LoongArch::BI__builtin_lasx_xvsrlri_w: + case LoongArch::BI__builtin_lasx_xvrotri_w: + case LoongArch::BI__builtin_lasx_xvsubi_bu: + case LoongArch::BI__builtin_lasx_xvsubi_hu: + case LoongArch::BI__builtin_lasx_xvsubi_wu: + case LoongArch::BI__builtin_lasx_xvsubi_du: + case LoongArch::BI__builtin_lasx_xvbsrl_v: + case LoongArch::BI__builtin_lasx_xvbsll_v: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case LoongArch::BI__builtin_lasx_xvssrarni_h_w: + case LoongArch::BI__builtin_lasx_xvssrarni_hu_w: + case LoongArch::BI__builtin_lasx_xvssrani_h_w: + case LoongArch::BI__builtin_lasx_xvssrani_hu_w: + case LoongArch::BI__builtin_lasx_xvsrarni_h_w: + case LoongArch::BI__builtin_lasx_xvsrani_h_w: + case LoongArch::BI__builtin_lasx_xvfrstpi_b: + case LoongArch::BI__builtin_lasx_xvfrstpi_h: + case LoongArch::BI__builtin_lasx_xvsrlni_h_w: + case LoongArch::BI__builtin_lasx_xvsrlrni_h_w: + case LoongArch::BI__builtin_lasx_xvssrlni_h_w: + case LoongArch::BI__builtin_lasx_xvssrlni_hu_w: + case LoongArch::BI__builtin_lasx_xvssrlrni_h_w: + case LoongArch::BI__builtin_lasx_xvssrlrni_hu_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31); + case LoongArch::BI__builtin_lasx_xvbitclri_d: + case LoongArch::BI__builtin_lasx_xvbitrevi_d: + case LoongArch::BI__builtin_lasx_xvbitseti_d: + case LoongArch::BI__builtin_lasx_xvsat_d: + case LoongArch::BI__builtin_lasx_xvsat_du: + case LoongArch::BI__builtin_lasx_xvslli_d: + case LoongArch::BI__builtin_lasx_xvsrai_d: + case LoongArch::BI__builtin_lasx_xvsrli_d: + case LoongArch::BI__builtin_lasx_xvsrari_d: + case LoongArch::BI__builtin_lasx_xvrotri_d: + case LoongArch::BI__builtin_lasx_xvsrlri_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 63); + case LoongArch::BI__builtin_lasx_xvssrarni_w_d: + case LoongArch::BI__builtin_lasx_xvssrarni_wu_d: + case LoongArch::BI__builtin_lasx_xvssrani_w_d: + case LoongArch::BI__builtin_lasx_xvssrani_wu_d: + case LoongArch::BI__builtin_lasx_xvsrarni_w_d: + case LoongArch::BI__builtin_lasx_xvsrlni_w_d: + case LoongArch::BI__builtin_lasx_xvsrlrni_w_d: + case LoongArch::BI__builtin_lasx_xvssrlni_w_d: + case LoongArch::BI__builtin_lasx_xvssrlni_wu_d: + case LoongArch::BI__builtin_lasx_xvssrlrni_w_d: + case LoongArch::BI__builtin_lasx_xvssrlrni_wu_d: + case LoongArch::BI__builtin_lasx_xvsrani_w_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 63); + case LoongArch::BI__builtin_lasx_xvssrarni_d_q: + case LoongArch::BI__builtin_lasx_xvssrarni_du_q: + case LoongArch::BI__builtin_lasx_xvssrani_d_q: + case LoongArch::BI__builtin_lasx_xvssrani_du_q: + case LoongArch::BI__builtin_lasx_xvsrarni_d_q: + case LoongArch::BI__builtin_lasx_xvssrlni_d_q: + case LoongArch::BI__builtin_lasx_xvssrlni_du_q: + case LoongArch::BI__builtin_lasx_xvssrlrni_d_q: + case LoongArch::BI__builtin_lasx_xvssrlrni_du_q: + case LoongArch::BI__builtin_lasx_xvsrani_d_q: + case LoongArch::BI__builtin_lasx_xvsrlni_d_q: + case LoongArch::BI__builtin_lasx_xvsrlrni_d_q: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 127); + case LoongArch::BI__builtin_lasx_xvseqi_b: + case LoongArch::BI__builtin_lasx_xvseqi_h: + case LoongArch::BI__builtin_lasx_xvseqi_w: + case LoongArch::BI__builtin_lasx_xvseqi_d: + case LoongArch::BI__builtin_lasx_xvslti_b: + case LoongArch::BI__builtin_lasx_xvslti_h: + case LoongArch::BI__builtin_lasx_xvslti_w: + case LoongArch::BI__builtin_lasx_xvslti_d: + case LoongArch::BI__builtin_lasx_xvslei_b: + case LoongArch::BI__builtin_lasx_xvslei_h: + case LoongArch::BI__builtin_lasx_xvslei_w: + case LoongArch::BI__builtin_lasx_xvslei_d: + case LoongArch::BI__builtin_lasx_xvmaxi_b: + case LoongArch::BI__builtin_lasx_xvmaxi_h: + case LoongArch::BI__builtin_lasx_xvmaxi_w: + case LoongArch::BI__builtin_lasx_xvmaxi_d: + case LoongArch::BI__builtin_lasx_xvmini_b: + case LoongArch::BI__builtin_lasx_xvmini_h: + case LoongArch::BI__builtin_lasx_xvmini_w: + case LoongArch::BI__builtin_lasx_xvmini_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -16, 15); + case LoongArch::BI__builtin_lasx_xvandi_b: + case LoongArch::BI__builtin_lasx_xvnori_b: + case LoongArch::BI__builtin_lasx_xvori_b: + case LoongArch::BI__builtin_lasx_xvshuf4i_b: + case LoongArch::BI__builtin_lasx_xvshuf4i_h: + case LoongArch::BI__builtin_lasx_xvshuf4i_w: + case LoongArch::BI__builtin_lasx_xvxori_b: + case LoongArch::BI__builtin_lasx_xvpermi_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 255); + case LoongArch::BI__builtin_lasx_xvbitseli_b: + case LoongArch::BI__builtin_lasx_xvshuf4i_d: + case LoongArch::BI__builtin_lasx_xvextrins_b: + case LoongArch::BI__builtin_lasx_xvextrins_h: + case LoongArch::BI__builtin_lasx_xvextrins_w: + case LoongArch::BI__builtin_lasx_xvextrins_d: + case LoongArch::BI__builtin_lasx_xvpermi_q: + case LoongArch::BI__builtin_lasx_xvpermi_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 255); + case LoongArch::BI__builtin_lasx_xvrepl128vei_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case LoongArch::BI__builtin_lasx_xvrepl128vei_h: + case LoongArch::BI__builtin_lasx_xvpickve2gr_w: + case LoongArch::BI__builtin_lasx_xvpickve2gr_wu: + case LoongArch::BI__builtin_lasx_xvpickve_w_f: + case LoongArch::BI__builtin_lasx_xvpickve_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 7); + case LoongArch::BI__builtin_lasx_xvinsgr2vr_w: + case LoongArch::BI__builtin_lasx_xvinsve0_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); + case LoongArch::BI__builtin_lasx_xvrepl128vei_w: + case LoongArch::BI__builtin_lasx_xvpickve2gr_d: + case LoongArch::BI__builtin_lasx_xvpickve2gr_du: + case LoongArch::BI__builtin_lasx_xvpickve_d_f: + case LoongArch::BI__builtin_lasx_xvpickve_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3); + case LoongArch::BI__builtin_lasx_xvinsve0_d: + case LoongArch::BI__builtin_lasx_xvinsgr2vr_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3); + case LoongArch::BI__builtin_lasx_xvstelm_b: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -128, 127) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 31); + case LoongArch::BI__builtin_lasx_xvstelm_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -256, 254) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 15); + case LoongArch::BI__builtin_lasx_xvstelm_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -512, 508) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 7); + case LoongArch::BI__builtin_lasx_xvstelm_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 3); + case LoongArch::BI__builtin_lasx_xvrepl128vei_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); + case LoongArch::BI__builtin_lasx_xvldrepl_b: + case LoongArch::BI__builtin_lasx_xvld: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2047); + case LoongArch::BI__builtin_lasx_xvldrepl_h: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2046); + case LoongArch::BI__builtin_lasx_xvldrepl_w: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2044); + case LoongArch::BI__builtin_lasx_xvldrepl_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, -2048, 2040); + case LoongArch::BI__builtin_lasx_xvst: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, -2048, 2047); + case LoongArch::BI__builtin_lasx_xvldi: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, -4096, 4095); + case LoongArch::BI__builtin_lasx_xvrepli_b: + case LoongArch::BI__builtin_lasx_xvrepli_h: + case LoongArch::BI__builtin_lasx_xvrepli_w: + case LoongArch::BI__builtin_lasx_xvrepli_d: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, -512, 511); + } + return false; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaM68k.cpp b/clang/lib/Sema/SemaM68k.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f091827092f831df6668079c2d7bf281e0079438 --- /dev/null +++ b/clang/lib/Sema/SemaM68k.cpp @@ -0,0 +1,56 @@ +//===------ SemaM68k.cpp -------- M68k target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to M68k. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaM68k.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Sema/ParsedAttr.h" + +namespace clang { +SemaM68k::SemaM68k(Sema &S) : SemaBase(S) {} + +void SemaM68k::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.checkExactlyNumArgs(SemaRef, 1)) + return; + + if (!AL.isArgExpr(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast(AL.getArgAsExpr(0)); + auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(getASTContext()); + if (!MaybeNumParams) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = MaybeNumParams->getLimitedValue(255); + if ((Num & 1) || Num > 30) { + Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (int)MaybeNumParams->getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + D->addAttr(::new (getASTContext()) + M68kInterruptAttr(getASTContext(), AL, Num)); + D->addAttr(UsedAttr::CreateImplicit(getASTContext())); +} +} // namespace clang diff --git a/clang/lib/Sema/SemaMIPS.cpp b/clang/lib/Sema/SemaMIPS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..269d927903c5d60ae8eb4b59458622c80800f665 --- /dev/null +++ b/clang/lib/Sema/SemaMIPS.cpp @@ -0,0 +1,300 @@ +//===------ SemaMIPS.cpp -------- MIPS target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to MIPS. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaMIPS.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaMIPS::SemaMIPS(Sema &S) : SemaBase(S) {} + +bool SemaMIPS::CheckMipsBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) || + CheckMipsBuiltinArgument(BuiltinID, TheCall); +} + +bool SemaMIPS::CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { + + if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_lwx) { + if (!TI.hasFeature("dsp")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp); + } + + if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) { + if (!TI.hasFeature("dspr2")) + return Diag(TheCall->getBeginLoc(), + diag::err_mips_builtin_requires_dspr2); + } + + if (Mips::BI__builtin_msa_add_a_b <= BuiltinID && + BuiltinID <= Mips::BI__builtin_msa_xori_b) { + if (!TI.hasFeature("msa")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa); + } + + return false; +} + +// CheckMipsBuiltinArgument - Checks the constant value passed to the +// intrinsic is correct. The switch statement is ordered by DSP, MSA. The +// ordering for DSP is unspecified. MSA is ordered by the data format used +// by the underlying instruction i.e., df/m, df/n and then by size. +// +// FIXME: The size tests here should instead be tablegen'd along with the +// definitions from include/clang/Basic/BuiltinsMips.def. +// FIXME: GCC is strict on signedness for some of these intrinsics, we should +// be too. +bool SemaMIPS::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { + unsigned i = 0, l = 0, u = 0, m = 0; + switch (BuiltinID) { + default: return false; + case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; + case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break; + case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break; + case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; + // MSA intrinsics. Instructions (which the intrinsics maps to) which use the + // df/m field. + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_bclri_b: + case Mips::BI__builtin_msa_bnegi_b: + case Mips::BI__builtin_msa_bseti_b: + case Mips::BI__builtin_msa_sat_s_b: + case Mips::BI__builtin_msa_sat_u_b: + case Mips::BI__builtin_msa_slli_b: + case Mips::BI__builtin_msa_srai_b: + case Mips::BI__builtin_msa_srari_b: + case Mips::BI__builtin_msa_srli_b: + case Mips::BI__builtin_msa_srlri_b: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_binsli_b: + case Mips::BI__builtin_msa_binsri_b: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_bclri_h: + case Mips::BI__builtin_msa_bnegi_h: + case Mips::BI__builtin_msa_bseti_h: + case Mips::BI__builtin_msa_sat_s_h: + case Mips::BI__builtin_msa_sat_u_h: + case Mips::BI__builtin_msa_slli_h: + case Mips::BI__builtin_msa_srai_h: + case Mips::BI__builtin_msa_srari_h: + case Mips::BI__builtin_msa_srli_h: + case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_binsli_h: + case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 5 bit immediate. + // The first block of intrinsics actually have an unsigned 5 bit field, + // not a df/n field. + case Mips::BI__builtin_msa_cfcmsa: + case Mips::BI__builtin_msa_ctcmsa: i = 0; l = 0; u = 31; break; + case Mips::BI__builtin_msa_clei_u_b: + case Mips::BI__builtin_msa_clei_u_h: + case Mips::BI__builtin_msa_clei_u_w: + case Mips::BI__builtin_msa_clei_u_d: + case Mips::BI__builtin_msa_clti_u_b: + case Mips::BI__builtin_msa_clti_u_h: + case Mips::BI__builtin_msa_clti_u_w: + case Mips::BI__builtin_msa_clti_u_d: + case Mips::BI__builtin_msa_maxi_u_b: + case Mips::BI__builtin_msa_maxi_u_h: + case Mips::BI__builtin_msa_maxi_u_w: + case Mips::BI__builtin_msa_maxi_u_d: + case Mips::BI__builtin_msa_mini_u_b: + case Mips::BI__builtin_msa_mini_u_h: + case Mips::BI__builtin_msa_mini_u_w: + case Mips::BI__builtin_msa_mini_u_d: + case Mips::BI__builtin_msa_addvi_b: + case Mips::BI__builtin_msa_addvi_h: + case Mips::BI__builtin_msa_addvi_w: + case Mips::BI__builtin_msa_addvi_d: + case Mips::BI__builtin_msa_bclri_w: + case Mips::BI__builtin_msa_bnegi_w: + case Mips::BI__builtin_msa_bseti_w: + case Mips::BI__builtin_msa_sat_s_w: + case Mips::BI__builtin_msa_sat_u_w: + case Mips::BI__builtin_msa_slli_w: + case Mips::BI__builtin_msa_srai_w: + case Mips::BI__builtin_msa_srari_w: + case Mips::BI__builtin_msa_srli_w: + case Mips::BI__builtin_msa_srlri_w: + case Mips::BI__builtin_msa_subvi_b: + case Mips::BI__builtin_msa_subvi_h: + case Mips::BI__builtin_msa_subvi_w: + case Mips::BI__builtin_msa_subvi_d: i = 1; l = 0; u = 31; break; + case Mips::BI__builtin_msa_binsli_w: + case Mips::BI__builtin_msa_binsri_w: i = 2; l = 0; u = 31; break; + // These intrinsics take an unsigned 6 bit immediate. + case Mips::BI__builtin_msa_bclri_d: + case Mips::BI__builtin_msa_bnegi_d: + case Mips::BI__builtin_msa_bseti_d: + case Mips::BI__builtin_msa_sat_s_d: + case Mips::BI__builtin_msa_sat_u_d: + case Mips::BI__builtin_msa_slli_d: + case Mips::BI__builtin_msa_srai_d: + case Mips::BI__builtin_msa_srari_d: + case Mips::BI__builtin_msa_srli_d: + case Mips::BI__builtin_msa_srlri_d: i = 1; l = 0; u = 63; break; + case Mips::BI__builtin_msa_binsli_d: + case Mips::BI__builtin_msa_binsri_d: i = 2; l = 0; u = 63; break; + // These intrinsics take a signed 5 bit immediate. + case Mips::BI__builtin_msa_ceqi_b: + case Mips::BI__builtin_msa_ceqi_h: + case Mips::BI__builtin_msa_ceqi_w: + case Mips::BI__builtin_msa_ceqi_d: + case Mips::BI__builtin_msa_clti_s_b: + case Mips::BI__builtin_msa_clti_s_h: + case Mips::BI__builtin_msa_clti_s_w: + case Mips::BI__builtin_msa_clti_s_d: + case Mips::BI__builtin_msa_clei_s_b: + case Mips::BI__builtin_msa_clei_s_h: + case Mips::BI__builtin_msa_clei_s_w: + case Mips::BI__builtin_msa_clei_s_d: + case Mips::BI__builtin_msa_maxi_s_b: + case Mips::BI__builtin_msa_maxi_s_h: + case Mips::BI__builtin_msa_maxi_s_w: + case Mips::BI__builtin_msa_maxi_s_d: + case Mips::BI__builtin_msa_mini_s_b: + case Mips::BI__builtin_msa_mini_s_h: + case Mips::BI__builtin_msa_mini_s_w: + case Mips::BI__builtin_msa_mini_s_d: i = 1; l = -16; u = 15; break; + // These intrinsics take an unsigned 8 bit immediate. + case Mips::BI__builtin_msa_andi_b: + case Mips::BI__builtin_msa_nori_b: + case Mips::BI__builtin_msa_ori_b: + case Mips::BI__builtin_msa_shf_b: + case Mips::BI__builtin_msa_shf_h: + case Mips::BI__builtin_msa_shf_w: + case Mips::BI__builtin_msa_xori_b: i = 1; l = 0; u = 255; break; + case Mips::BI__builtin_msa_bseli_b: + case Mips::BI__builtin_msa_bmnzi_b: + case Mips::BI__builtin_msa_bmzi_b: i = 2; l = 0; u = 255; break; + // df/n format + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_copy_s_b: + case Mips::BI__builtin_msa_copy_u_b: + case Mips::BI__builtin_msa_insve_b: + case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_copy_s_h: + case Mips::BI__builtin_msa_copy_u_h: + case Mips::BI__builtin_msa_insve_h: + case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 2 bit immediate. + case Mips::BI__builtin_msa_copy_s_w: + case Mips::BI__builtin_msa_copy_u_w: + case Mips::BI__builtin_msa_insve_w: + case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break; + case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break; + // These intrinsics take an unsigned 1 bit immediate. + case Mips::BI__builtin_msa_copy_s_d: + case Mips::BI__builtin_msa_copy_u_d: + case Mips::BI__builtin_msa_insve_d: + case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break; + case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break; + // Memory offsets and immediate loads. + // These intrinsics take a signed 10 bit immediate. + case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 255; break; + case Mips::BI__builtin_msa_ldi_h: + case Mips::BI__builtin_msa_ldi_w: + case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break; + case Mips::BI__builtin_msa_ld_b: i = 1; l = -512; u = 511; m = 1; break; + case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 2; break; + case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 4; break; + case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_ldr_d: i = 1; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_ldr_w: i = 1; l = -2048; u = 2044; m = 4; break; + case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 1; break; + case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 2; break; + case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 4; break; + case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_str_d: i = 2; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_str_w: i = 2; l = -2048; u = 2044; m = 4; break; + } + + if (!m) + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u); + + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u) || + SemaRef.BuiltinConstantArgMultiple(TheCall, i, m); +} + +void SemaMIPS::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + // Only one optional argument permitted. + if (AL.getNumArgs() > 1) { + Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (AL.getNumArgs() == 0) + Str = ""; + else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + // Semantic checks for a function with the 'interrupt' attribute for MIPS: + // a) Must be a function. + // b) Must have no parameters. + // c) Must have the 'void' return type. + // d) Cannot have the 'mips16' attribute, as that instruction set + // lacks the 'eret' instruction. + // e) The attribute itself must either have no argument or one of the + // valid interrupt types, see [MipsInterruptDocs]. + + if (!isFuncOrMethodForAttrSubject(D)) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 1; + return; + } + + // We still have to do this manually because the Interrupt attributes are + // a bit special due to sharing their spellings across targets. + if (checkAttrMutualExclusion(*this, D, AL)) + return; + + MipsInterruptAttr::InterruptType Kind; + if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << "'" + std::string(Str) + "'"; + return; + } + + D->addAttr(::new (getASTContext()) + MipsInterruptAttr(getASTContext(), AL, Kind)); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaMSP430.cpp b/clang/lib/Sema/SemaMSP430.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4038a1ff61d63ced9aec6365a5e0a7118a379b7e --- /dev/null +++ b/clang/lib/Sema/SemaMSP430.cpp @@ -0,0 +1,78 @@ +//===------ SemaMSP430.cpp ----- MSP430 target-specific routines ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to NVPTX. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaMSP430.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" + +namespace clang { + +SemaMSP430::SemaMSP430(Sema &S) : SemaBase(S) {} + +void SemaMSP430::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + // MSP430 'interrupt' attribute is applied to + // a function with no parameters and void return type. + if (!isFuncOrMethodForAttrSubject(D)) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MSP430*/ 1 << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MSP430*/ 1 << 1; + return; + } + + // The attribute takes one integer argument. + if (!AL.checkExactlyNumArgs(SemaRef, 1)) + return; + + if (!AL.isArgExpr(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant; + return; + } + + Expr *NumParamsExpr = static_cast(AL.getArgAsExpr(0)); + std::optional NumParams = llvm::APSInt(32); + if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(getASTContext()))) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); + return; + } + // The argument should be in range 0..63. + unsigned Num = NumParams->getLimitedValue(255); + if (Num > 63) { + Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (int)NumParams->getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + D->addAttr(::new (getASTContext()) + MSP430InterruptAttr(getASTContext(), AL, Num)); + D->addAttr(UsedAttr::CreateImplicit(getASTContext())); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaNVPTX.cpp b/clang/lib/Sema/SemaNVPTX.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc8941071463d3a331be5253b31568dfeda7c054 --- /dev/null +++ b/clang/lib/Sema/SemaNVPTX.cpp @@ -0,0 +1,35 @@ +//===------ SemaNVPTX.cpp ------- NVPTX target-specific routines ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to NVPTX. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaNVPTX.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaNVPTX::SemaNVPTX(Sema &S) : SemaBase(S) {} + +bool SemaNVPTX::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case NVPTX::BI__nvvm_cp_async_ca_shared_global_4: + case NVPTX::BI__nvvm_cp_async_ca_shared_global_8: + case NVPTX::BI__nvvm_cp_async_ca_shared_global_16: + case NVPTX::BI__nvvm_cp_async_cg_shared_global_16: + return SemaRef.checkArgCountAtMost(TheCall, 3); + } + + return false; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index 1e6cc21a487044bdbc9a1bdcef8bd82b1f00b00c..d396258cfc7d18c83021fe8ab7c910ed5ba959fa 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -11,10 +11,13 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaObjC.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/TemplateDeduction.h" @@ -1483,4 +1486,773 @@ bool SemaObjC::isCFError(RecordDecl *RD) { return false; } +bool SemaObjC::isNSStringType(QualType T, bool AllowNSAttributedString) { + const auto *PT = T->getAs(); + if (!PT) + return false; + + ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); + if (!Cls) + return false; + + IdentifierInfo *ClsName = Cls->getIdentifier(); + + if (AllowNSAttributedString && + ClsName == &getASTContext().Idents.get("NSAttributedString")) + return true; + // FIXME: Should we walk the chain of classes? + return ClsName == &getASTContext().Idents.get("NSString") || + ClsName == &getASTContext().Idents.get("NSMutableString"); +} + +bool SemaObjC::isCFStringType(QualType T) { + const auto *PT = T->getAs(); + if (!PT) + return false; + + const auto *RT = PT->getPointeeType()->getAs(); + if (!RT) + return false; + + const RecordDecl *RD = RT->getDecl(); + if (RD->getTagKind() != TagTypeKind::Struct) + return false; + + return RD->getIdentifier() == &getASTContext().Idents.get("__CFString"); +} + +static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { + // The IBOutlet/IBOutletCollection attributes only apply to instance + // variables or properties of Objective-C classes. The outlet must also + // have an object reference type. + if (const auto *VD = dyn_cast(D)) { + if (!VD->getType()->getAs()) { + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL << VD->getType() << 0; + return false; + } + } else if (const auto *PD = dyn_cast(D)) { + if (!PD->getType()->getAs()) { + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL << PD->getType() << 1; + return false; + } + } else { + S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL; + return false; + } + + return true; +} + +void SemaObjC::handleIBOutlet(Decl *D, const ParsedAttr &AL) { + if (!checkIBOutletCommon(SemaRef, D, AL)) + return; + + D->addAttr(::new (getASTContext()) IBOutletAttr(getASTContext(), AL)); +} + +void SemaObjC::handleIBOutletCollection(Decl *D, const ParsedAttr &AL) { + + ASTContext &Context = getASTContext(); + // The iboutletcollection attribute can have zero or one arguments. + if (AL.getNumArgs() > 1) { + Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; + return; + } + + if (!checkIBOutletCommon(SemaRef, D, AL)) + return; + + ParsedType PT; + + if (AL.hasParsedType()) + PT = AL.getTypeArg(); + else { + PT = SemaRef.getTypeName( + Context.Idents.get("NSObject"), AL.getLoc(), + SemaRef.getScopeForContext(D->getDeclContext()->getParent())); + if (!PT) { + Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; + return; + } + } + + TypeSourceInfo *QTLoc = nullptr; + QualType QT = SemaRef.GetTypeFromParser(PT, &QTLoc); + if (!QTLoc) + QTLoc = Context.getTrivialTypeSourceInfo(QT, AL.getLoc()); + + // Diagnose use of non-object type in iboutletcollection attribute. + // FIXME. Gnu attribute extension ignores use of builtin types in + // attributes. So, __attribute__((iboutletcollection(char))) will be + // treated as __attribute__((iboutletcollection())). + if (!QT->isObjCIdType() && !QT->isObjCObjectType()) { + Diag(AL.getLoc(), QT->isBuiltinType() + ? diag::err_iboutletcollection_builtintype + : diag::err_iboutletcollection_type) + << QT; + return; + } + + D->addAttr(::new (Context) IBOutletCollectionAttr(Context, AL, QTLoc)); +} + +void SemaObjC::handleSuppresProtocolAttr(Decl *D, const ParsedAttr &AL) { + if (!cast(D)->isThisDeclarationADefinition()) { + Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) + << AL << AL.getRange(); + return; + } + + D->addAttr(::new (getASTContext()) + ObjCExplicitProtocolImplAttr(getASTContext(), AL)); +} + +void SemaObjC::handleDirectAttr(Decl *D, const ParsedAttr &AL) { + // objc_direct cannot be set on methods declared in the context of a protocol + if (isa(D->getDeclContext())) { + Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; + return; + } + + if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + handleSimpleAttribute(*this, D, AL); + } else { + Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; + } +} + +void SemaObjC::handleDirectMembersAttr(Decl *D, const ParsedAttr &AL) { + if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + handleSimpleAttribute(*this, D, AL); + } else { + Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; + } +} + +void SemaObjC::handleMethodFamilyAttr(Decl *D, const ParsedAttr &AL) { + const auto *M = cast(D); + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *IL = AL.getArgAsIdent(0); + ObjCMethodFamilyAttr::FamilyKind F; + if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { + Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident; + return; + } + + if (F == ObjCMethodFamilyAttr::OMF_init && + !M->getReturnType()->isObjCObjectPointerType()) { + Diag(M->getLocation(), diag::err_init_method_bad_return_type) + << M->getReturnType(); + // Ignore the attribute. + return; + } + + D->addAttr(new (getASTContext()) + ObjCMethodFamilyAttr(getASTContext(), AL, F)); +} + +void SemaObjC::handleNSObject(Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast(D)) { + QualType T = TD->getUnderlyingType(); + if (!T->isCARCBridgableType()) { + Diag(TD->getLocation(), diag::err_nsobject_attribute); + return; + } + } else if (const auto *PD = dyn_cast(D)) { + QualType T = PD->getType(); + if (!T->isCARCBridgableType()) { + Diag(PD->getLocation(), diag::err_nsobject_attribute); + return; + } + } else { + // It is okay to include this attribute on properties, e.g.: + // + // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); + // + // In this case it follows tradition and suppresses an error in the above + // case. + Diag(D->getLocation(), diag::warn_nsobject_attribute); + } + D->addAttr(::new (getASTContext()) ObjCNSObjectAttr(getASTContext(), AL)); +} + +void SemaObjC::handleIndependentClass(Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast(D)) { + QualType T = TD->getUnderlyingType(); + if (!T->isObjCObjectPointerType()) { + Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); + return; + } + } else { + Diag(D->getLocation(), diag::warn_independentclass_attribute); + return; + } + D->addAttr(::new (getASTContext()) + ObjCIndependentClassAttr(getASTContext(), AL)); +} + +void SemaObjC::handleBlocksAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + BlocksAttr::BlockType type; + if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; + return; + } + + D->addAttr(::new (getASTContext()) BlocksAttr(getASTContext(), AL, type)); +} + +static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { + return QT->isDependentType() || QT->isObjCRetainableType(); +} + +static bool isValidSubjectOfNSAttribute(QualType QT) { + return QT->isDependentType() || QT->isObjCObjectPointerType() || + QT->isObjCNSObjectType(); +} + +static bool isValidSubjectOfCFAttribute(QualType QT) { + return QT->isDependentType() || QT->isPointerType() || + isValidSubjectOfNSAttribute(QT); +} + +static bool isValidSubjectOfOSAttribute(QualType QT) { + if (QT->isDependentType()) + return true; + QualType PT = QT->getPointeeType(); + return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr; +} + +void SemaObjC::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, + Sema::RetainOwnershipKind K, + bool IsTemplateInstantiation) { + ValueDecl *VD = cast(D); + switch (K) { + case Sema::RetainOwnershipKind::OS: + handleSimpleAttributeOrDiagnose( + *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()), + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1); + return; + case Sema::RetainOwnershipKind::NS: + handleSimpleAttributeOrDiagnose( + *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()), + + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount) + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type), + /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0); + return; + case Sema::RetainOwnershipKind::CF: + handleSimpleAttributeOrDiagnose( + *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()), + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1); + return; + } +} + +Sema::RetainOwnershipKind +SemaObjC::parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) { + switch (AL.getKind()) { + case ParsedAttr::AT_CFConsumed: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + return Sema::RetainOwnershipKind::CF; + case ParsedAttr::AT_OSConsumesThis: + case ParsedAttr::AT_OSConsumed: + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + case ParsedAttr::AT_OSReturnsRetainedOnZero: + case ParsedAttr::AT_OSReturnsRetainedOnNonZero: + return Sema::RetainOwnershipKind::OS; + case ParsedAttr::AT_NSConsumesSelf: + case ParsedAttr::AT_NSConsumed: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + return Sema::RetainOwnershipKind::NS; + default: + llvm_unreachable("Wrong argument supplied"); + } +} + +bool SemaObjC::checkNSReturnsRetainedReturnType(SourceLocation Loc, + QualType QT) { + if (isValidSubjectOfNSReturnsRetainedAttribute(QT)) + return false; + + Diag(Loc, diag::warn_ns_attribute_wrong_return_type) + << "'ns_returns_retained'" << 0 << 0; + return true; +} + +/// \return whether the parameter is a pointer to OSObject pointer. +bool SemaObjC::isValidOSObjectOutParameter(const Decl *D) { + const auto *PVD = dyn_cast(D); + if (!PVD) + return false; + QualType QT = PVD->getType(); + QualType PT = QT->getPointeeType(); + return !PT.isNull() && isValidSubjectOfOSAttribute(PT); +} + +void SemaObjC::handleXReturnsXRetainedAttr(Decl *D, const ParsedAttr &AL) { + QualType ReturnType; + Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL); + + if (const auto *MD = dyn_cast(D)) { + ReturnType = MD->getReturnType(); + } else if (getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) { + return; // ignore: was handled as a type attribute + } else if (const auto *PD = dyn_cast(D)) { + ReturnType = PD->getType(); + } else if (const auto *FD = dyn_cast(D)) { + ReturnType = FD->getReturnType(); + } else if (const auto *Param = dyn_cast(D)) { + // Attributes on parameters are used for out-parameters, + // passed as pointers-to-pointers. + unsigned DiagID = K == Sema::RetainOwnershipKind::CF + ? /*pointer-to-CF-pointer*/ 2 + : /*pointer-to-OSObject-pointer*/ 3; + ReturnType = Param->getType()->getPointeeType(); + if (ReturnType.isNull()) { + Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) + << AL << DiagID << AL.getRange(); + return; + } + } else if (AL.isUsedAsTypeAttr()) { + return; + } else { + AttributeDeclKind ExpectedDeclKind; + switch (AL.getKind()) { + default: + llvm_unreachable("invalid ownership attribute"); + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionOrMethod; + break; + + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionMethodOrParameter; + break; + } + Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedDeclKind; + return; + } + + bool TypeOK; + bool Cf; + unsigned ParmDiagID = 2; // Pointer-to-CF-pointer + switch (AL.getKind()) { + default: + llvm_unreachable("invalid ownership attribute"); + case ParsedAttr::AT_NSReturnsRetained: + TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); + Cf = false; + break; + + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + TypeOK = isValidSubjectOfNSAttribute(ReturnType); + Cf = false; + break; + + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + TypeOK = isValidSubjectOfCFAttribute(ReturnType); + Cf = true; + break; + + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + TypeOK = isValidSubjectOfOSAttribute(ReturnType); + Cf = true; + ParmDiagID = 3; // Pointer-to-OSObject-pointer + break; + } + + if (!TypeOK) { + if (AL.isUsedAsTypeAttr()) + return; + + if (isa(D)) { + Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) + << AL << ParmDiagID << AL.getRange(); + } else { + // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. + enum : unsigned { Function, Method, Property } SubjectKind = Function; + if (isa(D)) + SubjectKind = Method; + else if (isa(D)) + SubjectKind = Property; + Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) + << AL << SubjectKind << Cf << AL.getRange(); + } + return; + } + + switch (AL.getKind()) { + default: + llvm_unreachable("invalid ownership attribute"); + case ParsedAttr::AT_NSReturnsAutoreleased: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_CFReturnsNotRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_NSReturnsNotRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_CFReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_NSReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_OSReturnsRetained: + handleSimpleAttribute(*this, D, AL); + return; + case ParsedAttr::AT_OSReturnsNotRetained: + handleSimpleAttribute(*this, D, AL); + return; + }; +} + +void SemaObjC::handleReturnsInnerPointerAttr(Decl *D, const ParsedAttr &Attrs) { + const int EP_ObjCMethod = 1; + const int EP_ObjCProperty = 2; + + SourceLocation loc = Attrs.getLoc(); + QualType resultType; + if (isa(D)) + resultType = cast(D)->getReturnType(); + else + resultType = cast(D)->getType(); + + if (!resultType->isReferenceType() && + (!resultType->isPointerType() || resultType->isObjCRetainableType())) { + Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) << Attrs + << (isa(D) ? EP_ObjCMethod : EP_ObjCProperty) + << /*non-retainable pointer*/ 2; + + // Drop the attribute. + return; + } + + D->addAttr(::new (getASTContext()) + ObjCReturnsInnerPointerAttr(getASTContext(), Attrs)); +} + +void SemaObjC::handleRequiresSuperAttr(Decl *D, const ParsedAttr &Attrs) { + const auto *Method = cast(D); + + const DeclContext *DC = Method->getDeclContext(); + if (const auto *PDecl = dyn_cast_if_present(DC)) { + Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) + << Attrs << 0; + Diag(PDecl->getLocation(), diag::note_protocol_decl); + return; + } + if (Method->getMethodFamily() == OMF_dealloc) { + Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) + << Attrs << 1; + return; + } + + D->addAttr(::new (getASTContext()) + ObjCRequiresSuperAttr(getASTContext(), Attrs)); +} + +void SemaObjC::handleNSErrorDomain(Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { + Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0; + return; + } + + IdentifierLoc *IdentLoc = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!IdentLoc || !IdentLoc->Ident) { + // Try to locate the argument directly. + SourceLocation Loc = Attr.getLoc(); + if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) + Loc = Attr.getArgAsExpr(0)->getBeginLoc(); + + Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; + return; + } + + // Verify that the identifier is a valid decl in the C decl namespace. + LookupResult Result(SemaRef, DeclarationName(IdentLoc->Ident), + SourceLocation(), + Sema::LookupNameKind::LookupOrdinaryName); + if (!SemaRef.LookupName(Result, SemaRef.TUScope) || + !Result.getAsSingle()) { + Diag(IdentLoc->Loc, diag::err_nserrordomain_invalid_decl) + << 1 << IdentLoc->Ident; + return; + } + + D->addAttr(::new (getASTContext()) + NSErrorDomainAttr(getASTContext(), Attr, IdentLoc->Ident)); +} + +void SemaObjC::handleBridgeAttr(Decl *D, const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; + + if (!Parm) { + Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; + return; + } + + // Typedefs only allow objc_bridge(id) and have some additional checking. + if (const auto *TD = dyn_cast(D)) { + if (!Parm->Ident->isStr("id")) { + Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL; + return; + } + + // Only allow 'cv void *'. + QualType T = TD->getUnderlyingType(); + if (!T->isVoidPointerType()) { + Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); + return; + } + } + + D->addAttr(::new (getASTContext()) + ObjCBridgeAttr(getASTContext(), AL, Parm->Ident)); +} + +void SemaObjC::handleBridgeMutableAttr(Decl *D, const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; + + if (!Parm) { + Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; + return; + } + + D->addAttr(::new (getASTContext()) + ObjCBridgeMutableAttr(getASTContext(), AL, Parm->Ident)); +} + +void SemaObjC::handleBridgeRelatedAttr(Decl *D, const ParsedAttr &AL) { + IdentifierInfo *RelatedClass = + AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; + if (!RelatedClass) { + Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; + return; + } + IdentifierInfo *ClassMethod = + AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; + IdentifierInfo *InstanceMethod = + AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; + D->addAttr(::new (getASTContext()) ObjCBridgeRelatedAttr( + getASTContext(), AL, RelatedClass, ClassMethod, InstanceMethod)); +} + +void SemaObjC::handleDesignatedInitializer(Decl *D, const ParsedAttr &AL) { + DeclContext *Ctx = D->getDeclContext(); + + // This attribute can only be applied to methods in interfaces or class + // extensions. + if (!isa(Ctx) && + !(isa(Ctx) && + cast(Ctx)->IsClassExtension())) { + Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + return; + } + + ObjCInterfaceDecl *IFace; + if (auto *CatDecl = dyn_cast(Ctx)) + IFace = CatDecl->getClassInterface(); + else + IFace = cast(Ctx); + + if (!IFace) + return; + + IFace->setHasDesignatedInitializers(); + D->addAttr(::new (getASTContext()) + ObjCDesignatedInitializerAttr(getASTContext(), AL)); +} + +void SemaObjC::handleRuntimeName(Decl *D, const ParsedAttr &AL) { + StringRef MetaDataName; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) + return; + D->addAttr(::new (getASTContext()) + ObjCRuntimeNameAttr(getASTContext(), AL, MetaDataName)); +} + +// When a user wants to use objc_boxable with a union or struct +// but they don't have access to the declaration (legacy/third-party code) +// then they can 'enable' this feature with a typedef: +// typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; +void SemaObjC::handleBoxable(Decl *D, const ParsedAttr &AL) { + bool notify = false; + + auto *RD = dyn_cast(D); + if (RD && RD->getDefinition()) { + RD = RD->getDefinition(); + notify = true; + } + + if (RD) { + ObjCBoxableAttr *BoxableAttr = + ::new (getASTContext()) ObjCBoxableAttr(getASTContext(), AL); + RD->addAttr(BoxableAttr); + if (notify) { + // we need to notify ASTReader/ASTWriter about + // modification of existing declaration + if (ASTMutationListener *L = SemaRef.getASTMutationListener()) + L->AddedAttributeToRecord(BoxableAttr, RD); + } + } +} + +void SemaObjC::handleOwnershipAttr(Decl *D, const ParsedAttr &AL) { + if (hasDeclarator(D)) + return; + + Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedVariable; +} + +void SemaObjC::handlePreciseLifetimeAttr(Decl *D, const ParsedAttr &AL) { + const auto *VD = cast(D); + QualType QT = VD->getType(); + + if (!QT->isDependentType() && !QT->isObjCLifetimeType()) { + Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) << QT; + return; + } + + Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime(); + + // If we have no lifetime yet, check the lifetime we're presumably + // going to infer. + if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) + Lifetime = QT->getObjCARCImplicitLifetime(); + + switch (Lifetime) { + case Qualifiers::OCL_None: + assert(QT->isDependentType() && + "didn't infer lifetime for non-dependent type?"); + break; + + case Qualifiers::OCL_Weak: // meaningful + case Qualifiers::OCL_Strong: // meaningful + break; + + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) + << (Lifetime == Qualifiers::OCL_Autoreleasing); + break; + } + + D->addAttr(::new (getASTContext()) + ObjCPreciseLifetimeAttr(getASTContext(), AL)); +} + +static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD, + bool DiagnoseFailure) { + QualType Ty = VD->getType(); + if (!Ty->isObjCRetainableType()) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 0; + } + return false; + } + + Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime(); + + // SemaObjC::inferObjCARCLifetime must run after processing decl attributes + // (because __block lowers to an attribute), so if the lifetime hasn't been + // explicitly specified, infer it locally now. + if (LifetimeQual == Qualifiers::OCL_None) + LifetimeQual = Ty->getObjCARCImplicitLifetime(); + + // The attributes only really makes sense for __strong variables; ignore any + // attempts to annotate a parameter with any other lifetime qualifier. + if (LifetimeQual != Qualifiers::OCL_Strong) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 1; + } + return false; + } + + // Tampering with the type of a VarDecl here is a bit of a hack, but we need + // to ensure that the variable is 'const' so that we can error on + // modification, which can otherwise over-release. + VD->setType(Ty.withConst()); + VD->setARCPseudoStrong(true); + return true; +} + +void SemaObjC::handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL) { + if (auto *VD = dyn_cast(D)) { + assert(!isa(VD) && "should be diagnosed automatically"); + if (!VD->hasLocalStorage()) { + Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained) << 0; + return; + } + + if (!tryMakeVariablePseudoStrong(SemaRef, VD, /*DiagnoseFailure=*/true)) + return; + + handleSimpleAttribute(*this, D, AL); + return; + } + + // If D is a function-like declaration (method, block, or function), then we + // make every parameter psuedo-strong. + unsigned NumParams = + hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0; + for (unsigned I = 0; I != NumParams; ++I) { + auto *PVD = const_cast(getFunctionOrMethodParam(D, I)); + QualType Ty = PVD->getType(); + + // If a user wrote a parameter with __strong explicitly, then assume they + // want "real" strong semantics for that parameter. This works because if + // the parameter was written with __strong, then the strong qualifier will + // be non-local. + if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() == + Qualifiers::OCL_Strong) + continue; + + tryMakeVariablePseudoStrong(SemaRef, PVD, /*DiagnoseFailure=*/false); + } + handleSimpleAttribute(*this, D, AL); +} + } // namespace clang diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 09d91b31cfe5f9ee00ed8f73ae2edfaffa17c73e..1320fd90b440bfbea4c14c1b158e22e052ea8734 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -33,6 +33,7 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Loop: if (!IsStmt) return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; break; @@ -170,6 +171,57 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, default: return false; } + case OpenACCClauseKind::CopyIn: + case OpenACCClauseKind::PCopyIn: + case OpenACCClauseKind::PresentOrCopyIn: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::Declare: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + case OpenACCClauseKind::CopyOut: + case OpenACCClauseKind::PCopyOut: + case OpenACCClauseKind::PresentOrCopyOut: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Declare: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + case OpenACCClauseKind::Create: + case OpenACCClauseKind::PCreate: + case OpenACCClauseKind::PresentOrCreate: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + case OpenACCClauseKind::Attach: switch (DirectiveKind) { case OpenACCDirectiveKind::Parallel: @@ -233,6 +285,30 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, return false; } + case OpenACCClauseKind::Seq: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::Routine: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + + case OpenACCClauseKind::Independent: + case OpenACCClauseKind::Auto: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + case OpenACCClauseKind::Reduction: switch (DirectiveKind) { case OpenACCDirectiveKind::Parallel: @@ -246,6 +322,27 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, return false; } + case OpenACCClauseKind::DeviceType: + case OpenACCClauseKind::DType: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: + case OpenACCDirectiveKind::Update: + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::Routine: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + default: // Do nothing so we can go to the 'unimplemented' diagnostic instead. return true; @@ -268,36 +365,93 @@ bool checkAlreadyHasClauseOfKind( return false; } -/// Implement check from OpenACC3.3: section 2.5.4: -/// Only the async, wait, num_gangs, num_workers, and vector_length clauses may -/// follow a device_type clause. bool checkValidAfterDeviceType( SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause, const SemaOpenACC::OpenACCParsedClause &NewClause) { - // This is only a requirement on compute constructs so far, so this is fine - // otherwise. - if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind())) + // This is only a requirement on compute and loop constructs so far, so this + // is fine otherwise. + if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) && + NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop) return false; - switch (NewClause.getClauseKind()) { - case OpenACCClauseKind::Async: - case OpenACCClauseKind::Wait: - case OpenACCClauseKind::NumGangs: - case OpenACCClauseKind::NumWorkers: - case OpenACCClauseKind::VectorLength: - case OpenACCClauseKind::DType: - case OpenACCClauseKind::DeviceType: + + // OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are + // default clauses. Clauses that follow a device_type clause up to the end of + // the directive or up to the next device_type clause are device-specific + // clauses for the device types specified in the device_type argument. + // + // The above implies that despite what the individual text says, these are + // valid. + if (NewClause.getClauseKind() == OpenACCClauseKind::DType || + NewClause.getClauseKind() == OpenACCClauseKind::DeviceType) return false; - default: - S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type) - << NewClause.getClauseKind() << DeviceTypeClause.getClauseKind(); - S.Diag(DeviceTypeClause.getBeginLoc(), diag::note_acc_previous_clause_here); - return true; + + // Implement check from OpenACC3.3: section 2.5.4: + // Only the async, wait, num_gangs, num_workers, and vector_length clauses may + // follow a device_type clause. + if (isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind())) { + switch (NewClause.getClauseKind()) { + case OpenACCClauseKind::Async: + case OpenACCClauseKind::Wait: + case OpenACCClauseKind::NumGangs: + case OpenACCClauseKind::NumWorkers: + case OpenACCClauseKind::VectorLength: + return false; + default: + break; + } + } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Loop) { + // Implement check from OpenACC3.3: section 2.9: + // Only the collapse, gang, worker, vector, seq, independent, auto, and tile + // clauses may follow a device_type clause. + switch (NewClause.getClauseKind()) { + case OpenACCClauseKind::Collapse: + case OpenACCClauseKind::Gang: + case OpenACCClauseKind::Worker: + case OpenACCClauseKind::Vector: + case OpenACCClauseKind::Seq: + case OpenACCClauseKind::Independent: + case OpenACCClauseKind::Auto: + case OpenACCClauseKind::Tile: + return false; + default: + break; + } } + S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type) + << NewClause.getClauseKind() << DeviceTypeClause.getClauseKind() + << isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) + << NewClause.getDirectiveKind(); + S.Diag(DeviceTypeClause.getBeginLoc(), diag::note_acc_previous_clause_here); + return true; } } // namespace SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} +SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S, + OpenACCDirectiveKind DK) + : SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct), + DirKind(DK) { + // Compute constructs end up taking their 'loop'. + if (DirKind == OpenACCDirectiveKind::Parallel || + DirKind == OpenACCDirectiveKind::Serial || + DirKind == OpenACCDirectiveKind::Kernels) { + SemaRef.InsideComputeConstruct = true; + SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs); + } +} + +SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() { + SemaRef.InsideComputeConstruct = WasInsideComputeConstruct; + if (DirKind == OpenACCDirectiveKind::Parallel || + DirKind == OpenACCDirectiveKind::Serial || + DirKind == OpenACCDirectiveKind::Kernels) { + assert(SemaRef.ParentlessLoopConstructs.empty() && + "Didn't consume loop construct list?"); + SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs); + } +} + OpenACCClause * SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, OpenACCParsedClause &Clause) { @@ -521,10 +675,12 @@ SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, Clause.getEndLoc()); } case OpenACCClauseKind::Private: { - // Restrictions only properly implemented on 'compute' constructs, and - // 'compute' constructs are the only construct that can do anything with - // this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute' and 'loop' + // constructs, and 'compute'/'loop' constructs are the only construct that + // can do anything with this yet, so skip/treat as unimplemented in this + // case. + if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) break; // ActOnVar ensured that everything is a valid variable reference, so there @@ -719,10 +875,12 @@ SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, } case OpenACCClauseKind::DType: case OpenACCClauseKind::DeviceType: { - // Restrictions only properly implemented on 'compute' constructs, and - // 'compute' constructs are the only construct that can do anything with - // this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute' and 'loop' + // constructs, and 'compute'/'loop' constructs are the only construct that + // can do anything with this yet, so skip/treat as unimplemented in this + // case. + if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) break; // TODO OpenACC: Once we get enough of the CodeGen implemented that we have @@ -734,6 +892,102 @@ SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, Clause.getLParenLoc(), Clause.getDeviceTypeArchitectures(), Clause.getEndLoc()); } + case OpenACCClauseKind::Auto: { + // Restrictions only properly implemented on 'loop' constructs, and it is + // the only construct that can do anything with this, so skip/treat as + // unimplemented for the combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + break; + + // OpenACC 3.3 2.9: + // Only one of the seq, independent, and auto clauses may appear. + const auto *Itr = llvm::find_if( + ExistingClauses, + llvm::IsaPred); + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict) + << Clause.getClauseKind() << Clause.getDirectiveKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } + + return OpenACCAutoClause::Create(getASTContext(), Clause.getBeginLoc(), + Clause.getEndLoc()); + } + case OpenACCClauseKind::Independent: { + // Restrictions only properly implemented on 'loop' constructs, and it is + // the only construct that can do anything with this, so skip/treat as + // unimplemented for the combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + break; + + // OpenACC 3.3 2.9: + // Only one of the seq, independent, and auto clauses may appear. + const auto *Itr = llvm::find_if( + ExistingClauses, llvm::IsaPred); + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict) + << Clause.getClauseKind() << Clause.getDirectiveKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } + + return OpenACCIndependentClause::Create( + getASTContext(), Clause.getBeginLoc(), Clause.getEndLoc()); + } + case OpenACCClauseKind::Seq: { + // Restrictions only properly implemented on 'loop' constructs, and it is + // the only construct that can do anything with this, so skip/treat as + // unimplemented for the combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + break; + + // OpenACC 3.3 2.9: + // Only one of the seq, independent, and auto clauses may appear. + const auto *Itr = llvm::find_if( + ExistingClauses, + llvm::IsaPred); + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), diag::err_acc_loop_spec_conflict) + << Clause.getClauseKind() << Clause.getDirectiveKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } + + // OpenACC 3.3 2.9: + // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause + // appears. + Itr = llvm::find_if(ExistingClauses, + llvm::IsaPred); + + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) + << Clause.getClauseKind() << (*Itr)->getClauseKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } + + // TODO OpenACC: 2.9 ~ line 2010 specifies that the associated loop has some + // restrictions when there is a 'seq' clause in place. We probably need to + // implement that. + return OpenACCSeqClause::Create(getASTContext(), Clause.getBeginLoc(), + Clause.getEndLoc()); + } + case OpenACCClauseKind::Gang: + case OpenACCClauseKind::Worker: + case OpenACCClauseKind::Vector: { + // OpenACC 3.3 2.9: + // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause + // appears. + const auto *Itr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) + << Clause.getClauseKind() << (*Itr)->getClauseKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } + // Not yet implemented, so immediately drop to the 'not yet implemented' + // diagnostic. + break; + } case OpenACCClauseKind::Reduction: { // Restrictions only properly implemented on 'compute' constructs, and // 'compute' constructs are the only construct that can do anything with @@ -844,7 +1098,7 @@ ExprResult SemaOpenACC::CheckReductionVar(Expr *VarExpr) { } void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, - SourceLocation StartLoc) { + SourceLocation DirLoc) { switch (K) { case OpenACCDirectiveKind::Invalid: // Nothing to do here, an invalid kind has nothing we can check here. We @@ -855,11 +1109,12 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Loop: // Nothing to do here, there is no real legalization that needs to happen // here as these constructs do not take any arguments. break; default: - Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; + Diag(DirLoc, diag::warn_acc_construct_unimplemented) << K; break; } } @@ -1265,6 +1520,7 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult AssocStmt) { @@ -1275,16 +1531,34 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, return StmtError(); case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: - case OpenACCDirectiveKind::Kernels: - // TODO OpenACC: Add clauses to the construct here. - return OpenACCComputeConstruct::Create( - getASTContext(), K, StartLoc, EndLoc, Clauses, + case OpenACCDirectiveKind::Kernels: { + auto *ComputeConstruct = OpenACCComputeConstruct::Create( + getASTContext(), K, StartLoc, DirLoc, EndLoc, Clauses, + AssocStmt.isUsable() ? AssocStmt.get() : nullptr, + ParentlessLoopConstructs); + + ParentlessLoopConstructs.clear(); + return ComputeConstruct; + } + case OpenACCDirectiveKind::Loop: { + auto *LoopConstruct = OpenACCLoopConstruct::Create( + getASTContext(), StartLoc, DirLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); + + // If we are in the scope of a compute construct, add this to the list of + // loop constructs that need assigning to the next closing compute + // construct. + if (InsideComputeConstruct) + ParentlessLoopConstructs.push_back(LoopConstruct); + + return LoopConstruct; + } } llvm_unreachable("Unhandled case in directive handling?"); } -StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K, +StmtResult SemaOpenACC::ActOnAssociatedStmt(SourceLocation DirectiveLoc, + OpenACCDirectiveKind K, StmtResult AssocStmt) { switch (K) { default: @@ -1302,6 +1576,17 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K, // an interpretation of it is to allow this and treat the initializer as // the 'structured block'. return AssocStmt; + case OpenACCDirectiveKind::Loop: + if (AssocStmt.isUsable() && + !isa(AssocStmt.get())) { + Diag(AssocStmt.get()->getBeginLoc(), diag::err_acc_loop_not_for_loop); + Diag(DirectiveLoc, diag::note_acc_construct_here) << K; + return StmtError(); + } + // TODO OpenACC: 2.9 ~ line 2010 specifies that the associated loop has some + // restrictions when there is a 'seq' clause in place. We probably need to + // implement that, including piping in the clauses here. + return AssocStmt; } llvm_unreachable("Invalid associated statement application"); } diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3b495a15e02c34b44649e74351ca85ce34d81f9 --- /dev/null +++ b/clang/lib/Sema/SemaOpenCL.cpp @@ -0,0 +1,99 @@ +//===--- SemaOpenCL.cpp --- Semantic Analysis for OpenCL constructs -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements semantic analysis for OpenCL. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaOpenCL.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" + +namespace clang { +SemaOpenCL::SemaOpenCL(Sema &S) : SemaBase(S) {} + +void SemaOpenCL::handleNoSVMAttr(Decl *D, const ParsedAttr &AL) { + if (getLangOpts().getOpenCLCompatibleVersion() < 200) + Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) + << AL << "2.0" << 1; + else + Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL << getLangOpts().getOpenCLVersionString(); +} + +void SemaOpenCL::handleAccessAttr(Decl *D, const ParsedAttr &AL) { + if (D->isInvalidDecl()) + return; + + // Check if there is only one access qualifier. + if (D->hasAttr()) { + if (D->getAttr()->getSemanticSpelling() == + AL.getSemanticSpelling()) { + Diag(AL.getLoc(), diag::warn_duplicate_declspec) + << AL.getAttrName()->getName() << AL.getRange(); + } else { + Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) + << D->getSourceRange(); + D->setInvalidDecl(true); + return; + } + } + + // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that + // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel + // cannot read from and write to the same pipe object. Using the read_write + // (or __read_write) qualifier with the pipe qualifier is a compilation error. + // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the + // __opencl_c_read_write_images feature, image objects specified as arguments + // to a kernel can additionally be declared to be read-write. + // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0. + // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0. + if (const auto *PDecl = dyn_cast(D)) { + const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); + if (AL.getAttrName()->getName().contains("read_write")) { + bool ReadWriteImagesUnsupported = + (getLangOpts().getOpenCLCompatibleVersion() < 200) || + (getLangOpts().getOpenCLCompatibleVersion() == 300 && + !SemaRef.getOpenCLOptions().isSupported( + "__opencl_c_read_write_images", getLangOpts())); + if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) { + Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) + << AL << PDecl->getType() << DeclTy->isImageType(); + D->setInvalidDecl(true); + return; + } + } + } + + D->addAttr(::new (getASTContext()) OpenCLAccessAttr(getASTContext(), AL)); +} + +void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) { + uint32_t SGSize; + const Expr *E = AL.getArgAsExpr(0); + if (!SemaRef.checkUInt32Argument(AL, E, SGSize)) + return; + if (SGSize == 0) { + Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL << E->getSourceRange(); + return; + } + + OpenCLIntelReqdSubGroupSizeAttr *Existing = + D->getAttr(); + if (Existing && Existing->getSubGroupSize() != SGSize) + Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; + + D->addAttr(::new (getASTContext()) + OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize)); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 6110e5229b076cdf541807980bc789e0486b6872..6e6815328e91394136652ac57040e7e11c2dabf3 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -43,6 +43,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/IR/Assumptions.h" #include #include @@ -3074,11 +3075,11 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope, if (TypoCorrection Corrected = SemaRef.CorrectTypo(Id, Sema::LookupOrdinaryName, CurScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { - SemaRef.diagnoseTypo( - Corrected, - SemaRef.PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest - : diag::err_omp_expected_var_arg_suggest) - << Id.getName()); + SemaRef.diagnoseTypo(Corrected, + PDiag(Lookup.empty() + ? diag::err_undeclared_var_use_suggest + : diag::err_omp_expected_var_arg_suggest) + << Id.getName()); VD = Corrected.getCorrectionDeclAs(); } else { Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use @@ -7402,7 +7403,7 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( // Template specialization is an extension, check if we do it. bool IsTemplated = !TemplateParamLists.empty(); - if (IsTemplated & + if (IsTemplated && !DVScope.TI->isExtensionActive( llvm::omp::TraitProperty::implementation_extension_allow_templates)) return; @@ -7915,9 +7916,9 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, PartialDiagnostic::NullDiagnostic()), PartialDiagnosticAt( VariantRef->getExprLoc(), - SemaRef.PDiag(diag::err_omp_declare_variant_doesnt_support)), + PDiag(diag::err_omp_declare_variant_doesnt_support)), PartialDiagnosticAt(VariantRef->getExprLoc(), - SemaRef.PDiag(diag::err_omp_declare_variant_diff) + PDiag(diag::err_omp_declare_variant_diff) << FD->getLocation()), /*TemplatesSupported=*/true, /*ConstexprSupported=*/false, /*CLinkageMayDiffer=*/true)) @@ -9815,6 +9816,25 @@ static Stmt *buildPreInits(ASTContext &Context, return nullptr; } +/// Append the \p Item or the content of a CompoundStmt to the list \p +/// TargetList. +/// +/// A CompoundStmt is used as container in case multiple statements need to be +/// stored in lieu of using an explicit list. Flattening is necessary because +/// contained DeclStmts need to be visible after the execution of the list. Used +/// for OpenMP pre-init declarations/statements. +static void appendFlattendedStmtList(SmallVectorImpl &TargetList, + Stmt *Item) { + // nullptr represents an empty list. + if (!Item) + return; + + if (auto *CS = dyn_cast(Item)) + llvm::append_range(TargetList, CS->body()); + else + TargetList.push_back(Item); +} + /// Build preinits statement for the given declarations. static Stmt * buildPreInits(ASTContext &Context, @@ -9828,6 +9848,17 @@ buildPreInits(ASTContext &Context, return nullptr; } +/// Build pre-init statement for the given statements. +static Stmt *buildPreInits(ASTContext &Context, ArrayRef PreInits) { + if (PreInits.empty()) + return nullptr; + + SmallVector Stmts; + for (Stmt *S : PreInits) + appendFlattendedStmtList(Stmts, S); + return CompoundStmt::Create(Context, PreInits, FPOptionsOverride(), {}, {}); +} + /// Build postupdate expression for the given list of postupdates expressions. static Expr *buildPostUpdate(Sema &S, ArrayRef PostUpdates) { Expr *PostUpdate = nullptr; @@ -9924,11 +9955,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Stmt *DependentPreInits = Transform->getPreInits(); if (!DependentPreInits) return; - for (Decl *C : cast(DependentPreInits)->getDeclGroup()) { - auto *D = cast(C); - DeclRefExpr *Ref = buildDeclRefExpr(SemaRef, D, D->getType(), - Transform->getBeginLoc()); - Captures[Ref] = Ref; + + // Search for pre-init declared variables that need to be captured + // to be referenceable inside the directive. + SmallVector Constituents; + appendFlattendedStmtList(Constituents, DependentPreInits); + for (Stmt *S : Constituents) { + if (auto *DC = dyn_cast(S)) { + for (Decl *C : DC->decls()) { + auto *D = cast(C); + DeclRefExpr *Ref = buildDeclRefExpr( + SemaRef, D, D->getType().getNonReferenceType(), + Transform->getBeginLoc()); + Captures[Ref] = Ref; + } + } } })) return 0; @@ -15059,9 +15100,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective( bool SemaOpenMP::checkTransformableLoopNest( OpenMPDirectiveKind Kind, Stmt *AStmt, int NumLoops, SmallVectorImpl &LoopHelpers, - Stmt *&Body, - SmallVectorImpl, 0>> - &OriginalInits) { + Stmt *&Body, SmallVectorImpl> &OriginalInits) { OriginalInits.emplace_back(); bool Result = OMPLoopBasedDirective::doForAllLoops( AStmt->IgnoreContainers(), /*TryImperfectlyNestedLoops=*/false, NumLoops, @@ -15095,16 +15134,70 @@ bool SemaOpenMP::checkTransformableLoopNest( DependentPreInits = Dir->getPreInits(); else llvm_unreachable("Unhandled loop transformation"); - if (!DependentPreInits) - return; - llvm::append_range(OriginalInits.back(), - cast(DependentPreInits)->getDeclGroup()); + + appendFlattendedStmtList(OriginalInits.back(), DependentPreInits); }); assert(OriginalInits.back().empty() && "No preinit after innermost loop"); OriginalInits.pop_back(); return Result; } +/// Add preinit statements that need to be propageted from the selected loop. +static void addLoopPreInits(ASTContext &Context, + OMPLoopBasedDirective::HelperExprs &LoopHelper, + Stmt *LoopStmt, ArrayRef OriginalInit, + SmallVectorImpl &PreInits) { + + // For range-based for-statements, ensure that their syntactic sugar is + // executed by adding them as pre-init statements. + if (auto *CXXRangeFor = dyn_cast(LoopStmt)) { + Stmt *RangeInit = CXXRangeFor->getInit(); + if (RangeInit) + PreInits.push_back(RangeInit); + + DeclStmt *RangeStmt = CXXRangeFor->getRangeStmt(); + PreInits.push_back(new (Context) DeclStmt(RangeStmt->getDeclGroup(), + RangeStmt->getBeginLoc(), + RangeStmt->getEndLoc())); + + DeclStmt *RangeEnd = CXXRangeFor->getEndStmt(); + PreInits.push_back(new (Context) DeclStmt(RangeEnd->getDeclGroup(), + RangeEnd->getBeginLoc(), + RangeEnd->getEndLoc())); + } + + llvm::append_range(PreInits, OriginalInit); + + // List of OMPCapturedExprDecl, for __begin, __end, and NumIterations + if (auto *PI = cast_or_null(LoopHelper.PreInits)) { + PreInits.push_back(new (Context) DeclStmt( + PI->getDeclGroup(), PI->getBeginLoc(), PI->getEndLoc())); + } + + // Gather declarations for the data members used as counters. + for (Expr *CounterRef : LoopHelper.Counters) { + auto *CounterDecl = cast(CounterRef)->getDecl(); + if (isa(CounterDecl)) + PreInits.push_back(new (Context) DeclStmt( + DeclGroupRef(CounterDecl), SourceLocation(), SourceLocation())); + } +} + +/// Collect the loop statements (ForStmt or CXXRangeForStmt) of the affected +/// loop of a construct. +static void collectLoopStmts(Stmt *AStmt, MutableArrayRef LoopStmts) { + size_t NumLoops = LoopStmts.size(); + OMPLoopBasedDirective::doForAllLoops( + AStmt, /*TryImperfectlyNestedLoops=*/false, NumLoops, + [LoopStmts](unsigned Cnt, Stmt *CurStmt) { + assert(!LoopStmts[Cnt] && "Loop statement must not yet be assigned"); + LoopStmts[Cnt] = CurStmt; + return false; + }); + assert(!is_contained(LoopStmts, nullptr) && + "Expecting a loop statement for each affected loop"); +} + StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -15126,8 +15219,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, // Verify and diagnose loop nest. SmallVector LoopHelpers(NumLoops); Stmt *Body = nullptr; - SmallVector, 0>, 4> - OriginalInits; + SmallVector, 4> OriginalInits; if (!checkTransformableLoopNest(OMPD_tile, AStmt, NumLoops, LoopHelpers, Body, OriginalInits)) return StmtError(); @@ -15144,7 +15236,11 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, "Expecting loop iteration space dimensionality to match number of " "affected loops"); - SmallVector PreInits; + // Collect all affected loop statements. + SmallVector LoopStmts(NumLoops, nullptr); + collectLoopStmts(AStmt, LoopStmts); + + SmallVector PreInits; CaptureVars CopyTransformer(SemaRef); // Create iteration variables for the generated loops. @@ -15184,20 +15280,9 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, &SemaRef.PP.getIdentifierTable().get(TileCntName)); TileIndVars[I] = TileCntDecl; } - for (auto &P : OriginalInits[I]) { - if (auto *D = P.dyn_cast()) - PreInits.push_back(D); - else if (auto *PI = dyn_cast_or_null(P.dyn_cast())) - PreInits.append(PI->decl_begin(), PI->decl_end()); - } - if (auto *PI = cast_or_null(LoopHelper.PreInits)) - PreInits.append(PI->decl_begin(), PI->decl_end()); - // Gather declarations for the data members used as counters. - for (Expr *CounterRef : LoopHelper.Counters) { - auto *CounterDecl = cast(CounterRef)->getDecl(); - if (isa(CounterDecl)) - PreInits.push_back(CounterDecl); - } + + addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I], + PreInits); } // Once the original iteration values are set, append the innermost body. @@ -15246,19 +15331,20 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I]; Expr *NumIterations = LoopHelper.NumIterations; auto *OrigCntVar = cast(LoopHelper.Counters[0]); - QualType CntTy = OrigCntVar->getType(); + QualType IVTy = NumIterations->getType(); + Stmt *LoopStmt = LoopStmts[I]; // Commonly used variables. One of the constraints of an AST is that every // node object must appear at most once, hence we define lamdas that create // a new AST node at every use. - auto MakeTileIVRef = [&SemaRef = this->SemaRef, &TileIndVars, I, CntTy, + auto MakeTileIVRef = [&SemaRef = this->SemaRef, &TileIndVars, I, IVTy, OrigCntVar]() { - return buildDeclRefExpr(SemaRef, TileIndVars[I], CntTy, + return buildDeclRefExpr(SemaRef, TileIndVars[I], IVTy, OrigCntVar->getExprLoc()); }; - auto MakeFloorIVRef = [&SemaRef = this->SemaRef, &FloorIndVars, I, CntTy, + auto MakeFloorIVRef = [&SemaRef = this->SemaRef, &FloorIndVars, I, IVTy, OrigCntVar]() { - return buildDeclRefExpr(SemaRef, FloorIndVars[I], CntTy, + return buildDeclRefExpr(SemaRef, FloorIndVars[I], IVTy, OrigCntVar->getExprLoc()); }; @@ -15320,6 +15406,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, // further into the inner loop. SmallVector BodyParts; BodyParts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end()); + if (auto *SourceCXXFor = dyn_cast(LoopStmt)) + BodyParts.push_back(SourceCXXFor->getLoopVarStmt()); BodyParts.push_back(Inner); Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(), Inner->getBeginLoc(), Inner->getEndLoc()); @@ -15334,12 +15422,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef Clauses, auto &LoopHelper = LoopHelpers[I]; Expr *NumIterations = LoopHelper.NumIterations; DeclRefExpr *OrigCntVar = cast(LoopHelper.Counters[0]); - QualType CntTy = OrigCntVar->getType(); + QualType IVTy = NumIterations->getType(); - // Commonly used variables. - auto MakeFloorIVRef = [&SemaRef = this->SemaRef, &FloorIndVars, I, CntTy, + // Commonly used variables. One of the constraints of an AST is that every + // node object must appear at most once, hence we define lamdas that create + // a new AST node at every use. + auto MakeFloorIVRef = [&SemaRef = this->SemaRef, &FloorIndVars, I, IVTy, OrigCntVar]() { - return buildDeclRefExpr(SemaRef, FloorIndVars[I], CntTy, + return buildDeclRefExpr(SemaRef, FloorIndVars[I], IVTy, OrigCntVar->getExprLoc()); }; @@ -15405,8 +15495,7 @@ StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef Clauses, Stmt *Body = nullptr; SmallVector LoopHelpers( NumLoops); - SmallVector, 0>, NumLoops + 1> - OriginalInits; + SmallVector, NumLoops + 1> OriginalInits; if (!checkTransformableLoopNest(OMPD_unroll, AStmt, NumLoops, LoopHelpers, Body, OriginalInits)) return StmtError(); @@ -15418,6 +15507,10 @@ StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef Clauses, return OMPUnrollDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, NumGeneratedLoops, nullptr, nullptr); + assert(LoopHelpers.size() == NumLoops && + "Expecting a single-dimensional loop iteration space"); + assert(OriginalInits.size() == NumLoops && + "Expecting a single-dimensional loop iteration space"); OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front(); if (FullClause) { @@ -15481,24 +15574,13 @@ StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef Clauses, // of a canonical loop nest where these PreInits are emitted before the // outermost directive. + // Find the loop statement. + Stmt *LoopStmt = nullptr; + collectLoopStmts(AStmt, {LoopStmt}); + // Determine the PreInit declarations. - SmallVector PreInits; - assert(OriginalInits.size() == 1 && - "Expecting a single-dimensional loop iteration space"); - for (auto &P : OriginalInits[0]) { - if (auto *D = P.dyn_cast()) - PreInits.push_back(D); - else if (auto *PI = dyn_cast_or_null(P.dyn_cast())) - PreInits.append(PI->decl_begin(), PI->decl_end()); - } - if (auto *PI = cast_or_null(LoopHelper.PreInits)) - PreInits.append(PI->decl_begin(), PI->decl_end()); - // Gather declarations for the data members used as counters. - for (Expr *CounterRef : LoopHelper.Counters) { - auto *CounterDecl = cast(CounterRef)->getDecl(); - if (isa(CounterDecl)) - PreInits.push_back(CounterDecl); - } + SmallVector PreInits; + addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInits[0], PreInits); auto *IterationVarRef = cast(LoopHelper.IterationVarRef); QualType IVTy = IterationVarRef->getType(); @@ -15604,6 +15686,8 @@ StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef Clauses, // Inner For statement. SmallVector InnerBodyStmts; InnerBodyStmts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end()); + if (auto *CXXRangeFor = dyn_cast(LoopStmt)) + InnerBodyStmts.push_back(CXXRangeFor->getLoopVarStmt()); InnerBodyStmts.push_back(Body); CompoundStmt *InnerBody = CompoundStmt::Create(getASTContext(), InnerBodyStmts, FPOptionsOverride(), @@ -23612,7 +23696,7 @@ NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName( SemaRef.CorrectTypo(Id, Sema::LookupOrdinaryName, CurScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::err_undeclared_var_use_suggest) + PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); return nullptr; @@ -25289,5 +25373,42 @@ ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S, LLoc, RLoc, ID, Helpers); } +/// Check if \p AssumptionStr is a known assumption and warn if not. +static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc, + StringRef AssumptionStr) { + if (llvm::KnownAssumptionStrings.count(AssumptionStr)) + return; + + unsigned BestEditDistance = 3; + StringRef Suggestion; + for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) { + unsigned EditDistance = + AssumptionStr.edit_distance(KnownAssumptionIt.getKey()); + if (EditDistance < BestEditDistance) { + Suggestion = KnownAssumptionIt.getKey(); + BestEditDistance = EditDistance; + } + } + + if (!Suggestion.empty()) + S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown_suggested) + << AssumptionStr << Suggestion; + else + S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown) + << AssumptionStr; +} + +void SemaOpenMP::handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL) { + // Handle the case where the attribute has a text message. + StringRef Str; + SourceLocation AttrStrLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc)) + return; + + checkOMPAssumeAttr(SemaRef, AttrStrLoc, Str); + + D->addAttr(::new (getASTContext()) OMPAssumeAttr(getASTContext(), AL, Str)); +} + SemaOpenMP::SemaOpenMP(Sema &S) : SemaBase(S), VarDataSharingAttributesStack(nullptr) {} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 2eb25237a0de60ba3a18a6d27dbbf69595d87ab5..1b4bcdcb51160b29f62990c691f08f41acc716a7 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DependenceFlags.h" @@ -1481,7 +1482,7 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, } if (OldMethod && NewMethod && !OldMethod->isStatic() && - !OldMethod->isStatic()) { + !NewMethod->isStatic()) { bool HaveCorrespondingObjectParameters = [&](const CXXMethodDecl *Old, const CXXMethodDecl *New) { auto NewObjectType = New->getFunctionObjectParameterReferenceType(); @@ -6472,17 +6473,20 @@ ExprResult Sema::InitializeExplicitObjectArgument(Sema &S, Expr *Obj, Obj->getExprLoc(), Obj); } -static void PrepareExplicitObjectArgument(Sema &S, CXXMethodDecl *Method, +static bool PrepareExplicitObjectArgument(Sema &S, CXXMethodDecl *Method, Expr *Object, MultiExprArg &Args, SmallVectorImpl &NewArgs) { assert(Method->isExplicitObjectMemberFunction() && "Method is not an explicit member function"); assert(NewArgs.empty() && "NewArgs should be empty"); + NewArgs.reserve(Args.size() + 1); Expr *This = GetExplicitObjectExpr(S, Object, Method); NewArgs.push_back(This); NewArgs.append(Args.begin(), Args.end()); Args = NewArgs; + return S.DiagnoseInvalidExplicitObjectParameterInLambda( + Method, Object->getBeginLoc()); } /// Determine whether the provided type is an integral type, or an enumeration @@ -6968,6 +6972,7 @@ void Sema::AddOverloadCandidate( Candidate.IsSurrogate = false; Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); // Explicit functions are not actually candidates at all if we're not @@ -7542,10 +7547,24 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CandidateSet.getRewriteInfo().getRewriteKind(Method, PO); Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = + CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet; Candidate.ExplicitCallArguments = Args.size(); - unsigned NumParams = Method->getNumExplicitParams(); - unsigned ExplicitOffset = Method->isExplicitObjectMemberFunction() ? 1 : 0; + bool IgnoreExplicitObject = + (Method->isExplicitObjectMemberFunction() && + CandidateSet.getKind() == + OverloadCandidateSet::CSK_AddressOfOverloadSet); + bool ImplicitObjectMethodTreatedAsStatic = + CandidateSet.getKind() == + OverloadCandidateSet::CSK_AddressOfOverloadSet && + Method->isImplicitObjectMemberFunction(); + + unsigned ExplicitOffset = + !IgnoreExplicitObject && Method->isExplicitObjectMemberFunction() ? 1 : 0; + + unsigned NumParams = Method->getNumParams() - ExplicitOffset + + int(ImplicitObjectMethodTreatedAsStatic); // (C++ 13.3.2p2): A candidate function having fewer than m // parameters is viable only if it has an ellipsis in its parameter @@ -7563,7 +7582,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (8.3.6). For the purposes of overload resolution, the // parameter list is truncated on the right, so that there are // exactly m parameters. - unsigned MinRequiredArgs = Method->getMinRequiredExplicitArguments(); + unsigned MinRequiredArgs = Method->getMinRequiredArguments() - + ExplicitOffset + + int(ImplicitObjectMethodTreatedAsStatic); + if (Args.size() < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; @@ -7633,7 +7655,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // exist for each argument an implicit conversion sequence // (13.3.3.1) that converts that argument to the corresponding // parameter of F. - QualType ParamType = Proto->getParamType(ArgIdx + ExplicitOffset); + QualType ParamType; + if (ImplicitObjectMethodTreatedAsStatic) { + ParamType = ArgIdx == 0 + ? Method->getFunctionObjectParameterReferenceType() + : Proto->getParamType(ArgIdx - 1); + } else { + ParamType = Proto->getParamType(ArgIdx + ExplicitOffset); + } Candidate.Conversions[ConvIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, SuppressUserConversions, @@ -7714,6 +7743,7 @@ void Sema::AddMethodTemplateCandidate( Candidate.IgnoreObjectArgument = cast(Candidate.Function)->isStatic() || ObjectType.isNull(); + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; @@ -7804,6 +7834,7 @@ void Sema::AddTemplateOverloadCandidate( Candidate.IgnoreObjectArgument = isa(Candidate.Function) && !isa(Candidate.Function); + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; @@ -7995,6 +8026,7 @@ void Sema::AddConversionCandidate( Candidate.Function = Conversion; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); @@ -8197,6 +8229,7 @@ void Sema::AddTemplateConversionCandidate( Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = 1; Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); @@ -8237,6 +8270,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Viable = true; Candidate.IsSurrogate = true; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; Candidate.ExplicitCallArguments = Args.size(); // Determine the implicit conversion sequence for the implicit @@ -8462,6 +8496,7 @@ void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef Args, Candidate.Function = nullptr; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.TookAddressOfOverload = false; std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes); // Determine the implicit conversion sequences for each of the @@ -10363,7 +10398,7 @@ static bool sameFunctionParameterTypeLists(Sema &S, FunctionDecl *Fn1 = Cand1.Function; FunctionDecl *Fn2 = Cand2.Function; - if (Fn1->isVariadic() != Fn1->isVariadic()) + if (Fn1->isVariadic() != Fn2->isVariadic()) return false; if (!S.FunctionNonObjectParamTypesAreEqual( @@ -10926,6 +10961,12 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, if (Best->Function && Best->Function->isDeleted()) return OR_Deleted; + if (auto *M = dyn_cast_or_null(Best->Function); + Kind == CSK_AddressOfOverloadSet && M && + M->isImplicitObjectMemberFunction()) { + return OR_No_Viable_Function; + } + if (!EquivalentCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); @@ -11298,8 +11339,16 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, Expr *FromExpr = Conv.Bad.FromExpr; QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); - SourceRange ToParamRange = - !isObjectArgument ? Fn->getParamDecl(I)->getSourceRange() : SourceRange(); + SourceRange ToParamRange; + + // FIXME: In presence of parameter packs we can't determine parameter range + // reliably, as we don't have access to instantiation. + bool HasParamPack = + llvm::any_of(Fn->parameters().take_front(I), [](const ParmVarDecl *Parm) { + return Parm->isParameterPack(); + }); + if (!isObjectArgument && !HasParamPack) + ToParamRange = Fn->getParamDecl(I)->getSourceRange(); if (FromTy == S.Context.OverloadTy) { assert(FromExpr && "overload set argument came from implicit argument?"); @@ -11505,9 +11554,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, /// candidates. This is not covered by the more general DiagnoseArityMismatch() /// over a candidate in any candidate set. static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { + unsigned NumArgs, bool IsAddressOf = false) { FunctionDecl *Fn = Cand->Function; - unsigned MinParams = Fn->getMinRequiredArguments(); + unsigned MinParams = Fn->getMinRequiredExplicitArguments() + + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); // With invalid overloaded operators, it's possible that we think we // have an arity mismatch when in fact it looks like we have the @@ -11535,7 +11585,8 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, /// General arity mismatch diagnosis over a candidate in a candidate set. static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, - unsigned NumFormalArgs) { + unsigned NumFormalArgs, + bool IsAddressOf = false) { assert(isa(D) && "The templated declaration should at least be a function" " when diagnosing bad template argument deduction due to too many" @@ -11545,12 +11596,17 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, // TODO: treat calls to a missing default constructor as a special case const auto *FnTy = Fn->getType()->castAs(); - unsigned MinParams = Fn->getMinRequiredExplicitArguments(); + unsigned MinParams = Fn->getMinRequiredExplicitArguments() + + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); // at least / at most / exactly - bool HasExplicitObjectParam = Fn->hasCXXExplicitFunctionObjectParameter(); - unsigned ParamCount = FnTy->getNumParams() - (HasExplicitObjectParam ? 1 : 0); + bool HasExplicitObjectParam = + !IsAddressOf && Fn->hasCXXExplicitFunctionObjectParameter(); + + unsigned ParamCount = + Fn->getNumNonObjectParams() + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0); unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { if (MinParams != ParamCount || FnTy->isVariadic() || FnTy->isTemplateVariadic()) @@ -11570,7 +11626,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, std::pair FnKindPair = ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description); - if (modeCount == 1 && + if (modeCount == 1 && !IsAddressOf && Fn->getParamDecl(HasExplicitObjectParam ? 1 : 0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second @@ -11589,8 +11645,9 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, /// Arity mismatch diagnosis specific to a function overload candidate. static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned NumFormalArgs) { - if (!CheckArityMismatch(S, Cand, NumFormalArgs)) - DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs); + if (!CheckArityMismatch(S, Cand, NumFormalArgs, Cand->TookAddressOfOverload)) + DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs, + Cand->TookAddressOfOverload); } static TemplateDecl *getDescribedTemplate(Decl *Templated) { @@ -12030,6 +12087,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, Cand->FailureKind != ovl_fail_bad_conversion) return; + // Skip implicit member functions when trying to resolve + // the address of a an overload set for a function pointer. + if (Cand->TookAddressOfOverload && + !Cand->Function->hasCXXExplicitFunctionObjectParameter() && + !Cand->Function->isStatic()) + return; + // Note deleted candidates, but only if they're viable. if (Cand->Viable) { if (Fn->isDeleted()) { @@ -14073,6 +14137,21 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, } case OR_No_Viable_Function: { + if (*Best != CandidateSet->end() && + CandidateSet->getKind() == + clang::OverloadCandidateSet::CSK_AddressOfOverloadSet) { + if (CXXMethodDecl *M = + dyn_cast_if_present((*Best)->Function); + M && M->isImplicitObjectMemberFunction()) { + CandidateSet->NoteCandidates( + PartialDiagnosticAt( + Fn->getBeginLoc(), + SemaRef.PDiag(diag::err_member_call_without_object) << 0 << M), + SemaRef, OCD_AmbiguousCandidates, Args); + return ExprError(); + } + } + // Try to recover by looking for viable functions which the user might // have meant to call. ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, @@ -14164,8 +14243,10 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, Expr *ExecConfig, bool AllowTypoCorrection, bool CalleesAddressIsTaken) { - OverloadCandidateSet CandidateSet(Fn->getExprLoc(), - OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet( + Fn->getExprLoc(), CalleesAddressIsTaken + ? OverloadCandidateSet::CSK_AddressOfOverloadSet + : OverloadCandidateSet::CSK_Normal); ExprResult result; if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet, @@ -14351,7 +14432,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, if (Fn.isInvalid()) return ExprError(); return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), ArgsArray, - Context.DependentTy, VK, OpLoc, + Context.DependentTy, VK_PRValue, OpLoc, CurFPFeatureOverrides()); } @@ -15612,8 +15693,10 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, CallExpr *TheCall = nullptr; llvm::SmallVector NewArgs; if (Method->isExplicitObjectMemberFunction()) { - PrepareExplicitObjectArgument(*this, Method, MemExpr->getBase(), Args, - NewArgs); + if (PrepareExplicitObjectArgument(*this, Method, MemExpr->getBase(), Args, + NewArgs)) + return ExprError(); + // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr, @@ -15927,9 +16010,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Initialize the object parameter. llvm::SmallVector NewArgs; if (Method->isExplicitObjectMemberFunction()) { - // FIXME: we should do that during the definition of the lambda when we can. - DiagnoseInvalidExplicitObjectParameterInLambda(Method); - PrepareExplicitObjectArgument(*this, Method, Obj, Args, NewArgs); + IsError |= PrepareExplicitObjectArgument(*this, Method, Obj, Args, NewArgs); } else { ExprResult ObjRes = PerformImplicitObjectArgumentInitialization( Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method); @@ -16330,9 +16411,9 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); if (CXXMethodDecl *Method = dyn_cast(Fn)) { - if (Method->isStatic()) { - // Do nothing: static member functions aren't any different - // from non-member functions. + if (!Method->isImplicitObjectMemberFunction()) { + // Do nothing: the address of static and + // explicit object member functions is a (non-member) function pointer. } else { // Fix the subexpression, which really has to be an // UnresolvedLookupExpr holding an overloaded member function @@ -16390,7 +16471,10 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, } QualType Type = Fn->getType(); - ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue; + ExprValueKind ValueKind = + getLangOpts().CPlusPlus && !Fn->hasCXXExplicitFunctionObjectParameter() + ? VK_LValue + : VK_PRValue; // FIXME: Duplicated from BuildDeclarationNameExpr. if (unsigned BID = Fn->getBuiltinID()) { diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99f46b12e696830925f547b78eaa2db78b6f1651 --- /dev/null +++ b/clang/lib/Sema/SemaPPC.cpp @@ -0,0 +1,439 @@ +//===------ SemaPPC.cpp ------ PowerPC target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to PowerPC. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaPPC.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/APSInt.h" + +namespace clang { + +SemaPPC::SemaPPC(Sema &S) : SemaBase(S) {} + +void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { + const auto *ICE = dyn_cast(Arg->IgnoreParens()); + if (!ICE) + return; + + const auto *DR = dyn_cast(ICE->getSubExpr()); + if (!DR) + return; + + const auto *PD = dyn_cast(DR->getDecl()); + if (!PD || !PD->getType()->isRecordType()) + return; + + QualType ArgType = Arg->getType(); + for (const FieldDecl *FD : + ArgType->castAs()->getDecl()->fields()) { + if (const auto *AA = FD->getAttr()) { + CharUnits Alignment = getASTContext().toCharUnitsFromBits( + AA->getAlignment(getASTContext())); + if (Alignment.getQuantity() == 16) { + Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD; + Diag(Loc, diag::note_misaligned_member_used_here) << PD; + } + } + } +} + +static bool isPPC_64Builtin(unsigned BuiltinID) { + // These builtins only work on PPC 64bit targets. + switch (BuiltinID) { + case PPC::BI__builtin_divde: + case PPC::BI__builtin_divdeu: + case PPC::BI__builtin_bpermd: + case PPC::BI__builtin_pdepd: + case PPC::BI__builtin_pextd: + case PPC::BI__builtin_ppc_ldarx: + case PPC::BI__builtin_ppc_stdcx: + case PPC::BI__builtin_ppc_tdw: + case PPC::BI__builtin_ppc_trapd: + case PPC::BI__builtin_ppc_cmpeqb: + case PPC::BI__builtin_ppc_setb: + case PPC::BI__builtin_ppc_mulhd: + case PPC::BI__builtin_ppc_mulhdu: + case PPC::BI__builtin_ppc_maddhd: + case PPC::BI__builtin_ppc_maddhdu: + case PPC::BI__builtin_ppc_maddld: + case PPC::BI__builtin_ppc_load8r: + case PPC::BI__builtin_ppc_store8r: + case PPC::BI__builtin_ppc_insert_exp: + case PPC::BI__builtin_ppc_extract_sig: + case PPC::BI__builtin_ppc_addex: + case PPC::BI__builtin_darn: + case PPC::BI__builtin_darn_raw: + case PPC::BI__builtin_ppc_compare_and_swaplp: + case PPC::BI__builtin_ppc_fetch_and_addlp: + case PPC::BI__builtin_ppc_fetch_and_andlp: + case PPC::BI__builtin_ppc_fetch_and_orlp: + case PPC::BI__builtin_ppc_fetch_and_swaplp: + return true; + } + return false; +} + +bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + ASTContext &Context = getASTContext(); + unsigned i = 0, l = 0, u = 0; + bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; + llvm::APSInt Result; + + if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit) + return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) + << TheCall->getSourceRange(); + + switch (BuiltinID) { + default: + return false; + case PPC::BI__builtin_altivec_crypto_vshasigmaw: + case PPC::BI__builtin_altivec_crypto_vshasigmad: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15); + case PPC::BI__builtin_altivec_dss: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3); + case PPC::BI__builtin_tbegin: + case PPC::BI__builtin_tend: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1); + case PPC::BI__builtin_tsr: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 7); + case PPC::BI__builtin_tabortwc: + case PPC::BI__builtin_tabortdc: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31); + case PPC::BI__builtin_tabortwci: + case PPC::BI__builtin_tabortdci: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31); + // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', + // __builtin_(un)pack_longdouble are available only if long double uses IBM + // extended double representation. + case PPC::BI__builtin_unpack_longdouble: + if (SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1)) + return true; + [[fallthrough]]; + case PPC::BI__builtin_pack_longdouble: + if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) + return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) + << "ibmlongdouble"; + return false; + case PPC::BI__builtin_altivec_dst: + case PPC::BI__builtin_altivec_dstt: + case PPC::BI__builtin_altivec_dstst: + case PPC::BI__builtin_altivec_dststt: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3); + case PPC::BI__builtin_vsx_xxpermdi: + case PPC::BI__builtin_vsx_xxsldwi: + return BuiltinVSX(TheCall); + case PPC::BI__builtin_unpack_vector_int128: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); + case PPC::BI__builtin_altivec_vgnb: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 2, 7); + case PPC::BI__builtin_vsx_xxeval: + return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 255); + case PPC::BI__builtin_altivec_vsldbi: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); + case PPC::BI__builtin_altivec_vsrdbi: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); + case PPC::BI__builtin_vsx_xxpermx: + return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 7); + case PPC::BI__builtin_ppc_tw: + case PPC::BI__builtin_ppc_tdw: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 1, 31); + case PPC::BI__builtin_ppc_cmprb: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1); + // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must + // be a constant that represents a contiguous bit field. + case PPC::BI__builtin_ppc_rlwnm: + return SemaRef.ValueIsRunOfOnes(TheCall, 2); + case PPC::BI__builtin_ppc_rlwimi: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31) || + SemaRef.ValueIsRunOfOnes(TheCall, 3); + case PPC::BI__builtin_ppc_rldimi: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 63) || + SemaRef.ValueIsRunOfOnes(TheCall, 3); + case PPC::BI__builtin_ppc_addex: { + if (SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3)) + return true; + // Output warning for reserved values 1 to 3. + int ArgValue = + TheCall->getArg(2)->getIntegerConstantExpr(Context)->getSExtValue(); + if (ArgValue != 0) + Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour) + << ArgValue; + return false; + } + case PPC::BI__builtin_ppc_mtfsb0: + case PPC::BI__builtin_ppc_mtfsb1: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31); + case PPC::BI__builtin_ppc_mtfsf: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 255); + case PPC::BI__builtin_ppc_mtfsfi: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 7) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); + case PPC::BI__builtin_ppc_alignx: + return SemaRef.BuiltinConstantArgPower2(TheCall, 0); + case PPC::BI__builtin_ppc_rdlam: + return SemaRef.ValueIsRunOfOnes(TheCall, 2); + case PPC::BI__builtin_vsx_ldrmb: + case PPC::BI__builtin_vsx_strmb: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16); + case PPC::BI__builtin_altivec_vcntmbb: + case PPC::BI__builtin_altivec_vcntmbh: + case PPC::BI__builtin_altivec_vcntmbw: + case PPC::BI__builtin_altivec_vcntmbd: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); + case PPC::BI__builtin_vsx_xxgenpcvbm: + case PPC::BI__builtin_vsx_xxgenpcvhm: + case PPC::BI__builtin_vsx_xxgenpcvwm: + case PPC::BI__builtin_vsx_xxgenpcvdm: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3); + case PPC::BI__builtin_ppc_test_data_class: { + // Check if the first argument of the __builtin_ppc_test_data_class call is + // valid. The argument must be 'float' or 'double' or '__float128'. + QualType ArgType = TheCall->getArg(0)->getType(); + if (ArgType != QualType(Context.FloatTy) && + ArgType != QualType(Context.DoubleTy) && + ArgType != QualType(Context.Float128Ty)) + return Diag(TheCall->getBeginLoc(), + diag::err_ppc_invalid_test_data_class_type); + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 127); + } + case PPC::BI__builtin_ppc_maxfe: + case PPC::BI__builtin_ppc_minfe: + case PPC::BI__builtin_ppc_maxfl: + case PPC::BI__builtin_ppc_minfl: + case PPC::BI__builtin_ppc_maxfs: + case PPC::BI__builtin_ppc_minfs: { + if (Context.getTargetInfo().getTriple().isOSAIX() && + (BuiltinID == PPC::BI__builtin_ppc_maxfe || + BuiltinID == PPC::BI__builtin_ppc_minfe)) + return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type) + << "builtin" << true << 128 << QualType(Context.LongDoubleTy) + << false << Context.getTargetInfo().getTriple().str(); + // Argument type should be exact. + QualType ArgType = QualType(Context.LongDoubleTy); + if (BuiltinID == PPC::BI__builtin_ppc_maxfl || + BuiltinID == PPC::BI__builtin_ppc_minfl) + ArgType = QualType(Context.DoubleTy); + else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || + BuiltinID == PPC::BI__builtin_ppc_minfs) + ArgType = QualType(Context.FloatTy); + for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) + if (TheCall->getArg(I)->getType() != ArgType) + return Diag(TheCall->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; + return false; + } +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ + case PPC::BI__builtin_##Name: \ + return BuiltinPPCMMACall(TheCall, BuiltinID, Types); +#include "clang/Basic/BuiltinsPPC.def" + } + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u); +} + +// Check if the given type is a non-pointer PPC MMA type. This function is used +// in Sema to prevent invalid uses of restricted PPC MMA types. +bool SemaPPC::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) { + ASTContext &Context = getASTContext(); + if (Type->isPointerType() || Type->isArrayType()) + return false; + + QualType CoreType = Type.getCanonicalType().getUnqualifiedType(); +#define PPC_VECTOR_TYPE(Name, Id, Size) || CoreType == Context.Id##Ty + if (false +#include "clang/Basic/PPCTypes.def" + ) { + Diag(TypeLoc, diag::err_ppc_invalid_use_mma_type); + return true; + } + return false; +} + +/// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, +/// advancing the pointer over the consumed characters. The decoded type is +/// returned. If the decoded type represents a constant integer with a +/// constraint on its value then Mask is set to that value. The type descriptors +/// used in Str are specific to PPC MMA builtins and are documented in the file +/// defining the PPC builtins. +static QualType DecodePPCMMATypeFromStr(ASTContext &Context, const char *&Str, + unsigned &Mask) { + bool RequireICE = false; + ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; + switch (*Str++) { + case 'V': + return Context.getVectorType(Context.UnsignedCharTy, 16, + VectorKind::AltiVecVector); + case 'i': { + char *End; + unsigned size = strtoul(Str, &End, 10); + assert(End != Str && "Missing constant parameter constraint"); + Str = End; + Mask = size; + return Context.IntTy; + } + case 'W': { + char *End; + unsigned size = strtoul(Str, &End, 10); + assert(End != Str && "Missing PowerPC MMA type size"); + Str = End; + QualType Type; + switch (size) { +#define PPC_VECTOR_TYPE(typeName, Id, size) \ + case size: \ + Type = Context.Id##Ty; \ + break; +#include "clang/Basic/PPCTypes.def" + default: + llvm_unreachable("Invalid PowerPC MMA vector type"); + } + bool CheckVectorArgs = false; + while (!CheckVectorArgs) { + switch (*Str++) { + case '*': + Type = Context.getPointerType(Type); + break; + case 'C': + Type = Type.withConst(); + break; + default: + CheckVectorArgs = true; + --Str; + break; + } + } + return Type; + } + default: + return Context.DecodeTypeStr(--Str, Context, Error, RequireICE, true); + } +} + +bool SemaPPC::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeStr) { + + assert((TypeStr[0] != '\0') && + "Invalid types in PPC MMA builtin declaration"); + + ASTContext &Context = getASTContext(); + unsigned Mask = 0; + unsigned ArgNum = 0; + + // The first type in TypeStr is the type of the value returned by the + // builtin. So we first read that type and change the type of TheCall. + QualType type = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); + TheCall->setType(type); + + while (*TypeStr != '\0') { + Mask = 0; + QualType ExpectedType = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); + if (ArgNum >= TheCall->getNumArgs()) { + ArgNum++; + break; + } + + Expr *Arg = TheCall->getArg(ArgNum); + QualType PassedType = Arg->getType(); + QualType StrippedRVType = PassedType.getCanonicalType(); + + // Strip Restrict/Volatile qualifiers. + if (StrippedRVType.isRestrictQualified() || + StrippedRVType.isVolatileQualified()) + StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType(); + + // The only case where the argument type and expected type are allowed to + // mismatch is if the argument type is a non-void pointer (or array) and + // expected type is a void pointer. + if (StrippedRVType != ExpectedType) + if (!(ExpectedType->isVoidPointerType() && + (StrippedRVType->isPointerType() || StrippedRVType->isArrayType()))) + return Diag(Arg->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << PassedType << ExpectedType << 1 << 0 << 0; + + // If the value of the Mask is not 0, we have a constraint in the size of + // the integer argument so here we ensure the argument is a constant that + // is in the valid range. + if (Mask != 0 && + SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) + return true; + + ArgNum++; + } + + // In case we exited early from the previous loop, there are other types to + // read from TypeStr. So we need to read them all to ensure we have the right + // number of arguments in TheCall and if it is not the case, to display a + // better error message. + while (*TypeStr != '\0') { + (void)DecodePPCMMATypeFromStr(Context, TypeStr, Mask); + ArgNum++; + } + if (SemaRef.checkArgCount(TheCall, ArgNum)) + return true; + + return false; +} + +bool SemaPPC::BuiltinVSX(CallExpr *TheCall) { + unsigned ExpectedNumArgs = 3; + if (SemaRef.checkArgCount(TheCall, ExpectedNumArgs)) + return true; + + // Check the third argument is a compile time constant + if (!TheCall->getArg(2)->isIntegerConstantExpr(getASTContext())) + return Diag(TheCall->getBeginLoc(), + diag::err_vsx_builtin_nonconstant_argument) + << 3 /* argument index */ << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(2)->getBeginLoc(), + TheCall->getArg(2)->getEndLoc()); + + QualType Arg1Ty = TheCall->getArg(0)->getType(); + QualType Arg2Ty = TheCall->getArg(1)->getType(); + + // Check the type of argument 1 and argument 2 are vectors. + SourceLocation BuiltinLoc = TheCall->getBeginLoc(); + if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || + (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { + return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + } + + // Check the first two arguments are the same type. + if (!getASTContext().hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { + return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + } + + // When default clang type checking is turned off and the customized type + // checking is used, the returning type of the function must be explicitly + // set. Otherwise it is _Bool by default. + TheCall->setType(Arg1Ty); + + return false; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 26e13e87b1d6b65a0abb1fd964dfe097a2a6d422..fd4fc15c1fd79e5ace55099c3f1c1a6c044503c1 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1,4 +1,4 @@ -//==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==// +//===------ SemaRISCV.cpp ------- RISC-V target-specific routines ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,20 +6,26 @@ // //===----------------------------------------------------------------------===// // -// This file implements name lookup for RISC-V vector intrinsic. +// This file implements semantic analysis functions specific to RISC-V. // //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaRISCV.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/RISCVIntrinsicManager.h" #include "clang/Sema/Sema.h" #include "clang/Support/RISCVVIntrinsicUtils.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/TargetParser/RISCVTargetParser.h" #include #include #include @@ -166,7 +172,6 @@ private: // Mapping function name to RVVOverloadIntrinsicDef. StringMap OverloadIntrinsics; - // Create RVVIntrinsicDef. void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr, StringRef OverloadedSuffixStr, bool IsMask, @@ -342,18 +347,17 @@ void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics( /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P); } } // End for different LMUL - } // End for different TypeRange + } // End for different TypeRange } } void RISCVIntrinsicManagerImpl::InitIntrinsicList() { - if (S.DeclareRISCVVBuiltins && !ConstructedRISCVVBuiltins) { + if (S.RISCV().DeclareRVVBuiltins && !ConstructedRISCVVBuiltins) { ConstructedRISCVVBuiltins = true; - ConstructRVVIntrinsics(RVVIntrinsicRecords, - IntrinsicKind::RVV); + ConstructRVVIntrinsics(RVVIntrinsicRecords, IntrinsicKind::RVV); } - if (S.DeclareRISCVSiFiveVectorBuiltins && + if (S.RISCV().DeclareSiFiveVectorBuiltins && !ConstructedRISCVSiFiveVectorBuiltins) { ConstructedRISCVSiFiveVectorBuiltins = true; ConstructRVVIntrinsics(RVSiFiveVectorIntrinsicRecords, @@ -501,4 +505,988 @@ std::unique_ptr CreateRISCVIntrinsicManager(Sema &S) { return std::make_unique(S); } + +bool SemaRISCV::CheckLMUL(CallExpr *TheCall, unsigned ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + int64_t Val = Result.getSExtValue(); + if ((Val >= 0 && Val <= 3) || (Val >= 5 && Val <= 7)) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_invalid_lmul) + << Arg->getSourceRange(); +} + +static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall, + Sema &S, QualType Type, int EGW) { + assert((EGW == 128 || EGW == 256) && "EGW can only be 128 or 256 bits"); + + // LMUL * VLEN >= EGW + ASTContext::BuiltinVectorTypeInfo Info = + S.Context.getBuiltinVectorTypeInfo(Type->castAs()); + unsigned ElemSize = S.Context.getTypeSize(Info.ElementType); + unsigned MinElemCount = Info.EC.getKnownMinValue(); + + unsigned EGS = EGW / ElemSize; + // If EGS is less than or equal to the minimum number of elements, then the + // type is valid. + if (EGS <= MinElemCount) + return false; + + // Otherwise, we need vscale to be at least EGS / MinElemCont. + assert(EGS % MinElemCount == 0); + unsigned VScaleFactor = EGS / MinElemCount; + // Vscale is VLEN/RVVBitsPerBlock. + unsigned MinRequiredVLEN = VScaleFactor * llvm::RISCV::RVVBitsPerBlock; + std::string RequiredExt = "zvl" + std::to_string(MinRequiredVLEN) + "b"; + if (!TI.hasFeature(RequiredExt)) + return S.Diag(TheCall->getBeginLoc(), + diag::err_riscv_type_requires_extension) + << Type << RequiredExt; + + return false; +} + +bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + ASTContext &Context = getASTContext(); + // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, + // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. + switch (BuiltinID) { + default: + break; + case RISCVVector::BI__builtin_rvv_vmulhsu_vv: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_m: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_m: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv: + case RISCVVector::BI__builtin_rvv_vmulhu_vx: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_m: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_m: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vmulh_vv: + case RISCVVector::BI__builtin_rvv_vmulh_vx: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulh_vv_m: + case RISCVVector::BI__builtin_rvv_vmulh_vx_m: + case RISCVVector::BI__builtin_rvv_vmulh_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vv: + case RISCVVector::BI__builtin_rvv_vsmul_vx: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_m: + case RISCVVector::BI__builtin_rvv_vsmul_vx_m: + case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: { + ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo( + TheCall->getType()->castAs()); + + if (Context.getTypeSize(Info.ElementType) == 64 && !TI.hasFeature("v")) + return Diag(TheCall->getBeginLoc(), + diag::err_riscv_builtin_requires_extension) + << /* IsExtension */ true << TheCall->getSourceRange() << "v"; + + break; + } + } + + switch (BuiltinID) { + case RISCVVector::BI__builtin_rvv_vsetvli: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3) || + CheckLMUL(TheCall, 2); + case RISCVVector::BI__builtin_rvv_vsetvlimax: + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + CheckLMUL(TheCall, 1); + case RISCVVector::BI__builtin_rvv_vget_v: { + ASTContext::BuiltinVectorTypeInfo ResVecInfo = + Context.getBuiltinVectorTypeInfo(cast( + TheCall->getType().getCanonicalType().getTypePtr())); + ASTContext::BuiltinVectorTypeInfo VecInfo = + Context.getBuiltinVectorTypeInfo(cast( + TheCall->getArg(0)->getType().getCanonicalType().getTypePtr())); + unsigned MaxIndex; + if (VecInfo.NumVectors != 1) // vget for tuple type + MaxIndex = VecInfo.NumVectors; + else // vget for non-tuple type + MaxIndex = (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / + (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + } + case RISCVVector::BI__builtin_rvv_vset_v: { + ASTContext::BuiltinVectorTypeInfo ResVecInfo = + Context.getBuiltinVectorTypeInfo(cast( + TheCall->getType().getCanonicalType().getTypePtr())); + ASTContext::BuiltinVectorTypeInfo VecInfo = + Context.getBuiltinVectorTypeInfo(cast( + TheCall->getArg(2)->getType().getCanonicalType().getTypePtr())); + unsigned MaxIndex; + if (ResVecInfo.NumVectors != 1) // vset for tuple type + MaxIndex = ResVecInfo.NumVectors; + else // vset fo non-tuple type + MaxIndex = (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / + (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + } + // Vector Crypto + case RISCVVector::BI__builtin_rvv_vaeskf1_vi_tu: + case RISCVVector::BI__builtin_rvv_vaeskf2_vi_tu: + case RISCVVector::BI__builtin_rvv_vaeskf2_vi: + case RISCVVector::BI__builtin_rvv_vsm4k_vi_tu: { + QualType Op1Type = TheCall->getArg(0)->getType(); + QualType Op2Type = TheCall->getArg(1)->getType(); + return CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op1Type, 128) || + CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op2Type, 128) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31); + } + case RISCVVector::BI__builtin_rvv_vsm3c_vi_tu: + case RISCVVector::BI__builtin_rvv_vsm3c_vi: { + QualType Op1Type = TheCall->getArg(0)->getType(); + return CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op1Type, 256) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31); + } + case RISCVVector::BI__builtin_rvv_vaeskf1_vi: + case RISCVVector::BI__builtin_rvv_vsm4k_vi: { + QualType Op1Type = TheCall->getArg(0)->getType(); + return CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op1Type, 128) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + } + case RISCVVector::BI__builtin_rvv_vaesdf_vv: + case RISCVVector::BI__builtin_rvv_vaesdf_vs: + case RISCVVector::BI__builtin_rvv_vaesdm_vv: + case RISCVVector::BI__builtin_rvv_vaesdm_vs: + case RISCVVector::BI__builtin_rvv_vaesef_vv: + case RISCVVector::BI__builtin_rvv_vaesef_vs: + case RISCVVector::BI__builtin_rvv_vaesem_vv: + case RISCVVector::BI__builtin_rvv_vaesem_vs: + case RISCVVector::BI__builtin_rvv_vaesz_vs: + case RISCVVector::BI__builtin_rvv_vsm4r_vv: + case RISCVVector::BI__builtin_rvv_vsm4r_vs: + case RISCVVector::BI__builtin_rvv_vaesdf_vv_tu: + case RISCVVector::BI__builtin_rvv_vaesdf_vs_tu: + case RISCVVector::BI__builtin_rvv_vaesdm_vv_tu: + case RISCVVector::BI__builtin_rvv_vaesdm_vs_tu: + case RISCVVector::BI__builtin_rvv_vaesef_vv_tu: + case RISCVVector::BI__builtin_rvv_vaesef_vs_tu: + case RISCVVector::BI__builtin_rvv_vaesem_vv_tu: + case RISCVVector::BI__builtin_rvv_vaesem_vs_tu: + case RISCVVector::BI__builtin_rvv_vaesz_vs_tu: + case RISCVVector::BI__builtin_rvv_vsm4r_vv_tu: + case RISCVVector::BI__builtin_rvv_vsm4r_vs_tu: { + QualType Op1Type = TheCall->getArg(0)->getType(); + QualType Op2Type = TheCall->getArg(1)->getType(); + return CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op1Type, 128) || + CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op2Type, 128); + } + case RISCVVector::BI__builtin_rvv_vsha2ch_vv: + case RISCVVector::BI__builtin_rvv_vsha2cl_vv: + case RISCVVector::BI__builtin_rvv_vsha2ms_vv: + case RISCVVector::BI__builtin_rvv_vsha2ch_vv_tu: + case RISCVVector::BI__builtin_rvv_vsha2cl_vv_tu: + case RISCVVector::BI__builtin_rvv_vsha2ms_vv_tu: { + QualType Op1Type = TheCall->getArg(0)->getType(); + QualType Op2Type = TheCall->getArg(1)->getType(); + QualType Op3Type = TheCall->getArg(2)->getType(); + ASTContext::BuiltinVectorTypeInfo Info = + Context.getBuiltinVectorTypeInfo(Op1Type->castAs()); + uint64_t ElemSize = Context.getTypeSize(Info.ElementType); + if (ElemSize == 64 && !TI.hasFeature("zvknhb")) + return Diag(TheCall->getBeginLoc(), + diag::err_riscv_builtin_requires_extension) + << /* IsExtension */ true << TheCall->getSourceRange() << "zvknb"; + + return CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op1Type, + ElemSize * 4) || + CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op2Type, + ElemSize * 4) || + CheckInvalidVLENandLMUL(TI, TheCall, SemaRef, Op3Type, ElemSize * 4); + } + + case RISCVVector::BI__builtin_rvv_sf_vc_i_se: + // bit_27_26, bit_24_20, bit_11_7, simm5, sew, log2lmul + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, -16, 15) || + CheckLMUL(TheCall, 5); + case RISCVVector::BI__builtin_rvv_sf_vc_iv_se: + // bit_27_26, bit_11_7, vs2, simm5 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_v_i: + case RISCVVector::BI__builtin_rvv_sf_vc_v_i_se: + // bit_27_26, bit_24_20, simm5 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_v_iv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_iv_se: + // bit_27_26, vs2, simm5 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_ivv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_ivw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw_se: + // bit_27_26, vd, vs2, simm5 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 3, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_x_se: + // bit_27_26, bit_24_20, bit_11_7, xs1, sew, log2lmul + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31) || + CheckLMUL(TheCall, 5); + case RISCVVector::BI__builtin_rvv_sf_vc_xv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_vv_se: + // bit_27_26, bit_11_7, vs2, xs1/vs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_x: + case RISCVVector::BI__builtin_rvv_sf_vc_v_x_se: + // bit_27_26, bit_24-20, xs1 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case RISCVVector::BI__builtin_rvv_sf_vc_vvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_xvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_vvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_xvw_se: + // bit_27_26, vd, vs2, xs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_xv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vv_se: + // bit_27_26, vs2, xs1/vs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw_se: + // bit_27_26, vd, vs2, xs1/vs1 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3); + case RISCVVector::BI__builtin_rvv_sf_vc_fv_se: + // bit_26, bit_11_7, vs2, fs1 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1) || + SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); + case RISCVVector::BI__builtin_rvv_sf_vc_fvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_fvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw_se: + // bit_26, vd, vs2, fs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_fv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fv_se: + // bit_26, vs2, fs1 + return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1); + // Check if byteselect is in [0, 3] + case RISCV::BI__builtin_riscv_aes32dsi: + case RISCV::BI__builtin_riscv_aes32dsmi: + case RISCV::BI__builtin_riscv_aes32esi: + case RISCV::BI__builtin_riscv_aes32esmi: + case RISCV::BI__builtin_riscv_sm4ks: + case RISCV::BI__builtin_riscv_sm4ed: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3); + // Check if rnum is in [0, 10] + case RISCV::BI__builtin_riscv_aes64ks1i: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 10); + // Check if value range for vxrm is in [0, 3] + case RISCVVector::BI__builtin_rvv_vaaddu_vv: + case RISCVVector::BI__builtin_rvv_vaaddu_vx: + case RISCVVector::BI__builtin_rvv_vaadd_vv: + case RISCVVector::BI__builtin_rvv_vaadd_vx: + case RISCVVector::BI__builtin_rvv_vasubu_vv: + case RISCVVector::BI__builtin_rvv_vasubu_vx: + case RISCVVector::BI__builtin_rvv_vasub_vv: + case RISCVVector::BI__builtin_rvv_vasub_vx: + case RISCVVector::BI__builtin_rvv_vsmul_vv: + case RISCVVector::BI__builtin_rvv_vsmul_vx: + case RISCVVector::BI__builtin_rvv_vssra_vv: + case RISCVVector::BI__builtin_rvv_vssra_vx: + case RISCVVector::BI__builtin_rvv_vssrl_vv: + case RISCVVector::BI__builtin_rvv_vssrl_vx: + case RISCVVector::BI__builtin_rvv_vnclip_wv: + case RISCVVector::BI__builtin_rvv_vnclip_wx: + case RISCVVector::BI__builtin_rvv_vnclipu_wv: + case RISCVVector::BI__builtin_rvv_vnclipu_wx: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3); + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tu: + case RISCVVector::BI__builtin_rvv_vasub_vv_tu: + case RISCVVector::BI__builtin_rvv_vasub_vx_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: + case RISCVVector::BI__builtin_rvv_vssra_vv_tu: + case RISCVVector::BI__builtin_rvv_vssra_vx_tu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tu: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_m: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_m: + case RISCVVector::BI__builtin_rvv_vaadd_vv_m: + case RISCVVector::BI__builtin_rvv_vaadd_vx_m: + case RISCVVector::BI__builtin_rvv_vasubu_vv_m: + case RISCVVector::BI__builtin_rvv_vasubu_vx_m: + case RISCVVector::BI__builtin_rvv_vasub_vv_m: + case RISCVVector::BI__builtin_rvv_vasub_vx_m: + case RISCVVector::BI__builtin_rvv_vsmul_vv_m: + case RISCVVector::BI__builtin_rvv_vsmul_vx_m: + case RISCVVector::BI__builtin_rvv_vssra_vv_m: + case RISCVVector::BI__builtin_rvv_vssra_vx_m: + case RISCVVector::BI__builtin_rvv_vssrl_vv_m: + case RISCVVector::BI__builtin_rvv_vssrl_vx_m: + case RISCVVector::BI__builtin_rvv_vnclip_wv_m: + case RISCVVector::BI__builtin_rvv_vnclip_wx_m: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_m: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_m: + return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 3); + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tum: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_mu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tum: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_mu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tum: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tumu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_mu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tum: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tumu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_mu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tum: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_mu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tum: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_mu: + case RISCVVector::BI__builtin_rvv_vasub_vv_tum: + case RISCVVector::BI__builtin_rvv_vasub_vv_tumu: + case RISCVVector::BI__builtin_rvv_vasub_vv_mu: + case RISCVVector::BI__builtin_rvv_vasub_vx_tum: + case RISCVVector::BI__builtin_rvv_vasub_vx_tumu: + case RISCVVector::BI__builtin_rvv_vasub_vx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: + case RISCVVector::BI__builtin_rvv_vssra_vv_mu: + case RISCVVector::BI__builtin_rvv_vssra_vx_mu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_mu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_mu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_mu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_mu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_mu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: + case RISCVVector::BI__builtin_rvv_vssra_vv_tum: + case RISCVVector::BI__builtin_rvv_vssra_vx_tum: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tum: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tum: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tum: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tum: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tum: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: + case RISCVVector::BI__builtin_rvv_vssra_vv_tumu: + case RISCVVector::BI__builtin_rvv_vssra_vx_tumu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tumu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tumu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tumu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tumu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tumu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tumu: + return SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 3); + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 4); + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: + return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 4); + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: + return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 4); + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: + return SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 4); + case RISCV::BI__builtin_riscv_ntl_load: + case RISCV::BI__builtin_riscv_ntl_store: + DeclRefExpr *DRE = + cast(TheCall->getCallee()->IgnoreParenCasts()); + assert((BuiltinID == RISCV::BI__builtin_riscv_ntl_store || + BuiltinID == RISCV::BI__builtin_riscv_ntl_load) && + "Unexpected RISC-V nontemporal load/store builtin!"); + bool IsStore = BuiltinID == RISCV::BI__builtin_riscv_ntl_store; + unsigned NumArgs = IsStore ? 3 : 2; + + if (SemaRef.checkArgCountAtLeast(TheCall, NumArgs - 1)) + return true; + + if (SemaRef.checkArgCountAtMost(TheCall, NumArgs)) + return true; + + // Domain value should be compile-time constant. + // 2 <= domain <= 5 + if (TheCall->getNumArgs() == NumArgs && + SemaRef.BuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) + return true; + + Expr *PointerArg = TheCall->getArg(0); + ExprResult PointerArgResult = + SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg); + + if (PointerArgResult.isInvalid()) + return true; + PointerArg = PointerArgResult.get(); + + const PointerType *PtrType = PointerArg->getType()->getAs(); + if (!PtrType) { + Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer) + << PointerArg->getType() << PointerArg->getSourceRange(); + return true; + } + + QualType ValType = PtrType->getPointeeType(); + ValType = ValType.getUnqualifiedType(); + if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && + !ValType->isBlockPointerType() && !ValType->isFloatingType() && + !ValType->isVectorType() && !ValType->isRVVSizelessBuiltinType()) { + Diag(DRE->getBeginLoc(), + diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector) + << PointerArg->getType() << PointerArg->getSourceRange(); + return true; + } + + if (!IsStore) { + TheCall->setType(ValType); + return false; + } + + ExprResult ValArg = TheCall->getArg(1); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, ValType, /*consume*/ false); + ValArg = + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg); + if (ValArg.isInvalid()) + return true; + + TheCall->setArg(1, ValArg.get()); + TheCall->setType(Context.VoidTy); + return false; + } + + return false; +} + +void SemaRISCV::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap) { + ASTContext::BuiltinVectorTypeInfo Info = + SemaRef.Context.getBuiltinVectorTypeInfo(Ty->castAs()); + unsigned EltSize = SemaRef.Context.getTypeSize(Info.ElementType); + unsigned MinElts = Info.EC.getKnownMinValue(); + + if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) && + !FeatureMap.lookup("zve64d")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; + // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at + // least zve64x + else if (((EltSize == 64 && Info.ElementType->isIntegerType()) || + MinElts == 1) && + !FeatureMap.lookup("zve64x")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; + else if (Info.ElementType->isFloat16Type() && !FeatureMap.lookup("zvfh") && + !FeatureMap.lookup("zvfhmin")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) + << Ty << "zvfh or zvfhmin"; + else if (Info.ElementType->isBFloat16Type() && + !FeatureMap.lookup("experimental-zvfbfmin")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin"; + else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) && + !FeatureMap.lookup("zve32f")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; + // Given that caller already checked isRVVType() before calling this function, + // if we don't have at least zve32x supported, then we need to emit error. + else if (!FeatureMap.lookup("zve32x")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; +} + +/// Are the two types RVV-bitcast-compatible types? I.e. is bitcasting from the +/// first RVV type (e.g. an RVV scalable type) to the second type (e.g. an RVV +/// VLS type) allowed? +/// +/// This will also return false if the two given types do not make sense from +/// the perspective of RVV bitcasts. +bool SemaRISCV::isValidRVVBitcast(QualType srcTy, QualType destTy) { + assert(srcTy->isVectorType() || destTy->isVectorType()); + + auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { + if (!FirstType->isRVVSizelessBuiltinType()) + return false; + + const auto *VecTy = SecondType->getAs(); + return VecTy && VecTy->getVectorKind() == VectorKind::RVVFixedLengthData; + }; + + return ValidScalableConversion(srcTy, destTy) || + ValidScalableConversion(destTy, srcTy); +} + +void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { + // Warn about repeated attributes. + if (const auto *A = D->getAttr()) { + Diag(AL.getRange().getBegin(), + diag::warn_riscv_repeated_interrupt_attribute); + Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); + return; + } + + // Check the attribute argument. Argument is optional. + if (!AL.checkAtMostNumArgs(SemaRef, 1)) + return; + + StringRef Str; + SourceLocation ArgLoc; + + // 'machine'is the default interrupt mode. + if (AL.getNumArgs() == 0) + Str = "machine"; + else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + // Semantic checks for a function with the 'interrupt' attribute: + // - Must be a function. + // - Must have no parameters. + // - Must have the 'void' return type. + // - The attribute itself must either have no argument or one of the + // valid interrupt types, see [RISCVInterruptDocs]. + + if (D->getFunctionType() == nullptr) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*RISC-V*/ 2 << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*RISC-V*/ 2 << 1; + return; + } + + RISCVInterruptAttr::InterruptType Kind; + if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Str << ArgLoc; + return; + } + + D->addAttr(::new (getASTContext()) + RISCVInterruptAttr(getASTContext(), AL, Kind)); +} + +bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) { + return BuiltinID >= RISCV::FirstRVVBuiltin && + BuiltinID <= RISCV::LastRVVBuiltin; +} + +SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {} + } // namespace clang diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 18f6d8f03047376d55d760bd94b174d08a42f2d1..2b55c598d55c038791828b43a7c1f3c813f4fca4 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -10,6 +10,8 @@ #include "clang/Sema/SemaSYCL.h" #include "clang/AST/Mangle.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" @@ -156,3 +158,42 @@ ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc, return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); } + +void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) { + // The 'sycl_kernel' attribute applies only to function templates. + const auto *FD = cast(D); + const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate(); + assert(FT && "Function template is expected"); + + // Function template must have at least two template parameters. + const TemplateParameterList *TL = FT->getTemplateParameters(); + if (TL->size() < 2) { + Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params); + return; + } + + // Template parameters must be typenames. + for (unsigned I = 0; I < 2; ++I) { + const NamedDecl *TParam = TL->getParam(I); + if (isa(TParam)) { + Diag(FT->getLocation(), + diag::warn_sycl_kernel_invalid_template_param_type); + return; + } + } + + // Function must have at least one argument. + if (getFunctionOrMethodNumParams(D) != 1) { + Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params); + return; + } + + // Function must return void. + QualType RetTy = getFunctionOrMethodResultType(D); + if (!RetTy->isVoidType()) { + Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type); + return; + } + + handleSimpleAttribute(*this, D, AL); +} diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 36f8ecadcfab7df0d9383c03c5b54e3614093f3b..6f538ed55cb72e6e929370f7ae1d26c464a7334d 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -285,7 +285,7 @@ bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt, static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { NoInlineAttr NIA(S.Context, A); - if (!NIA.isClangNoInline()) { + if (!NIA.isStmtNoInline()) { S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt) << "[[clang::noinline]]"; return nullptr; @@ -665,7 +665,8 @@ bool Sema::CheckRebuiltStmtAttributes(ArrayRef Attrs) { ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A, SourceRange Range) { if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) { - Diag(A.getLoc(), diag::err_assume_attr_args) << A.getAttrName() << Range; + Diag(A.getLoc(), diag::err_attribute_wrong_number_arguments) + << A.getAttrName() << 1 << Range; return ExprError(); } @@ -682,7 +683,8 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A, Assumption = Res.get(); } - if (!getLangOpts().CPlusPlus23) + if (!getLangOpts().CPlusPlus23 && + A.getSyntax() == AttributeCommonInfo::AS_CXX11) Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range; return Assumption; diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf56ae8ac76d572bbf38444fb3ca2c2ae26f76c8 --- /dev/null +++ b/clang/lib/Sema/SemaSwift.cpp @@ -0,0 +1,765 @@ +//===------ SemaSwift.cpp ------ Swift language-specific routines ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to Swift. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaSwift.h" +#include "clang/AST/DeclBase.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaObjC.h" + +namespace clang { +SemaSwift::SemaSwift(Sema &S) : SemaBase(S) {} + +SwiftNameAttr *SemaSwift::mergeNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name) { + if (const auto *PrevSNA = D->getAttr()) { + if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { + Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) + << PrevSNA << &SNA + << (PrevSNA->isRegularKeywordAttribute() || + SNA.isRegularKeywordAttribute()); + Diag(SNA.getLoc(), diag::note_conflicting_attribute); + } + + D->dropAttr(); + } + return ::new (getASTContext()) SwiftNameAttr(getASTContext(), SNA, Name); +} + +/// Pointer-like types in the default address space. +static bool isValidSwiftContextType(QualType Ty) { + if (!Ty->hasPointerRepresentation()) + return Ty->isDependentType(); + return Ty->getPointeeType().getAddressSpace() == LangAS::Default; +} + +/// Pointers and references in the default address space. +static bool isValidSwiftIndirectResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs()) { + Ty = RefType->getPointeeType(); + } else { + return Ty->isDependentType(); + } + return Ty.getAddressSpace() == LangAS::Default; +} + +/// Pointers and references to pointers in the default address space. +static bool isValidSwiftErrorResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs()) { + Ty = RefType->getPointeeType(); + } else { + return Ty->isDependentType(); + } + if (!Ty.getQualifiers().empty()) + return false; + return isValidSwiftContextType(Ty); +} + +void SemaSwift::handleAttrAttr(Decl *D, const ParsedAttr &AL) { + // Make sure that there is a string literal as the annotation's single + // argument. + StringRef Str; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str)) + return; + + D->addAttr(::new (getASTContext()) SwiftAttrAttr(getASTContext(), AL, Str)); +} + +void SemaSwift::handleBridge(Decl *D, const ParsedAttr &AL) { + // Make sure that there is a string literal as the annotation's single + // argument. + StringRef BT; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, BT)) + return; + + // Warn about duplicate attributes if they have different arguments, but drop + // any duplicate attributes regardless. + if (const auto *Other = D->getAttr()) { + if (Other->getSwiftType() != BT) + Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; + return; + } + + D->addAttr(::new (getASTContext()) SwiftBridgeAttr(getASTContext(), AL, BT)); +} + +static bool isErrorParameter(Sema &S, QualType QT) { + const auto *PT = QT->getAs(); + if (!PT) + return false; + + QualType Pointee = PT->getPointeeType(); + + // Check for NSError**. + if (const auto *OPT = Pointee->getAs()) + if (const auto *ID = OPT->getInterfaceDecl()) + if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) + return true; + + // Check for CFError**. + if (const auto *PT = Pointee->getAs()) + if (const auto *RT = PT->getPointeeType()->getAs()) + if (S.ObjC().isCFError(RT->getDecl())) + return true; + + return false; +} + +void SemaSwift::handleError(Decl *D, const ParsedAttr &AL) { + auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + if (isErrorParameter(S, getFunctionOrMethodParamType(D, I))) + return true; + } + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter) + << AL << isa(D); + return false; + }; + + auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + // - C, ObjC, and block pointers are definitely okay. + // - References are definitely not okay. + // - nullptr_t is weird, but acceptable. + QualType RT = getFunctionOrMethodResultType(D); + if (RT->hasPointerRepresentation() && !RT->isReferenceType()) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa(D) + << /*pointer*/ 1; + return false; + }; + + auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + QualType RT = getFunctionOrMethodResultType(D); + if (RT->isIntegralType(S.Context)) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa(D) + << /*integral*/ 0; + return false; + }; + + if (D->isInvalidDecl()) + return; + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + SwiftErrorAttr::ConventionKind Convention; + if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(), + Convention)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Loc->Ident; + return; + } + + switch (Convention) { + case SwiftErrorAttr::None: + // No additional validation required. + break; + + case SwiftErrorAttr::NonNullError: + if (!hasErrorParameter(SemaRef, D, AL)) + return; + break; + + case SwiftErrorAttr::NullResult: + if (!hasErrorParameter(SemaRef, D, AL) || !hasPointerResult(SemaRef, D, AL)) + return; + break; + + case SwiftErrorAttr::NonZeroResult: + case SwiftErrorAttr::ZeroResult: + if (!hasErrorParameter(SemaRef, D, AL) || !hasIntegerResult(SemaRef, D, AL)) + return; + break; + } + + D->addAttr(::new (getASTContext()) + SwiftErrorAttr(getASTContext(), AL, Convention)); +} + +static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D, + const SwiftAsyncErrorAttr *ErrorAttr, + const SwiftAsyncAttr *AsyncAttr) { + if (AsyncAttr->getKind() == SwiftAsyncAttr::None) { + if (ErrorAttr->getConvention() != SwiftAsyncErrorAttr::None) { + S.Diag(AsyncAttr->getLocation(), + diag::err_swift_async_error_without_swift_async) + << AsyncAttr << isa(D); + } + return; + } + + const ParmVarDecl *HandlerParam = getFunctionOrMethodParam( + D, AsyncAttr->getCompletionHandlerIndex().getASTIndex()); + // handleSwiftAsyncAttr already verified the type is correct, so no need to + // double-check it here. + const auto *FuncTy = HandlerParam->getType() + ->castAs() + ->getPointeeType() + ->getAs(); + ArrayRef BlockParams; + if (FuncTy) + BlockParams = FuncTy->getParamTypes(); + + switch (ErrorAttr->getConvention()) { + case SwiftAsyncErrorAttr::ZeroArgument: + case SwiftAsyncErrorAttr::NonZeroArgument: { + uint32_t ParamIdx = ErrorAttr->getHandlerParamIdx(); + if (ParamIdx == 0 || ParamIdx > BlockParams.size()) { + S.Diag(ErrorAttr->getLocation(), + diag::err_attribute_argument_out_of_bounds) + << ErrorAttr << 2; + return; + } + QualType ErrorParam = BlockParams[ParamIdx - 1]; + if (!ErrorParam->isIntegralType(S.Context)) { + StringRef ConvStr = + ErrorAttr->getConvention() == SwiftAsyncErrorAttr::ZeroArgument + ? "zero_argument" + : "nonzero_argument"; + S.Diag(ErrorAttr->getLocation(), diag::err_swift_async_error_non_integral) + << ErrorAttr << ConvStr << ParamIdx << ErrorParam; + return; + } + break; + } + case SwiftAsyncErrorAttr::NonNullError: { + bool AnyErrorParams = false; + for (QualType Param : BlockParams) { + // Check for NSError *. + if (const auto *ObjCPtrTy = Param->getAs()) { + if (const auto *ID = ObjCPtrTy->getInterfaceDecl()) { + if (ID->getIdentifier() == S.ObjC().getNSErrorIdent()) { + AnyErrorParams = true; + break; + } + } + } + // Check for CFError *. + if (const auto *PtrTy = Param->getAs()) { + if (const auto *RT = PtrTy->getPointeeType()->getAs()) { + if (S.ObjC().isCFError(RT->getDecl())) { + AnyErrorParams = true; + break; + } + } + } + } + + if (!AnyErrorParams) { + S.Diag(ErrorAttr->getLocation(), + diag::err_swift_async_error_no_error_parameter) + << ErrorAttr << isa(D); + return; + } + break; + } + case SwiftAsyncErrorAttr::None: + break; + } +} + +void SemaSwift::handleAsyncError(Decl *D, const ParsedAttr &AL) { + IdentifierLoc *IDLoc = AL.getArgAsIdent(0); + SwiftAsyncErrorAttr::ConventionKind ConvKind; + if (!SwiftAsyncErrorAttr::ConvertStrToConventionKind(IDLoc->Ident->getName(), + ConvKind)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << IDLoc->Ident; + return; + } + + uint32_t ParamIdx = 0; + switch (ConvKind) { + case SwiftAsyncErrorAttr::ZeroArgument: + case SwiftAsyncErrorAttr::NonZeroArgument: { + if (!AL.checkExactlyNumArgs(SemaRef, 2)) + return; + + Expr *IdxExpr = AL.getArgAsExpr(1); + if (!SemaRef.checkUInt32Argument(AL, IdxExpr, ParamIdx)) + return; + break; + } + case SwiftAsyncErrorAttr::NonNullError: + case SwiftAsyncErrorAttr::None: { + if (!AL.checkExactlyNumArgs(SemaRef, 1)) + return; + break; + } + } + + auto *ErrorAttr = ::new (getASTContext()) + SwiftAsyncErrorAttr(getASTContext(), AL, ConvKind, ParamIdx); + D->addAttr(ErrorAttr); + + if (auto *AsyncAttr = D->getAttr()) + checkSwiftAsyncErrorBlock(SemaRef, D, ErrorAttr, AsyncAttr); +} + +// For a function, this will validate a compound Swift name, e.g. +// init(foo:bar:baz:) or controllerForName(_:), and +// the function will output the number of parameter names, and whether this is a +// single-arg initializer. +// +// For a type, enum constant, property, or variable declaration, this will +// validate either a simple identifier, or a qualified +// context.identifier name. +static bool validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, + SourceLocation Loc, StringRef Name, + unsigned &SwiftParamCount, + bool &IsSingleParamInit) { + SwiftParamCount = 0; + IsSingleParamInit = false; + + // Check whether this will be mapped to a getter or setter of a property. + bool IsGetter = false, IsSetter = false; + if (Name.consume_front("getter:")) + IsGetter = true; + else if (Name.consume_front("setter:")) + IsSetter = true; + + if (Name.back() != ')') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + bool IsMember = false; + StringRef ContextName, BaseName, Parameters; + + std::tie(BaseName, Parameters) = Name.split('('); + + // Split at the first '.', if it exists, which separates the context name + // from the base name. + std::tie(ContextName, BaseName) = BaseName.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*context*/ 1; + return false; + } else { + IsMember = true; + } + + if (!isValidAsciiIdentifier(BaseName) || BaseName == "_") { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*basename*/ 0; + return false; + } + + bool IsSubscript = BaseName == "subscript"; + // A subscript accessor must be a getter or setter. + if (IsSubscript && !IsGetter && !IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* getter or setter */ 0; + return false; + } + + if (Parameters.empty()) { + S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL; + return false; + } + + assert(Parameters.back() == ')' && "expected ')'"); + Parameters = Parameters.drop_back(); // ')' + + if (Parameters.empty()) { + // Setters and subscripts must have at least one parameter. + if (IsSubscript) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* have at least one parameter */ 1; + return false; + } + + if (IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL; + return false; + } + + return true; + } + + if (Parameters.back() != ':') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + StringRef CurrentParam; + std::optional SelfLocation; + unsigned NewValueCount = 0; + std::optional NewValueLocation; + do { + std::tie(CurrentParam, Parameters) = Parameters.split(':'); + + if (!isValidAsciiIdentifier(CurrentParam)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*parameter*/ 2; + return false; + } + + if (IsMember && CurrentParam == "self") { + // "self" indicates the "self" argument for a member. + + // More than one "self"? + if (SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL; + return false; + } + + // The "self" location is the current parameter. + SelfLocation = SwiftParamCount; + } else if (CurrentParam == "newValue") { + // "newValue" indicates the "newValue" argument for a setter. + + // There should only be one 'newValue', but it's only significant for + // subscript accessors, so don't error right away. + ++NewValueCount; + + NewValueLocation = SwiftParamCount; + } + + ++SwiftParamCount; + } while (!Parameters.empty()); + + // Only instance subscripts are currently supported. + if (IsSubscript && !SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /*have a 'self:' parameter*/ 2; + return false; + } + + IsSingleParamInit = + SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_"; + + // Check the number of parameters for a getter/setter. + if (IsGetter || IsSetter) { + // Setters have one parameter for the new value. + unsigned NumExpectedParams = IsGetter ? 0 : 1; + unsigned ParamDiag = IsGetter + ? diag::warn_attr_swift_name_getter_parameters + : diag::warn_attr_swift_name_setter_parameters; + + // Instance methods have one parameter for "self". + if (SelfLocation) + ++NumExpectedParams; + + // Subscripts may have additional parameters beyond the expected params for + // the index. + if (IsSubscript) { + if (SwiftParamCount < NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + + // A subscript setter must explicitly label its newValue parameter to + // distinguish it from index parameters. + if (IsSetter) { + if (!NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue) + << AL; + return false; + } + if (NewValueCount > 1) { + S.Diag(Loc, + diag::warn_attr_swift_name_subscript_setter_multiple_newValues) + << AL; + return false; + } + } else { + // Subscript getters should have no 'newValue:' parameter. + if (NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue) + << AL; + return false; + } + } + } else { + // Property accessors must have exactly the number of expected params. + if (SwiftParamCount != NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + } + } + + return true; +} + +bool SemaSwift::DiagnoseName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL, bool IsAsync) { + if (isa(D) || isa(D)) { + ArrayRef Params; + unsigned ParamCount; + + if (const auto *Method = dyn_cast(D)) { + ParamCount = Method->getSelector().getNumArgs(); + Params = Method->parameters().slice(0, ParamCount); + } else { + const auto *F = cast(D); + + ParamCount = F->getNumParams(); + Params = F->parameters(); + + if (!F->hasWrittenPrototype()) { + Diag(Loc, diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionWithProtoType; + return false; + } + } + + // The async name drops the last callback parameter. + if (IsAsync) { + if (ParamCount == 0) { + Diag(Loc, diag::warn_attr_swift_name_decl_missing_params) + << AL << isa(D); + return false; + } + ParamCount -= 1; + } + + unsigned SwiftParamCount; + bool IsSingleParamInit; + if (!validateSwiftFunctionName(SemaRef, AL, Loc, Name, SwiftParamCount, + IsSingleParamInit)) + return false; + + bool ParamCountValid; + if (SwiftParamCount == ParamCount) { + ParamCountValid = true; + } else if (SwiftParamCount > ParamCount) { + ParamCountValid = IsSingleParamInit && ParamCount == 0; + } else { + // We have fewer Swift parameters than Objective-C parameters, but that + // might be because we've transformed some of them. Check for potential + // "out" parameters and err on the side of not warning. + unsigned MaybeOutParamCount = + llvm::count_if(Params, [](const ParmVarDecl *Param) -> bool { + QualType ParamTy = Param->getType(); + if (ParamTy->isReferenceType() || ParamTy->isPointerType()) + return !ParamTy->getPointeeType().isConstQualified(); + return false; + }); + + ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount; + } + + if (!ParamCountValid) { + Diag(Loc, diag::warn_attr_swift_name_num_params) + << (SwiftParamCount > ParamCount) << AL << ParamCount + << SwiftParamCount; + return false; + } + } else if ((isa(D) || isa(D) || + isa(D) || isa(D) || + isa(D) || isa(D) || isa(D) || + isa(D) || isa(D)) && + !IsAsync) { + StringRef ContextName, BaseName; + + std::tie(ContextName, BaseName) = Name.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (!isValidAsciiIdentifier(ContextName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*context*/ 1; + return false; + } + + if (!isValidAsciiIdentifier(BaseName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*basename*/ 0; + return false; + } + } else { + Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL; + return false; + } + return true; +} + +void SemaSwift::handleName(Decl *D, const ParsedAttr &AL) { + StringRef Name; + SourceLocation Loc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) + return; + + if (!DiagnoseName(D, Name, Loc, AL, /*IsAsync=*/false)) + return; + + D->addAttr(::new (getASTContext()) SwiftNameAttr(getASTContext(), AL, Name)); +} + +void SemaSwift::handleAsyncName(Decl *D, const ParsedAttr &AL) { + StringRef Name; + SourceLocation Loc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) + return; + + if (!DiagnoseName(D, Name, Loc, AL, /*IsAsync=*/true)) + return; + + D->addAttr(::new (getASTContext()) + SwiftAsyncNameAttr(getASTContext(), AL, Name)); +} + +void SemaSwift::handleNewType(Decl *D, const ParsedAttr &AL) { + // Make sure that there is an identifier as the annotation's single argument. + if (!AL.checkExactlyNumArgs(SemaRef, 1)) + return; + + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + SwiftNewTypeAttr::NewtypeKind Kind; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) { + Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; + return; + } + + if (!isa(D)) { + Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) + << AL << AL.isRegularKeywordAttribute() << "typedefs"; + return; + } + + D->addAttr(::new (getASTContext()) + SwiftNewTypeAttr(getASTContext(), AL, Kind)); +} + +void SemaSwift::handleAsyncAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + SwiftAsyncAttr::Kind Kind; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!SwiftAsyncAttr::ConvertStrToKind(II->getName(), Kind)) { + Diag(AL.getLoc(), diag::err_swift_async_no_access) << AL << II; + return; + } + + ParamIdx Idx; + if (Kind == SwiftAsyncAttr::None) { + // If this is 'none', then there shouldn't be any additional arguments. + if (!AL.checkExactlyNumArgs(SemaRef, 1)) + return; + } else { + // Non-none swift_async requires a completion handler index argument. + if (!AL.checkExactlyNumArgs(SemaRef, 2)) + return; + + Expr *HandlerIdx = AL.getArgAsExpr(1); + if (!SemaRef.checkFunctionOrMethodParameterIndex(D, AL, 2, HandlerIdx, Idx)) + return; + + const ParmVarDecl *CompletionBlock = + getFunctionOrMethodParam(D, Idx.getASTIndex()); + QualType CompletionBlockType = CompletionBlock->getType(); + if (!CompletionBlockType->isBlockPointerType()) { + Diag(CompletionBlock->getLocation(), diag::err_swift_async_bad_block_type) + << CompletionBlock->getType(); + return; + } + QualType BlockTy = + CompletionBlockType->castAs()->getPointeeType(); + if (!BlockTy->castAs()->getReturnType()->isVoidType()) { + Diag(CompletionBlock->getLocation(), diag::err_swift_async_bad_block_type) + << CompletionBlock->getType(); + return; + } + } + + auto *AsyncAttr = + ::new (getASTContext()) SwiftAsyncAttr(getASTContext(), AL, Kind, Idx); + D->addAttr(AsyncAttr); + + if (auto *ErrorAttr = D->getAttr()) + checkSwiftAsyncErrorBlock(SemaRef, D, ErrorAttr, AsyncAttr); +} + +void SemaSwift::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, + ParameterABI abi) { + ASTContext &Context = getASTContext(); + QualType type = cast(D)->getType(); + + if (auto existingAttr = D->getAttr()) { + if (existingAttr->getABI() != abi) { + Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) + << getParameterABISpelling(abi) << existingAttr + << (CI.isRegularKeywordAttribute() || + existingAttr->isRegularKeywordAttribute()); + Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); + return; + } + } + + switch (abi) { + case ParameterABI::Ordinary: + llvm_unreachable("explicit attribute for ordinary parameter ABI?"); + + case ParameterABI::SwiftContext: + if (!isValidSwiftContextType(type)) { + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type; + } + D->addAttr(::new (Context) SwiftContextAttr(Context, CI)); + return; + + case ParameterABI::SwiftAsyncContext: + if (!isValidSwiftContextType(type)) { + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type; + } + D->addAttr(::new (Context) SwiftAsyncContextAttr(Context, CI)); + return; + + case ParameterABI::SwiftErrorResult: + if (!isValidSwiftErrorResultType(type)) { + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type; + } + D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI)); + return; + + case ParameterABI::SwiftIndirectResult: + if (!isValidSwiftIndirectResultType(type)) { + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer*/ 0 << type; + } + D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI)); + return; + } + llvm_unreachable("bad parameter ABI attribute"); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaSystemZ.cpp b/clang/lib/Sema/SemaSystemZ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e836adbee659590476bd9d1ae854b5160e341f2 --- /dev/null +++ b/clang/lib/Sema/SemaSystemZ.cpp @@ -0,0 +1,94 @@ +//===------ SemaSystemZ.cpp ------ SystemZ target-specific routines -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to SystemZ. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaSystemZ.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/APSInt.h" +#include + +namespace clang { + +SemaSystemZ::SemaSystemZ(Sema &S) : SemaBase(S) {} + +bool SemaSystemZ::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + if (BuiltinID == SystemZ::BI__builtin_tabort) { + Expr *Arg = TheCall->getArg(0); + if (std::optional AbortCode = + Arg->getIntegerConstantExpr(getASTContext())) + if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256) + return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code) + << Arg->getSourceRange(); + } + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: return false; + case SystemZ::BI__builtin_s390_lcbb: i = 1; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_verimb: + case SystemZ::BI__builtin_s390_verimh: + case SystemZ::BI__builtin_s390_verimf: + case SystemZ::BI__builtin_s390_verimg: i = 3; l = 0; u = 255; break; + case SystemZ::BI__builtin_s390_vfaeb: + case SystemZ::BI__builtin_s390_vfaeh: + case SystemZ::BI__builtin_s390_vfaef: + case SystemZ::BI__builtin_s390_vfaebs: + case SystemZ::BI__builtin_s390_vfaehs: + case SystemZ::BI__builtin_s390_vfaefs: + case SystemZ::BI__builtin_s390_vfaezb: + case SystemZ::BI__builtin_s390_vfaezh: + case SystemZ::BI__builtin_s390_vfaezf: + case SystemZ::BI__builtin_s390_vfaezbs: + case SystemZ::BI__builtin_s390_vfaezhs: + case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vfisb: + case SystemZ::BI__builtin_s390_vfidb: + return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15) || + SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15); + case SystemZ::BI__builtin_s390_vftcisb: + case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; + case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vsldb: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vstrcb: + case SystemZ::BI__builtin_s390_vstrch: + case SystemZ::BI__builtin_s390_vstrcf: + case SystemZ::BI__builtin_s390_vstrczb: + case SystemZ::BI__builtin_s390_vstrczh: + case SystemZ::BI__builtin_s390_vstrczf: + case SystemZ::BI__builtin_s390_vstrcbs: + case SystemZ::BI__builtin_s390_vstrchs: + case SystemZ::BI__builtin_s390_vstrcfs: + case SystemZ::BI__builtin_s390_vstrczbs: + case SystemZ::BI__builtin_s390_vstrczhs: + case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vmslg: i = 3; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vfminsb: + case SystemZ::BI__builtin_s390_vfmaxsb: + case SystemZ::BI__builtin_s390_vfmindb: + case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vsld: i = 2; l = 0; u = 7; break; + case SystemZ::BI__builtin_s390_vsrd: i = 2; l = 0; u = 7; break; + case SystemZ::BI__builtin_s390_vclfnhs: + case SystemZ::BI__builtin_s390_vclfnls: + case SystemZ::BI__builtin_s390_vcfn: + case SystemZ::BI__builtin_s390_vcnf: i = 1; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vcrnfs: i = 2; l = 0; u = 15; break; + } + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 02d9b64c2b14b12a95f6322370b170cfd2c14edb..40a759ea330de4548c2e8ccf26c6a59c06256332 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -292,7 +292,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, Template = FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); - if (SS.isSet() && !SS.isInvalid()) { + if (!SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, Template); @@ -342,8 +342,11 @@ bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, if (!TD || !getAsTypeTemplateDecl(TD)) return false; - if (Template) - *Template = TemplateTy::make(TemplateName(TD)); + if (Template) { + TemplateName Name = Context.getQualifiedTemplateName( + SS.getScopeRep(), /*TemplateKeyword=*/false, TemplateName(TD)); + *Template = TemplateTy::make(Name); + } return true; } @@ -983,10 +986,6 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { if (auto DTST = TL.getAs()) { TemplateName Name = DTST.getTypePtr()->getTemplateName(); - if (SS.isSet()) - Name = Context.getQualifiedTemplateName(SS.getScopeRep(), - /*HasTemplateKeyword=*/false, - Name); ParsedTemplateArgument Result(SS, TemplateTy::make(Name), DTST.getTemplateNameLoc()); if (EllipsisLoc.isValid()) @@ -1071,7 +1070,8 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } - Param->setDefaultArgument(DefaultTInfo); + Param->setDefaultArgument( + Context, TemplateArgumentLoc(DefaultTInfo->getType(), DefaultTInfo)); } return Param; @@ -1598,7 +1598,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; - Param->setDefaultArgument(Default); + Param->setDefaultArgument( + Context, getTrivialTemplateArgumentLoc(TemplateArgument(Default), + QualType(), SourceLocation())); } return Param; @@ -1839,7 +1841,8 @@ DeclResult Sema::CheckClassTemplate( TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) { assert(TemplateParams && TemplateParams->size() > 0 && "No template parameters"); - assert(TUK != TUK_Reference && "Can only declare or define class templates"); + assert(TUK != TagUseKind::Reference && + "Can only declare or define class templates"); bool Invalid = false; // Check that we can declare a template here. @@ -1861,8 +1864,9 @@ DeclResult Sema::CheckClassTemplate( // C++11 [basic.lookup.elab]p2). DeclContext *SemanticContext; LookupResult Previous(*this, Name, NameLoc, - (SS.isEmpty() && TUK == TUK_Friend) - ? LookupTagName : LookupOrdinaryName, + (SS.isEmpty() && TUK == TagUseKind::Friend) + ? LookupTagName + : LookupOrdinaryName, forRedeclarationInCurContext()); if (SS.isNotEmpty() && !SS.isInvalid()) { SemanticContext = computeDeclContext(SS, true); @@ -1870,11 +1874,11 @@ DeclResult Sema::CheckClassTemplate( // FIXME: Horrible, horrible hack! We can't currently represent this // in the AST, and historically we have just ignored such friend // class templates, so don't complain here. - Diag(NameLoc, TUK == TUK_Friend + Diag(NameLoc, TUK == TagUseKind::Friend ? diag::warn_template_qualified_friend_ignored : diag::err_template_qualified_declarator_no_match) << SS.getScopeRep() << SS.getRange(); - return TUK != TUK_Friend; + return TUK != TagUseKind::Friend; } if (RequireCompleteDeclContext(SS, SemanticContext)) @@ -1889,7 +1893,7 @@ DeclResult Sema::CheckClassTemplate( Invalid = true; } - if (TUK != TUK_Friend && TUK != TUK_Reference) + if (TUK != TagUseKind::Friend && TUK != TagUseKind::Reference) diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc, /*TemplateId-*/ nullptr, /*IsMemberSpecialization*/ false); @@ -1902,7 +1906,7 @@ DeclResult Sema::CheckClassTemplate( // If T is the name of a class, then each of the following shall have a // name different from T: // -- every member template of class T - if (TUK != TUK_Friend && + if (TUK != TagUseKind::Friend && DiagnoseClassNameShadow(SemanticContext, DeclarationNameInfo(Name, NameLoc))) return true; @@ -1944,7 +1948,7 @@ DeclResult Sema::CheckClassTemplate( } } - if (TUK == TUK_Friend) { + if (TUK == TagUseKind::Friend) { // C++ [namespace.memdef]p3: // [...] When looking for a prior declaration of a class or a function // declared as a friend, and when the name of the friend class or @@ -1981,9 +1985,8 @@ DeclResult Sema::CheckClassTemplate( PrevDecl = (*Previous.begin())->getUnderlyingDecl(); } } - } else if (PrevDecl && - !isDeclInScope(Previous.getRepresentativeDecl(), SemanticContext, - S, SS.isValid())) + } else if (PrevDecl && !isDeclInScope(Previous.getRepresentativeDecl(), + SemanticContext, S, SS.isValid())) PrevDecl = PrevClassTemplate = nullptr; if (auto *Shadow = dyn_cast_or_null( @@ -2005,7 +2008,7 @@ DeclResult Sema::CheckClassTemplate( // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself // could be dependent. - if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && + if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && !TemplateParameterListsAreEqual( TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext : CurContext, @@ -2021,8 +2024,8 @@ DeclResult Sema::CheckClassTemplate( // the class-key shall agree in kind with the original class // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); - if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, - TUK == TUK_Definition, KWLoc, Name)) { + if (!isAcceptableTagRedeclaration( + PrevRecordDecl, Kind, TUK == TagUseKind::Definition, KWLoc, Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -2031,7 +2034,7 @@ DeclResult Sema::CheckClassTemplate( } // Check for redefinition of this class template. - if (TUK == TUK_Definition) { + if (TUK == TagUseKind::Definition) { if (TagDecl *Def = PrevRecordDecl->getDefinition()) { // If we have a prior definition that is not visible, treat this as // simply making that previous definition visible. @@ -2068,7 +2071,7 @@ DeclResult Sema::CheckClassTemplate( // merging in the template parameter list from the previous class // template declaration. Skip this check for a friend in a dependent // context, because the template parameter list might be dependent. - if (!(TUK == TUK_Friend && CurContext->isDependentContext()) && + if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && CheckTemplateParameterList( TemplateParams, PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate) @@ -2076,8 +2079,8 @@ DeclResult Sema::CheckClassTemplate( (SS.isSet() && SemanticContext && SemanticContext->isRecord() && SemanticContext->isDependentContext()) ? TPC_ClassTemplateMember - : TUK == TUK_Friend ? TPC_FriendClassTemplate - : TPC_ClassTemplate, + : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate + : TPC_ClassTemplate, SkipBody)) Invalid = true; @@ -2085,9 +2088,10 @@ DeclResult Sema::CheckClassTemplate( // If the name of the template was qualified, we must be defining the // template out-of-line. if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) { - Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match - : diag::err_member_decl_does_not_match) - << Name << SemanticContext << /*IsDefinition*/true << SS.getRange(); + Diag(NameLoc, TUK == TagUseKind::Friend + ? diag::err_friend_decl_does_not_match + : diag::err_member_decl_does_not_match) + << Name << SemanticContext << /*IsDefinition*/ true << SS.getRange(); Invalid = true; } } @@ -2097,8 +2101,8 @@ DeclResult Sema::CheckClassTemplate( // recent declaration tricking the template instantiator to make substitutions // there. // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious - bool ShouldAddRedecl - = !(TUK == TUK_Friend && CurContext->isDependentContext()); + bool ShouldAddRedecl = + !(TUK == TagUseKind::Friend && CurContext->isDependentContext()); CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, @@ -2113,7 +2117,7 @@ DeclResult Sema::CheckClassTemplate( // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) { + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) { AddAlignmentAttributesForRecord(NewClass); AddMsStructLayoutForRecord(NewClass); } @@ -2144,14 +2148,15 @@ DeclResult Sema::CheckClassTemplate( PrevClassTemplate->setMemberSpecialization(); // Set the access specifier. - if (!Invalid && TUK != TUK_Friend && NewTemplate->getDeclContext()->isRecord()) + if (!Invalid && TUK != TagUseKind::Friend && + NewTemplate->getDeclContext()->isRecord()) SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); // Set the lexical context of these templates NewClass->setLexicalDeclContext(CurContext); NewTemplate->setLexicalDeclContext(CurContext); - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) NewClass->startDefinition(); ProcessDeclAttributeList(S, NewClass, Attr); @@ -2164,7 +2169,7 @@ DeclResult Sema::CheckClassTemplate( inferGslOwnerPointerAttribute(NewClass); inferNullableClassAttribute(NewClass); - if (TUK != TUK_Friend) { + if (TUK != TagUseKind::Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. Scope *Outer = S; while ((Outer->getFlags() & Scope::TemplateParamScope) != 0) @@ -2318,11 +2323,11 @@ transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, SemaRef.SubstTypeConstraint(NewTTP, TC, Args, /*EvaluateConstraint=*/true); if (TTP->hasDefaultArgument()) { - TypeSourceInfo *InstantiatedDefaultArg = - SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, - TTP->getDefaultArgumentLoc(), TTP->getDeclName()); - if (InstantiatedDefaultArg) - NewTTP->setDefaultArgument(InstantiatedDefaultArg); + TemplateArgumentLoc InstantiatedDefaultArg; + if (!SemaRef.SubstTemplateArgument( + TTP->getDefaultArgument(), Args, InstantiatedDefaultArg, + TTP->getDefaultArgumentLoc(), TTP->getDeclName())) + NewTTP->setDefaultArgument(SemaRef.Context, InstantiatedDefaultArg); } SemaRef.CurrentInstantiationScope->InstantiatedLocal(TTP, NewTTP); return NewTTP; @@ -3575,10 +3580,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, = dyn_cast(*NewParam)) { // Check the presence of a default argument here. if (NewTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewTypeParm->getLocation(), - NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() - .getSourceRange())) + DiagnoseDefaultTemplateArgument( + *this, TPC, NewTypeParm->getLocation(), + NewTypeParm->getDefaultArgument().getSourceRange())) NewTypeParm->removeDefaultArgument(); // Merge default arguments for template type parameters. @@ -3627,9 +3631,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Check the presence of a default argument here. if (NewNonTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewNonTypeParm->getLocation(), - NewNonTypeParm->getDefaultArgument()->getSourceRange())) { + DiagnoseDefaultTemplateArgument( + *this, TPC, NewNonTypeParm->getLocation(), + NewNonTypeParm->getDefaultArgument().getSourceRange())) { NewNonTypeParm->removeDefaultArgument(); } @@ -5015,7 +5019,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TagUseKind::Definition, TagLoc, Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result @@ -5616,6 +5620,15 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, } } +void Sema::diagnoseMissingTemplateArguments(const CXXScopeSpec &SS, + bool TemplateKeyword, + TemplateDecl *TD, + SourceLocation Loc) { + TemplateName Name = Context.getQualifiedTemplateName( + SS.getScopeRep(), TemplateKeyword, TemplateName(TD)); + diagnoseMissingTemplateArguments(Name, Loc); +} + ExprResult Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -5647,7 +5660,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, LocalInstantiationScope Scope(*this); EnterExpressionEvaluationContext EECtx{ - *this, ExpressionEvaluationContext::ConstantEvaluated, CSD}; + *this, ExpressionEvaluationContext::Unevaluated, CSD}; if (!AreArgsDependent && CheckConstraintSatisfaction( @@ -5686,7 +5699,8 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // Non-function templates require a template argument list. if (auto *TD = R.getAsSingle()) { if (!TemplateArgs && !isa(TD)) { - diagnoseMissingTemplateArguments(TemplateName(TD), R.getNameLoc()); + diagnoseMissingTemplateArguments( + SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), TD, R.getNameLoc()); return ExprError(); } } @@ -6040,22 +6054,26 @@ bool Sema::CheckTemplateTypeArgument( /// /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. -/// \returns the substituted template argument, or NULL if an error occurred. -static TypeSourceInfo *SubstDefaultTemplateArgument( +/// +/// \param Output the resulting substituted template argument. +/// +/// \returns true if an error occurred. +static bool SubstDefaultTemplateArgument( Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, ArrayRef SugaredConverted, - ArrayRef CanonicalConverted) { - TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); + ArrayRef CanonicalConverted, + TemplateArgumentLoc &Output) { + Output = Param->getDefaultArgument(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. - if (ArgType->getType()->isInstantiationDependentType()) { + if (Output.getArgument().isInstantiationDependent()) { Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template, SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) - return nullptr; + return true; // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted, @@ -6068,12 +6086,14 @@ static TypeSourceInfo *SubstDefaultTemplateArgument( ForLambdaCallOperator = Rec->isLambda(); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext(), !ForLambdaCallOperator); - ArgType = - SemaRef.SubstType(ArgType, TemplateArgLists, - Param->getDefaultArgumentLoc(), Param->getDeclName()); + + if (SemaRef.SubstTemplateArgument(Output, TemplateArgLists, Output, + Param->getDefaultArgumentLoc(), + Param->getDeclName())) + return true; } - return ArgType; + return false; } /// Substitute template arguments into the default template argument for @@ -6098,16 +6118,17 @@ static TypeSourceInfo *SubstDefaultTemplateArgument( /// parameters that precede \p Param in the template parameter list. /// /// \returns the substituted template argument, or NULL if an error occurred. -static ExprResult SubstDefaultTemplateArgument( +static bool SubstDefaultTemplateArgument( Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, ArrayRef SugaredConverted, - ArrayRef CanonicalConverted) { + ArrayRef CanonicalConverted, + TemplateArgumentLoc &Output) { Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template, SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) - return ExprError(); + return true; // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted, @@ -6118,7 +6139,8 @@ static ExprResult SubstDefaultTemplateArgument( Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); + return SemaRef.SubstTemplateArgument(Param->getDefaultArgument(), + TemplateArgLists, Output); } /// Substitute template arguments into the default template argument for @@ -6196,13 +6218,12 @@ TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( return TemplateArgumentLoc(); HasDefaultArg = true; - TypeSourceInfo *DI = SubstDefaultTemplateArgument( - *this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted, - CanonicalConverted); - if (DI) - return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); - - return TemplateArgumentLoc(); + TemplateArgumentLoc Output; + if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, + TypeParm, SugaredConverted, + CanonicalConverted, Output)) + return TemplateArgumentLoc(); + return Output; } if (NonTypeTemplateParmDecl *NonTypeParm @@ -6211,14 +6232,12 @@ TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( return TemplateArgumentLoc(); HasDefaultArg = true; - ExprResult Arg = SubstDefaultTemplateArgument( - *this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted, - CanonicalConverted); - if (Arg.isInvalid()) + TemplateArgumentLoc Output; + if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, + NonTypeParm, SugaredConverted, + CanonicalConverted, Output)) return TemplateArgumentLoc(); - - Expr *ArgE = Arg.getAs(); - return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE); + return Output; } TemplateTemplateParmDecl *TempTempParm @@ -6785,28 +6804,20 @@ bool Sema::CheckTemplateArgumentList( return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP, NewArgs); - TypeSourceInfo *ArgType = SubstDefaultTemplateArgument( - *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted, - CanonicalConverted); - if (!ArgType) + if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, + TTP, SugaredConverted, + CanonicalConverted, Arg)) return true; - - Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), - ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { if (!hasReachableDefaultArgument(NTTP)) return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP, NewArgs); - ExprResult E = SubstDefaultTemplateArgument( - *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted, - CanonicalConverted); - if (E.isInvalid()) + if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, + NTTP, SugaredConverted, + CanonicalConverted, Arg)) return true; - - Expr *Ex = E.getAs(); - Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); } else { TemplateTemplateParmDecl *TempParm = cast(*Param); @@ -9451,7 +9462,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { - assert(TUK != TUK_Reference && "References are not specializations"); + assert(TUK != TagUseKind::Reference && "References are not specializations"); SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc; SourceLocation LAngleLoc = TemplateId.LAngleLoc; @@ -9473,7 +9484,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( bool isPartialSpecialization = false; if (SS.isSet()) { - if (TUK != TUK_Reference && TUK != TUK_Friend && + if (TUK != TagUseKind::Reference && TUK != TagUseKind::Friend && diagnoseQualifiedDeclaration(SS, ClassTemplate->getDeclContext(), ClassTemplate->getDeclName(), TemplateNameLoc, &TemplateId, @@ -9488,9 +9499,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( bool Invalid = false; TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - KWLoc, TemplateNameLoc, SS, &TemplateId, - TemplateParameterLists, TUK == TUK_Friend, isMemberSpecialization, - Invalid); + KWLoc, TemplateNameLoc, SS, &TemplateId, TemplateParameterLists, + TUK == TagUseKind::Friend, isMemberSpecialization, Invalid); if (Invalid) return true; @@ -9501,7 +9511,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; - if (TUK == TUK_Friend) { + if (TUK == TagUseKind::Friend) { Diag(KWLoc, diag::err_partial_specialization_friend) << SourceRange(LAngleLoc, RAngleLoc); return true; @@ -9520,10 +9530,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization( } } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(Param)) { - if (Expr *DefArg = NTTP->getDefaultArgument()) { + if (NTTP->hasDefaultArgument()) { Diag(NTTP->getDefaultArgumentLoc(), diag::err_default_arg_in_partial_spec) - << DefArg->getSourceRange(); + << NTTP->getDefaultArgument().getSourceRange(); NTTP->removeDefaultArgument(); } } else { @@ -9537,14 +9547,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization( } } } else if (TemplateParams) { - if (TUK == TUK_Friend) + if (TUK == TagUseKind::Friend) Diag(KWLoc, diag::err_template_spec_friend) << FixItHint::CreateRemoval( SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc())) << SourceRange(LAngleLoc, RAngleLoc); } else { - assert(TUK == TUK_Friend && "should have a 'template<>' for this decl"); + assert(TUK == TagUseKind::Friend && + "should have a 'template<>' for this decl"); } // Check that the specialization uses the same tag kind as the @@ -9552,8 +9563,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); assert(Kind != TagTypeKind::Enum && "Invalid enum tag in class template spec!"); - if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, TUK == TUK_Definition, KWLoc, + if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, + TUK == TagUseKind::Definition, KWLoc, ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -9617,7 +9628,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // Check whether we can declare a class template specialization in // the current scope. - if (TUK != TUK_Friend && + if (TUK != TagUseKind::Friend && CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, TemplateNameLoc, isPartialSpecialization)) @@ -9644,8 +9655,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // This rule has since been removed, because it's redundant given DR1495, // but we keep it because it produces better diagnostics and recovery. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) - << /*class template*/0 << (TUK == TUK_Definition) - << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); + << /*class template*/ 0 << (TUK == TagUseKind::Definition) + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, @@ -9737,11 +9748,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization( } // If this is not a friend, note that this is an explicit specialization. - if (TUK != TUK_Friend) + if (TUK != TagUseKind::Friend) Specialization->setSpecializationKind(TSK_ExplicitSpecialization); // Check that this isn't a redefinition of this specialization. - if (TUK == TUK_Definition) { + if (TUK == TagUseKind::Definition) { RecordDecl *Def = Specialization->getDefinition(); NamedDecl *Hidden = nullptr; if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) { @@ -9762,7 +9773,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) { + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) { AddAlignmentAttributesForRecord(Specialization); AddMsStructLayoutForRecord(Specialization); } @@ -9783,10 +9794,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization( Specialization->setLexicalDeclContext(CurContext); // We may be starting the definition of this specialization. - if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) Specialization->startDefinition(); - if (TUK == TUK_Friend) { + if (TUK == TagUseKind::Friend) { // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -11160,11 +11171,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, bool Owned = false; bool IsDependent = false; - Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, - NameLoc, Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(), + Decl *TagD = + ActOnTag(S, TagSpec, TagUseKind::Reference, KWLoc, SS, Name, NameLoc, + Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(), false, TypeResult(), /*IsTypeSpecifier*/ false, - /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside).get(); + /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside) + .get(); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -11695,9 +11708,9 @@ TypeResult Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); - if (TUK == TUK_Declaration || TUK == TUK_Definition) { + if (TUK == TagUseKind::Declaration || TUK == TagUseKind::Definition) { Diag(NameLoc, diag::err_dependent_tag_decl) - << (TUK == TUK_Definition) << llvm::to_underlying(Kind) + << (TUK == TagUseKind::Definition) << llvm::to_underlying(Kind) << SS.getRange(); return true; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 41fd210f29d097ca6fb22fc73097400aea73bb1d..1011db2d2830dcd41919b229d339b94c03d99e5f 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -519,18 +519,14 @@ static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A, switch (A->getKind()) { case Decl::TemplateTypeParm: { auto *T = cast(A); - // FIXME: A TemplateTypeParmDecl's DefaultArgument can't hold a full - // TemplateArgument, so there is currently no way to specify a pack as a - // default argument for these. - if (T->isParameterPack()) - return A; auto *R = TemplateTypeParmDecl::Create( S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), T->getDepth(), T->getIndex(), T->getIdentifier(), - T->wasDeclaredWithTypename(), /*ParameterPack=*/false, + T->wasDeclaredWithTypename(), T->isParameterPack(), T->hasTypeConstraint()); R->setDefaultArgument( - S.Context.getTrivialTypeSourceInfo(Default.getAsType())); + S.Context, + S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation())); if (R->hasTypeConstraint()) { auto *C = R->getTypeConstraint(); R->setTypeConstraint(C->getConceptReference(), @@ -540,14 +536,14 @@ static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A, } case Decl::NonTypeTemplateParm: { auto *T = cast(A); - // FIXME: Ditto, as above for TemplateTypeParm case. - if (T->isParameterPack()) - return A; auto *R = NonTypeTemplateParmDecl::Create( S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), T->getDepth(), T->getIndex(), T->getIdentifier(), T->getType(), - /*ParameterPack=*/false, T->getTypeSourceInfo()); - R->setDefaultArgument(Default.getAsExpr()); + T->isParameterPack(), T->getTypeSourceInfo()); + R->setDefaultArgument(S.Context, + S.getTrivialTemplateArgumentLoc( + Default, Default.getNonTypeTemplateArgumentType(), + SourceLocation())); if (auto *PTC = T->getPlaceholderTypeConstraint()) R->setPlaceholderTypeConstraint(PTC); return R; @@ -593,7 +589,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // arguments as defaults. if (auto *TempArg = dyn_cast_or_null( Arg.getAsTemplateDecl())) { - assert(Arg.getKind() == TemplateName::Template); assert(!TempArg->isExpandedParameterPack()); TemplateParameterList *As = TempArg->getTemplateParameters(); @@ -662,6 +657,18 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. + +static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) { + for (const Type *T = QT.getTypePtr(); /**/; /**/) { + const TemplateSpecializationType *TST = + T->getAs(); + assert(TST && "Expected a TemplateSpecializationType"); + if (!TST->isSugared()) + return TST; + T = TST->desugar().getTypePtr(); + } +} + static TemplateDeductionResult DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, const QualType P, QualType A, @@ -670,26 +677,35 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, QualType UP = P; if (const auto *IP = P->getAs()) UP = IP->getInjectedSpecializationType(); - // FIXME: Try to preserve type sugar here, which is hard - // because of the unresolved template arguments. - const auto *TP = UP.getCanonicalType()->castAs(); + + assert(isa(UP.getCanonicalType())); + const TemplateSpecializationType *TP = ::getLastTemplateSpecType(UP); TemplateName TNP = TP->getTemplateName(); // If the parameter is an alias template, there is nothing to deduce. if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) return TemplateDeductionResult::Success; - ArrayRef PResolved = TP->template_arguments(); + // FIXME: To preserve sugar, the TST needs to carry sugared resolved + // arguments. + ArrayRef PResolved = + TP->getCanonicalTypeInternal() + ->castAs() + ->template_arguments(); QualType UA = A; + std::optional NNS; // Treat an injected-class-name as its underlying template-id. - if (const auto *Injected = A->getAs()) + if (const auto *Elaborated = A->getAs()) { + NNS = Elaborated->getQualifier(); + } else if (const auto *Injected = A->getAs()) { UA = Injected->getInjectedSpecializationType(); + NNS = nullptr; + } // Check whether the template argument is a dependent template-id. - // FIXME: Should not lose sugar here. - if (const auto *SA = - dyn_cast(UA.getCanonicalType())) { + if (isa(UA.getCanonicalType())) { + const TemplateSpecializationType *SA = ::getLastTemplateSpecType(UA); TemplateName TNA = SA->getTemplateName(); // If the argument is an alias template, there is nothing to deduce. @@ -702,11 +718,19 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, SA->template_arguments(), Deduced); Result != TemplateDeductionResult::Success) return Result; + + // FIXME: To preserve sugar, the TST needs to carry sugared resolved + // arguments. + ArrayRef AResolved = + SA->getCanonicalTypeInternal() + ->castAs() + ->template_arguments(); + // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->template_arguments(), Info, Deduced, + return DeduceTemplateArguments(S, TemplateParams, PResolved, AResolved, + Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } @@ -722,11 +746,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, return TemplateDeductionResult::NonDeducedMismatch; } + TemplateName TNA = TemplateName(SA->getSpecializedTemplate()); + if (NNS) + TNA = S.Context.getQualifiedTemplateName( + *NNS, false, TemplateName(SA->getSpecializedTemplate())); + // Perform template argument deduction for the template name. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, TP->getTemplateName(), - TemplateName(SA->getSpecializedTemplate()), Info, - SA->getTemplateArgs().asArray(), Deduced); + if (auto Result = + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, + SA->getTemplateArgs().asArray(), Deduced); Result != TemplateDeductionResult::Success) return Result; @@ -4473,7 +4501,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( // Deduce an argument of type ParamType from an expression with index ArgIdx. auto DeduceCallArgument = [&](QualType ParamType, unsigned ArgIdx, - bool ExplicitObjetArgument) { + bool ExplicitObjectArgument) { // C++ [demp.deduct.call]p1: (DR1391) // Template argument deduction is done by comparing each function template // parameter that contains template-parameters that participate in @@ -4481,7 +4509,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) return TemplateDeductionResult::Success; - if (ExplicitObjetArgument) { + if (ExplicitObjectArgument) { // ... with the type of the corresponding argument return DeduceTemplateArgumentsFromCallArgument( *this, TemplateParams, FirstInnerIndex, ParamType, ObjectType, @@ -4516,14 +4544,14 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( if (ParamIdx == 0 && HasExplicitObject) { if (auto Result = DeduceCallArgument(ParamType, 0, - /*ExplicitObjetArgument=*/true); + /*ExplicitObjectArgument=*/true); Result != TemplateDeductionResult::Success) return Result; continue; } if (auto Result = DeduceCallArgument(ParamType, ArgIdx++, - /*ExplicitObjetArgument=*/false); + /*ExplicitObjectArgument=*/false); Result != TemplateDeductionResult::Success) return Result; @@ -4558,7 +4586,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( PackScope.nextPackElement(), ++ArgIdx) { ParamTypesForArgChecking.push_back(ParamPattern); if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx, - /*ExplicitObjetArgument=*/false); + /*ExplicitObjectArgument=*/false); Result != TemplateDeductionResult::Success) return Result; } @@ -4598,8 +4626,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( unsigned PackArgEnd = ArgIdx + *ArgPosAfterSubstitution; for (; ArgIdx < PackArgEnd && ArgIdx < Args.size(); ArgIdx++) { ParamTypesForArgChecking.push_back(ParamPattern); - if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx, - /*ExplicitObjetArgument=*/false); + if (auto Result = + DeduceCallArgument(ParamPattern, ArgIdx, + /*ExplicitObjectArgument=*/false); Result != TemplateDeductionResult::Success) return Result; @@ -4776,8 +4805,13 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( DeduceReturnType(Specialization, Info.getLocation(), false)) return TemplateDeductionResult::MiscellaneousDeductionFailure; + // [C++26][expr.const]/p17 + // An expression or conversion is immediate-escalating if it is not initially + // in an immediate function context and it is [...] + // a potentially-evaluated id-expression that denotes an immediate function. if (IsAddressOfFunction && getLangOpts().CPlusPlus20 && Specialization->isImmediateEscalating() && + parentEvaluationContext().isPotentiallyEvaluated() && CheckIfFunctionSpecializationIsImmediate(Specialization, Info.getLocation())) return TemplateDeductionResult::MiscellaneousDeductionFailure; @@ -5100,6 +5134,20 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, return true; MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, /*Final=*/false); + // Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so + // that the template arguments of the constraint can be preserved. For + // example: + // + // template + // concept C = []() { return true; }(); + // + // We need the argument for T while evaluating type constraint D in + // building the CallExpr to the lambda. + EnterExpressionEvaluationContext EECtx( + S, Sema::ExpressionEvaluationContext::Unevaluated, + ImplicitConceptSpecializationDecl::Create( + S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(), + CanonicalConverted)); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 07626058c797763d496f07dbb9fd53d58996b586..863cc53c55afa4b38ce91de9a3bbe97adddab0cf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1619,11 +1619,6 @@ namespace { case TemplateArgument::Pack: // Literally rewrite the template argument pack, instead of unpacking // it. - assert( - SemaRef.CodeSynthesisContexts.back().Kind == - Sema::CodeSynthesisContext::BuildingDeductionGuides && - "Transforming a template argument pack is only allowed in building " - "deduction guide"); for (auto &pack : Arg.getPackAsArray()) { TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc( pack, QualType(), SourceLocation{}); @@ -1861,7 +1856,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); @@ -2034,10 +2029,8 @@ TemplateName TemplateInstantiator::TransformTemplateName( Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - assert(!Template.getAsQualifiedTemplateName() && - "template decl to substitute is qualified?"); if (Final) return Template; @@ -2057,8 +2050,8 @@ TemplateName TemplateInstantiator::TransformTemplateName( if (SubstPack->getFinal()) return Template; return getSema().Context.getSubstTemplateTemplateParm( - Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(), - SubstPack->getIndex(), getPackIndex(Pack)); + Template, SubstPack->getAssociatedDecl(), SubstPack->getIndex(), + getPackIndex(Pack)); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -4375,9 +4368,9 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) { bool Sema::SubstTemplateArgument( const TemplateArgumentLoc &Input, const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentLoc &Output) { - TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), - DeclarationName()); + TemplateArgumentLoc &Output, SourceLocation Loc, + const DeclarationName &Entity) { + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); return Instantiator.TransformTemplateArgument(Input, Output); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 381d79b2fcd4665715c9c6b0ad2e77ce503674ec..0681520764d9a0afdf44d7d6e2b5e4346f7e854e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -26,10 +26,12 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaSwift.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/TimeProfiler.h" @@ -563,7 +565,7 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( return; Expr *MaxExpr = Result.getAs(); - S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr); + S.AMDGPU().addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr); } ExplicitSpecifier Sema::instantiateExplicitSpecifier( @@ -607,7 +609,7 @@ static void instantiateDependentAMDGPUWavesPerEUAttr( MaxExpr = Result.getAs(); } - S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr); + S.AMDGPU().addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr); } static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr( @@ -630,7 +632,7 @@ static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr( Expr *YExpr = ResultY.getAs(); Expr *ZExpr = ResultZ.getAs(); - S.addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr); + S.AMDGPU().addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr); } // This doesn't take any template parameters, but we have a custom action that @@ -839,14 +841,15 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } if (const auto *ABIAttr = dyn_cast(TmplAttr)) { - AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI()); + Swift().AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI()); continue; } if (isa(TmplAttr) || isa(TmplAttr) || isa(TmplAttr)) { - AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr), - /*template instantiation=*/true); + ObjC().AddXConsumedAttr(New, *TmplAttr, + attrToRetainOwnershipKind(TmplAttr), + /*template instantiation=*/true); continue; } @@ -2956,11 +2959,10 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( } } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { - TypeSourceInfo *InstantiatedDefaultArg = - SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, - D->getDefaultArgumentLoc(), D->getDeclName()); - if (InstantiatedDefaultArg) - Inst->setDefaultArgument(InstantiatedDefaultArg); + TemplateArgumentLoc Output; + if (!SemaRef.SubstTemplateArgument(D->getDefaultArgument(), TemplateArgs, + Output)) + Inst->setDefaultArgument(SemaRef.getASTContext(), Output); } // Introduce this template parameter's instantiation into the instantiation @@ -3124,9 +3126,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs); - if (!Value.isInvalid()) - Param->setDefaultArgument(Value.get()); + TemplateArgumentLoc Result; + if (!SemaRef.SubstTemplateArgument(D->getDefaultArgument(), TemplateArgs, + Result)) + Param->setDefaultArgument(SemaRef.Context, Result); } // Introduce this template parameter's instantiation into the instantiation @@ -5055,6 +5058,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Function->setLocation(PatternDecl->getLocation()); Function->setInnerLocStart(PatternDecl->getInnerLocStart()); Function->setRangeEnd(PatternDecl->getEndLoc()); + Function->setDeclarationNameLoc(PatternDecl->getNameInfo().getInfo()); EnterExpressionEvaluationContext EvalContext( *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 0b20604665068c77065564612e14df79b4b20843..7a44b978aacdb7351aa2fbb3cfc4146c6f87a0b1 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -66,6 +66,9 @@ namespace { bool shouldWalkTypesOfTypeLocs() const { return false; } + // We need this so we can find e.g. attributes on lambdas. + bool shouldVisitImplicitCode() const { return true; } + //------------------------------------------------------------------------ // Recording occurrences of (unexpanded) parameter packs. //------------------------------------------------------------------------ diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index c19c8cc34dd3bdad1d4eea8c97ce9efea729d707..441fdcca0758f959ca5a50b1e95dc0713ba520ac 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2704,7 +2704,7 @@ QualType Sema::BuildFunctionType(QualType T, if (EPI.ExtInfo.getProducesResult()) { // This is just a warning, so we can't fail to build if we see it. - checkNSReturnsRetainedReturnType(Loc, T); + ObjC().checkNSReturnsRetainedReturnType(Loc, T); } if (Invalid) @@ -6005,12 +6005,16 @@ namespace { DeclarationNameInfo DNI = DeclarationNameInfo( TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(), TemplateId->TemplateNameLoc); - auto TN = TemplateId->Template.get(); + + NamedDecl *FoundDecl; + if (auto TN = TemplateId->Template.get(); + UsingShadowDecl *USD = TN.getAsUsingShadowDecl()) + FoundDecl = cast(USD); + else + FoundDecl = cast_if_present(TN.getAsTemplateDecl()); + auto *CR = ConceptReference::Create( - Context, NNS, TemplateId->TemplateKWLoc, DNI, - /*FoundDecl=*/TN.getKind() == TemplateName::NameKind::UsingTemplate - ? cast(TN.getAsUsingShadowDecl()) - : cast_if_present(TN.getAsTemplateDecl()), + Context, NNS, TemplateId->TemplateKWLoc, DNI, FoundDecl, /*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(), ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo)); TL.setConceptReference(CR); @@ -7635,8 +7639,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, return false; // Check whether the return type is reasonable. - if (S.checkNSReturnsRetainedReturnType(attr.getLoc(), - unwrapped.get()->getReturnType())) + if (S.ObjC().checkNSReturnsRetainedReturnType( + attr.getLoc(), unwrapped.get()->getReturnType())) return true; // Only actually change the underlying type in ARC builds. @@ -9345,9 +9349,9 @@ BuildTypeCoupledDecls(Expr *E, Decls.push_back(TypeCoupledDeclRefInfo(CountDecl, /*IsDref*/ false)); } -QualType Sema::BuildCountAttributedArrayType(QualType WrappedTy, - Expr *CountExpr) { - assert(WrappedTy->isIncompleteArrayType()); +QualType Sema::BuildCountAttributedArrayOrPointerType(QualType WrappedTy, + Expr *CountExpr) { + assert(WrappedTy->isIncompleteArrayType() || WrappedTy->isPointerType()); llvm::SmallVector Decls; BuildTypeCoupledDecls(CountExpr, Decls); diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0fa05bc1760960969fdd17e11fbb56c5ac0c0ec --- /dev/null +++ b/clang/lib/Sema/SemaWasm.cpp @@ -0,0 +1,341 @@ +//===------ SemaWasm.cpp ---- WebAssembly target-specific routines --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to WebAssembly. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaWasm.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaWasm::SemaWasm(Sema &S) : SemaBase(S) {} + +/// Checks the argument at the given index is a WebAssembly table and if it +/// is, sets ElTy to the element type. +static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, + QualType &ElTy) { + Expr *ArgExpr = E->getArg(ArgIndex); + const auto *ATy = dyn_cast(ArgExpr->getType()); + if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) { + return S.Diag(ArgExpr->getBeginLoc(), + diag::err_wasm_builtin_arg_must_be_table_type) + << ArgIndex + 1 << ArgExpr->getSourceRange(); + } + ElTy = ATy->getElementType(); + return false; +} + +/// Checks the argument at the given index is an integer. +static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, + unsigned ArgIndex) { + Expr *ArgExpr = E->getArg(ArgIndex); + if (!ArgExpr->getType()->isIntegerType()) { + return S.Diag(ArgExpr->getBeginLoc(), + diag::err_wasm_builtin_arg_must_be_integer_type) + << ArgIndex + 1 << ArgExpr->getSourceRange(); + } + return false; +} + +bool SemaWasm::BuiltinWasmRefNullExtern(CallExpr *TheCall) { + if (TheCall->getNumArgs() != 0) + return true; + + TheCall->setType(getASTContext().getWebAssemblyExternrefType()); + + return false; +} + +bool SemaWasm::BuiltinWasmRefNullFunc(CallExpr *TheCall) { + ASTContext &Context = getASTContext(); + if (TheCall->getNumArgs() != 0) { + Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs() + << /*is non object*/ 0; + return true; + } + + // This custom type checking code ensures that the nodes are as expected + // in order to later on generate the necessary builtin. + QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {}); + QualType Type = Context.getPointerType(Pointee); + Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref); + Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type, + Context.getPointerType(Pointee)); + TheCall->setType(Type); + + return false; +} + +/// Check that the first argument is a WebAssembly table, and the second +/// is an index to use as index into the table. +bool SemaWasm::BuiltinWasmTableGet(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) + return true; + + // If all is well, we set the type of TheCall to be the type of the + // element of the table. + // i.e. a table.get on an externref table has type externref, + // or whatever the type of the table element is. + TheCall->setType(ElTy); + + return false; +} + +/// Check that the first argumnet is a WebAssembly table, the second is +/// an index to use as index into the table and the third is the reference +/// type to set into the table. +bool SemaWasm::BuiltinWasmTableSet(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) + return true; + + if (!getASTContext().hasSameType(ElTy, TheCall->getArg(2)->getType())) + return true; + + return false; +} + +/// Check that the argument is a WebAssembly table. +bool SemaWasm::BuiltinWasmTableSize(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is the +/// value to use for new elements (of a type matching the table type), the +/// third value is an integer. +bool SemaWasm::BuiltinWasmTableGrow(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) + return true; + + Expr *NewElemArg = TheCall->getArg(1); + if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) { + return Diag(NewElemArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 2 << 1 << NewElemArg->getSourceRange(); + } + + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 2)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is an +/// integer, the third is the value to use to fill the table (of a type +/// matching the table type), and the fourth is an integer. +bool SemaWasm::BuiltinWasmTableFill(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 4)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) + return true; + + Expr *NewElemArg = TheCall->getArg(2); + if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) { + return Diag(NewElemArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 3 << 1 << NewElemArg->getSourceRange(); + } + + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 3)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is also a +/// WebAssembly table (of the same element type), and the third to fifth +/// arguments are integers. +bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 5)) + return true; + + QualType XElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, XElTy)) + return true; + + QualType YElTy; + if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 1, YElTy)) + return true; + + Expr *TableYArg = TheCall->getArg(1); + if (!getASTContext().hasSameType(XElTy, YElTy)) { + return Diag(TableYArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 2 << 1 << TableYArg->getSourceRange(); + } + + for (int I = 2; I <= 4; I++) { + if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, I)) + return true; + } + + return false; +} + +bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_ref_null_extern: + return BuiltinWasmRefNullExtern(TheCall); + case WebAssembly::BI__builtin_wasm_ref_null_func: + return BuiltinWasmRefNullFunc(TheCall); + case WebAssembly::BI__builtin_wasm_table_get: + return BuiltinWasmTableGet(TheCall); + case WebAssembly::BI__builtin_wasm_table_set: + return BuiltinWasmTableSet(TheCall); + case WebAssembly::BI__builtin_wasm_table_size: + return BuiltinWasmTableSize(TheCall); + case WebAssembly::BI__builtin_wasm_table_grow: + return BuiltinWasmTableGrow(TheCall); + case WebAssembly::BI__builtin_wasm_table_fill: + return BuiltinWasmTableFill(TheCall); + case WebAssembly::BI__builtin_wasm_table_copy: + return BuiltinWasmTableCopy(TheCall); + } + + return false; +} + +WebAssemblyImportModuleAttr * +SemaWasm::mergeImportModuleAttr(Decl *D, + const WebAssemblyImportModuleAttr &AL) { + auto *FD = cast(D); + + if (const auto *ExistingAttr = FD->getAttr()) { + if (ExistingAttr->getImportModule() == AL.getImportModule()) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) + << 0 << ExistingAttr->getImportModule() << AL.getImportModule(); + Diag(AL.getLoc(), diag::note_previous_attribute); + return nullptr; + } + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; + return nullptr; + } + return ::new (getASTContext()) + WebAssemblyImportModuleAttr(getASTContext(), AL, AL.getImportModule()); +} + +WebAssemblyImportNameAttr * +SemaWasm::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) { + auto *FD = cast(D); + + if (const auto *ExistingAttr = FD->getAttr()) { + if (ExistingAttr->getImportName() == AL.getImportName()) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) + << 1 << ExistingAttr->getImportName() << AL.getImportName(); + Diag(AL.getLoc(), diag::note_previous_attribute); + return nullptr; + } + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; + return nullptr; + } + return ::new (getASTContext()) + WebAssemblyImportNameAttr(getASTContext(), AL, AL.getImportName()); +} + +void SemaWasm::handleWebAssemblyImportModuleAttr(Decl *D, + const ParsedAttr &AL) { + auto *FD = cast(D); + + StringRef Str; + SourceLocation ArgLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; + return; + } + + FD->addAttr(::new (getASTContext()) + WebAssemblyImportModuleAttr(getASTContext(), AL, Str)); +} + +void SemaWasm::handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL) { + auto *FD = cast(D); + + StringRef Str; + SourceLocation ArgLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; + return; + } + + FD->addAttr(::new (getASTContext()) + WebAssemblyImportNameAttr(getASTContext(), AL, Str)); +} + +void SemaWasm::handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL) { + ASTContext &Context = getASTContext(); + if (!isFuncOrMethodForAttrSubject(D)) { + Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + auto *FD = cast(D); + if (FD->isThisDeclarationADefinition()) { + Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + D->addAttr(::new (Context) WebAssemblyExportNameAttr(Context, AL, Str)); + D->addAttr(UsedAttr::CreateImplicit(Context)); +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaX86.cpp b/clang/lib/Sema/SemaX86.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be26454ce909d5096f5db9ac8a0ea89d25a706eb --- /dev/null +++ b/clang/lib/Sema/SemaX86.cpp @@ -0,0 +1,972 @@ +//===------ SemaX86.cpp ---------- X86 target-specific routines -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis functions specific to X86. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaX86.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Attr.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/TargetParser/Triple.h" +#include + +namespace clang { + +SemaX86::SemaX86(Sema &S) : SemaBase(S) {} + +// Check if the rounding mode is legal. +bool SemaX86::CheckBuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { + // Indicates if this instruction has rounding control or just SAE. + bool HasRC = false; + + unsigned ArgNum = 0; + switch (BuiltinID) { + default: + return false; + case X86::BI__builtin_ia32_vcvttsd2si32: + case X86::BI__builtin_ia32_vcvttsd2si64: + case X86::BI__builtin_ia32_vcvttsd2usi32: + case X86::BI__builtin_ia32_vcvttsd2usi64: + case X86::BI__builtin_ia32_vcvttss2si32: + case X86::BI__builtin_ia32_vcvttss2si64: + case X86::BI__builtin_ia32_vcvttss2usi32: + case X86::BI__builtin_ia32_vcvttss2usi64: + case X86::BI__builtin_ia32_vcvttsh2si32: + case X86::BI__builtin_ia32_vcvttsh2si64: + case X86::BI__builtin_ia32_vcvttsh2usi32: + case X86::BI__builtin_ia32_vcvttsh2usi64: + ArgNum = 1; + break; + case X86::BI__builtin_ia32_maxpd512: + case X86::BI__builtin_ia32_maxps512: + case X86::BI__builtin_ia32_minpd512: + case X86::BI__builtin_ia32_minps512: + case X86::BI__builtin_ia32_maxph512: + case X86::BI__builtin_ia32_minph512: + ArgNum = 2; + break; + case X86::BI__builtin_ia32_vcvtph2pd512_mask: + case X86::BI__builtin_ia32_vcvtph2psx512_mask: + case X86::BI__builtin_ia32_cvtps2pd512_mask: + case X86::BI__builtin_ia32_cvttpd2dq512_mask: + case X86::BI__builtin_ia32_cvttpd2qq512_mask: + case X86::BI__builtin_ia32_cvttpd2udq512_mask: + case X86::BI__builtin_ia32_cvttpd2uqq512_mask: + case X86::BI__builtin_ia32_cvttps2dq512_mask: + case X86::BI__builtin_ia32_cvttps2qq512_mask: + case X86::BI__builtin_ia32_cvttps2udq512_mask: + case X86::BI__builtin_ia32_cvttps2uqq512_mask: + case X86::BI__builtin_ia32_vcvttph2w512_mask: + case X86::BI__builtin_ia32_vcvttph2uw512_mask: + case X86::BI__builtin_ia32_vcvttph2dq512_mask: + case X86::BI__builtin_ia32_vcvttph2udq512_mask: + case X86::BI__builtin_ia32_vcvttph2qq512_mask: + case X86::BI__builtin_ia32_vcvttph2uqq512_mask: + case X86::BI__builtin_ia32_getexppd512_mask: + case X86::BI__builtin_ia32_getexpps512_mask: + case X86::BI__builtin_ia32_getexpph512_mask: + case X86::BI__builtin_ia32_vcomisd: + case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_vcomish: + case X86::BI__builtin_ia32_vcvtph2ps512_mask: + ArgNum = 3; + break; + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpps512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_cmpsh_mask: + case X86::BI__builtin_ia32_vcvtsh2sd_round_mask: + case X86::BI__builtin_ia32_vcvtsh2ss_round_mask: + case X86::BI__builtin_ia32_cvtss2sd_round_mask: + case X86::BI__builtin_ia32_getexpsd128_round_mask: + case X86::BI__builtin_ia32_getexpss128_round_mask: + case X86::BI__builtin_ia32_getexpsh128_round_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_getmantph512_mask: + case X86::BI__builtin_ia32_maxsd_round_mask: + case X86::BI__builtin_ia32_maxss_round_mask: + case X86::BI__builtin_ia32_maxsh_round_mask: + case X86::BI__builtin_ia32_minsd_round_mask: + case X86::BI__builtin_ia32_minss_round_mask: + case X86::BI__builtin_ia32_minsh_round_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_reduceph512_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rndscaleph_mask: + ArgNum = 4; + break; + case X86::BI__builtin_ia32_fixupimmpd512_mask: + case X86::BI__builtin_ia32_fixupimmpd512_maskz: + case X86::BI__builtin_ia32_fixupimmps512_mask: + case X86::BI__builtin_ia32_fixupimmps512_maskz: + case X86::BI__builtin_ia32_fixupimmsd_mask: + case X86::BI__builtin_ia32_fixupimmsd_maskz: + case X86::BI__builtin_ia32_fixupimmss_mask: + case X86::BI__builtin_ia32_fixupimmss_maskz: + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_getmantsh_round_mask: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_rangesd128_round_mask: + case X86::BI__builtin_ia32_rangess128_round_mask: + case X86::BI__builtin_ia32_reducesd_mask: + case X86::BI__builtin_ia32_reducess_mask: + case X86::BI__builtin_ia32_reducesh_mask: + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + case X86::BI__builtin_ia32_rndscalesh_round_mask: + ArgNum = 5; + break; + case X86::BI__builtin_ia32_vcvtsd2si64: + case X86::BI__builtin_ia32_vcvtsd2si32: + case X86::BI__builtin_ia32_vcvtsd2usi32: + case X86::BI__builtin_ia32_vcvtsd2usi64: + case X86::BI__builtin_ia32_vcvtss2si32: + case X86::BI__builtin_ia32_vcvtss2si64: + case X86::BI__builtin_ia32_vcvtss2usi32: + case X86::BI__builtin_ia32_vcvtss2usi64: + case X86::BI__builtin_ia32_vcvtsh2si32: + case X86::BI__builtin_ia32_vcvtsh2si64: + case X86::BI__builtin_ia32_vcvtsh2usi32: + case X86::BI__builtin_ia32_vcvtsh2usi64: + case X86::BI__builtin_ia32_sqrtpd512: + case X86::BI__builtin_ia32_sqrtps512: + case X86::BI__builtin_ia32_sqrtph512: + ArgNum = 1; + HasRC = true; + break; + case X86::BI__builtin_ia32_addph512: + case X86::BI__builtin_ia32_divph512: + case X86::BI__builtin_ia32_mulph512: + case X86::BI__builtin_ia32_subph512: + case X86::BI__builtin_ia32_addpd512: + case X86::BI__builtin_ia32_addps512: + case X86::BI__builtin_ia32_divpd512: + case X86::BI__builtin_ia32_divps512: + case X86::BI__builtin_ia32_mulpd512: + case X86::BI__builtin_ia32_mulps512: + case X86::BI__builtin_ia32_subpd512: + case X86::BI__builtin_ia32_subps512: + case X86::BI__builtin_ia32_cvtsi2sd64: + case X86::BI__builtin_ia32_cvtsi2ss32: + case X86::BI__builtin_ia32_cvtsi2ss64: + case X86::BI__builtin_ia32_cvtusi2sd64: + case X86::BI__builtin_ia32_cvtusi2ss32: + case X86::BI__builtin_ia32_cvtusi2ss64: + case X86::BI__builtin_ia32_vcvtusi2sh: + case X86::BI__builtin_ia32_vcvtusi642sh: + case X86::BI__builtin_ia32_vcvtsi2sh: + case X86::BI__builtin_ia32_vcvtsi642sh: + ArgNum = 2; + HasRC = true; + break; + case X86::BI__builtin_ia32_cvtdq2ps512_mask: + case X86::BI__builtin_ia32_cvtudq2ps512_mask: + case X86::BI__builtin_ia32_vcvtpd2ph512_mask: + case X86::BI__builtin_ia32_vcvtps2phx512_mask: + case X86::BI__builtin_ia32_cvtpd2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2dq512_mask: + case X86::BI__builtin_ia32_cvtpd2qq512_mask: + case X86::BI__builtin_ia32_cvtpd2udq512_mask: + case X86::BI__builtin_ia32_cvtpd2uqq512_mask: + case X86::BI__builtin_ia32_cvtps2dq512_mask: + case X86::BI__builtin_ia32_cvtps2qq512_mask: + case X86::BI__builtin_ia32_cvtps2udq512_mask: + case X86::BI__builtin_ia32_cvtps2uqq512_mask: + case X86::BI__builtin_ia32_cvtqq2pd512_mask: + case X86::BI__builtin_ia32_cvtqq2ps512_mask: + case X86::BI__builtin_ia32_cvtuqq2pd512_mask: + case X86::BI__builtin_ia32_cvtuqq2ps512_mask: + case X86::BI__builtin_ia32_vcvtdq2ph512_mask: + case X86::BI__builtin_ia32_vcvtudq2ph512_mask: + case X86::BI__builtin_ia32_vcvtw2ph512_mask: + case X86::BI__builtin_ia32_vcvtuw2ph512_mask: + case X86::BI__builtin_ia32_vcvtph2w512_mask: + case X86::BI__builtin_ia32_vcvtph2uw512_mask: + case X86::BI__builtin_ia32_vcvtph2dq512_mask: + case X86::BI__builtin_ia32_vcvtph2udq512_mask: + case X86::BI__builtin_ia32_vcvtph2qq512_mask: + case X86::BI__builtin_ia32_vcvtph2uqq512_mask: + case X86::BI__builtin_ia32_vcvtqq2ph512_mask: + case X86::BI__builtin_ia32_vcvtuqq2ph512_mask: + ArgNum = 3; + HasRC = true; + break; + case X86::BI__builtin_ia32_addsh_round_mask: + case X86::BI__builtin_ia32_addss_round_mask: + case X86::BI__builtin_ia32_addsd_round_mask: + case X86::BI__builtin_ia32_divsh_round_mask: + case X86::BI__builtin_ia32_divss_round_mask: + case X86::BI__builtin_ia32_divsd_round_mask: + case X86::BI__builtin_ia32_mulsh_round_mask: + case X86::BI__builtin_ia32_mulss_round_mask: + case X86::BI__builtin_ia32_mulsd_round_mask: + case X86::BI__builtin_ia32_subsh_round_mask: + case X86::BI__builtin_ia32_subss_round_mask: + case X86::BI__builtin_ia32_subsd_round_mask: + case X86::BI__builtin_ia32_scalefph512_mask: + case X86::BI__builtin_ia32_scalefpd512_mask: + case X86::BI__builtin_ia32_scalefps512_mask: + case X86::BI__builtin_ia32_scalefsd_round_mask: + case X86::BI__builtin_ia32_scalefss_round_mask: + case X86::BI__builtin_ia32_scalefsh_round_mask: + case X86::BI__builtin_ia32_cvtsd2ss_round_mask: + case X86::BI__builtin_ia32_vcvtss2sh_round_mask: + case X86::BI__builtin_ia32_vcvtsd2sh_round_mask: + case X86::BI__builtin_ia32_sqrtsd_round_mask: + case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_sqrtsh_round_mask: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: + case X86::BI__builtin_ia32_vfmaddsh3_mask: + case X86::BI__builtin_ia32_vfmaddsh3_maskz: + case X86::BI__builtin_ia32_vfmaddsh3_mask3: + case X86::BI__builtin_ia32_vfmaddpd512_mask: + case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: + case X86::BI__builtin_ia32_vfmaddps512_mask: + case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddph512_mask: + case X86::BI__builtin_ia32_vfmaddph512_maskz: + case X86::BI__builtin_ia32_vfmaddph512_mask3: + case X86::BI__builtin_ia32_vfmsubph512_mask3: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask: + case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_mask: + case X86::BI__builtin_ia32_vfmaddsubps512_maskz: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: + case X86::BI__builtin_ia32_vfmsubaddps512_mask3: + case X86::BI__builtin_ia32_vfmaddsubph512_mask: + case X86::BI__builtin_ia32_vfmaddsubph512_maskz: + case X86::BI__builtin_ia32_vfmaddsubph512_mask3: + case X86::BI__builtin_ia32_vfmsubaddph512_mask3: + case X86::BI__builtin_ia32_vfmaddcsh_mask: + case X86::BI__builtin_ia32_vfmaddcsh_round_mask: + case X86::BI__builtin_ia32_vfmaddcsh_round_mask3: + case X86::BI__builtin_ia32_vfmaddcph512_mask: + case X86::BI__builtin_ia32_vfmaddcph512_maskz: + case X86::BI__builtin_ia32_vfmaddcph512_mask3: + case X86::BI__builtin_ia32_vfcmaddcsh_mask: + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask: + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3: + case X86::BI__builtin_ia32_vfcmaddcph512_mask: + case X86::BI__builtin_ia32_vfcmaddcph512_maskz: + case X86::BI__builtin_ia32_vfcmaddcph512_mask3: + case X86::BI__builtin_ia32_vfmulcsh_mask: + case X86::BI__builtin_ia32_vfmulcph512_mask: + case X86::BI__builtin_ia32_vfcmulcsh_mask: + case X86::BI__builtin_ia32_vfcmulcph512_mask: + ArgNum = 4; + HasRC = true; + break; + } + + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit + // is set. If the intrinsic has rounding control(bits 1:0), make sure its only + // combined with ROUND_NO_EXC. If the intrinsic does not have rounding + // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together. + if (Result == 4 /*ROUND_CUR_DIRECTION*/ || Result == 8 /*ROUND_NO_EXC*/ || + (!HasRC && Result == 12 /*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) || + (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_x86_builtin_invalid_rounding) + << Arg->getSourceRange(); +} + +// Check if the gather/scatter scale is legal. +bool SemaX86::CheckBuiltinGatherScatterScale(unsigned BuiltinID, + CallExpr *TheCall) { + unsigned ArgNum = 0; + switch (BuiltinID) { + default: + return false; + case X86::BI__builtin_ia32_gatherd_pd: + case X86::BI__builtin_ia32_gatherd_pd256: + case X86::BI__builtin_ia32_gatherq_pd: + case X86::BI__builtin_ia32_gatherq_pd256: + case X86::BI__builtin_ia32_gatherd_ps: + case X86::BI__builtin_ia32_gatherd_ps256: + case X86::BI__builtin_ia32_gatherq_ps: + case X86::BI__builtin_ia32_gatherq_ps256: + case X86::BI__builtin_ia32_gatherd_q: + case X86::BI__builtin_ia32_gatherd_q256: + case X86::BI__builtin_ia32_gatherq_q: + case X86::BI__builtin_ia32_gatherq_q256: + case X86::BI__builtin_ia32_gatherd_d: + case X86::BI__builtin_ia32_gatherd_d256: + case X86::BI__builtin_ia32_gatherq_d: + case X86::BI__builtin_ia32_gatherq_d256: + case X86::BI__builtin_ia32_gather3div2df: + case X86::BI__builtin_ia32_gather3div2di: + case X86::BI__builtin_ia32_gather3div4df: + case X86::BI__builtin_ia32_gather3div4di: + case X86::BI__builtin_ia32_gather3div4sf: + case X86::BI__builtin_ia32_gather3div4si: + case X86::BI__builtin_ia32_gather3div8sf: + case X86::BI__builtin_ia32_gather3div8si: + case X86::BI__builtin_ia32_gather3siv2df: + case X86::BI__builtin_ia32_gather3siv2di: + case X86::BI__builtin_ia32_gather3siv4df: + case X86::BI__builtin_ia32_gather3siv4di: + case X86::BI__builtin_ia32_gather3siv4sf: + case X86::BI__builtin_ia32_gather3siv4si: + case X86::BI__builtin_ia32_gather3siv8sf: + case X86::BI__builtin_ia32_gather3siv8si: + case X86::BI__builtin_ia32_gathersiv8df: + case X86::BI__builtin_ia32_gathersiv16sf: + case X86::BI__builtin_ia32_gatherdiv8df: + case X86::BI__builtin_ia32_gatherdiv16sf: + case X86::BI__builtin_ia32_gathersiv8di: + case X86::BI__builtin_ia32_gathersiv16si: + case X86::BI__builtin_ia32_gatherdiv8di: + case X86::BI__builtin_ia32_gatherdiv16si: + case X86::BI__builtin_ia32_scatterdiv2df: + case X86::BI__builtin_ia32_scatterdiv2di: + case X86::BI__builtin_ia32_scatterdiv4df: + case X86::BI__builtin_ia32_scatterdiv4di: + case X86::BI__builtin_ia32_scatterdiv4sf: + case X86::BI__builtin_ia32_scatterdiv4si: + case X86::BI__builtin_ia32_scatterdiv8sf: + case X86::BI__builtin_ia32_scatterdiv8si: + case X86::BI__builtin_ia32_scattersiv2df: + case X86::BI__builtin_ia32_scattersiv2di: + case X86::BI__builtin_ia32_scattersiv4df: + case X86::BI__builtin_ia32_scattersiv4di: + case X86::BI__builtin_ia32_scattersiv4sf: + case X86::BI__builtin_ia32_scattersiv4si: + case X86::BI__builtin_ia32_scattersiv8sf: + case X86::BI__builtin_ia32_scattersiv8si: + case X86::BI__builtin_ia32_scattersiv8df: + case X86::BI__builtin_ia32_scattersiv16sf: + case X86::BI__builtin_ia32_scatterdiv8df: + case X86::BI__builtin_ia32_scatterdiv16sf: + case X86::BI__builtin_ia32_scattersiv8di: + case X86::BI__builtin_ia32_scattersiv16si: + case X86::BI__builtin_ia32_scatterdiv8di: + case X86::BI__builtin_ia32_scatterdiv16si: + ArgNum = 4; + break; + } + + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + if (Result == 1 || Result == 2 || Result == 4 || Result == 8) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_x86_builtin_invalid_scale) + << Arg->getSourceRange(); +} + +enum { TileRegLow = 0, TileRegHigh = 7 }; + +bool SemaX86::CheckBuiltinTileArgumentsRange(CallExpr *TheCall, + ArrayRef ArgNums) { + for (int ArgNum : ArgNums) { + if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, + TileRegHigh)) + return true; + } + return false; +} + +bool SemaX86::CheckBuiltinTileDuplicate(CallExpr *TheCall, + ArrayRef ArgNums) { + // Because the max number of tile register is TileRegHigh + 1, so here we use + // each bit to represent the usage of them in bitset. + std::bitset ArgValues; + for (int ArgNum : ArgNums) { + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + continue; + + llvm::APSInt Result; + if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + int ArgExtValue = Result.getExtValue(); + assert((ArgExtValue >= TileRegLow && ArgExtValue <= TileRegHigh) && + "Incorrect tile register num."); + if (ArgValues.test(ArgExtValue)) + return Diag(TheCall->getBeginLoc(), + diag::err_x86_builtin_tile_arg_duplicate) + << TheCall->getArg(ArgNum)->getSourceRange(); + ArgValues.set(ArgExtValue); + } + return false; +} + +bool SemaX86::CheckBuiltinTileRangeAndDuplicate(CallExpr *TheCall, + ArrayRef ArgNums) { + return CheckBuiltinTileArgumentsRange(TheCall, ArgNums) || + CheckBuiltinTileDuplicate(TheCall, ArgNums); +} + +bool SemaX86::CheckBuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; + case X86::BI__builtin_ia32_tileloadd64: + case X86::BI__builtin_ia32_tileloaddt164: + case X86::BI__builtin_ia32_tilestored64: + case X86::BI__builtin_ia32_tilezero: + return CheckBuiltinTileArgumentsRange(TheCall, 0); + case X86::BI__builtin_ia32_tdpbssd: + case X86::BI__builtin_ia32_tdpbsud: + case X86::BI__builtin_ia32_tdpbusd: + case X86::BI__builtin_ia32_tdpbuud: + case X86::BI__builtin_ia32_tdpbf16ps: + case X86::BI__builtin_ia32_tdpfp16ps: + case X86::BI__builtin_ia32_tcmmimfp16ps: + case X86::BI__builtin_ia32_tcmmrlfp16ps: + return CheckBuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2}); + } +} +static bool isX86_32Builtin(unsigned BuiltinID) { + // These builtins only work on x86-32 targets. + switch (BuiltinID) { + case X86::BI__builtin_ia32_readeflags_u32: + case X86::BI__builtin_ia32_writeeflags_u32: + return true; + } + + return false; +} + +bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { + // Check for 32-bit only builtins on a 64-bit target. + const llvm::Triple &TT = TI.getTriple(); + if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) + return Diag(TheCall->getCallee()->getBeginLoc(), + diag::err_32_bit_builtin_64_bit_tgt); + + // If the intrinsic has rounding or SAE make sure its valid. + if (CheckBuiltinRoundingOrSAE(BuiltinID, TheCall)) + return true; + + // If the intrinsic has a gather/scatter scale immediate make sure its valid. + if (CheckBuiltinGatherScatterScale(BuiltinID, TheCall)) + return true; + + // If the intrinsic has a tile arguments, make sure they are valid. + if (CheckBuiltinTileArguments(BuiltinID, TheCall)) + return true; + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + int i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: + return false; + case X86::BI__builtin_ia32_vec_ext_v2si: + case X86::BI__builtin_ia32_vec_ext_v2di: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + i = 1; + l = 0; + u = 1; + break; + case X86::BI__builtin_ia32_vec_set_v2di: + case X86::BI__builtin_ia32_vinsertf128_pd256: + case X86::BI__builtin_ia32_vinsertf128_ps256: + case X86::BI__builtin_ia32_vinsertf128_si256: + case X86::BI__builtin_ia32_insert128i256: + case X86::BI__builtin_ia32_insertf32x8: + case X86::BI__builtin_ia32_inserti32x8: + case X86::BI__builtin_ia32_insertf64x4: + case X86::BI__builtin_ia32_inserti64x4: + case X86::BI__builtin_ia32_insertf64x2_256: + case X86::BI__builtin_ia32_inserti64x2_256: + case X86::BI__builtin_ia32_insertf32x4_256: + case X86::BI__builtin_ia32_inserti32x4_256: + i = 2; + l = 0; + u = 1; + break; + case X86::BI__builtin_ia32_vpermilpd: + case X86::BI__builtin_ia32_vec_ext_v4hi: + case X86::BI__builtin_ia32_vec_ext_v4si: + case X86::BI__builtin_ia32_vec_ext_v4sf: + case X86::BI__builtin_ia32_vec_ext_v4di: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + i = 1; + l = 0; + u = 3; + break; + case X86::BI_mm_prefetch: + case X86::BI__builtin_ia32_vec_ext_v8hi: + case X86::BI__builtin_ia32_vec_ext_v8si: + i = 1; + l = 0; + u = 7; + break; + case X86::BI__builtin_ia32_sha1rnds4: + case X86::BI__builtin_ia32_blendpd: + case X86::BI__builtin_ia32_shufpd: + case X86::BI__builtin_ia32_vec_set_v4hi: + case X86::BI__builtin_ia32_vec_set_v4si: + case X86::BI__builtin_ia32_vec_set_v4di: + case X86::BI__builtin_ia32_shuf_f32x4_256: + case X86::BI__builtin_ia32_shuf_f64x2_256: + case X86::BI__builtin_ia32_shuf_i32x4_256: + case X86::BI__builtin_ia32_shuf_i64x2_256: + case X86::BI__builtin_ia32_insertf64x2_512: + case X86::BI__builtin_ia32_inserti64x2_512: + case X86::BI__builtin_ia32_insertf32x4: + case X86::BI__builtin_ia32_inserti32x4: + i = 2; + l = 0; + u = 3; + break; + case X86::BI__builtin_ia32_vpermil2pd: + case X86::BI__builtin_ia32_vpermil2pd256: + case X86::BI__builtin_ia32_vpermil2ps: + case X86::BI__builtin_ia32_vpermil2ps256: + i = 3; + l = 0; + u = 3; + break; + case X86::BI__builtin_ia32_cmpb128_mask: + case X86::BI__builtin_ia32_cmpw128_mask: + case X86::BI__builtin_ia32_cmpd128_mask: + case X86::BI__builtin_ia32_cmpq128_mask: + case X86::BI__builtin_ia32_cmpb256_mask: + case X86::BI__builtin_ia32_cmpw256_mask: + case X86::BI__builtin_ia32_cmpd256_mask: + case X86::BI__builtin_ia32_cmpq256_mask: + case X86::BI__builtin_ia32_cmpb512_mask: + case X86::BI__builtin_ia32_cmpw512_mask: + case X86::BI__builtin_ia32_cmpd512_mask: + case X86::BI__builtin_ia32_cmpq512_mask: + case X86::BI__builtin_ia32_ucmpb128_mask: + case X86::BI__builtin_ia32_ucmpw128_mask: + case X86::BI__builtin_ia32_ucmpd128_mask: + case X86::BI__builtin_ia32_ucmpq128_mask: + case X86::BI__builtin_ia32_ucmpb256_mask: + case X86::BI__builtin_ia32_ucmpw256_mask: + case X86::BI__builtin_ia32_ucmpd256_mask: + case X86::BI__builtin_ia32_ucmpq256_mask: + case X86::BI__builtin_ia32_ucmpb512_mask: + case X86::BI__builtin_ia32_ucmpw512_mask: + case X86::BI__builtin_ia32_ucmpd512_mask: + case X86::BI__builtin_ia32_ucmpq512_mask: + case X86::BI__builtin_ia32_vpcomub: + case X86::BI__builtin_ia32_vpcomuw: + case X86::BI__builtin_ia32_vpcomud: + case X86::BI__builtin_ia32_vpcomuq: + case X86::BI__builtin_ia32_vpcomb: + case X86::BI__builtin_ia32_vpcomw: + case X86::BI__builtin_ia32_vpcomd: + case X86::BI__builtin_ia32_vpcomq: + case X86::BI__builtin_ia32_vec_set_v8hi: + case X86::BI__builtin_ia32_vec_set_v8si: + i = 2; + l = 0; + u = 7; + break; + case X86::BI__builtin_ia32_vpermilpd256: + case X86::BI__builtin_ia32_roundps: + case X86::BI__builtin_ia32_roundpd: + case X86::BI__builtin_ia32_roundps256: + case X86::BI__builtin_ia32_roundpd256: + case X86::BI__builtin_ia32_getmantpd128_mask: + case X86::BI__builtin_ia32_getmantpd256_mask: + case X86::BI__builtin_ia32_getmantps128_mask: + case X86::BI__builtin_ia32_getmantps256_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_getmantph128_mask: + case X86::BI__builtin_ia32_getmantph256_mask: + case X86::BI__builtin_ia32_getmantph512_mask: + case X86::BI__builtin_ia32_vec_ext_v16qi: + case X86::BI__builtin_ia32_vec_ext_v16hi: + i = 1; + l = 0; + u = 15; + break; + case X86::BI__builtin_ia32_pblendd128: + case X86::BI__builtin_ia32_blendps: + case X86::BI__builtin_ia32_blendpd256: + case X86::BI__builtin_ia32_shufpd256: + case X86::BI__builtin_ia32_roundss: + case X86::BI__builtin_ia32_roundsd: + case X86::BI__builtin_ia32_rangepd128_mask: + case X86::BI__builtin_ia32_rangepd256_mask: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps128_mask: + case X86::BI__builtin_ia32_rangeps256_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_getmantsh_round_mask: + case X86::BI__builtin_ia32_vec_set_v16qi: + case X86::BI__builtin_ia32_vec_set_v16hi: + i = 2; + l = 0; + u = 15; + break; + case X86::BI__builtin_ia32_vec_ext_v32qi: + i = 1; + l = 0; + u = 31; + break; + case X86::BI__builtin_ia32_cmpps: + case X86::BI__builtin_ia32_cmpss: + case X86::BI__builtin_ia32_cmppd: + case X86::BI__builtin_ia32_cmpsd: + case X86::BI__builtin_ia32_cmpps256: + case X86::BI__builtin_ia32_cmppd256: + case X86::BI__builtin_ia32_cmpps128_mask: + case X86::BI__builtin_ia32_cmppd128_mask: + case X86::BI__builtin_ia32_cmpps256_mask: + case X86::BI__builtin_ia32_cmppd256_mask: + case X86::BI__builtin_ia32_cmpps512_mask: + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_vec_set_v32qi: + i = 2; + l = 0; + u = 31; + break; + case X86::BI__builtin_ia32_permdf256: + case X86::BI__builtin_ia32_permdi256: + case X86::BI__builtin_ia32_permdf512: + case X86::BI__builtin_ia32_permdi512: + case X86::BI__builtin_ia32_vpermilps: + case X86::BI__builtin_ia32_vpermilps256: + case X86::BI__builtin_ia32_vpermilpd512: + case X86::BI__builtin_ia32_vpermilps512: + case X86::BI__builtin_ia32_pshufd: + case X86::BI__builtin_ia32_pshufd256: + case X86::BI__builtin_ia32_pshufd512: + case X86::BI__builtin_ia32_pshufhw: + case X86::BI__builtin_ia32_pshufhw256: + case X86::BI__builtin_ia32_pshufhw512: + case X86::BI__builtin_ia32_pshuflw: + case X86::BI__builtin_ia32_pshuflw256: + case X86::BI__builtin_ia32_pshuflw512: + case X86::BI__builtin_ia32_vcvtps2ph: + case X86::BI__builtin_ia32_vcvtps2ph_mask: + case X86::BI__builtin_ia32_vcvtps2ph256: + case X86::BI__builtin_ia32_vcvtps2ph256_mask: + case X86::BI__builtin_ia32_vcvtps2ph512_mask: + case X86::BI__builtin_ia32_rndscaleps_128_mask: + case X86::BI__builtin_ia32_rndscalepd_128_mask: + case X86::BI__builtin_ia32_rndscaleps_256_mask: + case X86::BI__builtin_ia32_rndscalepd_256_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_rndscaleph_mask: + case X86::BI__builtin_ia32_reducepd128_mask: + case X86::BI__builtin_ia32_reducepd256_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps128_mask: + case X86::BI__builtin_ia32_reduceps256_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_reduceph128_mask: + case X86::BI__builtin_ia32_reduceph256_mask: + case X86::BI__builtin_ia32_reduceph512_mask: + case X86::BI__builtin_ia32_prold512: + case X86::BI__builtin_ia32_prolq512: + case X86::BI__builtin_ia32_prold128: + case X86::BI__builtin_ia32_prold256: + case X86::BI__builtin_ia32_prolq128: + case X86::BI__builtin_ia32_prolq256: + case X86::BI__builtin_ia32_prord512: + case X86::BI__builtin_ia32_prorq512: + case X86::BI__builtin_ia32_prord128: + case X86::BI__builtin_ia32_prord256: + case X86::BI__builtin_ia32_prorq128: + case X86::BI__builtin_ia32_prorq256: + case X86::BI__builtin_ia32_fpclasspd128_mask: + case X86::BI__builtin_ia32_fpclasspd256_mask: + case X86::BI__builtin_ia32_fpclassps128_mask: + case X86::BI__builtin_ia32_fpclassps256_mask: + case X86::BI__builtin_ia32_fpclassps512_mask: + case X86::BI__builtin_ia32_fpclasspd512_mask: + case X86::BI__builtin_ia32_fpclassph128_mask: + case X86::BI__builtin_ia32_fpclassph256_mask: + case X86::BI__builtin_ia32_fpclassph512_mask: + case X86::BI__builtin_ia32_fpclasssd_mask: + case X86::BI__builtin_ia32_fpclassss_mask: + case X86::BI__builtin_ia32_fpclasssh_mask: + case X86::BI__builtin_ia32_pslldqi128_byteshift: + case X86::BI__builtin_ia32_pslldqi256_byteshift: + case X86::BI__builtin_ia32_pslldqi512_byteshift: + case X86::BI__builtin_ia32_psrldqi128_byteshift: + case X86::BI__builtin_ia32_psrldqi256_byteshift: + case X86::BI__builtin_ia32_psrldqi512_byteshift: + case X86::BI__builtin_ia32_kshiftliqi: + case X86::BI__builtin_ia32_kshiftlihi: + case X86::BI__builtin_ia32_kshiftlisi: + case X86::BI__builtin_ia32_kshiftlidi: + case X86::BI__builtin_ia32_kshiftriqi: + case X86::BI__builtin_ia32_kshiftrihi: + case X86::BI__builtin_ia32_kshiftrisi: + case X86::BI__builtin_ia32_kshiftridi: + i = 1; + l = 0; + u = 255; + break; + case X86::BI__builtin_ia32_vperm2f128_pd256: + case X86::BI__builtin_ia32_vperm2f128_ps256: + case X86::BI__builtin_ia32_vperm2f128_si256: + case X86::BI__builtin_ia32_permti256: + case X86::BI__builtin_ia32_pblendw128: + case X86::BI__builtin_ia32_pblendw256: + case X86::BI__builtin_ia32_blendps256: + case X86::BI__builtin_ia32_pblendd256: + case X86::BI__builtin_ia32_palignr128: + case X86::BI__builtin_ia32_palignr256: + case X86::BI__builtin_ia32_palignr512: + case X86::BI__builtin_ia32_alignq512: + case X86::BI__builtin_ia32_alignd512: + case X86::BI__builtin_ia32_alignd128: + case X86::BI__builtin_ia32_alignd256: + case X86::BI__builtin_ia32_alignq128: + case X86::BI__builtin_ia32_alignq256: + case X86::BI__builtin_ia32_vcomisd: + case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_shuf_f32x4: + case X86::BI__builtin_ia32_shuf_f64x2: + case X86::BI__builtin_ia32_shuf_i32x4: + case X86::BI__builtin_ia32_shuf_i64x2: + case X86::BI__builtin_ia32_shufpd512: + case X86::BI__builtin_ia32_shufps: + case X86::BI__builtin_ia32_shufps256: + case X86::BI__builtin_ia32_shufps512: + case X86::BI__builtin_ia32_dbpsadbw128: + case X86::BI__builtin_ia32_dbpsadbw256: + case X86::BI__builtin_ia32_dbpsadbw512: + case X86::BI__builtin_ia32_vpshldd128: + case X86::BI__builtin_ia32_vpshldd256: + case X86::BI__builtin_ia32_vpshldd512: + case X86::BI__builtin_ia32_vpshldq128: + case X86::BI__builtin_ia32_vpshldq256: + case X86::BI__builtin_ia32_vpshldq512: + case X86::BI__builtin_ia32_vpshldw128: + case X86::BI__builtin_ia32_vpshldw256: + case X86::BI__builtin_ia32_vpshldw512: + case X86::BI__builtin_ia32_vpshrdd128: + case X86::BI__builtin_ia32_vpshrdd256: + case X86::BI__builtin_ia32_vpshrdd512: + case X86::BI__builtin_ia32_vpshrdq128: + case X86::BI__builtin_ia32_vpshrdq256: + case X86::BI__builtin_ia32_vpshrdq512: + case X86::BI__builtin_ia32_vpshrdw128: + case X86::BI__builtin_ia32_vpshrdw256: + case X86::BI__builtin_ia32_vpshrdw512: + i = 2; + l = 0; + u = 255; + break; + case X86::BI__builtin_ia32_fixupimmpd512_mask: + case X86::BI__builtin_ia32_fixupimmpd512_maskz: + case X86::BI__builtin_ia32_fixupimmps512_mask: + case X86::BI__builtin_ia32_fixupimmps512_maskz: + case X86::BI__builtin_ia32_fixupimmsd_mask: + case X86::BI__builtin_ia32_fixupimmsd_maskz: + case X86::BI__builtin_ia32_fixupimmss_mask: + case X86::BI__builtin_ia32_fixupimmss_maskz: + case X86::BI__builtin_ia32_fixupimmpd128_mask: + case X86::BI__builtin_ia32_fixupimmpd128_maskz: + case X86::BI__builtin_ia32_fixupimmpd256_mask: + case X86::BI__builtin_ia32_fixupimmpd256_maskz: + case X86::BI__builtin_ia32_fixupimmps128_mask: + case X86::BI__builtin_ia32_fixupimmps128_maskz: + case X86::BI__builtin_ia32_fixupimmps256_mask: + case X86::BI__builtin_ia32_fixupimmps256_maskz: + case X86::BI__builtin_ia32_pternlogd512_mask: + case X86::BI__builtin_ia32_pternlogd512_maskz: + case X86::BI__builtin_ia32_pternlogq512_mask: + case X86::BI__builtin_ia32_pternlogq512_maskz: + case X86::BI__builtin_ia32_pternlogd128_mask: + case X86::BI__builtin_ia32_pternlogd128_maskz: + case X86::BI__builtin_ia32_pternlogd256_mask: + case X86::BI__builtin_ia32_pternlogd256_maskz: + case X86::BI__builtin_ia32_pternlogq128_mask: + case X86::BI__builtin_ia32_pternlogq128_maskz: + case X86::BI__builtin_ia32_pternlogq256_mask: + case X86::BI__builtin_ia32_pternlogq256_maskz: + case X86::BI__builtin_ia32_vsm3rnds2: + i = 3; + l = 0; + u = 255; + break; + case X86::BI__builtin_ia32_reducesd_mask: + case X86::BI__builtin_ia32_reducess_mask: + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + case X86::BI__builtin_ia32_rndscalesh_round_mask: + case X86::BI__builtin_ia32_reducesh_mask: + i = 4; + l = 0; + u = 255; + break; + case X86::BI__builtin_ia32_cmpccxadd32: + case X86::BI__builtin_ia32_cmpccxadd64: + i = 3; + l = 0; + u = 15; + break; + } + + // Note that we don't force a hard error on the range check here, allowing + // template-generated or macro-generated dead code to potentially have out-of- + // range values. These need to code generate, but don't need to necessarily + // make any sense. We use a warning that defaults to an error. + return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u, + /*RangeIsError*/ false); +} + +void SemaX86::handleAnyInterruptAttr(Decl *D, const ParsedAttr &AL) { + // Semantic checks for a function with the 'interrupt' attribute. + // a) Must be a function. + // b) Must have the 'void' return type. + // c) Must take 1 or 2 arguments. + // d) The 1st argument must be a pointer. + // e) The 2nd argument (if any) must be an unsigned integer. + ASTContext &Context = getASTContext(); + + if (!isFuncOrMethodForAttrSubject(D) || !hasFunctionProto(D) || + isInstanceMethod(D) || + CXXMethodDecl::isStaticOverloadedOperator( + cast(D)->getDeclName().getCXXOverloadedOperator())) { + Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionWithProtoType; + return; + } + // Interrupt handler must have void return type. + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + Diag(getFunctionOrMethodResultSourceRange(D).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (SemaRef.Context.getTargetInfo().getTriple().getArch() == + llvm::Triple::x86 + ? 0 + : 1) + << 0; + return; + } + // Interrupt handler must have 1 or 2 parameters. + unsigned NumParams = getFunctionOrMethodNumParams(D); + if (NumParams < 1 || NumParams > 2) { + Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute) + << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 1; + return; + } + // The first argument must be a pointer. + if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) { + Diag(getFunctionOrMethodParamRange(D, 0).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 2; + return; + } + // The second argument, if present, must be an unsigned integer. + unsigned TypeSize = + Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64 + ? 64 + : 32; + if (NumParams == 2 && + (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() || + Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) { + Diag(getFunctionOrMethodParamRange(D, 1).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 3 << Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false); + return; + } + D->addAttr(::new (Context) AnyX86InterruptAttr(Context, AL)); + D->addAttr(UsedAttr::CreateImplicit(Context)); +} + +void SemaX86::handleForceAlignArgPointerAttr(Decl *D, const ParsedAttr &AL) { + // If we try to apply it to a function pointer, don't warn, but don't + // do anything, either. It doesn't matter anyway, because there's nothing + // special about calling a force_align_arg_pointer function. + const auto *VD = dyn_cast(D); + if (VD && VD->getType()->isFunctionPointerType()) + return; + // Also don't warn on function pointer typedefs. + const auto *TD = dyn_cast(D); + if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || + TD->getUnderlyingType()->isFunctionType())) + return; + // Attribute can only be applied to function types. + if (!isa(D)) { + Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; + return; + } + + D->addAttr(::new (getASTContext()) + X86ForceAlignArgPointerAttr(getASTContext(), AL)); +} + +} // namespace clang diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6b53c2490cc492f8aea570d11f968322334175ea..95dd356d48bedd2e9230e1d2b569a363799aed28 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4033,11 +4033,21 @@ public: StmtResult RebuildOpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult StrBlock) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, EndLoc, - Clauses, StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, + EndLoc, Clauses, StrBlock); + } + + StmtResult RebuildOpenACCLoopConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + StmtResult Loop) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, EndLoc, Clauses, Loop); } private: @@ -4604,6 +4614,7 @@ TreeTransform::TransformTemplateName(CXXScopeSpec &SS, ObjectType, AllowInjectedClassName); } + // FIXME: Try to preserve more of the TemplateName. if (TemplateDecl *Template = Name.getAsTemplateDecl()) { TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, @@ -4611,11 +4622,8 @@ TreeTransform::TransformTemplateName(CXXScopeSpec &SS, if (!TransTemplate) return TemplateName(); - if (!getDerived().AlwaysRebuild() && - TransTemplate == Template) - return Name; - - return TemplateName(TransTemplate); + return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false, + TransTemplate); } if (SubstTemplateTemplateParmPackStorage *SubstPack @@ -7337,7 +7345,7 @@ QualType TreeTransform::TransformCountAttributedType( if (getDerived().AlwaysRebuild() || InnerTy != OldTy->desugar() || OldCount != NewCount) { // Currently, CountAttributedType can only wrap incomplete array types. - Result = SemaRef.BuildCountAttributedArrayType(InnerTy, NewCount); + Result = SemaRef.BuildCountAttributedArrayOrPointerType(InnerTy, NewCount); } TLB.push(Result); @@ -11488,6 +11496,31 @@ void OpenACCClauseTransform::VisitDeviceTypeClause( C.getArchitectures(), ParsedClause.getEndLoc()); } +template +void OpenACCClauseTransform::VisitAutoClause( + const OpenACCAutoClause &C) { + // Nothing to do, so just create a new node. + NewClause = OpenACCAutoClause::Create(Self.getSema().getASTContext(), + ParsedClause.getBeginLoc(), + ParsedClause.getEndLoc()); +} + +template +void OpenACCClauseTransform::VisitIndependentClause( + const OpenACCIndependentClause &C) { + NewClause = OpenACCIndependentClause::Create(Self.getSema().getASTContext(), + ParsedClause.getBeginLoc(), + ParsedClause.getEndLoc()); +} + +template +void OpenACCClauseTransform::VisitSeqClause( + const OpenACCSeqClause &C) { + NewClause = OpenACCSeqClause::Create(Self.getSema().getASTContext(), + ParsedClause.getBeginLoc(), + ParsedClause.getEndLoc()); +} + template void OpenACCClauseTransform::VisitReductionClause( const OpenACCReductionClause &C) { @@ -11542,8 +11575,6 @@ template StmtResult TreeTransform::TransformOpenACCComputeConstruct( OpenACCComputeConstruct *C) { getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); - // FIXME: When implementing this for constructs that can take arguments, we - // should do Sema for them here. if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(), C->getBeginLoc())) @@ -11552,15 +11583,42 @@ StmtResult TreeTransform::TransformOpenACCComputeConstruct( llvm::SmallVector TransformedClauses = getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), C->clauses()); - // Transform Structured Block. + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(), + C->getDirectiveKind()); StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock()); - StrBlock = - getSema().OpenACC().ActOnAssociatedStmt(C->getDirectiveKind(), StrBlock); + StrBlock = getSema().OpenACC().ActOnAssociatedStmt( + C->getBeginLoc(), C->getDirectiveKind(), StrBlock); return getDerived().RebuildOpenACCComputeConstruct( - C->getDirectiveKind(), C->getBeginLoc(), C->getEndLoc(), - TransformedClauses, StrBlock); + C->getDirectiveKind(), C->getBeginLoc(), C->getDirectiveLoc(), + C->getEndLoc(), TransformedClauses, StrBlock); +} + +template +StmtResult +TreeTransform::TransformOpenACCLoopConstruct(OpenACCLoopConstruct *C) { + + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(), + C->getBeginLoc())) + return StmtError(); + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + + // Transform Loop. + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(), + C->getDirectiveKind()); + StmtResult Loop = getDerived().TransformStmt(C->getLoop()); + Loop = getSema().OpenACC().ActOnAssociatedStmt(C->getBeginLoc(), + C->getDirectiveKind(), Loop); + + return getDerived().RebuildOpenACCLoopConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses, Loop); } //===----------------------------------------------------------------------===// @@ -14114,6 +14172,13 @@ TreeTransform::TransformCXXTemporaryObjectExpr( if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) return ExprError(); + + if (E->isListInitialization() && !E->isStdInitListInitialization()) { + ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc()); + if (Res.isInvalid()) + return ExprError(); + Args = {Res.get()}; + } } if (!getDerived().AlwaysRebuild() && @@ -14125,12 +14190,9 @@ TreeTransform::TransformCXXTemporaryObjectExpr( return SemaRef.MaybeBindToTemporary(E); } - // FIXME: We should just pass E->isListInitialization(), but we're not - // prepared to handle list-initialization without a child InitListExpr. SourceLocation LParenLoc = T->getTypeLoc().getEndLoc(); return getDerived().RebuildCXXTemporaryObjectExpr( - T, LParenLoc, Args, E->getEndLoc(), - /*ListInitialization=*/LParenLoc.isInvalid()); + T, LParenLoc, Args, E->getEndLoc(), E->isListInitialization()); } template @@ -14244,7 +14306,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // will be deemed as dependent even if there are no dependent template // arguments. // (A ClassTemplateSpecializationDecl is always a dependent context.) - while (DC->getDeclKind() == Decl::Kind::RequiresExprBody) + while (DC->isRequiresExprBody()) DC = DC->getParent(); if ((getSema().isUnevaluatedContext() || getSema().isConstantEvaluatedContext()) && diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index d7fc6697eaf74c41aec86d6ceb3d3e382126e60a..33cea32c3be6126351ee9fe50b1950cf1ff13f7c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -40,9 +40,11 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/ASTSourceDescriptor.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticError.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/ExceptionSpecificationType.h" @@ -1264,7 +1266,7 @@ bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, if (!Lex.first) { Lex = std::make_pair( &M, llvm::ArrayRef( - reinterpret_cast(Blob.data()), + reinterpret_cast(Blob.data()), Blob.size() / sizeof(DeclID))); } DC->setHasExternalLexicalStorage(true); @@ -3401,7 +3403,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, case TU_UPDATE_LEXICAL: { DeclContext *TU = ContextObj->getTranslationUnitDecl(); LexicalContents Contents( - reinterpret_cast(Blob.data()), + reinterpret_cast(Blob.data()), static_cast(Blob.size() / sizeof(DeclID))); TULexicalDecls.push_back(std::make_pair(&F, Contents)); TU->setHasExternalLexicalStorage(true); @@ -4059,7 +4061,7 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { RemapBuilder DeclRemap(F.DeclRemap); RemapBuilder TypeRemap(F.TypeRemap); - auto &ImportedModuleVector = F.DependentModules; + auto &ImportedModuleVector = F.TransitiveImports; assert(ImportedModuleVector.empty()); while (Data < DataEnd) { @@ -9403,6 +9405,20 @@ DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const { return Diags.Report(Loc, DiagID); } +void ASTReader::warnStackExhausted(SourceLocation Loc) { + // When Sema is available, avoid duplicate errors. + if (SemaObj) { + SemaObj->warnStackExhausted(Loc); + return; + } + + if (WarnedStackExhausted) + return; + WarnedStackExhausted = true; + + Diag(Loc, diag::warn_stack_exhausted); +} + /// Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &ASTReader::getIdentifierTable() { @@ -11928,12 +11944,15 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCReductionClause::Create(getContext(), BeginLoc, LParenLoc, Op, VarList, EndLoc); } - - case OpenACCClauseKind::Finalize: - case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Seq: + return OpenACCSeqClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Independent: + return OpenACCIndependentClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Auto: + return OpenACCAutoClause::Create(getContext(), BeginLoc, EndLoc); + + case OpenACCClauseKind::Finalize: + case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Worker: case OpenACCClauseKind::Vector: case OpenACCClauseKind::NoHost: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index a6254b70560c365025028a7693c52587ca4db6e0..765c083ce8df8cbb67adc232a962d906c5692ad5 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -49,6 +49,7 @@ #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/Stack.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTRecordReader.h" @@ -2695,7 +2696,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { } if (Record.readInt()) - D->setDefaultArgument(readTypeSourceInfo()); + D->setDefaultArgument(Reader.getContext(), + Record.readTemplateArgumentLoc()); } void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { @@ -2716,7 +2718,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // Rest of NonTypeTemplateParmDecl. D->ParameterPack = Record.readInt(); if (Record.readInt()) - D->setDefaultArgument(Record.readExpr()); + D->setDefaultArgument(Reader.getContext(), + Record.readTemplateArgumentLoc()); } } @@ -4125,7 +4128,10 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { // calls to Decl::getASTContext() by Decl's methods will find the // TranslationUnitDecl without crashing. D->setDeclContext(Context.getTranslationUnitDecl()); - Reader.Visit(D); + + // Reading some declarations can result in deep recursion. + clang::runWithSufficientStackSpace([&] { warnStackExhausted(DeclLoc); }, + [&] { Reader.Visit(D); }); // If this declaration is also a declaration context, get the // offsets for its tables of lexical and visible declarations. diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index eac4faff285490b09b6f307bd02c2c578351bddb..67ef170251914ea58fb1568bf6b1ce9f3ca0d057 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2797,6 +2797,7 @@ void ASTStmtReader::VisitOpenACCConstructStmt(OpenACCConstructStmt *S) { (void)Record.readInt(); S->Kind = Record.readEnum(); S->Range = Record.readSourceRange(); + S->DirectiveLoc = Record.readSourceLocation(); Record.readOpenACCClauseList(S->Clauses); } @@ -2809,6 +2810,12 @@ void ASTStmtReader::VisitOpenACCAssociatedStmtConstruct( void ASTStmtReader::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { VisitStmt(S); VisitOpenACCAssociatedStmtConstruct(S); + S->findAndSetChildLoops(); +} + +void ASTStmtReader::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); } //===----------------------------------------------------------------------===// @@ -4234,6 +4241,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OpenACCComputeConstruct::CreateEmpty(Context, NumClauses); break; } + case STMT_OPENACC_LOOP_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCLoopConstruct::CreateEmpty(Context, NumClauses); + break; + } case EXPR_REQUIRES: unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 00b0e48083217c2c8bfc4042f6959b5659fae0d5..953990a4aca6db686d6b4ee9887b794f67a2e0de 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1049,6 +1049,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_UNRESOLVED_USING_VALUE); RECORD(DECL_UNRESOLVED_USING_TYPENAME); RECORD(DECL_LINKAGE_SPEC); + RECORD(DECL_EXPORT); RECORD(DECL_CXX_RECORD); RECORD(DECL_CXX_METHOD); RECORD(DECL_CXX_CONSTRUCTOR); @@ -3204,9 +3205,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, } // Sort by diag::kind for deterministic output. - llvm::sort(Mappings, [](const auto &LHS, const auto &RHS) { - return LHS.first < RHS.first; - }); + llvm::sort(Mappings, llvm::less_first()); for (const auto &I : Mappings) { Record.push_back(I.first); @@ -3898,8 +3897,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, // Write out identifiers if either the ID is local or the identifier has // changed since it was loaded. - if (ID >= FirstIdentID || !Chain || !II->isFromAST() || - II->hasChangedSinceDeserialization() || + if (ID >= FirstIdentID || II->hasChangedSinceDeserialization() || (Trait.needDecls() && II->hasFETokenInfoChangedSinceDeserialization())) Generator.insert(II, ID, Trait); @@ -5037,6 +5035,14 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) { continue; } + // If we're writing C++ named modules, don't emit declarations which are + // not from modules by default. They may be built in declarations (be + // handled above) or implcit declarations (see the implementation of + // `Sema::Initialize()` for example). + if (isWritingStdCXXNamedModules() && !D->getOwningModule() && + D->isImplicit()) + continue; + GetDeclRef(D); } @@ -6197,8 +6203,9 @@ bool ASTWriter::wasDeclEmitted(const Decl *D) const { return true; bool Emitted = DeclIDs.contains(D); - assert((Emitted || GeneratingReducedBMI) && - "The declaration can only be omitted in reduced BMI."); + assert((Emitted || (!D->getOwningModule() && isWritingStdCXXNamedModules()) || + GeneratingReducedBMI) && + "The declaration within modules can only be omitted in reduced BMI."); return Emitted; } @@ -6501,10 +6508,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { // computed. Record->push_back(D->getODRHash()); - bool ModulesDebugInfo = - Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType(); - Record->push_back(ModulesDebugInfo); - if (ModulesDebugInfo) + bool ModulesCodegen = + !D->isDependentType() && + (Writer->Context->getLangOpts().ModulesDebugInfo || + D->isInNamedModule()); + Record->push_back(ModulesCodegen); + if (ModulesCodegen) Writer->AddDeclRef(D, Writer->ModularCodegenDecls); // IsLambda bit is already saved. @@ -7825,7 +7834,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::If: { const auto *IC = cast(C); writeSourceLocation(IC->getLParenLoc()); - writeStmtRef(IC->getConditionExpr()); + AddStmt(const_cast(IC->getConditionExpr())); return; } case OpenACCClauseKind::Self: { @@ -7833,7 +7842,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeSourceLocation(SC->getLParenLoc()); writeBool(SC->hasConditionExpr()); if (SC->hasConditionExpr()) - writeStmtRef(SC->getConditionExpr()); + AddStmt(const_cast(SC->getConditionExpr())); return; } case OpenACCClauseKind::NumGangs: { @@ -7847,13 +7856,13 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::NumWorkers: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); - writeStmtRef(NWC->getIntExpr()); + AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::VectorLength: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); - writeStmtRef(NWC->getIntExpr()); + AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::Private: { @@ -7932,15 +7941,15 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeSourceLocation(AC->getLParenLoc()); writeBool(AC->hasIntExpr()); if (AC->hasIntExpr()) - writeStmtRef(AC->getIntExpr()); + AddStmt(const_cast(AC->getIntExpr())); return; } case OpenACCClauseKind::Wait: { const auto *WC = cast(C); writeSourceLocation(WC->getLParenLoc()); writeBool(WC->getDevNumExpr()); - if (const Expr *DNE = WC->getDevNumExpr()) - writeStmtRef(DNE); + if (Expr *DNE = WC->getDevNumExpr()) + AddStmt(DNE); writeSourceLocation(WC->getQueuesLoc()); writeOpenACCIntExprList(WC->getQueueIdExprs()); @@ -7966,12 +7975,15 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeOpenACCVarList(RC); return; } - - case OpenACCClauseKind::Finalize: - case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Seq: case OpenACCClauseKind::Independent: case OpenACCClauseKind::Auto: + // Nothing to do here, there is no additional information beyond the + // begin/end loc and clause kind. + return; + + case OpenACCClauseKind::Finalize: + case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Worker: case OpenACCClauseKind::Vector: case OpenACCClauseKind::NoHost: diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c2f1d1b44241cc84f1512c51536d421eb28260ad..5a6ab4408eb2b54c2a337293771b846869bf366d 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1733,7 +1733,7 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (Writer.isGeneratingReducedBMI()) { auto Name = Context.DeclarationNames.getCXXDeductionGuideName(D); for (auto *DG : D->getDeclContext()->noload_lookup(Name)) - Writer.GetDeclRef(DG); + Writer.GetDeclRef(DG->getCanonicalDecl()); } Code = serialization::DECL_CLASS_TEMPLATE; @@ -1899,7 +1899,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); if (OwnsDefaultArg) - Record.AddTypeSourceInfo(D->getDefaultArgumentInfo()); + Record.AddTemplateArgumentLoc(D->getDefaultArgument()); if (!TC && !OwnsDefaultArg && D->getDeclContext() == D->getLexicalDeclContext() && @@ -1941,7 +1941,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); if (OwnsDefaultArg) - Record.AddStmt(D->getDefaultArgument()); + Record.AddTemplateArgumentLoc(D->getDefaultArgument()); Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM; } } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index a44852af97bea3e54f66c97860b8364322c2adb7..1a98e30e0f89fa9e7bf079c87a291aae23b12779 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2847,6 +2847,7 @@ void ASTStmtWriter::VisitOpenACCConstructStmt(OpenACCConstructStmt *S) { Record.push_back(S->clauses().size()); Record.writeEnum(S->Kind); Record.AddSourceRange(S->Range); + Record.AddSourceLocation(S->DirectiveLoc); Record.writeOpenACCClauseList(S->clauses()); } @@ -2862,6 +2863,12 @@ void ASTStmtWriter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { Code = serialization::STMT_OPENACC_COMPUTE_CONSTRUCT; } +void ASTStmtWriter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); + Code = serialization::STMT_OPENACC_LOOP_CONSTRUCT; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 4443ffd0929388157c9e3e1e8f03dcf2359d0afe..cd5a3bdd02e4a614a3341e21cb0523dcaaae3d7e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -96,13 +96,14 @@ add_clang_library(clangStaticAnalyzerCheckers PointerSortingChecker.cpp PointerSubChecker.cpp PthreadLockChecker.cpp - cert/PutenvWithAutoChecker.cpp + PutenvStackArrayChecker.cpp RetainCountChecker/RetainCountChecker.cpp RetainCountChecker/RetainCountDiagnostics.cpp ReturnPointerRangeChecker.cpp ReturnUndefChecker.cpp ReturnValueChecker.cpp RunLoopAutoreleaseLeakChecker.cpp + SetgidSetuidOrderChecker.cpp SimpleStreamChecker.cpp SmartPtrChecker.cpp SmartPtrModeling.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 34af7fb131f5a173d2f80603da5db29659decebe..467cf8889b6d3f3a277795997ac55db9944c3af5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -60,6 +60,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Checkers/Taint.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -322,6 +323,7 @@ public: CK_NewDeleteLeaksChecker, CK_MismatchedDeallocatorChecker, CK_InnerPointerChecker, + CK_TaintedAllocChecker, CK_NumCheckKinds }; @@ -365,6 +367,7 @@ private: mutable std::unique_ptr BT_MismatchedDealloc; mutable std::unique_ptr BT_OffsetFree[CK_NumCheckKinds]; mutable std::unique_ptr BT_UseZerroAllocated[CK_NumCheckKinds]; + mutable std::unique_ptr BT_TaintedAlloc; #define CHECK_FN(NAME) \ void NAME(const CallEvent &Call, CheckerContext &C) const; @@ -462,6 +465,13 @@ private: }; bool isMemCall(const CallEvent &Call) const; + void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C, + llvm::ArrayRef TaintedSyms, + AllocationFamily Family) const; + + void checkTaintedness(CheckerContext &C, const CallEvent &Call, + const SVal SizeSVal, ProgramStateRef State, + AllocationFamily Family) const; // TODO: Remove mutable by moving the initializtaion to the registry function. mutable std::optional KernelZeroFlagVal; @@ -521,9 +531,9 @@ private: /// malloc leaves it undefined. /// \param [in] State The \c ProgramState right before allocation. /// \returns The ProgramState right after allocation. - [[nodiscard]] static ProgramStateRef + [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx, - SVal Init, ProgramStateRef State, AllocationFamily Family); + SVal Init, ProgramStateRef State, AllocationFamily Family) const; /// Models memory allocation. /// @@ -534,9 +544,10 @@ private: /// malloc leaves it undefined. /// \param [in] State The \c ProgramState right before allocation. /// \returns The ProgramState right after allocation. - [[nodiscard]] static ProgramStateRef - MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init, - ProgramStateRef State, AllocationFamily Family); + [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C, + const CallEvent &Call, SVal Size, + SVal Init, ProgramStateRef State, + AllocationFamily Family) const; // Check if this malloc() for special flags. At present that means M_ZERO or // __GFP_ZERO (in which case, treat it like calloc). @@ -649,8 +660,9 @@ private: /// \param [in] Call The expression that reallocated memory /// \param [in] State The \c ProgramState right before reallocation. /// \returns The ProgramState right after allocation. - [[nodiscard]] static ProgramStateRef - CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State); + [[nodiscard]] ProgramStateRef CallocMem(CheckerContext &C, + const CallEvent &Call, + ProgramStateRef State) const; /// See if deallocation happens in a suspicious context. If so, escape the /// pointers that otherwise would have been deallocated and return true. @@ -1695,6 +1707,11 @@ MallocChecker::processNewAllocation(const CXXAllocatorCall &Call, // MallocUpdateRefState() instead of MallocMemAux() which breaks the // existing binding. SVal Target = Call.getObjectUnderConstruction(); + if (Call.getOriginExpr()->isArray()) { + if (auto SizeEx = NE->getArraySize()) + checkTaintedness(C, Call, C.getSVal(*SizeEx), State, AF_CXXNewArray); + } + State = MallocUpdateRefState(C, NE, State, Family, Target); State = ProcessZeroAllocCheck(Call, 0, State, Target); return State; @@ -1779,7 +1796,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx, SVal Init, ProgramStateRef State, - AllocationFamily Family) { + AllocationFamily Family) const { if (!State) return nullptr; @@ -1787,10 +1804,66 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family); } +void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State, + CheckerContext &C, + llvm::ArrayRef TaintedSyms, + AllocationFamily Family) const { + if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) { + if (!BT_TaintedAlloc) + BT_TaintedAlloc.reset(new BugType(CheckNames[CK_TaintedAllocChecker], + "Tainted Memory Allocation", + categories::TaintedData)); + auto R = std::make_unique(*BT_TaintedAlloc, Msg, N); + for (auto TaintedSym : TaintedSyms) { + R->markInteresting(TaintedSym); + } + C.emitReport(std::move(R)); + } +} + +void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call, + const SVal SizeSVal, ProgramStateRef State, + AllocationFamily Family) const { + if (!ChecksEnabled[CK_TaintedAllocChecker]) + return; + std::vector TaintedSyms = + taint::getTaintedSymbols(State, SizeSVal); + if (TaintedSyms.empty()) + return; + + SValBuilder &SVB = C.getSValBuilder(); + QualType SizeTy = SVB.getContext().getSizeType(); + QualType CmpTy = SVB.getConditionType(); + // In case the symbol is tainted, we give a warning if the + // size is larger than SIZE_MAX/4 + BasicValueFactory &BVF = SVB.getBasicValueFactory(); + const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy); + NonLoc MaxLength = + SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4)); + std::optional SizeNL = SizeSVal.getAs(); + auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy) + .getAs(); + if (!Cmp) + return; + auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp); + if (!StateTooLarge && StateNotTooLarge) { + // We can prove that size is not too large so there is no issue. + return; + } + + std::string Callee = "Memory allocation function"; + if (Call.getCalleeIdentifier()) + Callee = Call.getCalleeIdentifier()->getName().str(); + reportTaintBug( + Callee + " is called with a tainted (potentially attacker controlled) " + "value. Make sure the value is bound checked.", + State, C, TaintedSyms, Family); +} + ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init, ProgramStateRef State, - AllocationFamily Family) { + AllocationFamily Family) const { if (!State) return nullptr; @@ -1819,9 +1892,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, if (Size.isUndef()) Size = UnknownVal(); - // TODO: If Size is tainted and we cannot prove that it is within - // reasonable bounds, emit a warning that an attacker may - // provoke a memory exhaustion error. + checkTaintedness(C, Call, Size, State, AF_Malloc); // Set the region's extent. State = setDynamicExtent(State, RetVal.getAsRegion(), @@ -2761,7 +2832,7 @@ MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallEvent &Call, - ProgramStateRef State) { + ProgramStateRef State) const { if (!State) return nullptr; @@ -3734,3 +3805,4 @@ REGISTER_CHECKER(MallocChecker) REGISTER_CHECKER(NewDeleteChecker) REGISTER_CHECKER(NewDeleteLeaksChecker) REGISTER_CHECKER(MismatchedDeallocatorChecker) +REGISTER_CHECKER(TaintedAllocChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp similarity index 62% rename from clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp rename to clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp index a82f7caf16b291f2b018671658fe62d044105551..bf81d57bf82fd34eea733059672b129237ffaa91 100644 --- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp @@ -1,4 +1,4 @@ -//== PutenvWithAutoChecker.cpp --------------------------------- -*- C++ -*--=// +//== PutenvStackArrayChecker.cpp ------------------------------- -*- C++ -*--=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// // -// This file defines PutenvWithAutoChecker which finds calls of ``putenv`` -// function with automatic variable as the argument. +// This file defines PutenvStackArrayChecker which finds calls of ``putenv`` +// function with automatic array variable as the argument. // https://wiki.sei.cmu.edu/confluence/x/6NYxBQ // //===----------------------------------------------------------------------===// -#include "../AllocationState.h" +#include "AllocationState.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -26,9 +26,9 @@ using namespace clang; using namespace ento; namespace { -class PutenvWithAutoChecker : public Checker { +class PutenvStackArrayChecker : public Checker { private: - BugType BT{this, "'putenv' function should not be called with auto variables", + BugType BT{this, "'putenv' called with stack-allocated string", categories::SecurityError}; const CallDescription Putenv{CDM::CLibrary, {"putenv"}, 1}; @@ -37,20 +37,25 @@ public: }; } // namespace -void PutenvWithAutoChecker::checkPostCall(const CallEvent &Call, - CheckerContext &C) const { +void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { if (!Putenv.matches(Call)) return; SVal ArgV = Call.getArgSVal(0); const Expr *ArgExpr = Call.getArgExpr(0); - const MemSpaceRegion *MSR = ArgV.getAsRegion()->getMemorySpace(); - if (!isa(MSR)) + const auto *SSR = + dyn_cast(ArgV.getAsRegion()->getMemorySpace()); + if (!SSR) + return; + const auto *StackFrameFuncD = + dyn_cast_or_null(SSR->getStackFrame()->getDecl()); + if (StackFrameFuncD && StackFrameFuncD->isMain()) return; StringRef ErrorMsg = "The 'putenv' function should not be called with " - "arguments that have automatic storage"; + "arrays that have automatic storage"; ExplodedNode *N = C.generateErrorNode(); auto Report = std::make_unique(BT, ErrorMsg, N); @@ -60,8 +65,10 @@ void PutenvWithAutoChecker::checkPostCall(const CallEvent &Call, C.emitReport(std::move(Report)); } -void ento::registerPutenvWithAuto(CheckerManager &Mgr) { - Mgr.registerChecker(); +void ento::registerPutenvStackArray(CheckerManager &Mgr) { + Mgr.registerChecker(); } -bool ento::shouldRegisterPutenvWithAuto(const CheckerManager &) { return true; } +bool ento::shouldRegisterPutenvStackArray(const CheckerManager &) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/SetgidSetuidOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SetgidSetuidOrderChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbe3fd33a6b43fc001877796fa9b18631adc9538 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/SetgidSetuidOrderChecker.cpp @@ -0,0 +1,196 @@ +//===-- SetgidSetuidOrderChecker.cpp - check privilege revocation calls ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a checker to detect possible reversed order of privilege +// revocations when 'setgid' and 'setuid' is used. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" + +using namespace clang; +using namespace ento; + +namespace { + +enum SetPrivilegeFunctionKind { Irrelevant, Setuid, Setgid }; + +class SetgidSetuidOrderChecker : public Checker { + const BugType BT{this, "Possible wrong order of privilege revocation"}; + + const CallDescription SetuidDesc{CDM::CLibrary, {"setuid"}, 1}; + const CallDescription SetgidDesc{CDM::CLibrary, {"setgid"}, 1}; + + const CallDescription GetuidDesc{CDM::CLibrary, {"getuid"}, 0}; + const CallDescription GetgidDesc{CDM::CLibrary, {"getgid"}, 0}; + + const CallDescriptionSet OtherSetPrivilegeDesc{ + {CDM::CLibrary, {"seteuid"}, 1}, {CDM::CLibrary, {"setegid"}, 1}, + {CDM::CLibrary, {"setreuid"}, 2}, {CDM::CLibrary, {"setregid"}, 2}, + {CDM::CLibrary, {"setresuid"}, 3}, {CDM::CLibrary, {"setresgid"}, 3}}; + +public: + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, + bool Assumption) const; + +private: + void processSetuid(ProgramStateRef State, const CallEvent &Call, + CheckerContext &C) const; + void processSetgid(ProgramStateRef State, const CallEvent &Call, + CheckerContext &C) const; + void processOther(ProgramStateRef State, const CallEvent &Call, + CheckerContext &C) const; + /// Check if a function like \c getuid or \c getgid is called directly from + /// the first argument of function called from \a Call. + bool isFunctionCalledInArg(const CallDescription &Desc, + const CallEvent &Call) const; + void emitReport(ProgramStateRef State, CheckerContext &C) const; +}; + +} // end anonymous namespace + +/// Store if there was a call to 'setuid(getuid())' or 'setgid(getgid())' not +/// followed by other different privilege-change functions. +/// If the value \c Setuid is stored and a 'setgid(getgid())' call is found we +/// have found the bug to be reported. Value \c Setgid is used too to prevent +/// warnings at a setgid-setuid-setgid sequence. +REGISTER_TRAIT_WITH_PROGRAMSTATE(LastSetPrivilegeCall, SetPrivilegeFunctionKind) +/// Store the symbol value of the last 'setuid(getuid())' call. This is used to +/// detect if the result is compared to -1 and avoid warnings on that branch +/// (which is the failure branch of the call), and for identification of note +/// tags. +REGISTER_TRAIT_WITH_PROGRAMSTATE(LastSetuidCallSVal, SymbolRef) + +void SetgidSetuidOrderChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + if (SetuidDesc.matches(Call)) { + processSetuid(State, Call, C); + } else if (SetgidDesc.matches(Call)) { + processSetgid(State, Call, C); + } else if (OtherSetPrivilegeDesc.contains(Call)) { + processOther(State, Call, C); + } +} + +ProgramStateRef SetgidSetuidOrderChecker::evalAssume(ProgramStateRef State, + SVal Cond, + bool Assumption) const { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + SymbolRef LastSetuidSym = State->get(); + if (!LastSetuidSym) + return State; + + // Check if the most recent call to 'setuid(getuid())' is assumed to be != 0. + // It should be only -1 at failure, but we want to accept a "!= 0" check too. + // (But now an invalid failure check like "!= 1" will be recognized as correct + // too. The "invalid failure check" is a different bug that is not the scope + // of this checker.) + auto FailComparison = + SVB.evalBinOpNN(State, BO_NE, nonloc::SymbolVal(LastSetuidSym), + SVB.makeIntVal(0, /*isUnsigned=*/false), + SVB.getConditionType()) + .getAs(); + if (!FailComparison) + return State; + if (auto IsFailBranch = State->assume(*FailComparison); + IsFailBranch.first && !IsFailBranch.second) { + // This is the 'setuid(getuid())' != 0 case. + // On this branch we do not want to emit warning. + State = State->set(Irrelevant); + State = State->set(SymbolRef{}); + } + return State; +} + +void SetgidSetuidOrderChecker::processSetuid(ProgramStateRef State, + const CallEvent &Call, + CheckerContext &C) const { + bool IsSetuidWithGetuid = isFunctionCalledInArg(GetuidDesc, Call); + if (State->get() != Setgid && IsSetuidWithGetuid) { + SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); + State = State->set(Setuid); + State = State->set(RetSym); + const NoteTag *Note = C.getNoteTag([this, + RetSym](PathSensitiveBugReport &BR) { + if (!BR.isInteresting(RetSym) || &BR.getBugType() != &this->BT) + return ""; + return "Call to 'setuid' found here that removes superuser privileges"; + }); + C.addTransition(State, Note); + return; + } + State = State->set(Irrelevant); + State = State->set(SymbolRef{}); + C.addTransition(State); +} + +void SetgidSetuidOrderChecker::processSetgid(ProgramStateRef State, + const CallEvent &Call, + CheckerContext &C) const { + bool IsSetgidWithGetgid = isFunctionCalledInArg(GetgidDesc, Call); + if (State->get() == Setuid) { + if (IsSetgidWithGetgid) { + State = State->set(Irrelevant); + emitReport(State, C); + return; + } + State = State->set(Irrelevant); + } else { + State = State->set(IsSetgidWithGetgid ? Setgid + : Irrelevant); + } + State = State->set(SymbolRef{}); + C.addTransition(State); +} + +void SetgidSetuidOrderChecker::processOther(ProgramStateRef State, + const CallEvent &Call, + CheckerContext &C) const { + State = State->set(SymbolRef{}); + State = State->set(Irrelevant); + C.addTransition(State); +} + +bool SetgidSetuidOrderChecker::isFunctionCalledInArg( + const CallDescription &Desc, const CallEvent &Call) const { + if (const auto *CallInArg0 = + dyn_cast(Call.getArgExpr(0)->IgnoreParenImpCasts())) + return Desc.matchesAsWritten(*CallInArg0); + return false; +} + +void SetgidSetuidOrderChecker::emitReport(ProgramStateRef State, + CheckerContext &C) const { + if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { + llvm::StringLiteral Msg = + "A 'setgid(getgid())' call following a 'setuid(getuid())' " + "call is likely to fail; probably the order of these " + "statements is wrong"; + auto Report = std::make_unique(BT, Msg, N); + Report->markInteresting(State->get()); + C.emitReport(std::move(Report)); + } +} + +void ento::registerSetgidSetuidOrderChecker(CheckerManager &mgr) { + mgr.registerChecker(); +} + +bool ento::shouldRegisterSetgidSetuidOrderChecker(const CheckerManager &mgr) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 5c797d5233089a58139545f2dd74b7a6f42197f3..49bbff1942167bafc19fec03f4208e1756b7f08c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -271,6 +271,43 @@ public: TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {} + bool IsFunctionTrivial(const Decl *D) { + auto CacheIt = Cache.find(D); + if (CacheIt != Cache.end()) + return CacheIt->second; + + // Treat a recursive function call to be trivial until proven otherwise. + auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(D, true)); + if (!IsNew) + return RecursiveIt->second; + + bool Result = [&]() { + if (auto *CtorDecl = dyn_cast(D)) { + for (auto *CtorInit : CtorDecl->inits()) { + if (!Visit(CtorInit->getInit())) + return false; + } + } + const Stmt *Body = D->getBody(); + if (!Body) + return false; + return Visit(Body); + }(); + + if (!Result) { + // D and its mutually recursive callers are all non-trivial. + for (auto &It : RecursiveFn) + It.second = false; + } + RecursiveIt = RecursiveFn.find(D); + assert(RecursiveIt != RecursiveFn.end()); + Result = RecursiveIt->second; + RecursiveFn.erase(RecursiveIt); + Cache[D] = Result; + + return Result; + } + bool VisitStmt(const Stmt *S) { // All statements are non-trivial unless overriden later. // Don't even recurse into children by default. @@ -368,7 +405,7 @@ public: Name == "bitwise_cast" || Name.find("__builtin") == 0) return true; - return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); + return IsFunctionTrivial(Callee); } bool @@ -403,7 +440,7 @@ public: return true; // Recursively descend into the callee to confirm that it's trivial as well. - return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); + return IsFunctionTrivial(Callee); } bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) { @@ -413,7 +450,7 @@ public: if (!Callee) return false; // Recursively descend into the callee to confirm that it's trivial as well. - return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); + return IsFunctionTrivial(Callee); } bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { @@ -439,7 +476,7 @@ public: } // Recursively descend into the callee to confirm that it's trivial. - return TrivialFunctionAnalysis::isTrivialImpl(CE->getConstructor(), Cache); + return IsFunctionTrivial(CE->getConstructor()); } bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); } @@ -513,36 +550,13 @@ public: private: CacheTy &Cache; + CacheTy RecursiveFn; }; bool TrivialFunctionAnalysis::isTrivialImpl( const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) { - // If the function isn't in the cache, conservatively assume that - // it's not trivial until analysis completes. This makes every recursive - // function non-trivial. This also guarantees that each function - // will be scanned at most once. - auto [It, IsNew] = Cache.insert(std::make_pair(D, false)); - if (!IsNew) - return It->second; - TrivialFunctionAnalysisVisitor V(Cache); - - if (auto *CtorDecl = dyn_cast(D)) { - for (auto *CtorInit : CtorDecl->inits()) { - if (!V.Visit(CtorInit->getInit())) - return false; - } - } - - const Stmt *Body = D->getBody(); - if (!Body) - return false; - - bool Result = V.Visit(Body); - if (Result) - Cache[D] = true; - - return Result; + return V.IsFunctionTrivial(D); } bool TrivialFunctionAnalysis::isTrivialImpl( diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp index 7f4c3a7b787e88fe7869a5d6e28972fff4a2bb71..9df108e28ecdbb6cf200963e1e9cc20fdcd26f67 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp @@ -11,16 +11,116 @@ #include "PtrTypesSemantics.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/StmtVisitor.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" #include using namespace clang; using namespace ento; namespace { + +class DerefFuncDeleteExprVisitor + : public ConstStmtVisitor { + // Returns true if any of child statements return true. + bool VisitChildren(const Stmt *S) { + for (const Stmt *Child : S->children()) { + if (Child && Visit(Child)) + return true; + } + return false; + } + + bool VisitBody(const Stmt *Body) { + if (!Body) + return false; + + auto [It, IsNew] = VisitedBody.insert(Body); + if (!IsNew) // This body is recursive + return false; + + return Visit(Body); + } + +public: + DerefFuncDeleteExprVisitor(const TemplateArgumentList &ArgList, + const CXXRecordDecl *ClassDecl) + : ArgList(&ArgList), ClassDecl(ClassDecl) {} + + DerefFuncDeleteExprVisitor(const CXXRecordDecl *ClassDecl) + : ClassDecl(ClassDecl) {} + + std::optional HasSpecializedDelete(CXXMethodDecl *Decl) { + if (auto *Body = Decl->getBody()) + return VisitBody(Body); + if (Decl->getTemplateInstantiationPattern()) + return std::nullopt; // Indeterminate. There was no concrete instance. + return false; + } + + bool VisitCallExpr(const CallExpr *CE) { + const Decl *D = CE->getCalleeDecl(); + if (D && D->hasBody()) + return VisitBody(D->getBody()); + return false; + } + + bool VisitCXXDeleteExpr(const CXXDeleteExpr *E) { + auto *Arg = E->getArgument(); + while (Arg) { + if (auto *Paren = dyn_cast(Arg)) + Arg = Paren->getSubExpr(); + else if (auto *Cast = dyn_cast(Arg)) { + Arg = Cast->getSubExpr(); + auto CastType = Cast->getType(); + if (auto *PtrType = dyn_cast(CastType)) { + auto PointeeType = PtrType->getPointeeType(); + while (auto *ET = dyn_cast(PointeeType)) { + if (ET->isSugared()) + PointeeType = ET->desugar(); + } + if (auto *ParmType = dyn_cast(PointeeType)) { + if (ArgList) { + auto ParmIndex = ParmType->getIndex(); + auto Type = ArgList->get(ParmIndex).getAsType(); + if (Type->getAsCXXRecordDecl() == ClassDecl) + return true; + } + } else if (auto *RD = dyn_cast(PointeeType)) { + if (RD->getDecl() == ClassDecl) + return true; + } else if (auto *ST = + dyn_cast(PointeeType)) { + auto Type = ST->getReplacementType(); + if (auto *RD = dyn_cast(Type)) { + if (RD->getDecl() == ClassDecl) + return true; + } + } + } + } else + break; + } + return false; + } + + bool VisitStmt(const Stmt *S) { return VisitChildren(S); } + + // Return false since the contents of lambda isn't necessarily executed. + // If it is executed, VisitCallExpr above will visit its body. + bool VisitLambdaExpr(const LambdaExpr *) { return false; } + +private: + const TemplateArgumentList *ArgList{nullptr}; + const CXXRecordDecl *ClassDecl; + llvm::DenseSet VisitedBody; +}; + class RefCntblBaseVirtualDtorChecker : public Checker> { private: @@ -51,63 +151,93 @@ public: bool shouldVisitImplicitCode() const { return false; } bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { - Checker->visitCXXRecordDecl(RD); + if (!RD->hasDefinition()) + return true; + + Decls.insert(RD); + + for (auto &Base : RD->bases()) { + const auto AccSpec = Base.getAccessSpecifier(); + if (AccSpec == AS_protected || AccSpec == AS_private || + (AccSpec == AS_none && RD->isClass())) + continue; + + QualType T = Base.getType(); + if (T.isNull()) + continue; + + const CXXRecordDecl *C = T->getAsCXXRecordDecl(); + if (!C) + continue; + + if (auto *CTSD = dyn_cast(C)) { + for (auto &Arg : CTSD->getTemplateArgs().asArray()) { + if (Arg.getKind() != TemplateArgument::Type) + continue; + auto TemplT = Arg.getAsType(); + if (TemplT.isNull()) + continue; + + bool IsCRTP = TemplT->getAsCXXRecordDecl() == RD; + if (!IsCRTP) + continue; + CRTPs.insert(C); + } + } + } + return true; } + + llvm::SetVector Decls; + llvm::DenseSet CRTPs; }; LocalVisitor visitor(this); visitor.TraverseDecl(const_cast(TUD)); + for (auto *RD : visitor.Decls) { + if (visitor.CRTPs.contains(RD)) + continue; + visitCXXRecordDecl(RD); + } } void visitCXXRecordDecl(const CXXRecordDecl *RD) const { if (shouldSkipDecl(RD)) return; - CXXBasePaths Paths; - Paths.setOrigin(RD); + for (auto &Base : RD->bases()) { + const auto AccSpec = Base.getAccessSpecifier(); + if (AccSpec == AS_protected || AccSpec == AS_private || + (AccSpec == AS_none && RD->isClass())) + continue; - const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr; - const CXXRecordDecl *ProblematicBaseClass = nullptr; + auto hasRefInBase = clang::hasPublicMethodInBase(&Base, "ref"); + auto hasDerefInBase = clang::hasPublicMethodInBase(&Base, "deref"); - const auto IsPublicBaseRefCntblWOVirtualDtor = - [RD, &ProblematicBaseSpecifier, - &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) { - const auto AccSpec = Base->getAccessSpecifier(); - if (AccSpec == AS_protected || AccSpec == AS_private || - (AccSpec == AS_none && RD->isClass())) - return false; + bool hasRef = hasRefInBase && *hasRefInBase != nullptr; + bool hasDeref = hasDerefInBase && *hasDerefInBase != nullptr; - auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref"); - auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref"); + QualType T = Base.getType(); + if (T.isNull()) + continue; - bool hasRef = hasRefInBase && *hasRefInBase != nullptr; - bool hasDeref = hasDerefInBase && *hasDerefInBase != nullptr; + const CXXRecordDecl *C = T->getAsCXXRecordDecl(); + if (!C) + continue; - QualType T = Base->getType(); - if (T.isNull()) - return false; - - const CXXRecordDecl *C = T->getAsCXXRecordDecl(); - if (!C) - return false; - if (isRefCountedClass(C)) - return false; - - bool AnyInconclusiveBase = false; - const auto hasPublicRefInBase = - [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, - CXXBasePath &) { - auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref"); - if (!hasRefInBase) { - AnyInconclusiveBase = true; - return false; - } - return (*hasRefInBase) != nullptr; - }; - const auto hasPublicDerefInBase = [&AnyInconclusiveBase]( - const CXXBaseSpecifier *Base, - CXXBasePath &) { + bool AnyInconclusiveBase = false; + const auto hasPublicRefInBase = + [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { + auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref"); + if (!hasRefInBase) { + AnyInconclusiveBase = true; + return false; + } + return (*hasRefInBase) != nullptr; + }; + const auto hasPublicDerefInBase = + [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref"); if (!hasDerefInBase) { AnyInconclusiveBase = true; @@ -115,28 +245,42 @@ public: } return (*hasDerefInBase) != nullptr; }; - CXXBasePaths Paths; - Paths.setOrigin(C); - hasRef = hasRef || C->lookupInBases(hasPublicRefInBase, Paths, + CXXBasePaths Paths; + Paths.setOrigin(C); + hasRef = hasRef || C->lookupInBases(hasPublicRefInBase, Paths, + /*LookupInDependent =*/true); + hasDeref = hasDeref || C->lookupInBases(hasPublicDerefInBase, Paths, /*LookupInDependent =*/true); - hasDeref = hasDeref || C->lookupInBases(hasPublicDerefInBase, Paths, - /*LookupInDependent =*/true); - if (AnyInconclusiveBase || !hasRef || !hasDeref) - return false; - - const auto *Dtor = C->getDestructor(); - if (!Dtor || !Dtor->isVirtual()) { - ProblematicBaseSpecifier = Base; - ProblematicBaseClass = C; - return true; - } - - return false; - }; - - if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths, - /*LookupInDependent =*/true)) { - reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); + if (AnyInconclusiveBase || !hasRef || !hasDeref) + continue; + + auto HasSpecializedDelete = isClassWithSpecializedDelete(C, RD); + if (!HasSpecializedDelete || *HasSpecializedDelete) + continue; + if (C->lookupInBases( + [&](const CXXBaseSpecifier *Base, CXXBasePath &) { + auto *T = Base->getType().getTypePtrOrNull(); + if (!T) + return false; + auto *R = T->getAsCXXRecordDecl(); + if (!R) + return false; + auto Result = isClassWithSpecializedDelete(R, RD); + if (!Result) + AnyInconclusiveBase = true; + return Result && *Result; + }, + Paths, /*LookupInDependent =*/true)) + continue; + if (AnyInconclusiveBase) + continue; + + const auto *Dtor = C->getDestructor(); + if (!Dtor || !Dtor->isVirtual()) { + auto *ProblematicBaseSpecifier = &Base; + auto *ProblematicBaseClass = C; + reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); + } } } @@ -182,6 +326,32 @@ public: ClsName == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr"); } + static std::optional + isClassWithSpecializedDelete(const CXXRecordDecl *C, + const CXXRecordDecl *DerivedClass) { + if (auto *ClsTmplSpDecl = dyn_cast(C)) { + for (auto *MethodDecl : C->methods()) { + if (safeGetName(MethodDecl) == "deref") { + DerefFuncDeleteExprVisitor Visitor(ClsTmplSpDecl->getTemplateArgs(), + DerivedClass); + auto Result = Visitor.HasSpecializedDelete(MethodDecl); + if (!Result || *Result) + return Result; + } + } + return false; + } + for (auto *MethodDecl : C->methods()) { + if (safeGetName(MethodDecl) == "deref") { + DerefFuncDeleteExprVisitor Visitor(DerivedClass); + auto Result = Visitor.HasSpecializedDelete(MethodDecl); + if (!Result || *Result) + return Result; + } + } + return false; + } + void reportBug(const CXXRecordDecl *DerivedClass, const CXXBaseSpecifier *BaseSpec, const CXXRecordDecl *ProblematicBaseClass) const { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp index 0d9710a5e2d831ebdd38c94abd385b001758f8b8..274da0baf2ce5ca04e54ed8f9cce8f6a73c40fec 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp @@ -135,7 +135,19 @@ public: bool shouldVisitImplicitCode() const { return false; } bool VisitVarDecl(VarDecl *V) { - Checker->visitVarDecl(V); + auto *Init = V->getInit(); + if (Init && V->isLocalVarDecl()) + Checker->visitVarDecl(V, Init); + return true; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { + if (BO->isAssignmentOp()) { + if (auto *VarRef = dyn_cast(BO->getLHS())) { + if (auto *V = dyn_cast(VarRef->getDecl())) + Checker->visitVarDecl(V, BO->getRHS()); + } + } return true; } @@ -174,7 +186,7 @@ public: visitor.TraverseDecl(const_cast(TUD)); } - void visitVarDecl(const VarDecl *V) const { + void visitVarDecl(const VarDecl *V, const Expr *Value) const { if (shouldSkipVarDecl(V)) return; @@ -184,12 +196,8 @@ public: std::optional IsUncountedPtr = isUncountedPtr(ArgType); if (IsUncountedPtr && *IsUncountedPtr) { - const Expr *const InitExpr = V->getInit(); - if (!InitExpr) - return; // FIXME: later on we might warn on uninitialized vars too - if (tryToFindPtrOrigin( - InitExpr, /*StopAtFirstRefCountedObj=*/false, + Value, /*StopAtFirstRefCountedObj=*/false, [&](const clang::Expr *InitArgOrigin, bool IsSafe) { if (!InitArgOrigin) return true; @@ -232,34 +240,46 @@ public: })) return; - reportBug(V); + reportBug(V, Value); } } bool shouldSkipVarDecl(const VarDecl *V) const { assert(V); - if (!V->isLocalVarDecl()) - return true; - - if (BR->getSourceManager().isInSystemHeader(V->getLocation())) - return true; - - return false; + return BR->getSourceManager().isInSystemHeader(V->getLocation()); } - void reportBug(const VarDecl *V) const { + void reportBug(const VarDecl *V, const Expr *Value) const { assert(V); SmallString<100> Buf; llvm::raw_svector_ostream Os(Buf); - Os << "Local variable "; - printQuotedQualifiedName(Os, V); - Os << " is uncounted and unsafe."; - - PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager()); - auto Report = std::make_unique(Bug, Os.str(), BSLoc); - Report->addRange(V->getSourceRange()); - BR->emitReport(std::move(Report)); + if (dyn_cast(V)) { + Os << "Assignment to an uncounted parameter "; + printQuotedQualifiedName(Os, V); + Os << " is unsafe."; + + PathDiagnosticLocation BSLoc(Value->getExprLoc(), BR->getSourceManager()); + auto Report = std::make_unique(Bug, Os.str(), BSLoc); + Report->addRange(Value->getSourceRange()); + BR->emitReport(std::move(Report)); + } else { + if (V->hasLocalStorage()) + Os << "Local variable "; + else if (V->isStaticLocal()) + Os << "Static local variable "; + else if (V->hasGlobalStorage()) + Os << "Global variable "; + else + Os << "Variable "; + printQuotedQualifiedName(Os, V); + Os << " is uncounted and unsafe."; + + PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager()); + auto Report = std::make_unique(Bug, Os.str(), BSLoc); + Report->addRange(V->getSourceRange()); + BR->emitReport(std::move(Report)); + } } }; } // namespace diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 0b1edf3e5c96bf531883ea4553c7330d138d74f9..290d96611d466430270e3a30ac3f9a7c1893a6c2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1822,6 +1822,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPTargetParallelGenericLoopDirectiveClass: case Stmt::CapturedStmtClass: case Stmt::OpenACCComputeConstructClass: + case Stmt::OpenACCLoopConstructClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPMetaDirectiveClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); @@ -1970,33 +1971,45 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet Tmp; StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx); - const Expr *ArgE; - if (const auto *DefE = dyn_cast(S)) + bool HasRewrittenInit = false; + const Expr *ArgE = nullptr; + if (const auto *DefE = dyn_cast(S)) { ArgE = DefE->getExpr(); - else if (const auto *DefE = dyn_cast(S)) + HasRewrittenInit = DefE->hasRewrittenInit(); + } else if (const auto *DefE = dyn_cast(S)) { ArgE = DefE->getExpr(); - else + HasRewrittenInit = DefE->hasRewrittenInit(); + } else llvm_unreachable("unknown constant wrapper kind"); - bool IsTemporary = false; - if (const auto *MTE = dyn_cast(ArgE)) { - ArgE = MTE->getSubExpr(); - IsTemporary = true; - } + if (HasRewrittenInit) { + for (auto *N : PreVisit) { + ProgramStateRef state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); + state = state->BindExpr(S, LCtx, state->getSVal(ArgE, LCtx)); + Bldr2.generateNode(S, N, state); + } + } else { + // If it's not rewritten, the contents of these expressions are not + // actually part of the current function, so we fall back to constant + // evaluation. + bool IsTemporary = false; + if (const auto *MTE = dyn_cast(ArgE)) { + ArgE = MTE->getSubExpr(); + IsTemporary = true; + } + + std::optional ConstantVal = svalBuilder.getConstantVal(ArgE); + const LocationContext *LCtx = Pred->getLocationContext(); + for (auto *I : PreVisit) { + ProgramStateRef State = I->getState(); + State = State->BindExpr(S, LCtx, ConstantVal.value_or(UnknownVal())); + if (IsTemporary) + State = createTemporaryRegionIfNeeded(State, LCtx, cast(S), + cast(S)); - std::optional ConstantVal = svalBuilder.getConstantVal(ArgE); - if (!ConstantVal) - ConstantVal = UnknownVal(); - - const LocationContext *LCtx = Pred->getLocationContext(); - for (const auto I : PreVisit) { - ProgramStateRef State = I->getState(); - State = State->BindExpr(S, LCtx, *ConstantVal); - if (IsTemporary) - State = createTemporaryRegionIfNeeded(State, LCtx, - cast(S), - cast(S)); - Bldr2.generateNode(S, I, State); + Bldr2.generateNode(S, I, State); + } } getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 0c047b6c5da2f8007a7e4d17c8d8d06d8da549a0..0f82f22d8b9a8c7d1dd360ae39d668565bfec7b3 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -259,9 +259,7 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) { ++Index; } - llvm::stable_sort(SimpleNames, [](const MacroOpt &A, const MacroOpt &B) { - return A.first < B.first; - }); + llvm::stable_sort(SimpleNames, llvm::less_first()); // Keep the last instance of each macro name by going in reverse auto NewEnd = std::unique( SimpleNames.rbegin(), SimpleNames.rend(), diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index f46324ee9989eb87ad06a28a344f9c0cf8431b22..370d834846859fb150e48c050b418f619ccbb6b7 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -578,6 +578,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MD.ID.ModuleName = M->getFullModuleName(); MD.IsSystem = M->IsSystem; + // For modules which use export_as link name, the linked product that of the + // corresponding export_as-named module. + if (!M->UseExportAsModuleLinkName) + MD.LinkLibraries = M->LinkLibraries; ModuleMap &ModMapInfo = MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index a77686996879f1db975aada9101656b7c5bec8ac..5ecba5dfece3d085f94ad942f4d592ebae5d8d5d 100644 --- a/clang/lib/Tooling/JSONCompilationDatabase.cpp +++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp @@ -260,7 +260,7 @@ static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) { return Name; } -// There are compiler-wrappers (ccache, distcc, gomacc) that take the "real" +// There are compiler-wrappers (ccache, distcc) that take the "real" // compiler as an argument, e.g. distcc gcc -O3 foo.c. // These end up in compile_commands.json when people set CC="distcc gcc". // Clang's driver doesn't understand this, so we need to unwrap. @@ -269,8 +269,7 @@ static bool unwrapCommand(std::vector &Args) { return false; StringRef Wrapper = stripExecutableExtension(llvm::sys::path::filename(Args.front())); - if (Wrapper == "distcc" || Wrapper == "gomacc" || Wrapper == "ccache" || - Wrapper == "sccache") { + if (Wrapper == "distcc" || Wrapper == "ccache" || Wrapper == "sccache") { // Most of these wrappers support being invoked 3 ways: // `distcc g++ file.c` This is the mode we're trying to match. // We need to drop `distcc`. diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index e936ec6dc894bc7708b12ee23e55977553a76155..dd5064d993e667b72664c6ee29ef88bde444d7dd 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -54,6 +54,10 @@ constexpr int derefPtr(const int *d) { } static_assert(derefPtr(data) == 5, ""); +/// Make sure we can refer to the one-past-the-end element +/// and then return back to the end of the array. +static_assert((&data[5])[-1] == 1, ""); + constexpr int storePtr() { int b[] = {1,2,3,4}; int *c = b; diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp index fbe76aba73c90e26859a1a26262171ce5d9c7132..0a17106449faf358a8ee3a2e9d590de49027ef67 100644 --- a/clang/test/AST/Interp/builtin-functions.cpp +++ b/clang/test/AST/Interp/builtin-functions.cpp @@ -900,7 +900,7 @@ namespace shufflevector { static_assert(vectorShuffle6[7] == 7, "");// ref-error {{not an integral constant expression}} constexpr vector4char vectorShuffleFail1 = __builtin_shufflevector( // both-error {{must be initialized by a constant expression}}\ - // ref-error {{index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position 0 not permitted in a constexpr context.}} + // ref-error {{index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position 0 is not permitted in a constexpr context}} vector4charConst1, vector4charConst2, -1, -1, -1, -1); } diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 2a75457a4693f60c1ac86b95ebc33dc054c8cdfd..f4c7bf16f2f95ee8ae44392fcdf82ac9c3842f8f 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -278,3 +278,15 @@ void addrlabelexpr(void) { a0: ; static void *ps[] = { &&a0 }; // pedantic-warning {{use of GNU address-of-label extension}} } + +extern void cv2; +void *foo5 (void) +{ + return &cv2; // pedantic-warning{{address of an expression of type 'void'}} +} + +__attribute__((weak)) const unsigned int test10_bound = 10; +char test10_global[test10_bound]; // all-error {{variable length array declaration not allowed at file scope}} +void test10(void) { + char test10_local[test10_bound] = "help"; // all-error {{variable-sized object may not be initialized}} +} diff --git a/clang/test/AST/Interp/cxx03.cpp b/clang/test/AST/Interp/cxx03.cpp index b6aaf0840cfb3696085aca3e5ae1d2c79f97b25f..70ae4134842b5d7d8d64024469e33570e11e659f 100644 --- a/clang/test/AST/Interp/cxx03.cpp +++ b/clang/test/AST/Interp/cxx03.cpp @@ -24,3 +24,8 @@ namespace NonLValueMemberExpr { const int &TT1::subobj_init = PODType().value; } + +void LambdaAccessingADummy() { + int d; + int a9[1] = {[d = 0] = 1}; // both-error {{is not an integral constant expression}} +} diff --git a/clang/test/AST/Interp/cxx98.cpp b/clang/test/AST/Interp/cxx98.cpp index be81735329db821a5a77f6f62b643dceb2418b57..e68e4dbc8d74b4ed9ea38a917c4a44047da7fcec 100644 --- a/clang/test/AST/Interp/cxx98.cpp +++ b/clang/test/AST/Interp/cxx98.cpp @@ -50,3 +50,7 @@ _Static_assert(c0_test == 0, ""); int a = 0; // both-note {{declared here}} _Static_assert(a == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \ // both-note {{read of non-const variable 'a' is not allowed in a constant expression}} + +struct SelfReference { SelfReference &r; }; +extern SelfReference self_reference_1; +SelfReference self_reference_2 = {self_reference_1}; diff --git a/clang/test/AST/Interp/eval-order.cpp b/clang/test/AST/Interp/eval-order.cpp index 695a43c9d235b1eb44ae3a94b253155a51282db5..aaf2b74510bbfedd396a7a74fc90d42d0eb6da18 100644 --- a/clang/test/AST/Interp/eval-order.cpp +++ b/clang/test/AST/Interp/eval-order.cpp @@ -1,8 +1,7 @@ -// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu -// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++1z -verify=ref,both %s -fcxx-exceptions -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++1z -verify=expected,both %s -fcxx-exceptions -triple=x86_64-linux-gnu -fexperimental-new-constant-interpreter // ref-no-diagnostics -// expected-no-diagnostics /// Check that assignment operators evaluate their operands right-to-left. /// Copied from test/SemaCXX/constant-expression-cxx1z.cpp @@ -46,7 +45,7 @@ namespace EvalOrder { } template constexpr T &&b(T &&v) { if (!done_a) - throw "wrong"; + throw "wrong"; // expected-note 7{{not valid}} done_b = true; return (T &&)v; } @@ -76,21 +75,30 @@ namespace EvalOrder { // SEQ(A(&ud)->*B(&UserDefined::n)); FIXME // Rule 4: a(b1, b2, b3) - // SEQ(A(f)(B(1), B(2), B(3))); FIXME + SEQ(A(f)(B(1), B(2), B(3))); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} // Rule 5: b = a, b @= a - // SEQ(B(lvalue().get()) = A(0)); FIXME - // SEQ(B(lvalue().get()) = A(ud)); FIXME + SEQ(B(lvalue().get()) = A(0)); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} + SEQ(B(lvalue().get()) = A(ud)); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} SEQ(B(lvalue().get()) += A(0)); - // SEQ(B(lvalue().get()) += A(ud)); FIXME - // SEQ(B(lvalue().get()) += A(nm)); FIXME + SEQ(B(lvalue().get()) += A(ud)); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} + + SEQ(B(lvalue().get()) += A(nm)); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} + // Rule 6: a[b] constexpr int arr[3] = {}; SEQ(A(arr)[B(0)]); SEQ(A(+arr)[B(0)]); - // SEQ(A(0)[B(arr)]); FIXME - // SEQ(A(0)[B(+arr)]); FIXME + SEQ(A(0)[B(arr)]); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} + SEQ(A(0)[B(+arr)]); // expected-error {{not an integral constant expression}} FIXME \ + // expected-note 2{{in call to}} SEQ(A(ud)[B(0)]); // Rule 7: a << b diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index e95ade8ef51b701574f6397eda91b3de83d79c53..10c62a43ef33b459fdcc100a95ae1b4e02ccdb0c 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -623,3 +623,9 @@ namespace FuncPtrParam { *a; // both-warning {{expression result unused}} } } + +namespace { + void f() noexcept; + void (&r)() = f; + void (&cond3)() = r; +} diff --git a/clang/test/AST/Interp/objc.mm b/clang/test/AST/Interp/objc.mm new file mode 100644 index 0000000000000000000000000000000000000000..6402c8ae098fdbb0112508bf6d0c487bbc0b6d6a --- /dev/null +++ b/clang/test/AST/Interp/objc.mm @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s + +@interface A { + int a; + static_assert(a, ""); // both-error {{static assertion expression is not an integral constant expression}} +} +@end + +@interface NSString +@end +constexpr NSString *t0 = @"abc"; +constexpr NSString *t1 = @("abc"); diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 3a5ecd291a56819a6fc45a9e38f5ede4718b9d68..0a89c81bafd578808b7cb25cad134900e7f1708a 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1335,8 +1335,6 @@ namespace UnnamedBitFields { static_assert(a.c == 'a', ""); } -/// FIXME: This still doesn't work in the new interpreter because -/// we lack type information for dummy pointers. namespace VirtualBases { /// This used to crash. namespace One { @@ -1346,7 +1344,7 @@ namespace VirtualBases { }; class B : public virtual A { public: - int getX() { return x; } // ref-note {{declared here}} + int getX() { return x; } // both-note {{declared here}} }; class DV : virtual public B{}; @@ -1354,7 +1352,7 @@ namespace VirtualBases { void foo() { DV b; int a[b.getX()]; // both-warning {{variable length arrays}} \ - // ref-note {{non-constexpr function 'getX' cannot be used}} + // both-note {{non-constexpr function 'getX' cannot be used}} } } @@ -1469,3 +1467,16 @@ namespace IgnoredCtorWithZeroInit { return (S(), true); } } + +#if __cplusplus >= 202002L +namespace VirtOperator { + /// This used to crash because it's a virtual CXXOperatorCallExpr. + struct B { + virtual constexpr bool operator==(const B&) const { return true; } + }; + struct D : B { + constexpr bool operator==(const B&) const override{ return false; } // both-note {{operator}} + }; + constexpr bool cmp_base_derived = D() == D(); // both-warning {{ambiguous}} +} +#endif diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..293a1981a52f07fd2879f8afcdaf003a7fac335b --- /dev/null +++ b/clang/test/AST/Interp/unions.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s + +union U { + int a; + int b; +}; + +constexpr U a = {12}; +static_assert(a.a == 12, ""); +static_assert(a.b == 0, ""); // both-error {{not an integral constant expression}} \ + // both-note {{read of member 'b' of union with active member 'a'}} +union U1 { + int i; + float f = 3.0f; +}; +constexpr U1 u1{}; +static_assert(u1.f == 3.0, ""); +static_assert(u1.i == 1, ""); // both-error {{not an integral constant expression}} \ + // both-note {{read of member 'i' of union with active member 'f'}} + + + +union A { + int a; + double d; +}; +constexpr A aa = {1, 2.0}; // both-error {{excess elements in union initializer}} +constexpr A ab = {.d = 1.0}; +static_assert(ab.d == 1.0, ""); +static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \ + // both-note {{read of member 'a' of union with active member 'd'}} + + +namespace Empty { + union E {}; + constexpr E e{}; +} + +namespace SimpleStore { + union A { + int a; + int b; + }; + constexpr int foo() { + A a{.b = 4}; + a.b = 10; + return a.b; + } + static_assert(foo() == 10, ""); + + constexpr int empty() { + A a{}; /// Just test that this works. + return 10; + } + static_assert(empty() == 10, ""); +} + +namespace ZeroInit { + struct S { int m; }; + union Z { + float f; + }; + + constexpr Z z{}; + static_assert(z.f == 0.0, ""); +} diff --git a/clang/test/AST/ast-dump-APValue-anon-union.cpp b/clang/test/AST/ast-dump-APValue-anon-union.cpp index 0e6466ee1fd7361d30053b982f6ec644b9dd7f65..ffe14ed7322deb7f6ebed2679b523490a6bdf9d7 100644 --- a/clang/test/AST/ast-dump-APValue-anon-union.cpp +++ b/clang/test/AST/ast-dump-APValue-anon-union.cpp @@ -36,7 +36,7 @@ void Test() { constexpr U0 u0a{}; // CHECK: | `-VarDecl {{.*}} col:{{.*}} u0a 'const U0' constexpr listinit - // CHECK-NEXT: | |-value: Union None + // CHECK-NEXT: | |-value: Union .U0::(anonymous union at {{.*}}) Union .f Float 3.141500e+00 constexpr U0 u0b{3.1415f}; // CHECK: | `-VarDecl {{.*}} col:{{.*}} u0b 'const U0' constexpr listinit diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp index 9382558393e4c0eeae744c98a1d9433cf4f98d27..cd3b8c68213444f07dbabf6952035b2d42ac9d75 100644 --- a/clang/test/AST/ast-dump-ctad-alias.cpp +++ b/clang/test/AST/ast-dump-ctad-alias.cpp @@ -29,17 +29,21 @@ Out2::AInner t(1.0); // CHECK: | `-FunctionTemplateDecl {{.*}} // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 Y // CHECK-NEXT: | |-BinaryOperator {{.*}} '' '&&' -// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} '' lvalue (no ADL) = 'Concept' +// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} '' lvalue (no ADL) = 'Concept' // CHECK-NEXT: | | | |-TemplateArgument type 'int' // CHECK-NEXT: | | | | `-BuiltinType {{.*}} 'int' // CHECK-NEXT: | | | `-TemplateArgument type 'type-parameter-1-0' // CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0 // CHECK-NEXT: | | `-TypeTraitExpr {{.*}} 'bool' __is_deducible -// CHECK-NEXT: | | |-DeducedTemplateSpecializationType {{.*}} 'AInner' dependent +// CHECK-NEXT: | | |-DeducedTemplateSpecializationType {{.*}} 'Out2::AInner' dependent +// CHECK-NEXT: | | | `-name: 'Out2::AInner' +// CHECK-NEXT: | | | `-TypeAliasTemplateDecl {{.+}} AInner{{$}} // CHECK-NEXT: | | `-ElaboratedType {{.*}} 'Inner' sugar dependent -// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner' dependent Inner +// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner' dependent +// CHECK-NEXT: | | |-name: 'Inner':'Out::Inner' qualified +// CHECK-NEXT: | | | `-ClassTemplateDecl {{.+}} Inner{{$}} // CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0' -// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'type-parameter-1-0' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'type-parameter-1-0' // CHECK-NEXT: | | |-FunctionTemplate {{.*}} '' // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0 // CHECK-NEXT: | |-CXXDeductionGuideDecl {{.*}} 'auto (type-parameter-0-0) -> Inner' diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index 554cdcf83fcdfc16c41e84f43d5be15977b264f4..e84241cee922f5938b5b8f2abaeb2abeaeca4a8f 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -459,21 +459,23 @@ namespace testClassTemplateDecl { // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-148]]:3, col:31> col:31 TestTemplateDefaultNonType{{$}} // CHECK-NEXT: |-NonTypeTemplateParmDecl 0x{{.+}} col:16 'int' depth 0 index 0 I{{$}} -// CHECK-NEXT: | `-TemplateArgument expr{{$}} +// CHECK-NEXT: | `-TemplateArgument expr '42'{{$}} // CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} 'int' 42{{$}} // CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:31 struct TestTemplateDefaultNonType{{$}} // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:{{.*}}:3, col:68> col:68 TestTemplateTemplateDefaultType{{$}} // CHECK-NEXT: |-TemplateTemplateParmDecl 0x{{.+}} col:37 depth 0 index 0 TT{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} col:29 typename depth 1 index 0{{$}} -// CHECK-NEXT: | `-TemplateArgument template TestClassTemplate{{$}} -// CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:68 struct TestTemplateTemplateDefaultType{{$}} +// CHECK-NEXT: | `-TemplateArgument template 'TestClassTemplate':'testClassTemplateDecl::TestClassTemplate' qualified{{$}} +// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} line:{{.+}}:30 TestClassTemplate{{$}} +// CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:68 struct TestTemplateTemplateDefaultType{{$}} // CHECK: ClassTemplateDecl 0x{{.+}} prev 0x{{.+}} <{{.+}}:{{.*}}:3, col:82> col:48 TestTemplateTemplateDefaultType{{$}} // CHECK-NEXT: |-TemplateTemplateParmDecl 0x{{.+}} col:37 depth 0 index 0 TT{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} col:29 typename depth 1 index 0{{$}} -// CHECK-NEXT: | `-TemplateArgument template TestClassTemplate{{$}} -// CHECK-NEXT: | `-inherited from TemplateTemplateParm 0x{{.+}} 'TT'{{$}} +// CHECK-NEXT: | `-TemplateArgument template 'TestClassTemplate':'testClassTemplateDecl::TestClassTemplate' qualified{{$}} +// CHECK-NEXT: | |-inherited from TemplateTemplateParm 0x{{.+}} 'TT'{{$}} +// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} line:{{.+}}:30 TestClassTemplate // CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} prev 0x{{.+}} col:48 struct TestTemplateTemplateDefaultType definition{{$}} // CHECK-NEXT: |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}} // CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr{{$}} @@ -671,7 +673,7 @@ namespace TestNonTypeTemplateParmDecl { // CHECK: NamespaceDecl{{.*}} TestNonTypeTemplateParmDecl // CHECK-NEXT: FunctionTemplateDecl // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 0 I -// CHECK-NEXT: TemplateArgument expr +// CHECK-NEXT: TemplateArgument {{.*}} expr // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1 // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 1 ... J @@ -683,7 +685,8 @@ namespace TestTemplateTemplateParmDecl { // CHECK: FunctionTemplateDecl // CHECK-NEXT: TemplateTemplateParmDecl{{.*}} T // CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename -// CHECK-NEXT: TemplateArgument{{.*}} template A +// CHECK-NEXT: TemplateArgument{{.*}} template 'A':'TestTemplateTemplateParmDecl::A' qualified{{$}} +// CHECK-NEXT: ClassTemplateDecl {{.*}} A // CHECK-NEXT: TemplateTemplateParmDecl{{.*}} ... U // CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename @@ -710,12 +713,12 @@ namespace TestTemplateArgument { template class testIntegral { }; template class testIntegral<1>; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testIntegral - // CHECK: TemplateArgument{{.*}} integral 1 + // CHECK: TemplateArgument{{.*}} integral '1' template class> class testTemplate { }; template class testTemplate; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testTemplate - // CHECK: TemplateArgument{{.*}} A + // CHECK: TemplateArgument{{.*}} 'TestTemplateArgument::A'{{$}} template class ...T> class C { B testTemplateExpansion; @@ -731,10 +734,10 @@ namespace TestTemplateArgument { template class testPack { }; template class testPack<0, 1, 2>; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testPack - // CHECK: TemplateArgument{{.*}} integral 0 + // CHECK: TemplateArgument{{.*}} integral '0' // CHECK-NEXT: TemplateArgument{{.*}} pack - // CHECK-NEXT: TemplateArgument{{.*}} integral 1 - // CHECK-NEXT: TemplateArgument{{.*}} integral 2 + // CHECK-NEXT: TemplateArgument{{.*}} integral '1' + // CHECK-NEXT: TemplateArgument{{.*}} integral '2' } namespace testUsingDecl { diff --git a/clang/test/AST/ast-dump-default-init-json.cpp b/clang/test/AST/ast-dump-default-init-json.cpp index 1058b4e3ea4d93d9cbd6003034568a0d038ceb5f..f4949a9c9eedf4f5ac024ac9660c11f57a39b89d 100644 --- a/clang/test/AST/ast-dump-default-init-json.cpp +++ b/clang/test/AST/ast-dump-default-init-json.cpp @@ -789,10 +789,10 @@ void test() { // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "extendingDecl": { // CHECK-NEXT: "id": "0x{{.*}}", -// CHECK-NEXT: "kind": "FieldDecl", -// CHECK-NEXT: "name": "a", +// CHECK-NEXT: "kind": "VarDecl", +// CHECK-NEXT: "name": "b", // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "const A &" +// CHECK-NEXT: "qualType": "B" // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "storageDuration": "automatic", diff --git a/clang/test/AST/ast-dump-default-init.cpp b/clang/test/AST/ast-dump-default-init.cpp index 15b29f04bf21bf6700096a2f1f03577e9d95f312..26864fbf15424dc6af8815e3cdc02d836f111b51 100644 --- a/clang/test/AST/ast-dump-default-init.cpp +++ b/clang/test/AST/ast-dump-default-init.cpp @@ -13,7 +13,7 @@ void test() { } // CHECK: -CXXDefaultInitExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue has rewritten init // CHECK-NEXT: `-ExprWithCleanups 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue -// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Field 0x{{[^ ]*}} 'a' 'const A &' +// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Var 0x{{[^ ]*}} 'b' 'B' // CHECK-NEXT: `-ImplicitCastExpr 0x{{[^ ]*}} <{{.*}}> 'const A' // CHECK-NEXT: `-CXXFunctionalCastExpr 0x{{[^ ]*}} <{{.*}}> 'A' functional cast to A // CHECK-NEXT: `-InitListExpr 0x{{[^ ]*}} <{{.*}}> 'A' diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp index 4b7365e554cb7c8af20613e107380a53f322b6a6..dd2fe1fcf60cff3a61523d4a714baf8f6af80650 100644 --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -2333,7 +2333,7 @@ void TestNonADLCall3() { // CHECK-NEXT: "kind": "FunctionDecl", // CHECK-NEXT: "name": "operator delete", // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "void (void *) noexcept" +// CHECK-NEXT: "qualType": "void (void *, unsigned long) noexcept" // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "inner": [ diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index 604868103dab8b8fdbec5d373ab8efb7fe37ba80..5da025c229ea3d80adf606514f75f132f81bff2f 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -164,7 +164,7 @@ void UnaryExpressions(int *p) { // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *' ::delete p; - // CHECK: CXXDeleteExpr 0x{{[^ ]*}} 'void' global Function 0x{{[^ ]*}} 'operator delete' 'void (void *) noexcept' + // CHECK: CXXDeleteExpr 0x{{[^ ]*}} 'void' global Function 0x{{[^ ]*}} 'operator delete' 'void (void *, unsigned long) noexcept' // CHECK-NEXT: ImplicitCastExpr // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *' @@ -233,7 +233,7 @@ void PostfixExpressions(S a, S *p, U *r) { r->template U::~U(); // CHECK: CXXMemberCallExpr 0x{{[^ ]*}} 'void' // CHECK-NEXT: MemberExpr 0x{{[^ ]*}} '' ->~U 0x{{[^ ]*}} - // CHECK-NEXT: NestedNameSpecifier TypeSpecWithTemplate 'U' + // CHECK-NEXT: NestedNameSpecifier TypeSpecWithTemplate 'template U':'U' // CHECK-NEXT: ImplicitCastExpr // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'U *' lvalue ParmVar 0x{{[^ ]*}} 'r' 'U *' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp index da46cef7f3f1bce8b43f3aeaf0df8a7535f4f1a9..6fe05e33a5fb871058561bc5881457ba3e3d6fcb 100644 --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp @@ -79,7 +79,7 @@ int test() { // CHECK-NEXT: | | `-ReturnStmt [[ADDR_22:0x[a-z0-9]*]] // CHECK-NEXT: | | `-IntegerLiteral [[ADDR_23:0x[a-z0-9]*]] 'int' 0 // CHECK-NEXT: | `-FunctionDecl [[ADDR_24:0x[a-z0-9]*]] line:9:5 used also_before_mismatch 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-CompoundStmt [[ADDR_25:0x[a-z0-9]*]] // CHECK-NEXT: | `-ReturnStmt [[ADDR_26:0x[a-z0-9]*]] // CHECK-NEXT: | `-IntegerLiteral [[ADDR_23]] 'int' 0 @@ -179,7 +179,7 @@ int test() { // CHECK-NEXT: | | `-OMPDeclareVariantAttr [[ADDR_101:0x[a-z0-9]*]] <> Implicit implementation={extension(allow_templates)} // CHECK-NEXT: | | `-DeclRefExpr [[ADDR_102:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_103:0x[a-z0-9]*]] 'only_def[implementation={extension(allow_templates)}]' 'int ({{.*}})' // CHECK-NEXT: | `-FunctionDecl [[ADDR_104:0x[a-z0-9]*]] col:5 used only_def 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_105:0x[a-z0-9]*]] <> Implicit implementation={extension(allow_templates)} // CHECK-NEXT: | `-DeclRefExpr [[ADDR_106:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_107:0x[a-z0-9]*]] 'only_def[implementation={extension(allow_templates)}]' 'int ({{.*}})' // CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_108:0x[a-z0-9]*]] line:38:1 only_def[implementation={extension(allow_templates)}] @@ -189,7 +189,7 @@ int test() { // CHECK-NEXT: | | `-ReturnStmt [[ADDR_110:0x[a-z0-9]*]] // CHECK-NEXT: | | `-IntegerLiteral [[ADDR_111:0x[a-z0-9]*]] 'int' 0 // CHECK-NEXT: | `-FunctionDecl [[ADDR_107]] line:38:1 only_def[implementation={extension(allow_templates)}] 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-CompoundStmt [[ADDR_112:0x[a-z0-9]*]] // CHECK-NEXT: | `-ReturnStmt [[ADDR_113:0x[a-z0-9]*]] // CHECK-NEXT: | `-IntegerLiteral [[ADDR_111]] 'int' 0 diff --git a/clang/test/AST/ast-dump-stmt-json.cpp b/clang/test/AST/ast-dump-stmt-json.cpp index 667a12a0120244e6a6adb7d20870df586a983233..a473d17da94244f842834dc2951589c717e7f22f 100644 --- a/clang/test/AST/ast-dump-stmt-json.cpp +++ b/clang/test/AST/ast-dump-stmt-json.cpp @@ -994,7 +994,7 @@ void TestDependentGenericSelectionExpr(Ty T) { // CHECK-NEXT: "kind": "FunctionDecl", // CHECK-NEXT: "name": "operator delete", // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "void (void *) noexcept" +// CHECK-NEXT: "qualType": "void (void *, unsigned long) noexcept" // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "inner": [ @@ -1369,7 +1369,7 @@ void TestDependentGenericSelectionExpr(Ty T) { // CHECK-NEXT: "kind": "FunctionDecl", // CHECK-NEXT: "name": "operator delete", // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "void (void *) noexcept" +// CHECK-NEXT: "qualType": "void (void *, unsigned long) noexcept" // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "inner": [ @@ -1722,7 +1722,6 @@ void TestDependentGenericSelectionExpr(Ty T) { // CHECK-NEXT: "end": {} // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, -// CHECK-NEXT: "isUsed": true, // CHECK-NEXT: "name": "operator delete", // CHECK-NEXT: "mangledName": "_ZdlPv", // CHECK-NEXT: "type": { @@ -1810,6 +1809,126 @@ void TestDependentGenericSelectionExpr(Ty T) { // CHECK-NEXT: } +// CHECK-NOT: {{^}}Dumping +// CHECK: "kind": "FunctionDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "isUsed": true, +// CHECK-NEXT: "name": "operator delete", +// CHECK-NEXT: "mangledName": "_ZdlPvm", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void (void *, unsigned long) noexcept" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void *" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "unsigned long" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VisibilityAttr", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "implicit": true, +// CHECK-NEXT: "visibility": "default" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + +// CHECK-NOT: {{^}}Dumping +// CHECK: "kind": "FunctionDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "operator delete", +// CHECK-NEXT: "mangledName": "_ZdlPvmSt11align_val_t", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void (void *, unsigned long, std::align_val_t) noexcept" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void *" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "unsigned long" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "std::align_val_t" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VisibilityAttr", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "implicit": true, +// CHECK-NEXT: "visibility": "default" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": {}, @@ -1906,6 +2025,125 @@ void TestDependentGenericSelectionExpr(Ty T) { // CHECK-NEXT: } +// CHECK-NOT: {{^}}Dumping +// CHECK: "kind": "FunctionDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "operator delete[]", +// CHECK-NEXT: "mangledName": "_ZdaPvm", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void (void *, unsigned long) noexcept" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void *" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "unsigned long" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VisibilityAttr", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "implicit": true, +// CHECK-NEXT: "visibility": "default" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + +// CHECK-NOT: {{^}}Dumping +// CHECK: "kind": "FunctionDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "operator delete[]", +// CHECK-NEXT: "mangledName": "_ZdaPvmSt11align_val_t", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void (void *, unsigned long, std::align_val_t) noexcept" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void *" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "unsigned long" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": {}, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "std::align_val_t" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VisibilityAttr", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": {}, +// CHECK-NEXT: "end": {} +// CHECK-NEXT: }, +// CHECK-NEXT: "implicit": true, +// CHECK-NEXT: "visibility": "default" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionTemplateDecl", // CHECK-NEXT: "loc": { diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp index 37f6d8a0472d30e6ca37b6f79a9518fca24021bc..fea14abb3b2f4911cbcde3e60d451d757cbcde52 100644 --- a/clang/test/AST/ast-dump-template-decls.cpp +++ b/clang/test/AST/ast-dump-template-decls.cpp @@ -116,7 +116,10 @@ template struct C { using type2 = typename C::type1; // CHECK: TypeAliasDecl 0x{{[^ ]*}} col:7 type2 'typename C::type1':'void (int)' // CHECK-NEXT: ElaboratedType 0x{{[^ ]*}} 'typename C::type1' sugar -// CHECK-NEXT: TemplateSpecializationType 0x{{[^ ]*}} 'type1' sugar alias type1 +// CHECK-NEXT: TemplateSpecializationType 0x{{[^ ]*}} 'type1' sugar alias +// CHECK-NEXT: name: 'C::type1':'PR55886::C::type1' qualified +// CHECK-NEXT: NestedNameSpecifier TypeSpec 'C':'PR55886::C' +// CHECK-NEXT: TypeAliasTemplateDecl {{.+}} type1 // CHECK-NEXT: TemplateArgument type 'void' // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void' // CHECK-NEXT: FunctionProtoType 0x{{[^ ]*}} 'void (int)' cdecl @@ -135,7 +138,7 @@ template struct foo { template using bind = Z; }; using t1 = foo::bind; -// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'Y' sugar Y +// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'Y' sugar // CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... Bs pack_index 3 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z' // CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... Bs pack_index 2 @@ -149,7 +152,8 @@ template struct D { template using B = int(int (*...p)(T, U)); }; using t2 = D::B; -// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'B' sugar alias B +// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'B' sugar alias{{$}} +// CHECK-NEXT: name: 'D::B':'PR56099::D::B' qualified // CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (int (*)(float, int), int (*)(char, short))' cdecl // CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (float, int)' cdecl // CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T pack_index 1 @@ -169,8 +173,10 @@ template> class D1, class D2> using D = D1 class E {}; using test1 = D; -// CHECK: TypeAliasDecl 0x{{[^ ]*}} col:7 test1 'D':'subst_default_argument::E>' -// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'A' sugar A +// CHECK: TypeAliasDecl 0x{{[^ ]*}} col:7 test1 'D':'subst_default_argument::E>' +// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'A' sugar +// CHECK-NEXT: |-name: 'A':'subst_default_argument::A' qualified +// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A // CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 1 D2 // CHECK-NEXT: | |-TypeAliasTemplate 0x{{[^ ]*}} 'D' diff --git a/clang/test/AST/ast-dump-template-name.cpp b/clang/test/AST/ast-dump-template-name.cpp new file mode 100644 index 0000000000000000000000000000000000000000..acacdac857954cf4a3c50f7edd507bbc3343bcf9 --- /dev/null +++ b/clang/test/AST/ast-dump-template-name.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -std=c++26 -ast-dump -ast-dump-filter=Test %s | FileCheck %s + +template