diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 3ed5eb96eceb5..033ab804b165e 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/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index 4fd88ea81c84a..91e719c52d436 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -44,6 +44,8 @@ pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt # see https://github.com/llvm/llvm-project/pull/82393 and # https://discourse.llvm.org/t/rfc-future-of-windows-pre-commit-ci/76840/40 # for further information. +# We limit the number of parallel compile jobs to 24 control memory +# consumption and improve build reliability. cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_ENABLE_PROJECTS="${projects}" \ -G Ninja \ @@ -58,7 +60,9 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D MLIR_ENABLE_BINDINGS_PYTHON=ON \ -D CMAKE_EXE_LINKER_FLAGS="/MANIFEST:NO" \ -D CMAKE_MODULE_LINKER_FLAGS="/MANIFEST:NO" \ - -D CMAKE_SHARED_LINKER_FLAGS="/MANIFEST:NO" + -D CMAKE_SHARED_LINKER_FLAGS="/MANIFEST:NO" \ + -D LLVM_PARALLEL_COMPILE_JOBS=16 \ + -D LLVM_PARALLEL_LINK_JOBS=4 echo "--- ninja" # Targets are not escaped as they are passed as separate arguments. diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index a57ba28faf160..b47301851e29e 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/.github/workflows/restart-preempted-libcxx-jobs.yaml b/.github/workflows/restart-preempted-libcxx-jobs.yaml new file mode 100644 index 0000000000000..f8faaf25045bf --- /dev/null +++ b/.github/workflows/restart-preempted-libcxx-jobs.yaml @@ -0,0 +1,134 @@ +name: Restart Preempted Libc++ Workflow + +# The libc++ builders run on preemptable VMs, which can be shutdown at any time. +# This workflow identifies when a workflow run was canceled due to the VM being preempted, +# and restarts the workflow run. + +# We identify a canceled workflow run by checking the annotations of the check runs in the check suite, +# which should contain the message "The runner has received a shutdown signal." + +# Note: If a job is both preempted and also contains a non-preemption failure, we do not restart the workflow. + +on: + workflow_run: + workflows: [Build and Test libc\+\+] + types: + - completed + +permissions: + contents: read + +jobs: + restart: + if: github.repository_owner == 'llvm' && (github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'cancelled') + name: "Restart Job" + permissions: + statuses: read + checks: write + actions: write + runs-on: ubuntu-latest + steps: + - name: "Restart Job" + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 + with: + script: | + const failure_regex = /Process completed with exit code 1./ + const preemption_regex = /The runner has received a shutdown signal/ + + const wf_run = context.payload.workflow_run + core.notice(`Running on "${wf_run.display_title}" by @${wf_run.actor.login} (event: ${wf_run.event})\nWorkflow run URL: ${wf_run.html_url}`) + + + async function create_check_run(conclusion, message) { + // Create a check run on the given workflow run to indicate if + // we are restarting the workflow or not. + if (conclusion != 'success' && conclusion != 'skipped' && conclusion != 'neutral') { + core.setFailed('Invalid conclusion: ' + conclusion) + } + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'Restart Preempted Job', + head_sha: wf_run.head_sha, + status: 'completed', + conclusion: conclusion, + output: { + title: 'Restarted Preempted Job', + summary: message + } + }) + } + + console.log('Listing check runs for suite') + const check_suites = await github.rest.checks.listForSuite({ + owner: context.repo.owner, + repo: context.repo.repo, + check_suite_id: context.payload.workflow_run.check_suite_id, + per_page: 100 // FIXME: We don't have 100 check runs yet, but we should handle this better. + }) + + check_run_ids = []; + for (check_run of check_suites.data.check_runs) { + console.log('Checking check run: ' + check_run.id); + if (check_run.status != 'completed') { + console.log('Check run was not completed. Skipping.'); + continue; + } + if (check_run.conclusion != 'failure' && check_run.conclusion != 'cancelled') { + console.log('Check run had conclusion: ' + check_run.conclusion + '. Skipping.'); + continue; + } + check_run_ids.push(check_run.id); + } + + has_preempted_job = false; + + for (check_run_id of check_run_ids) { + console.log('Listing annotations for check run: ' + check_run_id); + + annotations = await github.rest.checks.listAnnotations({ + owner: context.repo.owner, + repo: context.repo.repo, + check_run_id: check_run_id + }) + + for (annotation of annotations.data) { + if (annotation.annotation_level != 'failure') { + continue; + } + + const preemption_match = annotation.message.match(preemption_regex); + + if (preemption_match != null) { + console.log('Found preemption message: ' + annotation.message); + has_preempted_job = true; + } + + const failure_match = annotation.message.match(failure_regex); + if (failure_match != null) { + // We only want to restart the workflow if all of the failures were due to preemption. + // We don't want to restart the workflow if there were other failures. + core.notice('Choosing not to rerun workflow because we found a non-preemption failure' + + 'Failure message: "' + annotation.message + '"'); + await create_check_run('skipped', 'Choosing not to rerun workflow because we found a non-preemption failure\n' + + 'Failure message: ' + annotation.message) + return; + } + } + } + + if (!has_preempted_job) { + core.notice('No preempted jobs found. Not restarting workflow.'); + await create_check_run('neutral', 'No preempted jobs found. Not restarting workflow.') + return; + } + + core.notice("Restarted workflow: " + context.payload.workflow_run.id); + await github.rest.actions.reRunWorkflowFailedJobs({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id + }) + await create_check_run('success', 'Restarted workflow run due to preempted job') + + diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index 1951ad5a2dc5e..8887d1f5d5bd4 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 0000000000000..d8829daf677b4 --- /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 bc95e2c4de3a1..a57b70714fe38 100644 --- a/bolt/include/bolt/Core/BinaryBasicBlock.h +++ b/bolt/include/bolt/Core/BinaryBasicBlock.h @@ -115,7 +115,7 @@ class BinaryBasicBlock { 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 @@ class BinaryBasicBlock { } /// 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 b685a99c79c14..6a13cbec69fee 100644 --- a/bolt/include/bolt/Core/FunctionLayout.h +++ b/bolt/include/bolt/Core/FunctionLayout.h @@ -213,7 +213,8 @@ class FunctionLayout { 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 64113bd026012..a55516d553979 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 @@ class RewriteInstance { 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 c897392f2a574..d13e28999a05c 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 73f4d5247d9ac..15e6127ad2e9e 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 87eba10354a37..38e080c9dd621 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 cf6b61ddd6031..9adbfdc5ff089 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 ab46503621e9a..8814ebbd10aa5 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 4b4913dd7a16c..e452e956c949e 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 182c13d370a39..bf77c0493a095 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 59fa15a876b50..9432240469c7b 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 aa608ecd97e8c..011e0c6ac8a0f 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-df-input-lowpc-ranges-other.s b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s new file mode 100644 index 0000000000000..c04fb521c75d3 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s @@ -0,0 +1,710 @@ +## clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-4 -gsplit-dwarf -fdebug-compilation-dir='.' +## __attribute__((always_inline)) +## int doStuffOther(int val) { +## if (val) +## ++val; +## return val; +## } +## __attribute__((always_inline)) +## int doStuffOther2(int val) { +## int foo = 3; +## return val + foo; +## } +## +## +## int mainOther(int argc, const char** argv) { +## return doStuffOther(argc) + doStuffOther2(argc);; +## } + + .text + .file "mainOther.cpp" + .section .text._Z12doStuffOtheri,"ax",@progbits + .globl _Z12doStuffOtheri # -- Begin function _Z12doStuffOtheri + .p2align 4, 0x90 + .type _Z12doStuffOtheri,@function +_Z12doStuffOtheri: # @_Z12doStuffOtheri +.Lfunc_begin0: + .file 1 "." "mainOther.cpp" + .loc 1 2 0 # mainOther.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 1 3 8 prologue_end # mainOther.cpp:3:8 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 1 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z12doStuffOtheri.__part.2 + jmp _Z12doStuffOtheri.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,1 +_Z12doStuffOtheri.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z12doStuffOtheri.__part.2 +.LBB_END0_1: + .size _Z12doStuffOtheri.__part.1, .LBB_END0_1-_Z12doStuffOtheri.__part.1 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits,unique,2 +_Z12doStuffOtheri.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 11 # mainOther.cpp:5:11 + movl -4(%rbp), %eax + .loc 1 5 4 epilogue_begin is_stmt 0 # mainOther.cpp:5:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z12doStuffOtheri.__part.2, .LBB_END0_2-_Z12doStuffOtheri.__part.2 + .cfi_endproc + .section .text._Z12doStuffOtheri,"ax",@progbits +.Lfunc_end0: + .size _Z12doStuffOtheri, .Lfunc_end0-_Z12doStuffOtheri + # -- End function + .section .text._Z13doStuffOther2i,"ax",@progbits + .globl _Z13doStuffOther2i # -- Begin function _Z13doStuffOther2i + .p2align 4, 0x90 + .type _Z13doStuffOther2i,@function +_Z13doStuffOther2i: # @_Z13doStuffOther2i +.Lfunc_begin1: + .loc 1 8 0 is_stmt 1 # mainOther.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp2: + .loc 1 9 8 prologue_end # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 1 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %eax + .loc 1 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %eax + .loc 1 10 4 epilogue_begin # mainOther.cpp:10:4 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z13doStuffOther2i, .Lfunc_end1-_Z13doStuffOther2i + # -- End function + .section .text._Z9mainOtheriPPKc,"ax",@progbits + .globl _Z9mainOtheriPPKc # -- Begin function _Z9mainOtheriPPKc + .p2align 4, 0x90 + .type _Z9mainOtheriPPKc,@function +_Z9mainOtheriPPKc: # @_Z9mainOtheriPPKc +.Lfunc_begin2: + .loc 1 14 0 is_stmt 1 # mainOther.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -16(%rbp) + movq %rsi, -24(%rbp) +.Ltmp3: + .loc 1 15 27 prologue_end # mainOther.cpp:15:27 + movl -16(%rbp), %eax + movl %eax, -12(%rbp) +.Ltmp4: + .loc 1 3 8 # mainOther.cpp:3:8 + cmpl $0, -12(%rbp) +.Ltmp5: + .loc 1 3 8 is_stmt 0 # mainOther.cpp:3:8 + je _Z9mainOtheriPPKc.__part.2 + jmp _Z9mainOtheriPPKc.__part.1 +.LBB_END2_0: + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,3 +_Z9mainOtheriPPKc.__part.1: # %if.then.i + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 6 is_stmt 1 # mainOther.cpp:4:6 + movl -12(%rbp), %eax + addl $1, %eax + movl %eax, -12(%rbp) + jmp _Z9mainOtheriPPKc.__part.2 +.LBB_END2_1: + .size _Z9mainOtheriPPKc.__part.1, .LBB_END2_1-_Z9mainOtheriPPKc.__part.1 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits,unique,4 +_Z9mainOtheriPPKc.__part.2: # %_Z12doStuffOtheri.exit + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 11 # mainOther.cpp:5:11 + movl -12(%rbp), %eax +.Ltmp6: + .loc 1 15 49 # mainOther.cpp:15:49 + movl -16(%rbp), %ecx + movl %ecx, -4(%rbp) +.Ltmp7: + .loc 1 9 8 # mainOther.cpp:9:8 + movl $3, -8(%rbp) + .loc 1 10 11 # mainOther.cpp:10:11 + movl -4(%rbp), %ecx + .loc 1 10 15 is_stmt 0 # mainOther.cpp:10:15 + addl -8(%rbp), %ecx +.Ltmp8: + .loc 1 15 33 is_stmt 1 # mainOther.cpp:15:33 + addl %ecx, %eax + .loc 1 15 6 epilogue_begin is_stmt 0 # mainOther.cpp:15:6 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END2_2: + .size _Z9mainOtheriPPKc.__part.2, .LBB_END2_2-_Z9mainOtheriPPKc.__part.2 + .cfi_endproc + .section .text._Z9mainOtheriPPKc,"ax",@progbits +.Lfunc_end2: + .size _Z9mainOtheriPPKc, .Lfunc_end2-_Z9mainOtheriPPKc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\262B" # DW_AT_GNU_ranges_base + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x29 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lskel_string0 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + .long .Lskel_string1 # DW_AT_GNU_dwo_name + .quad -1082921489565291703 # DW_AT_GNU_dwo_id + .long .debug_ranges # DW_AT_GNU_ranges_base + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges3 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_GNU_addr_base +.Ldebug_info_end0: + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad 0 + .quad 0 +.Ldebug_ranges1: + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 +.Ldebug_ranges2: + .quad .Ltmp4 + .quad .Lfunc_end2 + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .Ltmp6 + .quad 0 + .quad 0 +.Ldebug_ranges3: + .quad _Z12doStuffOtheri.__part.1 + .quad .LBB_END0_1 + .quad _Z12doStuffOtheri.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad _Z9mainOtheriPPKc.__part.1 + .quad .LBB_END2_1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 + .section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "." # string offset=0 +.Lskel_string1: + .asciz "mainOther.dwo" # string offset=2 + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "_Z12doStuffOtheri" # string offset=0 +.Linfo_string1: + .asciz "doStuffOther" # string offset=18 +.Linfo_string2: + .asciz "int" # string offset=31 +.Linfo_string3: + .asciz "val" # string offset=35 +.Linfo_string4: + .asciz "_Z13doStuffOther2i" # string offset=39 +.Linfo_string5: + .asciz "doStuffOther2" # string offset=58 +.Linfo_string6: + .asciz "foo" # string offset=72 +.Linfo_string7: + .asciz "_Z9mainOtheriPPKc" # string offset=76 +.Linfo_string8: + .asciz "mainOther" # string offset=94 +.Linfo_string9: + .asciz "argc" # string offset=104 +.Linfo_string10: + .asciz "argv" # string offset=109 +.Linfo_string11: + .asciz "char" # string offset=114 +.Linfo_string12: + .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" # string offset=119 +.Linfo_string13: + .asciz "mainOther.cpp" # string offset=223 +.Linfo_string14: + .asciz "mainOther.dwo" # string offset=237 + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .long 18 + .long 31 + .long 35 + .long 39 + .long 58 + .long 72 + .long 76 + .long 94 + .long 104 + .long 109 + .long 114 + .long 119 + .long 223 + .long 237 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0xde DW_TAG_compile_unit + .byte 12 # DW_AT_producer + .short 33 # DW_AT_language + .byte 13 # DW_AT_name + .byte 14 # DW_AT_GNU_dwo_name + .quad -1082921489565291703 # DW_AT_GNU_dwo_id + .byte 2 # Abbrev [2] 0x19:0x14 DW_TAG_subprogram + .long .Ldebug_ranges0-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long 74 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x24:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x2d:0x1d DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 97 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x39:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x41:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x4a:0x13 DW_TAG_subprogram + .byte 0 # DW_AT_linkage_name + .byte 1 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x54:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x5d:0x4 DW_TAG_base_type + .byte 2 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x61:0x1b DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x6b:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 9 # Abbrev [9] 0x73:0x8 DW_TAG_variable + .byte 6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x7c:0x59 DW_TAG_subprogram + .long .Ldebug_ranges1-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_linkage_name + .byte 8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 11 # Abbrev [11] 0x8b:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 112 + .byte 9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 11 # Abbrev [11] 0x96:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 104 + .byte 10 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 213 # DW_AT_type + .byte 12 # Abbrev [12] 0xa1:0x15 DW_TAG_inlined_subroutine + .long 74 # DW_AT_abstract_origin + .long .Ldebug_ranges2-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 14 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xad:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 13 # Abbrev [13] 0xb6:0x1e DW_TAG_inlined_subroutine + .long 97 # DW_AT_abstract_origin + .byte 7 # DW_AT_low_pc + .long .Ltmp8-.Ltmp7 # DW_AT_high_pc + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 35 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xc3:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0xcb:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 14 # Abbrev [14] 0xd5:0x5 DW_TAG_pointer_type + .long 218 # DW_AT_type + .byte 14 # Abbrev [14] 0xda:0x5 DW_TAG_pointer_type + .long 223 # DW_AT_type + .byte 15 # Abbrev [15] 0xdf:0x5 DW_TAG_const_type + .long 228 # DW_AT_type + .byte 8 # Abbrev [8] 0xe4:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\260B" # DW_AT_GNU_dwo_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 15 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_addr,"",@progbits +.Laddr_table_base0: + .quad _Z12doStuffOtheri.__part.1 + .quad _Z12doStuffOtheri.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + .quad _Z9mainOtheriPPKc.__part.1 + .quad _Z9mainOtheriPPKc.__part.2 + .quad .Lfunc_begin2 + .quad .Ltmp7 + .section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info +.LpubNames_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 74 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther" # External Name + .long 97 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuffOther2" # External Name + .long 124 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "mainOther" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_gnu_pubtypes,"",@progbits + .long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info +.LpubTypes_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 93 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "int" # External Name + .long 228 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "char" # External Name + .long 0 # End Mark +.LpubTypes_end0: + .ident "clang version 19.0.0git (git@github.com:llvm/llvm-project.git df542e1ed82bd4e5a9e345d3a3ae63a76893a0cf)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf4-subprogram-multiple-ranges-other.s b/bolt/test/X86/Inputs/dwarf4-subprogram-multiple-ranges-other.s new file mode 100644 index 0000000000000..0745b2f4cef83 --- /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 0000000000000..6586fc73ed8da --- /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 1f926c20c7ba8..03d6269031917 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 095ae92da0713..3c65051b833d7 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 68a0fbc8ff52c..93b02f4397cc8 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 8bbecc498ed75..71807510527f9 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 f3a3390e27cb9..526467f996b07 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 24cb635e13e98..f20aeb67725fc 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 8f65eaba891ec..3778891c8d916 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 dfdd1eea32333..cdaab1e2d7efa 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 0c64caaee8a50..231a77307ffef 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 9e7ed405afba9..f89fe4aaa474c 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 c88e4d0043b46..238347339f4e1 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 13611119beaf0..d5ac3548909e3 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 b1d05b83cb87c..820c00fa55086 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 3d6308d9e6f83..05ae4b609b199 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 5701d9e6dfd69..66f30036de8c1 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 e53863e22246d..0960020d74789 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 0d20654178543..6735b382025d8 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 635d560ae7533..d91c9bb47fb14 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 8b2fe512f392c..c325aaf1ad8b1 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 89aa4f78d52d1..427dcdbabf375 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 0a0b7fcff4ce9..55ba1fe316a91 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 82db6700079f9..28fcb6686e0a2 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 0d25aaef274a0..4350bd9ec1815 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 cbd5ce9dae0e5..791872a2b4f89 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 d5ba74fb60166..f14d77285c485 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 6126e9628a31a..4219eb3f9205e 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 faa4dc418f3b1..96777a808c4ea 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 e609440696db4..555887a067589 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 e73960e7251e6..74c9491d95d36 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 581ce2cffcfd4..6bcf8892ed0a8 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 d373b62ee6186..601c0c58ec0a6 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 e00958d106141..fa72c798516ba 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 5173c890f66ab..b5aee42f337f9 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 95c1c747a3d04..9ba8264eac071 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 6ef4fb97e8caa..57c75e282421a 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 91b3e9e4cf092..b690623b70d83 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 32bffcba4bec0..0553a217a12c1 100644 --- a/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test +++ b/bolt/test/X86/dwarf4-df-inlined-subroutine-lowpc-0.test @@ -9,8 +9,8 @@ ; RUN: llvm-dwarfdump --debug-info --verbose --show-form main.dwo.dwo >> log.txt ; RUN: cat log.txt | FileCheck -check-prefix=BOLT-MAIN %s -; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_low_pc is 0, -; and split dwarf is enabled. +;; Tests whether BOLT handles correctly DW_TAG_inlined_subroutine when DW_AT_low_pc is 0, +;; and split dwarf is enabled. ; BOLT-MAIN: 0x ; BOLT-MAIN: 0x diff --git a/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test b/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test new file mode 100644 index 0000000000000..c9abd02bbb7d9 --- /dev/null +++ b/bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test @@ -0,0 +1,97 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-other.s \ +; RUN: -split-dwarf-file=mainOther.dwo -o other.o +; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o other.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt +; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s + +;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges. + +; BOLT: .debug_ranges +; BOLT-NEXT: 00000000 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000090 [[#%.16x,ADDR1:]] [[#%.16x,ADDRB1:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR2:]] [[#%.16x,ADDRB2:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR3:]] [[#%.16x,ADDRB3:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR4:]] [[#%.16x,ADDRB4:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR5:]] [[#%.16x,ADDRB5:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR6:]] [[#%.16x,ADDRB6:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR7:]] [[#%.16x,ADDRB7:]] +; BOLT-NEXT: 00000090 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000110 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000150 +; BOLT-NEXT: 00000190 [[#%.16x,ADDR8:]] [[#%.16x,ADDRB8:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR9:]] [[#%.16x,ADDRB9:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR10:]] [[#%.16x,ADDRB10:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR11:]] [[#%.16x,ADDRB11:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR12:]] [[#%.16x,ADDRB12:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR13:]] [[#%.16x,ADDRB13:]] +; BOLT-NEXT: 00000190 [[#%.16x,ADDR14:]] [[#%.16x,ADDRB14:]] +; BOLT-NEXT: 00000190 + +; BOLT: DW_TAG_compile_unit +; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "main.dwo.dwo") +; BOLT-NEXT: DW_AT_GNU_dwo_id +; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000010) +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000090 +; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDRB1]]) +; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDRB2]]) +; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDRB3]]) +; BOLT-NEXT: [0x[[#ADDR4]], 0x[[#ADDRB4]]) +; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDRB5]]) +; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDRB6]]) +; BOLT-NEXT: [0x[[#ADDR7]], 0x[[#ADDRB7]]) +; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) + +; BOLT: DW_TAG_compile_unit +; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "mainOther.dwo.dwo") +; BOLT-NEXT: DW_AT_GNU_dwo_id +; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000110) +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000190 +; BOLT-NEXT: [0x[[#ADDR8]], 0x[[#ADDRB8]]) +; BOLT-NEXT: [0x[[#ADDR9]], 0x[[#ADDRB9]]) +; BOLT-NEXT: [0x[[#ADDR10]], 0x[[#ADDRB10]]) +; BOLT-NEXT: [0x[[#ADDR11]], 0x[[#ADDRB11]]) +; BOLT-NEXT: [0x[[#ADDR12]], 0x[[#ADDRB12]]) +; BOLT-NEXT: [0x[[#ADDR13]], 0x[[#ADDRB13]]) +; BOLT-NEXT: [0x[[#ADDR14]], 0x[[#ADDRB14]]) +; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000018) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 diff --git a/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test b/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test index fa116206950bb..276bea4ba0c1c 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 e5274cb829bc7..338aa5444cb51 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 2e861c7ea504b..2ff0b5dd36580 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 8deed6ab0939f..065ec7c7ac2c2 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 8fd2f19504373..d08b596ec8dd1 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 40eae605b6a8e..54382142afc8f 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 c6b8671deb98a..8077cc0808238 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 b326a6386ba92..673e86bb1533a 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 51293ce560088..eaf7580917016 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 8943ce851a7e5..640598978be7c 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 4cf0d3d0e2558..494fe43cf105f 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 9d27c9cd9ff87..1bbb12ef3139d 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 b9cbf513bb26f..3cec66132e9ef 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 0ba97acb4f9e6..94e112101f9ba 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 584e67b1c79fe..e7fc0dae3e440 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 753fad06eb069..fc6d8d324b959 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 e3734492d8f4c..c9b12574caa3a 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 0000000000000..c9ade995b7087 --- /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 63db886c91373..5efe07a280575 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 3e7e765f98b19..9c121e5acc4aa 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 0dcbbcdfcce3f..c02d2e4e6d445 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 a5d2ec8df20a6..a253f22836090 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 9ece6db3f00a0..1eb42683e40ee 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 c407ecadd1119..3cfe8a3b74f6e 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 d717b4b3b47dd..7ea804e95aa3f 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 bc747e0657b54..6b00ce0fdf805 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 b04e30bcf5329..761a4da696217 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 ec03a7bf8ad4a..dc7773dc053d9 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 d194808059369..e78b68680d6cc 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 6042bbee8948c..dbf6aef20a9cb 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 20dd9083169ac..15f7ead42dc13 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 5b1cdba712a9b..732e0d61d6726 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 753858d0b32e9..6ce0467a840b8 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 ea717a5e0888d..27614fe08634d 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 f266caec7af3b..e31d1e0a6351b 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 62f75c2c75532..01a9ed9d85e53 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 ea5b28a2e88f6..4461f5b35ff04 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 deaeea0366908..c6ad5afa305c2 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 6e9bd0502d8b6..3132208475bd7 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 4ecc66f52ff84..b9f38d42aa923 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 1867f49a52045..2123353044c37 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 12269287ef132..13272cc1c3c4d 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 1f78da2022b8c..b466f87d95e5e 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 036d4c9168ee5..754f05dc96328 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 1a59844814cda..1c7843e1f210f 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 17663a7f72df4..10ad6ed404f1c 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 c283ec02387fe..2da0bcca89b2a 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 6eaad4cd06d3b..9be540352005d 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 274451c4546ac..ff0f6990aaac0 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 8afbe9e747d24..070648c042c1d 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 69758505c2a61..b6e9f60bbfc70 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 b59a3f056b226..5381039ffa375 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 f8f33b321a7d4..338a476e46f3b 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 bccc92d3de84d..c9d3913a1933c 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 18fe7daa4ad48..a770e40260dde 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 00e15101f8531..6cb198515e0ff 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 1e8183b7527df..6a8d81d2d08ee 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 27b7a2b38d97a..ea73d7601b253 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 d4b8ab15fd0f5..3178c11a67069 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 aba62ea984541..6cdc345b435e1 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 6429ccd86b325..b88e69e86eb70 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 7ef53f6813814..873512aad5e8d 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 481ff41c301f3..647d498956195 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 737aae91608ba..5a83615cac031 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 987a9fa8cefad..e9ef99ef5b945 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 0756d537b25a5..d8492298a1604 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 6fc0825cd2fae..2cfe5e26bd4cd 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 414f3d6954947..ec2b8f7084c78 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 0000000000000..bcf63fe6a0d8c --- /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 9fedd57b0c6ff..80bf8f8990407 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 9f8f895ed5f16..21944eba4c92f 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 f53780eeb5b03..8ffa73c8c9dff 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 f5c399a944a91..2ede02f3b76fb 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 98330558a573b..17cdc7643bae5 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 9278c23ef5107..2345cac2fde96 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 feeb75da93a85..5ff4ba4286dbf 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 6d771df4b4ff8..b12942e93575d 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 3a4fa2f0eac13..a617ab653c638 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 2055ca603043a..61782f7136072 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 8cb87ed821e0e..fafaa62ccb081 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 312d1d47429f5..b883ed1a076bb 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 3d681208d3e95..94bd2961c9518 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 32d1f5a98b64a..9a5e5f83bc3f2 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 ac2f705c64e94..c03e2f5d46c83 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 fe84e8c037447..4b0c9e44080f7 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 5cedc833b0893..b8a6497c755d4 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 87a5ec142af25..f9ae7aebe7867 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 c3a62842b8756..ad15d41bc5b7a 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 3c863833449fa..c5106db5a5389 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 12e4fb92adcc0..94d7a91f2c7fd 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 039ff5c41d3d6..81cff9a32fbbd 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 bbc11e7d33171..8d2cb5e62a97b 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 5a87bdde9535e..9f6ef396bb159 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 800bed27243d1..c08376c91634c 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 f36e3ed6f7220..31af3db7d4a82 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 d13c828f605c3..99e5b29221409 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 c393f1dac8647..4dc0408c6d12f 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 0e1cca5c9bfe6..67f0a452bf34c 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 df12986efc42d..1ce81872326c1 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 785064df89c9c..99a4f2ea2ac99 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 eeb76d15aec44..dcb1ce5ab1567 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 6f9bc72d6e10d..2a97febfd23cd 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 bafd0912cf4a4..55704a884d208 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 92f4b9a14f0f4..a98be11573416 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 cc6107f478127..0d058fec8af48 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 c472b6bbf9c6a..22b34cef1bc4d 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 4195b97aac501..c8b6eda2278b9 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 4e0f9b16818d3..290e585fc1b75 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 5b989d18018b0..f1474326db3b6 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 ed3c77d49b6cc..c84551a0e2132 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 59c0af252b07b..09bda932121b3 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 9d33c0d5e7271..32696683fb5ea 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 3d24e1aad139a..c614e7b0f33e6 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 b039962643d40..d4dca825502ee 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 947d25cb6e8c4..ea9928d191884 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 0cbb5b625d007..42109db87d9ee 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 cb241110cf70d..4957375809840 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 24fde1004b007..51c8fcdb32eaa 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 41738e196b5d3..2d2a423fb85b6 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 870d9f880e286..978052e35007a 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 17050e48a95f9..b12b460d9d7b3 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 a2638e1388c9a..309e5c1d04f9c 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 523bdf25f5217..fa0c8dd68ae45 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 bebb697122f49..999c68566c949 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 4a725412dd616..bf31af342dc61 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 0bd44720f1b7a..90252f9ff68da 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 fa4af8287494f..d7cfad5f954be 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 e0b6ca0645e19..b43442ca9ea95 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 f4a8865b1f9a4..378abc3825246 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 308b97e30bb56..4d5d7bc818dd7 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 90c402b2234d7..5c9fb5ed1a757 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 d303c4255ae7e..c2f7a71b9e3e5 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 45e9f428e91d6..83223ace26b7e 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 8018ad75e5d69..4617331fb7613 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 1b581df237490..fb3aff8529f8c 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 0e235564dc3bd..8b2f58f625075 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 69c8c45428444..d821389a459fb 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 92aca5110059f..21a602b6729ae 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 eeefbd8ee4e6f..87a3c0655533d 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 db911ad0c0ebf..dfe21ef967ef3 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 2e5918e857e62..cbc2953d5db0a 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 ed9a206dec41f..6b5213ba19853 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 3fdd5f5e38fe0..343dd89f75fca 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 57b43cf4b6623..b3813ad86b46a 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 db31696ebd6db..c4860826bea5e 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 4a81b369c9766..c6e5aed34419f 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 2a5db3685e526..abad44e618003 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 9e1dcd54a617e..a21ea99c37efa 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 576fa8fcc3943..1d26b6e48e6fc 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 1767db2978d1f..8581d7e0c0f7b 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 4629a2cf9b957..df50a7fbe0305 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 1f51ba2e375e8..0b21e1b2b5358 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 259c301864002..a87c52cccb0fc 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 caebe59ed0865..52c816ccd9005 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 a3ac643ee1376..499dcaf4ced4c 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 639c800a795b1..634a45b3f2f10 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 a92e6731dffe6..12fe69110b260 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 71a172bb5f4a4..aae140418401f 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 dda27891443f2..681f14f1e533e 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 de9a4f1080656..5bed619e82a96 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 d12ac0a0f6f6c..e288160da1521 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 6e05129340a0f..5291f64b1c461 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 c3890c0337dd7..8021cfacd5433 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 acc49dc348340..de77dbcdae07d 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 ced59aea7a4c4..71407da548b7a 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 03211b399ba67..c050aa8ddb85e 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 ed50cc5227d85..9867f74fa3444 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 5e9efc87fa2f2..431851d12190f 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 7ce6d61a738b5..ab4fcf10f7a3c 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 83b69bd25ab92..f00b04d255c08 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 454de7e1b30b7..2d56167286c36 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 201e999907362..1a96f128e0f7c 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 63b70813c8851..3939b5cd338c6 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 5df4f3da04214..0b8668a842ed4 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 5684da4226be6..6d0a26823fe52 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 1f3522bce213c..fa381dbeb7b0f 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 fadc5590ea86f..2f69fdbcfe39d 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 f7b056e2ddb0e..cd80d96744ddc 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 c329c553813d2..fff67abbcea02 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 eb63ab37b4132..fa69691a590dc 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 1725a08577e34..df94ff08c8dac 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 5a9d932bc1af2..e5c9faa97bb49 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 4f4d84e49b133..8aa5f15d5ccfb 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 34993eb330cbd..3dd4251f7078f 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 e3de8335238d9..0650e9ec1c7ab 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 0ce2576ee401c..7c833c09bbf09 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 2c436d708df82..41216d81aa4b0 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 e5383b5235159..7656fda44d8d4 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 361f4ea94f2a5..06afff976e4a8 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 19307b4cdcbe3..bbc1b47b97ae6 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp @@ -150,6 +150,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( cxxMemberCallExpr( + argumentCountIs(0), on(expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), hasType(references(ValidContainer)))) @@ -163,7 +164,8 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { this); Finder->addMatcher( - callExpr(has(cxxDependentScopeMemberExpr( + callExpr(argumentCountIs(0), + has(cxxDependentScopeMemberExpr( hasObjectExpression( expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index c3208392df156..828f13805a698 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -1414,13 +1414,21 @@ IdentifierNamingCheck::getDiagInfo(const NamingCheckId &ID, }}; } +StringRef IdentifierNamingCheck::getRealFileName(StringRef FileName) const { + auto Iter = RealFileNameCache.try_emplace(FileName); + SmallString<256U> &RealFileName = Iter.first->getValue(); + if (!Iter.second) + return RealFileName; + llvm::sys::fs::real_path(FileName, RealFileName); + return RealFileName; +} + const IdentifierNamingCheck::FileStyle & IdentifierNamingCheck::getStyleForFile(StringRef FileName) const { if (!GetConfigPerFile) return *MainFileStyle; - SmallString<128> RealFileName; - llvm::sys::fs::real_path(FileName, RealFileName); + StringRef RealFileName = getRealFileName(FileName); StringRef Parent = llvm::sys::path::parent_path(RealFileName); auto Iter = NamingStylesCache.find(Parent); if (Iter != NamingStylesCache.end()) diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h index 27c8e4bc768c4..646ec0eac8dd1 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h @@ -205,6 +205,7 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { const NamingCheckFailure &Failure) const override; const FileStyle &getStyleForFile(StringRef FileName) const; + StringRef getRealFileName(StringRef FileName) const; /// Find the style kind of a field in an anonymous record. StyleKind findStyleKindForAnonField( @@ -222,6 +223,7 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { /// Stores the style options as a vector, indexed by the specified \ref /// StyleKind, for a given directory. mutable llvm::StringMap NamingStylesCache; + mutable llvm::StringMap> RealFileNameCache; FileStyle *MainFileStyle; ClangTidyContext *Context; const bool GetConfigPerFile; diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c587..41143b9ebc8d2 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 5bb2eb4a9f803..f32f674443ffe 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 7fa61108c78a0..f3e51a9b6dbc4 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 ce09af819247a..3e9b6a07d3b32 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -169,6 +169,10 @@ class Parser { 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 8e48f546d94e7..01b47679790f1 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 624e2116be7da..a01146d14e3c1 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 3ff759415f7c8..2bd1fbcad2ada 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 f0ffc429c0ca9..4ecfdf0184ab4 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 44a6647d4c0a8..10d67dead342c 100644 --- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp @@ -278,6 +278,21 @@ TEST(ParseYAML, IncludesIgnoreHeader) { 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 142310837bd9c..7027232460354 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 3e3195f6f6813..4f674d1a4d556 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/docs/clang-tidy/checks/readability/identifier-length.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst index 44d97f7b363bf..271970c292c8f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst @@ -28,10 +28,7 @@ The following options are described below: .. code-block:: c++ - int doubler(int x) // warns that x is too short - { - return 2 * x; - } + int i = 42; // warns that 'i' is too short This check does not have any fix suggestions in the general case since variable names have semantic value. @@ -50,7 +47,10 @@ The following options are described below: .. code-block:: c++ - int i = 42; // warns that 'i' is too short + int doubler(int x) // warns that x is too short + { + return 2 * x; + } This check does not have any fix suggestions in the general case since variable names have semantic value. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp index 84bdbd58b85e9..ecaf97fa348cc 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 63842d42bc208..477f720b193fb 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/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 1a7d0e6a05e31..677dac25df68e 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1799,8 +1799,8 @@ the configuration (without a prefix: ``Auto``). Never merge functions into a single line. * ``SFS_InlineOnly`` (in configuration: ``InlineOnly``) - Only merge functions defined inside a class. Same as "inline", - except it does not implies "empty": i.e. top level empty functions + Only merge functions defined inside a class. Same as ``inline``, + except it does not implies ``empty``: i.e. top level empty functions are not merged either. .. code-block:: c++ @@ -1825,7 +1825,7 @@ the configuration (without a prefix: ``Auto``). } * ``SFS_Inline`` (in configuration: ``Inline``) - Only merge functions defined inside a class. Implies "empty". + Only merge functions defined inside a class. Implies ``empty``. .. code-block:: c++ @@ -2042,7 +2042,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - AttributeMacros: ['__capability', '__output', '__unused'] + AttributeMacros: [__capability, __output, __unused] .. _BinPackArguments: @@ -3802,7 +3802,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - ForEachMacros: ['RANGES_FOR', 'FOREACH'] + ForEachMacros: [RANGES_FOR, FOREACH] For example: BOOST_FOREACH. @@ -3825,7 +3825,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - IfMacros: ['IF'] + IfMacros: [IF] For example: `KJ_IF_MAYBE `_ @@ -4374,7 +4374,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - JavaImportGroups: ['com.example', 'com', 'org'] + JavaImportGroups: [com.example, com, org] .. code-block:: java @@ -4438,7 +4438,7 @@ the configuration (without a prefix: ``Auto``). VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, - } from 'some/module.js' + } from "some/module.js" false: import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" @@ -5088,7 +5088,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - QualifierOrder: ['inline', 'static', 'type', 'const'] + QualifierOrder: [inline, static, type, const] .. code-block:: c++ @@ -5117,16 +5117,16 @@ the configuration (without a prefix: ``Auto``). .. note:: - it MUST contain 'type'. + It must contain ``type``. - Items to the left of 'type' will be placed to the left of the type and - aligned in the order supplied. Items to the right of 'type' will be + Items to the left of ``type`` will be placed to the left of the type and + aligned in the order supplied. Items to the right of ``type`` will be placed to the right of the type and aligned in the order supplied. .. code-block:: yaml - QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ] + QualifierOrder: [inline, static, type, const, volatile] .. _RawStringFormats: @@ -5138,10 +5138,10 @@ the configuration (without a prefix: ``Auto``). name will be reformatted assuming the specified language based on the style for that language defined in the .clang-format file. If no style has been defined in the .clang-format file for the specific language, a - predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not - found, the formatting is based on llvm style. A matching delimiter takes - precedence over a matching enclosing function name for determining the - language of the raw string contents. + predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is + not found, the formatting is based on ``LLVM`` style. A matching delimiter + takes precedence over a matching enclosing function name for determining + the language of the raw string contents. If a canonical delimiter is specified, occurrences of other delimiters for the same language will be updated to the canonical if possible. @@ -5156,17 +5156,17 @@ the configuration (without a prefix: ``Auto``). RawStringFormats: - Language: TextProto Delimiters: - - 'pb' - - 'proto' + - pb + - proto EnclosingFunctions: - - 'PARSE_TEXT_PROTO' + - PARSE_TEXT_PROTO BasedOnStyle: google - Language: Cpp Delimiters: - - 'cc' - - 'cpp' - BasedOnStyle: llvm - CanonicalDelimiter: 'cc' + - cc + - cpp + BasedOnStyle: LLVM + CanonicalDelimiter: cc .. _ReferenceAlignment: @@ -5533,7 +5533,7 @@ the configuration (without a prefix: ``Auto``). This determines the maximum length of short namespaces by counting unwrapped lines (i.e. containing neither opening nor closing - namespace brace) and makes "FixNamespaceComments" omit adding + namespace brace) and makes ``FixNamespaceComments`` omit adding end comments for those. .. code-block:: c++ @@ -5645,7 +5645,7 @@ the configuration (without a prefix: ``Auto``). * ``SUD_Lexicographic`` (in configuration: ``Lexicographic``) Using declarations are sorted in the order defined as follows: - Split the strings by "::" and discard any initial empty strings. Sort + Split the strings by ``::`` and discard any initial empty strings. Sort the lists of names lexicographically, and within those groups, names are in case-insensitive lexicographic order. @@ -5659,7 +5659,7 @@ the configuration (without a prefix: ``Auto``). * ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``) Using declarations are sorted in the order defined as follows: - Split the strings by "::" and discard any initial empty strings. The + Split the strings by ``::`` and discard any initial empty strings. The last element of each list is a non-namespace name; all others are namespace names. Sort the lists of names lexicographically, where the sort order of individual names is that all non-namespace names come @@ -5699,7 +5699,7 @@ the configuration (without a prefix: ``Auto``). .. _SpaceAfterTemplateKeyword: **SpaceAfterTemplateKeyword** (``Boolean``) :versionbadge:`clang-format 4` :ref:`¶ ` - If ``true``, a space will be inserted after the 'template' keyword. + If ``true``, a space will be inserted after the ``template`` keyword. .. code-block:: c++ @@ -5860,7 +5860,7 @@ the configuration (without a prefix: ``Auto``). * ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``) Put a space before opening parentheses only if the parentheses are not - empty i.e. '()' + empty. .. code-block:: c++ @@ -6245,7 +6245,7 @@ the configuration (without a prefix: ``Auto``). true: false: x = ( int32 )y vs. x = (int32)y - * ``bool InEmptyParentheses`` Put a space in parentheses only if the parentheses are empty i.e. '()' + * ``bool InEmptyParentheses`` Insert a space in empty parentheses, i.e. ``()``. .. code-block:: c++ @@ -6409,10 +6409,9 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml TableGenBreakInsideDAGArg: BreakAll - TableGenBreakingDAGArgOperators: ['ins', 'outs'] - + TableGenBreakingDAGArgOperators: [ins, outs] makes the line break only occurs inside DAGArgs beginning with the - specified identifiers 'ins' and 'outs'. + specified identifiers ``ins`` and ``outs``. .. code-block:: c++ @@ -6450,7 +6449,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - TypenameMacros: ['STACK_OF', 'LIST'] + TypenameMacros: [STACK_OF, LIST] For example: OpenSSL STACK_OF, BSD LIST_ENTRY. @@ -6518,7 +6517,7 @@ the configuration (without a prefix: ``Auto``). .. code-block:: yaml - WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE'] + WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] For example: BOOST_PP_STRINGIZE diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst index b3e2b870ae5f9..3d21e37784b36 100644 --- a/clang/docs/InternalsManual.rst +++ b/clang/docs/InternalsManual.rst @@ -123,6 +123,44 @@ severe that error recovery won't be able to recover sensibly from them (thus spewing a ton of bogus errors). One example of this class of error are failure to ``#include`` a file. +Diagnostic Wording +^^^^^^^^^^^^^^^^^^ +The wording used for a diagnostic is critical because it is the only way for a +user to know how to correct their code. Use the following suggestions when +wording a diagnostic. + +* Diagnostics in Clang do not start with a capital letter and do not end with + punctuation. + + * This does not apply to proper nouns like ``Clang`` or ``OpenMP``, to + acronyms like ``GCC`` or ``ARC``, or to language standards like ``C23`` + or ``C++17``. + * A trailing question mark is allowed. e.g., ``unknown identifier %0; did + you mean %1?``. + +* Appropriately capitalize proper nouns like ``Clang``, ``OpenCL``, ``GCC``, + ``Objective-C``, etc and language standard versions like ``C11`` or ``C++11``. +* The wording should be succinct. If necessary, use a semicolon to combine + sentence fragments instead of using complete sentences. e.g., prefer wording + like ``'%0' is deprecated; it will be removed in a future release of Clang`` + over wording like ``'%0' is deprecated. It will be removed in a future release + of Clang``. +* The wording should be actionable and avoid using standards terms or grammar + productions that a new user would not be familiar with. e.g., prefer wording + like ``missing semicolon`` over wording like ``syntax error`` (which is not + actionable) or ``expected unqualified-id`` (which uses standards terminology). +* The wording should clearly explain what is wrong with the code rather than + restating what the code does. e.g., prefer wording like ``type %0 requires a + value in the range %1 to %2`` over wording like ``%0 is invalid``. +* The wording should have enough contextual information to help the user + identify the issue in a complex expression. e.g., prefer wording like + ``both sides of the %0 binary operator are identical`` over wording like + ``identical operands to binary operator``. +* Use single quotes to denote syntactic constructs or command line arguments + named in a diagnostic message. e.g., prefer wording like ``'this' pointer + cannot be null in well-defined C++ code`` over wording like ``this pointer + cannot be null in well-defined C++ code``. + The Format String ^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 182f8b5824258..0c700d23257bf 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 ------------------ @@ -541,6 +546,9 @@ Improvements to Clang's diagnostics - Clang emits a ``-Wparentheses`` warning for expressions with consecutive comparisons like ``x < y < z``. Fixes #GH20456. +- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source. + Fixes #GH93369. + Improvements to Clang's time-trace ---------------------------------- @@ -629,6 +637,9 @@ Bug Fixes in This Version - ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for zero-sized arrays. Fixes (#GH54705). +- Correctly reject declarations where a statement is required in C. + Fixes #GH92775 + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -802,12 +813,24 @@ Bug Fixes to C++ Support - Fixed a regression introduced in Clang 18 causing a static function overloading a non-static function with the same parameters not to be diagnosed. (Fixes #GH93456). - Clang now diagnoses unexpanded parameter packs in attributes. (Fixes #GH93269). +- Clang now allows ``@$``` in raw string literals. Fixes (#GH93130). +- Fix an assertion failure when checking invalid ``this`` usage in the wrong context. (Fixes #GH91536). +- Clang no longer models dependent NTTP arguments as ``TemplateParamObjectDecl`` s. Fixes (#GH84052). +- Fix incorrect merging of modules which contain using declarations which shadow + other declarations. This could manifest as ODR checker false positives. + Fixes (`#80252 `_) +- Fix a regression introduced in Clang 18 causing incorrect overload resolution in the presence of functions only + differering by their constraints when only one of these function was variadic. +- Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625). +- Fixed a type constraint substitution issue involving a generic lambda expression. (#GH93821) 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 80ba70f67126f..f954857b0235a 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 3a31708a1e9de..bbc31832b9c3c 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 4bbb4380cdd7f..99093aa17972c 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/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index b706864798baa..04daf511f5871 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -31,6 +31,8 @@ class OpenACCConstructStmt : public Stmt { /// The location of the directive statement, from the '#' to the last token of /// the directive. SourceRange Range; + /// The location of the directive name. + SourceLocation DirectiveLoc; /// The list of clauses. This is stored here as an ArrayRef, as this is the /// most convienient place to access the list, however the list itself should @@ -39,8 +41,9 @@ class OpenACCConstructStmt : public Stmt { protected: OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K, - SourceLocation Start, SourceLocation End) - : Stmt(SC), Kind(K), Range(Start, End) {} + SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End) + : Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {} // Used only for initialization, the leaf class can initialize this to // trailing storage. @@ -59,6 +62,7 @@ class OpenACCConstructStmt : public Stmt { SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } + SourceLocation getDirectiveLoc() const { return DirectiveLoc; } ArrayRef clauses() const { return Clauses; } child_range children() { @@ -81,9 +85,11 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt { protected: OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K, - SourceLocation Start, SourceLocation End, - Stmt *AssocStmt) - : OpenACCConstructStmt(SC, K, Start, End), AssociatedStmt(AssocStmt) {} + SourceLocation Start, + SourceLocation DirectiveLoc, + SourceLocation End, Stmt *AssocStmt) + : OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End), + AssociatedStmt(AssocStmt) {} void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; } Stmt *getAssociatedStmt() { return AssociatedStmt; } @@ -126,10 +132,10 @@ class OpenACCComputeConstruct final friend class ASTStmtReader; friend class ASTContext; OpenACCComputeConstruct(unsigned NumClauses) - : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, - OpenACCDirectiveKind::Invalid, - SourceLocation{}, SourceLocation{}, - /*AssociatedStmt=*/nullptr) { + : OpenACCAssociatedStmtConstruct( + OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid, + SourceLocation{}, SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { // We cannot send the TrailingObjects storage to the base class (which holds // a reference to the data) until it is constructed, so we have to set it // separately here. @@ -141,11 +147,11 @@ class OpenACCComputeConstruct final } OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start, - SourceLocation End, + SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start, - End, StructuredBlock) { + DirectiveLoc, End, StructuredBlock) { assert(isOpenACCComputeDirectiveKind(K) && "Only parallel, serial, and kernels constructs should be " "represented by this type"); @@ -169,8 +175,8 @@ class OpenACCComputeConstruct final unsigned NumClauses); static OpenACCComputeConstruct * Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, - SourceLocation EndLoc, ArrayRef Clauses, - Stmt *StructuredBlock); + SourceLocation DirectiveLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *StructuredBlock); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index b7732e54ba107..7aedc086ab7d0 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -332,7 +332,7 @@ class TemplateName { /// 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 @@ class TemplateName { 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 1fede6e462e92..caa33abd99e47 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -213,6 +213,9 @@ class TextNodeDumper 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 e59cccccdd369..2665b7353ca4a 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) @@ -2025,9 +2023,12 @@ def Convergent : InheritableAttr { def NoInline : DeclOrStmtAttr { let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">, CXX11<"clang", "noinline">, C23<"clang", "noinline">, + CXX11<"msvc", "noinline">, C23<"msvc", "noinline">, Declspec<"noinline">]; - let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">, - C23<"clang", "noinline">]>]; + let Accessors = [Accessor<"isStmtNoInline", [CXX11<"clang", "noinline">, + C23<"clang", "noinline">, + CXX11<"msvc", "noinline">, + C23<"msvc", "noinline">]>]; let Documentation = [NoInlineDocs]; let Subjects = SubjectList<[Function, Stmt], WarnDiag, "functions and statements">; @@ -4477,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/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index fd8c1b480d6da..4e48ff48b60f5 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -135,6 +135,10 @@ TARGET_BUILTIN(__builtin_wasm_min_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_pmin_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_pmax_f64x2, "V2dV2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_max_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_pmin_f16x8, "V8hV8hV8h", "nc", "half-precision") +TARGET_BUILTIN(__builtin_wasm_pmax_f16x8, "V8hV8hV8h", "nc", "half-precision") TARGET_BUILTIN(__builtin_wasm_ceil_f32x4, "V4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_floor_f32x4, "V4fV4f", "nc", "simd128") diff --git a/clang/include/clang/Basic/CharInfo.h b/clang/include/clang/Basic/CharInfo.h index d807955311828..d71857e8e5dcc 100644 --- a/clang/include/clang/Basic/CharInfo.h +++ b/clang/include/clang/Basic/CharInfo.h @@ -28,8 +28,7 @@ namespace charinfo { CHAR_LOWER = 0x0040, // a-z CHAR_UNDER = 0x0080, // _ CHAR_PERIOD = 0x0100, // . - CHAR_RAWDEL = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"' - CHAR_PUNCT = 0x0400 // `$@() + CHAR_PUNCT = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"'`$@() }; enum { @@ -152,7 +151,7 @@ LLVM_READONLY inline bool isHexDigit(unsigned char c) { /// Note that '_' is both a punctuation character and an identifier character! LLVM_READONLY inline bool isPunctuation(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0; + return (InfoTable[c] & (CHAR_UNDER | CHAR_PERIOD | CHAR_PUNCT)) != 0; } /// Return true if this character is an ASCII printable character; that is, a @@ -160,8 +159,8 @@ LLVM_READONLY inline bool isPunctuation(unsigned char c) { /// terminal. LLVM_READONLY inline bool isPrintable(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT| - CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0; + return (InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_PERIOD | CHAR_PUNCT | + CHAR_DIGIT | CHAR_UNDER | CHAR_SPACE)) != 0; } /// Return true if this is the body character of a C preprocessing number, @@ -175,8 +174,9 @@ LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) { /// Return true if this is the body character of a C++ raw string delimiter. LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) { using namespace charinfo; - return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD| - CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0; + return (InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_PERIOD | CHAR_DIGIT | + CHAR_UNDER | CHAR_PUNCT)) != 0 && + c != '(' && c != ')'; } enum class EscapeChar { diff --git a/clang/include/clang/Basic/CustomizableOptional.h b/clang/include/clang/Basic/CustomizableOptional.h index 84d40025ee41b..2d6ae6a781a55 100644 --- a/clang/include/clang/Basic/CustomizableOptional.h +++ b/clang/include/clang/Basic/CustomizableOptional.h @@ -97,14 +97,6 @@ template class CustomizableOptional { 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 b94f6aef9ac60..bc96d5dfdf890 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 6b595a3567932..7d5ba7869ec34 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/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 5a4551a96ca4e..25fbfe83fa2bc 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -111,6 +111,14 @@ def warn_cxx98_compat_raw_string_literal : Warning< "raw string literals are incompatible with C++98">, InGroup, DefaultIgnore; +def warn_cxx26_compat_raw_string_literal_character_set : Warning< + " '%0' in a raw string literal delimiter is incompatible " + "with standards before C++2c">, + InGroup, DefaultIgnore; +def ext_cxx26_raw_string_literal_character_set : Extension< + " '%0' in a raw string literal delimiter is a C++2c extension">, + InGroup, DefaultIgnore; + def warn_multichar_character_literal : Warning< "multi-character character constant">, InGroup; def warn_four_char_character_literal : Warning< diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f8328be5890dd..d8c3fee7841f4 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 f15cba63624ea..e34eb692941b4 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 80e635e4a57ec..564a58e4eb670 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 03570f94de666..88938a981fd8a 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 de2f245fb29f8..57f37c5023110 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 8ccebe457ed53..76d7fd798bed3 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 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { 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 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { 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 @@ class ExtractAPIVisitor 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/Format/Format.h b/clang/include/clang/Format/Format.h index eb6647038403d..9bae252df366c 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -814,8 +814,8 @@ struct FormatStyle { enum ShortFunctionStyle : int8_t { /// Never merge functions into a single line. SFS_None, - /// Only merge functions defined inside a class. Same as "inline", - /// except it does not implies "empty": i.e. top level empty functions + /// Only merge functions defined inside a class. Same as ``inline``, + /// except it does not implies ``empty``: i.e. top level empty functions /// are not merged either. /// \code /// class Foo { @@ -836,7 +836,7 @@ struct FormatStyle { /// } /// \endcode SFS_Empty, - /// Only merge functions defined inside a class. Implies "empty". + /// Only merge functions defined inside a class. Implies ``empty``. /// \code /// class Foo { /// void f() { foo(); } @@ -1167,7 +1167,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// AttributeMacros: ['__capability', '__output', '__unused'] + /// AttributeMacros: [__capability, __output, __unused] /// \endcode /// /// \version 12 @@ -2631,7 +2631,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// ForEachMacros: ['RANGES_FOR', 'FOREACH'] + /// ForEachMacros: [RANGES_FOR, FOREACH] /// \endcode /// /// For example: BOOST_FOREACH. @@ -2653,7 +2653,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// IfMacros: ['IF'] + /// IfMacros: [IF] /// \endcode /// /// For example: `KJ_IF_MAYBE @@ -3030,7 +3030,7 @@ struct FormatStyle { /// in the following yaml example. This will result in imports being /// formatted as in the Java example below. /// \code{.yaml} - /// JavaImportGroups: ['com.example', 'com', 'org'] + /// JavaImportGroups: [com.example, com, org] /// \endcode /// /// \code{.java} @@ -3086,7 +3086,7 @@ struct FormatStyle { /// VeryLongImportsAreAnnoying, /// VeryLongImportsAreAnnoying, /// VeryLongImportsAreAnnoying, - /// } from 'some/module.js' + /// } from "some/module.js" /// /// false: /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" @@ -3615,7 +3615,7 @@ struct FormatStyle { /// Change specifiers/qualifiers to be aligned based on ``QualifierOrder``. /// With: /// \code{.yaml} - /// QualifierOrder: ['inline', 'static', 'type', 'const'] + /// QualifierOrder: [inline, static, type, const] /// \endcode /// /// \code @@ -3650,15 +3650,15 @@ struct FormatStyle { /// * type /// /// \note - /// it MUST contain 'type'. + /// It \b must contain ``type``. /// \endnote /// - /// Items to the left of 'type' will be placed to the left of the type and - /// aligned in the order supplied. Items to the right of 'type' will be + /// Items to the left of ``type`` will be placed to the left of the type and + /// aligned in the order supplied. Items to the right of ``type`` will be /// placed to the right of the type and aligned in the order supplied. /// /// \code{.yaml} - /// QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ] + /// QualifierOrder: [inline, static, type, const, volatile] /// \endcode /// \version 14 std::vector QualifierOrder; @@ -3692,10 +3692,10 @@ struct FormatStyle { /// name will be reformatted assuming the specified language based on the /// style for that language defined in the .clang-format file. If no style has /// been defined in the .clang-format file for the specific language, a - /// predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not - /// found, the formatting is based on llvm style. A matching delimiter takes - /// precedence over a matching enclosing function name for determining the - /// language of the raw string contents. + /// predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is + /// not found, the formatting is based on ``LLVM`` style. A matching delimiter + /// takes precedence over a matching enclosing function name for determining + /// the language of the raw string contents. /// /// If a canonical delimiter is specified, occurrences of other delimiters for /// the same language will be updated to the canonical if possible. @@ -3708,17 +3708,17 @@ struct FormatStyle { /// RawStringFormats: /// - Language: TextProto /// Delimiters: - /// - 'pb' - /// - 'proto' + /// - pb + /// - proto /// EnclosingFunctions: - /// - 'PARSE_TEXT_PROTO' + /// - PARSE_TEXT_PROTO /// BasedOnStyle: google /// - Language: Cpp /// Delimiters: - /// - 'cc' - /// - 'cpp' - /// BasedOnStyle: llvm - /// CanonicalDelimiter: 'cc' + /// - cc + /// - cpp + /// BasedOnStyle: LLVM + /// CanonicalDelimiter: cc /// \endcode /// \version 6 std::vector RawStringFormats; @@ -4046,7 +4046,7 @@ struct FormatStyle { /// /// This determines the maximum length of short namespaces by counting /// unwrapped lines (i.e. containing neither opening nor closing - /// namespace brace) and makes "FixNamespaceComments" omit adding + /// namespace brace) and makes ``FixNamespaceComments`` omit adding /// end comments for those. /// \code /// ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 @@ -4138,7 +4138,7 @@ struct FormatStyle { /// \endcode SUD_Never, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by "::" and discard any initial empty strings. Sort + /// Split the strings by ``::`` and discard any initial empty strings. Sort /// the lists of names lexicographically, and within those groups, names are /// in case-insensitive lexicographic order. /// \code @@ -4150,7 +4150,7 @@ struct FormatStyle { /// \endcode SUD_Lexicographic, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by "::" and discard any initial empty strings. The + /// Split the strings by ``::`` and discard any initial empty strings. The /// last element of each list is a non-namespace name; all others are /// namespace names. Sort the lists of names lexicographically, where the /// sort order of individual names is that all non-namespace names come @@ -4186,7 +4186,7 @@ struct FormatStyle { /// \version 9 bool SpaceAfterLogicalNot; - /// If \c true, a space will be inserted after the 'template' keyword. + /// If \c true, a space will be inserted after the ``template`` keyword. /// \code /// true: false: /// template void foo(); vs. template void foo(); @@ -4316,7 +4316,7 @@ struct FormatStyle { /// \endcode SBPO_ControlStatementsExceptControlMacros, /// Put a space before opening parentheses only if the parentheses are not - /// empty i.e. '()' + /// empty. /// \code /// void() { /// if (true) { @@ -4668,7 +4668,7 @@ struct FormatStyle { /// x = ( int32 )y vs. x = (int32)y /// \endcode bool InCStyleCasts; - /// Put a space in parentheses only if the parentheses are empty i.e. '()' + /// Insert a space in empty parentheses, i.e. ``()``. /// \code /// true: false: /// void f( ) { vs. void f() { @@ -4804,11 +4804,11 @@ struct FormatStyle { /// For example the configuration, /// \code{.yaml} /// TableGenBreakInsideDAGArg: BreakAll - /// TableGenBreakingDAGArgOperators: ['ins', 'outs'] + /// TableGenBreakingDAGArgOperators: [ins, outs] /// \endcode /// /// makes the line break only occurs inside DAGArgs beginning with the - /// specified identifiers 'ins' and 'outs'. + /// specified identifiers ``ins`` and ``outs``. /// /// \code /// let DAGArgIns = (ins @@ -4873,7 +4873,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// TypenameMacros: ['STACK_OF', 'LIST'] + /// TypenameMacros: [STACK_OF, LIST] /// \endcode /// /// For example: OpenSSL STACK_OF, BSD LIST_ENTRY. @@ -4929,7 +4929,7 @@ struct FormatStyle { /// /// In the .clang-format configuration file, this can be configured like: /// \code{.yaml} - /// WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE'] + /// WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] /// \endcode /// /// For example: BOOST_PP_STRINGIZE diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 8493026f5f7a6..d054b8cf0d240 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -467,15 +467,18 @@ class Parser : public CodeCompletionHandler { /// Flags describing a context in which we're parsing a statement. enum class ParsedStmtContext { + /// This context permits declarations in language modes where declarations + /// are not statements. + AllowDeclarationsInC = 0x1, /// This context permits standalone OpenMP directives. - AllowStandaloneOpenMPDirectives = 0x1, + AllowStandaloneOpenMPDirectives = 0x2, /// This context is at the top level of a GNU statement expression. - InStmtExpr = 0x2, + InStmtExpr = 0x4, /// The context of a regular substatement. SubStmt = 0, /// The context of a compound-statement. - Compound = AllowStandaloneOpenMPDirectives, + Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives, LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr) }; @@ -3656,6 +3659,7 @@ class Parser : public CodeCompletionHandler { struct OpenACCDirectiveParseInfo { OpenACCDirectiveKind DirKind; SourceLocation StartLoc; + SourceLocation DirLoc; SourceLocation EndLoc; SmallVector Clauses; // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and diff --git a/clang/include/clang/Sema/Attr.h b/clang/include/clang/Sema/Attr.h new file mode 100644 index 0000000000000..1133862568a6c --- /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 ec083f7cc09b7..7dea2b6826cfd 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { /// 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { return *OpenMPPtr; } + SemaPPC &PPC() { + assert(PPCPtr); + return *PPCPtr; + } + SemaPseudoObject &PseudoObject() { assert(PseudoObjectPtr); return *PseudoObjectPtr; @@ -1038,6 +1086,16 @@ class Sema final : public SemaBase { return *SYCLPtr; } + SemaSystemZ &SystemZ() { + assert(SystemZPtr); + return *SystemZPtr; + } + + SemaWasm &Wasm() { + assert(WasmPtr); + return *WasmPtr; + } + SemaX86 &X86() { assert(X86Ptr); return *X86Ptr; @@ -1073,15 +1131,25 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 @@ class Sema final : public SemaBase { 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 0000000000000..969078f552c6a --- /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 0000000000000..02698a33abd55 --- /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 0000000000000..a3bf59128d254 --- /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 3220f71dd797e..0b05245ab9686 100644 --- a/clang/include/clang/Sema/SemaBase.h +++ b/clang/include/clang/Sema/SemaBase.h @@ -217,6 +217,9 @@ class SemaBase { /// 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 34acaf19517f2..eac1f7c07c85d 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -49,6 +49,7 @@ class SemaHLSL : public SemaBase { 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 0000000000000..2d4a04f824bc2 --- /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 842eec099540c..d994d1819b442 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 0000000000000..aef0df9e8710f --- /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 0000000000000..3f1781b36efd9 --- /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 0000000000000..a663c694179d9 --- /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/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 6f69fa08939b8..66144de4340a8 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -379,7 +379,7 @@ class SemaOpenACC : public SemaBase { /// Called after the construct has been parsed, but clauses haven't been /// parsed. This allows us to diagnose not-implemented, as well as set up any /// state required for parsing the clauses. - void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); + void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc); /// Called after the directive, including its clauses, have been parsed and /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES @@ -400,6 +400,7 @@ class SemaOpenACC : public SemaBase { /// declaration group or associated statement. StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult AssocStmt); diff --git a/clang/include/clang/Sema/SemaPPC.h b/clang/include/clang/Sema/SemaPPC.h new file mode 100644 index 0000000000000..3e8929d5b6ded --- /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 0000000000000..8945471d53d63 --- /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 0000000000000..c3c781535024a --- /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/APValue.cpp b/clang/lib/AST/APValue.cpp index 8c77b563657d9..d8e33ff421c06 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -90,7 +90,7 @@ QualType APValue::LValueBase::getType() const { // For a materialized temporary, the type of the temporary we materialized // may not be the type of the expression. if (const MaterializeTemporaryExpr *MTE = - clang::dyn_cast(Base)) { + llvm::dyn_cast(Base)) { SmallVector CommaLHSs; SmallVector Adjustments; const Expr *Temp = MTE->getSubExpr(); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a2398fef623ea..73d3b152c49f1 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 41fbfe281ef65..0a35ed536a6a7 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 65d5eeb6354eb..ffb22194bce52 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 95ffd4784641f..d952f7e181848 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/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index ff92bc117f9ef..6ee7898f228de 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -687,26 +687,29 @@ bool ByteCodeStmtGen::visitDefaultStmt(const DefaultStmt *S) { template bool ByteCodeStmtGen::visitAttributedStmt(const AttributedStmt *S) { - for (const Attr *A : S->getAttrs()) { - auto *AA = dyn_cast(A); - if (!AA) - continue; + if (this->Ctx.getLangOpts().CXXAssumptions && + !this->Ctx.getLangOpts().MSVCCompat) { + for (const Attr *A : S->getAttrs()) { + auto *AA = dyn_cast(A); + if (!AA) + continue; - assert(isa(S->getSubStmt())); + assert(isa(S->getSubStmt())); - const Expr *Assumption = AA->getAssumption(); - if (Assumption->isValueDependent()) - return false; + const Expr *Assumption = AA->getAssumption(); + if (Assumption->isValueDependent()) + return false; - if (Assumption->HasSideEffects(this->Ctx.getASTContext())) - continue; + if (Assumption->HasSideEffects(this->Ctx.getASTContext())) + continue; - // Evaluate assumption. - if (!this->visitBool(Assumption)) - return false; + // Evaluate assumption. + if (!this->visitBool(Assumption)) + return false; - if (!this->emitAssume(Assumption)) - return false; + if (!this->emitAssume(Assumption)) + return false; + } } // Ignore other attributes. diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 246e56231539a..1249531eab09f 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 066377423df76..18ac4b1eb57e7 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -65,8 +65,9 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, assert(ArgTDecl != nullptr); QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); - if (QTName && !QTName->hasTemplateKeyword()) { - NNS = QTName->getQualifier(); + if (QTName && + !QTName->hasTemplateKeyword() && + (NNS = QTName->getQualifier())) { NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( Ctx, NNS, WithGlobalNsPrefix); if (QNNS != NNS) { diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index a381a8dd7b62c..47899b344c97a 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -23,15 +23,14 @@ OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) { return Inst; } -OpenACCComputeConstruct * -OpenACCComputeConstruct::Create(const ASTContext &C, OpenACCDirectiveKind K, - SourceLocation BeginLoc, SourceLocation EndLoc, - ArrayRef Clauses, - Stmt *StructuredBlock) { +OpenACCComputeConstruct *OpenACCComputeConstruct::Create( + const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *StructuredBlock) { void *Mem = C.Allocate( OpenACCComputeConstruct::totalSizeToAlloc( Clauses.size())); - auto *Inst = new (Mem) - OpenACCComputeConstruct(K, BeginLoc, EndLoc, Clauses, StructuredBlock); + auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, DirLoc, EndLoc, + Clauses, StructuredBlock); return Inst; } diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index a7ee973b7f7d0..46f7b79b272ef 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 2f0e4181e9408..3dbdad92813f6 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 4a1e94ffe283b..0e0e0a86f5cfc 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 04f105c128872..2097b29b7e0b6 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 5ed56b367a46a..58d01705d607b 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/Analysis/MacroExpansionContext.cpp b/clang/lib/Analysis/MacroExpansionContext.cpp index 564e359668a51..b212b7f245792 100644 --- a/clang/lib/Analysis/MacroExpansionContext.cpp +++ b/clang/lib/Analysis/MacroExpansionContext.cpp @@ -12,7 +12,7 @@ #define DEBUG_TYPE "macro-expansion-context" -static void dumpTokenInto(const clang::Preprocessor &PP, clang::raw_ostream &OS, +static void dumpTokenInto(const clang::Preprocessor &PP, llvm::raw_ostream &OS, clang::Token Tok); namespace clang { diff --git a/clang/lib/Basic/CharInfo.cpp b/clang/lib/Basic/CharInfo.cpp index d02054c9718f5..26d693b8e9b94 100644 --- a/clang/lib/Basic/CharInfo.cpp +++ b/clang/lib/Basic/CharInfo.cpp @@ -31,20 +31,20 @@ const uint16_t clang::charinfo::InfoTable[256] = { 0 , 0 , 0 , 0 , //32 SP 33 ! 34 " 35 # //36 $ 37 % 38 & 39 ' - CHAR_SPACE , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_SPACE , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , //40 ( 41 ) 42 * 43 + //44 , 45 - 46 . 47 / - CHAR_PUNCT , CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PERIOD , CHAR_PUNCT , //48 0 49 1 50 2 51 3 //52 4 53 5 54 6 55 7 CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , //56 8 57 9 58 : 59 ; //60 < 61 = 62 > 63 ? - CHAR_DIGIT , CHAR_DIGIT , CHAR_RAWDEL , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_DIGIT , CHAR_DIGIT , CHAR_PUNCT , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , //64 @ 65 A 66 B 67 C //68 D 69 E 70 F 71 G CHAR_PUNCT , CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , @@ -59,8 +59,8 @@ const uint16_t clang::charinfo::InfoTable[256] = { CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , //88 X 89 Y 90 Z 91 [ //92 \ 93 ] 94 ^ 95 _ - CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_RAWDEL , - CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER , + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , CHAR_UNDER , //96 ` 97 a 98 b 99 c //100 d 101 e 102 f 103 g CHAR_PUNCT , CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , @@ -75,6 +75,6 @@ const uint16_t clang::charinfo::InfoTable[256] = { CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , //120 x 121 y 122 z 123 { //124 | 125 } 126 ~ 127 DEL - CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_RAWDEL , - CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0 + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_PUNCT , + CHAR_PUNCT , CHAR_PUNCT , CHAR_PUNCT , 0 }; diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 3a30cff917bb4..036a655a4d073 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 0633b7e0da96a..9b2ae87adb2e7 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 90985c08fe7f8..b09680086248d 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 5edf8c7970913..37d0c478e0330 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) { @@ -20806,6 +20802,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_min_f32: case WebAssembly::BI__builtin_wasm_min_f64: + case WebAssembly::BI__builtin_wasm_min_f16x8: case WebAssembly::BI__builtin_wasm_min_f32x4: case WebAssembly::BI__builtin_wasm_min_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20816,6 +20813,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_max_f32: case WebAssembly::BI__builtin_wasm_max_f64: + case WebAssembly::BI__builtin_wasm_max_f16x8: case WebAssembly::BI__builtin_wasm_max_f32x4: case WebAssembly::BI__builtin_wasm_max_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20824,6 +20822,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_pmin_f16x8: case WebAssembly::BI__builtin_wasm_pmin_f32x4: case WebAssembly::BI__builtin_wasm_pmin_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); @@ -20832,6 +20831,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_pmax_f16x8: case WebAssembly::BI__builtin_wasm_pmax_f32x4: case WebAssembly::BI__builtin_wasm_pmax_f64x2: { Value *LHS = EmitScalarExpr(E->getArg(0)); diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 670bc4bf72cec..43dfbbb90dd52 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -71,8 +71,6 @@ class CGNVCUDARuntime : public CGCUDARuntime { 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 @@ class CGNVCUDARuntime : public CGCUDARuntime { /// 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 @@ class CGNVCUDARuntime : public CGCUDARuntime { } 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 fac278f0e20a4..1713f7065e7a2 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 bba00257fd4f0..5b2039af6128b 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -448,11 +448,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { AggValueSlot Dest = EnsureSlot(E->getType()); LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType()); LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field); - llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); - llvm::Value *IdxStart[] = { Zero, Zero }; - llvm::Value *ArrayStart = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxStart, - "arraystart"); + llvm::Value *ArrayStart = ArrayPtr.emitRawPointer(CGF); CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); ++Field; @@ -467,6 +463,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { Ctx.hasSameType(Field->getType()->getPointeeType(), ArrayType->getElementType())) { // End pointer. + llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); llvm::Value *IdxEnd[] = { Zero, Size }; llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP( ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd, @@ -1789,7 +1786,6 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // Push a destructor if necessary. // FIXME: if we have an array of structures, all explicitly // initialized, we can end up pushing a linear number of cleanups. - bool pushedCleanup = false; if (QualType::DestructionKind dtorKind = field->getType().isDestructedType()) { assert(LV.isSimple()); @@ -1797,17 +1793,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, LV.getAddress(), field->getType(), CGF.getDestroyer(dtorKind), false); - pushedCleanup = true; } } - - // If the GEP didn't get used because of a dead zero init or something - // else, clean it up for -O0 builds and general tidiness. - if (!pushedCleanup && LV.isSimple()) - if (llvm::GetElementPtrInst *GEP = - dyn_cast(LV.emitRawPointer(CGF))) - if (GEP->use_empty()) - GEP->eraseFromParent(); } } diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 43dd38659518d..6540ac69f2d9b 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -199,8 +199,7 @@ class CGObjCGNU : public CGObjCRuntime { 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 @@ class CGObjCGNU : public CGObjCRuntime { 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 e4774a587707a..c2314c3a57d33 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/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 76704c4d7be4a..db8e6f55302ad 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -1340,7 +1340,7 @@ void CodeGenPGO::setProfileVersion(llvm::Module &M) { llvm::APInt(64, ProfileVersion)), VarName); - IRLevelVersionVariable->setVisibility(llvm::GlobalValue::DefaultVisibility); + IRLevelVersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility); llvm::Triple TT(M.getTargetTriple()); if (TT.supportsCOMDAT()) { IRLevelVersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 8295d001ec6f7..75f9c99d5d0bf 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 97e451cfe2acb..4e1c52462e584 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/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 9849c59685cca..b141e5f2adfab 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2227,10 +2227,19 @@ void Generic_GCC::GCCInstallationDetector::init( SmallVector CandidateBiarchTripleAliases; // Add some triples that we want to check first. CandidateTripleAliases.push_back(TargetTriple.str()); - std::string TripleNoVendor = TargetTriple.getArchName().str() + "-" + - TargetTriple.getOSAndEnvironmentName().str(); - if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) + std::string TripleNoVendor, BiarchTripleNoVendor; + if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) { + StringRef OSEnv = TargetTriple.getOSAndEnvironmentName(); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) + OSEnv = "linux-gnu"; + TripleNoVendor = (TargetTriple.getArchName().str() + '-' + OSEnv).str(); CandidateTripleAliases.push_back(TripleNoVendor); + if (BiarchVariantTriple.getArch() != llvm::Triple::UnknownArch) { + BiarchTripleNoVendor = + (BiarchVariantTriple.getArchName().str() + '-' + OSEnv).str(); + CandidateBiarchTripleAliases.push_back(BiarchTripleNoVendor); + } + } CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, @@ -2453,11 +2462,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // lists should shrink over time. Please don't add more elements to *Triples. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", - "aarch64-suse-linux"}; + "aarch64-none-linux-gnu", "aarch64-redhat-linux", "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; - static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", - "aarch64_be-linux-gnu"}; + static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; @@ -2482,9 +2489,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", - "x86_64-slackware-linux", "x86_64-unknown-linux", - "x86_64-amazon-linux"}; + "x86_64-manbo-linux-gnu", "x86_64-slackware-linux", + "x86_64-unknown-linux", "x86_64-amazon-linux"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; static const char *const X32LibDirs[] = {"/libx32", "/lib"}; @@ -2500,26 +2506,24 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"}; static const char *const M68kLibDirs[] = {"/lib"}; - static const char *const M68kTriples[] = { - "m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"}; + static const char *const M68kTriples[] = {"m68k-unknown-linux-gnu", + "m68k-suse-linux"}; static const char *const MIPSLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSTriples[] = { "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/libo32", "/lib"}; - static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu"}; + static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", + "mips-img-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { - "mips64-linux-gnu", "mips-mti-linux-gnu", - "mips-img-linux-gnu", "mips64-linux-gnuabi64", + "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64-linux-gnuabi64", "mipsisa64r6-linux-gnu", "mipsisa64r6-linux-gnuabi64"}; static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64ELTriples[] = { - "mips64el-linux-gnu", "mips-mti-linux-gnu", - "mips-img-linux-gnu", "mips64el-linux-gnuabi64", + "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64", "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64"}; static const char *const MIPSN32LibDirs[] = {"/lib32"}; @@ -2534,46 +2538,39 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { - "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", + "powerpc-unknown-linux-gnu", // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux". "powerpc64-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPCLELibDirs[] = {"/lib32", "/lib"}; - static const char *const PPCLETriples[] = {"powerpcle-linux-gnu", - "powerpcle-unknown-linux-gnu", + static const char *const PPCLETriples[] = {"powerpcle-unknown-linux-gnu", "powerpcle-linux-musl"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; - static const char *const PPC64Triples[] = { - "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", - "powerpc64-suse-linux", "ppc64-redhat-linux"}; + static const char *const PPC64Triples[] = {"powerpc64-unknown-linux-gnu", + "powerpc64-suse-linux", + "ppc64-redhat-linux"}; static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64LETriples[] = { - "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", - "powerpc64le-none-linux-gnu", "powerpc64le-suse-linux", - "ppc64le-redhat-linux"}; + "powerpc64le-unknown-linux-gnu", "powerpc64le-none-linux-gnu", + "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"}; static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu", - "riscv32-linux-gnu", "riscv32-unknown-elf"}; static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", - "riscv64-linux-gnu", "riscv64-unknown-elf"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; - static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", - "sparcv8-linux-gnu"}; + static const char *const SPARCv8Triples[] = {"sparcv8-linux-gnu"}; static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; - static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", - "sparcv9-linux-gnu"}; + static const char *const SPARCv9Triples[] = {"sparcv9-linux-gnu"}; static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; static const char *const SystemZTriples[] = { - "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", - "s390x-suse-linux", "s390x-redhat-linux"}; - + "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", + "s390x-redhat-linux"}; using std::begin; using std::end; diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index b1ff697b368b1..f32a23f111e4b 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -106,9 +106,9 @@ class HIPUndefinedFatBinSymbols { 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 27de69550853c..ce900600cbee5 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 8792f4c750748..e4a4f27e502b1 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -727,6 +727,29 @@ struct FormatToken { 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 7c4c76a91f2c5..26c0aa36bdcb6 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 b6f7567adc140..053fd3d4df559 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); @@ -2243,7 +2236,7 @@ bool UnwrappedLineParser::tryToParseLambda() { bool InTemplateParameterList = false; while (FormatTok->isNot(tok::l_brace)) { - if (FormatTok->isTypeName(LangOpts)) { + if (FormatTok->isTypeName(LangOpts) || FormatTok->isAttribute()) { nextToken(); continue; } @@ -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 5ceb986a1f652..1227f45d5432b 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 56c3c3636c9bc..a9d182aa24470 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/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index c98645993abe0..c7543a48c0b50 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2261,8 +2261,17 @@ bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, unsigned PrefixLen = 0; - while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) + while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) { ++PrefixLen; + if (!isLexingRawMode() && + llvm::is_contained({'$', '@', '`'}, CurPtr[PrefixLen])) { + const char *Pos = &CurPtr[PrefixLen]; + Diag(Pos, LangOpts.CPlusPlus26 + ? diag::warn_cxx26_compat_raw_string_literal_character_set + : diag::ext_cxx26_raw_string_literal_character_set) + << StringRef(Pos, 1); + } + } // If the last character was not a '(', then we didn't lex a valid delimiter. if (CurPtr[PrefixLen] != '(') { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e149b1a0fb5ef..1558e3dcb8974 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/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index e9c60f76165b6..63afc18783a1f 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -1347,11 +1347,13 @@ void Parser::ParseOpenACCCacheVarList() { ParseOpenACCVarList(OpenACCClauseKind::Invalid); } -Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { - SourceLocation StartLoc = getCurToken().getLocation(); +Parser::OpenACCDirectiveParseInfo +Parser::ParseOpenACCDirective() { + SourceLocation StartLoc = ConsumeAnnotationToken(); + SourceLocation DirLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); - getActions().OpenACC().ActOnConstruct(DirKind, StartLoc); + getActions().OpenACC().ActOnConstruct(DirKind, DirLoc); // Once we've parsed the construct/directive name, some have additional // specifiers that need to be taken care of. Atomic has an 'atomic-clause' @@ -1390,7 +1392,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { break; case OpenACCDirectiveKind::Wait: // OpenACC has an optional paren-wrapped 'wait-argument'. - if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed) + if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed) T.skipToEnd(); else T.consumeClose(); @@ -1404,7 +1406,8 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present, plus set up return value. - OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, SourceLocation{}, + OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc, + SourceLocation{}, ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && @@ -1421,7 +1424,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); ParsingOpenACCDirectiveRAII DirScope(*this); - ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); @@ -1438,7 +1440,6 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); ParsingOpenACCDirectiveRAII DirScope(*this); - ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind, @@ -1456,6 +1457,6 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { } return getActions().OpenACC().ActOnEndStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, DirInfo.Clauses, - AssocStmt); + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc, + DirInfo.Clauses, AssocStmt); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index e959dd6378f46..50a872fedebf7 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -21,13 +21,13 @@ #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaOpenMP.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/UniqueVector.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" +#include #include using namespace clang; @@ -1646,19 +1646,17 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind, SmallVectorImpl &Clauses, SourceLocation Loc) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - DKind, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2114,19 +2112,17 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /*AllowScopeSpecifier=*/true)) { SmallVector Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2150,9 +2146,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_requires: { SourceLocation StartLoc = ConsumeToken(); SmallVector Clauses; - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; if (Tok.is(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); @@ -2163,11 +2157,11 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_requires, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2510,9 +2504,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector Clauses; - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ReadDirectiveWithinMetadirective @@ -2717,19 +2709,17 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( /*AllowScopeSpecifier=*/false)) { SmallVector Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - SmallVector, - llvm::omp::Clause_enumSize + 1> - FirstClauses(llvm::omp::Clause_enumSize + 1); + std::bitset SeenClauses; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.OpenMP().StartOpenMPClause(CKind); - OMPClause *Clause = ParseOpenMPClause( - OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt()); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !SeenClauses[unsigned(CKind)]); SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); - FirstClauses[unsigned(CKind)].setInt(true); + SeenClauses[unsigned(CKind)] = true; if (Clause != nullptr) Clauses.push_back(Clause); if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -2926,13 +2916,11 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( ImplicitClauseAllowed = false; Actions.OpenMP().StartOpenMPClause(CKind); HasImplicitClause = false; - OMPClause *Clause = ParseOpenMPClause( - DKind, CKind, !FirstClauses[unsigned(CKind)].getInt()); - FirstClauses[unsigned(CKind)].setInt(true); - if (Clause) { - FirstClauses[unsigned(CKind)].setPointer(Clause); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); + SeenClauses[unsigned(CKind)] = true; + if (Clause) Clauses.push_back(Clause); - } // Skip ',' if any. if (Tok.is(tok::comma)) @@ -2948,7 +2936,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( // If the depend or doacross clause is specified, the ordered construct // is a stand-alone directive. for (auto CK : {OMPC_depend, OMPC_doacross}) { - if (FirstClauses[unsigned(CK)].getInt()) { + if (SeenClauses[unsigned(CK)]) { if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Loc, diag::err_omp_immediate_directive) @@ -2960,7 +2948,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } } - if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) { + if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { Diag(Loc, diag::err_omp_required_clause) << getOpenMPDirectiveName(OMPD_tile) << "sizes"; } @@ -3758,7 +3746,7 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: if (!PA.checkExactlyNumArgs(Actions, 2)) continue; - if (auto *A = Actions.CreateAMDGPUFlatWorkGroupSizeAttr( + if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr( PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1))) Attrs.push_back(A); continue; @@ -3766,7 +3754,7 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { if (!PA.checkAtLeastNumArgs(Actions, 1) || !PA.checkAtMostNumArgs(Actions, 2)) continue; - if (auto *A = Actions.CreateAMDGPUWavesPerEUAttr( + if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr( PA, PA.getArgAsExpr(0), PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr)) Attrs.push_back(A); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index b0af04451166c..c25203243ee49 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -239,7 +239,15 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) && llvm::all_of(GNUAttrs, IsStmtAttr); - if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || + // In C, the grammar production for statement (C23 6.8.1p1) does not allow + // for declarations, which is different from C++ (C++23 [stmt.pre]p1). So + // in C++, we always allow a declaration, but in C we need to check whether + // we're in a statement context that allows declarations. e.g., in C, the + // following is invalid: if (1) int x; + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != + ParsedStmtContext()) && + ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index fe6471c81ff01..c9abf58fcbd29 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 d1fb21bb1ae1d..582adcfa84c46 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 0000000000000..c446cc1d042a4 --- /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 0000000000000..da37ccef051a6 --- /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 22f5a2f663477..330cd602297d4 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 0000000000000..bde1a26f1ebc0 --- /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 0442fb2929e3c..a2f12d622e8cc 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 c3251f3cc9d81..300af02239779 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 2a87b26f17a2b..34e46e12859bb 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 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, 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 5041fd65286fa..7c1fb23b90728 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 8ab429e2a136e..631fd4e354927 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 6d4379283f198..807453400abdd 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 ded4f59833ac0..fb4154757775b 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 d3e9dcb4f4399..4487c618862c5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -42,6 +42,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaPPC.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" @@ -931,7 +932,7 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, // PPC MMA non-pointer types are not allowed as throw expr types. if (Ex && Context.getTargetInfo().getTriple().isPPC64()) - CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc()); + PPC().CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc()); return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); @@ -1444,10 +1445,10 @@ bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) { // category are defined within such member functions as they are within // an implicit object member function). DeclContext *DC = getFunctionLevelDeclContext(); - if (const auto *Method = dyn_cast(DC); - Method && Method->isExplicitObjectMemberFunction()) { + const auto *Method = dyn_cast(DC); + if (Method && Method->isExplicitObjectMemberFunction()) { Diag(Loc, diag::err_invalid_this_use) << 1; - } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) { + } else if (Method && isLambdaCallWithExplicitObjectParameter(CurContext)) { Diag(Loc, diag::err_invalid_this_use) << 1; } else { Diag(Loc, diag::err_invalid_this_use) << 0; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 9aa60204bf29d..3ae1af26d0096 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 462ab2c952b67..9c423529c80e7 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 6a12c417e2f3a..9e614ae99f37d 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 0000000000000..5c921c0bc9e33 --- /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/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index ef0a655b631ab..be6ea20a956a3 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -5897,6 +5897,16 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, NamedDecl *ChosenDecl = Correction.isKeyword() ? nullptr : Correction.getFoundDecl(); + + // For builtin functions which aren't declared anywhere in source, + // don't emit the "declared here" note. + if (const auto *FD = dyn_cast_if_present(ChosenDecl); + FD && FD->getBuiltinID() && + PrevNote.getDiagID() == diag::note_previous_decl && + Correction.getCorrectionRange().getBegin() == FD->getBeginLoc()) { + ChosenDecl = nullptr; + } + if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); diff --git a/clang/lib/Sema/SemaLoongArch.cpp b/clang/lib/Sema/SemaLoongArch.cpp new file mode 100644 index 0000000000000..0a67bf2c77386 --- /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 0000000000000..df5328fbf6640 --- /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 0000000000000..cc8941071463d --- /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 09d91b31cfe5f..5b4d01860c0bd 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; @@ -844,7 +916,7 @@ ExprResult SemaOpenACC::CheckReductionVar(Expr *VarExpr) { } void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, - SourceLocation StartLoc) { + SourceLocation DirLoc) { switch (K) { case OpenACCDirectiveKind::Invalid: // Nothing to do here, an invalid kind has nothing we can check here. We @@ -859,7 +931,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, // here as these constructs do not take any arguments. break; default: - Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; + Diag(DirLoc, diag::warn_acc_construct_unimplemented) << K; break; } } @@ -1265,6 +1337,7 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult AssocStmt) { @@ -1278,7 +1351,7 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, case OpenACCDirectiveKind::Kernels: // TODO OpenACC: Add clauses to the construct here. return OpenACCComputeConstruct::Create( - getASTContext(), K, StartLoc, EndLoc, Clauses, + getASTContext(), K, StartLoc, DirLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); } llvm_unreachable("Unhandled case in directive handling?"); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bab61e8fd54e8..99528c2a4f1f4 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 6c5e8afbcfb6e..6c4ce1022ae27 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 0000000000000..99f46b12e6968 --- /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/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 8735d96c84079..6f538ed55cb72 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -285,7 +285,7 @@ bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt, static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { NoInlineAttr NIA(S.Context, A); - if (!NIA.isClangNoInline()) { + if (!NIA.isStmtNoInline()) { S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt) << "[[clang::noinline]]"; return nullptr; @@ -684,10 +684,8 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A, } if (!getLangOpts().CPlusPlus23 && - A.getSyntax() == AttributeCommonInfo::AS_CXX11) { - llvm::dbgs() << "Syntax: " << int(A.getSyntax()) << "\n"; + A.getSyntax() == AttributeCommonInfo::AS_CXX11) Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range; - } return Assumption; } diff --git a/clang/lib/Sema/SemaSystemZ.cpp b/clang/lib/Sema/SemaSystemZ.cpp new file mode 100644 index 0000000000000..7e836adbee659 --- /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 39e9dbed0c3e0..40a759ea330de 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, @@ -5652,7 +5660,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, LocalInstantiationScope Scope(*this); EnterExpressionEvaluationContext EECtx{ - *this, ExpressionEvaluationContext::ConstantEvaluated, CSD}; + *this, ExpressionEvaluationContext::Unevaluated, CSD}; if (!AreArgsDependent && CheckConstraintSatisfaction( @@ -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 f9ec34163e656..1011db2d2830d 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; @@ -5101,6 +5134,20 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, return true; MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, /*Final=*/false); + // Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so + // that the template arguments of the constraint can be preserved. For + // example: + // + // template + // concept C = []() { return true; }(); + // + // We need the argument for T while evaluating type constraint D in + // building the CallExpr to the lambda. + EnterExpressionEvaluationContext EECtx( + S, Sema::ExpressionEvaluationContext::Unevaluated, + ImplicitConceptSpecializationDecl::Create( + S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(), + CanonicalConverted)); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bb49aae2cb666..4c8eaf2d4ebf6 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 ef0b6b701a52c..7cec82c701028 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 0000000000000..c0fa05bc17609 --- /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 dee335b526991..efba99b85b0fb 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4033,11 +4033,12 @@ class TreeTransform { StmtResult RebuildOpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, StmtResult StrBlock) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, EndLoc, - Clauses, StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, + EndLoc, Clauses, StrBlock); } private: @@ -4604,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, @@ -4611,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 @@ -11559,8 +11558,8 @@ StmtResult TreeTransform::TransformOpenACCComputeConstruct( getSema().OpenACC().ActOnAssociatedStmt(C->getDirectiveKind(), StrBlock); return getDerived().RebuildOpenACCComputeConstruct( - C->getDirectiveKind(), C->getBeginLoc(), C->getEndLoc(), - TransformedClauses, StrBlock); + C->getDirectiveKind(), C->getBeginLoc(), C->getDirectiveLoc(), + C->getEndLoc(), TransformedClauses, StrBlock); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index eac4faff28549..bea2b94989107 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2797,6 +2797,7 @@ void ASTStmtReader::VisitOpenACCConstructStmt(OpenACCConstructStmt *S) { (void)Record.readInt(); S->Kind = Record.readEnum(); S->Range = Record.readSourceRange(); + S->DirectiveLoc = Record.readSourceLocation(); Record.readOpenACCClauseList(S->Clauses); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index dd548fabfd955..eb41a205bc82c 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3205,9 +3205,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, } // Sort by diag::kind for deterministic output. - llvm::sort(Mappings, [](const auto &LHS, const auto &RHS) { - return LHS.first < RHS.first; - }); + llvm::sort(Mappings, llvm::less_first()); for (const auto &I : Mappings) { Record.push_back(I.first); @@ -7835,7 +7833,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::If: { const auto *IC = cast(C); writeSourceLocation(IC->getLParenLoc()); - writeStmtRef(IC->getConditionExpr()); + AddStmt(const_cast(IC->getConditionExpr())); return; } case OpenACCClauseKind::Self: { @@ -7843,7 +7841,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeSourceLocation(SC->getLParenLoc()); writeBool(SC->hasConditionExpr()); if (SC->hasConditionExpr()) - writeStmtRef(SC->getConditionExpr()); + AddStmt(const_cast(SC->getConditionExpr())); return; } case OpenACCClauseKind::NumGangs: { @@ -7857,13 +7855,13 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::NumWorkers: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); - writeStmtRef(NWC->getIntExpr()); + AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::VectorLength: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); - writeStmtRef(NWC->getIntExpr()); + AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::Private: { @@ -7942,15 +7940,15 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeSourceLocation(AC->getLParenLoc()); writeBool(AC->hasIntExpr()); if (AC->hasIntExpr()) - writeStmtRef(AC->getIntExpr()); + AddStmt(const_cast(AC->getIntExpr())); return; } case OpenACCClauseKind::Wait: { const auto *WC = cast(C); writeSourceLocation(WC->getLParenLoc()); writeBool(WC->getDevNumExpr()); - if (const Expr *DNE = WC->getDevNumExpr()) - writeStmtRef(DNE); + if (Expr *DNE = WC->getDevNumExpr()) + AddStmt(DNE); writeSourceLocation(WC->getQueuesLoc()); writeOpenACCIntExprList(WC->getQueueIdExprs()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index a44852af97bea..3c586b270fbf4 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2847,6 +2847,7 @@ void ASTStmtWriter::VisitOpenACCConstructStmt(OpenACCConstructStmt *S) { Record.push_back(S->clauses().size()); Record.writeEnum(S->Kind); Record.AddSourceRange(S->Range); + Record.AddSourceLocation(S->DirectiveLoc); Record.writeOpenACCClauseList(S->clauses()); } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 0c047b6c5da2f..0f82f22d8b9a8 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -259,9 +259,7 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) { ++Index; } - llvm::stable_sort(SimpleNames, [](const MacroOpt &A, const MacroOpt &B) { - return A.first < B.first; - }); + llvm::stable_sort(SimpleNames, llvm::less_first()); // Keep the last instance of each macro name by going in reverse auto NewEnd = std::unique( SimpleNames.rbegin(), SimpleNames.rend(), diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp index 9382558393e4c..cd3b8c6821344 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 e062d4f068a40..e84241cee922f 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 f9e9ee9d35dde..5da025c229ea3 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 da46cef7f3f1b..6fe05e33a5fb8 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 37f6d8a0472d3..fea14abb3b2f4 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 0000000000000..acacdac857954 --- /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