diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 3ed5eb96eceb58f9b73743c72ede61a9a7df5915..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,9 +65,13 @@ 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 lldb cross-project-tests; do @@ -76,7 +82,10 @@ 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 @@ -241,7 +250,7 @@ fi all_projects="bolt clang clang-tools-extra compiler-rt cross-project-tests flang libc libclc lld lldb llvm mlir openmp polly pstl" modified_projects="$(keep-modified-projects ${all_projects})" -linux_projects_to_test=$(exclude-linux $(compute-projects-to-test ${modified_projects})) +linux_projects_to_test=$(exclude-linux $(compute-projects-to-test 0 ${modified_projects})) linux_check_targets=$(check-targets ${linux_projects_to_test} | sort | uniq) linux_projects=$(add-dependencies ${linux_projects_to_test} | sort | uniq) @@ -249,7 +258,7 @@ linux_runtimes_to_test=$(compute-runtimes-to-test ${linux_projects_to_test}) linux_runtime_check_targets=$(check-targets ${linux_runtimes_to_test} | sort | uniq) linux_runtimes=$(echo ${linux_runtimes_to_test} | sort | uniq) -windows_projects_to_test=$(exclude-windows $(compute-projects-to-test ${modified_projects})) +windows_projects_to_test=$(exclude-windows $(compute-projects-to-test 1 ${modified_projects})) windows_check_targets=$(check-targets ${windows_projects_to_test} | sort | uniq) windows_projects=$(add-dependencies ${windows_projects_to_test} | sort | uniq) diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index a57ba28faf160b7b6df2ac5ba8f89e9cb3a54b6e..b47301851e29ec009f7032f7585ecfcfeb9bca13 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -54,6 +54,9 @@ llvm-lit: - llvm/utils/lit/**/* PGO: + - llvm/**/ProfileData/**/* + - llvm/**/SampleProfile* + - llvm/**/CodeGen/MIRSampleProfile* - llvm/lib/Transforms/Instrumentation/CGProfile.cpp - llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp - llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -62,9 +65,9 @@ PGO: - llvm/lib/Transforms/Instrumentation/ValueProfile* - llvm/test/Instrumentation/InstrProfiling/**/* - llvm/test/Transforms/PGOProfile/**/* + - llvm/test/Transforms/SampleProfile/**/* - llvm/**/llvm-profdata/**/* - llvm/**/llvm-profgen/**/* - - llvm/unittests/ProfileData/**/* vectorization: - llvm/lib/Transforms/Vectorize/**/* @@ -746,6 +749,8 @@ backend:ARM: - clang/lib/CodeGen/Targets/ARM.cpp - clang/include/clang/Basic/BuiltinsARM* - llvm/test/MC/DisasemblerARM/** + - clang/include/clang/Sema/SemaARM.h + - clang/lib/Sema/SemaARM.cpp backend:AArch64: - llvm/include/llvm/IR/IntrinsicsAArch64.td @@ -757,6 +762,8 @@ backend:AArch64: - clang/lib/CodeGen/Targets/AArch64.cpp - clang/include/clang/Basic/BuiltinsAArch64* - llvm/test/MC/Disassembler/AArch64/** + - clang/include/clang/Sema/SemaARM.h + - clang/lib/Sema/SemaARM.cpp backend:loongarch: - llvm/include/llvm/IR/IntrinsicsLoongArch.td @@ -767,6 +774,8 @@ backend:loongarch: - clang/lib/Driver/ToolChains/Arch/LoongArch.* - clang/lib/CodeGen/Targets/LoongArch.cpp - clang/include/clang/Basic/BuiltinsLoongArch* + - clang/include/clang/Sema/SemaLoongArch.h + - clang/lib/Sema/SemaLoongArch.cpp backend:MSP430: - llvm/include/llvm/IR/IntrinsicsMSP430.td @@ -814,6 +823,8 @@ backend:WebAssembly: - llvm/unittests/Target/WebAssembly/** - llvm/test/DebugInfo/WebAssembly/** - llvm/test/MC/WebAssembly/** + - clang/include/clang/Sema/SemaWasm.h + - clang/lib/Sema/SemaLoongWasm.cpp backend:X86: - llvm/include/llvm/IR/IntrinsicsX86.td @@ -833,6 +844,8 @@ backend:X86: - llvm/include/llvm/TargetParser/X86* - llvm/lib/TargetParser/X86* - llvm/utils/TableGen/X86* + - clang/include/clang/Sema/SemaX86.h + - clang/lib/Sema/SemaX86.cpp backend:PowerPC: - llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC* @@ -857,6 +870,8 @@ backend:PowerPC: - clang/lib/Driver/ToolChains/AIX* - clang/lib/Driver/ToolChains/Arch/PPC.* - clang/test/CodeGen/PowerPC/** + - clang/include/clang/Sema/SemaPPC.h + - clang/lib/Sema/SemaPPC.cpp backend:SystemZ: - llvm/include/llvm/BinaryFormat/ELFRelocs/SystemZ* @@ -877,6 +892,8 @@ backend:SystemZ: - clang/lib/Driver/ToolChains/ZOS* - clang/lib/Driver/ToolChains/Arch/SystemZ.* - clang/test/CodeGen/SystemZ/** + - clang/include/clang/Sema/SemaSystemZ.h + - clang/lib/Sema/SemaSystemZ.cpp third-party:unittests: - third-party/unittests/** diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index 1951ad5a2dc5eb8997f32ef25e51cd6e807a6e5f..8887d1f5d5bd497e4e1cce5ec69559c2725de6f1 100644 --- a/bolt/docs/CommandLineArgumentReference.md +++ b/bolt/docs/CommandLineArgumentReference.md @@ -6,41 +6,37 @@ ## OPTIONS -### Generic options +### Generic options: - `-h` - Alias for `--help` + Alias for --help - `--help` - Display available options (`--help-hidden` for more). + Display available options (--help-hidden for more) - `--help-hidden` - Display all available options. + Display all available options - `--help-list` - Display list of available options (`--help-list-hidden` for more). + Display list of available options (--help-list-hidden for more) - `--help-list-hidden` - Display list of all available options. + Display list of all available options -- `--print-all-options` - - Print all option values after command line parsing. - -- `--print-options` +- `--version` - Print non-default options after command line parsing. + Display the version of this program -- `--version` +### Output options: - Display the version of this program. +- `--bolt-info` -### Output options + Write bolt info section in the output binary - `-o ` @@ -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/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/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 64113bd026012e8a66c29c0442039348baf71385..a55516d553979cd4c6ccb746eb60c5b1068c4879 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 @@ -596,6 +597,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/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index c897392f2a574c4181013643158080b64f365717..d13e28999a05ca61dc3aec0cdd891dedec641734 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -3641,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. // @@ -3659,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()) { 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/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/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index cf6b61ddd603148dc4660db8dee2235567acd699..9adbfdc5ff0897cb228f8e28ea58727185dc55f6 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -74,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/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index ab46503621e9aa618e3d41a339e5bceaa45da577..8814ebbd10aa500cc168b2e2633d10b13cc8343b 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -352,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/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 4b4913dd7a16c050afe4364cc71f51ca96555c4d..e452e956c949eb8b224074429a013683231ad273 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -55,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" @@ -945,9 +944,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) { @@ -1229,7 +1225,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; @@ -1460,10 +1456,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); 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/Inputs/lsda.ldscript b/bolt/test/Inputs/lsda.ldscript index aa608ecd97e8c5cdda5fc404eae2a3fa9ddf456c..011e0c6ac8a0f1da2bab0065917a08a207603c73 100644 --- a/bolt/test/Inputs/lsda.ldscript +++ b/bolt/test/Inputs/lsda.ldscript @@ -1,5 +1,8 @@ SECTIONS { + .interp : { *(.interp) } + . = ALIGN(CONSTANT(MAXPAGESIZE)); .text : { *(.text*) } + . = ALIGN(CONSTANT(MAXPAGESIZE)); .gcc_except_table.main : { *(.gcc_except_table*) } . = 0x20000; .eh_frame : { *(.eh_frame) } 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-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 8bbecc498ed75e0cd209d60f3dfdd0fe68ce3faf..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 @@ -17,7 +17,7 @@ # 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) +## 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]] 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 8f65eaba891ec4b171ab4581070510dd24ba8763..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,16 +26,16 @@ 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. +## 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 diff --git a/bolt/test/X86/bolt-address-translation.test b/bolt/test/X86/bolt-address-translation.test index dfdd1eea323337b436d7f77bcea2f734cf6f4571..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,28 +11,28 @@ # 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 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.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-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.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 index 12e4fb92adcc0d0017c874e8d09ec3a38da2e2cf..94d7a91f2c7fd99d529ec5b7a8e606d0e53c356a 100644 --- a/bolt/test/X86/ignored-interprocedural-reference.s +++ b/bolt/test/X86/ignored-interprocedural-reference.s @@ -1,5 +1,5 @@ -# This reproduces a bug with not processing interprocedural references from -# ignored functions. +## This reproduces a bug with not processing interprocedural references from +## ignored functions. # REQUIRES: system-linux @@ -16,7 +16,7 @@ # 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. +## main calls foo at valid instruction offset past nops that are to be stripped. .globl main main: .cfi_startproc @@ -25,7 +25,7 @@ main: .cfi_endproc .size main,.-main -# Placeholder cold fragment to force main to be ignored in non-relocation mode. +## Placeholder cold fragment to force main to be ignored in non-relocation mode. .globl main.cold main.cold: .cfi_startproc @@ -33,8 +33,8 @@ main.cold: .cfi_endproc .size main.cold,.-main.cold -# foo is set up to contain a valid instruction at called offset, and trapping -# instructions past that. +## foo is set up to contain a valid instruction at called offset, and trapping +## instructions past that. .globl foo foo: .cfi_startproc 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/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 90c402b2234d761dd99c1883f76d22ba8435b38d..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 \ 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/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/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/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/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/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/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/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/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3e3195f6f68139923a8c1931bb7090b17011a796..4f674d1a4d5560c805231975478f969d0db05d59 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 ------------------------- @@ -363,6 +368,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. 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/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/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9091f6341bd9b85edca817f77a6909c9c4256228..e1c81a818860f0c8c1e7ea10e71ba1244b9c9d39 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -98,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 @@ -249,6 +251,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 ------------------ @@ -318,6 +323,9 @@ Non-comprehensive list of changes in this release - Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may now be used within constant expressions. +- ``#pragma GCC diagnostic warning "-Wfoo"`` can now downgrade ``-Werror=foo`` + errors and certain default-to-error ``-W`` diagnostics to warnings. + New Compiler Flags ------------------ - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and @@ -810,12 +818,21 @@ Bug Fixes to C++ Support - 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). 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 ^^^^^^^^^^^^^^^^^^^^^^^ 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 3a31708a1e9de6ce683b0dcb69d45f4efdcfefe8..bbc31832b9c3cabbaffa9f548ac162945519ccaf 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3135,17 +3135,42 @@ alpha.unix 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`` +Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``. +Critical section handling functions modelled 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 test() { - std::mutex m; - m.lock(); - sleep(3); // warn: a blocking function sleep is called inside a critical - // section - m.unlock(); + 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. + } } .. _alpha-unix-Chroot: diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 4bbb4380cdd7fdcad20824f8fd6a928985d0c05d..99093aa17972c416d3b557d3d2011e9125cefbe1 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -855,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; } diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index b7732e54ba1079f2d037e451f45bbe2e9dcec725..7aedc086ab7d010b0b2f336c57fdb2de31f1a650 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -332,7 +332,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 +360,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 +421,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..caa33abd99e47d598fc630140385fbf4c8343c30 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 = {}); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ef9df1e9d8b4aaae8d9e5777a93571624b8ae926..2665b7353ca4a56a2f62c0b6eb540bd29bfdf3e6 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) @@ -4480,6 +4478,29 @@ 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; + } + } +}]; } def HLSLResource : InheritableAttr { 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/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 6b595a35679329f06d12ce942a3ffc36d2051761..7d5ba7869ec340a167cab2c2e4124c22145b3ad1 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1517,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/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f8328be5890dd6710e49b98f1ce69521e9ad149b..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">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f15cba63624ea6bb394403ae04f7842421604062..e34eb692941b4fc51fa6a61e0ba6043f4316de4e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12239,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">; 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 03570f94de66663f0403c25465010159008ca5b2..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], []>; @@ -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 de2f245fb29f8e20c2fd1bc2cd9fda7d4cb54cb8..57f37c5023110f0bb20ce298242385f52df1fee9 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4345,6 +4345,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, @@ -6277,11 +6281,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 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/Sema/Attr.h b/clang/include/clang/Sema/Attr.h new file mode 100644 index 0000000000000000000000000000000000000000..1133862568a6c2a8e8c3b36ecc7b16ba34d3b2e4 --- /dev/null +++ b/clang/include/clang/Sema/Attr.h @@ -0,0 +1,36 @@ +//===----- 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/Decl.h" +#include "clang/AST/DeclObjC.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); +} + +} // namespace clang +#endif // LLVM_CLANG_SEMA_ATTR_H diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ec083f7cc09b7ce1ad9a0bb56e1a58cd32bf92d2..7dea2b6826cfdbbd4313fc15b2821fd4f759179d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -67,6 +67,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,15 +169,25 @@ class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; +class SemaAMDGPU; +class SemaARM; +class SemaBPF; class SemaCodeCompletion; class SemaCUDA; class SemaHLSL; +class SemaHexagon; +class SemaLoongArch; +class SemaMIPS; +class SemaNVPTX; class SemaObjC; class SemaOpenACC; class SemaOpenMP; +class SemaPPC; class SemaPseudoObject; class SemaRISCV; class SemaSYCL; +class SemaSystemZ; +class SemaWasm; class SemaX86; class StandardConversionSequence; class Stmt; @@ -884,9 +895,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(); } @@ -993,6 +1001,21 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + SemaAMDGPU &AMDGPU() { + assert(AMDGPUPtr); + return *AMDGPUPtr; + } + + SemaARM &ARM() { + assert(ARMPtr); + return *ARMPtr; + } + + SemaBPF &BPF() { + assert(BPFPtr); + return *BPFPtr; + } + SemaCodeCompletion &CodeCompletion() { assert(CodeCompletionPtr); return *CodeCompletionPtr; @@ -1008,6 +1031,26 @@ public: return *HLSLPtr; } + SemaHexagon &Hexagon() { + assert(HexagonPtr); + return *HexagonPtr; + } + + SemaLoongArch &LoongArch() { + assert(LoongArchPtr); + return *LoongArchPtr; + } + + SemaMIPS &MIPS() { + assert(MIPSPtr); + return *MIPSPtr; + } + + SemaNVPTX &NVPTX() { + assert(NVPTXPtr); + return *NVPTXPtr; + } + SemaObjC &ObjC() { assert(ObjCPtr); return *ObjCPtr; @@ -1023,6 +1066,11 @@ public: return *OpenMPPtr; } + SemaPPC &PPC() { + assert(PPCPtr); + return *PPCPtr; + } + SemaPseudoObject &PseudoObject() { assert(PseudoObjectPtr); return *PseudoObjectPtr; @@ -1038,6 +1086,16 @@ public: return *SYCLPtr; } + SemaSystemZ &SystemZ() { + assert(SystemZPtr); + return *SystemZPtr; + } + + SemaWasm &Wasm() { + assert(WasmPtr); + return *WasmPtr; + } + SemaX86 &X86() { assert(X86Ptr); return *X86Ptr; @@ -1073,15 +1131,25 @@ private: mutable IdentifierInfo *Ident_super; + std::unique_ptr AMDGPUPtr; + std::unique_ptr ARMPtr; + 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 MIPSPtr; + std::unique_ptr NVPTXPtr; std::unique_ptr ObjCPtr; std::unique_ptr OpenACCPtr; std::unique_ptr OpenMPPtr; + std::unique_ptr PPCPtr; std::unique_ptr PseudoObjectPtr; std::unique_ptr RISCVPtr; std::unique_ptr SYCLPtr; + std::unique_ptr SystemZPtr; + std::unique_ptr WasmPtr; std::unique_ptr X86Ptr; ///@} @@ -2074,6 +2142,8 @@ public: 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, @@ -2087,8 +2157,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); @@ -2102,54 +2170,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 CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall); - bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - - 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); @@ -2162,13 +2189,6 @@ private: ExprResult BuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult AtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); - 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, @@ -2185,16 +2205,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, @@ -3548,6 +3558,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 @@ -3705,41 +3762,6 @@ public: 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, @@ -8988,6 +9010,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, 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..02698a33abd55e0f040a8373f924e74a5c045ecd --- /dev/null +++ b/clang/include/clang/Sema/SemaARM.h @@ -0,0 +1,63 @@ +//===----- 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/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace clang { + +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); +}; + +SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD); + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAARM_H diff --git a/clang/include/clang/Sema/SemaBPF.h b/clang/include/clang/Sema/SemaBPF.h new file mode 100644 index 0000000000000000000000000000000000000000..a3bf59128d2548050c4cea17841cca7caf2e7d7f --- /dev/null +++ b/clang/include/clang/Sema/SemaBPF.h @@ -0,0 +1,28 @@ +//===----- 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/Expr.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaBPF : public SemaBase { +public: + SemaBPF(Sema &S); + + bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); +}; +} // 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..eac1f7c07c85dec4d0c6f4b8e8a7058780976a4b 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -49,6 +49,7 @@ public: void DiagnoseAttrStageMismatch( const Attr *A, HLSLShaderAttr::ShaderType Stage, std::initializer_list AllowedStages); + void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); }; } // 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/SemaMIPS.h b/clang/include/clang/Sema/SemaMIPS.h new file mode 100644 index 0000000000000000000000000000000000000000..3f1781b36efd933bf55019f9a2b97adc547d6c5b --- /dev/null +++ b/clang/include/clang/Sema/SemaMIPS.h @@ -0,0 +1,33 @@ +//===----- 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/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +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); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAMIPS_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/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/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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a2398fef623ea2143c119ebfda8563cead2627f3..73d3b152c49f1f0c53721847379085b2617fd0f3 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()) @@ -6799,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 @@ -9304,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; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 41fbfe281ef65b3a82e46e8b0cd622fe0b7d4914..0a35ed536a6a7e917160ebdbc3ce268d83888f7c 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2408,9 +2408,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..ffb22194bce5290227d55d1781d5a95fbb950a13 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) { diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 95ffd4784641fcedef21ac67cad6affec8b8703d..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; } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 246e56231539ae2025bb3ae2e8cd3ef3ecf1ecec..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: 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/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index a7ee973b7f7d0692dfa1290aa586b524e9077b0c..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. @@ -539,16 +544,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, break; case Template: { - TemplateName TN = getAsTemplate(); - if (const auto *TD = TN.getAsTemplateDecl(); - TD && TD->getDeclName().isEmpty()) { - assert(isa(TD) && - "Unexpected anonymous template"); - const auto *TTP = cast(TD); - Out << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex(); - } else { - TN.print(Out, Policy, TemplateName::Qualified::Fully); - } + getAsTemplate().print(Out, Policy); break; } diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 2f0e4181e9408668e360ea5697e3f771793697d0..3dbdad92813f6f91482a52db80c2b92516665e3d 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -235,8 +235,8 @@ 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 +292,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 +311,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..0e0e0a86f5cfcb0973a222fc9f62ebeadda57da2 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -947,6 +947,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 +1106,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 +2014,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( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 04f105c12887216ec90d23ae5e835a1e6eb48029..2097b29b7e0b6d972ea562938ddc375c9af2a414 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4251,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 5ed56b367a46a7ede21e7c3ccb3a79aa0948840f..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); diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 3a30cff917bb4fa8a69817598eb7b0edf3fee035..036a655a4d073f45de80e50ec3a90862e970d9be 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -441,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") { @@ -961,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) { @@ -1478,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)) { @@ -1750,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 0633b7e0da96a28828a5b38885ef263954b5cebc..9b2ae87adb2e742551a07a8f76e667b2fb1d2cbf 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -172,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 a3c65105033247591990952d9f7f3c2c3407b6fa..37d0c478e03308cf1713f5ffef3a9f3b1e08582e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -5978,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()); } } @@ -14074,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)); @@ -14116,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)); @@ -14137,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); @@ -16724,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) { 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..1713f7065e7a20d591d84cac1559107c69c8bbd3 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(); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 7a92fc3dfb4a43471f2b215236adbd7d61acf3fd..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, 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/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index e4774a587707ac39e88cd38d8d7cadc89ead3c01..c2314c3a57d3309a5b617ebaf9439e8aac2e1643 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5341,6 +5341,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); @@ -6119,9 +6131,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(); @@ -6192,8 +6201,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(); @@ -6249,10 +6257,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/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 97e451cfe2acb411d25828c14d9c65f8b78f7caa..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" @@ -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. 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/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/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 b6f7567adc140121fc53e192684dc6d0eddd7d81..5c0ff0f6132b2d89a4ef73ac4f868121cc968e29 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1410,13 +1410,6 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { } } -static bool isAltOperator(const FormatToken &Tok) { - return isalpha(Tok.TokenText[0]) && - Tok.isOneOf(tok::ampamp, tok::ampequal, tok::amp, tok::pipe, - tok::tilde, tok::exclaim, tok::exclaimequal, tok::pipepipe, - tok::pipeequal, tok::caret, tok::caretequal); -} - void UnwrappedLineParser::parseStructuralElement( const FormatToken *OpeningBrace, IfStmtKind *IfKind, FormatToken **IfLeftBrace, bool *HasDoWhile, bool *HasLabel) { @@ -1699,7 +1692,7 @@ void UnwrappedLineParser::parseStructuralElement( for (const bool InRequiresExpression = OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); !eof();) { - if (IsCpp && isAltOperator(*FormatTok)) { + if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) { if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true); Next && Next->isBinaryOperator()) { FormatTok->Tok.setKind(tok::identifier); @@ -4026,6 +4019,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/Headers/intrin.h b/clang/lib/Headers/intrin.h index 5ceb986a1f652857f8cb1fdab335cf01e34ffbf5..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__) 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/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e149b1a0fb5efc94ce61ef7802af9332c28c7b17..1558e3dcb8974e828e0489dfae1c968f4597cb0d 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" @@ -3026,13 +3027,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; } 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/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index fe6471c81ff01a8f609ad96ea5ff432422d1ab5c..c9abf58fcbd29e765cccd8cae85da26eacbb6532 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -26,10 +26,13 @@ add_clang_library(clangSema Scope.cpp ScopeInfo.cpp Sema.cpp + SemaAMDGPU.cpp + SemaARM.cpp SemaAccess.cpp SemaAttr.cpp SemaAPINotes.cpp SemaAvailability.cpp + SemaBPF.cpp SemaBase.cpp SemaCXXScopeSpec.cpp SemaCast.cpp @@ -50,27 +53,34 @@ add_clang_library(clangSema SemaExprObjC.cpp SemaFixItUtils.cpp SemaHLSL.cpp + SemaHexagon.cpp SemaInit.cpp SemaLambda.cpp SemaLookup.cpp + SemaLoongArch.cpp + SemaMIPS.cpp SemaModule.cpp + SemaNVPTX.cpp SemaObjC.cpp SemaObjCProperty.cpp SemaOpenACC.cpp SemaOpenMP.cpp SemaOverload.cpp + SemaPPC.cpp SemaPseudoObject.cpp SemaRISCV.cpp SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp SemaSYCL.cpp + SemaSystemZ.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaTemplateVariadic.cpp SemaType.cpp + SemaWasm.cpp SemaX86.cpp TypeLocBuilder.cpp diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d1fb21bb1ae1d6f3693468326cb978477a1a9207..582adcfa84c4646e6174961b43c9327d8c6aa255 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -41,17 +41,27 @@ #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/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/SemaMIPS.h" +#include "clang/Sema/SemaNVPTX.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenACC.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/SemaSystemZ.h" +#include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" @@ -206,16 +216,26 @@ 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)), + 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)), + MIPSPtr(std::make_unique(*this)), + NVPTXPtr(std::make_unique(*this)), ObjCPtr(std::make_unique(*this)), OpenACCPtr(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)), + SystemZPtr(std::make_unique(*this)), + WasmPtr(std::make_unique(*this)), X86Ptr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), @@ -1357,6 +1377,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 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/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da37ccef051a68dbf2a7ac8b9e5e0e8ce5922a20 --- /dev/null +++ b/clang/lib/Sema/SemaARM.cpp @@ -0,0 +1,1088 @@ +//===------ 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/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 clang diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 22f5a2f66347789f1a08f8b0f44f1f3ec9eb05be..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 diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bde1a26f1ebc0e6b9782c85f4db5224d27e9085c --- /dev/null +++ b/clang/lib/Sema/SemaBPF.cpp @@ -0,0 +1,174 @@ +//===------ 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/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; +} + +} // 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/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c3251f3cc9d81faa2db8ccfc07ac6ed326259ca8..300af02239779f57b309351eece6a9cdcbfee796 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -61,9 +61,19 @@ #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" @@ -2259,23 +2269,23 @@ 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 X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); @@ -2283,21 +2293,22 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, 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 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); } } @@ -3287,1988 +3298,6 @@ 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 -}; - -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 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; - - // Check constant-ness first. - llvm::APSInt Imm; - if (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 (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; - } - } - - return HasError; -} - -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; - } - } - return ArmNonStreaming; -} - -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"; - } -} - -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 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); -} - -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; - - 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 - } - } - - 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 - } - - // 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)) - 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()) - return true; - if (DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy, RHSTy, - RHS.get(), 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_neon.inc" - #include "clang/Basic/arm_fp16.inc" - #undef GET_NEON_IMMEDIATE_CHECK - } - - 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" - } -} - -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(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() << 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) - << 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() << 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 = 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(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, @@ -5293,182 +3322,6 @@ bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { << 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); @@ -5664,225 +3517,30 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } // 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_global_load_lds: { - constexpr const int SizeIdx = 2; - llvm::APSInt Size; - Expr *ArgExpr = TheCall->getArg(SizeIdx); - ExprResult R = 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, 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: + case Builtin::BI__builtin_elementwise_bitreverse: { + if (CheckUnsignedIntRepresentation(this, TheCall)) + return true; 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::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); + 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::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(TheCall, 3); } - return false; } @@ -6113,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 @@ -6263,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()) @@ -6299,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; @@ -7165,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 @@ -8069,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(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) { @@ -8635,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(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(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(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(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(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. @@ -12718,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 @@ -18396,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(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(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(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(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(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(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/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2a87b26f17a2b1cb0d5b245c52511925e475ce56..34e46e12859bb2bf44926052fb97f639b2ce00f6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -50,7 +50,9 @@ #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/SemaWasm.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallString.h" @@ -538,8 +540,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. @@ -1137,12 +1140,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. @@ -2930,9 +2931,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)) @@ -8896,7 +8897,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; } @@ -12057,7 +12058,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(); } @@ -15349,7 +15350,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(); } @@ -18764,7 +18765,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 5041fd65286fa0d3a718bd5b7b5a8363f04a8aa4..7c1fb23b90728c427e0b077cea20a6a929cad4d3 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,12 @@ #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaWasm.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" @@ -71,19 +74,6 @@ 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) { @@ -94,7 +84,7 @@ static bool hasDeclarator(const Decl *D) { /// hasFunctionProto - Return true if the given decl has a argument /// information. This decl should have already passed -/// isFunctionOrMethod or isFunctionOrMethodOrBlock. +/// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject. static bool hasFunctionProto(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) return isa(FnTy); @@ -207,52 +197,7 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 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 +206,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()) { @@ -310,7 +255,7 @@ 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)); + assert(isFunctionOrMethodOrBlockForAttrSubject(D)); // In C++ the implicit 'this' function parameter also counts. // Parameters are counted from one. @@ -323,7 +268,7 @@ static bool checkFunctionOrMethodParameterIndex( std::optional IdxInt; if (IdxExpr->isTypeDependent() || !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + S.Diag(S.getAttrLoc(AI), diag::err_attribute_argument_n_type) << &AI << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; @@ -331,13 +276,14 @@ static bool checkFunctionOrMethodParameterIndex( unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { - S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) + S.Diag(S.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) + S.Diag(S.getAttrLoc(AI), + diag::err_attribute_invalid_implicit_this_argument) << &AI << IdxExpr->getSourceRange(); return false; } @@ -845,7 +791,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 +1046,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 +1156,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 @@ -2295,7 +2241,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 +2345,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 +2354,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)); @@ -3297,8 +3243,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) @@ -3321,7 +3267,7 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { 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)) + if (!S.checkUInt32Argument(AL, E, SGSize)) return; if (SGSize == 0) { S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) @@ -3790,7 +3736,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; } @@ -4003,7 +3949,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 +4048,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) { @@ -4139,7 +4085,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 +4173,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; @@ -5727,7 +5673,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; } @@ -5923,14 +5869,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; } @@ -6776,7 +6722,7 @@ static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) { return; Expr *IdxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, IdxExpr, ParamIdx)) + if (!S.checkUInt32Argument(AL, IdxExpr, ParamIdx)) return; break; } @@ -7278,7 +7224,7 @@ static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } uint32_t X; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), X)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), X)) return; if (X > 1024) { S.Diag(AL.getArgAsExpr(0)->getExprLoc(), @@ -7286,7 +7232,7 @@ static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } uint32_t Y; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Y)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y)) return; if (Y > 1024) { S.Diag(AL.getArgAsExpr(1)->getExprLoc(), @@ -7294,7 +7240,7 @@ static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } uint32_t Z; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(2), Z)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z)) return; if (Z > ZMax) { S.Diag(AL.getArgAsExpr(2)->getExprLoc(), @@ -7348,10 +7294,10 @@ static void handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } uint32_t SubComponent; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), SubComponent)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent)) return; uint32_t Component; - if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Component)) + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component)) return; QualType T = cast(D)->getType().getCanonicalType(); @@ -7602,7 +7548,7 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { 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)) { + if (!isFuncOrMethodForAttrSubject(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; @@ -7675,7 +7621,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // e) The attribute itself must either have no argument or one of the // valid interrupt types, see [MipsInterruptDocs]. - if (!isFunctionOrMethod(D)) { + if (!isFuncOrMethodForAttrSubject(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; @@ -7748,7 +7694,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // 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) || + if (!isFuncOrMethodForAttrSubject(D) || !hasFunctionProto(D) || + isInstanceMethod(D) || CXXMethodDecl::isStaticOverloadedOperator( cast(D)->getDeclName().getCXXOverloadedOperator())) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -7807,7 +7754,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { + if (!isFuncOrMethodForAttrSubject(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; @@ -7820,7 +7767,7 @@ static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { + if (!isFuncOrMethodForAttrSubject(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; @@ -7875,102 +7822,6 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { 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; - return; - } - - FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); -} - static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Warn about repeated attributes. @@ -8059,200 +7910,6 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } -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 @@ -8279,7 +7936,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, 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. @@ -9392,19 +9049,19 @@ 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); @@ -9419,13 +9076,13 @@ 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); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8ab429e2a136efecbc44c4a565cc1f5773e1856c..631fd4e354927f5cb665281c88d8f4a5739ffcea 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11547,12 +11547,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 { 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/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ded4f59833ac051fad2d9f0464f7d182a4e061a5..fb4154757775bc001db9d2a5758e2e344f7f3d9a 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(); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 6595abbcdda5b11e9c02df395ab077d574a2d33d..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); 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..9e614ae99f37d26c8cc5210cdaae147721544eeb 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -9,6 +9,9 @@ //===----------------------------------------------------------------------===// #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" @@ -16,6 +19,7 @@ #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 +294,296 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) << (AllowedStages.size() != 1) << join(StageStrings, ", "); } + +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/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/SemaMIPS.cpp b/clang/lib/Sema/SemaMIPS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df5328fbf6640473906303e505c4a7ea33145152 --- /dev/null +++ b/clang/lib/Sema/SemaMIPS.cpp @@ -0,0 +1,240 @@ +//===------ 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/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); +} + +} // 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/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 15239f4f35c39fdf4870afd90f8487e4d497319b..5b4d01860c0bd4b19df5aa440233cbc7d9857075 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -170,6 +170,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: @@ -246,6 +297,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; diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bab61e8fd54e8955b9433e1523883fb2324e1c8a..99528c2a4f1f44b8d3482e20a0228481116c2149 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3074,11 +3074,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 +7402,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 +7915,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)) @@ -23695,7 +23695,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; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6c5e8afbcfb6eec2d7b51e9be009e1e20bbef4f5..6c4ce1022ae274df0aa07b3d08a304c2b5ac2803 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10367,7 +10367,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( 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/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 39e9dbed0c3e0bc49591e792c35b7d27df8f3b5e..3e3ed77de710e5ac3184b009613feabbb65b7bb8 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()) @@ -5621,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, @@ -5691,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(); } } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index f9ec34163e656b08d59ce86aa334dbbf7018eeeb..8ec49fcf553d0e6397b460ecb390cfd21b61ddf8 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -589,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(); @@ -658,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, @@ -666,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. @@ -698,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); } @@ -718,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; @@ -4469,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 @@ -4477,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, @@ -4512,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; @@ -4554,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; } @@ -4594,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; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bb49aae2cb6663a11b4e9d0b415139f3b467f332..4c8eaf2d4ebf680cf1e3d7518d90c1a11719965b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -26,6 +26,7 @@ #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" @@ -563,7 +564,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 +608,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 +631,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 diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index ef0b6b701a52c58401284dc9237a5856ba311ce6..7cec82c7010280a73477cd97b6aafaab2b2677a0 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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); 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/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 765e6177d202d1c59c03a05b899e22bcb9af4347..efba99b85b0fb19d7ba6c12adce8aa34aad14a37 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4605,6 +4605,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, @@ -4612,11 +4613,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 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 e062d4f068a403a876cd72ffced8012b424dc291..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{{$}} @@ -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-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index f9e9ee9d35dde6989b5c0a43b80640f2fe029143..5da025c229ea3d80adf606514f75f132f81bff2f 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -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-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