diff --git a/.github/workflows/LLVM-Auto-Updater.yml b/.github/workflows/LLVM-Auto-Updater.yml new file mode 100644 index 000000000000..2588eaf12eae --- /dev/null +++ b/.github/workflows/LLVM-Auto-Updater.yml @@ -0,0 +1,116 @@ +name: Weekly-LLVM-Release-Update +on: + workflow_dispatch: + inputs: + tag_name: + description: "LLVM Version" + required: false + schedule: + - cron: "0 0 * * 1" + +permissions: + contents: write + +jobs: + merge-llvm: + runs-on: ubuntu-latest + outputs: + branch_version: ${{ steps.step1.outputs.branch_version }} + steps: + - name: Get LLVM version + id: step1 + run: | + if [[ -z $github_event_inputs_tag_name ]]; then + tag_name=$(curl -sL https://api.github.com/repos/llvm/llvm-project/releases/latest | jq -r '.tag_name') + else + tag_name=$github.event.inputs.tag_name + fi + + echo "Using version: $tag_name" + echo "tag_name=${tag_name}" >> $GITHUB_ENV + version=$(echo $tag_name | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+') + echo "version=${version}" >> $GITHUB_ENV + major_version=$(echo $version | awk -F '.' '{print $1}') + echo "major_version=${major_version}" >> $GITHUB_ENV + branch_version='release/'$major_version'.x' + echo "branch_version=${branch_version}" >> $GITHUB_ENV + is_official_release=$(curl -sL https://api.github.com/repos/llvm/llvm-project/releases/latest | jq -r '.prerelease') + echo "is_official_release=${is_official_release}" >> $GITHUB_ENV + echo "branch_version=${branch_version}" >> $GITHUB_OUTPUT + + - name: Ensure official release + run: | + if [[ "${{ env.is_official_release }}" != "false" ]]; then + exit 0 + fi + + - name: Checkout LLVM-project + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: Sparse checkout LLVM-project + run: | + git clone --depth 1 --filter=blob:none --sparse --branch ${{ env.branch_version }} https://github.com/llvm/llvm-project.git ../llvm-project + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + cd ../llvm-project + echo "sparse checkout" + git sparse-checkout set llvm/ cmake/ third-party/ .github/ + rm -rf .git/ .github/ + ls -la + cd - + + - name: Add files to branch ${{ env.branch_version }} + run: | + branch_exists=$(git ls-remote --exit-code --heads origin ${{env.branch_version}}) + echo "branch_exists=${branch_exists}" >> $GITHUB_ENV + git checkout ${{ env.branch_version }} 2>/dev/null || git checkout -b ${{ env.branch_version }} + if [[ "${{ env.branch_exists }}" = true ]]; then + git pull origin ${{ env.branch_version }} + git push -u origin ${{ env.branch_version }} + rm -rf !\(.git\|.github\) + fi + cp -r ../llvm-project/* . + ls -la + git add . + + - name: Update branch ${{ env.branch_version }} + if: ${{ env.branch_exists }} + run: | + echo "Branch already exists, update." + if [[ `git status --porcelain` ]]; then + git commit -m "Update LLVM ${{ env.branch_version }}" + else + echo "No changes to commit." + exit 0 + fi + + - name: Commit new branch ${{ env.branch_version }} + if: ${{ ! env.branch_exists }} + run: | + git commit -m "Add LLVM ${{ env.branch_version }}" + + - name: Push new branch + run: | + git push origin ${{ env.branch_version }} -f + + build-llvm-tblgen: + runs-on: ubuntu-latest + needs: merge-llvm + env: + branch_version: ${{ needs.merge-llvm.outputs.branch_version }} + steps: + - uses: lukka/get-cmake@latest + + - name: Checkout llvm-capstone + uses: actions/checkout@v3 + with: + ref: ${{ env.branch_version }} + + - name: Build llvm tblgen + run: | + mkdir build + cd build + cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm + cmake --build . --target llvm-tblgen --config Debug diff --git a/.github/workflows/LLVM-Tblgen-Build.yml b/.github/workflows/LLVM-Tblgen-Build.yml new file mode 100644 index 000000000000..d4e5d0aaeffa --- /dev/null +++ b/.github/workflows/LLVM-Tblgen-Build.yml @@ -0,0 +1,78 @@ +name: LLVM-Tblgen-Build +on: + workflow_dispatch: + push: + paths-ignore: + - ".github/workflows/LLVM-Auto-Updater.yml" + - "CONTRIBUTING.md" + - "README.md" + - "LICENSE.TXT" + - "SECURITY.md" + branches: + - auto-sync* + pull_request: + paths-ignore: + - ".github/workflows/LLVM-Auto-Updater.yml" + - "CONTRIBUTING.md" + - "README.md" + - "LICENSE.TXT" + - "SECURITY.md" + branches: + - auto-sync* + - release/** + +jobs: + build-and-test-llvm-tblgen: + runs-on: ubuntu-latest + steps: + - name: Checkout llvm-capstone (patched backends) + uses: actions/checkout@v4 + with: + clean: false + + - name: Set up Python + uses: actions/setup-python@v4 + + - name: Install dependencies + run: pip install cmake Ninja + + - name: Build patched llvm-tblgen + run: | + mkdir build + cd build + cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm + cmake --build . --target llvm-tblgen --config Debug + cd .. + + - name: Generate Capstone tables + run: | + ./gen_cs_tables.sh + + - name: Checkout LLVM + uses: actions/checkout@v4 + with: + clean: false + ref: auto-sync-18-base + + - name: Build LLVM llvm-tblgen + run: | + rm -rf build + mkdir build + cd build + cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm + cmake --build . --target llvm-tblgen --config Debug + cd .. + + - name: Checkout llvm-capstone (patched backends) + uses: actions/checkout@v4 + with: + clean: false + + - name: Generate original LLVM tables + run: | + ./gen_llvm_tables.sh + + - name: Compare LLVM and Capstone tables and syntax + run: | + ./compare_tblgen_output.sh + diff --git a/DeprecatedFeatures.md b/DeprecatedFeatures.md new file mode 100644 index 000000000000..b7975dc41afd --- /dev/null +++ b/DeprecatedFeatures.md @@ -0,0 +1,41 @@ +# Deprecated Features + +Capstone needs to support features which were removed by LLVM in the past. +Here we explain how to reintroduce them. + +## Reintroduction + +To get the old features back we copy them from the old `.td` files and include them in the new ones. + +To include removed features from previous LLVM versions do the following: + +1. Checkout the last LLVM version the feature was present. +2. Copy all feature related definitions into a `Deprecated.td` file. +3. Checkout the newest LLVM version again. +4. Wrap the different definition types in include guards. For example the `InstrInfo` definitions could be included in: + + ``` + #ifndef INCLUDED_CAPSTONE_DEPR_INSTR + #ifdef CAPSTONE_DEPR_INSTR + #define INCLUDED_CAPSTONE_DEPR_INSTR // Ensures it is only included once + + [Instruction definitions of removed feature] + + #endif // INCLUDED_CAPSTONE_DEPR_INSTR + #endif // CAPSTONE_DEPR_INSTR + ``` + + _Note that the order of `#ifndef` and `#ifdef` matters (otherwise you'll get an error from `tblgen`)._ + +5. Include the definitions in the current definition files with: + + ``` + #define CAPSTONE_DEPR_INSTR + include "Deprecated.md" + ``` + +## Notes +- It is possible that you have to change some definitions slightly. +Because certain classes no longer exist or were replaced (e.g.: `GCCBuiltin` -> `ClangBuiltin`). +- Some new processors might need to have the feature flag (`Has`) added +to their `UnsupportedFeatures` list. diff --git a/README.md b/README.md index 7fb16fd1d071..ae5188efa9b5 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,126 @@ -# The LLVM Compiler Infrastructure +# Capstone's LLVM with refactored TableGen backends -[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/llvm/llvm-project/badge)](https://securityscorecards.dev/viewer/?uri=github.com/llvm/llvm-project) -[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8273/badge)](https://www.bestpractices.dev/projects/8273) -[![libc++](https://github.com/llvm/llvm-project/actions/workflows/libcxx-build-and-test.yaml/badge.svg?branch=main&event=schedule)](https://github.com/llvm/llvm-project/actions/workflows/libcxx-build-and-test.yaml?query=event%3Aschedule) +This LLVM version has the purpose to generate code for the +[Capstone disassembler](https://github.com/capstone-engine/capstone). -Welcome to the LLVM project! +It refactors the TableGen emitter backends, so they can emit C code +in addition to the C++ code they normally emit. -This repository contains the source code for LLVM, a toolkit for the -construction of highly optimized compilers, optimizers, and run-time -environments. +## Build -The LLVM project has multiple components. The core of the project is -itself called "LLVM". This contains all of the tools, libraries, and header -files needed to process intermediate representations and convert them into -object files. Tools include an assembler, disassembler, bitcode analyzer, and -bitcode optimizer. +``` +python3 -m venv .venv +source .venv/bin/activate +pip install Ninja cmake +mkdir build +cd build +cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm +cmake --build . --target llvm-tblgen --config Debug +``` -C-like languages use the [Clang](http://clang.llvm.org/) frontend. This -component compiles C, C++, Objective-C, and Objective-C++ code into LLVM bitcode --- and from there into object files, using LLVM. +## Code generation -Other components include: -the [libc++ C++ standard library](https://libcxx.llvm.org), -the [LLD linker](https://lld.llvm.org), and more. +Please note that within LLVM we speak of a `Target` if we refer to an architecture. -## Getting the Source Code and Building LLVM +### Relevant files -Consult the -[Getting Started with LLVM](https://llvm.org/docs/GettingStarted.html#getting-the-source-code-and-building-llvm) -page for information on building and running LLVM. +The TableGen emitter backends are located in `llvm/utils/TableGen/`. -For information on how to contribute to the LLVM project, please take a look at -the [Contributing to LLVM](https://llvm.org/docs/Contributing.html) guide. +The target definition files (`.td`), which define the +instructions, operands, features etc., can be +found in `llvm/lib/Target//`. -## Getting in touch +### Code generation overview -Join the [LLVM Discourse forums](https://discourse.llvm.org/), [Discord -chat](https://discord.gg/xS7Z362), -[LLVM Office Hours](https://llvm.org/docs/GettingInvolved.html#office-hours) or -[Regular sync-ups](https://llvm.org/docs/GettingInvolved.html#online-sync-ups). +Generating code for a target has 6 steps: -The LLVM project has adopted a [code of conduct](https://llvm.org/docs/CodeOfConduct.html) for -participants to all modes of communication within the project. +``` + 5 6 + ┌──────────┐ ┌──────────┐ + │Printer │ │CS .inc │ + 1 2 3 4 ┌──►│Capstone ├─────►│files │ +┌───────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐ │ └──────────┘ └──────────┘ +│ .td │ │ │ │ │ │ Code- │ │ +│ files ├────►│ TableGen ├────►│ CodeGen ├────►│ Emitter │◄─┤ +└───────┘ └──────┬────┘ └───────────┘ └──────────┘ │ + │ ▲ │ ┌──────────┐ ┌──────────┐ + └─────────────────────────────────┘ └──►│Printer ├─────►│LLVM .inc │ + │LLVM │ │files │ + └──────────┘ └──────────┘ +``` + +1. LLVM targets are defined in `.td` files. They describe instructions, operands, +features and other properties. + +2. [LLVM TableGen](https://llvm.org/docs/TableGen/index.html) parses these files +and converts them to an internal representation of [Classes, Records, DAGs](https://llvm.org/docs/TableGen/ProgRef.html) + and other types. + +3. In the second step a TableGen component called [CodeGen](https://llvm.org/docs/CodeGenerator.html) +abstracts this even further. +The result is a representation which is _not_ specific to any target +(e.g. the `CodeGenInstruction` class can represent a machine instruction of any target). + +4. Different code emitter backends use the result of the former two components to +generated code. + +5. Whenever the emitter emits code it calls a `Printer`. Either the `PrinterCapstone` to emit C or `PrinterLLVM` to emit C++. +Which one is controlled by the `--printerLang=[CCS,C++]` option passed to `llvm-tblgen`. + +6. After the emitter backend is done, the `Printer` writes the `output_stream` content into the `.inc` files. + +### Emitter backends and their use cases + +We use the following emitter backends + +| Name | Generated Code | Note | +|------|----------------|------| +| AsmMatcherEmitter | Mapping tables for Capstone | | +| AsmWriterEmitter | State machine to decode the asm-string for a `MCInst` | | +| DecoderEmitter | State machine which decodes bytes to a `MCInst`. | | +| InstrInfoEmitter | Tables with instruction information (instruction enum, instr. operand information...) | | +| RegisterInfoEmitter | Tables with register information (register enum, register type info...) | | +| SubtargetEmitter | Table about the target features. | | +| SearchableTablesEmitter | Usually used to generate tables and decoding functions for system registers. | **1.** Not all targets use this. | +| | | **2.** Backend can't access the target name. Wherever the target name is needed `__ARCH__` or `##ARCH##` is printed and later replaced. | + +## Developer notes + +- If you find C++ code within the generated files you need to extend `PrinterCapstone::translateToC()`. +If this still doesn't fix the problem, the code snipped wasn't passed through `translateToC()` before emitting. +So you need to figure out where this specific code snipped is printed and add `translateToC()`. + +- Template functions with default values for their arguments, don't get replaced properly. + See: `handleDefaultArg()` in `PrinterCapstone.cpp` to add the default argument value. + +- Some operand printer or decoder are not recognized. Compiler error like: + ``` + .../AArch64GenAsmWriter.inc:18216:5: warning: implicit declaration of function ‘printMatrixIndex_1’; did you mean ‘printMatrix_0’? [-Wimplicit-function-declaration] + 18216 | printMatrixIndex_1(MI, 2, O); + | ^~~~~~~~~~~~~~~~~~ + | printMatrix_0 + + ``` + To fix this the function declaration is probably missing in the header (e.g. `InstPrinter.h`). You can copy the `DEFINE_printMatrix()` function to the header + and rewrite it as declaration. Just check the other `DECLARE_...` macros in the header file. + +- And `ARCH_OP_GROUP_...` is missing or not generated. Build error like: + ``` + AArch64InstPrinter.c:2249:42: error: ‘AArch64_OP_GROUP_MatrixIndex_8’ undeclared (first use in this function); did you mean ‘AArch64_OP_GROUP_MatrixIndex’? + 2249 | add_cs_detail(MI, CONCAT(AArch64_OP_GROUP_MatrixIndex, Scale), \ + ``` + Fix it by adding the postfix `MatrixIndex_8` to one of the exception lists in `PrinterCapstone::printOpPrintGroupEnum()`. + +- If the mapping files miss operand types or access information, then the `.td` files are incomplete (happens surprisingly often). +You need to search for the instruction or operands with missing or incorrect values and fix them. + ``` + Wrong access attributes for: + - Registers, Immediates: The instructions defines "out" and "in" operands incorrectly. + - Memory: The "mayLoad" or "mayStore" variable is not set for the instruction. + + Operand type is invalid: + - The "OperandType" variable is unset for this operand type. + ``` + +- If certain target features (e.g. architecture extensions) were removed from LLVM or you want to add your own, +checkout [DeprecatedFeatures.md](DeprecatedFeatures.md). diff --git a/compare_tblgen_output.sh b/compare_tblgen_output.sh new file mode 100755 index 000000000000..5b36f224a48b --- /dev/null +++ b/compare_tblgen_output.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Compare the generated tables of our refactored TableGen to the original ones. +archs="AArch64 ARM PPC" +file_names="GenAsmWriter GenDisassemblerTables GenInstrInfo GenRegisterInfo GenSubtargetInfo GenSystemOperands" +release="18" +repo_root=$(git rev-parse --show-toplevel) +gen_dir="$repo_root/output_tmp" + +# Requires that LLVM tables were generated before. +echo "Diff LLVM files (blanks and empty lines are ignored)" +for arch in $archs; do + for file_name in $file_names; do + out_CPP_LLVM="$gen_dir/$arch$file_name""_CPP_LLVM.inc" + out_CPP_CS="$gen_dir/$arch$file_name""_CPP_CS.inc" + + if [ ! -e "$out_CPP_CS" ]; then + continue + fi + + diff -w -B "$out_CPP_LLVM" "$out_CPP_CS" > /dev/null + if [ $? -ne 0 ]; then + echo "The following files mismatch: $out_CPP_LLVM $out_CPP_CS" + mismatch="true" + fi + done +done diff --git a/gen_cs_tables.sh b/gen_cs_tables.sh new file mode 100755 index 000000000000..1fed27b93321 --- /dev/null +++ b/gen_cs_tables.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Compare the generated tables of our refactored TableGen to the original ones. + +# We skip Alpha because it is no longer supported by upstream LLVM +archs="AArch64 ARM PPC" +file_names="GenAsmWriter GenDisassemblerTables GenInstrInfo GenRegisterInfo GenSubtargetInfo GenSystemOperands" +release="18" +repo_root=$(git rev-parse --show-toplevel) +gen_dir="$repo_root/output_tmp" + +if [ ! -d $gen_dir ]; then + mkdir "$gen_dir" +fi + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + echo "$0 [--rebuild]" + echo "\trebuild - Rebuild Capstone llvm-tblgen after upstream LLVM tables were generated." + exit 0 +fi + +gen_all() +{ + cd $gen_dir + table_type="$1" + postfix="$2" + echo "Generate inc files with $table_type as $postfix" + + for arch in $archs; do + for file_name in $file_names; do + out_file="$arch$file_name""_$postfix.inc" + if [ "$arch" = "PPC" ]; then + arch_include="$repo_root/llvm/lib/Target/PowerPC" + else + arch_include="$repo_root/llvm/lib/Target/$arch" + fi + + echo "\t$arch - $out_file" + + if [ $file_name = "GenAsmWriter" ]; then + $repo_root/build/bin/llvm-tblgen --gen-asm-writer "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenDisassemblerTables" ]; then + $repo_root/build/bin/llvm-tblgen --gen-disassembler "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenInstrInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-instr-info "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenRegisterInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-register-info "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenSubtargetInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-subtarget "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenSystemOperands" ]; then + if [ $arch != "PPC" ] ; then + $repo_root/build/bin/llvm-tblgen --gen-searchable-tables "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + fi + else + echo "File $file_name not handled." + exit 1 + fi + if [ $? -ne 0 ]; then + echo "Generation of $out_file failed." + return 0 + fi + done + done + + cd .. + return 1 +} + +# Generate patched +if gen_all "--printerLang=C++" "CPP_CS"; then + exit 1 +fi + +if gen_all "--printerLang=CCS" "C_CS"; then + exit 1 +fi + diff --git a/gen_llvm_tables.sh b/gen_llvm_tables.sh new file mode 100755 index 000000000000..c5014027b37e --- /dev/null +++ b/gen_llvm_tables.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +archs="AArch64 ARM PPC" +file_names="GenAsmWriter GenDisassemblerTables GenInstrInfo GenRegisterInfo GenSubtargetInfo GenSystemOperands" +release="18" +repo_root=$(git rev-parse --show-toplevel) +gen_dir="$repo_root/output_tmp" + +if [ ! -d $gen_dir ]; then + mkdir "$gen_dir" +fi + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + echo "$0 [--rebuild]" + echo "\trebuild - Rebuild Capstone llvm-tblgen after upstream LLVM tables were generated." + exit 0 +fi + +gen_all() +{ + cd $gen_dir + table_type="$1" + postfix="$2" + echo "Generate inc files with $table_type as $postfix" + + for arch in $archs; do + for file_name in $file_names; do + out_file="$arch$file_name""_$postfix.inc" + if [ "$arch" = "PPC" ]; then + arch_include="$repo_root/llvm/lib/Target/PowerPC" + else + arch_include="$repo_root/llvm/lib/Target/$arch" + fi + + echo "\t$arch - $out_file" + + if [ $file_name = "GenAsmWriter" ]; then + $repo_root/build/bin/llvm-tblgen --gen-asm-writer "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenDisassemblerTables" ]; then + $repo_root/build/bin/llvm-tblgen --gen-disassembler "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenInstrInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-instr-info "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenRegisterInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-register-info "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenSubtargetInfo" ]; then + $repo_root/build/bin/llvm-tblgen --gen-subtarget "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + elif [ $file_name = "GenSystemOperands" ]; then + if [ $arch != "PPC" ] ; then + $repo_root/build/bin/llvm-tblgen --gen-searchable-tables "$table_type" -o "$out_file" -I "$arch_include" -I "$repo_root/llvm/include" "$arch_include/$arch.td" + fi + else + echo "File $file_name not handled." + exit 1 + fi + if [ $? -ne 0 ]; then + echo "Generation of $out_file failed." + return 0 + fi + done + done + + cd .. + return 1 +} + +if gen_all "--color" "CPP_LLVM"; then + exit 1 +fi diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h index 8c315d255bb7..70a9039c4f24 100644 --- a/llvm/include/llvm/Support/Compiler.h +++ b/llvm/include/llvm/Support/Compiler.h @@ -151,7 +151,7 @@ #define LLVM_ATTRIBUTE_USED #endif -#if defined(__clang__) +#if defined(__clang__) && !defined(__INTELLISENSE__) #define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX))) #else #define LLVM_DEPRECATED(MSG, FIX) [[deprecated(MSG)]] diff --git a/llvm/include/llvm/TableGen/StringMatcher.h b/llvm/include/llvm/TableGen/StringMatcher.h index 795b7a6d41dc..a83e3e9ad731 100644 --- a/llvm/include/llvm/TableGen/StringMatcher.h +++ b/llvm/include/llvm/TableGen/StringMatcher.h @@ -13,6 +13,7 @@ #ifndef LLVM_TABLEGEN_STRINGMATCHER_H #define LLVM_TABLEGEN_STRINGMATCHER_H +#include "PrinterTypes.h" #include "llvm/ADT/StringRef.h" #include #include @@ -35,18 +36,26 @@ class StringMatcher { StringRef StrVariableName; const std::vector &Matches; raw_ostream &OS; + PrinterLanguage PL; public: StringMatcher(StringRef strVariableName, const std::vector &matches, raw_ostream &os) - : StrVariableName(strVariableName), Matches(matches), OS(os) {} + : StrVariableName(strVariableName), Matches(matches), OS(os), PL(PRINTER_LANG_CPP) {} + StringMatcher(StringRef strVariableName, + const std::vector &matches, raw_ostream &os, PrinterLanguage PL) + : StrVariableName(strVariableName), Matches(matches), OS(os), PL(PL) {} void Emit(unsigned Indent = 0, bool IgnoreDuplicates = false) const; + void EmitCPP(unsigned Indent = 0, bool IgnoreDuplicates = false) const; private: bool EmitStringMatcherForChar(const std::vector &Matches, unsigned CharNo, unsigned IndentCount, bool IgnoreDuplicates) const; + bool EmitStringMatcherForCharCPP(const std::vector &Matches, + unsigned CharNo, unsigned IndentCount, + bool IgnoreDuplicates) const; }; } // end namespace llvm diff --git a/llvm/include/llvm/TableGen/StringToOffsetTable.h b/llvm/include/llvm/TableGen/StringToOffsetTable.h index 66bcc81c94b5..373cb291500a 100644 --- a/llvm/include/llvm/TableGen/StringToOffsetTable.h +++ b/llvm/include/llvm/TableGen/StringToOffsetTable.h @@ -9,10 +9,12 @@ #ifndef LLVM_TABLEGEN_STRINGTOOFFSETTABLE_H #define LLVM_TABLEGEN_STRINGTOOFFSETTABLE_H +#include "PrinterTypes.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" #include namespace llvm { @@ -22,10 +24,14 @@ namespace llvm { /// It can then output this string blob and use indexes into the string to /// reference each piece. class StringToOffsetTable { + PrinterLanguage PL; StringMap StringOffset; std::string AggregateString; public: + StringToOffsetTable() : PL(PRINTER_LANG_CPP) {}; + StringToOffsetTable(PrinterLanguage PL) : PL(PL) {}; + bool Empty() const { return StringOffset.empty(); } unsigned GetOrAddStringOffset(StringRef Str, bool appendZero = true) { @@ -42,6 +48,16 @@ class StringToOffsetTable { } void EmitString(raw_ostream &O) { + switch(PL) { + default: + PrintFatalNote("No StringToOffsetTable method defined to emit the selected language.\n"); + case PRINTER_LANG_CPP: + EmitStringCPP(O); + break; + } + } + + void EmitStringCPP(raw_ostream &O) { // Escape the string. SmallString<256> Str; raw_svector_ostream(Str).write_escaped(AggregateString); diff --git a/llvm/lib/Support/BLAKE3/CMakeLists.txt b/llvm/lib/Support/BLAKE3/CMakeLists.txt index cb4f840461f7..38675c83c67d 100644 --- a/llvm/lib/Support/BLAKE3/CMakeLists.txt +++ b/llvm/lib/Support/BLAKE3/CMakeLists.txt @@ -10,6 +10,7 @@ if (LLVM_DISABLE_ASSEMBLY_FILES) else() set(CAN_USE_ASSEMBLER TRUE) endif() +set(CAN_USE_ASSEMBLER FALSE) macro(disable_blake3_x86_simd) add_compile_definitions(BLAKE3_NO_AVX512 BLAKE3_NO_AVX2 BLAKE3_NO_SSE41 BLAKE3_NO_SSE2) diff --git a/llvm/lib/TableGen/CMakeLists.txt b/llvm/lib/TableGen/CMakeLists.txt index c550840f147d..1db225125bd5 100644 --- a/llvm/lib/TableGen/CMakeLists.txt +++ b/llvm/lib/TableGen/CMakeLists.txt @@ -6,7 +6,6 @@ add_llvm_component_library(LLVMTableGen Parser.cpp Record.cpp SetTheory.cpp - StringMatcher.cpp TableGenBackend.cpp TableGenBackendSkeleton.cpp TGLexer.cpp diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td index 14e315534570..7b20216c85d0 100644 --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -669,6 +669,7 @@ class AIldr_ex_or_acq opcod, bits<2> opcod2, dag oops, dag iops, InstrIt let Inst{11-10} = 0b11; let Inst{9-8} = opcod2; let Inst{7-0} = 0b10011111; + let mayLoad = 1; } class AIstr_ex_or_rel opcod, bits<2> opcod2, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> @@ -684,6 +685,7 @@ class AIstr_ex_or_rel opcod, bits<2> opcod2, dag oops, dag iops, InstrIt let Inst{9-8} = opcod2; let Inst{7-4} = 0b1001; let Inst{3-0} = Rt; + let mayStore = 1; } // Atomic load/store instructions class AIldrex opcod, dag oops, dag iops, InstrItinClass itin, @@ -695,6 +697,7 @@ class AIstrex opcod, dag oops, dag iops, InstrItinClass itin, : AIstr_ex_or_rel { bits<4> Rd; let Inst{15-12} = Rd; + let mayLoad = 1; } // Exclusive load/store instructions @@ -792,6 +795,8 @@ class AI2ldstidx op, bit op20, dag oops, dag iops, Format f, let Inst{11-8} = addr{7-4}; // imm7_4/zero let Inst{7-4} = op; let Inst{3-0} = addr{3-0}; // imm3_0/Rm + let mayLoad = op20; + let mayStore = 0; let DecoderMethod = "DecodeAddrMode3Instruction"; } @@ -881,6 +891,8 @@ class AI3ldstidx op, bit op20, bit isPre, dag oops, dag iops, let Inst{20} = op20; // L bit let Inst{15-12} = Rt; // Rt let Inst{7-4} = op; + let mayLoad = op20; + let mayStore = !if(op20, 0, 1); } // FIXME: Merge with the above class when addrmode2 gets used for LDR, LDRB @@ -903,6 +915,8 @@ class AI3ldstidxT op, bit isLoad, dag oops, dag iops, let Inst{19-16} = addr; // Rn let Inst{15-12} = Rt; // Rt let Inst{7-4} = op; + let mayLoad = isLoad; + let mayStore = !if(isLoad, 0, 1); } // stores @@ -924,6 +938,7 @@ class AI3str op, dag oops, dag iops, Format f, InstrItinClass itin, let Inst{7-4} = op; let Inst{3-0} = addr{3-0}; // imm3_0/Rm let DecoderMethod = "DecodeAddrMode3Instruction"; + let mayStore = 1; } // addrmode4 instructions diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td index 812b5730875d..c586bd8b3659 100644 --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -2828,6 +2828,7 @@ def ERET : ABI<0b0001, (outs), (ins), NoItinerary, "eret", "", []>, // Load +let mayLoad = 1 in { defm LDR : AI_ldr1<0, "ldr", IIC_iLoad_r, IIC_iLoad_si, load>; defm LDRB : AI_ldr1nopc<1, "ldrb", IIC_iLoad_bh_r, IIC_iLoad_bh_si, @@ -2850,6 +2851,7 @@ def LDRcp : AI2ldst<0b010, 1, 0, (outs GPR:$Rt), (ins addrmode_imm12:$addr), let Inst{11-0} = addr{11-0}; // imm12 } +let mayLoad = 1 in { // Loads with zero extension def LDRH : AI3ld<0b1011, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_r, "ldrh", "\t$Rt, $addr", @@ -2863,6 +2865,7 @@ def LDRSH : AI3ld<0b1111, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, def LDRSB : AI3ld<0b1101, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_r, "ldrsb", "\t$Rt, $addr", [(set GPR:$Rt, (sextloadi8 addrmode3:$addr))]>; +} // mayLoad = 1 let mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 in { // Load doubleword @@ -2879,6 +2882,7 @@ def LOADDUAL : ARMPseudoInst<(outs GPRPairOp:$Rt), (ins addrmode3:$addr), } } +let mayLoad = 1 in { def LDA : AIldracq<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr), NoItinerary, "lda", "\t$Rt, $addr", []>; def LDAB : AIldracq<0b10, (outs GPR:$Rt), (ins addr_offset_none:$addr), @@ -3140,9 +3144,12 @@ def LDRConstPool : ARMAsmPseudo<"ldr${q} $Rt, $immediate", (ins const_pool_asm_imm:$immediate, pred:$q), (outs GPR:$Rt)>; +} // mayLoad = 1 +} // mayLoad = 1 // Store +let mayStore = 1 in { // Stores with truncate def STRH : AI3str<0b1011, (outs), (ins GPR:$Rt, addrmode3:$addr), StMiscFrm, IIC_iStore_bh_r, "strh", "\t$Rt, $addr", @@ -3236,6 +3243,7 @@ let mayStore = 1, hasSideEffects = 0 in { defm STR : AI2_stridx<0, "str", IIC_iStore_iu, IIC_iStore_ru>; defm STRB : AI2_stridx<1, "strb", IIC_iStore_bh_iu, IIC_iStore_bh_ru>; } +} // mayStore = 1 def : ARMPat<(post_store GPR:$Rt, addr_offset_none:$addr, am2offset_reg:$offset), @@ -3254,6 +3262,7 @@ def : ARMPat<(post_truncsti8 GPR:$Rt, addr_offset_none:$addr, (STRB_POST_IMM GPR:$Rt, addr_offset_none:$addr, am2offset_imm:$offset)>; +let mayStore = 1 in { // Pseudo-instructions for pattern matching the pre-indexed stores. We can't // put the patterns on the instruction definitions directly as ISel wants // the address base and offset to be separate operands, not a single @@ -3470,6 +3479,7 @@ def STLB : AIstrrel<0b10, (outs), (ins GPR:$Rt, addr_offset_none:$addr), NoItinerary, "stlb", "\t$Rt, $addr", []>; def STLH : AIstrrel<0b11, (outs), (ins GPR:$Rt, addr_offset_none:$addr), NoItinerary, "stlh", "\t$Rt, $addr", []>; +} // mayStore = 1 //===----------------------------------------------------------------------===// // Load / store multiple Instructions. @@ -5601,15 +5611,19 @@ multiclass LdSt2Cop pattern> { } } +let mayLoad = 1 in { defm LDC : LdStCop <1, 0, "ldc", [(int_arm_ldc timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm LDCL : LdStCop <1, 1, "ldcl", [(int_arm_ldcl timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm LDC2 : LdSt2Cop<1, 0, "ldc2", [(int_arm_ldc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; defm LDC2L : LdSt2Cop<1, 1, "ldc2l", [(int_arm_ldc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; +} +let mayStore = 1 in { defm STC : LdStCop <0, 0, "stc", [(int_arm_stc timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm STCL : LdStCop <0, 1, "stcl", [(int_arm_stcl timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm STC2 : LdSt2Cop<0, 0, "stc2", [(int_arm_stc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; defm STC2L : LdSt2Cop<0, 1, "stc2l", [(int_arm_stc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; +} } // DecoderNamespace = "CoProc" diff --git a/llvm/lib/Target/ARM/ARMInstrMVE.td b/llvm/lib/Target/ARM/ARMInstrMVE.td index 12c3968b9cec..ae8cf1ce6503 100644 --- a/llvm/lib/Target/ARM/ARMInstrMVE.td +++ b/llvm/lib/Target/ARM/ARMInstrMVE.td @@ -6186,8 +6186,8 @@ class MVE_VLDRSTR_base, Sched<[WriteVLD4]>; } // mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 +let mayLoad = 1 in { // Classes for VLD*LN pseudo-instructions with multi-register operands. // These are expanded to real instructions after register allocation. class VLDQLNPseudo @@ -1072,6 +1073,7 @@ def VLD1LNd32 : VLD1LN32<0b1000, {?,0,?,?}, "32", v2i32, load> { def VLD1LNq8Pseudo : VLD1QLNPseudo; def VLD1LNq16Pseudo : VLD1QLNPseudo; def VLD1LNq32Pseudo : VLD1QLNPseudo; +} // mayLoad = 1 let Predicates = [HasNEON] in { def : Pat<(vector_insert (v4f16 DPR:$src), @@ -1366,6 +1368,7 @@ def VLD4LNq32Pseudo_UPD : VLDQQQQLNWBPseudo, Sched<[WriteVLD2]>; } // mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 +let mayLoad = 1 in { // VLD1DUP : Vector Load (single element to all lanes) class VLD1DUP op7_4, string Dt, ValueType Ty, PatFrag LoadOp, Operand AddrMode> @@ -1385,12 +1388,14 @@ def VLD1DUPd16 : VLD1DUP<{0,1,0,?}, "16", v4i16, extloadi16, addrmode6dupalign16>; def VLD1DUPd32 : VLD1DUP<{1,0,0,?}, "32", v2i32, load, addrmode6dupalign32>; +} // mayLoad = 1 let Predicates = [HasNEON] in { def : Pat<(v2f32 (ARMvdup (f32 (load addrmode6dup:$addr)))), (VLD1DUPd32 addrmode6:$addr)>; } +let mayLoad = 1 in { class VLD1QDUP op7_4, string Dt, ValueType Ty, PatFrag LoadOp, Operand AddrMode> : NLdSt<1, 0b10, 0b1100, op7_4, (outs VecListDPairAllLanes:$Vd), @@ -1409,6 +1414,7 @@ def VLD1DUPq16 : VLD1QDUP<{0,1,1,?}, "16", v8i16, extloadi16, addrmode6dupalign16>; def VLD1DUPq32 : VLD1QDUP<{1,0,1,?}, "32", v4i32, load, addrmode6dupalign32>; +} // mayLoad = 1 let Predicates = [HasNEON] in { def : Pat<(v4f32 (ARMvdup (f32 (load addrmode6dup:$addr)))), @@ -2122,6 +2128,7 @@ def VST4q32oddPseudo_UPD : VSTQQQQWBPseudo, Sched<[WriteVST4]>; } // mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 +let mayStore = 1 in { // Classes for VST*LN pseudo-instructions with multi-register operands. // These are expanded to real instructions after register allocation. class VSTQLNPseudo @@ -2182,6 +2189,7 @@ def VST1LNd32 : VST1LN<0b1000, {?,0,?,?}, "32", v2i32, store, extractelt, def VST1LNq8Pseudo : VST1QLNPseudo; def VST1LNq16Pseudo : VST1QLNPseudo; def VST1LNq32Pseudo : VST1QLNPseudo; +} // mayStore = 1 let Predicates = [HasNEON] in { def : Pat<(store (extractelt (v2f32 DPR:$src), imm:$lane), addrmode6:$addr), @@ -2195,6 +2203,7 @@ def : Pat<(store (extractelt (v8f16 QPR:$src), imm:$lane), addrmode6:$addr), (VST1LNq16Pseudo addrmode6:$addr, QPR:$src, imm:$lane)>; } +let mayStore = 1 in { // ...with address register writeback: class VST1LNWB op11_8, bits<4> op7_4, string Dt, ValueType Ty, PatFrag StoreOp, SDNode ExtractOp, Operand AdrMode> @@ -2232,6 +2241,7 @@ def VST1LNd32_UPD : VST1LNWB<0b1000, {?,0,?,?}, "32", v2i32, post_store, def VST1LNq8Pseudo_UPD : VST1QLNWBPseudo; def VST1LNq16Pseudo_UPD : VST1QLNWBPseudo; def VST1LNq32Pseudo_UPD : VST1QLNWBPseudo; +} // mayStore = 1 let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in { @@ -8153,6 +8163,7 @@ def : NEONInstAlias<"vand${p}.i32 $Vd, $imm", (VBICiv4i32 QPR:$Vd, nImmSplatNotI32:$imm, pred:$p)>; +let mayLoad = 1 in { // VLD1 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VLD1LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vld1${p}", ".8", "$list, $addr", @@ -8189,8 +8200,9 @@ def VLD1LNdWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vld1${p}", ".32", "$list, $addr, $Rm", (ins VecListOneDWordIndexed:$list, addrmode6align32:$addr, rGPR:$Rm, pred:$p)>; +} // mayLoad = 1 - +let mayStore = 1 in { // VST1 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VST1LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vst1${p}", ".8", "$list, $addr", @@ -8227,7 +8239,9 @@ def VST1LNdWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vst1${p}", ".32", "$list, $addr, $Rm", (ins VecListOneDWordIndexed:$list, addrmode6align32:$addr, rGPR:$Rm, pred:$p)>; +} // mayStore = 1 +let mayLoad = 1 in { // VLD2 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VLD2LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vld2${p}", ".8", "$list, $addr", @@ -8285,8 +8299,9 @@ def VLD2LNqWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vld2${p}", ".32", "$list, $addr, $Rm", (ins VecListTwoQWordIndexed:$list, addrmode6align64:$addr, rGPR:$Rm, pred:$p)>; +} // mayLoad = 1 - +let mayStore = 1 in { // VST2 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VST2LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vst2${p}", ".8", "$list, $addr", @@ -8345,7 +8360,9 @@ def VST2LNqWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vst2${p}", ".32", "$list, $addr, $Rm", (ins VecListTwoQWordIndexed:$list, addrmode6align64:$addr, rGPR:$Rm, pred:$p)>; +} // mayStore = 1 +let mayLoad = 1 in { // VLD3 all-lanes pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VLD3DUPdAsm_8 : NEONDataTypeAsmPseudoInst<"vld3${p}", ".8", "$list, $addr", @@ -8534,7 +8551,9 @@ def VLD3qWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vld3${p}", ".32", "$list, $addr, $Rm", (ins VecListThreeQ:$list, addrmode6align64:$addr, rGPR:$Rm, pred:$p)>; +} // mayLoad = 1 +let mayStore = 1 in { // VST3 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VST3LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vst3${p}", ".8", "$list, $addr", @@ -8653,7 +8672,9 @@ def VST3qWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vst3${p}", ".32", "$list, $addr, $Rm", (ins VecListThreeQ:$list, addrmode6align64:$addr, rGPR:$Rm, pred:$p)>; +} // mayStore = 1 +let mayLoad = 1 in { // VLD4 all-lanes pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VLD4DUPdAsm_8 : NEONDataTypeAsmPseudoInst<"vld4${p}", ".8", "$list, $addr", @@ -8856,7 +8877,9 @@ def VLD4qWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vld4${p}", ".32", "$list, $addr, $Rm", (ins VecListFourQ:$list, addrmode6align64or128or256:$addr, rGPR:$Rm, pred:$p)>; +} // mayLoad = 1 +let mayStore = 1 in { // VST4 single-lane pseudo-instructions. These need special handling for // the lane index that an InstAlias can't handle, so we use these instead. def VST4LNdAsm_8 : NEONDataTypeAsmPseudoInst<"vst4${p}", ".8", "$list, $addr", @@ -8987,6 +9010,7 @@ def VST4qWB_register_Asm_32 : NEONDataTypeAsmPseudoInst<"vst4${p}", ".32", "$list, $addr, $Rm", (ins VecListFourQ:$list, addrmode6align64or128or256:$addr, rGPR:$Rm, pred:$p)>; +} // mayStore = 1 // VMOV/VMVN takes an optional datatype suffix defm : NEONDTAnyInstAlias<"vmov${p}", "$Vd, $Vm", diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td index be0ca964d3f9..e8126d8c132e 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -688,6 +688,7 @@ def tTRAP : TI<(outs), (ins), IIC_Br, // PC-relative loads need to be matched first as constant pool accesses need to // always be PC-relative. We do this using AddedComplexity, as the pattern is // simpler than the patterns of the other load instructions. +let mayLoad = 1 in { let canFoldAsLoad = 1, isReMaterializable = 1, AddedComplexity = 10 in def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i, "ldr", "\t$Rt, $addr", @@ -698,6 +699,7 @@ def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i, bits<8> addr; let Inst{10-8} = Rt; let Inst{7-0} = addr; + let mayLoad = 1; } // SP-relative loads should be matched before standard immediate-offset loads as @@ -711,6 +713,7 @@ def tLDRspi : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_sp:$addr), IIC_iLoad_i, bits<8> addr; let Inst{10-8} = Rt; let Inst{7-0} = addr; + let mayLoad = 1; } // Loads: reg/reg and reg/imm5 @@ -784,8 +787,10 @@ def tLDRSH : // A8.6.84 AddrModeT1_2, IIC_iLoad_bh_r, "ldrsh", "\t$Rt, $addr", [(set tGPR:$Rt, (sextloadi16 t_addrmode_rr_sext:$addr))]>, Sched<[WriteLd]>; +} // mayLoad = 1 +let mayStore = 1 in { def tSTRspi : T1pIs<(outs), (ins tGPR:$Rt, t_addrmode_sp:$addr), IIC_iStore_i, "str", "\t$Rt, $addr", [(store tGPR:$Rt, t_addrmode_sp:$addr)]>, @@ -794,6 +799,7 @@ def tSTRspi : T1pIs<(outs), (ins tGPR:$Rt, t_addrmode_sp:$addr), IIC_iStore_i, bits<8> addr; let Inst{10-8} = Rt; let Inst{7-0} = addr; + let mayStore = 1; } // A8.6.194 & A8.6.192 @@ -813,6 +819,7 @@ defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rr, t_addrmode_is2, AddrModeT1_2, IIC_iStore_bh_r, IIC_iStore_bh_i, "strh", truncstorei16>, Sched<[WriteST]>; +} // mayStore = 1 //===----------------------------------------------------------------------===// @@ -1500,7 +1507,7 @@ def tLEApcrelJT : tPseudoInst<(outs tGPR:$Rd), // Thumb-1 doesn't have the TBB or TBH instructions, but we can synthesize them // and make use of the same compressed jump table format as Thumb-2. -let Size = 2, isBranch = 1, isTerminator = 1, isBarrier = 1, +let mayLoad = 1, Size = 2, isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, isNotDuplicable = 1 in { def tTBB_JT : tPseudoInst<(outs), (ins tGPRwithpc:$base, tGPR:$index, i32imm:$jt, i32imm:$pclbl), 0, diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index acd46e8093aa..795304ab28cf 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -1591,6 +1591,7 @@ def t2LDRSH_POST : T2Ipostldst<1, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), // F5.1.72 LDR (immediate) T4 // .w suffixes; Constraints can't be used on t2InstAlias to describe // "$Rn = $Rn_wb" on POST or "$addr.base = $Rn_wb" on PRE. +let mayLoad = 1 in { def t2LDR_PRE_imm : t2AsmPseudo<"ldr${p}.w $Rt, $addr!", (ins GPR:$Rt, t2addrmode_imm8_pre:$addr, pred:$p)>; def t2LDR_POST_imm : t2AsmPseudo<"ldr${p}.w $Rt, $Rn, $imm", @@ -1692,13 +1693,16 @@ def t2LDAB : T2Ildacq<0b1101, 0b00, (outs rGPR:$Rt), def t2LDAH : T2Ildacq<0b1101, 0b01, (outs rGPR:$Rt), (ins addr_offset_none:$addr), "ldah", "\t$Rt, $addr", []>, Sched<[WriteLd]>; +} // mayLoad = 1 +let mayStore = 1 in { // Store defm t2STR :T2I_st<0b10,"str", IIC_iStore_i, IIC_iStore_si, GPR, store>; defm t2STRB:T2I_st<0b00,"strb", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, truncstorei8>; defm t2STRH:T2I_st<0b01,"strh", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, truncstorei16>; +} // Store doubleword let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in @@ -1733,6 +1737,7 @@ def t2STRB_PRE : T2Ipreldst<0, 0b00, 0, 1, (outs GPRnopc:$Rn_wb), Sched<[WriteST]>; } // mayStore = 1, hasSideEffects = 0 +let mayStore = 1 in { def t2STR_POST : T2Ipostldst<0, 0b10, 0, 0, (outs GPRnopc:$Rn_wb), (ins GPRnopc:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), @@ -1847,6 +1852,7 @@ class T2IstT type, string opc, InstrItinClass ii> def t2STRT : T2IstT<0b10, "strt", IIC_iStore_i>; def t2STRBT : T2IstT<0b00, "strbt", IIC_iStore_bh_i>; def t2STRHT : T2IstT<0b01, "strht", IIC_iStore_bh_i>; +} // mayStore = 1 // ldrd / strd pre / post variants @@ -1879,6 +1885,7 @@ def t2STRD_POST : T2Ii8s4post<0, 1, 0, (outs GPR:$wb), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>, Sched<[WriteST]>; +let mayStore = 1 in { class T2Istrrel bit54, dag oops, dag iops, string opc, string asm, list pattern> : Thumb2I; def t2STLH : T2Istrrel<0b01, (outs), (ins rGPR:$Rt, addr_offset_none:$addr), "stlh", "\t$Rt, $addr", []>; +} // mayStore = 1 // T2Ipl (Preload Data/Instruction) signals the memory system of possible future // data/instruction access. @@ -1972,9 +1980,11 @@ multiclass T2Ipl write, bits<1> instr, string opc> { } } +let mayLoad = 1 in { defm t2PLD : T2Ipl<0, 0, "pld">, Requires<[IsThumb2]>; defm t2PLDW : T2Ipl<1, 0, "pldw">, Requires<[IsThumb2,HasV7,HasMP]>; defm t2PLI : T2Ipl<0, 1, "pli">, Requires<[IsThumb2,HasV7]>; +} // mayLoad = 1 // PLD/PLDW/PLI aliases w/ the optional .w suffix def : t2InstAlias<"pld${p}.w\t$addr", @@ -2006,6 +2016,7 @@ def : InstAlias<"pli${p}.w\t$addr", // pci variant is very similar to i12, but supports negative offsets // from the PC. Only PLD and PLI have pci variants (not PLDW) +let mayLoad = 1 in { class T2Iplpci inst, string opc> : T2Ipc<(outs), (ins t2ldrlabel:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload (ARMWrapper tconstpool:$addr), @@ -2025,6 +2036,7 @@ class T2Iplpci inst, string opc> : T2Ipc<(outs), (ins t2ldrlabel:$addr), def t2PLDpci : T2Iplpci<0, "pld">, Requires<[IsThumb2]>; def t2PLIpci : T2Iplpci<1, "pli">, Requires<[IsThumb2,HasV7]>; +} // mayLoad = 1 def : t2InstAlias<"pld${p}.w $addr", (t2PLDpci t2ldrlabel:$addr, pred:$p)>; @@ -2048,6 +2060,7 @@ def : InstAlias<"pli${p}.w $addr", // Load / store multiple Instructions. // +let mayLoad = 1 in multiclass thumb2_ld_mult { def IA : @@ -3969,6 +3982,7 @@ def t2BR_JT : t2basePseudoInst<(outs), Sched<[WriteBr]>; // FIXME: Add a case that can be predicated. +let mayLoad = 1 in { def t2TBB_JT : t2PseudoInst<(outs), (ins GPR:$base, GPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>, Sched<[WriteBr]>; @@ -4002,6 +4016,7 @@ def t2TBH : T2I<(outs), (ins (addrmode_tbh $Rn, $Rm):$addr), IIC_Br, let DecoderMethod = "DecodeThumbTableBranch"; } +} // mayLoad } // isNotDuplicable, isIndirectBranch } // isBranch, isTerminator, isBarrier @@ -4465,16 +4480,20 @@ multiclass t2LdStCop op31_28, bit load, bit Dbit, string asm, list } let DecoderNamespace = "Thumb2CoProc" in { +let mayLoad = 1 in { defm t2LDC : t2LdStCop<0b1110, 1, 0, "ldc", [(int_arm_ldc timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm t2LDCL : t2LdStCop<0b1110, 1, 1, "ldcl", [(int_arm_ldcl timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm t2LDC2 : t2LdStCop<0b1111, 1, 0, "ldc2", [(int_arm_ldc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; defm t2LDC2L : t2LdStCop<0b1111, 1, 1, "ldc2l", [(int_arm_ldc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; +} +let mayStore = 1 in { defm t2STC : t2LdStCop<0b1110, 0, 0, "stc", [(int_arm_stc timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm t2STCL : t2LdStCop<0b1110, 0, 1, "stcl", [(int_arm_stcl timm:$cop, timm:$CRd, addrmode5:$addr)]>; defm t2STC2 : t2LdStCop<0b1111, 0, 0, "stc2", [(int_arm_stc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; defm t2STC2L : t2LdStCop<0b1111, 0, 1, "stc2l", [(int_arm_stc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; } +} //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td index 55d3efbd9b9a..c69f14068189 100644 --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -149,7 +149,7 @@ def fbits16 : Operand { // Load / store Instructions. // -let canFoldAsLoad = 1, isReMaterializable = 1 in { +let mayLoad = 1, canFoldAsLoad = 1, isReMaterializable = 1 in { def VLDRD : ADI5<0b1101, 0b01, (outs DPR:$Dd), (ins addrmode5:$addr), IIC_fpLoad64, "vldr", "\t$Dd, $addr", @@ -171,7 +171,7 @@ def VLDRH : AHI5<0b1101, 0b01, (outs HPR:$Sd), (ins addrmode5fp16:$addr), [(set HPR:$Sd, (f16 (alignedload16 addrmode5fp16:$addr)))]>, Requires<[HasFPRegs16]>; -} // End of 'let canFoldAsLoad = 1, isReMaterializable = 1 in' +} // End of 'mayLoad = 1, let canFoldAsLoad = 1, isReMaterializable = 1 in' def : Pat<(bf16 (alignedload16 addrmode5fp16:$addr)), (VLDRH addrmode5fp16:$addr)> { @@ -186,6 +186,7 @@ def : Pat<(bf16 (alignedload16 t2addrmode_imm12:$addr)), let Predicates = [HasNoFPRegs16, IsThumb]; } +let mayStore = 1 in { def VSTRD : ADI5<0b1101, 0b00, (outs), (ins DPR:$Dd, addrmode5:$addr), IIC_fpStore64, "vstr", "\t$Dd, $addr", [(alignedstore32 (f64 DPR:$Dd), addrmode5:$addr)]>, @@ -205,6 +206,7 @@ def VSTRH : AHI5<0b1101, 0b00, (outs), (ins HPR:$Sd, addrmode5fp16:$addr), IIC_fpStore16, "vstr", ".16\t$Sd, $addr", [(alignedstore16 (f16 HPR:$Sd), addrmode5fp16:$addr)]>, Requires<[HasFPRegs16]>; +} // mayStore = 1 def : Pat<(alignedstore16 (bf16 HPR:$Sd), addrmode5fp16:$addr), (VSTRH (bf16 HPR:$Sd), addrmode5fp16:$addr)> { @@ -234,6 +236,8 @@ multiclass vfp_ldst_mult { def grlenimm : Operand; def imm32 : Operand { let ParserMatchClass = ImmAsmOperand<"", 32, "">; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm1 : Operand, ImmLeaf(Imm);}]>{ let ParserMatchClass = UImmAsmOperand<1>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm2 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<2>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm2_plus1 : Operand, @@ -233,35 +236,43 @@ def uimm2_plus1 : Operand, let ParserMatchClass = UImmAsmOperand<2, "plus1">; let EncoderMethod = "getImmOpValueSub1"; let DecoderMethod = "decodeUImmOperand<2, 1>"; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm3 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<3>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm4 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<4>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm5 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<5>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm6 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<6>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm7 : Operand { let ParserMatchClass = UImmAsmOperand<7>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm8 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<8>; + let OperandType = "OPERAND_IMMEDIATE"; } class UImm12Operand : Operand, ImmLeaf (Imm);}]> { let DecoderMethod = "decodeUImmOperand<12>"; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm12 : UImm12Operand { @@ -275,21 +286,25 @@ def uimm12_ori : UImm12Operand { def uimm14 : Operand, ImmLeaf (Imm);}]> { let ParserMatchClass = UImmAsmOperand<14>; + let OperandType = "OPERAND_IMMEDIATE"; } def uimm15 : Operand, ImmLeaf (Imm);}]> { let ParserMatchClass = UImmAsmOperand<15>; + let OperandType = "OPERAND_IMMEDIATE"; } def simm5 : Operand { let ParserMatchClass = SImmAsmOperand<5>; let DecoderMethod = "decodeSImmOperand<5>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm8 : Operand { let ParserMatchClass = SImmAsmOperand<8>; let DecoderMethod = "decodeSImmOperand<8>"; + let OperandType = "OPERAND_IMMEDIATE"; } foreach I = [1, 2, 3] in { @@ -297,6 +312,7 @@ def simm8_lsl # I : Operand { let ParserMatchClass = SImmAsmOperand<8, "lsl" # I>; let EncoderMethod = "getImmOpValueAsr<" # I # ">"; let DecoderMethod = "decodeSImmOperand<8," # I # ">"; + let OperandType = "OPERAND_IMMEDIATE"; } } @@ -304,27 +320,32 @@ def simm9_lsl3 : Operand { let ParserMatchClass = SImmAsmOperand<9, "lsl3">; let EncoderMethod = "getImmOpValueAsr<3>"; let DecoderMethod = "decodeSImmOperand<9, 3>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm10 : Operand { let ParserMatchClass = SImmAsmOperand<10>; + let OperandType = "OPERAND_IMMEDIATE"; } def simm10_lsl2 : Operand { let ParserMatchClass = SImmAsmOperand<10, "lsl2">; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<10, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm11_lsl1 : Operand { let ParserMatchClass = SImmAsmOperand<11, "lsl1">; let EncoderMethod = "getImmOpValueAsr<1>"; let DecoderMethod = "decodeSImmOperand<11, 1>"; + let OperandType = "OPERAND_IMMEDIATE"; } class SImm12Operand : Operand, ImmLeaf (Imm);}]> { let DecoderMethod = "decodeSImmOperand<12>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm12 : SImm12Operand { @@ -342,6 +363,7 @@ def simm12_lu52id : SImm12Operand { def simm13 : Operand { let ParserMatchClass = SImmAsmOperand<13>; let DecoderMethod = "decodeSImmOperand<13>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm14_lsl2 : Operand, @@ -349,11 +371,13 @@ def simm14_lsl2 : Operand, let ParserMatchClass = SImmAsmOperand<14, "lsl2">; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<14, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm16 : Operand { let ParserMatchClass = SImmAsmOperand<16>; let DecoderMethod = "decodeSImmOperand<16>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm16_lsl2 : Operand, @@ -361,16 +385,19 @@ def simm16_lsl2 : Operand, let ParserMatchClass = SImmAsmOperand<16, "lsl2">; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<16, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm16_lsl2_br : Operand { let ParserMatchClass = SImmAsmOperand<16, "lsl2">; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<16, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } class SImm20Operand : Operand { let DecoderMethod = "decodeSImmOperand<20>"; + let OperandType = "OPERAND_IMMEDIATE"; } def simm20 : SImm20Operand { @@ -397,6 +424,7 @@ def simm21_lsl2 : Operand { let ParserMatchClass = SImmAsmOperand<21, "lsl2">; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<21, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } def SImm26OperandB: AsmOperandClass { @@ -412,6 +440,7 @@ def simm26_b : Operand { let ParserMatchClass = SImm26OperandB; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<26, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } def SImm26OperandBL: AsmOperandClass { @@ -427,6 +456,7 @@ def simm26_symbol : Operand { let ParserMatchClass = SImm26OperandBL; let EncoderMethod = "getImmOpValueAsr<2>"; let DecoderMethod = "decodeSImmOperand<26, 2>"; + let OperandType = "OPERAND_IMMEDIATE"; } // A 32-bit signed immediate with the lowest 16 bits zeroed, suitable for @@ -450,6 +480,7 @@ def BareSymbol : AsmOperandClass { // A bare symbol used in "PseudoLA_*" instructions. def bare_symbol : Operand { let ParserMatchClass = BareSymbol; + let OperandType = "OPERAND_IMMEDIATE"; } // Standalone (codegen-only) immleaf patterns. diff --git a/llvm/lib/Target/PowerPC/PPC.td b/llvm/lib/Target/PowerPC/PPC.td index 535616d33a80..1b58e76b6c85 100644 --- a/llvm/lib/Target/PowerPC/PPC.td +++ b/llvm/lib/Target/PowerPC/PPC.td @@ -338,6 +338,11 @@ def FeaturePredictableSelectIsExpensive : def FeatureFastMFLR : SubtargetFeature<"fast-MFLR", "HasFastMFLR", "true", "MFLR is a fast instruction">; +#define CAPSTONE_DEPR_FEATURE +include "PPCDeprecated.td" +#define CAPSTONE_PS_FEATURE +include "PPCInstrPairedSingle.td" + // Since new processors generally contain a superset of features of those that // came before them, the idea is to make implementations of new processors // less error prone and easier to read. @@ -673,6 +678,9 @@ def : ProcessorModel<"ppc64", G5Model, FeatureMFTB]>; def : ProcessorModel<"ppc64le", P8Model, ProcessorFeatures.P8Features>; +#define CAPSTONE_PS_PROCESSOR +include "PPCInstrPairedSingle.td" + //===----------------------------------------------------------------------===// // Calling Conventions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/PowerPC/PPCDeprecated.td b/llvm/lib/Target/PowerPC/PPCDeprecated.td new file mode 100644 index 000000000000..239d251aee67 --- /dev/null +++ b/llvm/lib/Target/PowerPC/PPCDeprecated.td @@ -0,0 +1,1510 @@ +//===- PPCDeprecated.td - The PowerPC deprecated Instr. and Regs --*- tablegen -*-===// +// +// 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 holds deprecated instructions and registers of the following PPC extensions: +// +// Book Q: QPX Architecture Definition. IBM (as updated in) 2011. +// +//===----------------------------------------------------------------------===// + +// +// QPX +// + +#ifndef INCLUDED_CAPSTONE_DEPR_FORMATS +#ifdef CAPSTONE_DEPR_FORMATS +#define INCLUDED_CAPSTONE_DEPR_FORMATS + +// Used for QPX +class AForm_4a opcode, bits<5> xo, dag OOL, dag IOL, string asmstr, + InstrItinClass itin, list pattern> + : AForm_1 { + let FRA = 0; + let FRC = 0; +} + +// Z23-Form (used by QPX) +class Z23Form_1 opcode, bits<8> xo, dag OOL, dag IOL, string asmstr, + InstrItinClass itin, list pattern> + : I { + bits<5> FRT; + bits<5> FRA; + bits<5> FRB; + bits<2> idx; + + let Pattern = pattern; + + bit RC = 0; // set by isRecordForm + + let Inst{6-10} = FRT; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-22} = idx; + let Inst{23-30} = xo; + let Inst{31} = RC; +} + +class Z23Form_2 opcode, bits<8> xo, dag OOL, dag IOL, string asmstr, + InstrItinClass itin, list pattern> + : Z23Form_1 { + let FRB = 0; +} + +class Z23Form_3 opcode, bits<8> xo, dag OOL, dag IOL, string asmstr, + InstrItinClass itin, list pattern> + : I { + bits<5> FRT; + bits<12> idx; + + let Pattern = pattern; + + bit RC = 0; // set by isRecordForm + + let Inst{6-10} = FRT; + let Inst{11-22} = idx; + let Inst{23-30} = xo; + let Inst{31} = RC; +} + +#endif // INCLUDED_CAPSTONE_DEPR_FORMATS +#endif // CAPSTONE_DEPR_FORMATS + +#ifndef INCLUDED_CAPSTONE_DEPR_INSTR +#ifdef CAPSTONE_DEPR_INSTR +#define INCLUDED_CAPSTONE_DEPR_INSTR + +def PPCqvfperm : SDNode<"PPCISD::QVFPERM", SDT_PPCqvfperm, []>; +def PPCqvgpci : SDNode<"PPCISD::QVGPCI", SDT_PPCqvgpci, []>; +def PPCqvaligni : SDNode<"PPCISD::QVALIGNI", SDT_PPCqvaligni, []>; +def PPCqvesplati : SDNode<"PPCISD::QVESPLATI", SDT_PPCqvesplati, []>; +def PPCqbflt : SDNode<"PPCISD::QBFLT", SDT_PPCqbflt, []>; +def PPCqvlfsb : SDNode<"PPCISD::QVLFSb", SDT_PPCqvlfsb, + [SDNPHasChain, SDNPMayLoad]>; + +def PPCRegQFRCAsmOperand : AsmOperandClass { + let Name = "RegQFRC"; let PredicateMethod = "isRegNumber"; +} +def qfrc : RegisterOperand { + let ParserMatchClass = PPCRegQFRCAsmOperand; +} +def PPCRegQSRCAsmOperand : AsmOperandClass { + let Name = "RegQSRC"; let PredicateMethod = "isRegNumber"; +} +def qsrc : RegisterOperand { + let ParserMatchClass = PPCRegQSRCAsmOperand; +} +def PPCRegQBRCAsmOperand : AsmOperandClass { + let Name = "RegQBRC"; let PredicateMethod = "isRegNumber"; +} +def qbrc : RegisterOperand { + let ParserMatchClass = PPCRegQBRCAsmOperand; +} + +//===----------------------------------------------------------------------===// +// Helpers for defining instructions that directly correspond to intrinsics. + +// QPXA1_Int - A AForm_1 intrinsic definition. +class QPXA1_Int opcode, bits<5> xo, string opc, Intrinsic IntID> + : AForm_1; +// QPXA1s_Int - A AForm_1 intrinsic definition (simple instructions). +class QPXA1s_Int opcode, bits<5> xo, string opc, Intrinsic IntID> + : AForm_1; +// QPXA2_Int - A AForm_2 intrinsic definition. +class QPXA2_Int opcode, bits<5> xo, string opc, Intrinsic IntID> + : AForm_2; +// QPXA3_Int - A AForm_3 intrinsic definition. +class QPXA3_Int opcode, bits<5> xo, string opc, Intrinsic IntID> + : AForm_3; +// QPXA4_Int - A AForm_4a intrinsic definition. +class QPXA4_Int opcode, bits<5> xo, string opc, Intrinsic IntID> + : AForm_4a; +// QPXX18_Int - A XForm_18 intrinsic definition. +class QPXX18_Int opcode, bits<10> xo, string opc, Intrinsic IntID> + : XForm_18; +// QPXX19_Int - A XForm_19 intrinsic definition. +class QPXX19_Int opcode, bits<10> xo, string opc, Intrinsic IntID> + : XForm_19; + +//===----------------------------------------------------------------------===// +// Pattern Frags. + +def extloadv4f32 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ + return cast(N)->getMemoryVT() == MVT::v4f32; +}]>; + +def truncstorev4f32 : PatFrag<(ops node:$val, node:$ptr), + (truncstore node:$val, node:$ptr), [{ + return cast(N)->getMemoryVT() == MVT::v4f32; +}]>; +def pre_truncstv4f32 : PatFrag<(ops node:$val, node:$base, node:$offset), + (pre_truncst node:$val, + node:$base, node:$offset), [{ + return cast(N)->getMemoryVT() == MVT::v4f32; +}]>; + +def fround_inexact : PatFrag<(ops node:$val), (fpround node:$val), [{ + return cast(N->getOperand(1))->getZExtValue() == 0; +}]>; + +def fround_exact : PatFrag<(ops node:$val), (fpround node:$val), [{ + return cast(N->getOperand(1))->getZExtValue() == 1; +}]>; + +let FastIselShouldIgnore = 1 in // FastIsel should ignore all u12 instrs. + def u12 : ImmLeaf; + +//===----------------------------------------------------------------------===// +// Instruction Definitions. + +def HasQPX : Predicate<"Subtarget->hasQPX()">, + AssemblerPredicate<(all_of FeatureQPX), "">; +let Predicates = [HasQPX] in { +let DecoderNamespace = "QPX" in { +let hasSideEffects = 0 in { // QPX instructions don't have side effects. +let Uses = [RM] in { + // Add Instructions + let isCommutable = 1 in { + def QVFADD : AForm_2<4, 21, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfadd $FRT, $FRA, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (fadd v4f64:$FRA, v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFADDS : QPXA2_Int<0, 21, "qvfadds", int_ppc_qpx_qvfadds>; + def QVFADDSs : AForm_2<0, 21, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfadds $FRT, $FRA, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (fadd v4f32:$FRA, v4f32:$FRB))]>; + } + def QVFSUB : AForm_2<4, 20, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfsub $FRT, $FRA, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (fsub v4f64:$FRA, v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFSUBS : QPXA2_Int<0, 20, "qvfsubs", int_ppc_qpx_qvfsubs>; + def QVFSUBSs : AForm_2<0, 20, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfsubs $FRT, $FRA, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (fsub v4f32:$FRA, v4f32:$FRB))]>; + + // Estimate Instructions + def QVFRE : AForm_4a<4, 24, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfre $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (PPCfre v4f64:$FRB))]>; + def QVFRES : QPXA4_Int<0, 24, "qvfres", int_ppc_qpx_qvfres>; + let isCodeGenOnly = 1 in + def QVFRESs : AForm_4a<0, 24, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfres $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (PPCfre v4f32:$FRB))]>; + + def QVFRSQRTE : AForm_4a<4, 26, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfrsqrte $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (PPCfrsqrte v4f64:$FRB))]>; + def QVFRSQRTES : QPXA4_Int<0, 26, "qvfrsqrtes", int_ppc_qpx_qvfrsqrtes>; + let isCodeGenOnly = 1 in + def QVFRSQRTESs : AForm_4a<0, 26, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfrsqrtes $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (PPCfrsqrte v4f32:$FRB))]>; + + // Multiply Instructions + let isCommutable = 1 in { + def QVFMUL : AForm_3<4, 25, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRC), + "qvfmul $FRT, $FRA, $FRC", IIC_FPGeneral, + [(set v4f64:$FRT, (fmul v4f64:$FRA, v4f64:$FRC))]>; + let isCodeGenOnly = 1 in + def QVFMULS : QPXA3_Int<0, 25, "qvfmuls", int_ppc_qpx_qvfmuls>; + def QVFMULSs : AForm_3<0, 25, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRC), + "qvfmuls $FRT, $FRA, $FRC", IIC_FPGeneral, + [(set v4f32:$FRT, (fmul v4f32:$FRA, v4f32:$FRC))]>; + } + def QVFXMUL : QPXA3_Int<4, 17, "qvfxmul", int_ppc_qpx_qvfxmul>; + def QVFXMULS : QPXA3_Int<0, 17, "qvfxmuls", int_ppc_qpx_qvfxmuls>; + + // Multiply-add instructions + def QVFMADD : AForm_1<4, 29, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRC, qfrc:$FRB), + "qvfmadd $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f64:$FRT, (fma v4f64:$FRA, v4f64:$FRC, v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFMADDS : QPXA1_Int<0, 29, "qvfmadds", int_ppc_qpx_qvfmadds>; + def QVFMADDSs : AForm_1<0, 29, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRC, qsrc:$FRB), + "qvfmadds $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f32:$FRT, (fma v4f32:$FRA, v4f32:$FRC, v4f32:$FRB))]>; + def QVFNMADD : AForm_1<4, 31, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRC, qfrc:$FRB), + "qvfnmadd $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f64:$FRT, (fneg (fma v4f64:$FRA, v4f64:$FRC, + v4f64:$FRB)))]>; + let isCodeGenOnly = 1 in + def QVFNMADDS : QPXA1_Int<0, 31, "qvfnmadds", int_ppc_qpx_qvfnmadds>; + def QVFNMADDSs : AForm_1<0, 31, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRC, qsrc:$FRB), + "qvfnmadds $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f32:$FRT, (fneg (fma v4f32:$FRA, v4f32:$FRC, + v4f32:$FRB)))]>; + def QVFMSUB : AForm_1<4, 28, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRC, qfrc:$FRB), + "qvfmsub $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f64:$FRT, (fma v4f64:$FRA, v4f64:$FRC, + (fneg v4f64:$FRB)))]>; + let isCodeGenOnly = 1 in + def QVFMSUBS : QPXA1_Int<0, 28, "qvfmsubs", int_ppc_qpx_qvfmsubs>; + def QVFMSUBSs : AForm_1<0, 28, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRC, qsrc:$FRB), + "qvfmsubs $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f32:$FRT, (fma v4f32:$FRA, v4f32:$FRC, + (fneg v4f32:$FRB)))]>; + def QVFNMSUB : AForm_1<4, 30, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRC, qfrc:$FRB), + "qvfnmsub $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f64:$FRT, (fneg (fma v4f64:$FRA, v4f64:$FRC, + (fneg v4f64:$FRB))))]>; + let isCodeGenOnly = 1 in + def QVFNMSUBS : QPXA1_Int<0, 30, "qvfnmsubs", int_ppc_qpx_qvfnmsubs>; + def QVFNMSUBSs : AForm_1<0, 30, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRC, qsrc:$FRB), + "qvfnmsubs $FRT, $FRA, $FRC, $FRB", IIC_FPFused, + [(set v4f32:$FRT, (fneg (fma v4f32:$FRA, v4f32:$FRC, + (fneg v4f32:$FRB))))]>; + def QVFXMADD : QPXA1_Int<4, 9, "qvfxmadd", int_ppc_qpx_qvfxmadd>; + def QVFXMADDS : QPXA1_Int<0, 9, "qvfxmadds", int_ppc_qpx_qvfxmadds>; + def QVFXXNPMADD : QPXA1_Int<4, 11, "qvfxxnpmadd", int_ppc_qpx_qvfxxnpmadd>; + def QVFXXNPMADDS : QPXA1_Int<0, 11, "qvfxxnpmadds", int_ppc_qpx_qvfxxnpmadds>; + def QVFXXCPNMADD : QPXA1_Int<4, 3, "qvfxxcpnmadd", int_ppc_qpx_qvfxxcpnmadd>; + def QVFXXCPNMADDS : QPXA1_Int<0, 3, "qvfxxcpnmadds", int_ppc_qpx_qvfxxcpnmadds>; + def QVFXXMADD : QPXA1_Int<4, 1, "qvfxxmadd", int_ppc_qpx_qvfxxmadd>; + def QVFXXMADDS : QPXA1_Int<0, 1, "qvfxxmadds", int_ppc_qpx_qvfxxmadds>; + + // Select Instruction + let isCodeGenOnly = 1 in + def QVFSEL : QPXA1s_Int<4, 23, "qvfsel", int_ppc_qpx_qvfsel>; + def QVFSELb : AForm_1<4, 23, (outs qfrc:$FRT), + (ins qbrc:$FRA, qfrc:$FRB, qfrc:$FRC), + "qvfsel $FRT, $FRA, $FRC, $FRB", IIC_VecPerm, + [(set v4f64:$FRT, (vselect v4i1:$FRA, + v4f64:$FRC, v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFSELbs : AForm_1<4, 23, (outs qsrc:$FRT), + (ins qbrc:$FRA, qsrc:$FRB, qsrc:$FRC), + "qvfsel $FRT, $FRA, $FRC, $FRB", IIC_VecPerm, + [(set v4f32:$FRT, (vselect v4i1:$FRA, + v4f32:$FRC, v4f32:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFSELbb: AForm_1<4, 23, (outs qbrc:$FRT), + (ins qbrc:$FRA, qbrc:$FRB, qbrc:$FRC), + "qvfsel $FRT, $FRA, $FRC, $FRB", IIC_VecPerm, + [(set v4i1:$FRT, (vselect v4i1:$FRA, + v4i1:$FRC, v4i1:$FRB))]>; + + // SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after + // instruction selection into a branch sequence. + def SELECT_CC_QFRC: PPCCustomInserterPseudo<(outs qfrc:$dst), (ins crrc:$cond, qfrc:$T, qfrc:$F, + i32imm:$BROPC), "#SELECT_CC_QFRC", + []>; + def SELECT_CC_QSRC: PPCCustomInserterPseudo<(outs qsrc:$dst), (ins crrc:$cond, qsrc:$T, qsrc:$F, + i32imm:$BROPC), "#SELECT_CC_QSRC", + []>; + def SELECT_CC_QBRC: PPCCustomInserterPseudo<(outs qbrc:$dst), (ins crrc:$cond, qbrc:$T, qbrc:$F, + i32imm:$BROPC), "#SELECT_CC_QBRC", + []>; + + // SELECT_* pseudo instructions, like SELECT_CC_* but taking condition + // register bit directly. + def SELECT_QFRC: PPCCustomInserterPseudo<(outs qfrc:$dst), (ins crbitrc:$cond, + qfrc:$T, qfrc:$F), "#SELECT_QFRC", + [(set v4f64:$dst, + (select i1:$cond, v4f64:$T, v4f64:$F))]>; + def SELECT_QSRC: PPCCustomInserterPseudo<(outs qsrc:$dst), (ins crbitrc:$cond, + qsrc:$T, qsrc:$F), "#SELECT_QSRC", + [(set v4f32:$dst, + (select i1:$cond, v4f32:$T, v4f32:$F))]>; + def SELECT_QBRC: PPCCustomInserterPseudo<(outs qbrc:$dst), (ins crbitrc:$cond, + qbrc:$T, qbrc:$F), "#SELECT_QBRC", + [(set v4i1:$dst, + (select i1:$cond, v4i1:$T, v4i1:$F))]>; + + // Convert and Round Instructions + def QVFCTID : QPXX19_Int<4, 814, "qvfctid", int_ppc_qpx_qvfctid>; + let isCodeGenOnly = 1 in + def QVFCTIDb : XForm_19<4, 814, (outs qbrc:$FRT), (ins qbrc:$FRB), + "qvfctid $FRT, $FRB", IIC_FPGeneral, []>; + + def QVFCTIDU : QPXX19_Int<4, 942, "qvfctidu", int_ppc_qpx_qvfctidu>; + def QVFCTIDZ : QPXX19_Int<4, 815, "qvfctidz", int_ppc_qpx_qvfctidz>; + def QVFCTIDUZ : QPXX19_Int<4, 943, "qvfctiduz", int_ppc_qpx_qvfctiduz>; + def QVFCTIW : QPXX19_Int<4, 14, "qvfctiw", int_ppc_qpx_qvfctiw>; + def QVFCTIWU : QPXX19_Int<4, 142, "qvfctiwu", int_ppc_qpx_qvfctiwu>; + def QVFCTIWZ : QPXX19_Int<4, 15, "qvfctiwz", int_ppc_qpx_qvfctiwz>; + def QVFCTIWUZ : QPXX19_Int<4, 143, "qvfctiwuz", int_ppc_qpx_qvfctiwuz>; + def QVFCFID : QPXX19_Int<4, 846, "qvfcfid", int_ppc_qpx_qvfcfid>; + let isCodeGenOnly = 1 in + def QVFCFIDb : XForm_19<4, 846, (outs qbrc:$FRT), (ins qbrc:$FRB), + "qvfcfid $FRT, $FRB", IIC_FPGeneral, []>; + + def QVFCFIDU : QPXX19_Int<4, 974, "qvfcfidu", int_ppc_qpx_qvfcfidu>; + def QVFCFIDS : QPXX19_Int<0, 846, "qvfcfids", int_ppc_qpx_qvfcfids>; + def QVFCFIDUS : QPXX19_Int<0, 974, "qvfcfidus", int_ppc_qpx_qvfcfidus>; + + let isCodeGenOnly = 1 in + def QVFRSP : QPXX19_Int<4, 12, "qvfrsp", int_ppc_qpx_qvfrsp>; + def QVFRSPs : XForm_19<4, 12, + (outs qsrc:$FRT), (ins qfrc:$FRB), + "qvfrsp $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (fround_inexact v4f64:$FRB))]>; + + def QVFRIZ : XForm_19<4, 424, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfriz $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (ftrunc v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFRIZs : XForm_19<4, 424, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfriz $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (ftrunc v4f32:$FRB))]>; + + def QVFRIN : XForm_19<4, 392, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfrin $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (fround v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFRINs : XForm_19<4, 392, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfrin $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (fround v4f32:$FRB))]>; + + def QVFRIP : XForm_19<4, 456, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfrip $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (fceil v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFRIPs : XForm_19<4, 456, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfrip $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (fceil v4f32:$FRB))]>; + + def QVFRIM : XForm_19<4, 488, (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfrim $FRT, $FRB", IIC_FPGeneral, + [(set v4f64:$FRT, (ffloor v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFRIMs : XForm_19<4, 488, (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfrim $FRT, $FRB", IIC_FPGeneral, + [(set v4f32:$FRT, (ffloor v4f32:$FRB))]>; + + // Move Instructions + def QVFMR : XForm_19<4, 72, + (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfmr $FRT, $FRB", IIC_VecPerm, + [/* (set v4f64:$FRT, v4f64:$FRB) */]>; + let isCodeGenOnly = 1 in { + def QVFMRs : XForm_19<4, 72, + (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfmr $FRT, $FRB", IIC_VecPerm, + [/* (set v4f32:$FRT, v4f32:$FRB) */]>; + def QVFMRb : XForm_19<4, 72, + (outs qbrc:$FRT), (ins qbrc:$FRB), + "qvfmr $FRT, $FRB", IIC_VecPerm, + [/* (set v4i1:$FRT, v4i1:$FRB) */]>; + } + def QVFNEG : XForm_19<4, 40, + (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfneg $FRT, $FRB", IIC_VecPerm, + [(set v4f64:$FRT, (fneg v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFNEGs : XForm_19<4, 40, + (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfneg $FRT, $FRB", IIC_VecPerm, + [(set v4f32:$FRT, (fneg v4f32:$FRB))]>; + def QVFABS : XForm_19<4, 264, + (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfabs $FRT, $FRB", IIC_VecPerm, + [(set v4f64:$FRT, (fabs v4f64:$FRB))]>; + let isCodeGenOnly = 1 in + def QVFABSs : XForm_19<4, 264, + (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfabs $FRT, $FRB", IIC_VecPerm, + [(set v4f32:$FRT, (fabs v4f32:$FRB))]>; + def QVFNABS : XForm_19<4, 136, + (outs qfrc:$FRT), (ins qfrc:$FRB), + "qvfnabs $FRT, $FRB", IIC_VecPerm, + [(set v4f64:$FRT, (fneg (fabs v4f64:$FRB)))]>; + let isCodeGenOnly = 1 in + def QVFNABSs : XForm_19<4, 136, + (outs qsrc:$FRT), (ins qsrc:$FRB), + "qvfnabs $FRT, $FRB", IIC_VecPerm, + [(set v4f32:$FRT, (fneg (fabs v4f32:$FRB)))]>; + def QVFCPSGN : XForm_18<4, 8, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfcpsgn $FRT, $FRA, $FRB", IIC_VecPerm, + [(set v4f64:$FRT, (fcopysign v4f64:$FRB, v4f64:$FRA))]>; + let isCodeGenOnly = 1 in + def QVFCPSGNs : XForm_18<4, 8, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfcpsgn $FRT, $FRA, $FRB", IIC_VecPerm, + [(set v4f32:$FRT, (fcopysign v4f32:$FRB, v4f32:$FRA))]>; + + def QVALIGNI : Z23Form_1<4, 5, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB, u2imm:$idx), + "qvaligni $FRT, $FRA, $FRB, $idx", IIC_VecPerm, + [(set v4f64:$FRT, + (PPCqvaligni v4f64:$FRA, v4f64:$FRB, + (i32 imm:$idx)))]>; + let isCodeGenOnly = 1 in + def QVALIGNIs : Z23Form_1<4, 5, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB, u2imm:$idx), + "qvaligni $FRT, $FRA, $FRB, $idx", IIC_VecPerm, + [(set v4f32:$FRT, + (PPCqvaligni v4f32:$FRA, v4f32:$FRB, + (i32 imm:$idx)))]>; + let isCodeGenOnly = 1 in + def QVALIGNIb : Z23Form_1<4, 5, + (outs qbrc:$FRT), (ins qbrc:$FRA, qbrc:$FRB, u2imm:$idx), + "qvaligni $FRT, $FRA, $FRB, $idx", IIC_VecPerm, + [(set v4i1:$FRT, + (PPCqvaligni v4i1:$FRA, v4i1:$FRB, + (i32 imm:$idx)))]>; + + def QVESPLATI : Z23Form_2<4, 37, + (outs qfrc:$FRT), (ins qfrc:$FRA, u2imm:$idx), + "qvesplati $FRT, $FRA, $idx", IIC_VecPerm, + [(set v4f64:$FRT, + (PPCqvesplati v4f64:$FRA, (i32 imm:$idx)))]>; + let isCodeGenOnly = 1 in + def QVESPLATIs : Z23Form_2<4, 37, + (outs qsrc:$FRT), (ins qsrc:$FRA, u2imm:$idx), + "qvesplati $FRT, $FRA, $idx", IIC_VecPerm, + [(set v4f32:$FRT, + (PPCqvesplati v4f32:$FRA, (i32 imm:$idx)))]>; + let isCodeGenOnly = 1 in + def QVESPLATIb : Z23Form_2<4, 37, + (outs qbrc:$FRT), (ins qbrc:$FRA, u2imm:$idx), + "qvesplati $FRT, $FRA, $idx", IIC_VecPerm, + [(set v4i1:$FRT, + (PPCqvesplati v4i1:$FRA, (i32 imm:$idx)))]>; + + def QVFPERM : AForm_1<4, 6, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB, qfrc:$FRC), + "qvfperm $FRT, $FRA, $FRB, $FRC", IIC_VecPerm, + [(set v4f64:$FRT, + (PPCqvfperm v4f64:$FRA, v4f64:$FRB, v4f64:$FRC))]>; + let isCodeGenOnly = 1 in + def QVFPERMs : AForm_1<4, 6, + (outs qsrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB, qfrc:$FRC), + "qvfperm $FRT, $FRA, $FRB, $FRC", IIC_VecPerm, + [(set v4f32:$FRT, + (PPCqvfperm v4f32:$FRA, v4f32:$FRB, v4f64:$FRC))]>; + + let isReMaterializable = 1, isAsCheapAsAMove = 1 in + def QVGPCI : Z23Form_3<4, 133, + (outs qfrc:$FRT), (ins u12imm:$idx), + "qvgpci $FRT, $idx", IIC_VecPerm, + [(set v4f64:$FRT, (PPCqvgpci (u12:$idx)))]>; + + // Compare Instruction + let isCodeGenOnly = 1 in + def QVFTSTNAN : QPXX18_Int<4, 64, "qvftstnan", int_ppc_qpx_qvftstnan>; + def QVFTSTNANb : XForm_18<4, 64, (outs qbrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvftstnan $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f64:$FRA, v4f64:$FRB, SETUO))]>; + let isCodeGenOnly = 1 in + def QVFTSTNANbs : XForm_18<4, 64, (outs qbrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvftstnan $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f32:$FRA, v4f32:$FRB, SETUO))]>; + let isCodeGenOnly = 1 in + def QVFCMPLT : QPXX18_Int<4, 96, "qvfcmplt", int_ppc_qpx_qvfcmplt>; + def QVFCMPLTb : XForm_18<4, 96, (outs qbrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfcmplt $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f64:$FRA, v4f64:$FRB, SETOLT))]>; + let isCodeGenOnly = 1 in + def QVFCMPLTbs : XForm_18<4, 96, (outs qbrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfcmplt $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f32:$FRA, v4f32:$FRB, SETOLT))]>; + let isCodeGenOnly = 1 in + def QVFCMPGT : QPXX18_Int<4, 32, "qvfcmpgt", int_ppc_qpx_qvfcmpgt>; + def QVFCMPGTb : XForm_18<4, 32, (outs qbrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfcmpgt $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f64:$FRA, v4f64:$FRB, SETOGT))]>; + let isCodeGenOnly = 1 in + def QVFCMPGTbs : XForm_18<4, 32, (outs qbrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfcmpgt $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f32:$FRA, v4f32:$FRB, SETOGT))]>; + let isCodeGenOnly = 1 in + def QVFCMPEQ : QPXX18_Int<4, 0, "qvfcmpeq", int_ppc_qpx_qvfcmpeq>; + def QVFCMPEQb : XForm_18<4, 0, (outs qbrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB), + "qvfcmpeq $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f64:$FRA, v4f64:$FRB, SETOEQ))]>; + let isCodeGenOnly = 1 in + def QVFCMPEQbs : XForm_18<4, 0, (outs qbrc:$FRT), (ins qsrc:$FRA, qsrc:$FRB), + "qvfcmpeq $FRT, $FRA, $FRB", IIC_FPCompare, + [(set v4i1:$FRT, + (setcc v4f32:$FRA, v4f32:$FRB, SETOEQ))]>; + + let isCodeGenOnly = 1 in + def QVFLOGICAL : XForm_20<4, 4, + (outs qfrc:$FRT), (ins qfrc:$FRA, qfrc:$FRB, u12imm:$tttt), + "qvflogical $FRT, $FRA, $FRB, $tttt", IIC_VecPerm, []>; + def QVFLOGICALb : XForm_20<4, 4, + (outs qbrc:$FRT), (ins qbrc:$FRA, qbrc:$FRB, u12imm:$tttt), + "qvflogical $FRT, $FRA, $FRB, $tttt", IIC_VecPerm, []>; + let isCodeGenOnly = 1 in + def QVFLOGICALs : XForm_20<4, 4, + (outs qbrc:$FRT), (ins qbrc:$FRA, qbrc:$FRB, u12imm:$tttt), + "qvflogical $FRT, $FRA, $FRB, $tttt", IIC_VecPerm, []>; + + // Load indexed instructions + let mayLoad = 1 in { + def QVLFDX : XForm_1_memOp<31, 583, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfdx $FRT, $src", IIC_LdStLFD, + [(set v4f64:$FRT, (load xoaddr:$src))]>; + let isCodeGenOnly = 1 in + def QVLFDXb : XForm_1_memOp<31, 583, + (outs qbrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfdx $FRT, $src", IIC_LdStLFD, []>; + + let RC = 1 in + def QVLFDXA : XForm_1<31, 583, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfdxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFDUX : XForm_1<31, 615, + (outs qfrc:$FRT, ptr_rc_nor0:$ea_result), + (ins (memrr $RA, $RB):$src), + "qvlfdux $FRT, $src", IIC_LdStLFDU, []>, + RegConstraint<"$src.ptrreg = $ea_result">, + NoEncode<"$ea_result">; + let RC = 1 in + def QVLFDUXA : XForm_1<31, 615, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfduxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFSX : XForm_1_memOp<31, 519, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfsx $FRT, $src", IIC_LdStLFD, + [(set v4f64:$FRT, (extloadv4f32 xoaddr:$src))]>; + + let isCodeGenOnly = 1 in + def QVLFSXb : XForm_1<31, 519, + (outs qbrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfsx $FRT, $src", IIC_LdStLFD, + [(set v4i1:$FRT, (PPCqvlfsb xoaddr:$src))]>; + let isCodeGenOnly = 1 in + def QVLFSXs : XForm_1_memOp<31, 519, + (outs qsrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfsx $FRT, $src", IIC_LdStLFD, + [(set v4f32:$FRT, (load xoaddr:$src))]>; + + let RC = 1 in + def QVLFSXA : XForm_1<31, 519, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfsxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFSUX : XForm_1<31, 551, + (outs qsrc:$FRT, ptr_rc_nor0:$ea_result), + (ins (memrr $RA, $RB):$src), + "qvlfsux $FRT, $src", IIC_LdStLFDU, []>, + RegConstraint<"$src.ptrreg = $ea_result">, + NoEncode<"$ea_result">; + + let RC = 1 in + def QVLFSUXA : XForm_1<31, 551, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfsuxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCDX : XForm_1<31, 71, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcdx $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCDXA : XForm_1<31, 71, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcdxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCDUX : XForm_1<31, 103, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcdux $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCDUXA : XForm_1<31, 103, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcduxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCSX : XForm_1<31, 7, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcsx $FRT, $src", IIC_LdStLFD, []>; + let isCodeGenOnly = 1 in + def QVLFCSXs : XForm_1<31, 7, + (outs qsrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcsx $FRT, $src", IIC_LdStLFD, []>; + + let RC = 1 in + def QVLFCSXA : XForm_1<31, 7, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcsxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCSUX : XForm_1<31, 39, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcsux $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCSUXA : XForm_1<31, 39, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfcsuxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFIWAX : XForm_1<31, 871, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfiwax $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFIWAXA : XForm_1<31, 871, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfiwaxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFIWZX : XForm_1<31, 839, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfiwzx $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFIWZXA : XForm_1<31, 839, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlfiwzxa $FRT, $src", IIC_LdStLFD, []>; + + + def QVLPCLDX : XForm_1<31, 582, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlpcldx $FRT, $src", IIC_LdStLFD, []>; + def QVLPCLSX : XForm_1<31, 518, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlpclsx $FRT, $src", IIC_LdStLFD, []>; + let isCodeGenOnly = 1 in + def QVLPCLSXint : XForm_11<31, 518, + (outs qfrc:$FRT), (ins G8RC:$src), + "qvlpclsx $FRT, 0, $src", IIC_LdStLFD, []>; + def QVLPCRDX : XForm_1<31, 70, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlpcrdx $FRT, $src", IIC_LdStLFD, []>; + def QVLPCRSX : XForm_1<31, 6, + (outs qfrc:$FRT), (ins (memrr $RA, $RB):$src), + "qvlpcrsx $FRT, $src", IIC_LdStLFD, []>; + } + + // Store indexed instructions + let mayStore = 1 in { + def QVSTFDX : XForm_8_memOp<31, 711, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdx $FRT, $dst", IIC_LdStSTFD, + [(store qfrc:$FRT, xoaddr:$dst)]>; + let isCodeGenOnly = 1 in + def QVSTFDXb : XForm_8_memOp<31, 711, + (outs), (ins qbrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdx $FRT, $dst", IIC_LdStSTFD, []>; + + let RC = 1 in + def QVSTFDXA : XForm_8<31, 711, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDUX : XForm_8<31, 743, (outs ptr_rc_nor0:$ea_res), + (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdux $FRT, $dst", IIC_LdStSTFDU, []>, + RegConstraint<"$dst.ptrreg = $ea_res">, + NoEncode<"$ea_res">; + + let RC = 1 in + def QVSTFDUXA : XForm_8<31, 743, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfduxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDXI : XForm_8<31, 709, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFDXIA : XForm_8<31, 709, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfdxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDUXI : XForm_8<31, 741, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfduxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFDUXIA : XForm_8<31, 741, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfduxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSX : XForm_8_memOp<31, 647, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsx $FRT, $dst", IIC_LdStSTFD, + [(truncstorev4f32 qfrc:$FRT, xoaddr:$dst)]>; + let isCodeGenOnly = 1 in + def QVSTFSXs : XForm_8_memOp<31, 647, + (outs), (ins qsrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsx $FRT, $dst", IIC_LdStSTFD, + [(store qsrc:$FRT, xoaddr:$dst)]>; + + let RC = 1 in + def QVSTFSXA : XForm_8<31, 647, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSUX : XForm_8<31, 679, (outs ptr_rc_nor0:$ea_res), + (ins qsrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsux $FRT, $dst", IIC_LdStSTFDU, []>, + RegConstraint<"$dst.ptrreg = $ea_res">, + NoEncode<"$ea_res">; + let isCodeGenOnly = 1 in + def QVSTFSUXs: XForm_8<31, 679, (outs ptr_rc_nor0:$ea_res), + (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsux $FRT, $dst", IIC_LdStSTFDU, []>, + RegConstraint<"$dst.ptrreg = $ea_res">, + NoEncode<"$ea_res">; + + let RC = 1 in + def QVSTFSUXA : XForm_8<31, 679, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsuxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSXI : XForm_8<31, 645, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFSXIA : XForm_8<31, 645, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSUXI : XForm_8<31, 677, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsuxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFSUXIA : XForm_8<31, 677, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfsuxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDX : XForm_8<31, 199, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcdx $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDXA : XForm_8<31, 199, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcdxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSX : XForm_8<31, 135, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsx $FRT, $dst", IIC_LdStSTFD, []>; + let isCodeGenOnly = 1 in + def QVSTFCSXs : XForm_8<31, 135, + (outs), (ins qsrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsx $FRT, $dst", IIC_LdStSTFD, []>; + + let RC = 1 in + def QVSTFCSXA : XForm_8<31, 135, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDUX : XForm_8<31, 231, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcdux $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDUXA : XForm_8<31, 231, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcduxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSUX : XForm_8<31, 167, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsux $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSUXA : XForm_8<31, 167, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsuxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDXI : XForm_8<31, 197, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcdxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDXIA : XForm_8<31, 197, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcdxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSXI : XForm_8<31, 133, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSXIA : XForm_8<31, 133, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDUXI : XForm_8<31, 229, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcduxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDUXIA : XForm_8<31, 229, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcduxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSUXI : XForm_8<31, 165, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsuxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSUXIA : XForm_8<31, 165, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfcsuxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFIWX : XForm_8<31, 967, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfiwx $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFIWXA : XForm_8<31, 967, + (outs), (ins qfrc:$FRT, (memrr $RA, $RB):$dst), + "qvstfiwxa $FRT, $dst", IIC_LdStSTFD, []>; + } +} + +} // neverHasSideEffects +} + +def : InstAlias<"qvfclr $FRT", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRT, qbrc:$FRT, 0)>; +def : InstAlias<"qvfand $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 1)>; +def : InstAlias<"qvfandc $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 4)>; +def : InstAlias<"qvfctfb $FRT, $FRA", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRA, 5)>; +def : InstAlias<"qvfxor $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 6)>; +def : InstAlias<"qvfor $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 7)>; +def : InstAlias<"qvfnor $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 8)>; +def : InstAlias<"qvfequ $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 9)>; +def : InstAlias<"qvfnot $FRT, $FRA", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRA, 10)>; +def : InstAlias<"qvforc $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 13)>; +def : InstAlias<"qvfnand $FRT, $FRA, $FRB", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRA, qbrc:$FRB, 14)>; +def : InstAlias<"qvfset $FRT", + (QVFLOGICALb qbrc:$FRT, qbrc:$FRT, qbrc:$FRT, 15)>; + +//===----------------------------------------------------------------------===// +// Additional QPX Patterns +// + +def : Pat<(v4f64 (scalar_to_vector f64:$A)), + (INSERT_SUBREG (v4f64 (IMPLICIT_DEF)), $A, sub_64)>; +def : Pat<(v4f32 (scalar_to_vector f32:$A)), + (INSERT_SUBREG (v4f32 (IMPLICIT_DEF)), $A, sub_64)>; + +def : Pat<(f64 (extractelt v4f64:$S, 0)), + (EXTRACT_SUBREG $S, sub_64)>; +def : Pat<(f32 (extractelt v4f32:$S, 0)), + (EXTRACT_SUBREG $S, sub_64)>; + +def : Pat<(f64 (extractelt v4f64:$S, 1)), + (EXTRACT_SUBREG (QVESPLATI $S, 1), sub_64)>; +def : Pat<(f64 (extractelt v4f64:$S, 2)), + (EXTRACT_SUBREG (QVESPLATI $S, 2), sub_64)>; +def : Pat<(f64 (extractelt v4f64:$S, 3)), + (EXTRACT_SUBREG (QVESPLATI $S, 3), sub_64)>; + +def : Pat<(f32 (extractelt v4f32:$S, 1)), + (EXTRACT_SUBREG (QVESPLATIs $S, 1), sub_64)>; +def : Pat<(f32 (extractelt v4f32:$S, 2)), + (EXTRACT_SUBREG (QVESPLATIs $S, 2), sub_64)>; +def : Pat<(f32 (extractelt v4f32:$S, 3)), + (EXTRACT_SUBREG (QVESPLATIs $S, 3), sub_64)>; + +def : Pat<(f64 (extractelt v4f64:$S, i64:$F)), + (EXTRACT_SUBREG (QVFPERM $S, $S, + (QVLPCLSXint (RLDICR $F, 2, + /* 63-2 = */ 61))), + sub_64)>; +def : Pat<(f32 (extractelt v4f32:$S, i64:$F)), + (EXTRACT_SUBREG (QVFPERMs $S, $S, + (QVLPCLSXint (RLDICR $F, 2, + /* 63-2 = */ 61))), + sub_64)>; + +def : Pat<(int_ppc_qpx_qvfperm v4f64:$A, v4f64:$B, v4f64:$C), + (QVFPERM $A, $B, $C)>; + +def : Pat<(int_ppc_qpx_qvfcpsgn v4f64:$A, v4f64:$B), + (QVFCPSGN $A, $B)>; + +// FCOPYSIGN's operand types need not agree. +def : Pat<(fcopysign v4f64:$frB, v4f32:$frA), + (QVFCPSGN (COPY_TO_REGCLASS $frA, QFRC), $frB)>; +def : Pat<(fcopysign QSRC:$frB, QFRC:$frA), + (QVFCPSGNs (COPY_TO_REGCLASS $frA, QSRC), $frB)>; + +def : Pat<(int_ppc_qpx_qvfneg v4f64:$A), (QVFNEG $A)>; +def : Pat<(int_ppc_qpx_qvfabs v4f64:$A), (QVFABS $A)>; +def : Pat<(int_ppc_qpx_qvfnabs v4f64:$A), (QVFNABS $A)>; + +def : Pat<(int_ppc_qpx_qvfriz v4f64:$A), (QVFRIZ $A)>; +def : Pat<(int_ppc_qpx_qvfrin v4f64:$A), (QVFRIN $A)>; +def : Pat<(int_ppc_qpx_qvfrip v4f64:$A), (QVFRIP $A)>; +def : Pat<(int_ppc_qpx_qvfrim v4f64:$A), (QVFRIM $A)>; + +def : Pat<(int_ppc_qpx_qvfre v4f64:$A), (QVFRE $A)>; +def : Pat<(int_ppc_qpx_qvfrsqrte v4f64:$A), (QVFRSQRTE $A)>; + +def : Pat<(int_ppc_qpx_qvfadd v4f64:$A, v4f64:$B), + (QVFADD $A, $B)>; +def : Pat<(int_ppc_qpx_qvfsub v4f64:$A, v4f64:$B), + (QVFSUB $A, $B)>; +def : Pat<(int_ppc_qpx_qvfmul v4f64:$A, v4f64:$B), + (QVFMUL $A, $B)>; + +// Additional QVFNMSUB patterns: -a*c + b == -(a*c - b) +def : Pat<(fma (fneg v4f64:$A), v4f64:$C, v4f64:$B), + (QVFNMSUB $A, $C, $B)>; +def : Pat<(fma v4f64:$A, (fneg v4f64:$C), v4f64:$B), + (QVFNMSUB $A, $C, $B)>; +def : Pat<(fma (fneg v4f32:$A), v4f32:$C, v4f32:$B), + (QVFNMSUBSs $A, $C, $B)>; +def : Pat<(fma v4f32:$A, (fneg v4f32:$C), v4f32:$B), + (QVFNMSUBSs $A, $C, $B)>; + +def : Pat<(int_ppc_qpx_qvfmadd v4f64:$A, v4f64:$B, v4f64:$C), + (QVFMADD $A, $B, $C)>; +def : Pat<(int_ppc_qpx_qvfnmadd v4f64:$A, v4f64:$B, v4f64:$C), + (QVFNMADD $A, $B, $C)>; +def : Pat<(int_ppc_qpx_qvfmsub v4f64:$A, v4f64:$B, v4f64:$C), + (QVFMSUB $A, $B, $C)>; +def : Pat<(int_ppc_qpx_qvfnmsub v4f64:$A, v4f64:$B, v4f64:$C), + (QVFNMSUB $A, $B, $C)>; + +def : Pat<(int_ppc_qpx_qvlfd xoaddr:$src), + (QVLFDX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfda xoaddr:$src), + (QVLFDXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfs xoaddr:$src), + (QVLFSX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfsa xoaddr:$src), + (QVLFSXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfcda xoaddr:$src), + (QVLFCDXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfcd xoaddr:$src), + (QVLFCDX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfcsa xoaddr:$src), + (QVLFCSXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfcs xoaddr:$src), + (QVLFCSX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfda xoaddr:$src), + (QVLFDXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfiwaa xoaddr:$src), + (QVLFIWAXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfiwa xoaddr:$src), + (QVLFIWAX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfiwza xoaddr:$src), + (QVLFIWZXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfiwz xoaddr:$src), + (QVLFIWZX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlfsa xoaddr:$src), + (QVLFSXA xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlpcld xoaddr:$src), + (QVLPCLDX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlpcls xoaddr:$src), + (QVLPCLSX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlpcrd xoaddr:$src), + (QVLPCRDX xoaddr:$src)>; +def : Pat<(int_ppc_qpx_qvlpcrs xoaddr:$src), + (QVLPCRSX xoaddr:$src)>; + +def : Pat<(int_ppc_qpx_qvstfd v4f64:$T, xoaddr:$dst), + (QVSTFDX $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfs v4f64:$T, xoaddr:$dst), + (QVSTFSX $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfcda v4f64:$T, xoaddr:$dst), + (QVSTFCDXA $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfcd v4f64:$T, xoaddr:$dst), + (QVSTFCDX $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfcsa v4f64:$T, xoaddr:$dst), + (QVSTFCSXA $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfcs v4f64:$T, xoaddr:$dst), + (QVSTFCSX $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfda v4f64:$T, xoaddr:$dst), + (QVSTFDXA $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfiwa v4f64:$T, xoaddr:$dst), + (QVSTFIWXA $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfiw v4f64:$T, xoaddr:$dst), + (QVSTFIWX $T, xoaddr:$dst)>; +def : Pat<(int_ppc_qpx_qvstfsa v4f64:$T, xoaddr:$dst), + (QVSTFSXA $T, xoaddr:$dst)>; + +def : Pat<(pre_store v4f64:$rS, iPTR:$ptrreg, iPTR:$ptroff), + (QVSTFDUX $rS, $ptrreg, $ptroff)>; +def : Pat<(pre_store v4f32:$rS, iPTR:$ptrreg, iPTR:$ptroff), + (QVSTFSUX $rS, $ptrreg, $ptroff)>; +def : Pat<(pre_truncstv4f32 v4f64:$rS, iPTR:$ptrreg, iPTR:$ptroff), + (QVSTFSUXs $rS, $ptrreg, $ptroff)>; + +def : Pat<(int_ppc_qpx_qvflogical v4f64:$A, v4f64:$B, (i32 imm:$idx)), + (QVFLOGICAL $A, $B, imm:$idx)>; +def : Pat<(int_ppc_qpx_qvgpci (u12:$idx)), + (QVGPCI imm:$idx)>; + +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETOGE), + (QVFLOGICALb (QVFCMPLTb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETOLE), + (QVFLOGICALb (QVFCMPGTb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETONE), + (QVFLOGICALb (QVFCMPEQb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETO), + (QVFLOGICALb (QVFTSTNANb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETUEQ), + (QVFLOGICALb (QVFCMPEQb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETUGT), + (QVFLOGICALb (QVFCMPGTb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETUGE), + (QVFLOGICALb (QVFTSTNANb $FRA, $FRB), + (QVFCMPLTb $FRA, $FRB), (i32 13))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETULT), + (QVFLOGICALb (QVFCMPLTb $FRA, $FRB), + (QVFTSTNANb $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETULE), + (QVFLOGICALb (QVFTSTNANb $FRA, $FRB), + (QVFCMPGTb $FRA, $FRB), (i32 13))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETUNE), + (QVFLOGICALb (QVFTSTNANb $FRA, $FRB), + (QVFCMPEQb $FRA, $FRB), (i32 13))>; + +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETEQ), + (QVFCMPEQb $FRA, $FRB)>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETGT), + (QVFCMPGTb $FRA, $FRB)>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETGE), + (QVFLOGICALb (QVFCMPLTb $FRA, $FRB), + (QVFCMPLTb $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETLT), + (QVFCMPLTb $FRA, $FRB)>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETLE), + (QVFLOGICALb (QVFCMPGTb $FRA, $FRB), + (QVFCMPGTb $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f64:$FRA, v4f64:$FRB, SETNE), + (QVFLOGICALb (QVFCMPEQb $FRA, $FRB), + (QVFCMPEQb $FRA, $FRB), (i32 10))>; + +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETOGE), + (QVFLOGICALb (QVFCMPLTbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETOLE), + (QVFLOGICALb (QVFCMPGTbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETONE), + (QVFLOGICALb (QVFCMPEQbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 8))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETO), + (QVFLOGICALb (QVFTSTNANbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETUEQ), + (QVFLOGICALb (QVFCMPEQbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETUGT), + (QVFLOGICALb (QVFCMPGTbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETUGE), + (QVFLOGICALb (QVFTSTNANbs $FRA, $FRB), + (QVFCMPLTbs $FRA, $FRB), (i32 13))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETULT), + (QVFLOGICALb (QVFCMPLTbs $FRA, $FRB), + (QVFTSTNANbs $FRA, $FRB), (i32 7))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETULE), + (QVFLOGICALb (QVFTSTNANbs $FRA, $FRB), + (QVFCMPGTbs $FRA, $FRB), (i32 13))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETUNE), + (QVFLOGICALb (QVFTSTNANbs $FRA, $FRB), + (QVFCMPEQbs $FRA, $FRB), (i32 13))>; + +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETEQ), + (QVFCMPEQbs $FRA, $FRB)>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETGT), + (QVFCMPGTbs $FRA, $FRB)>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETGE), + (QVFLOGICALb (QVFCMPLTbs $FRA, $FRB), + (QVFCMPLTbs $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETLT), + (QVFCMPLTbs $FRA, $FRB)>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETLE), + (QVFLOGICALb (QVFCMPGTbs $FRA, $FRB), + (QVFCMPGTbs $FRA, $FRB), (i32 10))>; +def : Pat<(setcc v4f32:$FRA, v4f32:$FRB, SETNE), + (QVFLOGICALb (QVFCMPEQbs $FRA, $FRB), + (QVFCMPEQbs $FRA, $FRB), (i32 10))>; + +def : Pat<(and v4i1:$FRA, (not v4i1:$FRB)), + (QVFLOGICALb $FRA, $FRB, (i32 4))>; +def : Pat<(not (or v4i1:$FRA, v4i1:$FRB)), + (QVFLOGICALb $FRA, $FRB, (i32 8))>; +def : Pat<(not (xor v4i1:$FRA, v4i1:$FRB)), + (QVFLOGICALb $FRA, $FRB, (i32 9))>; +def : Pat<(or v4i1:$FRA, (not v4i1:$FRB)), + (QVFLOGICALb $FRA, $FRB, (i32 13))>; +def : Pat<(not (and v4i1:$FRA, v4i1:$FRB)), + (QVFLOGICALb $FRA, $FRB, (i32 14))>; + +def : Pat<(and v4i1:$FRA, v4i1:$FRB), + (QVFLOGICALb $FRA, $FRB, (i32 1))>; +def : Pat<(or v4i1:$FRA, v4i1:$FRB), + (QVFLOGICALb $FRA, $FRB, (i32 7))>; +def : Pat<(xor v4i1:$FRA, v4i1:$FRB), + (QVFLOGICALb $FRA, $FRB, (i32 6))>; +def : Pat<(not v4i1:$FRA), + (QVFLOGICALb $FRA, $FRA, (i32 10))>; + +def : Pat<(v4f64 (fpextend v4f32:$src)), + (COPY_TO_REGCLASS $src, QFRC)>; + +def : Pat<(v4f32 (fround_exact v4f64:$src)), + (COPY_TO_REGCLASS $src, QSRC)>; + +// Extract the underlying floating-point values from the +// QPX (-1.0, 1.0) boolean representation. +def : Pat<(v4f64 (PPCqbflt v4i1:$src)), + (COPY_TO_REGCLASS $src, QFRC)>; + +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETLT)), + (SELECT_QFRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETULT)), + (SELECT_QFRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETLE)), + (SELECT_QFRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETULE)), + (SELECT_QFRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETEQ)), + (SELECT_QFRC (CREQV $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETGE)), + (SELECT_QFRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETUGE)), + (SELECT_QFRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETGT)), + (SELECT_QFRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETUGT)), + (SELECT_QFRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f64 (selectcc i1:$lhs, i1:$rhs, v4f64:$tval, v4f64:$fval, SETNE)), + (SELECT_QFRC (CRXOR $lhs, $rhs), $tval, $fval)>; + +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETLT)), + (SELECT_QSRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETULT)), + (SELECT_QSRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETLE)), + (SELECT_QSRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETULE)), + (SELECT_QSRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETEQ)), + (SELECT_QSRC (CREQV $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETGE)), + (SELECT_QSRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETUGE)), + (SELECT_QSRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETGT)), + (SELECT_QSRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETUGT)), + (SELECT_QSRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4f32 (selectcc i1:$lhs, i1:$rhs, v4f32:$tval, v4f32:$fval, SETNE)), + (SELECT_QSRC (CRXOR $lhs, $rhs), $tval, $fval)>; + +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETLT)), + (SELECT_QBRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETULT)), + (SELECT_QBRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETLE)), + (SELECT_QBRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETULE)), + (SELECT_QBRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETEQ)), + (SELECT_QBRC (CREQV $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETGE)), + (SELECT_QBRC (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETUGE)), + (SELECT_QBRC (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETGT)), + (SELECT_QBRC (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETUGT)), + (SELECT_QBRC (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(v4i1 (selectcc i1:$lhs, i1:$rhs, v4i1:$tval, v4i1:$fval, SETNE)), + (SELECT_QBRC (CRXOR $lhs, $rhs), $tval, $fval)>; + +} // end HasQPX + +let Predicates = [HasQPX, NoNaNsFPMath] in { +def : Pat<(fminnum v4f64:$FRA, v4f64:$FRB), + (QVFSELb (QVFCMPLTb $FRA, $FRB), $FRB, $FRA)>; +def : Pat<(fmaxnum v4f64:$FRA, v4f64:$FRB), + (QVFSELb (QVFCMPGTb $FRA, $FRB), $FRB, $FRA)>; + +def : Pat<(fminnum v4f32:$FRA, v4f32:$FRB), + (QVFSELbs (QVFCMPLTbs $FRA, $FRB), $FRB, $FRA)>; +def : Pat<(fmaxnum v4f32:$FRA, v4f32:$FRB), + (QVFSELbs (QVFCMPGTbs $FRA, $FRB), $FRB, $FRA)>; +} + +let Predicates = [HasQPX, NaNsFPMath] in { +// When either of these operands is NaN, we should return the other operand. +// QVFCMPLT/QVFCMPGT return false is either operand is NaN, which means we need +// to explicitly or with a NaN test on the second operand. +def : Pat<(fminnum v4f64:$FRA, v4f64:$FRB), + (QVFSELb (QVFLOGICALb (QVFCMPLTb $FRA, $FRB), + (QVFTSTNANb $FRB, $FRB), (i32 7)), + $FRB, $FRA)>; +def : Pat<(fmaxnum v4f64:$FRA, v4f64:$FRB), + (QVFSELb (QVFLOGICALb (QVFCMPGTb $FRA, $FRB), + (QVFTSTNANb $FRB, $FRB), (i32 7)), + $FRB, $FRA)>; + +def : Pat<(fminnum v4f32:$FRA, v4f32:$FRB), + (QVFSELbs (QVFLOGICALb (QVFCMPLTbs $FRA, $FRB), + (QVFTSTNANbs $FRB, $FRB), (i32 7)), + $FRB, $FRA)>; +def : Pat<(fmaxnum v4f32:$FRA, v4f32:$FRB), + (QVFSELbs (QVFLOGICALb (QVFCMPGTbs $FRA, $FRB), + (QVFTSTNANbs $FRB, $FRB), (i32 7)), + $FRB, $FRA)>; +} + +#endif // INCLUDED_CAPSTONE_DEPR_INSTR +#endif // CAPSTONE_DEPR_INSTR + +#ifndef INCLUDED_CAPSTONE_DEPR_REGS +#ifdef CAPSTONE_DEPR_REGS +#define INCLUDED_CAPSTONE_DEPR_REGS + +// QFPR - One of the 32 256-bit floating-point vector registers (used for QPX) +class QFPR : PPCReg { + let HWEncoding = SubReg.HWEncoding; + let SubRegs = [SubReg]; + let SubRegIndices = [sub_64]; +} + +// QPX Floating-point registers +foreach Index = 0-31 in { + def QF#Index : QFPR("F"#Index), "q"#Index>, + DwarfRegNum<[!add(Index, 32), !add(Index, 32)]>; +} + +def QFRC : RegisterClass<"PPC", [v4f64], 256, (add (sequence "QF%u", 0, 13), + (sequence "QF%u", 31, 14))>; +def QSRC : RegisterClass<"PPC", [v4f32], 128, (add QFRC)>; +def QBRC : RegisterClass<"PPC", [v4i1], 256, (add QFRC)> { + // These are actually stored as floating-point values where a positive + // number is true and anything else (including NaN) is false. + let Size = 256; +} + +#endif // INCLUDED_CAPSTONE_DEPR_REGS +#endif // CAPSTONE_DEPR_REGS + +#ifndef INCLUDED_CAPSTONE_DEPR_FEATURE +#ifdef CAPSTONE_DEPR_FEATURE +#define INCLUDED_CAPSTONE_DEPR_FEATURE +def FeatureQPX : SubtargetFeature<"qpx","HasQPX", "true", + "Enable QPX instructions", + [FeatureFPU]>; +#endif // INCLUDED_CAPSTONE_DEPR_FEATURE +#endif // CAPSTONE_DEPR_FEATURE + +#ifndef INCLUDED_CAPSTONE_DEPR_INTRINSICS +#ifdef CAPSTONE_DEPR_INTRINSICS +#define INCLUDED_CAPSTONE_DEPR_INTRINSICS + +//===----------------------------------------------------------------------===// +// PowerPC QPX Intrinsics. +// + +let TargetPrefix = "ppc" in { // All PPC intrinsics start with "llvm.ppc.". + /// PowerPC_QPX_Intrinsic - Base class for all QPX intrinsics. + class PowerPC_QPX_Intrinsic ret_types, + list param_types, + list properties> + : ClangBuiltin, + Intrinsic; +} + +//===----------------------------------------------------------------------===// +// PowerPC QPX Intrinsic Class Definitions. +// + +/// PowerPC_QPX_FF_Intrinsic - A PowerPC intrinsic that takes one v4f64 +/// vector and returns one. These intrinsics have no side effects. +class PowerPC_QPX_FF_Intrinsic + : PowerPC_QPX_Intrinsic; + +/// PowerPC_QPX_FFF_Intrinsic - A PowerPC intrinsic that takes two v4f64 +/// vectors and returns one. These intrinsics have no side effects. +class PowerPC_QPX_FFF_Intrinsic + : PowerPC_QPX_Intrinsic; + +/// PowerPC_QPX_FFFF_Intrinsic - A PowerPC intrinsic that takes three v4f64 +/// vectors and returns one. These intrinsics have no side effects. +class PowerPC_QPX_FFFF_Intrinsic + : PowerPC_QPX_Intrinsic; + +/// PowerPC_QPX_Load_Intrinsic - A PowerPC intrinsic that takes a pointer +/// and returns a v4f64. +class PowerPC_QPX_Load_Intrinsic + : PowerPC_QPX_Intrinsic; + +/// PowerPC_QPX_LoadPerm_Intrinsic - A PowerPC intrinsic that takes a pointer +/// and returns a v4f64 permutation. +class PowerPC_QPX_LoadPerm_Intrinsic + : PowerPC_QPX_Intrinsic; + +/// PowerPC_QPX_Store_Intrinsic - A PowerPC intrinsic that takes a pointer +/// and stores a v4f64. +class PowerPC_QPX_Store_Intrinsic + : PowerPC_QPX_Intrinsic; + +//===----------------------------------------------------------------------===// +// PowerPC QPX Intrinsic Definitions. + +let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". + // Add Instructions + def int_ppc_qpx_qvfadd : PowerPC_QPX_FFF_Intrinsic<"qvfadd">; + def int_ppc_qpx_qvfadds : PowerPC_QPX_FFF_Intrinsic<"qvfadds">; + def int_ppc_qpx_qvfsub : PowerPC_QPX_FFF_Intrinsic<"qvfsub">; + def int_ppc_qpx_qvfsubs : PowerPC_QPX_FFF_Intrinsic<"qvfsubs">; + + // Estimate Instructions + def int_ppc_qpx_qvfre : PowerPC_QPX_FF_Intrinsic<"qvfre">; + def int_ppc_qpx_qvfres : PowerPC_QPX_FF_Intrinsic<"qvfres">; + def int_ppc_qpx_qvfrsqrte : PowerPC_QPX_FF_Intrinsic<"qvfrsqrte">; + def int_ppc_qpx_qvfrsqrtes : PowerPC_QPX_FF_Intrinsic<"qvfrsqrtes">; + + // Multiply Instructions + def int_ppc_qpx_qvfmul : PowerPC_QPX_FFF_Intrinsic<"qvfmul">; + def int_ppc_qpx_qvfmuls : PowerPC_QPX_FFF_Intrinsic<"qvfmuls">; + def int_ppc_qpx_qvfxmul : PowerPC_QPX_FFF_Intrinsic<"qvfxmul">; + def int_ppc_qpx_qvfxmuls : PowerPC_QPX_FFF_Intrinsic<"qvfxmuls">; + + // Multiply-add instructions + def int_ppc_qpx_qvfmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfmadd">; + def int_ppc_qpx_qvfmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfmadds">; + def int_ppc_qpx_qvfnmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfnmadd">; + def int_ppc_qpx_qvfnmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfnmadds">; + def int_ppc_qpx_qvfmsub : PowerPC_QPX_FFFF_Intrinsic<"qvfmsub">; + def int_ppc_qpx_qvfmsubs : PowerPC_QPX_FFFF_Intrinsic<"qvfmsubs">; + def int_ppc_qpx_qvfnmsub : PowerPC_QPX_FFFF_Intrinsic<"qvfnmsub">; + def int_ppc_qpx_qvfnmsubs : PowerPC_QPX_FFFF_Intrinsic<"qvfnmsubs">; + def int_ppc_qpx_qvfxmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfxmadd">; + def int_ppc_qpx_qvfxmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfxmadds">; + def int_ppc_qpx_qvfxxnpmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfxxnpmadd">; + def int_ppc_qpx_qvfxxnpmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfxxnpmadds">; + def int_ppc_qpx_qvfxxcpnmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfxxcpnmadd">; + def int_ppc_qpx_qvfxxcpnmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfxxcpnmadds">; + def int_ppc_qpx_qvfxxmadd : PowerPC_QPX_FFFF_Intrinsic<"qvfxxmadd">; + def int_ppc_qpx_qvfxxmadds : PowerPC_QPX_FFFF_Intrinsic<"qvfxxmadds">; + + // Select Instruction + def int_ppc_qpx_qvfsel : PowerPC_QPX_FFFF_Intrinsic<"qvfsel">; + + // Permute Instruction + def int_ppc_qpx_qvfperm : PowerPC_QPX_FFFF_Intrinsic<"qvfperm">; + + // Convert and Round Instructions + def int_ppc_qpx_qvfctid : PowerPC_QPX_FF_Intrinsic<"qvfctid">; + def int_ppc_qpx_qvfctidu : PowerPC_QPX_FF_Intrinsic<"qvfctidu">; + def int_ppc_qpx_qvfctidz : PowerPC_QPX_FF_Intrinsic<"qvfctidz">; + def int_ppc_qpx_qvfctiduz : PowerPC_QPX_FF_Intrinsic<"qvfctiduz">; + def int_ppc_qpx_qvfctiw : PowerPC_QPX_FF_Intrinsic<"qvfctiw">; + def int_ppc_qpx_qvfctiwu : PowerPC_QPX_FF_Intrinsic<"qvfctiwu">; + def int_ppc_qpx_qvfctiwz : PowerPC_QPX_FF_Intrinsic<"qvfctiwz">; + def int_ppc_qpx_qvfctiwuz : PowerPC_QPX_FF_Intrinsic<"qvfctiwuz">; + def int_ppc_qpx_qvfcfid : PowerPC_QPX_FF_Intrinsic<"qvfcfid">; + def int_ppc_qpx_qvfcfidu : PowerPC_QPX_FF_Intrinsic<"qvfcfidu">; + def int_ppc_qpx_qvfcfids : PowerPC_QPX_FF_Intrinsic<"qvfcfids">; + def int_ppc_qpx_qvfcfidus : PowerPC_QPX_FF_Intrinsic<"qvfcfidus">; + def int_ppc_qpx_qvfrsp : PowerPC_QPX_FF_Intrinsic<"qvfrsp">; + def int_ppc_qpx_qvfriz : PowerPC_QPX_FF_Intrinsic<"qvfriz">; + def int_ppc_qpx_qvfrin : PowerPC_QPX_FF_Intrinsic<"qvfrin">; + def int_ppc_qpx_qvfrip : PowerPC_QPX_FF_Intrinsic<"qvfrip">; + def int_ppc_qpx_qvfrim : PowerPC_QPX_FF_Intrinsic<"qvfrim">; + + // Move Instructions + def int_ppc_qpx_qvfneg : PowerPC_QPX_FF_Intrinsic<"qvfneg">; + def int_ppc_qpx_qvfabs : PowerPC_QPX_FF_Intrinsic<"qvfabs">; + def int_ppc_qpx_qvfnabs : PowerPC_QPX_FF_Intrinsic<"qvfnabs">; + def int_ppc_qpx_qvfcpsgn : PowerPC_QPX_FFF_Intrinsic<"qvfcpsgn">; + + // Compare Instructions + def int_ppc_qpx_qvftstnan : PowerPC_QPX_FFF_Intrinsic<"qvftstnan">; + def int_ppc_qpx_qvfcmplt : PowerPC_QPX_FFF_Intrinsic<"qvfcmplt">; + def int_ppc_qpx_qvfcmpgt : PowerPC_QPX_FFF_Intrinsic<"qvfcmpgt">; + def int_ppc_qpx_qvfcmpeq : PowerPC_QPX_FFF_Intrinsic<"qvfcmpeq">; + + // Load instructions + def int_ppc_qpx_qvlfd : PowerPC_QPX_Load_Intrinsic<"qvlfd">; + def int_ppc_qpx_qvlfda : PowerPC_QPX_Load_Intrinsic<"qvlfda">; + def int_ppc_qpx_qvlfs : PowerPC_QPX_Load_Intrinsic<"qvlfs">; + def int_ppc_qpx_qvlfsa : PowerPC_QPX_Load_Intrinsic<"qvlfsa">; + + def int_ppc_qpx_qvlfcda : PowerPC_QPX_Load_Intrinsic<"qvlfcda">; + def int_ppc_qpx_qvlfcd : PowerPC_QPX_Load_Intrinsic<"qvlfcd">; + def int_ppc_qpx_qvlfcsa : PowerPC_QPX_Load_Intrinsic<"qvlfcsa">; + def int_ppc_qpx_qvlfcs : PowerPC_QPX_Load_Intrinsic<"qvlfcs">; + def int_ppc_qpx_qvlfiwaa : PowerPC_QPX_Load_Intrinsic<"qvlfiwaa">; + def int_ppc_qpx_qvlfiwa : PowerPC_QPX_Load_Intrinsic<"qvlfiwa">; + def int_ppc_qpx_qvlfiwza : PowerPC_QPX_Load_Intrinsic<"qvlfiwza">; + def int_ppc_qpx_qvlfiwz : PowerPC_QPX_Load_Intrinsic<"qvlfiwz">; + + def int_ppc_qpx_qvlpcld : PowerPC_QPX_LoadPerm_Intrinsic<"qvlpcld">; + def int_ppc_qpx_qvlpcls : PowerPC_QPX_LoadPerm_Intrinsic<"qvlpcls">; + def int_ppc_qpx_qvlpcrd : PowerPC_QPX_LoadPerm_Intrinsic<"qvlpcrd">; + def int_ppc_qpx_qvlpcrs : PowerPC_QPX_LoadPerm_Intrinsic<"qvlpcrs">; + + // Store instructions + def int_ppc_qpx_qvstfd : PowerPC_QPX_Store_Intrinsic<"qvstfd">; + def int_ppc_qpx_qvstfda : PowerPC_QPX_Store_Intrinsic<"qvstfda">; + def int_ppc_qpx_qvstfs : PowerPC_QPX_Store_Intrinsic<"qvstfs">; + def int_ppc_qpx_qvstfsa : PowerPC_QPX_Store_Intrinsic<"qvstfsa">; + + def int_ppc_qpx_qvstfcda : PowerPC_QPX_Store_Intrinsic<"qvstfcda">; + def int_ppc_qpx_qvstfcd : PowerPC_QPX_Store_Intrinsic<"qvstfcd">; + def int_ppc_qpx_qvstfcsa : PowerPC_QPX_Store_Intrinsic<"qvstfcsa">; + def int_ppc_qpx_qvstfcs : PowerPC_QPX_Store_Intrinsic<"qvstfcs">; + def int_ppc_qpx_qvstfiwa : PowerPC_QPX_Store_Intrinsic<"qvstfiwa">; + def int_ppc_qpx_qvstfiw : PowerPC_QPX_Store_Intrinsic<"qvstfiw">; + + // Logical and permutation formation + def int_ppc_qpx_qvflogical : PowerPC_QPX_Intrinsic<"qvflogical", + [llvm_v4f64_ty], + [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i32_ty], + [IntrNoMem]>; + def int_ppc_qpx_qvgpci : PowerPC_QPX_Intrinsic<"qvgpci", + [llvm_v4f64_ty], [llvm_i32_ty], [IntrNoMem]>; +} + +#endif // INCLUDED_CAPSTONE_DEPR_INTRINSICS +#endif // CAPSTONE_DEPR_INTRINSICS \ No newline at end of file diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td index 0322bb37b1fd..5d6c171ab7bc 100644 --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -1267,6 +1267,7 @@ def : InstAlias<"mtspefscr $Rx", (MTSPR8 512, g8rc:$Rx)>; // Sign extending loads. +let mayLoad = 1 in { let PPC970_Unit = 2 in { let Interpretation64Bit = 1, isCodeGenOnly = 1 in def LHA8: DForm_1<42, (outs g8rc:$RST), (ins (memri $D, $RA):$addr), @@ -1287,6 +1288,8 @@ def LWAX : XForm_1_memOp<31, 341, (outs g8rc:$RST), (ins (memrr $RA, $RB):$addr) "lwax $RST, $addr", IIC_LdStLHA, [(set i64:$RST, (sextloadi32 XForm:$addr))]>, isPPC64, PPC970_DGroup_Cracked, SExt32To64; +} + // For fast-isel: let isCodeGenOnly = 1, mayLoad = 1, hasSideEffects = 0 in { def LWA_32 : DSForm_1<58, 2, (outs gprc:$RST), (ins (memrix $D, $RA):$addr), @@ -1390,7 +1393,7 @@ def LWZUX8 : XForm_1_memOp<31, 55, (outs g8rc:$RST, ptr_rc_nor0:$ea_result), // Full 8-byte loads. -let PPC970_Unit = 2 in { +let PPC970_Unit = 2, mayLoad = 1 in { def LD : DSForm_1<58, 0, (outs g8rc:$RST), (ins (memrix $D, $RA):$addr), "ld $RST, $addr", IIC_LdStLD, [(set i64:$RST, (load DSForm:$addr))]>, isPPC64; @@ -1626,7 +1629,7 @@ def PADDIdtprel : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, s16imm isPPC64; let PPC970_Unit = 2 in { -let Interpretation64Bit = 1, isCodeGenOnly = 1 in { +let Interpretation64Bit = 1, isCodeGenOnly = 1, mayStore = 1 in { // Truncating stores. def STB8 : DForm_1<38, (outs), (ins g8rc:$RST, (memri $D, $RA):$addr), "stb $RST, $addr", IIC_LdStStore, @@ -1652,6 +1655,7 @@ def STWX8 : XForm_8_memOp<31, 151, (outs), (ins g8rc:$RST, (memrr $RA, $RB):$add } // Interpretation64Bit // Normal 8-byte stores. +let mayStore = 1 in { def STD : DSForm_1<62, 0, (outs), (ins g8rc:$RST, (memrix $D, $RA):$addr), "std $RST, $addr", IIC_LdStSTD, [(store i64:$RST, DSForm:$addr)]>, isPPC64; @@ -1666,6 +1670,7 @@ def STDBRX: XForm_8_memOp<31, 660, (outs), (ins g8rc:$RST, (memrr $RA, $RB):$add [(PPCstbrx i64:$RST, ForceXForm:$addr, i64)]>, isPPC64, PPC970_DGroup_Cracked; } +} let mayStore = 1, hasNoSchedulingInfo = 1 in { // Normal 16-byte stores. diff --git a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td index 386c94a32499..ccebec1e4818 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td +++ b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td @@ -426,6 +426,7 @@ def LVXL : XForm_1_memOp<31, 359, (outs vrrc:$RST), (ins (memrr $RA, $RB):$addr) [(set v4i32:$RST, (int_ppc_altivec_lvxl ForceXForm:$addr))]>; } +let mayLoad = 1 in { def LVSL : XForm_1_memOp<31, 6, (outs vrrc:$RST), (ins (memrr $RA, $RB):$addr), "lvsl $RST, $addr", IIC_LdStLoad, [(set v16i8:$RST, (int_ppc_altivec_lvsl ForceXForm:$addr))]>, @@ -434,6 +435,7 @@ def LVSR : XForm_1_memOp<31, 38, (outs vrrc:$RST), (ins (memrr $RA, $RB):$addr) "lvsr $RST, $addr", IIC_LdStLoad, [(set v16i8:$RST, (int_ppc_altivec_lvsr ForceXForm:$addr))]>, PPC970_Unit_LSU; +} let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in { // Stores. def STVEBX: XForm_8_memOp<31, 135, (outs), (ins vrrc:$RST, (memrr $RA, $RB):$addr), diff --git a/llvm/lib/Target/PowerPC/PPCInstrFormats.td b/llvm/lib/Target/PowerPC/PPCInstrFormats.td index 5389f42a325c..8db29ff0ca49 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrFormats.td +++ b/llvm/lib/Target/PowerPC/PPCInstrFormats.td @@ -2380,3 +2380,7 @@ class PPCPostRAExpPseudo pattern> class PseudoXFormMemOp pattern> : PPCPostRAExpPseudo, XFormMemOp; +#define CAPSTONE_PS_FORMATS +include "PPCInstrPairedSingle.td" +#define CAPSTONE_DEPR_FORMATS +include "PPCDeprecated.td" diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td index 5550ba420739..6a8c60324ef9 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -694,39 +694,66 @@ def PDForm : ComplexPattern; //===----------------------------------------------------------------------===// // PowerPC Instruction Predicate Definitions. -def In32BitMode : Predicate<"!Subtarget->isPPC64()">; -def In64BitMode : Predicate<"Subtarget->isPPC64()">; -def IsBookE : Predicate<"Subtarget->isBookE()">; -def IsNotBookE : Predicate<"!Subtarget->isBookE()">; -def HasOnlyMSYNC : Predicate<"Subtarget->hasOnlyMSYNC()">; -def HasSYNC : Predicate<"!Subtarget->hasOnlyMSYNC()">; -def IsPPC4xx : Predicate<"Subtarget->isPPC4xx()">; -def IsPPC6xx : Predicate<"Subtarget->isPPC6xx()">; -def IsE500 : Predicate<"Subtarget->isE500()">; -def HasSPE : Predicate<"Subtarget->hasSPE()">; -def HasICBT : Predicate<"Subtarget->hasICBT()">; -def HasPartwordAtomics : Predicate<"Subtarget->hasPartwordAtomics()">; -def HasQuadwordAtomics : Predicate<"Subtarget->hasQuadwordAtomics()">; +def In32BitMode : Predicate<"!Subtarget->isPPC64()">, + AssemblerPredicate<(all_of (not Feature64Bit)), "64bit">; +def In64BitMode : Predicate<"Subtarget->isPPC64()">, + AssemblerPredicate<(all_of Feature64Bit), "64bit">; +def IsBookE : Predicate<"Subtarget->isBookE()">, + AssemblerPredicate<(all_of FeatureBookE), "booke">; +def IsNotBookE : Predicate<"!Subtarget->isBookE()">, + AssemblerPredicate<(all_of (not FeatureBookE)), "notbooke">; +def HasOnlyMSYNC : Predicate<"Subtarget->hasOnlyMSYNC()">, + AssemblerPredicate<(all_of FeatureMSYNC), "msync">; +def HasSYNC : Predicate<"!Subtarget->hasOnlyMSYNC()">, + AssemblerPredicate<(all_of (not FeatureMSYNC)), "sync">; +def IsPPC4xx : Predicate<"Subtarget->isPPC4xx()">, + AssemblerPredicate<(all_of FeaturePPC4xx), "ppc4xx">; +def IsPPC6xx : Predicate<"Subtarget->isPPC6xx()">, + AssemblerPredicate<(all_of FeaturePPC6xx), "ppc6xx">; +def IsE500 : Predicate<"Subtarget->isE500()">, + AssemblerPredicate<(all_of FeatureE500), "e500">; +def HasSPE : Predicate<"Subtarget->hasSPE()">, + AssemblerPredicate<(all_of FeatureSPE), "spe">; +def HasICBT : Predicate<"Subtarget->hasICBT()">, + AssemblerPredicate<(all_of FeatureICBT), "icbt">; +def HasPartwordAtomics : Predicate<"Subtarget->hasPartwordAtomics()">, + AssemblerPredicate<(all_of FeaturePartwordAtomic), "partwordatomic">; +def HasQuadwordAtomics : Predicate<"Subtarget->hasQuadwordAtomics()">, + AssemblerPredicate<(all_of FeatureQuadwordAtomic), "quadwordatomic">; def NoNaNsFPMath - : Predicate<"Subtarget->getTargetMachine().Options.NoNaNsFPMath">; + : Predicate<"Subtarget->getTargetMachine().Options.NoNaNsFPMath">, + AssemblerPredicate<(all_of (not FeatureFPU)), "notfpu">; def NaNsFPMath - : Predicate<"!Subtarget->getTargetMachine().Options.NoNaNsFPMath">; -def HasBPERMD : Predicate<"Subtarget->hasBPERMD()">; -def HasExtDiv : Predicate<"Subtarget->hasExtDiv()">; -def IsISA2_06 : Predicate<"Subtarget->isISA2_06()">; -def IsISA2_07 : Predicate<"Subtarget->isISA2_07()">; -def IsISA3_0 : Predicate<"Subtarget->isISA3_0()">; -def HasFPU : Predicate<"Subtarget->hasFPU()">; -def PCRelativeMemops : Predicate<"Subtarget->hasPCRelativeMemops()">; -def IsNotISA3_1 : Predicate<"!Subtarget->isISA3_1()">; + : Predicate<"!Subtarget->getTargetMachine().Options.NoNaNsFPMath">, + AssemblerPredicate<(all_of FeatureFPU), "fpu">; +def HasBPERMD : Predicate<"Subtarget->hasBPERMD()">, + AssemblerPredicate<(all_of FeatureBPERMD), "bpermd">; +def HasExtDiv : Predicate<"Subtarget->hasExtDiv()">, + AssemblerPredicate<(all_of FeatureFPU), "fpu">; +def IsISA2_06 : Predicate<"Subtarget->isISA2_06()">, + AssemblerPredicate<(all_of FeatureBPERMD), "bpermd">; +def IsISA2_07 : Predicate<"Subtarget->isISA2_07()">, + AssemblerPredicate<(all_of FeatureExtDiv), "extdiv">; +def IsISA3_0 : Predicate<"Subtarget->isISA3_0()">, + AssemblerPredicate<(all_of FeatureISA2_06), "isa2_06">; +def HasFPU : Predicate<"Subtarget->hasFPU()">, + AssemblerPredicate<(all_of FeatureISA2_07), "isa2_07">; +def PCRelativeMemops : Predicate<"Subtarget->hasPCRelativeMemops()">, + AssemblerPredicate<(all_of FeatureISA3_0), "isa3_0">; +def IsNotISA3_1 : Predicate<"!Subtarget->isISA3_1()">, + AssemblerPredicate<(all_of (not FeatureISA3_1)), "notisa3_1">; // AIX assembler may not be modern enough to support some extended mne. -def ModernAs: Predicate<"!Subtarget->isAIXABI() || Subtarget->HasModernAIXAs">, +def ModernAs: Predicate<"!Subtarget->isAIXABI() || Subtarget->HasModernAIXAs">, AssemblerPredicate<(any_of (not AIXOS), FeatureModernAIXAs)>; -def IsAIX : Predicate<"Subtarget->isAIXABI()">; -def NotAIX : Predicate<"!Subtarget->isAIXABI()">; -def IsISAFuture : Predicate<"Subtarget->isISAFuture()">; -def IsNotISAFuture : Predicate<"!Subtarget->isISAFuture()">; +def IsAIX : Predicate<"Subtarget->isAIXABI()">, + AssemblerPredicate<(all_of AIXOS), "aix">; +def NotAIX : Predicate<"!Subtarget->isAIXABI()">, + AssemblerPredicate<(all_of (not AIXOS)), "notaix">; +def IsISAFuture : Predicate<"Subtarget->isISAFuture()">, + AssemblerPredicate<(all_of FeatureISAFuture), "isafuture">; +def IsNotISAFuture : Predicate<"!Subtarget->isISAFuture()">, + AssemblerPredicate<(all_of (not FeatureISAFuture)), "notisafuture">; //===----------------------------------------------------------------------===// // PowerPC Multiclass Definitions. @@ -1683,16 +1710,20 @@ def DCBA : DCB_Form<758, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcba $addr" def DCBI : DCB_Form<470, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcbi $addr", IIC_LdStDCBF, [(int_ppc_dcbi xoaddr:$addr)]>, PPC970_DGroup_Single; +let mayLoad = 1 in def DCBST : DCB_Form<54, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcbst $addr", IIC_LdStDCBF, [(int_ppc_dcbst xoaddr:$addr)]>, PPC970_DGroup_Single; +let mayStore = 1 in { def DCBZ : DCB_Form<1014, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcbz $addr", IIC_LdStDCBF, [(int_ppc_dcbz xoaddr:$addr)]>, PPC970_DGroup_Single; def DCBZL : DCB_Form<1014, 1, (outs), (ins (memrr $RA, $RB):$addr), "dcbzl $addr", IIC_LdStDCBF, [(int_ppc_dcbzl xoaddr:$addr)]>, PPC970_DGroup_Single; +} +let mayLoad = 1 in def DCBF : DCB_Form_hint<86, (outs), (ins u3imm:$TH, (memrr $RA, $RB):$addr), "dcbf $addr, $TH", IIC_LdStDCBF, []>, PPC970_DGroup_Single; @@ -1710,10 +1741,12 @@ def ICBLC : XForm_icbt<31, 230, (outs), (ins u4imm:$CT, (memrr $RA, $RB):$addr) "icblc $CT, $addr", IIC_LdStStore>, Requires<[HasICBT]>; def ICBLQ : XForm_icbt<31, 198, (outs), (ins u4imm:$CT, (memrr $RA, $RB):$addr), "icblq. $CT, $addr", IIC_LdStLoad>, Requires<[HasICBT]>; +let mayLoad = 1 in { def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, (memrr $RA, $RB):$addr), "icbt $CT, $addr", IIC_LdStLoad>, Requires<[HasICBT]>; def ICBTLS : XForm_icbt<31, 486, (outs), (ins u4imm:$CT, (memrr $RA, $RB):$addr), "icbtls $CT, $addr", IIC_LdStLoad>, Requires<[HasICBT]>; +} def : Pat<(int_ppc_dcbt xoaddr:$dst), (DCBT 0, xoaddr:$dst)>; @@ -1941,7 +1974,7 @@ def ADDG6S : XOForm_1<31, 74, 0, (outs gprc:$RT), (ins gprc:$RA, gprc:$RB), // // Unindexed (r+i) Loads. -let PPC970_Unit = 2 in { +let PPC970_Unit = 2, mayLoad = 1 in { def LBZ : DForm_1<34, (outs gprc:$RST), (ins (memri $D, $RA):$addr), "lbz $RST, $addr", IIC_LdStLoad, [(set i32:$RST, (zextloadi8 DForm:$addr))]>, ZExt32To64, @@ -2151,7 +2184,7 @@ def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STFDU $rS, iaddroff:$ptroff, $ptrreg)>; // Indexed (r+r) Stores. -let PPC970_Unit = 2 in { +let PPC970_Unit = 2, mayStore = 1 in { def STBX : XForm_8_memOp<31, 215, (outs), (ins gprc:$RST, (memrr $RA, $RB):$addr), "stbx $RST, $addr", IIC_LdStStore, [(truncstorei8 i32:$RST, XForm:$addr)]>, @@ -4221,6 +4254,7 @@ def STSWI : XForm_base_r3xo_memOp<31, 725, (outs), def ISYNC : XLForm_2_ext<19, 150, 0, 0, 0, (outs), (ins), "isync", IIC_SprISYNC, []>; +let mayLoad = 1 in def ICBI : XForm_1a<31, 982, (outs), (ins (memrr $RA, $RB):$addr), "icbi $addr", IIC_LdStICBI, []>; @@ -4392,6 +4426,7 @@ def NAP : XLForm_1_np<19, 434, (outs), (ins), "nap", IIC_BrB, []>; def ATTN : XForm_attn<0, 256, (outs), (ins), "attn", IIC_BrB>; +let mayLoad = 1 in { def LBZCIX : XForm_base_r3xo_memOp<31, 853, (outs gprc:$RST), (ins gprc:$RA, gprc:$RB), "lbzcix $RST, $RA, $RB", IIC_LdStLoad, []>; @@ -4404,7 +4439,9 @@ def LWZCIX : XForm_base_r3xo_memOp<31, 789, (outs gprc:$RST), def LDCIX : XForm_base_r3xo_memOp<31, 885, (outs gprc:$RST), (ins gprc:$RA, gprc:$RB), "ldcix $RST, $RA, $RB", IIC_LdStLoad, []>; +} // mayLoad = 1 +let mayStore = 1 in { def STBCIX : XForm_base_r3xo_memOp<31, 981, (outs), (ins gprc:$RST, gprc:$RA, gprc:$RB), "stbcix $RST, $RA, $RB", IIC_LdStLoad, []>; @@ -4417,9 +4454,11 @@ def STWCIX : XForm_base_r3xo_memOp<31, 917, (outs), def STDCIX : XForm_base_r3xo_memOp<31, 1013, (outs), (ins gprc:$RST, gprc:$RA, gprc:$RB), "stdcix $RST, $RA, $RB", IIC_LdStLoad, []>; +} // mayStore = 1 // External PID Load Store Instructions +let mayLoad = 1 in { def LBEPX : XForm_1<31, 95, (outs gprc:$RST), (ins (memrr $RA, $RB):$addr), "lbepx $RST, $addr", IIC_LdStLoad, []>, Requires<[IsE500]>; @@ -4435,7 +4474,9 @@ def LHEPX : XForm_1<31, 287, (outs gprc:$RST), (ins (memrr $RA, $RB):$addr), def LWEPX : XForm_1<31, 31, (outs gprc:$RST), (ins (memrr $RA, $RB):$addr), "lwepx $RST, $addr", IIC_LdStLoad, []>, Requires<[IsE500]>; +} +let mayStore = 1 in { def STBEPX : XForm_8<31, 223, (outs), (ins gprc:$RST, (memrr $RA, $RB):$addr), "stbepx $RST, $addr", IIC_LdStStore, []>, Requires<[IsE500]>; @@ -4451,6 +4492,7 @@ def STHEPX : XForm_8<31, 415, (outs), (ins gprc:$RST, (memrr $RA, $RB):$addr), def STWEPX : XForm_8<31, 159, (outs), (ins gprc:$RST, (memrr $RA, $RB):$addr), "stwepx $RST, $addr", IIC_LdStStore, []>, Requires<[IsE500]>; +} def DCBFEP : DCB_Form<127, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcbfep $addr", IIC_LdStDCBF, []>, Requires<[IsE500]>; @@ -4472,6 +4514,7 @@ def DCBZEP : DCB_Form<1023, 0, (outs), (ins (memrr $RA, $RB):$addr), "dcbzep $a def DCBZLEP : DCB_Form<1023, 1, (outs), (ins (memrr $RA, $RB):$addr), "dcbzlep $addr", IIC_LdStDCBF, []>, Requires<[IsE500]>; +let mayLoad = 1 in def ICBIEP : XForm_1a<31, 991, (outs), (ins (memrr $RA, $RB):$addr), "icbiep $addr", IIC_LdStICBI, []>, Requires<[IsE500]>; @@ -4504,9 +4547,11 @@ def DCBTSTCT : PPCAsmPseudo<"dcbtstct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTSTDS : PPCAsmPseudo<"dcbtstds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTSTT : PPCAsmPseudo<"dcbtstt $dst", (ins memrr:$dst)>; +let mayLoad = 1 in { def DCBFx : PPCAsmPseudo<"dcbf $dst", (ins memrr:$dst)>; def DCBFL : PPCAsmPseudo<"dcbfl $dst", (ins memrr:$dst)>; def DCBFLP : PPCAsmPseudo<"dcbflp $dst", (ins memrr:$dst)>; +} def : Pat<(int_ppc_isync), (ISYNC)>; def : Pat<(int_ppc_dcbfl xoaddr:$dst), @@ -4702,6 +4747,7 @@ def : InstAlias<"tlbilxva $RA, $RB", (TLBILX 3, gprc:$RA, gprc:$RB)>, Requires<[IsBookE]>; def : InstAlias<"tlbilxva $RB", (TLBILX 3, R0, gprc:$RB)>, Requires<[IsBookE]>; +let mayLoad = 1 in def LAx : PPCAsmPseudo<"la $rA, $addr", (ins gprc:$rA, memri:$addr)>; def SUBI : PPCAsmPseudo<"subi $rA, $rB, $imm", @@ -5320,3 +5366,10 @@ def : Pat<(int_ppc_dcbtt ForceXForm:$dst), def : Pat<(int_ppc_stfiw ForceXForm:$dst, f64:$XT), (STFIWX f64:$XT, ForceXForm:$dst)>; + +#define CAPSTONE_DEPR_INTRINSICS +include "PPCDeprecated.td" +#define CAPSTONE_DEPR_INSTR +#define CAPSTONE_PS_INSTR +include "PPCDeprecated.td" +include "PPCInstrPairedSingle.td" diff --git a/llvm/lib/Target/PowerPC/PPCInstrPairedSingle.td b/llvm/lib/Target/PowerPC/PPCInstrPairedSingle.td new file mode 100644 index 000000000000..7c43c4ee6c55 --- /dev/null +++ b/llvm/lib/Target/PowerPC/PPCInstrPairedSingle.td @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Definitions for the PowerPC Paired Single instructions. +// +// Originally these were created by DarkKirb in https://reviews.llvm.org/D85137. +// terorie extended these defintions in https://github.com/capstone-engine/capstone/pull/1898 + + +#ifndef INCLUDED_CAPSTONE_PS_FORMATS +#ifdef CAPSTONE_PS_FORMATS +#define INCLUDED_CAPSTONE_PS_FORMATS + +def PPCDispRID12Operand : AsmOperandClass { + let Name = "DispRID12"; let PredicateMethod = "isS12Imm"; + let RenderMethod = "addImmOperands"; +} + +def dispRID12 : Operand { + let ParserMatchClass = PPCDispRID12Operand; + let OperandType = "OPERAND_IMMEDIATE"; +} + +def memrid12 : Operand { // Paired Single displacement where imm is 12 bits. + let PrintMethod = "printMemRegImm"; + let MIOperandInfo = (ops dispRID12:$imm, ptr_rc_nor0:$reg); + let OperandType = "OPERAND_MEMORY"; +} + +// PSForm_qd - Undocumented paired-singles quantized load/store form direct. +class PSForm_qd op, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I { + bits<5> FRT; + bit W; + bits<3> I; + bits<12> d; + bits<5> A; + + let Inst{6-10} = FRT; + let Inst{11-15} = A; + let Inst{16} = W; + let Inst{17-19} = I; + let Inst{20-31} = d; +} + +// PSForm_qi - Undocumented paired-singles quantized load/store form indexed. +class PSForm_qi psqop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I<4, OOL, IOL, asmstr, itin> { + bits<5> FRT; + bits<5> A; + bits<5> B; + bit W; + bits<3> I; + + let Inst{6-10} = FRT; + let Inst{11-15} = A; + let Inst{16-20} = B; + let Inst{21} = W; + let Inst{22-24} = I; + let Inst{25-30} = psqop; + let Inst{31} = 0; +} + +// PSForm_x - Undocumented paired-singles operation base form, short opcode. +class PSForm_x psxop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I<4, OOL, IOL, asmstr, itin> { + bits<5> FRT; + bits<5> FRA; + bits<5> FRB; + bits<5> FRC; + bit RC = 0; // set by isRecordForm + + let Inst{6-10} = FRT; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-25} = FRC; + let Inst{26-30} = psxop; + let Inst{31} = RC; +} + +// PSForm_y - Undocumented paired-singles operation base form, long opcode. +class PSForm_y psyop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I<4, OOL, IOL, asmstr, itin> { + bits<5> FRT; + bits<5> FRA; + bits<5> FRB; + bit RC = 0; // set by isRecordForm + + let Inst{6-10} = FRT; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-30} = psyop; + let Inst{31} = RC; +} + +// PSForm_c - Undocumented paired-singles compare form. +class PSForm_c pszop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I<4, OOL, IOL, asmstr, itin> { + bits<3> BF; + bits<5> FRA; + bits<5> FRB; + + let Inst{6-8} = BF; + let Inst{9-10} = 0; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-30} = pszop; + let Inst{31} = 0; +} + +// Undocumented dcbz_l instruction. +class DCBZL_Form xop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : I<4, OOL, IOL, asmstr, itin> { + bits<5> A; + bits<5> B; + + let Inst{6-10} = 0; + let Inst{11-15} = A; + let Inst{16-20} = B; + let Inst{21-30} = xop; + let Inst{31} = 0; +} + +#endif // INCLUDED_CAPSTONE_PS_FORMATS +#endif // CAPSTONE_PS_FORMATS + +#ifndef INCLUDED_CAPSTONE_PS_INSTR +#ifdef CAPSTONE_PS_INSTR +#define INCLUDED_CAPSTONE_PS_INSTR + +let Predicates = [HasPS] in { +let DecoderNamespace = "PS" in { + +let mayLoad = 1 in { +def PSQ_L : PSForm_qd<56, + (outs f8rc:$FRT), (ins (memrid12 $IMM, $RA):$src, u1imm:$W, u3imm: $I), + "psq_l $FRT, $src, $W, $I", IIC_FPGeneral>; +def PSQ_LU : PSForm_qd<57, + (outs f8rc:$FRT), (ins (memrid12 $IMM, $RA):$src, u1imm:$W, u3imm: $I), + "psq_lu $FRT, $src, $W, $I", IIC_FPGeneral>; +def PSQ_LX : PSForm_qi<6, + (outs f8rc:$FRT), (ins gprc:$rA, gprc:$rB, u1imm:$W, u3imm: $I), + "psq_lx $FRT, $rA, $rB, $W, $I", IIC_FPGeneral>; +def PSQ_LUX : PSForm_qi<38, + (outs f8rc:$FRT), (ins gprc:$rA, gprc:$rB, u1imm:$W, u3imm: $I), + "psq_lux $FRT, $rA, $rB, $W, $I", IIC_FPGeneral>; +} + +let mayStore = 1 in { +def PSQ_ST : PSForm_qd<60, + (outs), (ins f8rc:$FRT, (memrid12 $IMM, $RA):$dst, u1imm:$W, u3imm: $I), + "psq_st $FRT, $dst, $W, $I", IIC_FPGeneral>; +def PSQ_STU : PSForm_qd<61, + (outs), (ins f8rc:$FRT, (memrid12 $IMM, $RA):$dst, u1imm:$W, u3imm: $I), + "psq_stu $FRT, $dst, $W, $I", IIC_FPGeneral>; +def PSQ_STX : PSForm_qi<7, + (outs), (ins f8rc:$FRT,gprc:$rA, gprc:$rB, u1imm:$W, u3imm: $I), + "psq_stx $FRT, $rA, $rB, $W, $I", IIC_FPGeneral>; +def PSQ_STUX : PSForm_qi<39, + (outs), (ins f8rc:$FRT,gprc:$rA, gprc:$rB, u1imm:$W, u3imm: $I), + "psq_stux $FRT, $rA, $rB, $W, $I", IIC_FPGeneral>; +} + +// op. FRT, FRA, FRC, FRB +multiclass PSForm_xr psxop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_x; + let Defs = [CR1] in + def o : PSForm_x, + isRecordForm; + } +} + +// op FRT, FRA, FRB +class PSForm_x1 psxop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : PSForm_x { + let FRC = 0; +} + +// op. FRT, FRA, FRB +multiclass PSForm_x1r psxop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_x1; + let Defs = [CR1] in + def o : PSForm_x1, + isRecordForm; + } +} + +// op FRT, FRB +class PSForm_x2 psxop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : PSForm_x { + let FRA = 0; + let FRC = 0; +} + +// op. FRT, FRB +multiclass PSForm_x2r psxop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_x2; + let Defs = [CR1] in + def o : PSForm_x2, + isRecordForm; + } +} + +// op FRT, FRA, FRC +class PSForm_x3 psxop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : PSForm_x { + let FRB = 0; +} + +// op. FRT, FRA, FRC +multiclass PSForm_x3r psxop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_x3; + let Defs = [CR1] in + def o : PSForm_x3, + isRecordForm; + } +} + +// op. FRT, FRA, FRB +multiclass PSForm_yr psyop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_y; + let Defs = [CR1] in + def o : PSForm_y, + isRecordForm; + } +} + +// op FRT, FRA, FRB +class PSForm_y2 psyop, dag OOL, dag IOL, string asmstr, + InstrItinClass itin> + : PSForm_y { + let FRA = 0; +} + +// op. FRT, FRB +multiclass PSForm_y2r psyop, dag OOL, dag IOL, string asmbase, + string asmstr, InstrItinClass itin> { + let BaseName = asmbase in { + def NAME : PSForm_y2; + let Defs = [CR1] in + def o : PSForm_y2, + isRecordForm; + } +} + +defm PS_DIV : PSForm_x1r<18, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_div", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_SUB : PSForm_x1r<20, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_sub", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_ADD : PSForm_x1r<21, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_add", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_SEL : PSForm_xr<23, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_sel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_RES : PSForm_x2r<24, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_res", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_MUL : PSForm_x3r<25, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC), + "ps_mul", "$FRT, $FRA, $FRC", IIC_FPGeneral>; +defm PS_RSQRTE : PSForm_x2r<26, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_rsqrte", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_MSUB : PSForm_xr<28, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_msub", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_MADD : PSForm_xr<29, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_madd", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_NMSUB : PSForm_xr<30, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_nmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_NMADD : PSForm_xr<31, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_nmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_NEG : PSForm_y2r<40, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_neg", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_MR : PSForm_y2r<72, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_mr", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_NABS : PSForm_y2r<136, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_nabs", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_ABS : PSForm_y2r<264, (outs f8rc:$FRT), (ins f8rc:$FRB), + "ps_abs", "$FRT, $FRB", IIC_FPGeneral>; +defm PS_SUM0 : PSForm_xr<10, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_sum0", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_SUM1 : PSForm_xr<11, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_sum1", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_MULS0 : PSForm_x3r<12, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC), + "ps_muls0", "$FRT, $FRA, $FRC", IIC_FPGeneral>; +defm PS_MULS1 : PSForm_x3r<13, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC), + "ps_muls1", "$FRT, $FRA, $FRC", IIC_FPGeneral>; +defm PS_MADDS0 : PSForm_xr<14, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_madds0", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +defm PS_MADDS1 : PSForm_xr<15, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), + "ps_madds1", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral>; +def PS_CMPU0 : PSForm_c<0, + (outs crrc:$crD), (ins f8rc:$FRA, f8rc:$FRB), + "ps_cmpu0 $crD, $FRA, $FRB", IIC_FPGeneral>; +def PS_CMPO0 : PSForm_c<32, + (outs crrc:$crD), (ins f8rc:$FRA, f8rc:$FRB), + "ps_cmpo0 $crD, $FRA, $FRB", IIC_FPGeneral>; +def PS_CMPU1 : PSForm_c<64, + (outs crrc:$crD), (ins f8rc:$FRA, f8rc:$FRB), + "ps_cmpu1 $crD, $FRA, $FRB", IIC_FPGeneral>; +def PS_CMPO1 : PSForm_c<96, + (outs crrc:$crD), (ins f8rc:$FRA, f8rc:$FRB), + "ps_cmpo1 $crD, $FRA, $FRB", IIC_FPGeneral>; +defm PS_MERGE00 : PSForm_yr<528, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_merge00", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_MERGE01 : PSForm_yr<560, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_merge01", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_MERGE10 : PSForm_yr<592, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_merge10", "$FRT, $FRA, $FRB", IIC_FPGeneral>; +defm PS_MERGE11 : PSForm_yr<624, + (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), + "ps_merge11", "$FRT, $FRA, $FRB", IIC_FPGeneral>; + +def PSC_DCBZL : DCBZL_Form<1014, + (outs), (ins gprc:$rA, gprc:$rB), + "dcbz_l $rA, $rB", IIC_FPGeneral>; + +} +} +#endif // INCLUDED_CAPSTONE_PS_INSTR +#endif // CAPSTONE_PS_INSTR + +#ifndef INCLUDED_CAPSTONE_PS_FEATURE +#ifdef CAPSTONE_PS_FEATURE +#define INCLUDED_CAPSTONE_PS_FEATURE + +def FeaturePS : SubtargetFeature<"ps","HasPS","false", + "Enable paired-singles instructions", + [FeatureFPU]>; + +def HasPS : Predicate<"PPCSubTarget->hasPS()">, + AssemblerPredicate<(all_of FeaturePS), "ps">; + +#endif // INCLUDED_CAPSTONE_PS_FEATURE +#endif // CAPSTONE_PS_FEATURE + +#ifndef INCLUDED_CAPSTONE_PS_PROCESSOR +#ifdef CAPSTONE_PS_PROCESSOR +#define INCLUDED_CAPSTONE_PS_PROCESSOR + +def : Processor<"750cl", G4Itineraries, [Directive750, + FeatureFRES, FeatureFRSQRTE, + FeatureMFTB, FeaturePS]>; + +#endif // INCLUDED_CAPSTONE_PS_PROCESSOR +#endif // CAPSTONE_PS_PROCESSOR diff --git a/llvm/lib/Target/PowerPC/PPCInstrSPE.td b/llvm/lib/Target/PowerPC/PPCInstrSPE.td index 5adfbad6ca11..5327ca693c50 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrSPE.td +++ b/llvm/lib/Target/PowerPC/PPCInstrSPE.td @@ -452,6 +452,7 @@ def EVFSTSTLT : EVXForm_3<669, (outs crrc:$crD), (ins sperc:$RA, sperc:$RB "evfststlt $crD, $RA, $RB", IIC_VecGeneral, []>; } +let mayLoad = 1 in { def EVLDD : EVXForm_D<769, (outs sperc:$RT), (ins (spe8dis $D, $RA):$dst), "evldd $RT, $dst", IIC_LdStLoad, [(set f64:$RT, (load iaddr:$dst))]>; @@ -500,6 +501,7 @@ def EVLWWSPLAT : EVXForm_D<793, (outs sperc:$RT), (ins (spe4dis $D, $RA):$ds "evlwwsplat $RT, $dst", IIC_LdStLoad, []>; def EVLWWSPLATX : EVXForm_1<792, (outs sperc:$RT), (ins (memrr $RA, $RB):$src), "evlwwsplatx $RT, $src", IIC_LdStLoad, []>; +} // mayLoad = 1 def EVMERGEHI : EVXForm_1<556, (outs sperc:$RT), (ins sperc:$RA, sperc:$RB), "evmergehi $RT, $RA, $RB", IIC_VecGeneral, []>; @@ -743,6 +745,7 @@ def EVSRWU : EVXForm_1<544, (outs sperc:$RT), (ins sperc:$RA, sperc:$RB) "evsrwu $RT, $RA, $RB", IIC_VecGeneral, []>; +let mayStore = 1 in { def EVSTDD : EVXForm_D<801, (outs), (ins sperc:$RT, (spe8dis $D, $RA):$dst), "evstdd $RT, $dst", IIC_LdStStore, [(store f64:$RT, iaddr:$dst)]>; @@ -775,6 +778,7 @@ def EVSTWWO : EVXForm_D<829, (outs), (ins sperc:$RT, (spe4dis $D, $RA):$d "evstwwo $RT, $dst", IIC_LdStStore, []>; def EVSTWWOX : EVXForm_1<828, (outs), (ins sperc:$RT, (memrr $RA, $RB):$dst), "evstwwox $RT, $dst", IIC_LdStStore, []>; +} // mayStore = 1 def EVSUBFSSIAAW : EVXForm_2<1219, (outs sperc:$RT), (ins sperc:$RA), "evsubfssiaaw $RT, $RA", IIC_VecComplex, []>; @@ -794,6 +798,7 @@ def EVXOR : EVXForm_1<534, (outs sperc:$RT), (ins sperc:$RA, sperc:$RB) []>; let isAsmParserOnly = 1 in { +let mayLoad = 1 in { // Identical to the integer Load/Stores, but to handle floats def SPELWZ : DForm_1<32, (outs spe4rc:$RST), (ins (memri $D, $RA):$addr), "lwz $RST, $addr", IIC_LdStLoad, @@ -801,12 +806,16 @@ def SPELWZ : DForm_1<32, (outs spe4rc:$RST), (ins (memri $D, $RA):$addr), def SPELWZX : XForm_1<31, 23, (outs spe4rc:$RST), (ins (memrr $RA, $RB):$addr), "lwzx $RST, $addr", IIC_LdStLoad, [(set f32:$RST, (load xaddr:$addr))]>; +} // mayLoad = 1 + +let mayStore = 1 in { def SPESTW : DForm_1<36, (outs), (ins spe4rc:$RST, (memri $D, $RA):$addr), "stw $RST, $addr", IIC_LdStStore, [(store f32:$RST, iaddr:$addr)]>; def SPESTWX : XForm_8<31, 151, (outs), (ins spe4rc:$RST, (memrr $RA, $RB):$addr), "stwx $RST, $addr", IIC_LdStStore, [(store f32:$RST, xaddr:$addr)]>; +} // mayStore = 1 } } // HasSPE diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td index 8a37e40414ee..d2766c4a7ab1 100644 --- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td +++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td @@ -803,6 +803,7 @@ def absdirectbrtarget : Operand { let EncoderMethod = "getAbsDirectBrEncoding"; let DecoderMethod = "decodeDirectBrTarget"; let ParserMatchClass = PPCDirectBrAsmOperand; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCCondBrAsmOperand : AsmOperandClass { let Name = "CondBr"; let PredicateMethod = "isCondBr"; @@ -820,6 +821,7 @@ def abscondbrtarget : Operand { let EncoderMethod = "getAbsCondBrEncoding"; let DecoderMethod = "decodeCondBrTarget"; let ParserMatchClass = PPCCondBrAsmOperand; + let OperandType = "OPERAND_IMMEDIATE"; } def calltarget : Operand { let PrintMethod = "printBranchOperand"; @@ -833,6 +835,7 @@ def abscalltarget : Operand { let EncoderMethod = "getAbsDirectBrEncoding"; let DecoderMethod = "decodeDirectBrTarget"; let ParserMatchClass = PPCDirectBrAsmOperand; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCCRBitMaskOperand : AsmOperandClass { let Name = "CRBitMask"; let PredicateMethod = "isCRBitMask"; @@ -861,11 +864,13 @@ def dispRI34 : Operand { let ParserMatchClass = PPCDispRI34Operand; let EncoderMethod = "getDispRI34Encoding"; let DecoderMethod = "decodeSImmOperand<34>"; + let OperandType = "OPERAND_IMMEDIATE"; } def dispRI34_pcrel : Operand { let ParserMatchClass = PPCDispRI34Operand; let EncoderMethod = "getDispRI34PCRelEncoding"; let DecoderMethod = "decodeSImmOperand<34>"; + let OperandType = "OPERAND_IMMEDIATE"; } def memri34 : Operand { // memri, imm is a 34-bit value. let PrintMethod = "printMemRegImm34"; @@ -893,6 +898,7 @@ def PPCDispRIOperand : AsmOperandClass { def dispRI : Operand { let ParserMatchClass = PPCDispRIOperand; let EncoderMethod = "getDispRIEncoding"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispRIXOperand : AsmOperandClass { let Name = "DispRIX"; let PredicateMethod = "isS16ImmX4"; @@ -902,6 +908,7 @@ def dispRIX : Operand { let ParserMatchClass = PPCDispRIXOperand; let EncoderMethod = "getDispRIXEncoding"; let DecoderMethod = "decodeDispRIXOperand"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispRIHashOperand : AsmOperandClass { let Name = "DispRIHash"; let PredicateMethod = "isHashImmX8"; @@ -911,6 +918,7 @@ def dispRIHash : Operand { let ParserMatchClass = PPCDispRIHashOperand; let EncoderMethod = "getDispRIHashEncoding"; let DecoderMethod = "decodeDispRIHashOperand"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispRIX16Operand : AsmOperandClass { let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16"; @@ -921,6 +929,7 @@ def dispRIX16 : Operand { let EncoderMethod = "getDispRIX16Encoding"; let DecoderMethod = "decodeDispRIX16Operand"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispSPE8Operand : AsmOperandClass { let Name = "DispSPE8"; let PredicateMethod = "isU8ImmX8"; @@ -930,6 +939,7 @@ def dispSPE8 : Operand { let ParserMatchClass = PPCDispSPE8Operand; let DecoderMethod = "decodeDispSPE8Operand"; let EncoderMethod = "getDispSPE8Encoding"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispSPE4Operand : AsmOperandClass { let Name = "DispSPE4"; let PredicateMethod = "isU7ImmX4"; @@ -939,6 +949,7 @@ def dispSPE4 : Operand { let ParserMatchClass = PPCDispSPE4Operand; let DecoderMethod = "decodeDispSPE4Operand"; let EncoderMethod = "getDispSPE4Encoding"; + let OperandType = "OPERAND_IMMEDIATE"; } def PPCDispSPE2Operand : AsmOperandClass { let Name = "DispSPE2"; let PredicateMethod = "isU6ImmX2"; @@ -948,6 +959,7 @@ def dispSPE2 : Operand { let ParserMatchClass = PPCDispSPE2Operand; let DecoderMethod = "decodeDispSPE2Operand"; let EncoderMethod = "getDispSPE2Encoding"; + let OperandType = "OPERAND_IMMEDIATE"; } def memri : Operand { @@ -1123,3 +1135,6 @@ def PPCRegDMRpRCAsmOperand : AsmOperandClass { def dmrp : RegisterOperand { let ParserMatchClass = PPCRegDMRpRCAsmOperand; } + +#define CAPSTONE_DEPR_REGS +include "PPCDeprecated.td" diff --git a/llvm/lib/Target/PowerPC/PPCScheduleP10.td b/llvm/lib/Target/PowerPC/PPCScheduleP10.td index f922f8a7d985..5c8563ea5671 100644 --- a/llvm/lib/Target/PowerPC/PPCScheduleP10.td +++ b/llvm/lib/Target/PowerPC/PPCScheduleP10.td @@ -30,7 +30,7 @@ def P10Model : SchedMachineModel { let CompleteModel = 1; // Power 10 does not support instructions from SPE, Book E and HTM. - let UnsupportedFeatures = [HasSPE, IsE500, IsBookE, IsISAFuture, HasHTM]; + let UnsupportedFeatures = [HasSPE, IsE500, IsBookE, IsISAFuture, HasHTM, HasQPX, HasPS]; } let SchedModel = P10Model in { diff --git a/llvm/lib/Target/PowerPC/PPCScheduleP9.td b/llvm/lib/Target/PowerPC/PPCScheduleP9.td index 36befceef4ac..ac38bed1b044 100644 --- a/llvm/lib/Target/PowerPC/PPCScheduleP9.td +++ b/llvm/lib/Target/PowerPC/PPCScheduleP9.td @@ -43,7 +43,8 @@ def P9Model : SchedMachineModel { // instructions introduced after ISA 3.0. let UnsupportedFeatures = [HasSPE, PrefixInstrs, MMA, PairedVectorMemops, IsBookE, - PCRelativeMemops, IsISA3_1, IsISAFuture]; + PCRelativeMemops, IsISA3_1, IsISAFuture, + HasQPX, HasPS]; } let SchedModel = P9Model in { diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 73724e662f9e..8c9cbdce9f9e 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -95,31 +95,8 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenInstAlias.h" -#include "CodeGenInstruction.h" -#include "CodeGenRegisters.h" -#include "CodeGenTarget.h" -#include "SubtargetFeatureInfo.h" -#include "Types.h" -#include "llvm/ADT/CachedHashString.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/StringMatcher.h" -#include "llvm/TableGen/StringToOffsetTable.h" -#include "llvm/TableGen/TableGenBackend.h" -#include -#include -#include -#include -#include +#include "AsmMatcherEmitterTypes.h" +#include "Printer.h" using namespace llvm; @@ -132,124 +109,32 @@ static cl::opt cl::desc("Only match instructions with the given prefix"), cl::cat(AsmMatcherEmitterCat)); -namespace { -class AsmMatcherInfo; - -// Register sets are used as keys in some second-order sets TableGen creates -// when generating its data structures. This means that the order of two -// RegisterSets can be seen in the outputted AsmMatcher tables occasionally, and -// can even affect compiler output (at least seen in diagnostics produced when -// all matches fail). So we use a type that sorts them consistently. -typedef std::set RegisterSet; - -class AsmMatcherEmitter { - RecordKeeper &Records; -public: - AsmMatcherEmitter(RecordKeeper &R) : Records(R) {} - - void run(raw_ostream &o); -}; - -/// ClassInfo - Helper class for storing the information about a particular -/// class of operands which can be matched. -struct ClassInfo { - enum ClassInfoKind { - /// Invalid kind, for use as a sentinel value. - Invalid = 0, - - /// The class for a particular token. - Token, - - /// The (first) register class, subsequent register classes are - /// RegisterClass0+1, and so on. - RegisterClass0, - - /// The (first) user defined class, subsequent user defined classes are - /// UserClass0+1, and so on. - UserClass0 = 1<<16 - }; - - /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + - /// N) for the Nth user defined class. - unsigned Kind; - - /// SuperClasses - The super classes of this class. Note that for simplicities - /// sake user operands only record their immediate super class, while register - /// operands include all superclasses. - std::vector SuperClasses; - - /// Name - The full class name, suitable for use in an enum. - std::string Name; - - /// ClassName - The unadorned generic name for this class (e.g., Token). - std::string ClassName; - - /// ValueName - The name of the value this class represents; for a token this - /// is the literal token string, for an operand it is the TableGen class (or - /// empty if this is a derived class). - std::string ValueName; - - /// PredicateMethod - The name of the operand method to test whether the - /// operand matches this class; this is not valid for Token or register kinds. - std::string PredicateMethod; - - /// RenderMethod - The name of the operand method to add this operand to an - /// MCInst; this is not valid for Token or register kinds. - std::string RenderMethod; - - /// ParserMethod - The name of the operand method to do a target specific - /// parsing on the operand. - std::string ParserMethod; - - /// For register classes: the records for all the registers in this class. - RegisterSet Registers; - - /// For custom match classes: the diagnostic kind for when the predicate fails. - std::string DiagnosticType; - - /// For custom match classes: the diagnostic string for when the predicate fails. - std::string DiagnosticString; - - /// Is this operand optional and not always required. - bool IsOptional; - - /// DefaultMethod - The name of the method that returns the default operand - /// for optional operand - std::string DefaultMethod; - -public: - /// isRegisterClass() - Check if this is a register class. - bool isRegisterClass() const { - return Kind >= RegisterClass0 && Kind < UserClass0; - } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - /// isUserClass() - Check if this is a user defined class. - bool isUserClass() const { - return Kind >= UserClass0; - } +// +// ClassInfo implementation +// - /// isRelatedTo - Check whether this class is "related" to \p RHS. Classes - /// are related if they are in the same class hierarchy. - bool isRelatedTo(const ClassInfo &RHS) const { +bool ClassInfo::isRelatedTo(const ClassInfo &RHS) const { // Tokens are only related to tokens. if (Kind == Token || RHS.Kind == Token) - return Kind == Token && RHS.Kind == Token; - + return Kind == Token && RHS.Kind == Token; + // Registers classes are only related to registers classes, and only if // their intersection is non-empty. if (isRegisterClass() || RHS.isRegisterClass()) { - if (!isRegisterClass() || !RHS.isRegisterClass()) - return false; - - RegisterSet Tmp; - std::insert_iterator II(Tmp, Tmp.begin()); - std::set_intersection(Registers.begin(), Registers.end(), - RHS.Registers.begin(), RHS.Registers.end(), - II, LessRecordByID()); - - return !Tmp.empty(); - } - + if (!isRegisterClass() || !RHS.isRegisterClass()) + return false; + + RegisterSet Tmp; + std::insert_iterator II(Tmp, Tmp.begin()); + std::set_intersection(Registers.begin(), Registers.end(), + RHS.Registers.begin(), RHS.Registers.end(), II, + LessRecordByID()); + + return !Tmp.empty(); + } + // Otherwise we have two users operands; they are related if they are in the // same class hierarchy. // @@ -258,102 +143,98 @@ struct ClassInfo { assert(isUserClass() && RHS.isUserClass() && "Unexpected class!"); const ClassInfo *Root = this; while (!Root->SuperClasses.empty()) - Root = Root->SuperClasses.front(); - + Root = Root->SuperClasses.front(); + const ClassInfo *RHSRoot = &RHS; while (!RHSRoot->SuperClasses.empty()) - RHSRoot = RHSRoot->SuperClasses.front(); - + RHSRoot = RHSRoot->SuperClasses.front(); + return Root == RHSRoot; - } +} - /// isSubsetOf - Test whether this class is a subset of \p RHS. - bool isSubsetOf(const ClassInfo &RHS) const { +bool ClassInfo::isSubsetOf(const ClassInfo &RHS) const { // This is a subset of RHS if it is the same class... if (this == &RHS) - return true; - + return true; + // ... or if any of its super classes are a subset of RHS. SmallVector Worklist(SuperClasses.begin(), SuperClasses.end()); SmallPtrSet Visited; while (!Worklist.empty()) { - auto *CI = Worklist.pop_back_val(); - if (CI == &RHS) - return true; - for (auto *Super : CI->SuperClasses) - if (Visited.insert(Super).second) - Worklist.push_back(Super); - } - + auto *CI = Worklist.pop_back_val(); + if (CI == &RHS) + return true; + for (auto *Super : CI->SuperClasses) + if (Visited.insert(Super).second) + Worklist.push_back(Super); + } + return false; - } +} - int getTreeDepth() const { +int ClassInfo::getTreeDepth() const { int Depth = 0; const ClassInfo *Root = this; while (!Root->SuperClasses.empty()) { - Depth++; - Root = Root->SuperClasses.front(); + Depth++; + Root = Root->SuperClasses.front(); } return Depth; - } +} - const ClassInfo *findRoot() const { +const ClassInfo *ClassInfo::findRoot() const { const ClassInfo *Root = this; while (!Root->SuperClasses.empty()) - Root = Root->SuperClasses.front(); + Root = Root->SuperClasses.front(); return Root; - } +} - /// Compare two classes. This does not produce a total ordering, but does - /// guarantee that subclasses are sorted before their parents, and that the - /// ordering is transitive. - bool operator<(const ClassInfo &RHS) const { +bool ClassInfo::operator<(const ClassInfo &RHS) const { if (this == &RHS) - return false; + return false; // First, enforce the ordering between the three different types of class. // Tokens sort before registers, which sort before user classes. if (Kind == Token) { - if (RHS.Kind != Token) - return true; - assert(RHS.Kind == Token); + if (RHS.Kind != Token) + return true; + assert(RHS.Kind == Token); } else if (isRegisterClass()) { - if (RHS.Kind == Token) - return false; - else if (RHS.isUserClass()) - return true; - assert(RHS.isRegisterClass()); + if (RHS.Kind == Token) + return false; + else if (RHS.isUserClass()) + return true; + assert(RHS.isRegisterClass()); } else if (isUserClass()) { - if (!RHS.isUserClass()) - return false; - assert(RHS.isUserClass()); + if (!RHS.isUserClass()) + return false; + assert(RHS.isUserClass()); } else { - llvm_unreachable("Unknown ClassInfoKind"); + llvm_unreachable("Unknown ClassInfoKind"); } if (Kind == Token || isUserClass()) { - // Related tokens and user classes get sorted by depth in the inheritence - // tree (so that subclasses are before their parents). - if (isRelatedTo(RHS)) { - if (getTreeDepth() > RHS.getTreeDepth()) - return true; - if (getTreeDepth() < RHS.getTreeDepth()) - return false; + // Related tokens and user classes get sorted by depth in the inheritence + // tree (so that subclasses are before their parents). + if (isRelatedTo(RHS)) { + if (getTreeDepth() > RHS.getTreeDepth()) + return true; + if (getTreeDepth() < RHS.getTreeDepth()) + return false; } else { - // Unrelated tokens and user classes are ordered by the name of their - // root nodes, so that there is a consistent ordering between - // unconnected trees. - return findRoot()->ValueName < RHS.findRoot()->ValueName; + // Unrelated tokens and user classes are ordered by the name of their + // root nodes, so that there is a consistent ordering between + // unconnected trees. + return findRoot()->ValueName < RHS.findRoot()->ValueName; } } else if (isRegisterClass()) { - // For register sets, sort by number of registers. This guarantees that - // a set will always sort before all of it's strict supersets. - if (Registers.size() != RHS.Registers.size()) - return Registers.size() < RHS.Registers.size(); + // For register sets, sort by number of registers. This guarantees that + // a set will always sort before all of it's strict supersets. + if (Registers.size() != RHS.Registers.size()) + return Registers.size() < RHS.Registers.size(); } else { - llvm_unreachable("Unknown ClassInfoKind"); + llvm_unreachable("Unknown ClassInfoKind"); } // FIXME: We should be able to just return false here, as we only need a @@ -362,272 +243,47 @@ struct ClassInfo { // accidentally rely on this behaviour, so it will have to stay like this // until they are fixed. return ValueName < RHS.ValueName; - } -}; - -class AsmVariantInfo { -public: - StringRef RegisterPrefix; - StringRef TokenizingCharacters; - StringRef SeparatorCharacters; - StringRef BreakCharacters; - StringRef Name; - int AsmVariantNo; -}; - -/// MatchableInfo - Helper class for storing the necessary information for an -/// instruction or alias which is capable of being matched. -struct MatchableInfo { - struct AsmOperand { - /// Token - This is the token that the operand came from. - StringRef Token; - - /// The unique class instance this operand should match. - ClassInfo *Class; - - /// The operand name this is, if anything. - StringRef SrcOpName; - - /// The operand name this is, before renaming for tied operands. - StringRef OrigSrcOpName; - - /// The suboperand index within SrcOpName, or -1 for the entire operand. - int SubOpIdx; - - /// Whether the token is "isolated", i.e., it is preceded and followed - /// by separators. - bool IsIsolatedToken; - - /// Register record if this token is singleton register. - Record *SingletonReg; - - explicit AsmOperand(bool IsIsolatedToken, StringRef T) - : Token(T), Class(nullptr), SubOpIdx(-1), - IsIsolatedToken(IsIsolatedToken), SingletonReg(nullptr) {} - }; - - /// ResOperand - This represents a single operand in the result instruction - /// generated by the match. In cases (like addressing modes) where a single - /// assembler operand expands to multiple MCOperands, this represents the - /// single assembler operand, not the MCOperand. - struct ResOperand { - enum { - /// RenderAsmOperand - This represents an operand result that is - /// generated by calling the render method on the assembly operand. The - /// corresponding AsmOperand is specified by AsmOperandNum. - RenderAsmOperand, - - /// TiedOperand - This represents a result operand that is a duplicate of - /// a previous result operand. - TiedOperand, - - /// ImmOperand - This represents an immediate value that is dumped into - /// the operand. - ImmOperand, - - /// RegOperand - This represents a fixed register that is dumped in. - RegOperand - } Kind; - - /// Tuple containing the index of the (earlier) result operand that should - /// be copied from, as well as the indices of the corresponding (parsed) - /// operands in the asm string. - struct TiedOperandsTuple { - unsigned ResOpnd; - unsigned SrcOpnd1Idx; - unsigned SrcOpnd2Idx; - }; - - union { - /// This is the operand # in the AsmOperands list that this should be - /// copied from. - unsigned AsmOperandNum; - - /// Description of tied operands. - TiedOperandsTuple TiedOperands; - - /// ImmVal - This is the immediate value added to the instruction. - int64_t ImmVal; - - /// Register - This is the register record. - Record *Register; - }; - - /// MINumOperands - The number of MCInst operands populated by this - /// operand. - unsigned MINumOperands; - - static ResOperand getRenderedOp(unsigned AsmOpNum, unsigned NumOperands) { - ResOperand X; - X.Kind = RenderAsmOperand; - X.AsmOperandNum = AsmOpNum; - X.MINumOperands = NumOperands; - return X; - } - - static ResOperand getTiedOp(unsigned TiedOperandNum, unsigned SrcOperand1, - unsigned SrcOperand2) { - ResOperand X; - X.Kind = TiedOperand; - X.TiedOperands = { TiedOperandNum, SrcOperand1, SrcOperand2 }; - X.MINumOperands = 1; - return X; - } - - static ResOperand getImmOp(int64_t Val) { - ResOperand X; - X.Kind = ImmOperand; - X.ImmVal = Val; - X.MINumOperands = 1; - return X; - } - - static ResOperand getRegOp(Record *Reg) { - ResOperand X; - X.Kind = RegOperand; - X.Register = Reg; - X.MINumOperands = 1; - return X; - } - }; - - /// AsmVariantID - Target's assembly syntax variant no. - int AsmVariantID; - - /// AsmString - The assembly string for this instruction (with variants - /// removed), e.g. "movsx $src, $dst". - std::string AsmString; - - /// TheDef - This is the definition of the instruction or InstAlias that this - /// matchable came from. - Record *const TheDef; - - /// DefRec - This is the definition that it came from. - PointerUnion DefRec; - - const CodeGenInstruction *getResultInst() const { - if (isa(DefRec)) - return cast(DefRec); - return cast(DefRec)->ResultInst; - } - - /// ResOperands - This is the operand list that should be built for the result - /// MCInst. - SmallVector ResOperands; - - /// Mnemonic - This is the first token of the matched instruction, its - /// mnemonic. - StringRef Mnemonic; - - /// AsmOperands - The textual operands that this instruction matches, - /// annotated with a class and where in the OperandList they were defined. - /// This directly corresponds to the tokenized AsmString after the mnemonic is - /// removed. - SmallVector AsmOperands; - - /// Predicates - The required subtarget features to match this instruction. - SmallVector RequiredFeatures; - - /// ConversionFnKind - The enum value which is passed to the generated - /// convertToMCInst to convert parsed operands into an MCInst for this - /// function. - std::string ConversionFnKind; - - /// If this instruction is deprecated in some form. - bool HasDeprecation = false; - - /// If this is an alias, this is use to determine whether or not to using - /// the conversion function defined by the instruction's AsmMatchConverter - /// or to use the function generated by the alias. - bool UseInstAsmMatchConverter; - - MatchableInfo(const CodeGenInstruction &CGI) - : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef), DefRec(&CGI), - UseInstAsmMatchConverter(true) { - } - - MatchableInfo(std::unique_ptr Alias) - : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef), - DefRec(Alias.release()), - UseInstAsmMatchConverter( - TheDef->getValueAsBit("UseInstAsmMatchConverter")) { - } - - // Could remove this and the dtor if PointerUnion supported unique_ptr - // elements with a dynamic failure/assertion (like the one below) in the case - // where it was copied while being in an owning state. - MatchableInfo(const MatchableInfo &RHS) - : AsmVariantID(RHS.AsmVariantID), AsmString(RHS.AsmString), - TheDef(RHS.TheDef), DefRec(RHS.DefRec), ResOperands(RHS.ResOperands), - Mnemonic(RHS.Mnemonic), AsmOperands(RHS.AsmOperands), - RequiredFeatures(RHS.RequiredFeatures), - ConversionFnKind(RHS.ConversionFnKind), - HasDeprecation(RHS.HasDeprecation), - UseInstAsmMatchConverter(RHS.UseInstAsmMatchConverter) { - assert(!isa(DefRec)); - } - - ~MatchableInfo() { - delete dyn_cast_if_present(DefRec); - } - - // Two-operand aliases clone from the main matchable, but mark the second - // operand as a tied operand of the first for purposes of the assembler. - void formTwoOperandAlias(StringRef Constraint); - - void initialize(const AsmMatcherInfo &Info, - SmallPtrSetImpl &SingletonRegisters, - AsmVariantInfo const &Variant, - bool HasMnemonicFirst); - - /// validate - Return true if this matchable is a valid thing to match against - /// and perform a bunch of validity checking. - bool validate(StringRef CommentDelimiter, bool IsAlias) const; +} - /// findAsmOperand - Find the AsmOperand with the specified name and - /// suboperand index. - int findAsmOperand(StringRef N, int SubOpIdx) const { +// +// MatchableInfo implementation +// +int MatchableInfo::findAsmOperand(StringRef N, int SubOpIdx) const { auto I = find_if(AsmOperands, [&](const AsmOperand &Op) { - return Op.SrcOpName == N && Op.SubOpIdx == SubOpIdx; + return Op.SrcOpName == N && Op.SubOpIdx == SubOpIdx; }); return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1; - } +} - /// findAsmOperandNamed - Find the first AsmOperand with the specified name. - /// This does not check the suboperand index. - int findAsmOperandNamed(StringRef N, int LastIdx = -1) const { +int MatchableInfo::findAsmOperandNamed(StringRef N, int LastIdx) const { auto I = llvm::find_if(llvm::drop_begin(AsmOperands, LastIdx + 1), [&](const AsmOperand &Op) { return Op.SrcOpName == N; }); return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1; - } +} - int findAsmOperandOriginallyNamed(StringRef N) const { - auto I = - find_if(AsmOperands, - [&](const AsmOperand &Op) { return Op.OrigSrcOpName == N; }); +int MatchableInfo::findAsmOperandOriginallyNamed(StringRef N) const { + auto I = find_if(AsmOperands, [&](const AsmOperand &Op) { + return Op.OrigSrcOpName == N; + }); return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1; - } - - void buildInstructionResultOperands(); - void buildAliasResultOperands(bool AliasConstraintsAreChecked); +} - /// operator< - Compare two matchables. - bool operator<(const MatchableInfo &RHS) const { +bool MatchableInfo::operator<(const MatchableInfo &RHS) const { // The primary comparator is the instruction mnemonic. if (int Cmp = Mnemonic.compare_insensitive(RHS.Mnemonic)) - return Cmp == -1; - + return Cmp == -1; + if (AsmOperands.size() != RHS.AsmOperands.size()) - return AsmOperands.size() < RHS.AsmOperands.size(); - + return AsmOperands.size() < RHS.AsmOperands.size(); + // Compare lexicographically by operand. The matcher validates that other // orderings wouldn't be ambiguous using \see couldMatchAmbiguouslyWith(). for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { - if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) - return true; - if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) - return false; + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) + return true; + if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) + return false; } // For X86 AVX/AVX512 instructions, we prefer vex encoding because the @@ -651,166 +307,74 @@ struct MatchableInfo { return RequiredFeatures.size() > RHS.RequiredFeatures.size(); return false; - } +} - /// couldMatchAmbiguouslyWith - Check whether this matchable could - /// ambiguously match the same set of operands as \p RHS (without being a - /// strictly superior match). - bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) const { +bool MatchableInfo::couldMatchAmbiguouslyWith(const MatchableInfo &RHS) const { // The primary comparator is the instruction mnemonic. if (Mnemonic != RHS.Mnemonic) - return false; - + return false; + // Different variants can't conflict. if (AsmVariantID != RHS.AsmVariantID) - return false; - + return false; + // The number of operands is unambiguous. if (AsmOperands.size() != RHS.AsmOperands.size()) - return false; - + return false; + // Otherwise, make sure the ordering of the two instructions is unambiguous // by checking that either (a) a token or operand kind discriminates them, // or (b) the ordering among equivalent kinds is consistent. - + // Tokens and operand kinds are unambiguous (assuming a correct target // specific parser). for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) - if (AsmOperands[i].Class->Kind != RHS.AsmOperands[i].Class->Kind || - AsmOperands[i].Class->Kind == ClassInfo::Token) - if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class || - *RHS.AsmOperands[i].Class < *AsmOperands[i].Class) - return false; - + if (AsmOperands[i].Class->Kind != RHS.AsmOperands[i].Class->Kind || + AsmOperands[i].Class->Kind == ClassInfo::Token) + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class || + *RHS.AsmOperands[i].Class < *AsmOperands[i].Class) + return false; + // Otherwise, this operand could commute if all operands are equivalent, or // there is a pair of operands that compare less than and a pair that // compare greater than. bool HasLT = false, HasGT = false; for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { - if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) - HasLT = true; - if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) - HasGT = true; + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) + HasLT = true; + if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) + HasGT = true; } - + return HasLT == HasGT; - } - - void dump() const; - -private: - void tokenizeAsmString(AsmMatcherInfo const &Info, - AsmVariantInfo const &Variant); - void addAsmOperand(StringRef Token, bool IsIsolatedToken = false); -}; - -struct OperandMatchEntry { - unsigned OperandMask; - const MatchableInfo* MI; - ClassInfo *CI; +} - static OperandMatchEntry create(const MatchableInfo *mi, ClassInfo *ci, - unsigned opMask) { +// +// OperandMatchEntry implementation +// +OperandMatchEntry OperandMatchEntry::create(const MatchableInfo *mi, ClassInfo *ci, + unsigned opMask) { OperandMatchEntry X; X.OperandMask = opMask; X.CI = ci; X.MI = mi; return X; - } -}; - -class AsmMatcherInfo { -public: - /// Tracked Records - RecordKeeper &Records; - - /// The tablegen AsmParser record. - Record *AsmParser; - - /// Target - The target information. - CodeGenTarget &Target; - - /// The classes which are needed for matching. - std::forward_list Classes; - - /// The information on the matchables to match. - std::vector> Matchables; - - /// Info for custom matching operands by user defined methods. - std::vector OperandMatchInfo; - - /// Map of Register records to their class information. - typedef std::map RegisterClassesTy; - RegisterClassesTy RegisterClasses; - - /// Map of Predicate records to their subtarget information. - std::map SubtargetFeatures; - - /// Map of AsmOperandClass records to their class information. - std::map AsmOperandClasses; - - /// Map of RegisterClass records to their class information. - std::map RegisterClassClasses; - -private: - /// Map of token to class information which has already been constructed. - std::map TokenClasses; - -private: - /// getTokenClass - Lookup or create the class for the given token. - ClassInfo *getTokenClass(StringRef Token); - - /// getOperandClass - Lookup or create the class for the given operand. - ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI, - int SubOpIdx); - ClassInfo *getOperandClass(Record *Rec, int SubOpIdx); - - /// buildRegisterClasses - Build the ClassInfo* instances for register - /// classes. - void buildRegisterClasses(SmallPtrSetImpl &SingletonRegisters); - - /// buildOperandClasses - Build the ClassInfo* instances for user defined - /// operand classes. - void buildOperandClasses(); - - void buildInstructionOperandReference(MatchableInfo *II, StringRef OpName, - unsigned AsmOpIdx); - void buildAliasOperandReference(MatchableInfo *II, StringRef OpName, - MatchableInfo::AsmOperand &Op); - -public: - AsmMatcherInfo(Record *AsmParser, - CodeGenTarget &Target, - RecordKeeper &Records); - - /// Construct the various tables used during matching. - void buildInfo(); - - /// buildOperandMatchInfo - Build the necessary information to handle user - /// defined operand parsing methods. - void buildOperandMatchInfo(); +} - /// getSubtargetFeature - Lookup or create the subtarget feature info for the - /// given operand. - const SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const { +// +// AsmMatcherInfo implementations +// +const SubtargetFeatureInfo *AsmMatcherInfo::getSubtargetFeature(Record *Def) const { assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!"); const auto &I = SubtargetFeatures.find(Def); return I == SubtargetFeatures.end() ? nullptr : &I->second; - } - - RecordKeeper &getRecords() const { - return Records; - } - - bool hasOptionalOperands() const { - return any_of(Classes, - [](const ClassInfo &Class) { return Class.IsOptional; }); - } -}; +} -} // end anonymous namespace +bool AsmMatcherInfo::hasOptionalOperands() const { +return any_of(Classes, + [](const ClassInfo &Class) { return Class.IsOptional; }); +} -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MatchableInfo::dump() const { errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n"; @@ -1104,7 +668,13 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const { << "ignoring instruction with tied operand '" << Tok << "'\n"; }); - return false; + // Capstone: There are ARM instructions like: + // vst2${p}.32 {$Vd[$lane], $src2[$lane]}, $Rn$Rm + // The $lane operand would prevent this instruction to be added to a + // Matchable. This would mean that these instructions + // get no mappable info. + // So we only care about this. + return true; } } @@ -1949,7 +1519,7 @@ static unsigned emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::vector> &Infos, bool HasMnemonicFirst, bool HasOptionalOperands, - raw_ostream &OS) { + PrinterLLVM &PI) { SmallSetVector OperandConversionKinds; SmallSetVector InstructionConversionKinds; std::vector > ConversionTable; @@ -1958,86 +1528,17 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // TargetOperandClass - This is the target's operand class, like X86Operand. std::string TargetOperandClass = Target.getName().str() + "Operand"; - // Write the convert function to a separate stream, so we can drop it after - // the enum. We'll build up the conversion handlers for the individual - // operand types opportunistically as we encounter them. - std::string ConvertFnBody; - raw_string_ostream CvtOS(ConvertFnBody); // Start the unified conversion function. - if (HasOptionalOperands) { - CvtOS << "void " << Target.getName() << ClassName << "::\n" - << "convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector &Operands,\n" - << " const SmallBitVector &OptionalOperandsMask) {\n"; - } else { - CvtOS << "void " << Target.getName() << ClassName << "::\n" - << "convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector &Operands) {\n"; - } - CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; - CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n"; - if (HasOptionalOperands) { - size_t MaxNumOperands = 0; - for (const auto &MI : Infos) { - MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size()); - } - CvtOS << " unsigned DefaultsOffset[" << (MaxNumOperands + 1) - << "] = { 0 };\n"; - CvtOS << " assert(OptionalOperandsMask.size() == " << (MaxNumOperands) - << ");\n"; - CvtOS << " for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands) - << "; ++i) {\n"; - CvtOS << " DefaultsOffset[i + 1] = NumDefaults;\n"; - CvtOS << " NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n"; - CvtOS << " }\n"; - } - CvtOS << " unsigned OpIdx;\n"; - CvtOS << " Inst.setOpcode(Opcode);\n"; - CvtOS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; - if (HasOptionalOperands) { - CvtOS << " OpIdx = *(p + 1) - DefaultsOffset[*(p + 1)];\n"; - } else { - CvtOS << " OpIdx = *(p + 1);\n"; + size_t MaxNumOperands = 0; + for (const auto &MI : Infos) { + MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size()); } - CvtOS << " switch (*p) {\n"; - CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n"; - CvtOS << " case CVT_Reg:\n"; - CvtOS << " static_cast<" << TargetOperandClass - << " &>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; - CvtOS << " break;\n"; - CvtOS << " case CVT_Tied: {\n"; - CvtOS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; - CvtOS << " std::begin(TiedAsmOperandTable)) &&\n"; - CvtOS << " \"Tied operand not found\");\n"; - CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n"; - CvtOS << " if (TiedResOpnd != (uint8_t)-1)\n"; - CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n"; - CvtOS << " break;\n"; - CvtOS << " }\n"; - - std::string OperandFnBody; - raw_string_ostream OpOS(OperandFnBody); + PI.asmMatcherEmitConversionFunctionI(Target.getName(), ClassName, + TargetOperandClass, HasOptionalOperands, + MaxNumOperands); + // Start the operand number lookup function. - OpOS << "void " << Target.getName() << ClassName << "::\n" - << "convertToMapAndConstraints(unsigned Kind,\n"; - OpOS.indent(27); - OpOS << "const OperandVector &Operands) {\n" - << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" - << " unsigned NumMCOperands = 0;\n" - << " const uint8_t *Converter = ConversionTable[Kind];\n" - << " for (const uint8_t *p = Converter; *p; p += 2) {\n" - << " switch (*p) {\n" - << " default: llvm_unreachable(\"invalid conversion entry!\");\n" - << " case CVT_Reg:\n" - << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" - << " Operands[*(p + 1)]->setConstraint(\"r\");\n" - << " ++NumMCOperands;\n" - << " break;\n" - << " case CVT_Tied:\n" - << " ++NumMCOperands;\n" - << " break;\n"; + PI.asmMatcherEmitOperandFunctionI(Target.getName(), ClassName); // Pre-populate the operand conversion kinds with the standard always // available entries. @@ -2073,10 +1574,9 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, ConversionTable.back().push_back(CVT_Done); // Add the handler to the conversion driver function. - CvtOS << " case CVT_" - << getEnumNameForToken(AsmMatchConverter) << ":\n" - << " " << AsmMatchConverter << "(Inst, Operands);\n" - << " break;\n"; + PI.asmMatcherEmitConversionFunctionII( + getEnumNameForToken(AsmMatchConverter), + AsmMatchConverter); // FIXME: Handle the operand number lookup for custom match functions. continue; @@ -2133,37 +1633,12 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // This is a new operand kind. Add a handler for it to the // converter driver. - CvtOS << " case " << Name << ":\n"; - if (Op.Class->IsOptional) { - // If optional operand is not present in actual instruction then we - // should call its DefaultMethod before RenderMethod - assert(HasOptionalOperands); - CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n" - << " " << Op.Class->DefaultMethod << "()" - << "->" << Op.Class->RenderMethod << "(Inst, " - << OpInfo.MINumOperands << ");\n" - << " } else {\n" - << " static_cast<" << TargetOperandClass - << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n" - << " }\n"; - } else { - CvtOS << " static_cast<" << TargetOperandClass - << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n"; - } - CvtOS << " break;\n"; + PI.asmMatcherEmitConversionFunctionIII( + Name, TargetOperandClass, HasOptionalOperands, + Op, OpInfo); // Add a handler for the operand number lookup. - OpOS << " case " << Name << ":\n" - << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n"; - - if (Op.Class->isRegisterClass()) - OpOS << " Operands[*(p + 1)]->setConstraint(\"r\");\n"; - else - OpOS << " Operands[*(p + 1)]->setConstraint(\"m\");\n"; - OpOS << " NumMCOperands += " << OpInfo.MINumOperands << ";\n" - << " break;\n"; + PI.asmMatcherEmitOperandFunctionII(Name, Op, OpInfo); break; } case MatchableInfo::ResOperand::TiedOperand: { @@ -2207,15 +1682,9 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, if (!IsNewConverter) break; - CvtOS << " case " << Name << ":\n" - << " Inst.addOperand(MCOperand::createImm(" << Val << "));\n" - << " break;\n"; + PI.asmMatcherEmitConversionFunctionIV(Name, Val); + PI.asmMatcherEmitOperandFunctionIII(Name); - OpOS << " case " << Name << ":\n" - << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" - << " Operands[*(p + 1)]->setConstraint(\"\");\n" - << " ++NumMCOperands;\n" - << " break;\n"; break; } case MatchableInfo::ResOperand::RegOperand: { @@ -2238,15 +1707,8 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, if (!IsNewConverter) break; - CvtOS << " case " << Name << ":\n" - << " Inst.addOperand(MCOperand::createReg(" << Reg << "));\n" - << " break;\n"; - - OpOS << " case " << Name << ":\n" - << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" - << " Operands[*(p + 1)]->setConstraint(\"m\");\n" - << " ++NumMCOperands;\n" - << " break;\n"; + PI.asmMatcherEmitConversionFunctionV(Name, Reg); + PI.asmMatcherEmitOperandFunctionIV(Name); } } } @@ -2267,10 +1729,10 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, } // Finish up the converter driver function. - CvtOS << " }\n }\n}\n\n"; + PI.asmMatcherEmitConversionFunctionVI(); // Finish up the operand number lookup function. - OpOS << " }\n }\n}\n\n"; + PI.asmMatcherEmitOperandFunctionV(); // Output a static table for tied operands. if (TiedOperandsEnumMap.size()) { @@ -2281,80 +1743,33 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, "an 8bit offset from the conversion table, where index " "'255' is reserved as operand not to be copied."); - OS << "enum {\n"; - for (auto &KV : TiedOperandsEnumMap) { - OS << " " << KV.second << ",\n"; - } - OS << "};\n\n"; - - OS << "static const uint8_t TiedAsmOperandTable[][3] = {\n"; - for (auto &KV : TiedOperandsEnumMap) { - OS << " /* " << KV.second << " */ { " - << utostr(std::get<0>(KV.first)) << ", " - << utostr(std::get<1>(KV.first)) << ", " - << utostr(std::get<2>(KV.first)) << " },\n"; - } - OS << "};\n\n"; + PI.asmMatcherEmitTiedOperandEnum(TiedOperandsEnumMap); + + PI.asmMatcherEmitTiedOpTable(TiedOperandsEnumMap); } else - OS << "static const uint8_t TiedAsmOperandTable[][3] = " - "{ /* empty */ {0, 0, 0} };\n\n"; + PI.asmMatcherEmitTiedOpEmptyTable(); - OS << "namespace {\n"; + PI.emitNamespace("", true); // Output the operand conversion kind enum. - OS << "enum OperatorConversionKind {\n"; - for (const auto &Converter : OperandConversionKinds) - OS << " " << Converter << ",\n"; - OS << " CVT_NUM_CONVERTERS\n"; - OS << "};\n\n"; + PI.asmMatcherEmitOperandConvKindEnum(OperandConversionKinds); // Output the instruction conversion kind enum. - OS << "enum InstructionConversionKind {\n"; - for (const auto &Signature : InstructionConversionKinds) - OS << " " << Signature << ",\n"; - OS << " CVT_NUM_SIGNATURES\n"; - OS << "};\n\n"; + PI.asmMatcherEmitInstrConvKindEnum(InstructionConversionKinds); - OS << "} // end anonymous namespace\n\n"; + PI.emitNamespace("", false); // Output the conversion table. - OS << "static const uint8_t ConversionTable[CVT_NUM_SIGNATURES][" - << MaxRowLength << "] = {\n"; - - for (unsigned Row = 0, ERow = ConversionTable.size(); Row != ERow; ++Row) { - assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!"); - OS << " // " << InstructionConversionKinds[Row] << "\n"; - OS << " { "; - for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2) { - OS << OperandConversionKinds[ConversionTable[Row][i]] << ", "; - if (OperandConversionKinds[ConversionTable[Row][i]] != - CachedHashString("CVT_Tied")) { - OS << (unsigned)(ConversionTable[Row][i + 1]) << ", "; - continue; - } - - // For a tied operand, emit a reference to the TiedAsmOperandTable - // that contains the operand to copy, and the parsed operands to - // check for their tied constraints. - auto Key = std::make_tuple((uint8_t)ConversionTable[Row][i + 1], - (uint8_t)ConversionTable[Row][i + 2], - (uint8_t)ConversionTable[Row][i + 3]); - auto TiedOpndEnum = TiedOperandsEnumMap.find(Key); - assert(TiedOpndEnum != TiedOperandsEnumMap.end() && - "No record for tied operand pair"); - OS << TiedOpndEnum->second << ", "; - i += 2; - } - OS << "CVT_Done },\n"; - } - - OS << "};\n\n"; + PI.asmMatcherEmitConversionTable(MaxRowLength, + ConversionTable, + InstructionConversionKinds, + OperandConversionKinds, + TiedOperandsEnumMap); // Spit out the conversion driver function. - OS << CvtOS.str(); - + PI.asmMatcherWriteCvtOSToOS(); // Spit out the operand number lookup function. - OS << OpOS.str(); + PI.asmMatcherWriteOpOSToOS(); return ConversionTable.size(); } @@ -2362,179 +1777,29 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, /// emitMatchClassEnumeration - Emit the enumeration for match class kinds. static void emitMatchClassEnumeration(CodeGenTarget &Target, std::forward_list &Infos, - raw_ostream &OS) { - OS << "namespace {\n\n"; - - OS << "/// MatchClassKind - The kinds of classes which participate in\n" - << "/// instruction matching.\n"; - OS << "enum MatchClassKind {\n"; - OS << " InvalidMatchClass = 0,\n"; - OS << " OptionalMatchClass = 1,\n"; - ClassInfo::ClassInfoKind LastKind = ClassInfo::Token; - StringRef LastName = "OptionalMatchClass"; - for (const auto &CI : Infos) { - if (LastKind == ClassInfo::Token && CI.Kind != ClassInfo::Token) { - OS << " MCK_LAST_TOKEN = " << LastName << ",\n"; - } else if (LastKind < ClassInfo::UserClass0 && - CI.Kind >= ClassInfo::UserClass0) { - OS << " MCK_LAST_REGISTER = " << LastName << ",\n"; - } - LastKind = (ClassInfo::ClassInfoKind)CI.Kind; - LastName = CI.Name; - - OS << " " << CI.Name << ", // "; - if (CI.Kind == ClassInfo::Token) { - OS << "'" << CI.ValueName << "'\n"; - } else if (CI.isRegisterClass()) { - if (!CI.ValueName.empty()) - OS << "register class '" << CI.ValueName << "'\n"; - else - OS << "derived register class\n"; - } else { - OS << "user defined class '" << CI.ValueName << "'\n"; - } - } - OS << " NumMatchClassKinds\n"; - OS << "};\n\n"; - - OS << "} // end anonymous namespace\n\n"; + PrinterLLVM const &PI) { + PI.emitNamespace("", true); + PI.asmMatcherEmitMatchClassKindEnum(Infos); + PI.emitNamespace("", false); } /// emitMatchClassDiagStrings - Emit a function to get the diagnostic text to be /// used when an assembly operand does not match the expected operand class. -static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &OS) { +static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, PrinterLLVM const &PI) { // If the target does not use DiagnosticString for any operands, don't emit // an unused function. if (llvm::all_of(Info.Classes, [](const ClassInfo &CI) { return CI.DiagnosticString.empty(); })) return; - - OS << "static const char *getMatchKindDiag(" << Info.Target.getName() - << "AsmParser::" << Info.Target.getName() - << "MatchResultTy MatchResult) {\n"; - OS << " switch (MatchResult) {\n"; - - for (const auto &CI: Info.Classes) { - if (!CI.DiagnosticString.empty()) { - assert(!CI.DiagnosticType.empty() && - "DiagnosticString set without DiagnosticType"); - OS << " case " << Info.Target.getName() - << "AsmParser::Match_" << CI.DiagnosticType << ":\n"; - OS << " return \"" << CI.DiagnosticString << "\";\n"; - } - } - - OS << " default:\n"; - OS << " return nullptr;\n"; - - OS << " }\n"; - OS << "}\n\n"; -} - -static void emitRegisterMatchErrorFunc(AsmMatcherInfo &Info, raw_ostream &OS) { - OS << "static unsigned getDiagKindFromRegisterClass(MatchClassKind " - "RegisterClass) {\n"; - if (none_of(Info.Classes, [](const ClassInfo &CI) { - return CI.isRegisterClass() && !CI.DiagnosticType.empty(); - })) { - OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; - } else { - OS << " switch (RegisterClass) {\n"; - for (const auto &CI: Info.Classes) { - if (CI.isRegisterClass() && !CI.DiagnosticType.empty()) { - OS << " case " << CI.Name << ":\n"; - OS << " return " << Info.Target.getName() << "AsmParser::Match_" - << CI.DiagnosticType << ";\n"; - } - } - - OS << " default:\n"; - OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; - - OS << " }\n"; - } - OS << "}\n\n"; -} - -/// emitValidateOperandClass - Emit the function to validate an operand class. -static void emitValidateOperandClass(AsmMatcherInfo &Info, - raw_ostream &OS) { - OS << "static unsigned validateOperandClass(MCParsedAsmOperand &GOp, " - << "MatchClassKind Kind) {\n"; - OS << " " << Info.Target.getName() << "Operand &Operand = (" - << Info.Target.getName() << "Operand &)GOp;\n"; - - // The InvalidMatchClass is not to match any operand. - OS << " if (Kind == InvalidMatchClass)\n"; - OS << " return MCTargetAsmParser::Match_InvalidOperand;\n\n"; - - // Check for Token operands first. - // FIXME: Use a more specific diagnostic type. - OS << " if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)\n"; - OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n" - << " MCTargetAsmParser::Match_Success :\n" - << " MCTargetAsmParser::Match_InvalidOperand;\n\n"; - - // Check the user classes. We don't care what order since we're only - // actually matching against one of them. - OS << " switch (Kind) {\n" - " default: break;\n"; - for (const auto &CI : Info.Classes) { - if (!CI.isUserClass()) - continue; - - OS << " // '" << CI.ClassName << "' class\n"; - OS << " case " << CI.Name << ": {\n"; - OS << " DiagnosticPredicate DP(Operand." << CI.PredicateMethod - << "());\n"; - OS << " if (DP.isMatch())\n"; - OS << " return MCTargetAsmParser::Match_Success;\n"; - if (!CI.DiagnosticType.empty()) { - OS << " if (DP.isNearMatch())\n"; - OS << " return " << Info.Target.getName() << "AsmParser::Match_" - << CI.DiagnosticType << ";\n"; - OS << " break;\n"; - } - else - OS << " break;\n"; - OS << " }\n"; - } - OS << " } // end switch (Kind)\n\n"; - - // Check for register operands, including sub-classes. - OS << " if (Operand.isReg()) {\n"; - OS << " MatchClassKind OpKind;\n"; - OS << " switch (Operand.getReg()) {\n"; - OS << " default: OpKind = InvalidMatchClass; break;\n"; - for (const auto &RC : Info.RegisterClasses) - OS << " case " << RC.first->getValueAsString("Namespace") << "::" - << RC.first->getName() << ": OpKind = " << RC.second->Name - << "; break;\n"; - OS << " }\n"; - OS << " return isSubclass(OpKind, Kind) ? " - << "(unsigned)MCTargetAsmParser::Match_Success :\n " - << " getDiagKindFromRegisterClass(Kind);\n }\n\n"; - - // Expected operand is a register, but actual is not. - OS << " if (Kind > MCK_LAST_TOKEN && Kind <= MCK_LAST_REGISTER)\n"; - OS << " return getDiagKindFromRegisterClass(Kind);\n\n"; - - // Generic fallthrough match failure case for operands that don't have - // specialized diagnostic types. - OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; - OS << "}\n\n"; + PI.asmMatcherEmitMatchClassDiagStrings(Info); } /// emitIsSubclass - Emit the subclass predicate function. static void emitIsSubclass(CodeGenTarget &Target, std::forward_list &Infos, - raw_ostream &OS) { - OS << "/// isSubclass - Compute whether \\p A is a subclass of \\p B.\n"; - OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n"; - OS << " if (A == B)\n"; - OS << " return true;\n\n"; - + PrinterLLVM const &PI) { + PI.asmMatcherEmitIsSubclassI(); bool EmittedSwitch = false; for (const auto &A : Infos) { std::vector SuperClasses; @@ -2549,47 +1814,26 @@ static void emitIsSubclass(CodeGenTarget &Target, continue; // If this is the first SuperClass, emit the switch header. - if (!EmittedSwitch) { - OS << " switch (A) {\n"; - OS << " default:\n"; - OS << " return false;\n"; - EmittedSwitch = true; - } - - OS << "\n case " << A.Name << ":\n"; + EmittedSwitch = PI.asmMatcherEmitIsSubclassII(EmittedSwitch, A.Name); if (SuperClasses.size() == 1) { - OS << " return B == " << SuperClasses.back() << ";\n"; + PI.asmMatcherEmitIsSubclassIII(SuperClasses.back()); continue; } - if (!SuperClasses.empty()) { - OS << " switch (B) {\n"; - OS << " default: return false;\n"; - for (StringRef SC : SuperClasses) - OS << " case " << SC << ": return true;\n"; - OS << " }\n"; - } else { - // No case statement to emit - OS << " return false;\n"; - } + PI.asmMatcherEmitIsSubclassIV(SuperClasses); } // If there were case statements emitted into the string stream write the // default. - if (EmittedSwitch) - OS << " }\n"; - else - OS << " return false;\n"; - - OS << "}\n\n"; + PI.asmMatcherEmitIsSubclassV(EmittedSwitch); } /// emitMatchTokenString - Emit the function to match a token string to the /// appropriate match class value. static void emitMatchTokenString(CodeGenTarget &Target, std::forward_list &Infos, - raw_ostream &OS) { + PrinterLLVM const &PI) { // Construct the match list. std::vector Matches; for (const auto &CI : Infos) { @@ -2597,18 +1841,13 @@ static void emitMatchTokenString(CodeGenTarget &Target, Matches.emplace_back(CI.ValueName, "return " + CI.Name + ";"); } - OS << "static MatchClassKind matchTokenString(StringRef Name) {\n"; - - StringMatcher("Name", Matches, OS).Emit(); - - OS << " return InvalidMatchClass;\n"; - OS << "}\n\n"; + PI.asmMatcherEmitMatchTokenString(Matches); } /// emitMatchRegisterName - Emit the function to match a string to the target /// specific register enum. static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, - raw_ostream &OS) { + PrinterLLVM const &PI) { // Construct the match list. std::vector Matches; const auto &Regs = Target.getRegBank().getRegisters(); @@ -2620,20 +1859,13 @@ static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, "return " + utostr(Reg.EnumValue) + ";"); } - OS << "static unsigned MatchRegisterName(StringRef Name) {\n"; - - bool IgnoreDuplicates = - AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); - StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates); - - OS << " return 0;\n"; - OS << "}\n\n"; + PI.asmMatcherEmitMatchRegisterName(AsmParser, Matches); } /// Emit the function to match a string to the target /// specific register enum. static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser, - raw_ostream &OS) { + PrinterLLVM const &PI) { // Construct the match list. std::vector Matches; const auto &Regs = Target.getRegBank().getRegisters(); @@ -2652,19 +1884,11 @@ static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser, "return " + utostr(Reg.EnumValue) + ";"); } } - - OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n"; - - bool IgnoreDuplicates = - AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); - StringMatcher("Name", Matches, OS).Emit(0, IgnoreDuplicates); - - OS << " return 0;\n"; - OS << "}\n\n"; + PI.asmMatcherEmitMatchRegisterAltName(AsmParser, Matches); } /// emitOperandDiagnosticTypes - Emit the operand matching diagnostic types. -static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) { +static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, PrinterLLVM const &PI) { // Get the set of diagnostic types from all of the operand classes. std::set Types; for (const auto &OpClassEntry : Info.AsmOperandClasses) { @@ -2679,32 +1903,7 @@ static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) { if (Types.empty()) return; // Now emit the enum entries. - for (StringRef Type : Types) - OS << " Match_" << Type << ",\n"; - OS << " END_OPERAND_DIAGNOSTIC_TYPES\n"; -} - -/// emitGetSubtargetFeatureName - Emit the helper function to get the -/// user-level name for a subtarget feature. -static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) { - OS << "// User-level names for subtarget features that participate in\n" - << "// instruction matching.\n" - << "static const char *getSubtargetFeatureName(uint64_t Val) {\n"; - if (!Info.SubtargetFeatures.empty()) { - OS << " switch(Val) {\n"; - for (const auto &SF : Info.SubtargetFeatures) { - const SubtargetFeatureInfo &SFI = SF.second; - // FIXME: Totally just a placeholder name to get the algorithm working. - OS << " case " << SFI.getEnumBitName() << ": return \"" - << SFI.TheDef->getValueAsString("PredicateName") << "\";\n"; - } - OS << " default: return \"(unknown)\";\n"; - OS << " }\n"; - } else { - // Nothing to emit, so skip the switch - OS << " return \"(unknown)\";\n"; - } - OS << "}\n\n"; + PI.asmMatcherEmitOperandDiagTypes(Types); } static std::string GetAliasRequiredFeatures(Record *R, @@ -2731,7 +1930,7 @@ static std::string GetAliasRequiredFeatures(Record *R, return Result; } -static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, +static void emitMnemonicAliasVariant(PrinterLLVM const &PI, const AsmMatcherInfo &Info, std::vector &Aliases, unsigned Indent = 0, StringRef AsmParserVariantName = StringRef()){ @@ -2786,33 +1985,24 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, if (R->getValueAsString("ToMnemonic") == AliasEntry.first) PrintFatalError(R->getLoc(), "MnemonicAlias to the same string"); - if (!MatchCode.empty()) - MatchCode += "else "; - MatchCode += "if (" + FeatureMask + ")\n"; - MatchCode += " Mnemonic = \""; - MatchCode += R->getValueAsString("ToMnemonic").lower(); - MatchCode += "\";\n"; + PI.asmMatcherAppendMnemonicAlias(R, FeatureMask, MatchCode); } if (AliasWithNoPredicate != -1) { Record *R = ToVec[AliasWithNoPredicate]; - if (!MatchCode.empty()) - MatchCode += "else\n "; - MatchCode += "Mnemonic = \""; - MatchCode += R->getValueAsString("ToMnemonic").lower(); - MatchCode += "\";\n"; + PI.asmMatcherAppendMnemonic(R, MatchCode); } - MatchCode += "return;"; + PI.asmMatcherAppendMnemonicAliasEnd(MatchCode); Cases.push_back(std::make_pair(AliasEntry.first, MatchCode)); } - StringMatcher("Mnemonic", Cases, OS).Emit(Indent); + PI.asmMatcherEmitMnemonicAliasVariant(Cases, Indent); } /// emitMnemonicAliases - If the target has any MnemonicAlias<> definitions, /// emit a function for them and return true, otherwise return false. -static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, +static bool emitMnemonicAliases(PrinterLLVM const &PI, const AsmMatcherInfo &Info, CodeGenTarget &Target) { // Ignore aliases when match-prefix is set. if (!MatchPrefix.empty()) @@ -2822,390 +2012,45 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, Info.getRecords().getAllDerivedDefinitions("MnemonicAlias"); if (Aliases.empty()) return false; - OS << "static void applyMnemonicAliases(StringRef &Mnemonic, " - "const FeatureBitset &Features, unsigned VariantID) {\n"; - OS << " switch (VariantID) {\n"; + PI.asmMatcherEmitApplyMnemonicAliasesI(); unsigned VariantCount = Target.getAsmParserVariantCount(); for (unsigned VC = 0; VC != VariantCount; ++VC) { Record *AsmVariant = Target.getAsmParserVariant(VC); int AsmParserVariantNo = AsmVariant->getValueAsInt("Variant"); StringRef AsmParserVariantName = AsmVariant->getValueAsString("Name"); - OS << " case " << AsmParserVariantNo << ":\n"; - emitMnemonicAliasVariant(OS, Info, Aliases, /*Indent=*/2, + PI.asmMatcherEmitApplyMnemonicAliasesII(AsmParserVariantNo); + emitMnemonicAliasVariant(PI, Info, Aliases, /*Indent=*/2, AsmParserVariantName); - OS << " break;\n"; + PI.asmMatcherEmitApplyMnemonicAliasesIII(); } - OS << " }\n"; + PI.asmMatcherEmitApplyMnemonicAliasesIV(); // Emit aliases that apply to all variants. - emitMnemonicAliasVariant(OS, Info, Aliases); + emitMnemonicAliasVariant(PI, Info, Aliases); - OS << "}\n\n"; + PI.asmMatcherEmitApplyMnemonicAliasesV(); return true; } -static void -emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, - const AsmMatcherInfo &Info, StringRef ClassName, - StringToOffsetTable &StringTable, - unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, - bool HasMnemonicFirst, const Record &AsmParser) { - unsigned MaxMask = 0; - for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { - MaxMask |= OMI.OperandMask; - } - - // Emit the static custom operand parsing table; - OS << "namespace {\n"; - OS << " struct OperandMatchEntry {\n"; - OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) - << " Mnemonic;\n"; - OS << " " << getMinimalTypeForRange(MaxMask) - << " OperandMask;\n"; - OS << " " << getMinimalTypeForRange(std::distance( - Info.Classes.begin(), Info.Classes.end())) << " Class;\n"; - OS << " " << getMinimalTypeForRange(MaxFeaturesIndex) - << " RequiredFeaturesIdx;\n\n"; - OS << " StringRef getMnemonic() const {\n"; - OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; - OS << " MnemonicTable[Mnemonic]);\n"; - OS << " }\n"; - OS << " };\n\n"; - - OS << " // Predicate for searching for an opcode.\n"; - OS << " struct LessOpcodeOperand {\n"; - OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n"; - OS << " return LHS.getMnemonic() < RHS;\n"; - OS << " }\n"; - OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n"; - OS << " return LHS < RHS.getMnemonic();\n"; - OS << " }\n"; - OS << " bool operator()(const OperandMatchEntry &LHS,"; - OS << " const OperandMatchEntry &RHS) {\n"; - OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; - OS << " }\n"; - OS << " };\n"; - - OS << "} // end anonymous namespace\n\n"; - - OS << "static const OperandMatchEntry OperandMatchTable[" - << Info.OperandMatchInfo.size() << "] = {\n"; - - OS << " /* Operand List Mnemonic, Mask, Operand Class, Features */\n"; - for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { - const MatchableInfo &II = *OMI.MI; - - OS << " { "; - - // Store a pascal-style length byte in the mnemonic. - std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.lower(); - OS << StringTable.GetOrAddStringOffset(LenMnemonic, false) - << " /* " << II.Mnemonic << " */, "; - - OS << OMI.OperandMask; - OS << " /* "; - ListSeparator LS; - for (int i = 0, e = 31; i !=e; ++i) - if (OMI.OperandMask & (1 << i)) - OS << LS << i; - OS << " */, "; - - OS << OMI.CI->Name; - - // Write the required features mask. - OS << ", AMFBS"; - if (II.RequiredFeatures.empty()) - OS << "_None"; - else - for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) - OS << '_' << II.RequiredFeatures[i]->TheDef->getName(); - - OS << " },\n"; - } - OS << "};\n\n"; - - // Emit the operand class switch to call the correct custom parser for - // the found operand class. - OS << "ParseStatus " << Target.getName() << ClassName << "::\n" - << "tryCustomParseOperand(OperandVector" - << " &Operands,\n unsigned MCK) {\n\n" - << " switch(MCK) {\n"; - - for (const auto &CI : Info.Classes) { - if (CI.ParserMethod.empty()) - continue; - OS << " case " << CI.Name << ":\n" - << " return " << CI.ParserMethod << "(Operands);\n"; - } - - OS << " default:\n"; - OS << " return ParseStatus::NoMatch;\n"; - OS << " }\n"; - OS << " return ParseStatus::NoMatch;\n"; - OS << "}\n\n"; - - // Emit the static custom operand parser. This code is very similar with - // the other matcher. Also use MatchResultTy here just in case we go for - // a better error handling. - OS << "ParseStatus " << Target.getName() << ClassName << "::\n" - << "MatchOperandParserImpl(OperandVector" - << " &Operands,\n StringRef Mnemonic,\n" - << " bool ParseForAllFeatures) {\n"; - - // Emit code to get the available features. - OS << " // Get the current feature set.\n"; - OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n"; - - OS << " // Get the next operand index.\n"; - OS << " unsigned NextOpNum = Operands.size()" - << (HasMnemonicFirst ? " - 1" : "") << ";\n"; - - // Emit code to search the table. - OS << " // Search the table.\n"; - if (HasMnemonicFirst) { - OS << " auto MnemonicRange =\n"; - OS << " std::equal_range(std::begin(OperandMatchTable), " - "std::end(OperandMatchTable),\n"; - OS << " Mnemonic, LessOpcodeOperand());\n\n"; - } else { - OS << " auto MnemonicRange = std::make_pair(std::begin(OperandMatchTable)," - " std::end(OperandMatchTable));\n"; - OS << " if (!Mnemonic.empty())\n"; - OS << " MnemonicRange =\n"; - OS << " std::equal_range(std::begin(OperandMatchTable), " - "std::end(OperandMatchTable),\n"; - OS << " Mnemonic, LessOpcodeOperand());\n\n"; - } - - OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; - OS << " return ParseStatus::NoMatch;\n\n"; - - OS << " for (const OperandMatchEntry *it = MnemonicRange.first,\n" - << " *ie = MnemonicRange.second; it != ie; ++it) {\n"; - - OS << " // equal_range guarantees that instruction mnemonic matches.\n"; - OS << " assert(Mnemonic == it->getMnemonic());\n\n"; - - // Emit check that the required features are available. - OS << " // check if the available features match\n"; - OS << " const FeatureBitset &RequiredFeatures = " - "FeatureBitsets[it->RequiredFeaturesIdx];\n"; - OS << " if (!ParseForAllFeatures && (AvailableFeatures & " - "RequiredFeatures) != RequiredFeatures)\n"; - OS << " continue;\n\n"; - - // Emit check to ensure the operand number matches. - OS << " // check if the operand in question has a custom parser.\n"; - OS << " if (!(it->OperandMask & (1 << NextOpNum)))\n"; - OS << " continue;\n\n"; - - // Emit call to the custom parser method - StringRef ParserName = AsmParser.getValueAsString("OperandParserMethod"); - if (ParserName.empty()) - ParserName = "tryCustomParseOperand"; - OS << " // call custom parse method to handle the operand\n"; - OS << " ParseStatus Result = " << ParserName << "(Operands, it->Class);\n"; - OS << " if (!Result.isNoMatch())\n"; - OS << " return Result;\n"; - OS << " }\n\n"; - - OS << " // Okay, we had no match.\n"; - OS << " return ParseStatus::NoMatch;\n"; - OS << "}\n\n"; -} - -static void emitAsmTiedOperandConstraints(CodeGenTarget &Target, - AsmMatcherInfo &Info, - raw_ostream &OS) { - std::string AsmParserName = - std::string(Info.AsmParser->getValueAsString("AsmParserClassName")); - OS << "static bool "; - OS << "checkAsmTiedOperandConstraints(const " << Target.getName() - << AsmParserName << "&AsmParser,\n"; - OS << " unsigned Kind,\n"; - OS << " const OperandVector &Operands,\n"; - OS << " uint64_t &ErrorInfo) {\n"; - OS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; - OS << " const uint8_t *Converter = ConversionTable[Kind];\n"; - OS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; - OS << " switch (*p) {\n"; - OS << " case CVT_Tied: {\n"; - OS << " unsigned OpIdx = *(p + 1);\n"; - OS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; - OS << " std::begin(TiedAsmOperandTable)) &&\n"; - OS << " \"Tied operand not found\");\n"; - OS << " unsigned OpndNum1 = TiedAsmOperandTable[OpIdx][1];\n"; - OS << " unsigned OpndNum2 = TiedAsmOperandTable[OpIdx][2];\n"; - OS << " if (OpndNum1 != OpndNum2) {\n"; - OS << " auto &SrcOp1 = Operands[OpndNum1];\n"; - OS << " auto &SrcOp2 = Operands[OpndNum2];\n"; - OS << " if (!AsmParser.areEqualRegs(*SrcOp1, *SrcOp2)) {\n"; - OS << " ErrorInfo = OpndNum2;\n"; - OS << " return false;\n"; - OS << " }\n"; - OS << " }\n"; - OS << " break;\n"; - OS << " }\n"; - OS << " default:\n"; - OS << " break;\n"; - OS << " }\n"; - OS << " }\n"; - OS << " return true;\n"; - OS << "}\n\n"; -} - -static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, - unsigned VariantCount) { - OS << "static std::string " << Target.getName() - << "MnemonicSpellCheck(StringRef S, const FeatureBitset &FBS," - << " unsigned VariantID) {\n"; - if (!VariantCount) - OS << " return \"\";"; - else { - OS << " const unsigned MaxEditDist = 2;\n"; - OS << " std::vector Candidates;\n"; - OS << " StringRef Prev = \"\";\n\n"; - - OS << " // Find the appropriate table for this asm variant.\n"; - OS << " const MatchEntry *Start, *End;\n"; - OS << " switch (VariantID) {\n"; - OS << " default: llvm_unreachable(\"invalid variant!\");\n"; - for (unsigned VC = 0; VC != VariantCount; ++VC) { - Record *AsmVariant = Target.getAsmParserVariant(VC); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC - << "); End = std::end(MatchTable" << VC << "); break;\n"; - } - OS << " }\n\n"; - OS << " for (auto I = Start; I < End; I++) {\n"; - OS << " // Ignore unsupported instructions.\n"; - OS << " const FeatureBitset &RequiredFeatures = " - "FeatureBitsets[I->RequiredFeaturesIdx];\n"; - OS << " if ((FBS & RequiredFeatures) != RequiredFeatures)\n"; - OS << " continue;\n"; - OS << "\n"; - OS << " StringRef T = I->getMnemonic();\n"; - OS << " // Avoid recomputing the edit distance for the same string.\n"; - OS << " if (T.equals(Prev))\n"; - OS << " continue;\n"; - OS << "\n"; - OS << " Prev = T;\n"; - OS << " unsigned Dist = S.edit_distance(T, false, MaxEditDist);\n"; - OS << " if (Dist <= MaxEditDist)\n"; - OS << " Candidates.push_back(T);\n"; - OS << " }\n"; - OS << "\n"; - OS << " if (Candidates.empty())\n"; - OS << " return \"\";\n"; - OS << "\n"; - OS << " std::string Res = \", did you mean: \";\n"; - OS << " unsigned i = 0;\n"; - OS << " for (; i < Candidates.size() - 1; i++)\n"; - OS << " Res += Candidates[i].str() + \", \";\n"; - OS << " return Res + Candidates[i].str() + \"?\";\n"; - } - OS << "}\n"; - OS << "\n"; -} - -static void emitMnemonicChecker(raw_ostream &OS, - CodeGenTarget &Target, - unsigned VariantCount, - bool HasMnemonicFirst, - bool HasMnemonicAliases) { - OS << "static bool " << Target.getName() - << "CheckMnemonic(StringRef Mnemonic,\n"; - OS << " " - << "const FeatureBitset &AvailableFeatures,\n"; - OS << " " - << "unsigned VariantID) {\n"; - - if (!VariantCount) { - OS << " return false;\n"; - } else { - if (HasMnemonicAliases) { - OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; - OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);"; - OS << "\n\n"; - } - OS << " // Find the appropriate table for this asm variant.\n"; - OS << " const MatchEntry *Start, *End;\n"; - OS << " switch (VariantID) {\n"; - OS << " default: llvm_unreachable(\"invalid variant!\");\n"; - for (unsigned VC = 0; VC != VariantCount; ++VC) { - Record *AsmVariant = Target.getAsmParserVariant(VC); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC - << "); End = std::end(MatchTable" << VC << "); break;\n"; - } - OS << " }\n\n"; - - OS << " // Search the table.\n"; - if (HasMnemonicFirst) { - OS << " auto MnemonicRange = " - "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; - } else { - OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; - OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; - OS << " if (!Mnemonic.empty())\n"; - OS << " MnemonicRange = " - << "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; - } - - OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; - OS << " return false;\n\n"; - - OS << " for (const MatchEntry *it = MnemonicRange.first, " - << "*ie = MnemonicRange.second;\n"; - OS << " it != ie; ++it) {\n"; - OS << " const FeatureBitset &RequiredFeatures =\n"; - OS << " FeatureBitsets[it->RequiredFeaturesIdx];\n"; - OS << " if ((AvailableFeatures & RequiredFeatures) == "; - OS << "RequiredFeatures)\n"; - OS << " return true;\n"; - OS << " }\n"; - OS << " return false;\n"; - } - OS << "}\n"; - OS << "\n"; -} - -// Emit a function mapping match classes to strings, for debugging. -static void emitMatchClassKindNames(std::forward_list &Infos, - raw_ostream &OS) { - OS << "#ifndef NDEBUG\n"; - OS << "const char *getMatchClassName(MatchClassKind Kind) {\n"; - OS << " switch (Kind) {\n"; +namespace { - OS << " case InvalidMatchClass: return \"InvalidMatchClass\";\n"; - OS << " case OptionalMatchClass: return \"OptionalMatchClass\";\n"; - for (const auto &CI : Infos) { - OS << " case " << CI.Name << ": return \"" << CI.Name << "\";\n"; - } - OS << " case NumMatchClassKinds: return \"NumMatchClassKinds\";\n"; +class AsmMatcherEmitter { + RecordKeeper &Records; + PrinterLLVM &PI; - OS << " }\n"; - OS << " llvm_unreachable(\"unhandled MatchClassKind!\");\n"; - OS << "}\n\n"; - OS << "#endif // NDEBUG\n"; -} +public: + AsmMatcherEmitter(RecordKeeper &R, PrinterLLVM &PI) : Records(R), PI(PI) {} -static std::string -getNameForFeatureBitset(const std::vector &FeatureBitset) { - std::string Name = "AMFBS"; - for (const auto &Feature : FeatureBitset) - Name += ("_" + Feature->getName()).str(); - return Name; -} + void run(); +}; -void AsmMatcherEmitter::run(raw_ostream &OS) { +void AsmMatcherEmitter::run() { + PI.asmMatcherEmitSourceFileHeader("Assembly Matcher Source Fragment"); CodeGenTarget Target(Records); Record *AsmParser = Target.getAsmParser(); StringRef ClassName = AsmParser->getValueAsString("AsmParserClassName"); - emitSourceFileHeader("Assembly Matcher Source Fragment", OS, Records); - // Compute the information on the instructions to match. AsmMatcherInfo Info(AsmParser, Target, Records); Info.buildInfo(); @@ -3268,131 +2113,72 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Write the output. // Information for the class declaration. - OS << "\n#ifdef GET_ASSEMBLER_HEADER\n"; - OS << "#undef GET_ASSEMBLER_HEADER\n"; - OS << " // This should be included into the middle of the declaration of\n"; - OS << " // your subclasses implementation of MCTargetAsmParser.\n"; - OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset &FB) const;\n"; - if (HasOptionalOperands) { - OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector &Operands,\n" - << " const SmallBitVector &OptionalOperandsMask);\n"; - } else { - OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector &Operands);\n"; - } - OS << " void convertToMapAndConstraints(unsigned Kind,\n "; - OS << " const OperandVector &Operands) override;\n"; - OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" - << " MCInst &Inst,\n"; - if (ReportMultipleNearMisses) - OS << " SmallVectorImpl *NearMisses,\n"; - else - OS << " uint64_t &ErrorInfo,\n" - << " FeatureBitset &MissingFeatures,\n"; - OS << " bool matchingInlineAsm,\n" - << " unsigned VariantID = 0);\n"; - if (!ReportMultipleNearMisses) - OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" - << " MCInst &Inst,\n" - << " uint64_t &ErrorInfo,\n" - << " bool matchingInlineAsm,\n" - << " unsigned VariantID = 0) {\n" - << " FeatureBitset MissingFeatures;\n" - << " return MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,\n" - << " matchingInlineAsm, VariantID);\n" - << " }\n\n"; - - - if (!Info.OperandMatchInfo.empty()) { - OS << " ParseStatus MatchOperandParserImpl(\n"; - OS << " OperandVector &Operands,\n"; - OS << " StringRef Mnemonic,\n"; - OS << " bool ParseForAllFeatures = false);\n"; - - OS << " ParseStatus tryCustomParseOperand(\n"; - OS << " OperandVector &Operands,\n"; - OS << " unsigned MCK);\n\n"; - } - - OS << "#endif // GET_ASSEMBLER_HEADER\n\n"; + PI.emitIncludeToggle("GET_ASSEMBLER_HEADER", true); + PI.asmMatcherEmitDeclarations(HasOptionalOperands, ReportMultipleNearMisses, !Info.OperandMatchInfo.empty()); + PI.emitIncludeToggle("GET_ASSEMBLER_HEADER", false); // Emit the operand match diagnostic enum names. - OS << "\n#ifdef GET_OPERAND_DIAGNOSTIC_TYPES\n"; - OS << "#undef GET_OPERAND_DIAGNOSTIC_TYPES\n\n"; - emitOperandDiagnosticTypes(Info, OS); - OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n"; - - OS << "\n#ifdef GET_REGISTER_MATCHER\n"; - OS << "#undef GET_REGISTER_MATCHER\n\n"; + PI.emitIncludeToggle("GET_OPERAND_DIAGNOSTIC_TYPES", true); + emitOperandDiagnosticTypes(Info, PI); + PI.emitIncludeToggle("GET_OPERAND_DIAGNOSTIC_TYPES", false); + PI.emitIncludeToggle("GET_REGISTER_MATCHER", true); // Emit the subtarget feature enumeration. - SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( - Info.SubtargetFeatures, OS); + PI.asmMatcherEmitSTFBitEnum(Info); // Emit the function to match a register name to number. // This should be omitted for Mips target if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName")) - emitMatchRegisterName(Target, AsmParser, OS); + emitMatchRegisterName(Target, AsmParser, PI); if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterAltName")) - emitMatchRegisterAltName(Target, AsmParser, OS); - - OS << "#endif // GET_REGISTER_MATCHER\n\n"; - - OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n"; - OS << "#undef GET_SUBTARGET_FEATURE_NAME\n\n"; + emitMatchRegisterAltName(Target, AsmParser, PI); + PI.emitIncludeToggle("GET_REGISTER_MATCHER", false); + PI.emitIncludeToggle("GET_SUBTARGET_FEATURE_NAME", true); // Generate the helper function to get the names for subtarget features. - emitGetSubtargetFeatureName(Info, OS); - - OS << "#endif // GET_SUBTARGET_FEATURE_NAME\n\n"; - - OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n"; - OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n"; + PI.asmMatcherEmitGetSubtargetFeatureName(Info.SubtargetFeatures); + PI.emitIncludeToggle("GET_SUBTARGET_FEATURE_NAME", false); + PI.emitIncludeToggle("GET_MATCHER_IMPLEMENTATION", true); // Generate the function that remaps for mnemonic aliases. - bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target); + bool HasMnemonicAliases = emitMnemonicAliases(PI, Info, Target); // Generate the convertToMCInst function to convert operands into an MCInst. // Also, generate the convertToMapAndConstraints function for MS-style inline // assembly. The latter doesn't actually generate a MCInst. unsigned NumConverters = emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, - HasOptionalOperands, OS); + HasOptionalOperands, PI); // Emit the enumeration for classes which participate in matching. - emitMatchClassEnumeration(Target, Info.Classes, OS); + emitMatchClassEnumeration(Target, Info.Classes, PI); // Emit a function to get the user-visible string to describe an operand // match failure in diagnostics. - emitOperandMatchErrorDiagStrings(Info, OS); + emitOperandMatchErrorDiagStrings(Info, PI); // Emit a function to map register classes to operand match failure codes. - emitRegisterMatchErrorFunc(Info, OS); + PI.asmMatcherEmitRegisterMatchErrorFunc(Info); // Emit the routine to match token strings to their match class. - emitMatchTokenString(Target, Info.Classes, OS); + emitMatchTokenString(Target, Info.Classes, PI); // Emit the subclass predicate routine. - emitIsSubclass(Target, Info.Classes, OS); + emitIsSubclass(Target, Info.Classes, PI); // Emit the routine to validate an operand against a match class. - emitValidateOperandClass(Info, OS); + PI.asmMatcherEmitValidateOperandClass(Info); - emitMatchClassKindNames(Info.Classes, OS); + PI.asmMatcherEmitMatchClassKindNames(Info.Classes); // Emit the available features compute function. - SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( - Info.Target.getName(), ClassName, "ComputeAvailableFeatures", - Info.SubtargetFeatures, OS); + PI.asmMatcherEmitComputeAssemblerAvailableFeatures(Info, ClassName); if (!ReportMultipleNearMisses) - emitAsmTiedOperandConstraints(Target, Info, OS); + PI.asmMatcherEmitAsmTiedOperandConstraints(Target, Info); - StringToOffsetTable StringTable; + StringToOffsetTable StringTable(PrinterLLVM::getLanguage()); size_t MaxNumOperands = 0; unsigned MaxMnemonicIndex = 0; @@ -3407,9 +2193,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { StringTable.GetOrAddStringOffset(LenMnemonic, false)); } - OS << "static const char MnemonicTable[] =\n"; - StringTable.EmitString(OS); - OS << ";\n\n"; + PI.asmMatcherEmitMnemonicTable(StringTable); std::vector> FeatureBitsets; for (const auto &MI : Info.Matchables) { @@ -3437,29 +2221,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { FeatureBitsets.erase( std::unique(FeatureBitsets.begin(), FeatureBitsets.end()), FeatureBitsets.end()); - OS << "// Feature bitsets.\n" - << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n" - << " AMFBS_None,\n"; - for (const auto &FeatureBitset : FeatureBitsets) { - if (FeatureBitset.empty()) - continue; - OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; - } - OS << "};\n\n" - << "static constexpr FeatureBitset FeatureBitsets[] = {\n" - << " {}, // AMFBS_None\n"; - for (const auto &FeatureBitset : FeatureBitsets) { - if (FeatureBitset.empty()) - continue; - OS << " {"; - for (const auto &Feature : FeatureBitset) { - const auto &I = Info.SubtargetFeatures.find(Feature); - assert(I != Info.SubtargetFeatures.end() && "Didn't import predicate?"); - OS << I->second.getEnumBitName() << ", "; - } - OS << "},\n"; - } - OS << "};\n\n"; + PI.asmMatcherEmitFeatureBitsetEnum(FeatureBitsets); + PI.asmMatcherEmitFeatureBitsets(FeatureBitsets, Info); // Emit the static match table; unused classes get initialized to 0 which is // guaranteed to be InvalidMatchClass. @@ -3471,537 +2234,64 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // order the match kinds appropriately (putting mnemonics last), then we // should only end up using a few bits for each class, especially the ones // following the mnemonic. - OS << "namespace {\n"; - OS << " struct MatchEntry {\n"; - OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) - << " Mnemonic;\n"; - OS << " uint16_t Opcode;\n"; - OS << " " << getMinimalTypeForRange(NumConverters) - << " ConvertFn;\n"; - OS << " " << getMinimalTypeForRange(FeatureBitsets.size()) - << " RequiredFeaturesIdx;\n"; - OS << " " << getMinimalTypeForRange( - std::distance(Info.Classes.begin(), Info.Classes.end())) - << " Classes[" << MaxNumOperands << "];\n"; - OS << " StringRef getMnemonic() const {\n"; - OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; - OS << " MnemonicTable[Mnemonic]);\n"; - OS << " }\n"; - OS << " };\n\n"; - - OS << " // Predicate for searching for an opcode.\n"; - OS << " struct LessOpcode {\n"; - OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n"; - OS << " return LHS.getMnemonic() < RHS;\n"; - OS << " }\n"; - OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n"; - OS << " return LHS < RHS.getMnemonic();\n"; - OS << " }\n"; - OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n"; - OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; - OS << " }\n"; - OS << " };\n"; - - OS << "} // end anonymous namespace\n\n"; + PI.emitNamespace("", true); + PI.asmMatcherEmitMatchEntryStruct(MaxMnemonicIndex, NumConverters, MaxNumOperands, + FeatureBitsets, Info); + PI.emitNamespace("", false); unsigned VariantCount = Target.getAsmParserVariantCount(); - for (unsigned VC = 0; VC != VariantCount; ++VC) { - Record *AsmVariant = Target.getAsmParserVariant(VC); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - - OS << "static const MatchEntry MatchTable" << VC << "[] = {\n"; + PI.asmMatcherEmitMatchTable(Target, Info, StringTable, VariantCount); - for (const auto &MI : Info.Matchables) { - if (MI->AsmVariantID != AsmVariantNo) - continue; - - // Store a pascal-style length byte in the mnemonic. - std::string LenMnemonic = - char(MI->Mnemonic.size()) + MI->Mnemonic.lower(); - OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false) - << " /* " << MI->Mnemonic << " */, " - << Target.getInstNamespace() << "::" - << MI->getResultInst()->TheDef->getName() << ", " - << MI->ConversionFnKind << ", "; - - // Write the required features mask. - OS << "AMFBS"; - if (MI->RequiredFeatures.empty()) - OS << "_None"; - else - for (unsigned i = 0, e = MI->RequiredFeatures.size(); i != e; ++i) - OS << '_' << MI->RequiredFeatures[i]->TheDef->getName(); - - OS << ", { "; - ListSeparator LS; - for (const MatchableInfo::AsmOperand &Op : MI->AsmOperands) - OS << LS << Op.Class->Name; - OS << " }, },\n"; - } - - OS << "};\n\n"; - } - - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/Format.h\"\n\n"; + PI.asmMatcherEmitIncludes(); // Finally, build the match function. - OS << "unsigned " << Target.getName() << ClassName << "::\n" - << "MatchInstructionImpl(const OperandVector &Operands,\n"; - OS << " MCInst &Inst,\n"; - if (ReportMultipleNearMisses) - OS << " SmallVectorImpl *NearMisses,\n"; - else - OS << " uint64_t &ErrorInfo,\n" - << " FeatureBitset &MissingFeatures,\n"; - OS << " bool matchingInlineAsm, unsigned VariantID) {\n"; - - if (!ReportMultipleNearMisses) { - OS << " // Eliminate obvious mismatches.\n"; - OS << " if (Operands.size() > " - << (MaxNumOperands + HasMnemonicFirst) << ") {\n"; - OS << " ErrorInfo = " - << (MaxNumOperands + HasMnemonicFirst) << ";\n"; - OS << " return Match_InvalidOperand;\n"; - OS << " }\n\n"; - } - - // Emit code to get the available features. - OS << " // Get the current feature set.\n"; - OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n"; - - OS << " // Get the instruction mnemonic, which is the first token.\n"; - if (HasMnemonicFirst) { - OS << " StringRef Mnemonic = ((" << Target.getName() - << "Operand &)*Operands[0]).getToken();\n\n"; - } else { - OS << " StringRef Mnemonic;\n"; - OS << " if (Operands[0]->isToken())\n"; - OS << " Mnemonic = ((" << Target.getName() - << "Operand &)*Operands[0]).getToken();\n\n"; - } - - if (HasMnemonicAliases) { - OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; - OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);\n\n"; - } - - // Emit code to compute the class list for this operand vector. - if (!ReportMultipleNearMisses) { - OS << " // Some state to try to produce better error messages.\n"; - OS << " bool HadMatchOtherThanFeatures = false;\n"; - OS << " bool HadMatchOtherThanPredicate = false;\n"; - OS << " unsigned RetCode = Match_InvalidOperand;\n"; - OS << " MissingFeatures.set();\n"; - OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; - OS << " // wrong for all instances of the instruction.\n"; - OS << " ErrorInfo = ~0ULL;\n"; - } - - if (HasOptionalOperands) { - OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n"; - } - - // Emit code to search the table. - OS << " // Find the appropriate table for this asm variant.\n"; - OS << " const MatchEntry *Start, *End;\n"; - OS << " switch (VariantID) {\n"; - OS << " default: llvm_unreachable(\"invalid variant!\");\n"; - for (unsigned VC = 0; VC != VariantCount; ++VC) { - Record *AsmVariant = Target.getAsmParserVariant(VC); - int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC - << "); End = std::end(MatchTable" << VC << "); break;\n"; - } - OS << " }\n"; - - OS << " // Search the table.\n"; - if (HasMnemonicFirst) { - OS << " auto MnemonicRange = " - "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; - } else { - OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; - OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; - OS << " if (!Mnemonic.empty())\n"; - OS << " MnemonicRange = " - "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; - } + PI.asmMatcherEmitMatchFunction( + Target, AsmParser, ClassName, HasMnemonicFirst, HasOptionalOperands, + ReportMultipleNearMisses, HasMnemonicAliases, MaxNumOperands, + HasDeprecation, VariantCount); - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"AsmMatcher: found \" <<\n" - << " std::distance(MnemonicRange.first, MnemonicRange.second) <<\n" - << " \" encodings with mnemonic '\" << Mnemonic << \"'\\n\");\n\n"; - - OS << " // Return a more specific error code if no mnemonics match.\n"; - OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; - OS << " return Match_MnemonicFail;\n\n"; - - OS << " for (const MatchEntry *it = MnemonicRange.first, " - << "*ie = MnemonicRange.second;\n"; - OS << " it != ie; ++it) {\n"; - OS << " const FeatureBitset &RequiredFeatures = " - "FeatureBitsets[it->RequiredFeaturesIdx];\n"; - OS << " bool HasRequiredFeatures =\n"; - OS << " (AvailableFeatures & RequiredFeatures) == RequiredFeatures;\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Trying to match opcode \"\n"; - OS << " << MII.getName(it->Opcode) << \"\\n\");\n"; - - if (ReportMultipleNearMisses) { - OS << " // Some state to record ways in which this instruction did not match.\n"; - OS << " NearMissInfo OperandNearMiss = NearMissInfo::getSuccess();\n"; - OS << " NearMissInfo FeaturesNearMiss = NearMissInfo::getSuccess();\n"; - OS << " NearMissInfo EarlyPredicateNearMiss = NearMissInfo::getSuccess();\n"; - OS << " NearMissInfo LatePredicateNearMiss = NearMissInfo::getSuccess();\n"; - OS << " bool MultipleInvalidOperands = false;\n"; - } - - if (HasMnemonicFirst) { - OS << " // equal_range guarantees that instruction mnemonic matches.\n"; - OS << " assert(Mnemonic == it->getMnemonic());\n"; - } - - // Emit check that the subclasses match. - if (!ReportMultipleNearMisses) - OS << " bool OperandsValid = true;\n"; - if (HasOptionalOperands) { - OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n"; - } - OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex") - << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex") - << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n"; - OS << " auto Formal = " - << "static_cast(it->Classes[FormalIdx]);\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; - OS << " dbgs() << \" Matching formal operand class \" << getMatchClassName(Formal)\n"; - OS << " << \" against actual operand at index \" << ActualIdx);\n"; - OS << " if (ActualIdx < Operands.size())\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \" (\";\n"; - OS << " Operands[ActualIdx]->print(dbgs()); dbgs() << \"): \");\n"; - OS << " else\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n"; - OS << " if (ActualIdx >= Operands.size()) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand " - "index out of range\\n\");\n"; - if (ReportMultipleNearMisses) { - OS << " bool ThisOperandValid = (Formal == " <<"InvalidMatchClass) || " - "isSubclass(Formal, OptionalMatchClass);\n"; - OS << " if (!ThisOperandValid) {\n"; - OS << " if (!OperandNearMiss) {\n"; - OS << " // Record info about match failure for later use.\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"recording too-few-operands near miss\\n\");\n"; - OS << " OperandNearMiss =\n"; - OS << " NearMissInfo::getTooFewOperands(Formal, it->Opcode);\n"; - OS << " } else if (OperandNearMiss.getKind() != NearMissInfo::NearMissTooFewOperands) {\n"; - OS << " // If more than one operand is invalid, give up on this match entry.\n"; - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs() << \"second invalid operand, giving up on this opcode\\n\");\n"; - OS << " MultipleInvalidOperands = true;\n"; - OS << " break;\n"; - OS << " }\n"; - OS << " } else {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal " - "operand not required\\n\");\n"; - OS << " }\n"; - OS << " continue;\n"; - } else { - OS << " if (Formal == InvalidMatchClass) {\n"; - if (HasOptionalOperands) { - OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands - << ");\n"; - } - OS << " break;\n"; - OS << " }\n"; - OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n"; - if (HasOptionalOperands) { - OS << " OptionalOperandsMask.set(FormalIdx);\n"; - } - OS << " continue;\n"; - OS << " }\n"; - OS << " OperandsValid = false;\n"; - OS << " ErrorInfo = ActualIdx;\n"; - OS << " break;\n"; - } - OS << " }\n"; - OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n"; - OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n"; - OS << " if (Diag == Match_Success) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; - OS << " dbgs() << \"match success using generic matcher\\n\");\n"; - OS << " ++ActualIdx;\n"; - OS << " continue;\n"; - OS << " }\n"; - OS << " // If the generic handler indicates an invalid operand\n"; - OS << " // failure, check for a special case.\n"; - OS << " if (Diag != Match_Success) {\n"; - OS << " unsigned TargetDiag = validateTargetOperandClass(Actual, Formal);\n"; - OS << " if (TargetDiag == Match_Success) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; - OS << " dbgs() << \"match success using target matcher\\n\");\n"; - OS << " ++ActualIdx;\n"; - OS << " continue;\n"; - OS << " }\n"; - OS << " // If the target matcher returned a specific error code use\n"; - OS << " // that, else use the one from the generic matcher.\n"; - OS << " if (TargetDiag != Match_InvalidOperand && " - "HasRequiredFeatures)\n"; - OS << " Diag = TargetDiag;\n"; - OS << " }\n"; - OS << " // If current formal operand wasn't matched and it is optional\n" - << " // then try to match next formal operand\n"; - OS << " if (Diag == Match_InvalidOperand " - << "&& isSubclass(Formal, OptionalMatchClass)) {\n"; - if (HasOptionalOperands) { - OS << " OptionalOperandsMask.set(FormalIdx);\n"; - } - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"ignoring optional operand\\n\");\n"; - OS << " continue;\n"; - OS << " }\n"; - - if (ReportMultipleNearMisses) { - OS << " if (!OperandNearMiss) {\n"; - OS << " // If this is the first invalid operand we have seen, record some\n"; - OS << " // information about it.\n"; - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs()\n"; - OS << " << \"operand match failed, recording near-miss with diag code \"\n"; - OS << " << Diag << \"\\n\");\n"; - OS << " OperandNearMiss =\n"; - OS << " NearMissInfo::getMissedOperand(Diag, Formal, it->Opcode, ActualIdx);\n"; - OS << " ++ActualIdx;\n"; - OS << " } else {\n"; - OS << " // If more than one operand is invalid, give up on this match entry.\n"; - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs() << \"second operand mismatch, skipping this opcode\\n\");\n"; - OS << " MultipleInvalidOperands = true;\n"; - OS << " break;\n"; - OS << " }\n"; - OS << " }\n\n"; - } else { - OS << " // If this operand is broken for all of the instances of this\n"; - OS << " // mnemonic, keep track of it so we can report loc info.\n"; - OS << " // If we already had a match that only failed due to a\n"; - OS << " // target predicate, that diagnostic is preferred.\n"; - OS << " if (!HadMatchOtherThanPredicate &&\n"; - OS << " (it == MnemonicRange.first || ErrorInfo <= ActualIdx)) {\n"; - OS << " if (HasRequiredFeatures && (ErrorInfo != ActualIdx || Diag " - "!= Match_InvalidOperand))\n"; - OS << " RetCode = Diag;\n"; - OS << " ErrorInfo = ActualIdx;\n"; - OS << " }\n"; - OS << " // Otherwise, just reject this instance of the mnemonic.\n"; - OS << " OperandsValid = false;\n"; - OS << " break;\n"; - OS << " }\n\n"; - } - - if (ReportMultipleNearMisses) - OS << " if (MultipleInvalidOperands) {\n"; - else - OS << " if (!OperandsValid) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n"; - OS << " \"operand mismatches, ignoring \"\n"; - OS << " \"this opcode\\n\");\n"; - OS << " continue;\n"; - OS << " }\n"; - - // Emit check that the required features are available. - OS << " if (!HasRequiredFeatures) {\n"; - if (!ReportMultipleNearMisses) - OS << " HadMatchOtherThanFeatures = true;\n"; - OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & " - "~AvailableFeatures;\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features:\";\n"; - OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n"; - OS << " if (NewMissingFeatures[I])\n"; - OS << " dbgs() << ' ' << I;\n"; - OS << " dbgs() << \"\\n\");\n"; - if (ReportMultipleNearMisses) { - OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n"; - } else { - OS << " if (NewMissingFeatures.count() <=\n" - " MissingFeatures.count())\n"; - OS << " MissingFeatures = NewMissingFeatures;\n"; - OS << " continue;\n"; - } - OS << " }\n"; - OS << "\n"; - OS << " Inst.clear();\n\n"; - OS << " Inst.setOpcode(it->Opcode);\n"; - // Verify the instruction with the target-specific match predicate function. - OS << " // We have a potential match but have not rendered the operands.\n" - << " // Check the target predicate to handle any context sensitive\n" - " // constraints.\n" - << " // For example, Ties that are referenced multiple times must be\n" - " // checked here to ensure the input is the same for each match\n" - " // constraints. If we leave it any later the ties will have been\n" - " // canonicalized\n" - << " unsigned MatchResult;\n" - << " if ((MatchResult = checkEarlyTargetMatchPredicate(Inst, " - "Operands)) != Match_Success) {\n" - << " Inst.clear();\n"; - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs() << \"Early target match predicate failed with diag code \"\n"; - OS << " << MatchResult << \"\\n\");\n"; - if (ReportMultipleNearMisses) { - OS << " EarlyPredicateNearMiss = NearMissInfo::getMissedPredicate(MatchResult);\n"; - } else { - OS << " RetCode = MatchResult;\n" - << " HadMatchOtherThanPredicate = true;\n" - << " continue;\n"; - } - OS << " }\n\n"; - - if (ReportMultipleNearMisses) { - OS << " // If we did not successfully match the operands, then we can't convert to\n"; - OS << " // an MCInst, so bail out on this instruction variant now.\n"; - OS << " if (OperandNearMiss) {\n"; - OS << " // If the operand mismatch was the only problem, reprrt it as a near-miss.\n"; - OS << " if (NearMisses && !FeaturesNearMiss && !EarlyPredicateNearMiss) {\n"; - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs()\n"; - OS << " << \"Opcode result: one mismatched operand, adding near-miss\\n\");\n"; - OS << " NearMisses->push_back(OperandNearMiss);\n"; - OS << " } else {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n"; - OS << " \"types of mismatch, so not \"\n"; - OS << " \"reporting near-miss\\n\");\n"; - OS << " }\n"; - OS << " continue;\n"; - OS << " }\n\n"; - } - - OS << " if (matchingInlineAsm) {\n"; - OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n"; - if (!ReportMultipleNearMisses) { - OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, " - "Operands, ErrorInfo))\n"; - OS << " return Match_InvalidTiedOperand;\n"; - OS << "\n"; - } - OS << " return Match_Success;\n"; - OS << " }\n\n"; - OS << " // We have selected a definite instruction, convert the parsed\n" - << " // operands into the appropriate MCInst.\n"; - if (HasOptionalOperands) { - OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n" - << " OptionalOperandsMask);\n"; - } else { - OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; - } - OS << "\n"; - - // Verify the instruction with the target-specific match predicate function. - OS << " // We have a potential match. Check the target predicate to\n" - << " // handle any context sensitive constraints.\n" - << " if ((MatchResult = checkTargetMatchPredicate(Inst)) !=" - << " Match_Success) {\n" - << " DEBUG_WITH_TYPE(\"asm-matcher\",\n" - << " dbgs() << \"Target match predicate failed with diag code \"\n" - << " << MatchResult << \"\\n\");\n" - << " Inst.clear();\n"; - if (ReportMultipleNearMisses) { - OS << " LatePredicateNearMiss = NearMissInfo::getMissedPredicate(MatchResult);\n"; - } else { - OS << " RetCode = MatchResult;\n" - << " HadMatchOtherThanPredicate = true;\n" - << " continue;\n"; - } - OS << " }\n\n"; - - if (ReportMultipleNearMisses) { - OS << " int NumNearMisses = ((int)(bool)OperandNearMiss +\n"; - OS << " (int)(bool)FeaturesNearMiss +\n"; - OS << " (int)(bool)EarlyPredicateNearMiss +\n"; - OS << " (int)(bool)LatePredicateNearMiss);\n"; - OS << " if (NumNearMisses == 1) {\n"; - OS << " // We had exactly one type of near-miss, so add that to the list.\n"; - OS << " assert(!OperandNearMiss && \"OperandNearMiss was handled earlier\");\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: found one type of \"\n"; - OS << " \"mismatch, so reporting a \"\n"; - OS << " \"near-miss\\n\");\n"; - OS << " if (NearMisses && FeaturesNearMiss)\n"; - OS << " NearMisses->push_back(FeaturesNearMiss);\n"; - OS << " else if (NearMisses && EarlyPredicateNearMiss)\n"; - OS << " NearMisses->push_back(EarlyPredicateNearMiss);\n"; - OS << " else if (NearMisses && LatePredicateNearMiss)\n"; - OS << " NearMisses->push_back(LatePredicateNearMiss);\n"; - OS << "\n"; - OS << " continue;\n"; - OS << " } else if (NumNearMisses > 1) {\n"; - OS << " // This instruction missed in more than one way, so ignore it.\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n"; - OS << " \"types of mismatch, so not \"\n"; - OS << " \"reporting near-miss\\n\");\n"; - OS << " continue;\n"; - OS << " }\n"; + if (!Info.OperandMatchInfo.empty()) { + unsigned MaxMask = 0; + for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { + MaxMask |= OMI.OperandMask; + } + PI.asmMatcherEmitCustomOperandParsing(MaxMask, Target, Info, ClassName, + StringTable, MaxMnemonicIndex, FeatureBitsets.size(), + HasMnemonicFirst, *AsmParser); } + PI.emitIncludeToggle("GET_MATCHER_IMPLEMENTATION", false); - // Call the post-processing function, if used. - StringRef InsnCleanupFn = AsmParser->getValueAsString("AsmParserInstCleanup"); - if (!InsnCleanupFn.empty()) - OS << " " << InsnCleanupFn << "(Inst);\n"; - - if (HasDeprecation) { - OS << " std::string Info;\n"; - OS << " if (!getParser().getTargetParser().getTargetOptions().MCNoDeprecatedWarn &&\n"; - OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; - OS << " SMLoc Loc = ((" << Target.getName() - << "Operand &)*Operands[0]).getStartLoc();\n"; - OS << " getParser().Warning(Loc, Info, std::nullopt);\n"; - OS << " }\n"; - } + PI.emitIncludeToggle("GET_MNEMONIC_SPELL_CHECKER", true); + PI.asmMatcherEmitMnemonicSpellChecker(Target, VariantCount); + PI.emitIncludeToggle("GET_MNEMONIC_SPELL_CHECKER", false); - if (!ReportMultipleNearMisses) { - OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, " - "Operands, ErrorInfo))\n"; - OS << " return Match_InvalidTiedOperand;\n"; - OS << "\n"; - } + PI.emitIncludeToggle("GET_MNEMONIC_CHECKER", true); + PI.asmMatcherEmitMnemonicChecker(Target, VariantCount, + HasMnemonicFirst, HasMnemonicAliases); + PI.emitIncludeToggle("GET_MNEMONIC_CHECKER", false); +} - OS << " DEBUG_WITH_TYPE(\n"; - OS << " \"asm-matcher\",\n"; - OS << " dbgs() << \"Opcode result: complete match, selecting this opcode\\n\");\n"; - OS << " return Match_Success;\n"; - OS << " }\n\n"; - - if (ReportMultipleNearMisses) { - OS << " // No instruction variants matched exactly.\n"; - OS << " return Match_NearMisses;\n"; - } else { - OS << " // Okay, we had no match. Try to return a useful error code.\n"; - OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n"; - OS << " return RetCode;\n\n"; - OS << " ErrorInfo = 0;\n"; - OS << " return Match_MissingFeature;\n"; +void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) { + formatted_raw_ostream FOS(OS); + PrinterLanguage const PLang = PrinterLLVM::getLanguage(); + PrinterLLVM *PI = nullptr; + switch (PLang) { + default: + PrintFatalNote( + "AsmMatcher backend does not support the selected ouput language."); + return; + case PRINTER_LANG_CPP: + PI = new PrinterLLVM(FOS); + break; + case PRINTER_LANG_CAPSTONE_C: + PI = new PrinterCapstone(FOS); + break; } - OS << "}\n\n"; - - if (!Info.OperandMatchInfo.empty()) - emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, - MaxMnemonicIndex, FeatureBitsets.size(), - HasMnemonicFirst, *AsmParser); - - OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; - - OS << "\n#ifdef GET_MNEMONIC_SPELL_CHECKER\n"; - OS << "#undef GET_MNEMONIC_SPELL_CHECKER\n\n"; - - emitMnemonicSpellChecker(OS, Target, VariantCount); - OS << "#endif // GET_MNEMONIC_SPELL_CHECKER\n\n"; - - OS << "\n#ifdef GET_MNEMONIC_CHECKER\n"; - OS << "#undef GET_MNEMONIC_CHECKER\n\n"; - - emitMnemonicChecker(OS, Target, VariantCount, - HasMnemonicFirst, HasMnemonicAliases); - - OS << "#endif // GET_MNEMONIC_CHECKER\n\n"; + AsmMatcherEmitter(RK, *PI).run(); + delete PI; +} } -static TableGen::Emitter::OptClass - X("gen-asm-matcher", "Generate assembly instruction matcher"); +static TableGen::Emitter::Opt + X("gen-asm-matcher", EmitAsmMatcher, "Generate assembly instruction matcher"); diff --git a/llvm/utils/TableGen/AsmMatcherEmitterTypes.h b/llvm/utils/TableGen/AsmMatcherEmitterTypes.h new file mode 100644 index 000000000000..5da09a0c1d93 --- /dev/null +++ b/llvm/utils/TableGen/AsmMatcherEmitterTypes.h @@ -0,0 +1,480 @@ +//===----- AsmMatcherEmitterTypes.h - Asm Matcher Types -*- 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 +// +//===-----------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_ASMMATCHEREMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_ASMMATCHEREMITTERTYPES_H + +#include "CodeGenInstAlias.h" +#include "CodeGenInstruction.h" +#include "CodeGenRegisters.h" +#include "CodeGenTarget.h" +#include "SubtargetFeatureInfo.h" +#include "Types.h" +#include "llvm/ADT/CachedHashString.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/StringToOffsetTable.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +#include +#include + +using namespace llvm; + +class AsmMatcherInfo; + +// Register sets are used as keys in some second-order sets TableGen creates +// when generating its data structures. This means that the order of two +// RegisterSets can be seen in the outputted AsmMatcher tables occasionally, and +// can even affect compiler output (at least seen in diagnostics produced when +// all matches fail). So we use a type that sorts them consistently. +typedef std::set RegisterSet; + +/// ClassInfo - Helper class for storing the information about a particular +/// class of operands which can be matched. +struct ClassInfo { + enum ClassInfoKind { + /// Invalid kind, for use as a sentinel value. + Invalid = 0, + + /// The class for a particular token. + Token, + + /// The (first) register class, subsequent register classes are + /// RegisterClass0+1, and so on. + RegisterClass0, + + /// The (first) user defined class, subsequent user defined classes are + /// UserClass0+1, and so on. + UserClass0 = 1 << 16 + }; + + /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + + /// N) for the Nth user defined class. + unsigned Kind; + + /// SuperClasses - The super classes of this class. Note that for simplicities + /// sake user operands only record their immediate super class, while register + /// operands include all superclasses. + std::vector SuperClasses; + + /// Name - The full class name, suitable for use in an enum. + std::string Name; + + /// ClassName - The unadorned generic name for this class (e.g., Token). + std::string ClassName; + + /// ValueName - The name of the value this class represents; for a token this + /// is the literal token string, for an operand it is the TableGen class (or + /// empty if this is a derived class). + std::string ValueName; + + /// PredicateMethod - The name of the operand method to test whether the + /// operand matches this class; this is not valid for Token or register kinds. + std::string PredicateMethod; + + /// RenderMethod - The name of the operand method to add this operand to an + /// MCInst; this is not valid for Token or register kinds. + std::string RenderMethod; + + /// ParserMethod - The name of the operand method to do a target specific + /// parsing on the operand. + std::string ParserMethod; + + /// For register classes: the records for all the registers in this class. + RegisterSet Registers; + + /// For custom match classes: the diagnostic kind for when the predicate + /// fails. + std::string DiagnosticType; + + /// For custom match classes: the diagnostic string for when the predicate + /// fails. + std::string DiagnosticString; + + /// Is this operand optional and not always required. + bool IsOptional; + + /// DefaultMethod - The name of the method that returns the default operand + /// for optional operand + std::string DefaultMethod; + +public: + /// isRegisterClass() - Check if this is a register class. + bool isRegisterClass() const { + return Kind >= RegisterClass0 && Kind < UserClass0; + } + + /// isUserClass() - Check if this is a user defined class. + bool isUserClass() const { return Kind >= UserClass0; } + + /// isRelatedTo - Check whether this class is "related" to \p RHS. Classes + /// are related if they are in the same class hierarchy. + bool isRelatedTo(const ClassInfo &RHS) const; + + /// isSubsetOf - Test whether this class is a subset of \p RHS. + bool isSubsetOf(const ClassInfo &RHS) const; + + int getTreeDepth() const; + + const ClassInfo *findRoot() const; + + /// Compare two classes. This does not produce a total ordering, but does + /// guarantee that subclasses are sorted before their parents, and that the + /// ordering is transitive. + bool operator<(const ClassInfo &RHS) const; +}; + +class AsmVariantInfo { +public: + StringRef RegisterPrefix; + StringRef TokenizingCharacters; + StringRef SeparatorCharacters; + StringRef BreakCharacters; + StringRef Name; + int AsmVariantNo; +}; + +/// MatchableInfo - Helper class for storing the necessary information for an +/// instruction or alias which is capable of being matched. +struct MatchableInfo { + struct AsmOperand { + /// Token - This is the token that the operand came from. + StringRef Token; + + /// The unique class instance this operand should match. + ClassInfo *Class; + + /// The operand name this is, if anything. + StringRef SrcOpName; + + /// The operand name this is, before renaming for tied operands. + StringRef OrigSrcOpName; + + /// The suboperand index within SrcOpName, or -1 for the entire operand. + int SubOpIdx; + + /// Whether the token is "isolated", i.e., it is preceded and followed + /// by separators. + bool IsIsolatedToken; + + /// Register record if this token is singleton register. + Record *SingletonReg; + + explicit AsmOperand(bool IsIsolatedToken, StringRef T) + : Token(T), Class(nullptr), SubOpIdx(-1), + IsIsolatedToken(IsIsolatedToken), SingletonReg(nullptr) {} + }; + + /// ResOperand - This represents a single operand in the result instruction + /// generated by the match. In cases (like addressing modes) where a single + /// assembler operand expands to multiple MCOperands, this represents the + /// single assembler operand, not the MCOperand. + struct ResOperand { + enum { + /// RenderAsmOperand - This represents an operand result that is + /// generated by calling the render method on the assembly operand. The + /// corresponding AsmOperand is specified by AsmOperandNum. + RenderAsmOperand, + + /// TiedOperand - This represents a result operand that is a duplicate of + /// a previous result operand. + TiedOperand, + + /// ImmOperand - This represents an immediate value that is dumped into + /// the operand. + ImmOperand, + + /// RegOperand - This represents a fixed register that is dumped in. + RegOperand + } Kind; + + /// Tuple containing the index of the (earlier) result operand that should + /// be copied from, as well as the indices of the corresponding (parsed) + /// operands in the asm string. + struct TiedOperandsTuple { + unsigned ResOpnd; + unsigned SrcOpnd1Idx; + unsigned SrcOpnd2Idx; + }; + + union { + /// This is the operand # in the AsmOperands list that this should be + /// copied from. + unsigned AsmOperandNum; + + /// Description of tied operands. + TiedOperandsTuple TiedOperands; + + /// ImmVal - This is the immediate value added to the instruction. + int64_t ImmVal; + + /// Register - This is the register record. + Record *Register; + }; + + /// MINumOperands - The number of MCInst operands populated by this + /// operand. + unsigned MINumOperands; + + static ResOperand getRenderedOp(unsigned AsmOpNum, unsigned NumOperands) { + ResOperand X; + X.Kind = RenderAsmOperand; + X.AsmOperandNum = AsmOpNum; + X.MINumOperands = NumOperands; + return X; + } + + static ResOperand getTiedOp(unsigned TiedOperandNum, unsigned SrcOperand1, + unsigned SrcOperand2) { + ResOperand X; + X.Kind = TiedOperand; + X.TiedOperands = { TiedOperandNum, SrcOperand1, SrcOperand2 }; + X.MINumOperands = 1; + return X; + } + + static ResOperand getImmOp(int64_t Val) { + ResOperand X; + X.Kind = ImmOperand; + X.ImmVal = Val; + X.MINumOperands = 1; + return X; + } + + static ResOperand getRegOp(Record *Reg) { + ResOperand X; + X.Kind = RegOperand; + X.Register = Reg; + X.MINumOperands = 1; + return X; + } + }; + + /// AsmVariantID - Target's assembly syntax variant no. + int AsmVariantID; + + /// AsmString - The assembly string for this instruction (with variants + /// removed), e.g. "movsx $src, $dst". + std::string AsmString; + + /// TheDef - This is the definition of the instruction or InstAlias that this + /// matchable came from. + Record *const TheDef; + + /// DefRec - This is the definition that it came from. + PointerUnion DefRec; + + const CodeGenInstruction *getResultInst() const { + if (isa(DefRec)) + return cast(DefRec); + return cast(DefRec)->ResultInst; + } + + /// ResOperands - This is the operand list that should be built for the result + /// MCInst. + SmallVector ResOperands; + + /// Mnemonic - This is the first token of the matched instruction, its + /// mnemonic. + StringRef Mnemonic; + + /// AsmOperands - The textual operands that this instruction matches, + /// annotated with a class and where in the OperandList they were defined. + /// This directly corresponds to the tokenized AsmString after the mnemonic is + /// removed. + SmallVector AsmOperands; + + /// Predicates - The required subtarget features to match this instruction. + SmallVector RequiredFeatures; + + /// ConversionFnKind - The enum value which is passed to the generated + /// convertToMCInst to convert parsed operands into an MCInst for this + /// function. + std::string ConversionFnKind; + + /// If this instruction is deprecated in some form. + bool HasDeprecation = false; + + /// If this is an alias, this is use to determine whether or not to using + /// the conversion function defined by the instruction's AsmMatchConverter + /// or to use the function generated by the alias. + bool UseInstAsmMatchConverter; + + MatchableInfo(const CodeGenInstruction &CGI) + : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef), DefRec(&CGI), + UseInstAsmMatchConverter(true) { + } + + MatchableInfo(std::unique_ptr Alias) + : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef), + DefRec(Alias.release()), + UseInstAsmMatchConverter( + TheDef->getValueAsBit("UseInstAsmMatchConverter")) { + } + + // Could remove this and the dtor if PointerUnion supported unique_ptr + // elements with a dynamic failure/assertion (like the one below) in the case + // where it was copied while being in an owning state. + MatchableInfo(const MatchableInfo &RHS) + : AsmVariantID(RHS.AsmVariantID), AsmString(RHS.AsmString), + TheDef(RHS.TheDef), DefRec(RHS.DefRec), ResOperands(RHS.ResOperands), + Mnemonic(RHS.Mnemonic), AsmOperands(RHS.AsmOperands), + RequiredFeatures(RHS.RequiredFeatures), + ConversionFnKind(RHS.ConversionFnKind), + HasDeprecation(RHS.HasDeprecation), + UseInstAsmMatchConverter(RHS.UseInstAsmMatchConverter) { + assert(!isa(DefRec)); + } + + ~MatchableInfo() { + delete dyn_cast_if_present(DefRec); + } + + // Two-operand aliases clone from the main matchable, but mark the second + // operand as a tied operand of the first for purposes of the assembler. + void formTwoOperandAlias(StringRef Constraint); + + void initialize(const AsmMatcherInfo &Info, + SmallPtrSetImpl &SingletonRegisters, + AsmVariantInfo const &Variant, + bool HasMnemonicFirst); + + /// validate - Return true if this matchable is a valid thing to match against + /// and perform a bunch of validity checking. + bool validate(StringRef CommentDelimiter, bool IsAlias) const; + + /// findAsmOperand - Find the AsmOperand with the specified name and + /// suboperand index. + int findAsmOperand(StringRef N, int SubOpIdx) const; + + /// findAsmOperandNamed - Find the first AsmOperand with the specified name. + /// This does not check the suboperand index. + int findAsmOperandNamed(StringRef N, int LastIdx = -1) const; + + int findAsmOperandOriginallyNamed(StringRef N) const; + + void buildInstructionResultOperands(); + void buildAliasResultOperands(bool AliasConstraintsAreChecked); + + /// operator< - Compare two matchables. + bool operator<(const MatchableInfo &RHS) const; + + /// couldMatchAmbiguouslyWith - Check whether this matchable could + /// ambiguously match the same set of operands as \p RHS (without being a + /// strictly superior match). + bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) const; + + void dump() const; + + void tokenizeAsmString(AsmMatcherInfo const &Info, + AsmVariantInfo const &Variant); +private: + void addAsmOperand(StringRef Token, bool IsIsolatedToken = false); +}; + +struct OperandMatchEntry { + unsigned OperandMask; + const MatchableInfo *MI; + ClassInfo *CI; + + static OperandMatchEntry create(const MatchableInfo *mi, ClassInfo *ci, + unsigned opMask); +}; + +class AsmMatcherInfo { +public: + /// Tracked Records + RecordKeeper &Records; + + /// The tablegen AsmParser record. + Record *AsmParser; + + /// Target - The target information. + CodeGenTarget &Target; + + /// The classes which are needed for matching. + std::forward_list Classes; + + /// The information on the matchables to match. + std::vector> Matchables; + + /// Info for custom matching operands by user defined methods. + std::vector OperandMatchInfo; + + /// Map of Register records to their class information. + typedef std::map RegisterClassesTy; + RegisterClassesTy RegisterClasses; + + /// Map of Predicate records to their subtarget information. + std::map SubtargetFeatures; + + /// Map of AsmOperandClass records to their class information. + std::map AsmOperandClasses; + + /// Map of RegisterClass records to their class information. + std::map RegisterClassClasses; + +private: + /// Map of token to class information which has already been constructed. + std::map TokenClasses; + +private: + /// getTokenClass - Lookup or create the class for the given token. + ClassInfo *getTokenClass(StringRef Token); + + /// getOperandClass - Lookup or create the class for the given operand. + ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI, + int SubOpIdx); + ClassInfo *getOperandClass(Record *Rec, int SubOpIdx); + + /// buildRegisterClasses - Build the ClassInfo* instances for register + /// classes. + void buildRegisterClasses(SmallPtrSetImpl &SingletonRegisters); + + /// buildOperandClasses - Build the ClassInfo* instances for user defined + /// operand classes. + void buildOperandClasses(); + + void buildInstructionOperandReference(MatchableInfo *II, StringRef OpName, + unsigned AsmOpIdx); + void buildAliasOperandReference(MatchableInfo *II, StringRef OpName, + MatchableInfo::AsmOperand &Op); + +public: + AsmMatcherInfo(Record *AsmParser, CodeGenTarget &Target, + RecordKeeper &Records); + + /// Construct the various tables used during matching. + void buildInfo(); + + /// buildOperandMatchInfo - Build the necessary information to handle user + /// defined operand parsing methods. + void buildOperandMatchInfo(); + + /// getSubtargetFeature - Lookup or create the subtarget feature info for the + /// given operand. + const SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const; + + RecordKeeper &getRecords() const { return Records; } + + bool hasOptionalOperands() const; +}; + +#endif // LLVM_UTILS_TABLEGEN_ASMMATCHEREMITTERTYPES_H diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index e0cd5fad3254..0e963ff57231 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -16,6 +16,7 @@ #include "CodeGenInstruction.h" #include "CodeGenRegisters.h" #include "CodeGenTarget.h" +#include "Printer.h" #include "SequenceToOffsetTable.h" #include "Types.h" #include "llvm/ADT/ArrayRef.h" @@ -57,24 +58,27 @@ namespace { class AsmWriterEmitter { RecordKeeper &Records; CodeGenTarget Target; + PrinterLLVM &PI; ArrayRef NumberedInstructions; std::vector Instructions; public: - AsmWriterEmitter(RecordKeeper &R); + AsmWriterEmitter(RecordKeeper &R, PrinterLLVM &PI); - void run(raw_ostream &o); + void run(); private: void EmitGetMnemonic( - raw_ostream &o, std::vector> &TableDrivenOperandPrinters, unsigned &BitsLeft, unsigned &AsmStrBits); void EmitPrintInstruction( - raw_ostream &o, std::vector> &TableDrivenOperandPrinters, unsigned &BitsLeft, unsigned &AsmStrBits); - void EmitGetRegisterName(raw_ostream &o); - void EmitPrintAliasInstruction(raw_ostream &O); + void EmitInstructions(std::vector &Insts, + bool PassSubtarget); + void EmitGetRegisterName(); + void EmitRegisterNameString(StringRef AltName, + const std::deque &Registers); + void EmitPrintAliasInstruction(); void FindUniqueOperandCommands(std::vector &UOC, std::vector> &InstIdxs, @@ -84,30 +88,10 @@ class AsmWriterEmitter { } // end anonymous namespace -static void PrintCases(std::vector> &OpsToPrint, raw_ostream &O, - bool PassSubtarget) { - O << " case " << OpsToPrint.back().first << ":"; - AsmWriterOperand TheOp = OpsToPrint.back().second; - OpsToPrint.pop_back(); - - // Check to see if any other operands are identical in this list, and if so, - // emit a case label for them. - for (unsigned i = OpsToPrint.size(); i != 0; --i) - if (OpsToPrint[i-1].second == TheOp) { - O << "\n case " << OpsToPrint[i-1].first << ":"; - OpsToPrint.erase(OpsToPrint.begin()+i-1); - } - - // Finally, emit the code. - O << "\n " << TheOp.getCode(PassSubtarget); - O << "\n break;\n"; -} - /// EmitInstructions - Emit the last instruction in the vector and any other /// instructions that are suitably similar to it. -static void EmitInstructions(std::vector &Insts, - raw_ostream &O, bool PassSubtarget) { +void AsmWriterEmitter::EmitInstructions(std::vector &Insts, + bool PassSubtarget) { AsmWriterInst FirstInst = Insts.back(); Insts.pop_back(); @@ -127,39 +111,11 @@ static void EmitInstructions(std::vector &Insts, } } } + PI.asmWriterEmitInstruction(FirstInst, + SimilarInsts, + DifferingOperand, + PassSubtarget); - O << " case " << FirstInst.CGI->Namespace << "::" - << FirstInst.CGI->TheDef->getName() << ":\n"; - for (const AsmWriterInst &AWI : SimilarInsts) - O << " case " << AWI.CGI->Namespace << "::" - << AWI.CGI->TheDef->getName() << ":\n"; - for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) { - if (i != DifferingOperand) { - // If the operand is the same for all instructions, just print it. - O << " " << FirstInst.Operands[i].getCode(PassSubtarget); - } else { - // If this is the operand that varies between all of the instructions, - // emit a switch for just this operand now. - O << " switch (MI->getOpcode()) {\n"; - O << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; - std::vector> OpsToPrint; - OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace.str() + "::" + - FirstInst.CGI->TheDef->getName().str(), - FirstInst.Operands[i])); - - for (const AsmWriterInst &AWI : SimilarInsts) { - OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace.str()+"::" + - AWI.CGI->TheDef->getName().str(), - AWI.Operands[i])); - } - std::reverse(OpsToPrint.begin(), OpsToPrint.end()); - while (!OpsToPrint.empty()) - PrintCases(OpsToPrint, O, PassSubtarget); - O << " }"; - } - O << "\n"; - } - O << " break;\n"; } void AsmWriterEmitter:: @@ -294,21 +250,16 @@ static void UnescapeAliasString(std::string &Str) { } void AsmWriterEmitter::EmitGetMnemonic( - raw_ostream &O, std::vector> &TableDrivenOperandPrinters, unsigned &BitsLeft, unsigned &AsmStrBits) { Record *AsmWriter = Target.getAsmWriter(); StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); - O << "/// getMnemonic - This method is automatically generated by " - "tablegen\n" - "/// from the instruction set description.\n" - "std::pair " - << Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n"; + PI.asmWriterEmitGetMnemonic(Target.getName().str(), ClassName); // Build an aggregate string, and build a table of offsets into it. - SequenceToOffsetTable StringTable; + SequenceToOffsetTable StringTable(PrinterLLVM::getLanguage(), true); /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. @@ -401,133 +352,28 @@ void AsmWriterEmitter::EmitGetMnemonic( } // Emit the string table itself. - StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]"); - - // Emit the lookup tables in pieces to minimize wasted bytes. - unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8; - unsigned Table = 0, Shift = 0; - SmallString<128> BitsString; - raw_svector_ostream BitsOS(BitsString); - // If the total bits is more than 32-bits we need to use a 64-bit type. - BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) - << "_t Bits = 0;\n"; - while (BytesNeeded != 0) { - // Figure out how big this table section needs to be, but no bigger than 4. - unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u); - BytesNeeded -= TableSize; - TableSize *= 8; // Convert to bits; - uint64_t Mask = (1ULL << TableSize) - 1; - O << " static const uint" << TableSize << "_t OpInfo" << Table - << "[] = {\n"; - for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { - O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// " - << NumberedInstructions[i]->TheDef->getName() << "\n"; - } - O << " };\n\n"; - // Emit string to combine the individual table lookups. - BitsOS << " Bits |= "; - // If the total bits is more than 32-bits we need to use a 64-bit type. - if (BitsLeft < (OpcodeInfoBits - 32)) - BitsOS << "(uint64_t)"; - BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n"; - // Prepare the shift for the next iteration and increment the table count. - Shift += TableSize; - ++Table; - } - - O << " // Emit the opcode for the instruction.\n"; - O << BitsString; - - // Make sure we don't return an invalid pointer if bits is 0 - O << " if (Bits == 0)\n" - " return {nullptr, Bits};\n"; - - // Return mnemonic string and bits. - O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1 - << ")-1, Bits};\n\n"; - - O << "}\n"; + PI.asmWriterEmitAsmStrs(StringTable); + PI.asmWriterEmitMnemonicDecodeTable(OpcodeInfoBits, + BitsLeft, + AsmStrBits, + NumberedInstructions, + OpcodeInfo); } /// EmitPrintInstruction - Generate the code for the "printInstruction" method /// implementation. Destroys all instances of AsmWriterInst information, by /// clearing the Instructions vector. void AsmWriterEmitter::EmitPrintInstruction( - raw_ostream &O, std::vector> &TableDrivenOperandPrinters, unsigned &BitsLeft, unsigned &AsmStrBits) { - const unsigned OpcodeInfoBits = 64; Record *AsmWriter = Target.getAsmWriter(); StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); - // This function has some huge switch statements that causing excessive - // compile time in LLVM profile instrumenation build. This print function - // usually is not frequently called in compilation. Here we disable the - // profile instrumenation for this function. - O << "/// printInstruction - This method is automatically generated by " - "tablegen\n" - "/// from the instruction set description.\n" - "LLVM_NO_PROFILE_INSTRUMENT_FUNCTION\n" - "void " - << Target.getName() << ClassName - << "::printInstruction(const MCInst *MI, uint64_t Address, " - << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") - << "raw_ostream &O) {\n"; - - // Emit the initial tab character. - O << " O << \"\\t\";\n\n"; - - // Emit the starting string. - O << " auto MnemonicInfo = getMnemonic(MI);\n\n"; - O << " O << MnemonicInfo.first;\n\n"; - - O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) - << "_t Bits = MnemonicInfo.second;\n" - << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"; - - // Output the table driven operand information. - BitsLeft = OpcodeInfoBits-AsmStrBits; - for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) { - std::vector &Commands = TableDrivenOperandPrinters[i]; - - // Compute the number of bits we need to represent these cases, this is - // ceil(log2(numentries)). - unsigned NumBits = Log2_32_Ceil(Commands.size()); - assert(NumBits <= BitsLeft && "consistency error"); - - // Emit code to extract this field from Bits. - O << "\n // Fragment " << i << " encoded into " << NumBits - << " bits for " << Commands.size() << " unique commands.\n"; - - if (Commands.size() == 2) { - // Emit two possibilitys with if/else. - O << " if ((Bits >> " - << (OpcodeInfoBits-BitsLeft) << ") & " - << ((1 << NumBits)-1) << ") {\n" - << Commands[1] - << " } else {\n" - << Commands[0] - << " }\n\n"; - } else if (Commands.size() == 1) { - // Emit a single possibility. - O << Commands[0] << "\n\n"; - } else { - O << " switch ((Bits >> " - << (OpcodeInfoBits-BitsLeft) << ") & " - << ((1 << NumBits)-1) << ") {\n" - << " default: llvm_unreachable(\"Invalid command number.\");\n"; - - // Print out all the cases. - for (unsigned j = 0, e = Commands.size(); j != e; ++j) { - O << " case " << j << ":\n"; - O << Commands[j]; - O << " break;\n"; - } - O << " }\n\n"; - } - BitsLeft -= NumBits; - } + PI.asmWriterEmitPrintInstruction(Target.getName().str(), + TableDrivenOperandPrinters, + BitsLeft, AsmStrBits, + ClassName, PassSubtarget); // Okay, delete instructions with no operand info left. llvm::erase_if(Instructions, @@ -544,21 +390,20 @@ void AsmWriterEmitter::EmitPrintInstruction( // instructions. if (!Instructions.empty()) { // Find the opcode # of inline asm. - O << " switch (MI->getOpcode()) {\n"; - O << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; + PI.asmWriterEmitInstrSwitch(); while (!Instructions.empty()) - EmitInstructions(Instructions, O, PassSubtarget); + EmitInstructions(Instructions, PassSubtarget); - O << " }\n"; + PI.asmWriterEmitCompoundClosure(2, true, false); } - O << "}\n"; + PI.asmWriterEmitCompoundClosure(0, true, false); } -static void -emitRegisterNameString(raw_ostream &O, StringRef AltName, - const std::deque &Registers) { - SequenceToOffsetTable StringTable; +void AsmWriterEmitter::EmitRegisterNameString( + StringRef AltName, + const std::deque &Registers) { + SequenceToOffsetTable StringTable(PrinterLLVM::getLanguage()); SmallVector AsmNames(Registers.size()); unsigned i = 0; for (const auto &Reg : Registers) { @@ -595,21 +440,11 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, } StringTable.layout(); - StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") + - AltName + "[]"); - - O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32) - << " RegAsmOffset" << AltName << "[] = {"; - for (unsigned i = 0, e = Registers.size(); i != e; ++i) { - if ((i % 14) == 0) - O << "\n "; - O << StringTable.get(AsmNames[i]) << ", "; - } - O << "\n };\n" - << "\n"; + PI.asmWriterEmitStringLiteralDef(StringTable, AltName); + PI.asmWriterEmitRegAsmOffsets(Registers.size(), AsmNames, StringTable, AltName); } -void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { +void AsmWriterEmitter::EmitGetRegisterName() { Record *AsmWriter = Target.getAsmWriter(); StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const auto &Registers = Target.getRegBank().getRegisters(); @@ -617,57 +452,18 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { bool hasAltNames = AltNameIndices.size() > 1; StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace"); - O << - "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" - "/// from the register set description. This returns the assembler name\n" - "/// for the specified register.\n" - "const char *" << Target.getName() << ClassName << "::"; - if (hasAltNames) - O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n"; - else - O << "getRegisterName(MCRegister Reg) {\n"; - O << " unsigned RegNo = Reg.id();\n" - << " assert(RegNo && RegNo < " << (Registers.size() + 1) - << " && \"Invalid register number!\");\n" - << "\n"; + PI.asmWriterEmitGetRegNameAssert(Target.getName().str(), + ClassName, + hasAltNames, + Registers.size()); if (hasAltNames) { for (const Record *R : AltNameIndices) - emitRegisterNameString(O, R->getName(), Registers); + EmitRegisterNameString(R->getName(), Registers); } else - emitRegisterNameString(O, "", Registers); + EmitRegisterNameString("", Registers); - if (hasAltNames) { - O << " switch(AltIdx) {\n" - << " default: llvm_unreachable(\"Invalid register alt name index!\");\n"; - for (const Record *R : AltNameIndices) { - StringRef AltName = R->getName(); - O << " case "; - if (!Namespace.empty()) - O << Namespace << "::"; - O << AltName << ":\n"; - if (R->isValueUnset("FallbackRegAltNameIndex")) - O << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName - << "[RegNo-1]) &&\n" - << " \"Invalid alt name index for register!\");\n"; - else { - O << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName - << "[RegNo-1]))\n" - << " return getRegisterName(RegNo, "; - if (!Namespace.empty()) - O << Namespace << "::"; - O << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n"; - } - O << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName - << "[RegNo-1];\n"; - } - O << " }\n"; - } else { - O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n" - << " \"Invalid alt name index for register!\");\n" - << " return AsmStrs+RegAsmOffset[RegNo-1];\n"; - } - O << "}\n"; + PI.asmWriterEmitAltIdxSwitch(hasAltNames, AltNameIndices, Namespace); } namespace { @@ -804,11 +600,10 @@ struct AliasPriorityComparator { } // end anonymous namespace -void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { +void AsmWriterEmitter::EmitPrintAliasInstruction() { Record *AsmWriter = Target.getAsmWriter(); - O << "\n#ifdef PRINT_ALIAS_INSTR\n"; - O << "#undef PRINT_ALIAS_INSTR\n\n"; + PI.emitIncludeToggle("PRINT_ALIAS_INSTR", true); ////////////////////////////// // Gather information about aliases we need to print @@ -895,7 +690,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Ignore unchecked result operands. while (IAP.getCondCount() < MIOpNum) - IAP.addCond("AliasPatternCond::K_Ignore, 0"); + IAP.addCond(PI.asmWriterGetPatCondKIgnore()); const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i]; @@ -933,11 +728,11 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (R->isSubClassOf("RegisterOperand")) R = R->getValueAsDef("RegClass"); IAP.addCond(std::string( - formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID", + formatv(PI.asmWriterGetPatCondKRegClass(), Namespace, R->getName()))); } else { IAP.addCond(std::string(formatv( - "AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName)))); + PI.asmWriterGetPatCondKTiedReg(), IAP.getOpIndex(ROName)))); } } else { // Assume all printable operands are desired for now. This can be @@ -955,7 +750,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { break; // No conditions on this operand at all } IAP.addCond( - std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry))); + std::string(formatv(PI.asmWriterGetPatCondKCustom(), Entry))); } break; } @@ -968,19 +763,19 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { PrintFatalError("Matching an alias with an immediate out of the " "range of int32_t is not supported"); IAP.addCond(std::string( - formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32))); + formatv(PI.asmWriterGetPatCondKImm(), Imm32))); break; } case CodeGenInstAlias::ResultOperand::K_Reg: if (!CGA.ResultOperands[i].getRegister()) { IAP.addCond(std::string(formatv( - "AliasPatternCond::K_Reg, {0}::NoRegister", Namespace))); + PI.asmWriterGetPatCondKNoReg(), Namespace))); break; } StringRef Reg = CGA.ResultOperands[i].getRegister()->getName(); IAP.addCond(std::string( - formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg))); + formatv(PI.asmWriterGetPatCondKReg(), Namespace, Reg))); break; } @@ -1034,13 +829,13 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); IAP.addCond(std::string(formatv( - "AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "", + PI.asmWriterGetPatCondKFeature(), IsOr ? "Or" : "", IsNeg ? "Neg" : "", Namespace, Arg->getAsString()))); } // If an AssemblerPredicate with ors is used, note end of list should // these be combined. if (IsOr) - IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0"); + IAP.addCond(PI.asmWriterGetPatCondKEndOrFeature()); } IAPrinterMap[Aliases.first].push_back(std::move(IAP)); @@ -1051,15 +846,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Write out the printAliasInstr function ////////////////////////////// - std::string Header; - raw_string_ostream HeaderO(Header); - - HeaderO << "bool " << Target.getName() << ClassName - << "::printAliasInstr(const MCInst" - << " *MI, uint64_t Address, " - << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") - << "raw_ostream &OS) {\n"; - std::string PatternsForOpcode; raw_string_ostream OpcodeO(PatternsForOpcode); @@ -1104,15 +890,15 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { unsigned PatternStart = PatternCount; // Insert the pattern start and opcode in the pattern list for debugging. - PatternO << formatv(" // {0} - {1}\n", It->first, PatternStart); + PatternO << formatv(PI.asmWriterGetPatOpcStart(), It->first, PatternStart); for (IAPrinter *IAP : UniqueIAPs) { // Start each condition list with a comment of the resulting pattern that // we're trying to match. unsigned CondStart = CondCount; - CondO << formatv(" // {0} - {1}\n", IAP->getResult(), CondStart); + CondO << formatv(PI.asmWriterGetCondPatStart(), IAP->getResult(), CondStart); for (const auto &Cond : IAP->getConds()) - CondO << " {" << Cond << "},\n"; + CondO << PI.asmWriterGetCond(Cond); CondCount += IAP->getCondCount(); // After operands have been examined, re-encode the alias string with @@ -1128,167 +914,52 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } unsigned AsmStrOffset = Insertion.first->second; - PatternO << formatv(" {{{0}, {1}, {2}, {3} },\n", AsmStrOffset, + PatternO << formatv(PI.asmWriterGetPatternFormat(), AsmStrOffset, CondStart, IAP->getNumMIOps(), IAP->getCondCount()); ++PatternCount; } - OpcodeO << formatv(" {{{0}, {1}, {2} },\n", It->first, PatternStart, + OpcodeO << formatv(PI.asmWriterGetOpcodeFormat(), It->first, PatternStart, PatternCount - PatternStart); } if (OpcodeO.str().empty()) { - O << HeaderO.str(); - O << " return false;\n"; - O << "}\n\n"; - O << "#endif // PRINT_ALIAS_INSTR\n"; + PI.asmWriterEmitPrintAliasInstrHeader(Target.getName().str(), ClassName, PassSubtarget); + PI.asmWriterEmitPrintAliasInstrBodyRetFalse(); + PI.emitIncludeToggle("PRINT_ALIAS_INSTR", false, false); return; } // Forward declare the validation method if needed. if (!MCOpPredicates.empty()) - O << "static bool " << Target.getName() << ClassName - << "ValidateMCOperand(const MCOperand &MCOp,\n" - << " const MCSubtargetInfo &STI,\n" - << " unsigned PredicateIndex);\n"; - - O << HeaderO.str(); - O.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n"; - O << OpcodeO.str(); - O.indent(2) << "};\n\n"; - O.indent(2) << "static const AliasPattern Patterns[] = {\n"; - O << PatternO.str(); - O.indent(2) << "};\n\n"; - O.indent(2) << "static const AliasPatternCond Conds[] = {\n"; - O << CondO.str(); - O.indent(2) << "};\n\n"; - O.indent(2) << "static const char AsmStrings[] =\n"; - for (const auto &P : AsmStrings) { - O.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n"; - } - - O.indent(2) << ";\n\n"; - - // Assert that the opcode table is sorted. Use a static local constructor to - // ensure that the check only happens once on first run. - O << "#ifndef NDEBUG\n"; - O.indent(2) << "static struct SortCheck {\n"; - O.indent(2) << " SortCheck(ArrayRef OpToPatterns) {\n"; - O.indent(2) << " assert(std::is_sorted(\n"; - O.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n"; - O.indent(2) << " [](const PatternsForOpcode &L, const " - "PatternsForOpcode &R) {\n"; - O.indent(2) << " return L.Opcode < R.Opcode;\n"; - O.indent(2) << " }) &&\n"; - O.indent(2) << " \"tablegen failed to sort opcode patterns\");\n"; - O.indent(2) << " }\n"; - O.indent(2) << "} sortCheckVar(OpToPatterns);\n"; - O << "#endif\n\n"; - - O.indent(2) << "AliasMatchingData M {\n"; - O.indent(2) << " ArrayRef(OpToPatterns),\n"; - O.indent(2) << " ArrayRef(Patterns),\n"; - O.indent(2) << " ArrayRef(Conds),\n"; - O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n"; - if (MCOpPredicates.empty()) - O.indent(2) << " nullptr,\n"; - else - O.indent(2) << " &" << Target.getName() << ClassName << "ValidateMCOperand,\n"; - O.indent(2) << "};\n"; - - O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, " - << (PassSubtarget ? "&STI" : "nullptr") << ", M);\n"; - O.indent(2) << "if (!AsmString) return false;\n\n"; - - // Code that prints the alias, replacing the operands with the ones from the - // MCInst. - O << " unsigned I = 0;\n"; - O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; - O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; - O << " ++I;\n"; - O << " OS << '\\t' << StringRef(AsmString, I);\n"; - - O << " if (AsmString[I] != '\\0') {\n"; - O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n"; - O << " OS << '\\t';\n"; - O << " ++I;\n"; - O << " }\n"; - O << " do {\n"; - O << " if (AsmString[I] == '$') {\n"; - O << " ++I;\n"; - O << " if (AsmString[I] == (char)0xff) {\n"; - O << " ++I;\n"; - O << " int OpIdx = AsmString[I++] - 1;\n"; - O << " int PrintMethodIdx = AsmString[I++] - 1;\n"; - O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, "; - O << (PassSubtarget ? "STI, " : ""); - O << "OS);\n"; - O << " } else\n"; - O << " printOperand(MI, unsigned(AsmString[I++]) - 1, "; - O << (PassSubtarget ? "STI, " : ""); - O << "OS);\n"; - O << " } else {\n"; - O << " OS << AsmString[I++];\n"; - O << " }\n"; - O << " } while (AsmString[I] != '\\0');\n"; - O << " }\n\n"; - - O << " return true;\n"; - O << "}\n\n"; + PI.asmWriterEmitDeclValid(Target.getName().str(), ClassName); + + PI.asmWriterEmitPrintAliasInstrHeader(Target.getName().str(), + ClassName, + PassSubtarget); + PI.asmWriterEmitPrintAliasInstrBody(OpcodeO, + PatternO, + CondO, + AsmStrings, + MCOpPredicates, + Target.getName().str(), + ClassName, + PassSubtarget); ////////////////////////////// // Write out the printCustomAliasOperand function ////////////////////////////// - O << "void " << Target.getName() << ClassName << "::" - << "printCustomAliasOperand(\n" - << " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n" - << " unsigned PrintMethodIdx,\n" - << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "") - << " raw_ostream &OS) {\n"; - if (PrintMethods.empty()) - O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n"; - else { - O << " switch (PrintMethodIdx) {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown PrintMethod kind\");\n" - << " break;\n"; - - for (unsigned i = 0; i < PrintMethods.size(); ++i) { - O << " case " << i << ":\n" - << " " << PrintMethods[i].first << "(MI, " - << (PrintMethods[i].second ? "Address, " : "") << "OpIdx, " - << (PassSubtarget ? "STI, " : "") << "OS);\n" - << " break;\n"; - } - O << " }\n"; - } - O << "}\n\n"; - - if (!MCOpPredicates.empty()) { - O << "static bool " << Target.getName() << ClassName - << "ValidateMCOperand(const MCOperand &MCOp,\n" - << " const MCSubtargetInfo &STI,\n" - << " unsigned PredicateIndex) {\n" - << " switch (PredicateIndex) {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" - << " break;\n"; - - for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { - StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate"); - O << " case " << i + 1 << ": {\n" - << MCOpPred.data() << "\n" - << " }\n"; - } - O << " }\n" - << "}\n\n"; - } + PI.asmWriterEmitPrintAliasOp(Target.getName().str(), + ClassName, + PrintMethods, + PassSubtarget); - O << "#endif // PRINT_ALIAS_INSTR\n"; + PI.asmWriterEmitPrintMC(Target.getName().str(), ClassName, MCOpPredicates); + PI.emitIncludeToggle("PRINT_ALIAS_INSTR", false, false); } -AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { +AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R, PrinterLLVM &PI) : Records(R), Target(R), PI(PI) { Record *AsmWriter = Target.getAsmWriter(); unsigned Variant = AsmWriter->getValueAsInt("Variant"); @@ -1302,16 +973,34 @@ AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { } } -void AsmWriterEmitter::run(raw_ostream &O) { +void AsmWriterEmitter::run() { std::vector> TableDrivenOperandPrinters; unsigned BitsLeft = 0; unsigned AsmStrBits = 0; - emitSourceFileHeader("Assembly Writer Source Fragment", O, Records); - EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits); - EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits); - EmitGetRegisterName(O); - EmitPrintAliasInstruction(O); + + PI.asmWriterEmitSourceFileHeader(Records); + EmitGetMnemonic(TableDrivenOperandPrinters, BitsLeft, AsmStrBits); + EmitPrintInstruction(TableDrivenOperandPrinters, BitsLeft, AsmStrBits); + EmitGetRegisterName(); + EmitPrintAliasInstruction(); +} + +void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) { + CodeGenTarget CGTarget(RK); + PrinterLanguage const PL = PrinterLLVM::getLanguage(); + PrinterLLVM *PI; + + formatted_raw_ostream FOS(OS); + if (PL == PRINTER_LANG_CPP) { + PI = new PrinterLLVM(FOS, CGTarget.getName().str()); + } else if (PL == PRINTER_LANG_CAPSTONE_C) { + PI = new PrinterCapstone(FOS, CGTarget.getName().str()); + } else { + llvm_unreachable("AsmWriterEmitter does not support the given output language."); + } + AsmWriterEmitter(RK, *PI).run(); + delete PI; } -static TableGen::Emitter::OptClass - X("gen-asm-writer", "Generate assembly writer"); +static TableGen::Emitter::Opt X("gen-asm-writer", EmitAsmWriter, + "Generate instruction descriptions"); diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp index c9558593e142..6893f4c12c04 100644 --- a/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -12,25 +12,40 @@ #include "AsmWriterInst.h" #include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "Printer.h" #include "llvm/ADT/StringExtras.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include using namespace llvm; static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } std::string AsmWriterOperand::getCode(bool PassSubtarget) const { + bool LangCS = PrinterLLVM::getLanguage() == PRINTER_LANG_CAPSTONE_C; if (OperandType == isLiteralTextOperand) { - if (Str.size() == 1) - return "O << '" + Str + "';"; - return "O << \"" + Str + "\";"; + std::string Res; + if (Str.size() == 1) { + Res = LangCS ? "SStream_concat1(O, '" + Str + "');" : "O << '" + Str + "';"; + return Res; + } + + Res = LangCS ? "SStream_concat0(O, \"" + Str + "\");" : "O << \"" + Str + "\";"; + return Res; } if (OperandType == isLiteralStatementOperand) return Str; - std::string Result = Str + "(MI"; + PassSubtarget = LangCS ? false : PassSubtarget; + + std::string Result; + Result = Str; + + Result = Result + "(MI"; + if (PCRel) Result += ", Address"; if (MIOpNo != ~0U) diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index 0100bf345ec2..660d6e08509a 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -70,12 +70,15 @@ add_tablegen(llvm-tblgen LLVM OptParserEmitter.cpp OptRSTEmitter.cpp PredicateExpander.cpp + PrinterLLVM.cpp + PrinterCapstone.cpp PseudoLoweringEmitter.cpp CompressInstEmitter.cpp MacroFusionPredicatorEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SearchableTableEmitter.cpp + StringMatcher.cpp SubtargetEmitter.cpp SubtargetFeatureInfo.cpp TableGen.cpp diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp index fd375735dfd2..0980971c73c9 100644 --- a/llvm/utils/TableGen/CodeGenMapTable.cpp +++ b/llvm/utils/TableGen/CodeGenMapTable.cpp @@ -188,9 +188,12 @@ class MapTableEmitter { std::vector KeyInstrVec; DenseMap > MapTable; + // Simple flag for Capstone C files. + bool EmitC; + public: - MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec): - Target(Target), InstrMapDesc(IMRec) { + MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec, bool EmitC = false): + Target(Target), InstrMapDesc(IMRec), EmitC(EmitC) { const std::string &FilterClass = InstrMapDesc.getFilterClass(); InstrDefs = Records.getAllDerivedDefinitions(FilterClass); } @@ -210,8 +213,8 @@ class MapTableEmitter { void buildMapTable(); void emitBinSearch(raw_ostream &OS, unsigned TableSize); - void emitTablesWithFunc(raw_ostream &OS); - unsigned emitBinSearchTable(raw_ostream &OS); + void emitTablesWithFunc(raw_ostream &OS, bool EmitC); + unsigned emitBinSearchTable(raw_ostream &OS, bool EmitC); // Lookup functions to query binary search tables. void emitMapFuncBody(raw_ostream &OS, unsigned TableSize); @@ -358,7 +361,7 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr, // Binary search is used for locating instructions in the table. //===----------------------------------------------------------------------===// -unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { +unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS, bool EmitC) { ArrayRef NumberedInstructions = Target.getInstructionsByEnumValue(); @@ -367,6 +370,7 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { unsigned NumCol = ValueCols.size(); unsigned TotalNumInstr = NumberedInstructions.size(); unsigned TableSize = 0; + std::string NSSep = (EmitC ? "_" : "::"); OS << "static const uint16_t "<getName(); } else { OutStr += ", (uint16_t)-1U";} } if (RelExists) { - OS << " { " << Namespace << "::" << CurInstr->getName(); + OS << " { " << Namespace << NSSep << CurInstr->getName(); OS << OutStr <<" },\n"; TableSize++; } } } if (!TableSize) { - OS << " { " << Namespace << "::" << "INSTRUCTION_LIST_END, "; - OS << Namespace << "::" << "INSTRUCTION_LIST_END }"; + OS << " { " << Namespace << NSSep << "INSTRUCTION_LIST_END, "; + OS << Namespace << NSSep << "INSTRUCTION_LIST_END }"; } OS << "}; // End of " << InstrMapDesc.getName() << "Table\n\n"; return TableSize; @@ -469,7 +473,7 @@ void MapTableEmitter::emitMapFuncBody(raw_ostream &OS, // Emit relation tables and the functions to query them. //===----------------------------------------------------------------------===// -void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) { +void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS, bool EmitC) { // Emit function name and the input parameters : mostly opcode value of the // current instruction. However, if a table has multiple columns (more than 2 @@ -478,7 +482,8 @@ void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) { ListInit *ColFields = InstrMapDesc.getColFields(); const std::vector &ValueCols = InstrMapDesc.getValueCols(); - OS << "// "<< InstrMapDesc.getName() << "\nLLVM_READONLY\n"; + OS << "// "<< InstrMapDesc.getName() << "\n"; + OS << (EmitC ? "" : "LLVM_READONLY\n"); OS << "int "<< InstrMapDesc.getName() << "(uint16_t Opcode"; if (ValueCols.size() > 1) { for (Init *CF : ColFields->getValues()) { @@ -489,7 +494,7 @@ void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) { OS << ") {\n"; // Emit map table. - unsigned TableSize = emitBinSearchTable(OS); + unsigned TableSize = emitBinSearchTable(OS, EmitC); // Emit rest of the function body. emitMapFuncBody(OS, TableSize); @@ -563,7 +568,7 @@ namespace llvm { // between instructions. These relations are emitted as a tables along with the // functions to query them. //===----------------------------------------------------------------------===// -void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { +void EmitMapTable(RecordKeeper &Records, raw_ostream &OS, bool EmitC = false) { CodeGenTarget Target(Records); StringRef NameSpace = Target.getInstNamespace(); std::vector InstrMapVec; @@ -574,8 +579,10 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { OS << "#ifdef GET_INSTRMAP_INFO\n"; OS << "#undef GET_INSTRMAP_INFO\n"; - OS << "namespace llvm {\n\n"; - OS << "namespace " << NameSpace << " {\n\n"; + if (!EmitC) { + OS << "namespace llvm {\n\n"; + OS << "namespace " << NameSpace << " {\n\n"; + } // Emit coulumn field names and their values as enums. emitEnums(OS, Records); @@ -596,10 +603,12 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { IMap.buildMapTable(); // Emit map tables and the functions to query them. - IMap.emitTablesWithFunc(OS); + IMap.emitTablesWithFunc(OS, EmitC); + } + if (!EmitC) { + OS << "} // end namespace " << NameSpace << "\n"; + OS << "} // end namespace llvm\n"; } - OS << "} // end namespace " << NameSpace << "\n"; - OS << "} // end namespace llvm\n"; OS << "#endif // GET_INSTRMAP_INFO\n\n"; } diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index 37fa30349eea..a8cc6961eacb 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -17,6 +17,7 @@ #include "CodeGenInstruction.h" #include "CodeGenRegisters.h" #include "CodeGenSchedule.h" +#include "Printer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" @@ -263,6 +264,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::Untyped: return "MVT::Untyped"; case MVT::funcref: return "MVT::funcref"; case MVT::externref: return "MVT::externref"; + case MVT::INVALID_SIMPLE_VALUE_TYPE: return "MVT::INVALID_SIMPLE_VALUE_TYPE"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } // clang-format on @@ -277,7 +279,11 @@ std::string llvm::getQualifiedName(const Record *R) { Namespace = std::string(R->getValueAsString("Namespace")); if (Namespace.empty()) return std::string(R->getName()); - return Namespace + "::" + R->getName().str(); + + if (PrinterLLVM::getLanguage() == PRINTER_LANG_CAPSTONE_C) + return Namespace + "_" + R->getName().str(); + else + return Namespace + "::" + R->getName().str(); } diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 607f19653c7a..d3ff76ea5f49 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -14,8 +14,10 @@ #include "CodeGenHwModes.h" #include "CodeGenInstruction.h" #include "CodeGenTarget.h" +#include "DecoderEmitterTypes.h" #include "InfoByHwMode.h" #include "TableGenBackends.h" +#include "Printer.h" #include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" @@ -58,117 +60,38 @@ STATISTIC(NumInstructions, "Number of instructions considered"); STATISTIC(NumEncodingsSupported, "Number of encodings supported"); STATISTIC(NumEncodingsOmitted, "Number of encodings omitted"); -struct EncodingField { - unsigned Base, Width, Offset; - EncodingField(unsigned B, unsigned W, unsigned O) - : Base(B), Width(W), Offset(O) { } -}; - -struct OperandInfo { - std::vector Fields; - std::string Decoder; - bool HasCompleteDecoder; - uint64_t InitValue; - - OperandInfo(std::string D, bool HCD) - : Decoder(std::move(D)), HasCompleteDecoder(HCD), InitValue(0) {} - - void addField(unsigned Base, unsigned Width, unsigned Offset) { - Fields.push_back(EncodingField(Base, Width, Offset)); - } - - unsigned numFields() const { return Fields.size(); } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return Fields.begin(); } - const_iterator end() const { return Fields.end(); } -}; - -typedef std::vector DecoderTable; -typedef uint32_t DecoderFixup; -typedef std::vector FixupList; -typedef std::vector FixupScopeList; -typedef SmallSetVector PredicateSet; -typedef SmallSetVector DecoderSet; -struct DecoderTableInfo { - DecoderTable Table; - FixupScopeList FixupStack; - PredicateSet Predicates; - DecoderSet Decoders; -}; - -struct EncodingAndInst { - const Record *EncodingDef; - const CodeGenInstruction *Inst; - StringRef HwModeName; - - EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst, - StringRef HwModeName = "") - : EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {} -}; - -struct EncodingIDAndOpcode { - unsigned EncodingID; - unsigned Opcode; - - EncodingIDAndOpcode() : EncodingID(0), Opcode(0) {} - EncodingIDAndOpcode(unsigned EncodingID, unsigned Opcode) - : EncodingID(EncodingID), Opcode(Opcode) {} -}; - -raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) { - if (Value.EncodingDef != Value.Inst->TheDef) - OS << Value.EncodingDef->getName() << ":"; - OS << Value.Inst->TheDef->getName(); - return OS; -} - class DecoderEmitter { RecordKeeper &RK; + const PrinterLLVM &PI; std::vector NumberedEncodings; + ArrayRef NumberedInstructions; + DenseMap IndexOfInstruction; + // The opcode map. + // It maps the DecoderNamespace (e.g. ARM Thumb16) and instruction sizes + // to the encodings which belong into this subset. + std::map, std::vector> + OpcMap; + std::map> Operands; + std::vector InstrLen; + public: - DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace) - : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)) {} - - // Emit the decoder state machine table. - void emitTable(formatted_raw_ostream &o, DecoderTable &Table, - unsigned Indentation, unsigned BitWidth, - StringRef Namespace) const; - void emitInstrLenTable(formatted_raw_ostream &OS, - std::vector &InstrLen) const; - void emitPredicateFunction(formatted_raw_ostream &OS, - PredicateSet &Predicates, - unsigned Indentation) const; - void emitDecoderFunction(formatted_raw_ostream &OS, - DecoderSet &Decoders, - unsigned Indentation) const; + // Defaults preserved here for documentation, even though they aren't + // strictly necessary given the way that this is currently being called. + DecoderEmitter(RecordKeeper &R, const PrinterLLVM &PI) + : RK(R), PI(PI), NumberedInstructions(nullptr), Target(R) {} + void retrieveHwModeEncodings(); + unsigned fillOpcMap(bool const IsVarLenInst); // run - Output the code emitter - void run(raw_ostream &o); + void run(); private: CodeGenTarget Target; - -public: - std::string PredicateNamespace; }; } // end anonymous namespace -// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system -// for a bit value. -// -// BIT_UNFILTERED is used as the init value for a filter position. It is used -// only for filter processings. -typedef enum { - BIT_TRUE, // '1' - BIT_FALSE, // '0' - BIT_UNSET, // '?' - BIT_UNFILTERED // unfiltered -} bit_value_t; - static bool ValueSet(bit_value_t V) { return (V == BIT_TRUE || V == BIT_FALSE); } @@ -341,16 +264,6 @@ class Filter { } // end anonymous namespace -// These are states of our finite state machines used in FilterChooser's -// filterProcessor() which produces the filter candidates to use. -typedef enum { - ATTR_NONE, - ATTR_FILTERED, - ATTR_ALL_SET, - ATTR_ALL_UNSET, - ATTR_MIXED -} bitAttr_t; - /// FilterChooser - FilterChooser chooses the best filter among a set of Filters /// in order to perform the decoding of instructions at the current level. /// @@ -372,12 +285,15 @@ class FilterChooser { protected: friend class Filter; + // The Printer to emit source code from. + const PrinterLLVM &PI; + // Vector of codegen instructions to choose our filter. ArrayRef AllInstructions; // Vector of uid's for this filter chooser to work on. - // The first member of the pair is the opcode id being decoded, the second is - // the opcode id that should be emitted. + // The first member of the pair is the opcode id being decoded, the second + // is the opcode id that should be emitted. const std::vector &Opcodes; // Lookup table for the operand decoding of instructions. @@ -399,28 +315,25 @@ class FilterChooser { // Width of instructions unsigned BitWidth; - // Parent emitter - const DecoderEmitter *Emitter; - public: - FilterChooser(ArrayRef Insts, + FilterChooser(const PrinterLLVM &PI, ArrayRef Insts, const std::vector &IDs, const std::map> &Ops, - unsigned BW, const DecoderEmitter *E) - : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), + unsigned BW) + : PI(PI), AllInstructions(Insts), Opcodes(IDs), Operands(Ops), FilterBitValues(BW, BIT_UNFILTERED), Parent(nullptr), BestIndex(-1), - BitWidth(BW), Emitter(E) { + BitWidth(BW) { doFilter(); } - FilterChooser(ArrayRef Insts, + FilterChooser(const PrinterLLVM &PI, ArrayRef Insts, const std::vector &IDs, const std::map> &Ops, const std::vector &ParentFilterBitValues, - const FilterChooser &parent) - : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), - FilterBitValues(ParentFilterBitValues), Parent(&parent), BestIndex(-1), - BitWidth(parent.BitWidth), Emitter(parent.Emitter) { + const FilterChooser &Parent) + : PI(Parent.PI), AllInstructions(Insts), Opcodes(IDs), Operands(Ops), + FilterBitValues(ParentFilterBitValues), Parent(&Parent), BestIndex(-1), + BitWidth(Parent.BitWidth) { doFilter(); } @@ -431,59 +344,35 @@ class FilterChooser { protected: // Populates the insn given the uid. - void insnWithID(insn_t &Insn, unsigned Opcode) const { - BitsInit &Bits = getBitsField(*AllInstructions[Opcode].EncodingDef, "Inst"); - Insn.resize(BitWidth > Bits.getNumBits() ? BitWidth : Bits.getNumBits(), - BIT_UNSET); - // We may have a SoftFail bitmask, which specifies a mask where an encoding - // may differ from the value in "Inst" and yet still be valid, but the - // disassembler should return SoftFail instead of Success. - // - // This is used for marking UNPREDICTABLE instructions in the ARM world. - const RecordVal *RV = - AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); - const BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; - for (unsigned i = 0; i < Bits.getNumBits(); ++i) { - if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE) - Insn[i] = BIT_UNSET; - else - Insn[i] = bitFromBits(Bits, i); - } - } + void insnWithID(insn_t &Insn, unsigned Opcode) const; // Emit the name of the encoding/instruction pair. - void emitNameWithID(raw_ostream &OS, unsigned Opcode) const { - const Record *EncodingDef = AllInstructions[Opcode].EncodingDef; - const Record *InstDef = AllInstructions[Opcode].Inst->TheDef; - if (EncodingDef != InstDef) - OS << EncodingDef->getName() << ":"; - OS << InstDef->getName(); - } + void emitNameWithID(raw_ostream &ErrOS, unsigned Opcode) const; - // Populates the field of the insn given the start position and the number of - // consecutive bits to scan for. + // Populates the field of the insn given the start position and the number + // of consecutive bits to scan for. // // Returns false if there exists any uninitialized bit value in the range. // Returns true, otherwise. bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, unsigned NumBits) const; - /// dumpFilterArray - dumpFilterArray prints out debugging info for the given - /// filter array as a series of chars. - void dumpFilterArray(raw_ostream &o, - const std::vector & filter) const; + /// dumpFilterArray - dumpFilterArray prints out debugging info for the + /// given filter array as a series of chars. + void dumpFilterArray(raw_ostream &ErrOS, + const std::vector &Filter) const; /// dumpStack - dumpStack traverses the filter chooser chain and calls /// dumpFilterArray on each filter chooser up to the top level one. - void dumpStack(raw_ostream &o, const char *prefix) const; + void dumpStack(raw_ostream &ErrOS, const char *Prefix) const; Filter &bestFilter() { assert(BestIndex != -1 && "BestIndex not set"); return Filters[BestIndex]; } - bool PositionFiltered(unsigned i) const { - return ValueSet(FilterBitValues[i]); + bool positionFiltered(unsigned I) const { + return ValueSet(FilterBitValues[I]); } // Calculates the island(s) needed to decode the instruction. @@ -495,20 +384,11 @@ class FilterChooser { std::vector &FieldVals, const insn_t &Insn) const; - // Emits code to check the Predicates member of an instruction are true. - // Returns true if predicate matches were emitted, false otherwise. - bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation, - unsigned Opc) const; - bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, - raw_ostream &OS) const; - bool doesOpcodeNeedPredicate(unsigned Opc) const; unsigned getPredicateIndex(DecoderTableInfo &TableInfo, StringRef P) const; - void emitPredicateTableEntry(DecoderTableInfo &TableInfo, - unsigned Opc) const; + void emitPredicateTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const; - void emitSoftFailTableEntry(DecoderTableInfo &TableInfo, - unsigned Opc) const; + void emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const; // Emits table entries to decode the singleton. void emitSingletonTableEntry(DecoderTableInfo &TableInfo, @@ -518,26 +398,22 @@ class FilterChooser { void emitSingletonTableEntry(DecoderTableInfo &TableInfo, const Filter &Best) const; - void emitBinaryParser(raw_ostream &o, unsigned &Indentation, - const OperandInfo &OpInfo, - bool &OpHasCompleteDecoder) const; - - void emitDecoder(raw_ostream &OS, unsigned Indentation, unsigned Opc, + void emitDecoder(raw_ostream &DecoderOS, unsigned Opc, bool &HasCompleteDecoder) const; unsigned getDecoderIndex(DecoderSet &Decoders, unsigned Opc, bool &HasCompleteDecoder) const; // Assign a single filter and run with it. - void runSingleFilter(unsigned startBit, unsigned numBit, bool mixed); + void runSingleFilter(unsigned StartBit, unsigned NumBit, bool Mixed); // reportRegion is a helper function for filterProcessor to mark a region as // eligible for use as a filter region. void reportRegion(bitAttr_t RA, unsigned StartBit, unsigned BitIndex, bool AllowMixed); - // FilterProcessor scans the well-known encoding bits of the instructions and - // builds up a list of candidate filters. It chooses the best filter and - // recursively descends down the decoding tree. + // FilterProcessor scans the well-known encoding bits of the instructions + // and builds up a list of candidate filters. It chooses the best filter + // and recursively descends down the decoding tree. bool filterProcessor(bool AllowMixed, bool Greedy = true); // Decides on the best configuration of filter(s) to use in order to decode @@ -619,9 +495,11 @@ void Filter::recurse() { // Delegates to an inferior filter chooser for further processing on this // group of instructions whose segment values are variable. - FilterChooserMap.insert(std::make_pair(NO_FIXED_SEGMENTS_SENTINEL, - std::make_unique(Owner->AllInstructions, - VariableInstructions, Owner->Operands, BitValueArray, *Owner))); + FilterChooserMap.insert(std::make_pair( + NO_FIXED_SEGMENTS_SENTINEL, + std::make_unique(Owner->PI, Owner->AllInstructions, + VariableInstructions, Owner->Operands, + BitValueArray, *Owner))); } // No need to recurse for a singleton filtered instruction. @@ -632,11 +510,11 @@ void Filter::recurse() { } // Otherwise, create sub choosers. - for (const auto &Inst : FilteredInstructions) { + for (const auto &InstSubset: FilteredInstructions) { // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex) { - if (Inst.first & (1ULL << bitIndex)) + if (InstSubset.first & (1ULL << bitIndex)) BitValueArray[StartBit + bitIndex] = BIT_TRUE; else BitValueArray[StartBit + bitIndex] = BIT_FALSE; @@ -645,9 +523,9 @@ void Filter::recurse() { // Delegates to an inferior filter chooser for further processing on this // category of instructions. FilterChooserMap.insert(std::make_pair( - Inst.first, std::make_unique( - Owner->AllInstructions, Inst.second, - Owner->Operands, BitValueArray, *Owner))); + InstSubset.first, std::make_unique( + Owner->PI, Owner->AllInstructions, InstSubset.second, + Owner->Operands, BitValueArray, *Owner))); } } @@ -761,259 +639,35 @@ unsigned Filter::usefulness() const { // // ////////////////////////////////// -// Emit the decoder state machine table. -void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table, - unsigned Indentation, unsigned BitWidth, - StringRef Namespace) const { - OS.indent(Indentation) << "static const uint8_t DecoderTable" << Namespace - << BitWidth << "[] = {\n"; - - Indentation += 2; - - // FIXME: We may be able to use the NumToSkip values to recover - // appropriate indentation levels. - DecoderTable::const_iterator I = Table.begin(); - DecoderTable::const_iterator E = Table.end(); - while (I != E) { - assert (I < E && "incomplete decode table entry!"); - - uint64_t Pos = I - Table.begin(); - OS << "/* " << Pos << " */"; - OS.PadToColumn(12); - - switch (*I) { - default: - PrintFatalError("invalid decode table opcode"); - case MCD::OPC_ExtractField: { - ++I; - unsigned Start = *I++; - unsigned Len = *I++; - OS.indent(Indentation) << "MCD::OPC_ExtractField, " << Start << ", " - << Len << ", // Inst{"; - if (Len > 1) - OS << (Start + Len - 1) << "-"; - OS << Start << "} ...\n"; - break; - } - case MCD::OPC_FilterValue: { - ++I; - OS.indent(Indentation) << "MCD::OPC_FilterValue, "; - // The filter value is ULEB128 encoded. - while (*I >= 128) - OS << (unsigned)*I++ << ", "; - OS << (unsigned)*I++ << ", "; - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_CheckField: { - ++I; - unsigned Start = *I++; - unsigned Len = *I++; - OS.indent(Indentation) << "MCD::OPC_CheckField, " << Start << ", " - << Len << ", ";// << Val << ", " << NumToSkip << ",\n"; - // ULEB128 encoded field value. - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_CheckPredicate: { - ++I; - OS.indent(Indentation) << "MCD::OPC_CheckPredicate, "; - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_Decode: - case MCD::OPC_TryDecode: { - bool IsTry = *I == MCD::OPC_TryDecode; - ++I; - // Extract the ULEB128 encoded Opcode to a buffer. - uint8_t Buffer[16], *p = Buffer; - while ((*p++ = *I++) >= 128) - assert((p - Buffer) <= (ptrdiff_t)sizeof(Buffer) - && "ULEB128 value too large!"); - // Decode the Opcode value. - unsigned Opc = decodeULEB128(Buffer); - OS.indent(Indentation) << "MCD::OPC_" << (IsTry ? "Try" : "") - << "Decode, "; - for (p = Buffer; *p >= 128; ++p) - OS << (unsigned)*p << ", "; - OS << (unsigned)*p << ", "; - - // Decoder index. - for (; *I >= 128; ++I) - OS << (unsigned)*I << ", "; - OS << (unsigned)*I++ << ", "; - - if (!IsTry) { - OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; - break; - } - - // Fallthrough for OPC_TryDecode. - - // 24-bit numtoskip value. - uint8_t Byte = *I++; - uint32_t NumToSkip = Byte; - OS << (unsigned)Byte << ", "; - Byte = *I++; - OS << (unsigned)Byte << ", "; - NumToSkip |= Byte << 8; - Byte = *I++; - OS << utostr(Byte) << ", "; - NumToSkip |= Byte << 16; - - OS << "// Opcode: " << NumberedEncodings[Opc] - << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; - break; - } - case MCD::OPC_SoftFail: { - ++I; - OS.indent(Indentation) << "MCD::OPC_SoftFail"; - // Positive mask - uint64_t Value = 0; - unsigned Shift = 0; - do { - OS << ", " << (unsigned)*I; - Value += (*I & 0x7f) << Shift; - Shift += 7; - } while (*I++ >= 128); - if (Value > 127) { - OS << " /* 0x"; - OS.write_hex(Value); - OS << " */"; - } - // Negative mask - Value = 0; - Shift = 0; - do { - OS << ", " << (unsigned)*I; - Value += (*I & 0x7f) << Shift; - Shift += 7; - } while (*I++ >= 128); - if (Value > 127) { - OS << " /* 0x"; - OS.write_hex(Value); - OS << " */"; - } - OS << ",\n"; - break; - } - case MCD::OPC_Fail: { - ++I; - OS.indent(Indentation) << "MCD::OPC_Fail,\n"; - break; - } - } - } - OS.indent(Indentation) << "0\n"; - - Indentation -= 2; - - OS.indent(Indentation) << "};\n\n"; -} - -void DecoderEmitter::emitInstrLenTable(formatted_raw_ostream &OS, - std::vector &InstrLen) const { - OS << "static const uint8_t InstrLenTable[] = {\n"; - for (unsigned &Len : InstrLen) { - OS << Len << ",\n"; - } - OS << "};\n\n"; -} - -void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS, - PredicateSet &Predicates, - unsigned Indentation) const { - // The predicate function is just a big switch statement based on the - // input predicate index. - OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " - << "const FeatureBitset &Bits) {\n"; - Indentation += 2; - if (!Predicates.empty()) { - OS.indent(Indentation) << "switch (Idx) {\n"; - OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; - unsigned Index = 0; - for (const auto &Predicate : Predicates) { - OS.indent(Indentation) << "case " << Index++ << ":\n"; - OS.indent(Indentation+2) << "return (" << Predicate << ");\n"; - } - OS.indent(Indentation) << "}\n"; - } else { - // No case statement to emit - OS.indent(Indentation) << "llvm_unreachable(\"Invalid index!\");\n"; +// Populates the insn given the uid. +void FilterChooser::insnWithID(insn_t &Insn, unsigned Opcode) const { + BitsInit const &Bits = + getBitsField(*AllInstructions[Opcode].EncodingDef, "Inst"); + Insn.resize(BitWidth > Bits.getNumBits() ? BitWidth : Bits.getNumBits(), + BIT_UNSET); + // We may have a SoftFail bitmask, which specifies a mask where an encoding + // may differ from the value in "Inst" and yet still be valid, but the + // disassembler should return SoftFail instead of Success. + // + // This is used for marking UNPREDICTABLE instructions in the ARM world. + const RecordVal *RV = + AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); + const BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; + for (unsigned I = 0; I < Bits.getNumBits(); ++I) { + if (SFBits && bitFromBits(*SFBits, I) == BIT_TRUE) + Insn[I] = BIT_UNSET; + else + Insn[I] = bitFromBits(Bits, I); } - Indentation -= 2; - OS.indent(Indentation) << "}\n\n"; } -void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, - DecoderSet &Decoders, - unsigned Indentation) const { - // The decoder function is just a big switch statement based on the - // input decoder index. - OS.indent(Indentation) << "template \n"; - OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," - << " unsigned Idx, InsnType insn, MCInst &MI,\n"; - OS.indent(Indentation) - << " uint64_t " - << "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n"; - Indentation += 2; - OS.indent(Indentation) << "DecodeComplete = true;\n"; - // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits - // It would be better for emitBinaryParser to use a 64-bit tmp whenever - // possible but fall back to an InsnType-sized tmp for truly large fields. - OS.indent(Indentation) << "using TmpType = " - "std::conditional_t::" - "value, InsnType, uint64_t>;\n"; - OS.indent(Indentation) << "TmpType tmp;\n"; - OS.indent(Indentation) << "switch (Idx) {\n"; - OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; - unsigned Index = 0; - for (const auto &Decoder : Decoders) { - OS.indent(Indentation) << "case " << Index++ << ":\n"; - OS << Decoder; - OS.indent(Indentation+2) << "return S;\n"; - } - OS.indent(Indentation) << "}\n"; - Indentation -= 2; - OS.indent(Indentation) << "}\n\n"; +// Emit the name of the encoding/instruction pair. +void FilterChooser::emitNameWithID(raw_ostream &ErrOS, unsigned Opcode) const { + const Record *EncodingDef = AllInstructions[Opcode].EncodingDef; + const Record *InstDef = AllInstructions[Opcode].Inst->TheDef; + if (EncodingDef != InstDef) + ErrOS << EncodingDef->getName() << ":"; + ErrOS << InstDef->getName(); } // Populates the field of the insn given the start position and the number of @@ -1091,7 +745,7 @@ unsigned FilterChooser::getIslands(std::vector &StartBits, for (unsigned i = 0; i < BitWidth; ++i) { int64_t Val = Value(Insn[i]); - bool Filtered = PositionFiltered(i); + bool Filtered = positionFiltered(i); switch (State) { default: llvm_unreachable("Unreachable code!"); case 0: @@ -1131,66 +785,22 @@ unsigned FilterChooser::getIslands(std::vector &StartBits, return Num; } -void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation, - const OperandInfo &OpInfo, - bool &OpHasCompleteDecoder) const { - const std::string &Decoder = OpInfo.Decoder; - - bool UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; - - if (UseInsertBits) { - o.indent(Indentation) << "tmp = 0x"; - o.write_hex(OpInfo.InitValue); - o << ";\n"; - } - - for (const EncodingField &EF : OpInfo) { - o.indent(Indentation); - if (UseInsertBits) - o << "insertBits(tmp, "; - else - o << "tmp = "; - o << "fieldFromInstruction(insn, " << EF.Base << ", " << EF.Width << ')'; - if (UseInsertBits) - o << ", " << EF.Offset << ", " << EF.Width << ')'; - else if (EF.Offset != 0) - o << " << " << EF.Offset; - o << ";\n"; - } - - if (Decoder != "") { - OpHasCompleteDecoder = OpInfo.HasCompleteDecoder; - o.indent(Indentation) << "if (!Check(S, " << Decoder - << "(MI, tmp, Address, Decoder))) { " - << (OpHasCompleteDecoder ? "" - : "DecodeComplete = false; ") - << "return MCDisassembler::Fail; }\n"; - } else { - OpHasCompleteDecoder = true; - o.indent(Indentation) << "MI.addOperand(MCOperand::createImm(tmp));\n"; - } -} - -void FilterChooser::emitDecoder(raw_ostream &OS, unsigned Indentation, - unsigned Opc, bool &HasCompleteDecoder) const { +void FilterChooser::emitDecoder(raw_ostream &DecoderOS, unsigned Opc, + bool &HasCompleteDecoder) const { HasCompleteDecoder = true; for (const auto &Op : Operands.find(Opc)->second) { // If a custom instruction decoder was specified, use that. if (Op.numFields() == 0 && !Op.Decoder.empty()) { HasCompleteDecoder = Op.HasCompleteDecoder; - OS.indent(Indentation) - << "if (!Check(S, " << Op.Decoder - << "(MI, insn, Address, Decoder))) { " - << (HasCompleteDecoder ? "" : "DecodeComplete = false; ") - << "return MCDisassembler::Fail; }\n"; + PI.decoderEmitterEmitOpDecoder(DecoderOS, Op); break; } - bool OpHasCompleteDecoder; - emitBinaryParser(OS, Indentation, Op, OpHasCompleteDecoder); - if (!OpHasCompleteDecoder) - HasCompleteDecoder = false; + PI.decoderEmitterEmitOpBinaryParser(DecoderOS, Op); + + // If a custom decoder was set the flag decides otherwise its true. + HasCompleteDecoder = Op.Decoder != "" ? Op.HasCompleteDecoder : true; } } @@ -1199,11 +809,8 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, bool &HasCompleteDecoder) const { // Build up the predicate string. SmallString<256> Decoder; - // FIXME: emitDecoder() function can take a buffer directly rather than - // a stream. raw_svector_ostream S(Decoder); - unsigned I = 4; - emitDecoder(S, I, Opc, HasCompleteDecoder); + emitDecoder(S, Opc, HasCompleteDecoder); // Using the full decoder string as the key value here is a bit // heavyweight, but is effective. If the string comparisons become a @@ -1218,63 +825,6 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, return (unsigned)(P - Decoders.begin()); } -// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. -bool FilterChooser::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, - raw_ostream &OS) const { - if (auto *D = dyn_cast(&Val)) { - if (!D->getDef()->isSubClassOf("SubtargetFeature")) - return true; - OS << "Bits[" << Emitter->PredicateNamespace << "::" << D->getAsString() - << "]"; - return false; - } - if (auto *D = dyn_cast(&Val)) { - std::string Op = D->getOperator()->getAsString(); - if (Op == "not" && D->getNumArgs() == 1) { - OS << '!'; - return emitPredicateMatchAux(*D->getArg(0), true, OS); - } - if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { - bool Paren = D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); - if (Paren) - OS << '('; - ListSeparator LS(Op == "any_of" ? " || " : " && "); - for (auto *Arg : D->getArgs()) { - OS << LS; - if (emitPredicateMatchAux(*Arg, ParenIfBinOp, OS)) - return true; - } - if (Paren) - OS << ')'; - return false; - } - } - return true; -} - -bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, - unsigned Opc) const { - ListInit *Predicates = - AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); - bool IsFirstEmission = true; - for (unsigned i = 0; i < Predicates->size(); ++i) { - Record *Pred = Predicates->getElementAsRecord(i); - if (!Pred->getValue("AssemblerMatcherPredicate")) - continue; - - if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) - continue; - - if (!IsFirstEmission) - o << " && "; - if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"), - Predicates->size() > 1, o)) - PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); - IsFirstEmission = false; - } - return !Predicates->empty(); -} - bool FilterChooser::doesOpcodeNeedPredicate(unsigned Opc) const { ListInit *Predicates = AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); @@ -1311,23 +861,22 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo, // Build up the predicate string. SmallString<256> Predicate; - // FIXME: emitPredicateMatch() functions can take a buffer directly rather - // than a stream. raw_svector_ostream PS(Predicate); - unsigned I = 0; - emitPredicateMatch(PS, I, Opc); + const ListInit *Predicates = + AllInstructions[Opc].EncodingDef->getValueAsListInit("Predicates"); + PI.decoderEmitterEmitPredicateMatch(PS, Predicates, Opc); // Figure out the index into the predicate table for the predicate just // computed. - unsigned PIdx = getPredicateIndex(TableInfo, PS.str()); + unsigned const PIdx = getPredicateIndex(TableInfo, PS.str()); SmallString<16> PBytes; raw_svector_ostream S(PBytes); encodeULEB128(PIdx, S); TableInfo.Table.push_back(MCD::OPC_CheckPredicate); // Predicate index - for (unsigned i = 0, e = PBytes.size(); i != e; ++i) - TableInfo.Table.push_back(PBytes[i]); + for (unsigned I = 0, E = PBytes.size(); I != E; ++I) + TableInfo.Table.push_back(PBytes[I]); // Push location for NumToSkip backpatching. TableInfo.FixupStack.back().push_back(TableInfo.Table.size()); TableInfo.Table.push_back(0); @@ -2131,312 +1680,11 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, return Bits.getNumBits(); } -// emitFieldFromInstruction - Emit the templated helper function -// fieldFromInstruction(). -// On Windows we make sure that this function is not inlined when -// using the VS compiler. It has a bug which causes the function -// to be optimized out in some circumstances. See llvm.org/pr38292 -static void emitFieldFromInstruction(formatted_raw_ostream &OS) { - OS << "// Helper functions for extracting fields from encoded instructions.\n" - << "// InsnType must either be integral or an APInt-like object that " - "must:\n" - << "// * be default-constructible and copy-constructible\n" - << "// * be constructible from an APInt (this can be private)\n" - << "// * Support insertBits(bits, startBit, numBits)\n" - << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" - << "// * Support the ~, &, ==, and != operators with other objects of " - "the same type\n" - << "// * Support the != and bitwise & with uint64_t\n" - << "// * Support put (<<) to raw_ostream&\n" - << "template \n" - << "#if defined(_MSC_VER) && !defined(__clang__)\n" - << "__declspec(noinline)\n" - << "#endif\n" - << "static std::enable_if_t::value, InsnType>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " assert(startBit + numBits <= 64 && \"Cannot support >64-bit " - "extractions!\");\n" - << " assert(startBit + numBits <= (sizeof(InsnType) * 8) &&\n" - << " \"Instruction field out of bounds!\");\n" - << " InsnType fieldMask;\n" - << " if (numBits == sizeof(InsnType) * 8)\n" - << " fieldMask = (InsnType)(-1LL);\n" - << " else\n" - << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n" - << " return (insn & fieldMask) >> startBit;\n" - << "}\n" - << "\n" - << "template \n" - << "static std::enable_if_t::value, " - "uint64_t>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" - << "}\n\n"; -} - -// emitInsertBits - Emit the templated helper function insertBits(). -static void emitInsertBits(formatted_raw_ostream &OS) { - OS << "// Helper function for inserting bits extracted from an encoded " - "instruction into\n" - << "// a field.\n" - << "template \n" - << "static std::enable_if_t::value>\n" - << "insertBits(InsnType &field, InsnType bits, unsigned startBit, " - "unsigned numBits) {\n" - << " assert(startBit + numBits <= sizeof field * 8);\n" - << " field |= (InsnType)bits << startBit;\n" - << "}\n" - << "\n" - << "template \n" - << "static std::enable_if_t::value>\n" - << "insertBits(InsnType &field, uint64_t bits, unsigned startBit, " - "unsigned numBits) {\n" - << " field.insertBits(bits, startBit, numBits);\n" - << "}\n\n"; -} - -// emitDecodeInstruction - Emit the templated helper function -// decodeInstruction(). -static void emitDecodeInstruction(formatted_raw_ostream &OS, - bool IsVarLenInst) { - OS << "template \n" - << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " - "MCInst &MI,\n" - << " InsnType insn, uint64_t " - "Address,\n" - << " const MCDisassembler *DisAsm,\n" - << " const MCSubtargetInfo &STI"; - if (IsVarLenInst) { - OS << ",\n" - << " llvm::function_ref makeUp"; - } - OS << ") {\n" - << " const FeatureBitset &Bits = STI.getFeatureBits();\n" - << "\n" - << " const uint8_t *Ptr = DecodeTable;\n" - << " uint64_t CurFieldValue = 0;\n" - << " DecodeStatus S = MCDisassembler::Success;\n" - << " while (true) {\n" - << " ptrdiff_t Loc = Ptr - DecodeTable;\n" - << " switch (*Ptr) {\n" - << " default:\n" - << " errs() << Loc << \": Unexpected decode table opcode!\\n\";\n" - << " return MCDisassembler::Fail;\n" - << " case MCD::OPC_ExtractField: {\n" - << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n" - << " ++Ptr;\n"; - if (IsVarLenInst) - OS << " makeUp(insn, Start + Len);\n"; - OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " - "\", \"\n" - << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_FilterValue: {\n" - << " // Decode the field value.\n" - << " unsigned Len;\n" - << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the filter operation.\n" - << " if (Val != CurFieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " - "\", \" << NumToSkip\n" - << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " - ": \"PASS:\")\n" - << " << \" continuing at \" << (Ptr - DecodeTable) << " - "\"\\n\");\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckField: {\n" - << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n"; - if (IsVarLenInst) - OS << " makeUp(insn, Start + Len);\n"; - OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " // Decode the field value.\n" - << " unsigned PtrLen = 0;\n" - << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);\n" - << " Ptr += PtrLen;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // If the actual and expected values don't match, skip.\n" - << " if (ExpectedValue != FieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " - "\", \"\n" - << " << Len << \", \" << ExpectedValue << \", \" << " - "NumToSkip\n" - << " << \"): FieldValue = \" << FieldValue << \", " - "ExpectedValue = \"\n" - << " << ExpectedValue << \": \"\n" - << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " - "\"FAIL\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckPredicate: {\n" - << " unsigned Len;\n" - << " // Decode the Predicate Index value.\n" - << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << " // Check the predicate.\n" - << " bool Pred;\n" - << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" - << " Ptr += NumToSkip;\n" - << " (void)Pred;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " - "<< \"): \"\n" - << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Decode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << "\n" - << " MI.clear();\n" - << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n"; - if (IsVarLenInst) { - OS << " Len = InstrLenTable[Opc];\n" - << " makeUp(insn, Len);\n"; - } - OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " - "DecodeComplete);\n" - << " assert(DecodeComplete);\n" - << "\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \"\n" - << " << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " return S;\n" - << " }\n" - << " case MCD::OPC_TryDecode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the decode operation.\n" - << " MCInst TmpMI;\n" - << " TmpMI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " - "DecodeComplete);\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " - "Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \");\n" - << "\n" - << " if (DecodeComplete) {\n" - << " // Decoding complete.\n" - << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " MI = TmpMI;\n" - << " return S;\n" - << " } else {\n" - << " assert(S == MCDisassembler::Fail);\n" - << " // If the decoding was incomplete, skip.\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " - "DecodeTable) << \"\\n\");\n" - << " // Reset decode status. This also drops a SoftFail status " - "that could be\n" - << " // set before the decode attempt.\n" - << " S = MCDisassembler::Success;\n" - << " }\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_SoftFail: {\n" - << " // Decode the mask values.\n" - << " unsigned Len;\n" - << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " - "NegativeMask) != 0;\n" - << " if (Fail)\n" - << " S = MCDisassembler::SoftFail;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " - "\"FAIL\\n\" : \"PASS\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Fail: {\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" - << " return MCDisassembler::Fail;\n" - << " }\n" - << " }\n" - << " }\n" - << " llvm_unreachable(\"bogosity detected in disassembler state " - "machine!\");\n" - << "}\n\n"; -} - -// Helper to propagate SoftFail status. Returns false if the status is Fail; -// callers are expected to early-exit in that condition. (Note, the '&' operator -// is correct to propagate the values of this enum; see comment on 'enum -// DecodeStatus'.) -static void emitCheck(formatted_raw_ostream &OS) { - OS << "static bool Check(DecodeStatus &Out, DecodeStatus In) {\n" - << " Out = static_cast(Out & In);\n" - << " return Out != MCDisassembler::Fail;\n" - << "}\n\n"; -} - -// Emits disassembler code for instruction decoding. -void DecoderEmitter::run(raw_ostream &o) { - formatted_raw_ostream OS(o); - OS << "#include \"llvm/MC/MCInst.h\"\n"; - OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; - OS << "#include \"llvm/Support/DataTypes.h\"\n"; - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/LEB128.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n"; - OS << "#include \"llvm/TargetParser/SubtargetFeature.h\"\n"; - OS << "#include \n"; - OS << '\n'; - OS << "namespace llvm {\n\n"; - - emitFieldFromInstruction(OS); - emitInsertBits(OS); - emitCheck(OS); - - Target.reverseBitsForLittleEndianEncoding(); - - // Parameterize the decoders based on namespace and instruction width. +/// Encodings of instructions might differ if the Hardware Mode is different as +/// well. Here we add all possible encodings. +void DecoderEmitter::retrieveHwModeEncodings() { std::set HwModeNames; - const auto &NumberedInstructions = Target.getInstructionsByEnumValue(); - NumberedEncodings.reserve(NumberedInstructions.size()); - DenseMap IndexOfInstruction; + // First, collect all HwModes referenced by the target. for (const auto &NumberedInstruction : NumberedInstructions) { IndexOfInstruction[NumberedInstruction->TheDef] = NumberedEncodings.size(); @@ -2445,7 +1693,7 @@ void DecoderEmitter::run(raw_ostream &o) { NumberedInstruction->TheDef->getValue("EncodingInfos")) { if (auto *DI = dyn_cast_or_null(RV->getValue())) { const CodeGenHwModes &HWM = Target.getHwModes(); - EncodingInfoByHwMode EBM(DI->getDef(), HWM); + EncodingInfoByHwMode const EBM(DI->getDef(), HWM); for (auto &KV : EBM) HwModeNames.insert(HWM.getMode(KV.first).Name); } @@ -2478,28 +1726,18 @@ void DecoderEmitter::run(raw_ostream &o) { NumberedEncodings.emplace_back(NumberedInstruction->TheDef, NumberedInstruction, HwModeName); } - for (const auto &NumberedAlias : RK.getAllDerivedDefinitions("AdditionalEncoding")) - NumberedEncodings.emplace_back( - NumberedAlias, - &Target.getInstruction(NumberedAlias->getValueAsDef("AliasOf"))); - - std::map, std::vector> - OpcMap; - std::map> Operands; - std::vector InstrLen; +} - bool IsVarLenInst = - any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { - RecordVal *RV = CGI->TheDef->getValue("Inst"); - return RV && isa(RV->getValue()); - }); +/// Fills the Opcode Map with the encodings of the different decoder spaces. +/// It returns the maximum length of all variable length instructions. +/// Or 0 if no variable length is in the set (\p IsVarLenInst = false) +unsigned DecoderEmitter::fillOpcMap(bool const IsVarLenInst) { unsigned MaxInstLen = 0; - - for (unsigned i = 0; i < NumberedEncodings.size(); ++i) { - const Record *EncodingDef = NumberedEncodings[i].EncodingDef; - const CodeGenInstruction *Inst = NumberedEncodings[i].Inst; + for (unsigned I = 0; I < NumberedEncodings.size(); ++I) { + const Record *EncodingDef = NumberedEncodings[I].EncodingDef; + const CodeGenInstruction *Inst = NumberedEncodings[I].Inst; const Record *Def = Inst->TheDef; - unsigned Size = EncodingDef->getValueAsInt("Size"); + unsigned const Size = EncodingDef->getValueAsInt("Size"); if (Def->getValueAsString("Namespace") == "TargetOpcode" || Def->getValueAsBit("isPseudo") || Def->getValueAsBit("isAsmParserOnly") || @@ -2508,7 +1746,7 @@ void DecoderEmitter::run(raw_ostream &o) { continue; } - if (i < NumberedInstructions.size()) + if (I < NumberedInstructions.size()) NumInstructions++; NumEncodings++; @@ -2518,31 +1756,65 @@ void DecoderEmitter::run(raw_ostream &o) { if (IsVarLenInst) InstrLen.resize(NumberedInstructions.size(), 0); - if (unsigned Len = populateInstruction(Target, *EncodingDef, *Inst, i, - Operands, IsVarLenInst)) { + if (unsigned const Len = populateInstruction(Target, *EncodingDef, *Inst, I, + Operands, IsVarLenInst)) { if (IsVarLenInst) { MaxInstLen = std::max(MaxInstLen, Len); - InstrLen[i] = Len; + InstrLen[I] = Len; } std::string DecoderNamespace = std::string(EncodingDef->getValueAsString("DecoderNamespace")); - if (!NumberedEncodings[i].HwModeName.empty()) + if (!NumberedEncodings[I].HwModeName.empty()) DecoderNamespace += - std::string("_") + NumberedEncodings[i].HwModeName.str(); + std::string("_") + NumberedEncodings[I].HwModeName.str(); OpcMap[std::make_pair(DecoderNamespace, Size)].emplace_back( - i, IndexOfInstruction.find(Def)->second); + I, IndexOfInstruction.find(Def)->second); } else { NumEncodingsOmitted++; } } + return MaxInstLen; +} + +// Emits disassembler code for instruction decoding. +void DecoderEmitter::run() { + PI.decoderEmitterEmitSourceFileHeader(); + PI.decoderEmitterEmitIncludes(); + PI.emitNamespace("llvm", true); + PI.decoderEmitterEmitFieldFromInstruction(); + PI.decoderEmitterEmitInsertBits(); + PI.decoderEmitterEmitCheck(); + + Target.reverseBitsForLittleEndianEncoding(); + + // Parameterize the decoders based on namespace and instruction width. + NumberedInstructions = Target.getInstructionsByEnumValue(); + NumberedEncodings.reserve(NumberedInstructions.size()); + retrieveHwModeEncodings(); + + for (const auto &NumberedAlias : + RK.getAllDerivedDefinitions("AdditionalEncoding")) + NumberedEncodings.emplace_back( + NumberedAlias, + &Target.getInstruction(NumberedAlias->getValueAsDef("AliasOf"))); + + bool const IsVarLenInst = + any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { + RecordVal *RV = CGI->TheDef->getValue("Inst"); + return RV && isa(RV->getValue()); + }); + + unsigned const MaxInstLen = fillOpcMap(IsVarLenInst); + + // Build the state machine for instruction decoding. DecoderTableInfo TableInfo; for (const auto &Opc : OpcMap) { // Emit the decoder for this namespace+width combination. - ArrayRef NumberedEncodingsRef( + ArrayRef const NumberedEncodingsRef( NumberedEncodings.data(), NumberedEncodings.size()); - FilterChooser FC(NumberedEncodingsRef, Opc.second, Operands, - IsVarLenInst ? MaxInstLen : 8 * Opc.first.second, this); + FilterChooser const FC(PI, NumberedEncodingsRef, Opc.second, Operands, + IsVarLenInst ? MaxInstLen : 8 * Opc.first.second); // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across all @@ -2563,31 +1835,96 @@ void DecoderEmitter::run(raw_ostream &o) { TableInfo.Table.push_back(MCD::OPC_Fail); // Print the table to the output stream. - emitTable(OS, TableInfo.Table, 0, FC.getBitWidth(), Opc.first.first); + PI.decoderEmitterEmitTable(TableInfo.Table, FC.getBitWidth(), Opc.first.first, + NumberedEncodings); + PI.flushOS(); } // For variable instruction, we emit a instruction length table // to let the decoder know how long the instructions are. // You can see example usage in M68k's disassembler. if (IsVarLenInst) - emitInstrLenTable(OS, InstrLen); + PI.decoderEmitterEmitInstrLenTable(InstrLen); // Emit the predicate function. - emitPredicateFunction(OS, TableInfo.Predicates, 0); + PI.decoderEmitterEmitPredicateFunction(TableInfo.Predicates, 0); // Emit the decoder function. - emitDecoderFunction(OS, TableInfo.Decoders, 0); + PI.decoderEmitterEmitDecoderFunction(TableInfo.Decoders, 0); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS, IsVarLenInst); + PI.decoderEmitterEmitDecodeInstruction(IsVarLenInst); + PI.emitNamespace("llvm", false); +} - OS << "\n} // end namespace llvm\n"; +static void setPrinterParameters(CodeGenTarget &Target, PrinterLanguage PL, + std::string &PredicateNamespace, + std::string &GPrefix, std::string &GPostfix, + std::string &ROK, std::string &RFail, + std::string &L) { + PredicateNamespace = std::string(Target.getName()); + + if (PredicateNamespace == "Thumb") + PredicateNamespace = "ARM"; + + switch (PL) { + default: + PrintFatalNote("DecoderEmitter does not support the given output language."); + case llvm::PRINTER_LANG_CPP: + GPrefix = "if (!Check(S, "; + L = " MCDisassembler::DecodeStatus S = " + "MCDisassembler::Success;\n(void)S;"; + break; + case llvm::PRINTER_LANG_CAPSTONE_C: + GPrefix = "if (!Check(&S, "; + L = " MCDisassembler_DecodeStatus S = " + "MCDisassembler_Success;\n(void)S;"; + break; + } + GPostfix = "))"; + + ROK = "S"; + + switch (PL) { + default: + PrintFatalNote("DecoderEmitter does not support the given output language."); + case llvm::PRINTER_LANG_CPP: + RFail = "MCDisassembler::Fail"; + break; + case llvm::PRINTER_LANG_CAPSTONE_C: + RFail = "MCDisassembler_Fail"; + break; + } } namespace llvm { -void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace) { - DecoderEmitter(RK, PredicateNamespace).run(OS); +void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, CodeGenTarget &Target) { + formatted_raw_ostream FOS(OS); + PrinterLLVM *PI; + std::string PredicateNamespace; + std::string GPrefix; + std::string GPostfix; + std::string ROK; + std::string RFail; + std::string L; + PrinterLanguage const PL = PrinterLLVM::getLanguage(); + + setPrinterParameters(Target, PL, PredicateNamespace, GPrefix, GPostfix, + ROK, RFail, L); + + if (PL == PRINTER_LANG_CPP) { + PI = new PrinterLLVM(FOS, PredicateNamespace, + GPrefix, GPostfix, ROK, RFail, + L, Target.getName().str()); + } else if (PL == PRINTER_LANG_CAPSTONE_C) { + PI = new PrinterCapstone(FOS, PredicateNamespace, + GPrefix, GPostfix, ROK, RFail, + L, Target.getName().str()); + } else { + PrintFatalNote("DecoderEmitter does not support the given output language."); + } + DecoderEmitter(RK, *PI).run(); + delete PI; } } // end namespace llvm diff --git a/llvm/utils/TableGen/DecoderEmitter.md b/llvm/utils/TableGen/DecoderEmitter.md new file mode 100644 index 000000000000..1f8337413dcf --- /dev/null +++ b/llvm/utils/TableGen/DecoderEmitter.md @@ -0,0 +1,232 @@ +# Decoder emitter + +The decoder emitter generates the code for the disassembler of several architectures. + +The general design is split into three classes. + +- `DecoderEmitter`: Controls code generation and pre-processes `Records`. +- `FilterChooser`: Builds the decoding state machine. +- `Filter`: Represents a state in the decoding state machine. + +The rough process of the code generation is described in the following diagram. +The details about the state machine creation (the `recurse` step) are explained below. + +``` +DecoderEmitter FilterChooser Filter PrinterInterface Output Stream + + ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ + │ ├────────┐ │ │ │ │ │ │ │ │ + │ │ │Separate instr. │ │ │ │ │ │ │ │ + │ │ │into groups │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │◄───────┘ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Start separation process │ │ Separate │ │ │ │ │ │ + │ │ of instr. groups │ │ into │ │ │ │ │ │ + │ ├──────────────────────────►│ │ subsets │ │ │ │ │ │ + │ │ │ ├───────────┐ │ │ │ │ │ │ + │ │ │ │ │ Add Filter to │ │ │ │ │ │ + │ │ │ │ │ Filterlist │ │ │ │ │ │ + │ │ │ │ R ├──────────────────►│ │ │ │ │ │ + │ │ │ │ E │ │ │ │ │ │ │ + │ │ │ │ C │ │ │ │ │ │ │ + │ │ │ │ U │ └───┘ │ │ │ │ + │ │ │ │ R │ │ │ │ │ + │ │ │ │ S │ Request Filter decoder string │ │ │ │ + │ │ │ │ E ├───────────────────────────────────────►│ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │◄───────────────────────────────────────┤ │ │ │ + │ │ │ │ │ Return decoder string │ │ │ │ + │ │ │ │◄──────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │◄──────────────────────────┤ │ │ │ │ │ + │ │ Return list of decoder │ │ │ │ │ │ + │ │ strings └───┘ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ Request to print decoders into file │ │ Print │ │ + │ ├───────────────────────────────────────────────────────────────────────────────────►│ │ decoders │ │ + │ │ │ ├────────────────►│ │ + │ │ │ │ │ │ + │ │ Request to print helper functions into file │ │ Print │ │ + │ ├───────────────────────────────────────────────────────────────────────────────────►│ │ functions │ │ + │ │ │ ├────────────────►│ │ + │ │ │ │ │ │ + └───┘ │ │ │ │ + └───┘ └───┘ +``` + +# Instruction Decoding + +The disassembler of LLVM decodes instructions with the help of a non-cyclic [state machine](https://en.wikipedia.org/wiki/Finite-state_machine). + +Reading this will help you a lot to understand the code! +Because we describe here how this state machine is generated. + +## The general idea + +We start with a single set off all instructions of an architecture. +These instructions are put in groups. Each group holds the instructions of a specific CPU extension or mode +(think of `Thumb` mode in ARM, or vector extension of some processors). +For each group a state machine is generated. It decodes instructions of this group. + +To generate the state machine we first take all instructions of a group. +This set is split into subsets each of which can be distinguished to the other subsets by a certain bit field in its encoding. +This and other separation information is called `Filter`. + +The subsets are further split into smaller subsets until only single instructions are left. + +_Each subset represents a state in our decoding state machine._ + +
+ +This generator will build the states for several instruction groups (the `uint8_t decoder[]` tables) +and a decoder function which walks over those states until it fails or identifies an instruction. + +## Step 1 - Determine best bits for set separation + +In this step we determine which bits are most suited to separate the current set of instructions into subsets. + +Lets assume we have four instructions with a width of 8 bits (all instructions of a group have the same bit width). + +```text +Bit 0 1 2 3 4 5 6 7 + +IA: 0 1 0 ? ? 1 ? ? +IB: ? 1 0 0 0 ? ? ? +IC: 0 0 0 0 1 ? ? ? +ID: ? 0 1 ? ? ? ? ? + +`?` = unset bit position (holds variable bits) +``` + +Now we have a `BitAttr` mask which saves which bits are suitable for filtering the set into subsets. + +``` +BitAttr: . . _ _ _ _ _ _ + +"." = Bit already used by previous Filter. +"_" = Bit unset/None (not used by previous Filter) +``` + +In the beginning all bits are unset (`_`) but the more instructions become filtered the more bits are set to `.`. + +To determine which bits in instruction `IA` to `ID` can be used to distinguish them, we define a automaton (see below). +The automaton gets the value at `BitAttr[i]` (`Filtered` or `Unset`/`None`) as start state and as input the bits at `IA[i]`, `IB[i]`, `IC[i]`, `ID[i]`. + +The result can be: `AllSet` (`S`), `All_unset` (`U`), `Mixed` (`M`) or `Filtered` (`F`) +The result is written to `BitAttr[i]`. + +``` + 0,1 + ┌─────┐ + │ │ + │ │ + │ │ + │ ▼ + ┌─┴───────┐ + 0,1 │ │ 0,1,? + ┌─────────────────►│All_Set │ ┌────┐ + │ │ │ │ │ + │ └────┬────┘ │ │ + │ │ │ │ + │ │? │ ▼ + │ │ ┌───┴──────┐ + │ ▼ │ │ +┌────┴───┐ ┌───────────┐ │ Filtered │ +│ │ │ ├─────┐ │ │ +│ None │ │ Mixed │ │0,1,? └──────────┘ +│ │ │ │◄────┘ +└───┬────┘ └───────────┘ + │ ▲ + │ │0,1 + │ │ + │ ┌────┴─────┐ + │ ? │ │ + └──────────────────►│ All_unset│ + │ │ + └─┬────────┘ + │ ▲ + │ │ + │ │ + │ │ + └─────┘ + ? +``` + +Here is how our little example would play out. + +``` +IA: 0 1 0 ? ? 1 ? ? +IB: ? 1 0 0 0 ? ? ? +IC: 0 0 0 0 1 ? ? ? +ID: ? 0 1 ? ? ? ? ? + +BitAttr: . . _ _ _ _ _ _ + +becomes + +BitAttr: . . S M M M U U +``` + +## Step 2 - Determine potential Filters + +Now we report regions in the `BitAttr` which might be suitable as a `Filter`. +A `region` is the index of the start bit and the length. + +There are three region reporting strategies: + +1. Report only successive `S` bits. +2. Report only successive `S` or successive `M` bits. +3. A special and rare case (explained in code). + +The strategies are tried from 1 to 3. +If non of them works we get a conflict (the set of instructions are indistinguishable). This case is explained in the code. + +If we continue with our example we get the following regions: + +``` +region = (startIndex, length) + +Bit 0 1 2 3 4 5 6 7 +BitAttr: . . S M M M U U + +strategy 1 = R1 = (2, 1) +strategy 2 = R1 = (2, 1), R2 = (3, 3) +``` + +## Step 3 - Select the best region as Filter + +We determine the best `Filter` by checking which region distinguishes the most instructions. +Lets assume we used strategy 2 here, so we have: + +``` +Bit 0 1 2 3 4 5 6 7 + +IA: 0 1 0 ? ? 1 ? ? +IB: ? 1 0 0 0 ? ? ? +IC: 0 0 0 0 1 ? ? ? +ID: ? 0 1 ? ? ? ? ? + +R1 = (2, 1) +R2 = (3, 3) +``` + +`R1` can create two subsets: `(IA, IB, IC)` and `(ID)`. +`R2` can create only one subset `(IA, IB, IC, ID)`. + +`R1` can separate instructions by bit 2 (which is either `0` or `1` in all instructions). + +`R2` has not a single bit position where all instruction bits are known (remember: `?` are variable bits, we can't distinguish them). +Therefore it can not separate instructions. + +Because `R1` creates the most subsets it is chosen as the Filter. + +## Recurse + +The `BitAttr` bits are reset to either `Filtered` (if used) or `Unset` and passed on to the inferior `FilterChooser` of each subset. +For each subset we start the process again from `Step 1` (not for subsets of size 1 obviously). + diff --git a/llvm/utils/TableGen/DecoderEmitterTypes.h b/llvm/utils/TableGen/DecoderEmitterTypes.h new file mode 100644 index 000000000000..a3039fc52a6e --- /dev/null +++ b/llvm/utils/TableGen/DecoderEmitterTypes.h @@ -0,0 +1,142 @@ +//===------- DecoderEmitterTypes.h - Decoder Generator ----------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_DECODEREMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_DECODEREMITTERTYPES_H + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "InfoByHwMode.h" +#include "VarLenCodeEmitterGen.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/CachedHashString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCDecoderOps.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +////////////////////// +// Structs and Types +////////////////////// + +struct EncodingField { + unsigned Base, Width, Offset; + EncodingField(unsigned B, unsigned W, unsigned O) + : Base(B), Width(W), Offset(O) {} +}; + +struct OperandInfo { + std::vector Fields; + std::string Decoder; + bool HasCompleteDecoder; + uint64_t InitValue; + + OperandInfo(std::string D, bool HCD) + : Decoder(std::move(D)), HasCompleteDecoder(HCD), InitValue(0) {} + + void addField(unsigned Base, unsigned Width, unsigned Offset) { + Fields.push_back(EncodingField(Base, Width, Offset)); + } + + unsigned numFields() const { return Fields.size(); } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return Fields.begin(); } + const_iterator end() const { return Fields.end(); } +}; + +typedef std::vector DecoderTable; +typedef uint32_t DecoderFixup; +typedef std::vector FixupList; +typedef std::vector FixupScopeList; +typedef SmallSetVector PredicateSet; +typedef SmallSetVector DecoderSet; +struct DecoderTableInfo { + DecoderTable Table; + FixupScopeList FixupStack; + PredicateSet Predicates; + DecoderSet Decoders; +}; + +struct EncodingAndInst { + const Record *EncodingDef; + const CodeGenInstruction *Inst; + StringRef HwModeName; + + EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst, + StringRef HwModeName = "") + : EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {} +}; + +struct EncodingIDAndOpcode { + unsigned EncodingID; + unsigned Opcode; + + EncodingIDAndOpcode() : EncodingID(0), Opcode(0) {} + EncodingIDAndOpcode(unsigned EncodingID, unsigned Opcode) + : EncodingID(EncodingID), Opcode(Opcode) {} +}; + +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system +// for a bit value. +// +// BIT_UNFILTERED is used as the init value for a filter position. It is used +// only for filter processings. +typedef enum { + BIT_TRUE, // '1' + BIT_FALSE, // '0' + BIT_UNSET, // '?' + BIT_UNFILTERED // unfiltered +} bit_value_t; + +// Representation of the instruction to work on. +typedef std::vector insn_t; + +// These are states of our finite state machines used in FilterChooser's +// filterProcessor() which produces the filter candidates to use. +typedef enum { + ATTR_NONE, + ATTR_FILTERED, + ATTR_ALL_SET, + ATTR_ALL_UNSET, + ATTR_MIXED +} bitAttr_t; + +inline raw_ostream &operator<<(raw_ostream &OS, const EncodingAndInst &Value) { + if (Value.EncodingDef != Value.Inst->TheDef) + OS << Value.EncodingDef->getName() << ":"; + OS << Value.Inst->TheDef->getName(); + return OS; +} + +#endif // LLVM_UTILS_TABLEGEN_DECODEREMITTERTYPES_H diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp index 92f3721507e5..751c5efe4d1a 100644 --- a/llvm/utils/TableGen/DisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -8,6 +8,7 @@ #include "CodeGenTarget.h" #include "TableGenBackends.h" +#include "Printer.h" #include "WebAssemblyDisassemblerEmitter.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" @@ -96,14 +97,14 @@ using namespace llvm::X86Disassembler; static void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); - emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); // X86 uses a custom disassembler. if (Target.getName() == "X86") { + emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); DisassemblerTables Tables; - ArrayRef numberedInstructions = - Target.getInstructionsByEnumValue(); + ArrayRef numberedInstructions = + Target.getInstructionsByEnumValue(); for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i) RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i); @@ -121,14 +122,11 @@ static void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { // below (which depends on a Size table-gen Record), and also uses a custom // disassembler. if (Target.getName() == "WebAssembly") { + emitSourceFileHeader(" * " + Target.getName().str() + " Disassembler", OS); emitWebAssemblyDisassemblerTables(OS, Target.getInstructionsByEnumValue()); return; } - - std::string PredicateNamespace = std::string(Target.getName()); - if (PredicateNamespace == "Thumb") - PredicateNamespace = "ARM"; - EmitDecoder(Records, OS, PredicateNamespace); + EmitDecoder(Records, OS, Target); } static TableGen::Emitter::Opt X("gen-disassembler", EmitDisassembler, diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index b2250c0cf989..f923a928f34d 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -11,31 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenDAGPatterns.h" -#include "CodeGenInstruction.h" -#include "CodeGenSchedule.h" -#include "CodeGenTarget.h" -#include "PredicateExpander.h" -#include "SequenceToOffsetTable.h" -#include "SubtargetFeatureInfo.h" -#include "TableGenBackends.h" -#include "Types.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include -#include -#include -#include -#include -#include -#include +#include "InstrInfoEmitterTypes.h" +#include "Printer.h" +#include "PrinterTypes.h" using namespace llvm; @@ -49,70 +27,61 @@ namespace { class InstrInfoEmitter { RecordKeeper &Records; + PrinterLLVM &PI; CodeGenDAGPatterns CDP; const CodeGenSchedModels &SchedModels; public: - InstrInfoEmitter(RecordKeeper &R): - Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {} + InstrInfoEmitter(RecordKeeper &R, PrinterLLVM &PI): + Records(R), PI(PI), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {} // run - Output the instruction set description. - void run(raw_ostream &OS); + void run(); private: - void emitEnums(raw_ostream &OS); - - typedef std::vector OperandInfoTy; - typedef std::vector OperandInfoListTy; - typedef std::map OperandInfoMapTy; - - /// The keys of this map are maps which have OpName enum values as their keys - /// and instruction operand indices as their values. The values of this map - /// are lists of instruction names. - typedef std::map, - std::vector> OpNameMapTy; - typedef std::map::iterator StrUintMapIter; + void emitEnums(); + // Typedefs went into InstrInfoEmitterTypes.h /// Generate member functions in the target-specific GenInstrInfo class. /// /// This method is used to custom expand TIIPredicate definitions. /// See file llvm/Target/TargetInstPredicates.td for a description of what is /// a TIIPredicate and how to use it. - void emitTIIHelperMethods(raw_ostream &OS, StringRef TargetName, + void emitTIIHelperMethods(StringRef TargetName, bool ExpandDefinition = true); /// Expand TIIPredicate definitions to functions that accept a const MCInst /// reference. - void emitMCIIHelperMethods(raw_ostream &OS, StringRef TargetName); + void emitMCIIHelperMethods(StringRef TargetName); /// Write verifyInstructionPredicates methods. - void emitFeatureVerifier(raw_ostream &OS, const CodeGenTarget &Target); + void emitFeatureVerifier(const CodeGenTarget &Target); void emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map, unsigned> &EL, - const OperandInfoMapTy &OperandInfo, raw_ostream &OS); + const OperandInfoMapTy &OperandInfo); void emitOperandTypeMappings( - raw_ostream &OS, const CodeGenTarget &Target, + const CodeGenTarget &Target, ArrayRef NumberedInstructions); void initOperandMapData( ArrayRef NumberedInstructions, StringRef Namespace, std::map &Operands, OpNameMapTy &OperandMap); - void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, + void emitOperandNameMappings(const CodeGenTarget &Target, ArrayRef NumberedInstructions); void emitLogicalOperandSizeMappings( - raw_ostream &OS, StringRef Namespace, + StringRef Namespace, ArrayRef NumberedInstructions); void emitLogicalOperandTypeMappings( - raw_ostream &OS, StringRef Namespace, + StringRef Namespace, ArrayRef NumberedInstructions); // Operand information. unsigned CollectOperandInfo(OperandInfoListTy &OperandInfoList, OperandInfoMapTy &OperandInfoMap); - void EmitOperandInfo(raw_ostream &OS, OperandInfoListTy &OperandInfoList); + void EmitOperandInfo(OperandInfoListTy &OperandInfoList); OperandInfoTy GetOperandInfo(const CodeGenInstruction &Inst); }; @@ -122,7 +91,7 @@ class InstrInfoEmitter { // Operand Info Emission. //===----------------------------------------------------------------------===// -InstrInfoEmitter::OperandInfoTy +OperandInfoTy InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { OperandInfoTy Result; @@ -153,57 +122,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { Record *OpR = OperandList[j].Rec; std::string Res; - if (OpR->isSubClassOf("RegisterOperand")) - OpR = OpR->getValueAsDef("RegClass"); - if (OpR->isSubClassOf("RegisterClass")) - Res += getQualifiedName(OpR) + "RegClassID, "; - else if (OpR->isSubClassOf("PointerLikeRegClass")) - Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; - else - // -1 means the operand does not have a fixed register class. - Res += "-1, "; - - // Fill in applicable flags. - Res += "0"; - - // Ptr value whose register class is resolved via callback. - if (OpR->isSubClassOf("PointerLikeRegClass")) - Res += "|(1<isSubClassOf("PredicateOp")) - Res += "|(1<isSubClassOf("OptionalDefOperand")) - Res += "|(1<isSubClassOf("BranchTargetOperand")) - Res += "|(1<second] = Info.MIOperandNo; } - OperandMap[OpList].push_back(Namespace.str() + "::" + - Inst->TheDef->getName().str()); + OperandMap[OpList].push_back( + PI.instrInfoGetInstMapEntry(Namespace, Inst->TheDef->getName())); } } @@ -280,7 +191,7 @@ void InstrInfoEmitter::initOperandMapData( /// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) /// for looking up the operand index for an instruction, given a value from /// OpName enum -void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, +void InstrInfoEmitter::emitOperandNameMappings( const CodeGenTarget &Target, ArrayRef NumberedInstructions) { StringRef Namespace = Target.getInstNamespace(); @@ -292,68 +203,30 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap); - OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n"; - OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "namespace " << OpNameNS << " {\n"; - OS << "enum {\n"; - for (const auto &Op : Operands) - OS << " " << Op.first << " = " << Op.second << ",\n"; - - OS << " OPERAND_LAST"; - OS << "\n};\n"; - OS << "} // end namespace OpName\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n"; - - OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n"; - OS << "#undef GET_INSTRINFO_NAMED_OPS\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "LLVM_READONLY\n"; - OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n"; - if (!Operands.empty()) { - OS << " static const int16_t OperandMap [][" << Operands.size() - << "] = {\n"; - for (const auto &Entry : OperandMap) { - const std::map &OpList = Entry.first; - OS << "{"; - - // Emit a row of the OperandMap table - for (unsigned i = 0, e = Operands.size(); i != e; ++i) - OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", "; - - OS << "},\n"; - } - OS << "};\n"; - - OS << " switch(Opcode) {\n"; - unsigned TableIndex = 0; - for (const auto &Entry : OperandMap) { - for (const std::string &Name : Entry.second) - OS << " case " << Name << ":\n"; - - OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n"; - } - OS << " default: return -1;\n"; - OS << " }\n"; - } else { - // There are no operands, so no need to emit anything - OS << " return -1;\n"; - } - OS << "}\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_ENUM", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.emitNamespace(OpNameNS, true); + PI.instrInfoEmitOperandEnum(Operands); + PI.emitNamespace(OpNameNS, false); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false, "", false); + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_ENUM", false); + + PI.emitIncludeToggle("GET_INSTRINFO_NAMED_OPS", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.instrInfoEmitGetNamedOperandIdx(Operands, OperandMap); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false, "", false); + PI.emitIncludeToggle("GET_INSTRINFO_NAMED_OPS", false); } /// Generate an enum for all the operand types for this target, under the /// llvm::TargetNamespace::OpTypes namespace. /// Operand types are all definitions derived of the Operand Target.td class. void InstrInfoEmitter::emitOperandTypeMappings( - raw_ostream &OS, const CodeGenTarget &Target, + const CodeGenTarget &Target, ArrayRef NumberedInstructions) { StringRef Namespace = Target.getInstNamespace(); @@ -363,38 +236,33 @@ void InstrInfoEmitter::emitOperandTypeMappings( std::vector RegisterClasses = Records.getAllDerivedDefinitions("RegisterClass"); - OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; - OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "namespace OpTypes {\n"; - OS << "enum OperandType {\n"; + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_TYPES_ENUM", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.emitNamespace("OpTypes", true); + PI.instrInfoEmitOpTypeEnumPartI(); unsigned EnumVal = 0; for (const std::vector *RecordsToAdd : {&Operands, &RegisterOperands, &RegisterClasses}) { for (const Record *Op : *RecordsToAdd) { if (!Op->isAnonymous()) - OS << " " << Op->getName() << " = " << EnumVal << ",\n"; + PI.instrInfoEmitOpTypeEnumPartII(Op->getName(), EnumVal); ++EnumVal; } } - OS << " OPERAND_TYPE_LIST_END" << "\n};\n"; - OS << "} // end namespace OpTypes\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; - - OS << "#ifdef GET_INSTRINFO_OPERAND_TYPE\n"; - OS << "#undef GET_INSTRINFO_OPERAND_TYPE\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "LLVM_READONLY\n"; - OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n"; - auto getInstrName = [&](int I) -> StringRef { - return NumberedInstructions[I]->TheDef->getName(); - }; + PI.instrInfoEmitOpTypeEnumPartIII(); + PI.emitNamespace("OpTypes", false); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_TYPES_ENUM", false); + + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_TYPE", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.instrInfoEmitGetOpTypeHdr(); + // TODO: Factor out duplicate operand lists to compress the tables. if (!NumberedInstructions.empty()) { std::vector OperandOffsets; @@ -421,13 +289,7 @@ void InstrInfoEmitter::emitOperandTypeMappings( // Size the unsigned integer offset to save space. assert(OperandRecords.size() <= UINT32_MAX && "Too many operands for offset table"); - OS << " static const " << getMinimalTypeForRange(OperandRecords.size()); - OS << " Offsets[] = {\n"; - for (int I = 0, E = OperandOffsets.size(); I != E; ++I) { - OS << " /* " << getInstrName(I) << " */\n"; - OS << " " << OperandOffsets[I] << ",\n"; - } - OS << " };\n"; + PI.instrInfoEmitOpTypeOffsetTable(OperandOffsets, OperandRecords.size(), NumberedInstructions); // Add an entry for the end so that we don't need to special case it below. OperandOffsets.push_back(OperandRecords.size()); @@ -436,45 +298,23 @@ void InstrInfoEmitter::emitOperandTypeMappings( // Size the signed integer operand type to save space. assert(EnumVal <= INT16_MAX && "Too many operand types for operand types table"); - OS << "\n using namespace OpTypes;\n"; - OS << " static"; - OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t"); - OS << " OpcodeOperandTypes[] = {\n "; - for (int I = 0, E = OperandRecords.size(), CurOffset = 0; I != E; ++I) { - // We print each Opcode's operands in its own row. - if (I == OperandOffsets[CurOffset]) { - OS << "\n /* " << getInstrName(CurOffset) << " */\n "; - while (OperandOffsets[++CurOffset] == I) - OS << "/* " << getInstrName(CurOffset) << " */\n "; - } - Record *OpR = OperandRecords[I]; - if ((OpR->isSubClassOf("Operand") || - OpR->isSubClassOf("RegisterOperand") || - OpR->isSubClassOf("RegisterClass")) && - !OpR->isAnonymous()) - OS << OpR->getName(); - else - OS << -1; - OS << ", "; - } - OS << "\n };\n"; - - OS << " return OpcodeOperandTypes[Offsets[Opcode] + OpIdx];\n"; + PI.instrInfoEmitOpcodeOpTypesTable(EnumVal, + OperandRecords, + OperandOffsets, + NumberedInstructions); + PI.instrInfoEmitGetOpTypeReturn(); } else { - OS << " llvm_unreachable(\"No instructions defined\");\n"; + PI.instrInfoEmitGetOpTypeUnreachable(); } - OS << "}\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_OPERAND_TYPE\n\n"; - - OS << "#ifdef GET_INSTRINFO_MEM_OPERAND_SIZE\n"; - OS << "#undef GET_INSTRINFO_MEM_OPERAND_SIZE\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "LLVM_READONLY\n"; - OS << "static int getMemOperandSize(int OpType) {\n"; - OS << " switch (OpType) {\n"; + PI.instrInfoEmitGetOpTypeEnd(); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_TYPE", false); + + PI.emitIncludeToggle("GET_INSTRINFO_MEM_OPERAND_SIZE", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.instrInfoEmitGetMemOpSizeHdr(); std::map> SizeToOperandName; for (const Record *Op : Operands) { if (!Op->isSubClassOf("X86MemOperand")) @@ -482,20 +322,15 @@ void InstrInfoEmitter::emitOperandTypeMappings( if (int Size = Op->getValueAsInt("Size")) SizeToOperandName[Size].push_back(Op->getName()); } - OS << " default: return 0;\n"; - for (const auto &KV : SizeToOperandName) { - for (const StringRef &OperandName : KV.second) - OS << " case OpTypes::" << OperandName << ":\n"; - OS << " return " << KV.first << ";\n\n"; - } - OS << " }\n}\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_MEM_OPERAND_SIZE\n\n"; + + PI.instrInfoEmitGetOpMemSizeTbl(SizeToOperandName); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_MEM_OPERAND_SIZE", false); } void InstrInfoEmitter::emitLogicalOperandSizeMappings( - raw_ostream &OS, StringRef Namespace, + StringRef Namespace, ArrayRef NumberedInstructions) { std::map, unsigned> LogicalOpSizeMap; @@ -520,69 +355,36 @@ void InstrInfoEmitter::emitLogicalOperandSizeMappings( auto I = LogicalOpSizeMap.insert({LogicalOpList, LogicalOpSizeMap.size()}).first; InstMap[I->second].push_back( - (Namespace + "::" + Inst->TheDef->getName()).str()); + PI.instrInfoGetInstMapEntry(Namespace, Inst->TheDef->getName())); } - OS << "#ifdef GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n"; - OS << "#undef GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "LLVM_READONLY static unsigned\n"; - OS << "getLogicalOperandSize(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + PI.emitIncludeToggle("GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.instrInfoEmitGetLogicalOpSizeHdr(); if (!InstMap.empty()) { std::vector *> LogicalOpSizeList( LogicalOpSizeMap.size()); for (auto &P : LogicalOpSizeMap) { LogicalOpSizeList[P.second] = &P.first; } - OS << " static const unsigned SizeMap[][" << LogicalOpListSize - << "] = {\n"; - for (auto &R : LogicalOpSizeList) { - const auto &Row = *R; - OS << " {"; - int i; - for (i = 0; i < static_cast(Row.size()); ++i) { - OS << Row[i] << ", "; - } - for (; i < static_cast(LogicalOpListSize); ++i) { - OS << "0, "; - } - OS << "}, "; - OS << "\n"; - } - OS << " };\n"; - - OS << " switch (Opcode) {\n"; - OS << " default: return LogicalOpIdx;\n"; - for (auto &P : InstMap) { - auto OpMapIdx = P.first; - const auto &Insts = P.second; - for (const auto &Inst : Insts) { - OS << " case " << Inst << ":\n"; - } - OS << " return SizeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; - } - OS << " }\n"; + PI.instrInfoEmitGetLogicalOpSizeTable(LogicalOpListSize, LogicalOpSizeList); + + PI.instrInfoEmitGetLogicalOpSizeSwitch(InstMap); } else { - OS << " return LogicalOpIdx;\n"; + PI.instrInfoEmitGetLogicalOpSizeReturn(); } - OS << "}\n"; - - OS << "LLVM_READONLY static inline unsigned\n"; - OS << "getLogicalOperandIdx(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; - OS << " auto S = 0U;\n"; - OS << " for (auto i = 0U; i < LogicalOpIdx; ++i)\n"; - OS << " S += getLogicalOperandSize(Opcode, i);\n"; - OS << " return S;\n"; - OS << "}\n"; - - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n\n"; + PI.instrInfoEmitGetLogicalOpSizeEnd(); + + PI.instrInfoEmitGetLogicalOpIdx(); + + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP", false); } void InstrInfoEmitter::emitLogicalOperandTypeMappings( - raw_ostream &OS, StringRef Namespace, + StringRef Namespace, ArrayRef NumberedInstructions) { std::map, unsigned> LogicalOpTypeMap; @@ -602,7 +404,7 @@ void InstrInfoEmitter::emitLogicalOperandTypeMappings( OpR->isSubClassOf("RegisterClass")) && !OpR->isAnonymous()) { LogicalOpTypeList.push_back( - (Namespace + "::OpTypes::" + Op.Rec->getName()).str()); + PI.instrInfoGetOpTypeListEntry(Namespace, Op.Rec->getName())); } else { LogicalOpTypeList.push_back("-1"); } @@ -613,144 +415,78 @@ void InstrInfoEmitter::emitLogicalOperandTypeMappings( LogicalOpTypeMap.insert({LogicalOpTypeList, LogicalOpTypeMap.size()}) .first; InstMap[I->second].push_back( - (Namespace + "::" + Inst->TheDef->getName()).str()); + PI.instrInfoGetInstMapEntry(Namespace, Inst->TheDef->getName())); } - OS << "#ifdef GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n"; - OS << "#undef GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n"; - OS << "namespace llvm {\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "LLVM_READONLY static int\n"; - OS << "getLogicalOperandType(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + PI.emitIncludeToggle("GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Namespace.str(), true); + PI.instrInfoEmitGetLogicalOpTypeHdr(); if (!InstMap.empty()) { std::vector *> LogicalOpTypeList( LogicalOpTypeMap.size()); for (auto &P : LogicalOpTypeMap) { LogicalOpTypeList[P.second] = &P.first; } - OS << " static const int TypeMap[][" << OpTypeListSize << "] = {\n"; - for (int r = 0, rs = LogicalOpTypeList.size(); r < rs; ++r) { - const auto &Row = *LogicalOpTypeList[r]; - OS << " {"; - int i, s = Row.size(); - for (i = 0; i < s; ++i) { - if (i > 0) - OS << ", "; - OS << Row[i]; - } - for (; i < static_cast(OpTypeListSize); ++i) { - if (i > 0) - OS << ", "; - OS << "-1"; - } - OS << "}"; - if (r != rs - 1) - OS << ","; - OS << "\n"; - } - OS << " };\n"; - - OS << " switch (Opcode) {\n"; - OS << " default: return -1;\n"; - for (auto &P : InstMap) { - auto OpMapIdx = P.first; - const auto &Insts = P.second; - for (const auto &Inst : Insts) { - OS << " case " << Inst << ":\n"; - } - OS << " return TypeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; - } - OS << " }\n"; + PI.instrInfoEmitGetLogicalOpTypeTable(OpTypeListSize, + LogicalOpTypeList); + PI.instrInfoEmitGetLogicalOpTypeSwitch(InstMap); } else { - OS << " return -1;\n"; + PI.instrInfoEmitGetLogicalOpTypeReturn(); } - OS << "}\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n\n"; + PI.instrInfoEmitGetLogicalOpTypeEnd(); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP", false); } -void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS, +void InstrInfoEmitter::emitMCIIHelperMethods( StringRef TargetName) { RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); - OS << "#ifdef GET_INSTRINFO_MC_HELPER_DECLS\n"; - OS << "#undef GET_INSTRINFO_MC_HELPER_DECLS\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_HELPER_DECLS", true); + PI.emitNamespace("llvm", true); + PI.instrInfoEmitDeclareMCInstFeatureClasses(); - OS << "namespace llvm {\n"; - OS << "class MCInst;\n"; - OS << "class FeatureBitset;\n\n"; + PI.emitNamespace(TargetName.str() + "_MC", true); - OS << "namespace " << TargetName << "_MC {\n\n"; + PI.instrInfoEmitPredFcnDecl(TIIPredicates); - for (const Record *Rec : TIIPredicates) { - OS << "bool " << Rec->getValueAsString("FunctionName") - << "(const MCInst &MI);\n"; - } - - OS << "void verifyInstructionPredicates(unsigned Opcode, const FeatureBitset " - "&Features);\n"; - - OS << "\n} // end namespace " << TargetName << "_MC\n"; - OS << "} // end namespace llvm\n\n"; + PI.emitNamespace(TargetName.str() + "_MC", false); + PI.emitNamespace("llvm", false); - OS << "#endif // GET_INSTRINFO_MC_HELPER_DECLS\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_HELPER_DECLS", false); - OS << "#ifdef GET_INSTRINFO_MC_HELPERS\n"; - OS << "#undef GET_INSTRINFO_MC_HELPERS\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_HELPERS", true); - OS << "namespace llvm {\n"; - OS << "namespace " << TargetName << "_MC {\n\n"; + PI.emitNamespace("llvm", true); + PI.emitNamespace(TargetName.str() + "_MC", true); - PredicateExpander PE(TargetName); - PE.setExpandForMC(true); - - for (const Record *Rec : TIIPredicates) { - OS << "bool " << Rec->getValueAsString("FunctionName"); - OS << "(const MCInst &MI) {\n"; - - OS.indent(PE.getIndentLevel() * 2); - PE.expandStatement(OS, Rec->getValueAsDef("Body")); - OS << "\n}\n\n"; - } + PI.instrInfoEmitPredFcnImpl(TargetName, TIIPredicates); - OS << "} // end namespace " << TargetName << "_MC\n"; - OS << "} // end namespace llvm\n\n"; + PI.emitNamespace(TargetName.str() + "_MC", false); + PI.emitNamespace("llvm", false); - OS << "#endif // GET_GENISTRINFO_MC_HELPERS\n\n"; + // Typo in LLVM source + PI.emitIncludeToggle("GET_GENISTRINFO_MC_HELPERS", false); } -static std::string -getNameForFeatureBitset(const std::vector &FeatureBitset) { - std::string Name = "CEFBS"; - for (const auto &Feature : FeatureBitset) - Name += ("_" + Feature->getName()).str(); - return Name; -} - -void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS, +void InstrInfoEmitter::emitFeatureVerifier( const CodeGenTarget &Target) { const auto &All = SubtargetFeatureInfo::getAll(Records); std::map SubtargetFeatures; SubtargetFeatures.insert(All.begin(), All.end()); - OS << "#if (defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)) " - << "||\\\n" - << " defined(GET_AVAILABLE_OPCODE_CHECKER)\n" - << "#define GET_COMPUTE_FEATURES\n" - << "#endif\n"; - OS << "#ifdef GET_COMPUTE_FEATURES\n" - << "#undef GET_COMPUTE_FEATURES\n" - << "namespace llvm {\n" - << "namespace " << Target.getName() << "_MC {\n\n"; + PI.emitIncludeToggle("GET_COMPUTE_FEATURES", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Target.getName().str() + "_MC", true); // Emit the subtarget feature enumeration. - SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, - OS); + PI.instrInfoEmitSubtargetFeatureBitEnumeration(SubtargetFeatures); + // Emit the available features compute function. - OS << "inline "; - SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( - Target.getName(), "", "computeAvailableFeatures", SubtargetFeatures, OS); + PI.instrInfoEmitComputeAssemblerAvailableFeatures(Target.getName(), + SubtargetFeatures); std::vector> FeatureBitsets; for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { @@ -779,142 +515,49 @@ void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS, FeatureBitsets.erase( std::unique(FeatureBitsets.begin(), FeatureBitsets.end()), FeatureBitsets.end()); - OS << "inline FeatureBitset computeRequiredFeatures(unsigned Opcode) {\n" - << " enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n" - << " CEFBS_None,\n"; - for (const auto &FeatureBitset : FeatureBitsets) { - if (FeatureBitset.empty()) - continue; - OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; - } - OS << " };\n\n" - << " static constexpr FeatureBitset FeatureBitsets[] = {\n" - << " {}, // CEFBS_None\n"; - for (const auto &FeatureBitset : FeatureBitsets) { - if (FeatureBitset.empty()) - continue; - OS << " {"; - for (const auto &Feature : FeatureBitset) { - const auto &I = SubtargetFeatures.find(Feature); - assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); - OS << I->second.getEnumBitName() << ", "; - } - OS << "},\n"; - } - OS << " };\n" - << " static constexpr " << getMinimalTypeForRange(FeatureBitsets.size()) - << " RequiredFeaturesRefs[] = {\n"; - unsigned InstIdx = 0; - for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { - OS << " CEFBS"; - unsigned NumPredicates = 0; - for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) { - const auto &I = SubtargetFeatures.find(Predicate); - if (I != SubtargetFeatures.end()) { - OS << '_' << I->second.TheDef->getName(); - NumPredicates++; - } - } - if (!NumPredicates) - OS << "_None"; - OS << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n"; - InstIdx++; - } - OS << " };\n\n" - << " assert(Opcode < " << InstIdx << ");\n" - << " return FeatureBitsets[RequiredFeaturesRefs[Opcode]];\n" - << "}\n\n"; - - OS << "} // end namespace " << Target.getName() << "_MC\n" - << "} // end namespace llvm\n" - << "#endif // GET_COMPUTE_FEATURES\n\n"; - - OS << "#ifdef GET_AVAILABLE_OPCODE_CHECKER\n" - << "#undef GET_AVAILABLE_OPCODE_CHECKER\n" - << "namespace llvm {\n" - << "namespace " << Target.getName() << "_MC {\n"; - OS << "bool isOpcodeAvailable(" - << "unsigned Opcode, const FeatureBitset &Features) {\n" - << " FeatureBitset AvailableFeatures = " - << "computeAvailableFeatures(Features);\n" - << " FeatureBitset RequiredFeatures = " - << "computeRequiredFeatures(Opcode);\n" - << " FeatureBitset MissingFeatures =\n" - << " (AvailableFeatures & RequiredFeatures) ^\n" - << " RequiredFeatures;\n" - << " return !MissingFeatures.any();\n" - << "}\n"; - OS << "} // end namespace " << Target.getName() << "_MC\n" - << "} // end namespace llvm\n" - << "#endif // GET_AVAILABLE_OPCODE_CHECKER\n\n"; - - OS << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n" - << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n" - << "#include \n\n"; - - OS << "namespace llvm {\n"; - OS << "namespace " << Target.getName() << "_MC {\n\n"; + PI.instrInfoEmitFeatureBitsEnum(FeatureBitsets); + PI.instrInfoEmitFeatureBitsArray(FeatureBitsets, SubtargetFeatures); + + // Emit the predicate verifier. + PI.instrInfoEmitRequiredFeatureRefs(FeatureBitsets, SubtargetFeatures, Target); + PI.emitNamespace(Target.getName().str() + "_MC", false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_COMPUTE_FEATURES", false); + + PI.emitIncludeToggle("GET_AVAILABLE_OPCODE_CHECKER", true); + PI.emitNamespace("llvm", true); + PI.emitNamespace(Target.getName().str() + "_MC", true); + PI.instrInfoEmitOpcodeChecker(); + PI.emitNamespace(Target.getName().str() + "_MC", false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_AVAILABLE_OPCODE_CHECKER", false); + + PI.emitIncludeToggle("ENABLE_INSTR_PREDICATE_VERIFIER", true); + PI.instrInfoEmitInstrPredVerifierIncludes(); + + PI.emitNamespace("llvm", true); + PI.emitNamespace(Target.getName().str() + "_MC", true); // Emit the name table for error messages. - OS << "#ifndef NDEBUG\n"; - SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); - OS << "#endif // NDEBUG\n\n"; + PI.instrInfoEmitEmitSTFNameTable(SubtargetFeatures); // Emit the predicate verifier. - OS << "void verifyInstructionPredicates(\n" - << " unsigned Opcode, const FeatureBitset &Features) {\n" - << "#ifndef NDEBUG\n"; - OS << " FeatureBitset AvailableFeatures = " - "computeAvailableFeatures(Features);\n"; - OS << " FeatureBitset RequiredFeatures = " - << "computeRequiredFeatures(Opcode);\n"; - OS << " FeatureBitset MissingFeatures =\n" - << " (AvailableFeatures & RequiredFeatures) ^\n" - << " RequiredFeatures;\n" - << " if (MissingFeatures.any()) {\n" - << " std::ostringstream Msg;\n" - << " Msg << \"Attempting to emit \" << &" << Target.getName() - << "InstrNameData[" << Target.getName() << "InstrNameIndices[Opcode]]\n" - << " << \" instruction but the \";\n" - << " for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)\n" - << " if (MissingFeatures.test(i))\n" - << " Msg << SubtargetFeatureNames[i] << \" \";\n" - << " Msg << \"predicate(s) are not met\";\n" - << " report_fatal_error(Msg.str().c_str());\n" - << " }\n" - << "#endif // NDEBUG\n"; - OS << "}\n"; - OS << "} // end namespace " << Target.getName() << "_MC\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // ENABLE_INSTR_PREDICATE_VERIFIER\n\n"; + PI.instrInfoEmitPredicateVerifier(Target.getName()); + PI.emitNamespace(Target.getName().str() + "_MC", false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("ENABLE_INSTR_PREDICATE_VERIFIER", false); } -void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS, +void InstrInfoEmitter::emitTIIHelperMethods( StringRef TargetName, bool ExpandDefinition) { RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); if (TIIPredicates.empty()) return; - PredicateExpander PE(TargetName); - PE.setExpandForMC(false); - - for (const Record *Rec : TIIPredicates) { - OS << (ExpandDefinition ? "" : "static ") << "bool "; - if (ExpandDefinition) - OS << TargetName << "InstrInfo::"; - OS << Rec->getValueAsString("FunctionName"); - OS << "(const MachineInstr &MI)"; - if (!ExpandDefinition) { - OS << ";\n"; - continue; - } - - OS << " {\n"; - OS.indent(PE.getIndentLevel() * 2); - PE.expandStatement(OS, Rec->getValueAsDef("Body")); - OS << "\n}\n\n"; - } + PI.instrInfoEmitTIIPredicates(TargetName, + TIIPredicates, + ExpandDefinition); } //===----------------------------------------------------------------------===// @@ -922,9 +565,9 @@ void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS, //===----------------------------------------------------------------------===// // run - Emit the main instruction description records for the target... -void InstrInfoEmitter::run(raw_ostream &OS) { - emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS); - emitEnums(OS); +void InstrInfoEmitter::run() { + PI.instrInfoEmitSourceFileHeader(); + emitEnums(); CodeGenTarget &Target = CDP.getTargetInfo(); const std::string &TargetName = std::string(Target.getName()); @@ -953,80 +596,52 @@ void InstrInfoEmitter::run(raw_ostream &OS) { ArrayRef NumberedInstructions = Target.getInstructionsByEnumValue(); - OS << "#if defined(GET_INSTRINFO_MC_DESC) || " - "defined(GET_INSTRINFO_CTOR_DTOR)\n"; - OS << "namespace llvm {\n\n"; - - OS << "struct " << TargetName << "InstrTable {\n"; - OS << " MCInstrDesc Insts[" << NumberedInstructions.size() << "];\n"; - OS << " static_assert(alignof(MCInstrDesc) >= alignof(MCOperandInfo), " - "\"Unwanted padding between Insts and OperandInfo\");\n"; - OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n"; - OS << " static_assert(alignof(MCOperandInfo) >= alignof(MCPhysReg), " - "\"Unwanted padding between OperandInfo and ImplicitOps\");\n"; - OS << " MCPhysReg ImplicitOps[" << std::max(ImplicitListSize, 1U) << "];\n"; - OS << "};\n\n"; - - OS << "} // end namespace llvm\n"; - OS << "#endif // defined(GET_INSTRINFO_MC_DESC) || " - "defined(GET_INSTRINFO_CTOR_DTOR)\n\n"; - - OS << "#ifdef GET_INSTRINFO_MC_DESC\n"; - OS << "#undef GET_INSTRINFO_MC_DESC\n"; - OS << "namespace llvm {\n\n"; - - // Emit all of the MCInstrDesc records in reverse ENUM ordering. + PI.emitPPIf("defined(GET_INSTRINFO_MC_DESC) || defined(GET_INSTRINFO_CTOR_DTOR)", true); + PI.emitNamespace("llvm", true); + + PI.instrInfoEmitMCInstrDescDecl(TargetName, + NumberedInstructions.size(), + OperandInfoSize, + std::max(ImplicitListSize, 1U)); + + PI.emitNamespace("llvm", false); + PI.emitPPIf("defined(GET_INSTRINFO_MC_DESC) || defined(GET_INSTRINFO_CTOR_DTOR)", false); + + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", true); + PI.emitNamespace("llvm", true); + + // Emit all of the MCInstrDesc records in ascending ENUM ordering. Records.startTimer("Emit InstrDesc records"); - OS << "static_assert(sizeof(MCOperandInfo) % sizeof(MCPhysReg) == 0);\n"; - OS << "static constexpr unsigned " << TargetName << "ImpOpBase = sizeof " - << TargetName << "InstrTable::OperandInfo / (sizeof(MCPhysReg));\n\n"; - OS << "extern const " << TargetName << "InstrTable " << TargetName - << "Descs = {\n {\n"; + PI.instrInfoEmitMCInstrDescHdr(TargetName); SequenceToOffsetTable InstrNames; unsigned Num = NumberedInstructions.size(); for (const CodeGenInstruction *Inst : reverse(NumberedInstructions)) { // Keep a list of the instruction names. InstrNames.add(std::string(Inst->TheDef->getName())); // Emit the record into the table. - emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoMap, OS); + emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoMap); } - OS << " }, {\n"; + PI.instrInfoEmitMCInstrDescClose(); // Emit all of the operand info records. Records.startTimer("Emit operand info"); - EmitOperandInfo(OS, OperandInfoList); + EmitOperandInfo(OperandInfoList); - OS << " }, {\n"; + PI.instrInfoEmitMCInstrDescClose(); // Emit all of the instruction's implicit uses and defs. Records.startTimer("Emit uses/defs"); - for (auto &List : ImplicitLists) { - OS << " /* " << EmittedLists[List] << " */"; - for (auto &Reg : List) - OS << ' ' << getQualifiedName(Reg) << ','; - OS << '\n'; - } - - OS << " }\n};\n\n"; + PI.instrInfoEmitMCInstrImplUses(ImplicitLists, EmittedLists); + PI.instrInfoEmitMCInstrDescEnd(); // Emit the array of instruction names. Records.startTimer("Emit instruction names"); InstrNames.layout(); - InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + - "InstrNameData[]"); + PI.instrInfoEmitStringLiteralDef(TargetName, InstrNames); - OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {"; - Num = 0; - for (const CodeGenInstruction *Inst : NumberedInstructions) { - // Newline every eight entries. - if (Num % 8 == 0) - OS << "\n "; - OS << InstrNames.get(std::string(Inst->TheDef->getName())) << "U, "; - ++Num; - } - OS << "\n};\n\n"; + PI.instrInfoEmitInstrNameIndices(TargetName, NumberedInstructions, InstrNames); bool HasDeprecationFeatures = llvm::any_of(NumberedInstructions, [](const CodeGenInstruction *Inst) { @@ -1034,21 +649,10 @@ void InstrInfoEmitter::run(raw_ostream &OS) { !Inst->DeprecatedReason.empty(); }); if (HasDeprecationFeatures) { - OS << "extern const uint8_t " << TargetName - << "InstrDeprecationFeatures[] = {"; - Num = 0; - for (const CodeGenInstruction *Inst : NumberedInstructions) { - if (Num % 8 == 0) - OS << "\n "; - if (!Inst->HasComplexDeprecationPredicate && - !Inst->DeprecatedReason.empty()) - OS << Target.getInstNamespace() << "::" << Inst->DeprecatedReason - << ", "; - else - OS << "uint8_t(-1), "; - ++Num; - } - OS << "\n};\n\n"; + PI.instrInfoEmitInstrDeprFeatures(TargetName, + Target.getInstNamespace().str(), + NumberedInstructions, + InstrNames); } bool HasComplexDeprecationInfos = @@ -1056,195 +660,94 @@ void InstrInfoEmitter::run(raw_ostream &OS) { return Inst->HasComplexDeprecationPredicate; }); if (HasComplexDeprecationInfos) { - OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName - << "InstrComplexDeprecationInfos[] = {"; - Num = 0; - for (const CodeGenInstruction *Inst : NumberedInstructions) { - if (Num % 8 == 0) - OS << "\n "; - if (Inst->HasComplexDeprecationPredicate) - // Emit a function pointer to the complex predicate method. - OS << "&get" << Inst->DeprecatedReason << "DeprecationInfo, "; - else - OS << "nullptr, "; - ++Num; - } - OS << "\n};\n\n"; + PI.instrInfoEmitInstrComplexDeprInfos(TargetName, + NumberedInstructions); } // MCInstrInfo initialization routine. Records.startTimer("Emit initialization routine"); - OS << "static inline void Init" << TargetName - << "MCInstrInfo(MCInstrInfo *II) {\n"; - OS << " II->InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName - << "InstrNameIndices, " << TargetName << "InstrNameData, "; - if (HasDeprecationFeatures) - OS << TargetName << "InstrDeprecationFeatures, "; - else - OS << "nullptr, "; - if (HasComplexDeprecationInfos) - OS << TargetName << "InstrComplexDeprecationInfos, "; - else - OS << "nullptr, "; - OS << NumberedInstructions.size() << ");\n}\n\n"; - - OS << "} // end namespace llvm\n"; - - OS << "#endif // GET_INSTRINFO_MC_DESC\n\n"; - - // Create a TargetInstrInfo subclass to hide the MC layer initialization. - OS << "#ifdef GET_INSTRINFO_HEADER\n"; - OS << "#undef GET_INSTRINFO_HEADER\n"; - - std::string ClassName = TargetName + "GenInstrInfo"; - OS << "namespace llvm {\n"; - OS << "struct " << ClassName << " : public TargetInstrInfo {\n" - << " explicit " << ClassName - << "(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, " - "unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u);\n" - << " ~" << ClassName << "() override = default;\n"; - - - OS << "\n};\n} // end namespace llvm\n"; - - OS << "#endif // GET_INSTRINFO_HEADER\n\n"; - - OS << "#ifdef GET_INSTRINFO_HELPER_DECLS\n"; - OS << "#undef GET_INSTRINFO_HELPER_DECLS\n\n"; - emitTIIHelperMethods(OS, TargetName, /* ExpandDefinition = */ false); - OS << "\n"; - OS << "#endif // GET_INSTRINFO_HELPER_DECLS\n\n"; - - OS << "#ifdef GET_INSTRINFO_HELPERS\n"; - OS << "#undef GET_INSTRINFO_HELPERS\n\n"; - emitTIIHelperMethods(OS, TargetName, /* ExpandDefinition = */ true); - OS << "#endif // GET_INSTRINFO_HELPERS\n\n"; - - OS << "#ifdef GET_INSTRINFO_CTOR_DTOR\n"; - OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; - - OS << "namespace llvm {\n"; - OS << "extern const " << TargetName << "InstrTable " << TargetName - << "Descs;\n"; - OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; - OS << "extern const char " << TargetName << "InstrNameData[];\n"; - if (HasDeprecationFeatures) - OS << "extern const uint8_t " << TargetName - << "InstrDeprecationFeatures[];\n"; - if (HasComplexDeprecationInfos) - OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName - << "InstrComplexDeprecationInfos[];\n"; - OS << ClassName << "::" << ClassName - << "(unsigned CFSetupOpcode, unsigned CFDestroyOpcode, unsigned " - "CatchRetOpcode, unsigned ReturnOpcode)\n" - << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, " - "ReturnOpcode) {\n" - << " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName - << "InstrNameIndices, " << TargetName << "InstrNameData, "; - if (HasDeprecationFeatures) - OS << TargetName << "InstrDeprecationFeatures, "; - else - OS << "nullptr, "; - if (HasComplexDeprecationInfos) - OS << TargetName << "InstrComplexDeprecationInfos, "; - else - OS << "nullptr, "; - OS << NumberedInstructions.size() << ");\n}\n"; - OS << "} // end namespace llvm\n"; - - OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; + + PI.instrInfoEmitMCInstrInfoInitRoutine(TargetName, + NumberedInstructions.size(), + HasDeprecationFeatures, + HasComplexDeprecationInfos); + + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", false); + + PI.emitIncludeToggle("GET_INSTRINFO_HEADER", true); + PI.emitNamespace("llvm", true); + PI.instrInfoEmitHeader(Target.getName().str()); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_HEADER", false); + + PI.emitIncludeToggle("GET_INSTRINFO_HELPER_DECLS", true); + emitTIIHelperMethods(TargetName, /* ExpandDefinition = */ false); + PI.emitIncludeToggle("GET_INSTRINFO_HELPER_DECLS", false); + + PI.emitIncludeToggle("GET_INSTRINFO_HELPERS", true); + emitTIIHelperMethods(TargetName, /* ExpandDefinition = */ true); + PI.emitIncludeToggle("GET_INSTRINFO_HELPERS", false); + + PI.emitIncludeToggle("GET_INSTRINFO_CTOR_DTOR", true); + PI.emitNamespace("llvm", true); + + PI.instrInfoEmitExternArrays(TargetName, + HasDeprecationFeatures, + HasComplexDeprecationInfos); + PI.instrInfoEmitMCInstrInfoInit(TargetName, + NumberedInstructions.size(), + HasDeprecationFeatures, + HasComplexDeprecationInfos); + PI.emitNamespace("llvm", false); + + PI.emitIncludeToggle("GET_INSTRINFO_CTOR_DTOR", false); Records.startTimer("Emit operand name mappings"); - emitOperandNameMappings(OS, Target, NumberedInstructions); + emitOperandNameMappings(Target, NumberedInstructions); Records.startTimer("Emit operand type mappings"); - emitOperandTypeMappings(OS, Target, NumberedInstructions); + emitOperandTypeMappings(Target, NumberedInstructions); Records.startTimer("Emit logical operand size mappings"); - emitLogicalOperandSizeMappings(OS, TargetName, NumberedInstructions); + emitLogicalOperandSizeMappings(TargetName, NumberedInstructions); Records.startTimer("Emit logical operand type mappings"); - emitLogicalOperandTypeMappings(OS, TargetName, NumberedInstructions); + emitLogicalOperandTypeMappings(TargetName, NumberedInstructions); Records.startTimer("Emit helper methods"); - emitMCIIHelperMethods(OS, TargetName); + emitMCIIHelperMethods(TargetName); + PI.instrInfoEmitSetGetComputeFeatureMacro(); Records.startTimer("Emit verifier methods"); - emitFeatureVerifier(OS, Target); + emitFeatureVerifier(Target); } void InstrInfoEmitter::emitRecord( const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, - std::map, unsigned> &EmittedLists, - const OperandInfoMapTy &OperandInfoMap, raw_ostream &OS) { + std::map, unsigned> &EmittedLists, + const OperandInfoMapTy &OperandInfoMap) { int MinOperands = 0; if (!Inst.Operands.empty()) // Each logical operand can be multiple MI operands. MinOperands = Inst.Operands.back().MIOperandNo + Inst.Operands.back().MINumOperands; - OS << " { "; - OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t" - << Inst.TheDef->getValueAsInt("Size") << ",\t" - << SchedModels.getSchedClassIdx(Inst) << ",\t"; + PI.instrInfoEmitRecord(SchedModels, Inst, Num, MinOperands); CodeGenTarget &Target = CDP.getTargetInfo(); // Emit the implicit use/def list... - OS << Inst.ImplicitUses.size() << ",\t" << Inst.ImplicitDefs.size() << ",\t"; std::vector ImplicitOps = Inst.ImplicitUses; llvm::append_range(ImplicitOps, Inst.ImplicitDefs); - OS << Target.getName() << "ImpOpBase + " << EmittedLists[ImplicitOps] - << ",\t"; + PI.instrInfoEmitUseDefsLists(Target.getName(), Inst, EmittedLists, ImplicitOps); // Emit the operand info offset. OperandInfoTy OperandInfo = GetOperandInfo(Inst); - OS << OperandInfoMap.find(OperandInfo)->second << ",\t0"; + PI.instrInfoEmitOperandInfoOffset(Target.getName(), OperandInfo, OperandInfoMap); // Emit all of the target independent flags... - if (Inst.isPreISelOpcode) OS << "|(1ULL<getValueAsBitsInit("TSFlags"); @@ -1258,62 +761,40 @@ void InstrInfoEmitter::emitRecord( PrintFatalError(Inst.TheDef->getLoc(), "Invalid TSFlags bit in " + Inst.TheDef->getName()); } - OS << ", 0x"; - OS.write_hex(Value); - OS << "ULL"; + PI.instrInfoEmitTSFFlags(Value); - OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; + PI.instrInfoEmitRecordEnd(Num, Inst.TheDef->getName().str()); } // emitEnums - Print out enum values for all of the instructions. -void InstrInfoEmitter::emitEnums(raw_ostream &OS) { - OS << "#ifdef GET_INSTRINFO_ENUM\n"; - OS << "#undef GET_INSTRINFO_ENUM\n"; - - OS << "namespace llvm {\n\n"; - +void InstrInfoEmitter::emitEnums() { const CodeGenTarget &Target = CDP.getTargetInfo(); // We must emit the PHI opcode first... StringRef Namespace = Target.getInstNamespace(); - if (Namespace.empty()) PrintFatalError("No instructions defined!"); - - OS << "namespace " << Namespace << " {\n"; - OS << " enum {\n"; - unsigned Num = 0; - for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) - OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n"; - OS << " INSTRUCTION_LIST_END = " << Num << "\n"; - OS << " };\n\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_ENUM\n\n"; - - OS << "#ifdef GET_INSTRINFO_SCHED_ENUM\n"; - OS << "#undef GET_INSTRINFO_SCHED_ENUM\n"; - OS << "namespace llvm {\n\n"; - OS << "namespace " << Namespace << " {\n"; - OS << "namespace Sched {\n"; - OS << " enum {\n"; - Num = 0; - for (const auto &Class : SchedModels.explicit_classes()) - OS << " " << Class.Name << "\t= " << Num++ << ",\n"; - OS << " SCHED_LIST_END = " << Num << "\n"; - OS << " };\n"; - OS << "} // end namespace Sched\n"; - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - - OS << "#endif // GET_INSTRINFO_SCHED_ENUM\n\n"; + PI.instrInfoEmitEnums(Target, Namespace, SchedModels); } -static void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) { +void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) { + formatted_raw_ostream FOS(OS); + PrinterLLVM *PI; + PrinterLanguage const PL = PrinterLLVM::getLanguage(); + + if (PL == PRINTER_LANG_CPP) { + PI = new PrinterLLVM(FOS); + } else if (PL == PRINTER_LANG_CAPSTONE_C) { + PI = new PrinterCapstone(FOS); + } else { + llvm_unreachable("InstrInfoEmitter does not support the given output language."); + } + RK.startTimer("Analyze DAG patterns"); - InstrInfoEmitter(RK).run(OS); + InstrInfoEmitter(RK, *PI).run(); RK.startTimer("Emit map table"); - EmitMapTable(RK, OS); + EmitMapTable(RK, OS, PL == PRINTER_LANG_CAPSTONE_C); + delete PI; } static TableGen::Emitter::Opt X("gen-instr-info", EmitInstrInfo, diff --git a/llvm/utils/TableGen/InstrInfoEmitterTypes.h b/llvm/utils/TableGen/InstrInfoEmitterTypes.h new file mode 100644 index 000000000000..93d9627cc7c5 --- /dev/null +++ b/llvm/utils/TableGen/InstrInfoEmitterTypes.h @@ -0,0 +1,49 @@ +//===---- InstrInfoEmitterTypes.h - Instruction Set Desc. ----*- 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 +// +//===------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_INSTRINFOEMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_INSTRINFOEMITTERTYPES_H + +#include "CodeGenDAGPatterns.h" +#include "CodeGenInstruction.h" +#include "CodeGenSchedule.h" +#include "CodeGenTarget.h" +#include "PredicateExpander.h" +#include "SequenceToOffsetTable.h" +#include "SubtargetFeatureInfo.h" +#include "TableGenBackends.h" +#include "Types.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +#include +#include +#include +#include + +typedef std::vector OperandInfoTy; +typedef std::vector OperandInfoListTy; +typedef std::map OperandInfoMapTy; + +/// The keys of this map are maps which have OpName enum values as their keys +/// and instruction operand indices as their values. The values of this map +/// are lists of instruction names. +typedef std::map, + std::vector> OpNameMapTy; +typedef std::map::iterator StrUintMapIter; + +#endif // LLVM_UTILS_TABLEGEN_INSTRINFOEMITTERTYPES_H diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp index 7f494e532b1f..c25175273a46 100644 --- a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp +++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp @@ -218,7 +218,7 @@ void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { // Emit file header. emitSourceFileHeader("Macro Fusion Predicators", OS); - PredicateExpander PE(Target.getName()); + PredicateExpanderLLVM PE(Target.getName()); PE.setByRef(false); PE.setExpandForMC(false); diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp index 0b9b6389fe38..7877f6e7038d 100644 --- a/llvm/utils/TableGen/PredicateExpander.cpp +++ b/llvm/utils/TableGen/PredicateExpander.cpp @@ -16,12 +16,12 @@ namespace llvm { -void PredicateExpander::expandTrue(raw_ostream &OS) { OS << "true"; } -void PredicateExpander::expandFalse(raw_ostream &OS) { OS << "false"; } +void PredicateExpanderLLVM::expandTrue(raw_ostream &OS) { OS << "true"; } +void PredicateExpanderLLVM::expandFalse(raw_ostream &OS) { OS << "false"; } -void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex, - int ImmVal, - StringRef FunctionMapper) { +void PredicateExpanderLLVM::expandCheckImmOperand(raw_ostream &OS, int OpIndex, + int ImmVal, + StringRef FunctionMapper) { if (!FunctionMapper.empty()) OS << FunctionMapper << "("; OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex @@ -31,9 +31,9 @@ void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex, OS << (shouldNegate() ? " != " : " == ") << ImmVal; } -void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex, - StringRef ImmVal, - StringRef FunctionMapper) { +void PredicateExpanderLLVM::expandCheckImmOperand(raw_ostream &OS, int OpIndex, + StringRef ImmVal, + StringRef FunctionMapper) { if (ImmVal.empty()) expandCheckImmOperandSimple(OS, OpIndex, FunctionMapper); @@ -46,9 +46,8 @@ void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex, OS << (shouldNegate() ? " != " : " == ") << ImmVal; } -void PredicateExpander::expandCheckImmOperandSimple(raw_ostream &OS, - int OpIndex, - StringRef FunctionMapper) { +void PredicateExpanderLLVM::expandCheckImmOperandSimple( + raw_ostream &OS, int OpIndex, StringRef FunctionMapper) { if (shouldNegate()) OS << "!"; if (!FunctionMapper.empty()) @@ -59,7 +58,7 @@ void PredicateExpander::expandCheckImmOperandSimple(raw_ostream &OS, OS << ")"; } -void PredicateExpander::expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, +void PredicateExpanderLLVM::expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal, StringRef FunctionMapper) { if (!FunctionMapper.empty()) @@ -71,9 +70,9 @@ void PredicateExpander::expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, OS << (shouldNegate() ? " >= " : " < ") << ImmVal; } -void PredicateExpander::expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, +void PredicateExpanderLLVM::expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal, - StringRef FunctionMapper) { + StringRef FunctionMapper) { if (!FunctionMapper.empty()) OS << FunctionMapper << "("; OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex @@ -83,9 +82,9 @@ void PredicateExpander::expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, OS << (shouldNegate() ? " <= " : " > ") << ImmVal; } -void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex, - const Record *Reg, - StringRef FunctionMapper) { +void PredicateExpanderLLVM::expandCheckRegOperand(raw_ostream &OS, int OpIndex, + const Record *Reg, + StringRef FunctionMapper) { assert(Reg->isSubClassOf("Register") && "Expected a register Record!"); if (!FunctionMapper.empty()) @@ -101,10 +100,8 @@ void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex, OS << Reg->getName(); } - -void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS, - int OpIndex, - StringRef FunctionMapper) { +void PredicateExpanderLLVM::expandCheckRegOperandSimple( + raw_ostream &OS, int OpIndex, StringRef FunctionMapper) { if (shouldNegate()) OS << "!"; if (!FunctionMapper.empty()) @@ -115,32 +112,34 @@ void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS, OS << ")"; } -void PredicateExpander::expandCheckInvalidRegOperand(raw_ostream &OS, - int OpIndex) { +void PredicateExpanderLLVM::expandCheckInvalidRegOperand(raw_ostream &OS, + int OpIndex) { OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex << ").getReg() " << (shouldNegate() ? "!= " : "== ") << "0"; } -void PredicateExpander::expandCheckSameRegOperand(raw_ostream &OS, int First, - int Second) { +void PredicateExpanderLLVM::expandCheckSameRegOperand(raw_ostream &OS, + int First, int Second) { OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI" << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()"; } -void PredicateExpander::expandCheckNumOperands(raw_ostream &OS, int NumOps) { +void PredicateExpanderLLVM::expandCheckNumOperands(raw_ostream &OS, + int NumOps) { OS << "MI" << (isByRef() ? "." : "->") << "getNumOperands() " << (shouldNegate() ? "!= " : "== ") << NumOps; } -void PredicateExpander::expandCheckOpcode(raw_ostream &OS, const Record *Inst) { +void PredicateExpanderLLVM::expandCheckOpcode(raw_ostream &OS, + const Record *Inst) { OS << "MI" << (isByRef() ? "." : "->") << "getOpcode() " << (shouldNegate() ? "!= " : "== ") << Inst->getValueAsString("Namespace") << "::" << Inst->getName(); } -void PredicateExpander::expandCheckOpcode(raw_ostream &OS, - const RecVec &Opcodes) { +void PredicateExpanderLLVM::expandCheckOpcode(raw_ostream &OS, + const RecVec &Opcodes) { assert(!Opcodes.empty() && "Expected at least one opcode to check!"); bool First = true; @@ -169,17 +168,17 @@ void PredicateExpander::expandCheckOpcode(raw_ostream &OS, OS << ')'; } -void PredicateExpander::expandCheckPseudo(raw_ostream &OS, - const RecVec &Opcodes) { +void PredicateExpanderLLVM::expandCheckPseudo(raw_ostream &OS, + const RecVec &Opcodes) { if (shouldExpandForMC()) expandFalse(OS); else expandCheckOpcode(OS, Opcodes); } -void PredicateExpander::expandPredicateSequence(raw_ostream &OS, - const RecVec &Sequence, - bool IsCheckAll) { +void PredicateExpanderLLVM::expandPredicateSequence(raw_ostream &OS, + const RecVec &Sequence, + bool IsCheckAll) { assert(!Sequence.empty() && "Found an invalid empty predicate set!"); if (Sequence.size() == 1) return expandPredicate(OS, Sequence[0]); @@ -206,29 +205,31 @@ void PredicateExpander::expandPredicateSequence(raw_ostream &OS, setNegatePredicate(OldValue); } -void PredicateExpander::expandTIIFunctionCall(raw_ostream &OS, - StringRef MethodName) { +void PredicateExpanderLLVM::expandTIIFunctionCall(raw_ostream &OS, + StringRef MethodName) { OS << (shouldNegate() ? "!" : ""); OS << TargetName << (shouldExpandForMC() ? "_MC::" : "InstrInfo::"); OS << MethodName << (isByRef() ? "(MI)" : "(*MI)"); } -void PredicateExpander::expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) { +void PredicateExpanderLLVM::expandCheckIsRegOperand(raw_ostream &OS, + int OpIndex) { OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex << ").isReg() "; } -void PredicateExpander::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) { +void PredicateExpanderLLVM::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) { OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex << ").getReg().isVirtual()"; } -void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) { +void PredicateExpanderLLVM::expandCheckIsImmOperand(raw_ostream &OS, + int OpIndex) { OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex << ").isImm() "; } -void PredicateExpander::expandCheckFunctionPredicateWithTII( +void PredicateExpanderLLVM::expandCheckFunctionPredicateWithTII( raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn, StringRef TIIPtr) { if (!shouldExpandForMC()) { @@ -240,23 +241,22 @@ void PredicateExpander::expandCheckFunctionPredicateWithTII( OS << MCInstFn << (isByRef() ? "(MI" : "(*MI") << ", MCII)"; } -void PredicateExpander::expandCheckFunctionPredicate(raw_ostream &OS, - StringRef MCInstFn, - StringRef MachineInstrFn) { +void PredicateExpanderLLVM::expandCheckFunctionPredicate( + raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn) { OS << (shouldExpandForMC() ? MCInstFn : MachineInstrFn) << (isByRef() ? "(MI)" : "(*MI)"); } -void PredicateExpander::expandCheckNonPortable(raw_ostream &OS, - StringRef Code) { +void PredicateExpanderLLVM::expandCheckNonPortable(raw_ostream &OS, + StringRef Code) { if (shouldExpandForMC()) return expandFalse(OS); OS << '(' << Code << ')'; } -void PredicateExpander::expandReturnStatement(raw_ostream &OS, - const Record *Rec) { +void PredicateExpanderLLVM::expandReturnStatement(raw_ostream &OS, + const Record *Rec) { std::string Buffer; raw_string_ostream SS(Buffer); @@ -266,8 +266,8 @@ void PredicateExpander::expandReturnStatement(raw_ostream &OS, OS << Buffer; } -void PredicateExpander::expandOpcodeSwitchCase(raw_ostream &OS, - const Record *Rec) { +void PredicateExpanderLLVM::expandOpcodeSwitchCase(raw_ostream &OS, + const Record *Rec) { const RecVec &Opcodes = Rec->getValueAsListOfDefs("Opcodes"); for (const Record *Opcode : Opcodes) { OS.indent(getIndentLevel() * 2); @@ -281,9 +281,9 @@ void PredicateExpander::expandOpcodeSwitchCase(raw_ostream &OS, decreaseIndentLevel(); } -void PredicateExpander::expandOpcodeSwitchStatement(raw_ostream &OS, - const RecVec &Cases, - const Record *Default) { +void PredicateExpanderLLVM::expandOpcodeSwitchStatement(raw_ostream &OS, + const RecVec &Cases, + const Record *Default) { std::string Buffer; raw_string_ostream SS(Buffer); @@ -308,7 +308,8 @@ void PredicateExpander::expandOpcodeSwitchStatement(raw_ostream &OS, OS << Buffer; } -void PredicateExpander::expandStatement(raw_ostream &OS, const Record *Rec) { +void PredicateExpanderLLVM::expandStatement(raw_ostream &OS, + const Record *Rec) { // Assume that padding has been added by the caller. if (Rec->isSubClassOf("MCOpcodeSwitchStatement")) { expandOpcodeSwitchStatement(OS, Rec->getValueAsListOfDefs("Cases"), @@ -324,7 +325,8 @@ void PredicateExpander::expandStatement(raw_ostream &OS, const Record *Rec) { llvm_unreachable("No known rules to expand this MCStatement"); } -void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) { +void PredicateExpanderLLVM::expandPredicate(raw_ostream &OS, + const Record *Rec) { // Assume that padding has been added by the caller. if (Rec->isSubClassOf("MCTrue")) { if (shouldNegate()) @@ -433,8 +435,573 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) { llvm_unreachable("No known rules to expand this MCInstPredicate"); } -void STIPredicateExpander::expandHeader(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderLLVM::expandHeader(raw_ostream &OS, + const STIPredicateFunction &Fn) { + const Record *Rec = Fn.getDeclaration(); + StringRef FunctionName = Rec->getValueAsString("Name"); + + OS.indent(getIndentLevel() * 2); + OS << "bool "; + if (shouldExpandDefinition()) + OS << getClassPrefix() << "::"; + OS << FunctionName << "("; + if (shouldExpandForMC()) + OS << "const MCInst " << (isByRef() ? "&" : "*") << "MI"; + else + OS << "const MachineInstr " << (isByRef() ? "&" : "*") << "MI"; + if (Rec->getValueAsBit("UpdatesOpcodeMask")) + OS << ", APInt &Mask"; + OS << (shouldExpandForMC() ? ", unsigned ProcessorID) const " : ") const "); + if (shouldExpandDefinition()) { + OS << "{\n"; + return; + } + + if (Rec->getValueAsBit("OverridesBaseClassMember")) + OS << "override"; + OS << ";\n"; +} + +void PredicateExpanderLLVM::expandPrologue(raw_ostream &OS, + const STIPredicateFunction &Fn) { + RecVec Delegates = Fn.getDeclaration()->getValueAsListOfDefs("Delegates"); + bool UpdatesOpcodeMask = + Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); + + increaseIndentLevel(); + unsigned IndentLevel = getIndentLevel(); + for (const Record *Delegate : Delegates) { + OS.indent(IndentLevel * 2); + OS << "if (" << Delegate->getValueAsString("Name") << "(MI"; + if (UpdatesOpcodeMask) + OS << ", Mask"; + if (shouldExpandForMC()) + OS << ", ProcessorID"; + OS << "))\n"; + OS.indent((1 + IndentLevel) * 2); + OS << "return true;\n\n"; + } + + if (shouldExpandForMC()) + return; + + OS.indent(IndentLevel * 2); + OS << "unsigned ProcessorID = getSchedModel().getProcessorID();\n"; +} + +void PredicateExpanderLLVM::expandOpcodeGroup(raw_ostream &OS, + const OpcodeGroup &Group, + bool ShouldUpdateOpcodeMask) { + const OpcodeInfo &OI = Group.getOpcodeInfo(); + for (const PredicateInfo &PI : OI.getPredicates()) { + const APInt &ProcModelMask = PI.ProcModelMask; + bool FirstProcID = true; + for (unsigned I = 0, E = ProcModelMask.getActiveBits(); I < E; ++I) { + if (!ProcModelMask[I]) + continue; + + if (FirstProcID) { + OS.indent(getIndentLevel() * 2); + OS << "if (ProcessorID == " << I; + } else { + OS << " || ProcessorID == " << I; + } + FirstProcID = false; + } + + OS << ") {\n"; + + increaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + if (ShouldUpdateOpcodeMask) { + if (PI.OperandMask.isZero()) + OS << "Mask.clearAllBits();\n"; + else + OS << "Mask = " << PI.OperandMask << ";\n"; + OS.indent(getIndentLevel() * 2); + } + OS << "return "; + expandPredicate(OS, PI.Predicate); + OS << ";\n"; + decreaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + OS << "}\n"; + } +} + +void PredicateExpanderLLVM::expandBody(raw_ostream &OS, + const STIPredicateFunction &Fn) { + bool UpdatesOpcodeMask = + Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); + + unsigned IndentLevel = getIndentLevel(); + OS.indent(IndentLevel * 2); + OS << "switch(MI" << (isByRef() ? "." : "->") << "getOpcode()) {\n"; + OS.indent(IndentLevel * 2); + OS << "default:\n"; + OS.indent(IndentLevel * 2); + OS << " break;"; + + for (const OpcodeGroup &Group : Fn.getGroups()) { + for (const Record *Opcode : Group.getOpcodes()) { + OS << '\n'; + OS.indent(IndentLevel * 2); + OS << "case " << getTargetName() << "::" << Opcode->getName() << ":"; + } + + OS << '\n'; + increaseIndentLevel(); + expandOpcodeGroup(OS, Group, UpdatesOpcodeMask); + + OS.indent(getIndentLevel() * 2); + OS << "break;\n"; + decreaseIndentLevel(); + } + + OS.indent(IndentLevel * 2); + OS << "}\n"; +} + +void PredicateExpanderLLVM::expandEpilogue(raw_ostream &OS, + const STIPredicateFunction &Fn) { + OS << '\n'; + OS.indent(getIndentLevel() * 2); + OS << "return "; + expandPredicate(OS, Fn.getDefaultReturnPredicate()); + OS << ";\n"; + + decreaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + StringRef FunctionName = Fn.getDeclaration()->getValueAsString("Name"); + OS << "} // " << ClassPrefix << "::" << FunctionName << "\n\n"; +} + +void PredicateExpanderLLVM::expandSTIPredicate(raw_ostream &OS, + const STIPredicateFunction &Fn) { + const Record *Rec = Fn.getDeclaration(); + if (shouldExpandForMC() && !Rec->getValueAsBit("ExpandForMC")) + return; + + expandHeader(OS, Fn); + if (shouldExpandDefinition()) { + expandPrologue(OS, Fn); + expandBody(OS, Fn); + expandEpilogue(OS, Fn); + } +} + +//--------------- +// Capstone +//--------------- + +void PredicateExpanderCapstone::expandTrue(raw_ostream &OS) { OS << "true"; } +void PredicateExpanderCapstone::expandFalse(raw_ostream &OS) { OS << "false"; } + +void PredicateExpanderCapstone::expandCheckImmOperand(raw_ostream &OS, int OpIndex, + int ImmVal, + StringRef FunctionMapper) { + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm()"; + if (!FunctionMapper.empty()) + OS << ")"; + OS << (shouldNegate() ? " != " : " == ") << ImmVal; +} + +void PredicateExpanderCapstone::expandCheckImmOperand(raw_ostream &OS, int OpIndex, + StringRef ImmVal, + StringRef FunctionMapper) { + if (ImmVal.empty()) + expandCheckImmOperandSimple(OS, OpIndex, FunctionMapper); + + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm()"; + if (!FunctionMapper.empty()) + OS << ")"; + OS << (shouldNegate() ? " != " : " == ") << ImmVal; +} + +void PredicateExpanderCapstone::expandCheckImmOperandSimple( + raw_ostream &OS, int OpIndex, StringRef FunctionMapper) { + if (shouldNegate()) + OS << "!"; + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm()"; + if (!FunctionMapper.empty()) + OS << ")"; +} + +void PredicateExpanderCapstone::expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, + int ImmVal, + StringRef FunctionMapper) { + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm()"; + if (!FunctionMapper.empty()) + OS << ")"; + OS << (shouldNegate() ? " >= " : " < ") << ImmVal; +} + +void PredicateExpanderCapstone::expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, + int ImmVal, + StringRef FunctionMapper) { + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm()"; + if (!FunctionMapper.empty()) + OS << ")"; + OS << (shouldNegate() ? " <= " : " > ") << ImmVal; +} + +void PredicateExpanderCapstone::expandCheckRegOperand(raw_ostream &OS, int OpIndex, + const Record *Reg, + StringRef FunctionMapper) { + assert(Reg->isSubClassOf("Register") && "Expected a register Record!"); + + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg()"; + if (!FunctionMapper.empty()) + OS << ")"; + OS << (shouldNegate() ? " != " : " == "); + const StringRef Str = Reg->getValueAsString("Namespace"); + if (!Str.empty()) + OS << Str << "::"; + OS << Reg->getName(); +} + +void PredicateExpanderCapstone::expandCheckRegOperandSimple( + raw_ostream &OS, int OpIndex, StringRef FunctionMapper) { + if (shouldNegate()) + OS << "!"; + if (!FunctionMapper.empty()) + OS << FunctionMapper << "("; + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg()"; + if (!FunctionMapper.empty()) + OS << ")"; +} + +void PredicateExpanderCapstone::expandCheckInvalidRegOperand(raw_ostream &OS, + int OpIndex) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg() " << (shouldNegate() ? "!= " : "== ") << "0"; +} + +void PredicateExpanderCapstone::expandCheckSameRegOperand(raw_ostream &OS, + int First, int Second) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First + << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI" + << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()"; +} + +void PredicateExpanderCapstone::expandCheckNumOperands(raw_ostream &OS, + int NumOps) { + OS << "MI" << (isByRef() ? "." : "->") << "getNumOperands() " + << (shouldNegate() ? "!= " : "== ") << NumOps; +} + +void PredicateExpanderCapstone::expandCheckOpcode(raw_ostream &OS, + const Record *Inst) { + OS << "MI" << (isByRef() ? "." : "->") << "getOpcode() " + << (shouldNegate() ? "!= " : "== ") << Inst->getValueAsString("Namespace") + << "::" << Inst->getName(); +} + +void PredicateExpanderCapstone::expandCheckOpcode(raw_ostream &OS, + const RecVec &Opcodes) { + assert(!Opcodes.empty() && "Expected at least one opcode to check!"); + bool First = true; + + if (Opcodes.size() == 1) { + OS << "( "; + expandCheckOpcode(OS, Opcodes[0]); + OS << " )"; + return; + } + + OS << '('; + increaseIndentLevel(); + for (const Record *Rec : Opcodes) { + OS << '\n'; + OS.indent(getIndentLevel() * 2); + if (!First) + OS << (shouldNegate() ? "&& " : "|| "); + + expandCheckOpcode(OS, Rec); + First = false; + } + + OS << '\n'; + decreaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + OS << ')'; +} + +void PredicateExpanderCapstone::expandCheckPseudo(raw_ostream &OS, + const RecVec &Opcodes) { + if (shouldExpandForMC()) + expandFalse(OS); + else + expandCheckOpcode(OS, Opcodes); +} + +void PredicateExpanderCapstone::expandPredicateSequence(raw_ostream &OS, + const RecVec &Sequence, + bool IsCheckAll) { + assert(!Sequence.empty() && "Found an invalid empty predicate set!"); + if (Sequence.size() == 1) + return expandPredicate(OS, Sequence[0]); + + // Okay, there is more than one predicate in the set. + bool First = true; + OS << (shouldNegate() ? "!(" : "("); + increaseIndentLevel(); + + bool OldValue = shouldNegate(); + setNegatePredicate(false); + for (const Record *Rec : Sequence) { + OS << '\n'; + OS.indent(getIndentLevel() * 2); + if (!First) + OS << (IsCheckAll ? "&& " : "|| "); + expandPredicate(OS, Rec); + First = false; + } + OS << '\n'; + decreaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + OS << ')'; + setNegatePredicate(OldValue); +} + +void PredicateExpanderCapstone::expandTIIFunctionCall(raw_ostream &OS, + StringRef MethodName) { + OS << (shouldNegate() ? "!" : ""); + OS << TargetName << (shouldExpandForMC() ? "_MC::" : "InstrInfo::"); + OS << MethodName << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpanderCapstone::expandCheckIsRegOperand(raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isReg() "; +} + +void PredicateExpanderCapstone::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").getReg().isVirtual()"; +} + +void PredicateExpanderCapstone::expandCheckIsImmOperand(raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isImm() "; +} + +void PredicateExpanderCapstone::expandCheckFunctionPredicateWithTII( + raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn, + StringRef TIIPtr) { + if (!shouldExpandForMC()) { + OS << (TIIPtr.empty() ? "TII" : TIIPtr) << "->" << MachineInstrFn; + OS << (isByRef() ? "(MI)" : "(*MI)"); + return; + } + + OS << MCInstFn << (isByRef() ? "(MI" : "(*MI") << ", MCII)"; +} + +void PredicateExpanderCapstone::expandCheckFunctionPredicate( + raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn) { + OS << (shouldExpandForMC() ? MCInstFn : MachineInstrFn) + << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpanderCapstone::expandCheckNonPortable(raw_ostream &OS, + StringRef Code) { + if (shouldExpandForMC()) + return expandFalse(OS); + + OS << '(' << Code << ')'; +} + +void PredicateExpanderCapstone::expandReturnStatement(raw_ostream &OS, + const Record *Rec) { + std::string Buffer; + raw_string_ostream SS(Buffer); + + SS << "return "; + expandPredicate(SS, Rec); + SS << ";"; + OS << Buffer; +} + +void PredicateExpanderCapstone::expandOpcodeSwitchCase(raw_ostream &OS, + const Record *Rec) { + const RecVec &Opcodes = Rec->getValueAsListOfDefs("Opcodes"); + for (const Record *Opcode : Opcodes) { + OS.indent(getIndentLevel() * 2); + OS << "case " << Opcode->getValueAsString("Namespace") + << "_" << Opcode->getName() << ":\n"; + } + + increaseIndentLevel(); + OS.indent(getIndentLevel() * 2); + expandStatement(OS, Rec->getValueAsDef("CaseStmt")); + decreaseIndentLevel(); +} + +void PredicateExpanderCapstone::expandOpcodeSwitchStatement(raw_ostream &OS, + const RecVec &Cases, + const Record *Default) { + std::string Buffer; + raw_string_ostream SS(Buffer); + + SS << "switch(MI" << (isByRef() ? "." : "->") << "getOpcode()) {\n"; + for (const Record *Rec : Cases) { + expandOpcodeSwitchCase(SS, Rec); + SS << '\n'; + } + + // Expand the default case. + SS.indent(getIndentLevel() * 2); + SS << "default:\n"; + + increaseIndentLevel(); + SS.indent(getIndentLevel() * 2); + expandStatement(SS, Default); + decreaseIndentLevel(); + SS << '\n'; + + SS.indent(getIndentLevel() * 2); + SS << "} // end of switch-stmt"; + OS << Buffer; +} + +void PredicateExpanderCapstone::expandStatement(raw_ostream &OS, + const Record *Rec) { + // Assume that padding has been added by the caller. + if (Rec->isSubClassOf("MCOpcodeSwitchStatement")) { + expandOpcodeSwitchStatement(OS, Rec->getValueAsListOfDefs("Cases"), + Rec->getValueAsDef("DefaultCase")); + return; + } + + if (Rec->isSubClassOf("MCReturnStatement")) { + expandReturnStatement(OS, Rec->getValueAsDef("Pred")); + return; + } + + llvm_unreachable("No known rules to expand this MCStatement"); +} + +void PredicateExpanderCapstone::expandPredicate(raw_ostream &OS, + const Record *Rec) { + // Assume that padding has been added by the caller. + if (Rec->isSubClassOf("MCTrue")) { + if (shouldNegate()) + return expandFalse(OS); + return expandTrue(OS); + } + + if (Rec->isSubClassOf("MCFalse")) { + if (shouldNegate()) + return expandTrue(OS); + return expandFalse(OS); + } + + if (Rec->isSubClassOf("CheckNot")) { + flipNegatePredicate(); + expandPredicate(OS, Rec->getValueAsDef("Pred")); + flipNegatePredicate(); + return; + } + + if (Rec->isSubClassOf("CheckIsRegOperand")) + return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckIsImmOperand")) + return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckRegOperand")) + return expandCheckRegOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsDef("Reg"), + Rec->getValueAsString("FunctionMapper")); + + if (Rec->isSubClassOf("CheckRegOperandSimple")) + return expandCheckRegOperandSimple(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsString("FunctionMapper")); + + if (Rec->isSubClassOf("CheckInvalidRegOperand")) + return expandCheckInvalidRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckImmOperand")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsInt("ImmVal"), + Rec->getValueAsString("FunctionMapper")); + + if (Rec->isSubClassOf("CheckImmOperand_s")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsString("ImmVal"), + Rec->getValueAsString("FunctionMapper")); + + if (Rec->isSubClassOf("CheckImmOperandSimple")) + return expandCheckImmOperandSimple(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsString("FunctionMapper")); + + if (Rec->isSubClassOf("CheckSameRegOperand")) + return expandCheckSameRegOperand(OS, Rec->getValueAsInt("FirstIndex"), + Rec->getValueAsInt("SecondIndex")); + + if (Rec->isSubClassOf("CheckNumOperands")) + return expandCheckNumOperands(OS, Rec->getValueAsInt("NumOps")); + + if (Rec->isSubClassOf("CheckPseudo")) + return expandCheckPseudo(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckOpcode")) + return expandCheckOpcode(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckAll")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ true); + + if (Rec->isSubClassOf("CheckAny")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ false); + + if (Rec->isSubClassOf("CheckFunctionPredicate")) { + return expandCheckFunctionPredicate( + OS, Rec->getValueAsString("MCInstFnName"), + Rec->getValueAsString("MachineInstrFnName")); + } + + if (Rec->isSubClassOf("CheckFunctionPredicateWithTII")) { + return expandCheckFunctionPredicateWithTII( + OS, Rec->getValueAsString("MCInstFnName"), + Rec->getValueAsString("MachineInstrFnName"), + Rec->getValueAsString("TIIPtrName")); + } + + if (Rec->isSubClassOf("CheckNonPortable")) + return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock")); + + if (Rec->isSubClassOf("TIIPredicate")) + return expandTIIFunctionCall(OS, Rec->getValueAsString("FunctionName")); + + llvm_unreachable("No known rules to expand this MCInstPredicate"); +} + +void PredicateExpanderCapstone::expandHeader(raw_ostream &OS, + const STIPredicateFunction &Fn) { const Record *Rec = Fn.getDeclaration(); StringRef FunctionName = Rec->getValueAsString("Name"); @@ -460,8 +1027,8 @@ void STIPredicateExpander::expandHeader(raw_ostream &OS, OS << ";\n"; } -void STIPredicateExpander::expandPrologue(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderCapstone::expandPrologue(raw_ostream &OS, + const STIPredicateFunction &Fn) { RecVec Delegates = Fn.getDeclaration()->getValueAsListOfDefs("Delegates"); bool UpdatesOpcodeMask = Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); @@ -487,8 +1054,9 @@ void STIPredicateExpander::expandPrologue(raw_ostream &OS, OS << "unsigned ProcessorID = getSchedModel().getProcessorID();\n"; } -void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group, - bool ShouldUpdateOpcodeMask) { +void PredicateExpanderCapstone::expandOpcodeGroup(raw_ostream &OS, + const OpcodeGroup &Group, + bool ShouldUpdateOpcodeMask) { const OpcodeInfo &OI = Group.getOpcodeInfo(); for (const PredicateInfo &PI : OI.getPredicates()) { const APInt &ProcModelMask = PI.ProcModelMask; @@ -526,8 +1094,8 @@ void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup } } -void STIPredicateExpander::expandBody(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderCapstone::expandBody(raw_ostream &OS, + const STIPredicateFunction &Fn) { bool UpdatesOpcodeMask = Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); @@ -559,8 +1127,8 @@ void STIPredicateExpander::expandBody(raw_ostream &OS, OS << "}\n"; } -void STIPredicateExpander::expandEpilogue(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderCapstone::expandEpilogue(raw_ostream &OS, + const STIPredicateFunction &Fn) { OS << '\n'; OS.indent(getIndentLevel() * 2); OS << "return "; @@ -573,8 +1141,8 @@ void STIPredicateExpander::expandEpilogue(raw_ostream &OS, OS << "} // " << ClassPrefix << "::" << FunctionName << "\n\n"; } -void STIPredicateExpander::expandSTIPredicate(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderCapstone::expandSTIPredicate(raw_ostream &OS, + const STIPredicateFunction &Fn) { const Record *Rec = Fn.getDeclaration(); if (shouldExpandForMC() && !Rec->getValueAsBit("ExpandForMC")) return; diff --git a/llvm/utils/TableGen/PredicateExpander.h b/llvm/utils/TableGen/PredicateExpander.h index a0dc63023978..d2a13b382784 100644 --- a/llvm/utils/TableGen/PredicateExpander.h +++ b/llvm/utils/TableGen/PredicateExpander.h @@ -21,29 +21,56 @@ namespace llvm { +// Forward declarations. +class STIPredicateFunction; +class OpcodeGroup; class raw_ostream; class Record; +class PredicateExpanderLLVM; +class PredicateExpanderCapstone; class PredicateExpander { + + friend PredicateExpanderLLVM; + friend PredicateExpanderCapstone; + bool EmitCallsByRef; bool NegatePredicate; bool ExpandForMC; unsigned IndentLevel; StringRef TargetName; + // STI only + bool ExpandDefinition; + StringRef ClassPrefix; PredicateExpander(const PredicateExpander &) = delete; PredicateExpander &operator=(const PredicateExpander &) = delete; +private: + virtual void expandHeader(raw_ostream &OS, const STIPredicateFunction &Fn) = 0; + virtual void expandPrologue(raw_ostream &OS, const STIPredicateFunction &Fn) = 0; + virtual void expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group, + bool ShouldUpdateOpcodeMask) = 0; + virtual void expandBody(raw_ostream &OS, const STIPredicateFunction &Fn) = 0; + virtual void expandEpilogue(raw_ostream &OS, const STIPredicateFunction &Fn) = 0; + public: PredicateExpander(StringRef Target) : EmitCallsByRef(true), NegatePredicate(false), ExpandForMC(false), - IndentLevel(1U), TargetName(Target) {} + IndentLevel(1U), TargetName(Target), ExpandDefinition(false) {} + virtual ~PredicateExpander() {} bool isByRef() const { return EmitCallsByRef; } bool shouldNegate() const { return NegatePredicate; } bool shouldExpandForMC() const { return ExpandForMC; } unsigned getIndentLevel() const { return IndentLevel; } StringRef getTargetName() const { return TargetName; } + // STI only + bool shouldExpandDefinition() const { return ExpandDefinition; } + StringRef getClassPrefix() const { return ClassPrefix; } + void setClassPrefix(StringRef S) { ClassPrefix = S; } + void setExpandDefinition(bool Value) { ExpandDefinition = Value; } + void setByRef(bool Value) { EmitCallsByRef = Value; } void flipNegatePredicate() { NegatePredicate = !NegatePredicate; } void setNegatePredicate(bool Value) { NegatePredicate = Value; } @@ -53,47 +80,53 @@ class PredicateExpander { void decreaseIndentLevel() { --IndentLevel; } using RecVec = std::vector; - void expandTrue(raw_ostream &OS); - void expandFalse(raw_ostream &OS); - void expandCheckImmOperand(raw_ostream &OS, int OpIndex, int ImmVal, - StringRef FunctionMapper); - void expandCheckImmOperand(raw_ostream &OS, int OpIndex, StringRef ImmVal, - StringRef FunctionMapperer); - void expandCheckImmOperandSimple(raw_ostream &OS, int OpIndex, - StringRef FunctionMapper); - void expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal, - StringRef FunctionMapper); - void expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal, - StringRef FunctionMapper); - void expandCheckRegOperand(raw_ostream &OS, int OpIndex, const Record *Reg, - StringRef FunctionMapper); - void expandCheckRegOperandSimple(raw_ostream &OS, int OpIndex, - StringRef FunctionMapper); - void expandCheckSameRegOperand(raw_ostream &OS, int First, int Second); - void expandCheckNumOperands(raw_ostream &OS, int NumOps); - void expandCheckOpcode(raw_ostream &OS, const Record *Inst); + virtual void expandTrue(raw_ostream &OS) = 0; + virtual void expandFalse(raw_ostream &OS) = 0; + virtual void expandCheckImmOperand(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) = 0; + virtual void expandCheckImmOperand(raw_ostream &OS, int OpIndex, + StringRef ImmVal, + StringRef FunctionMapperer) = 0; + virtual void expandCheckImmOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) = 0; + virtual void expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) = 0; + virtual void expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) = 0; + virtual void expandCheckRegOperand(raw_ostream &OS, int OpIndex, + const Record *Reg, + StringRef FunctionMapper) = 0; + virtual void expandCheckRegOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) = 0; + virtual void expandCheckSameRegOperand(raw_ostream &OS, int First, + int Second) = 0; + virtual void expandCheckNumOperands(raw_ostream &OS, int NumOps) = 0; + virtual void expandCheckOpcode(raw_ostream &OS, const Record *Inst) = 0; - void expandCheckPseudo(raw_ostream &OS, const RecVec &Opcodes); - void expandCheckOpcode(raw_ostream &OS, const RecVec &Opcodes); - void expandPredicateSequence(raw_ostream &OS, const RecVec &Sequence, - bool IsCheckAll); - void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName); - void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex); - void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex); - void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex); - void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex); - void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, - StringRef MachineInstrFn); - void expandCheckFunctionPredicateWithTII(raw_ostream &OS, StringRef MCInstFn, - StringRef MachineInstrFn, - StringRef TIIPtr); - void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock); - void expandPredicate(raw_ostream &OS, const Record *Rec); - void expandReturnStatement(raw_ostream &OS, const Record *Rec); - void expandOpcodeSwitchCase(raw_ostream &OS, const Record *Rec); - void expandOpcodeSwitchStatement(raw_ostream &OS, const RecVec &Cases, - const Record *Default); - void expandStatement(raw_ostream &OS, const Record *Rec); + virtual void expandCheckPseudo(raw_ostream &OS, const RecVec &Opcodes) = 0; + virtual void expandCheckOpcode(raw_ostream &OS, const RecVec &Opcodes) = 0; + virtual void expandPredicateSequence(raw_ostream &OS, const RecVec &Sequence, + bool IsCheckAll) = 0; + virtual void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName) = 0; + virtual void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) = 0; + virtual void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) = 0; + virtual void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) = 0; + virtual void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex) = 0; + virtual void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn) = 0; + virtual void expandCheckFunctionPredicateWithTII(raw_ostream &OS, + StringRef MCInstFn, + StringRef MachineInstrFn, + StringRef TIIPtr) = 0; + virtual void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock) = 0; + virtual void expandPredicate(raw_ostream &OS, const Record *Rec) = 0; + virtual void expandReturnStatement(raw_ostream &OS, const Record *Rec) = 0; + virtual void expandOpcodeSwitchCase(raw_ostream &OS, const Record *Rec) = 0; + virtual void expandOpcodeSwitchStatement(raw_ostream &OS, const RecVec &Cases, + const Record *Default) = 0; + virtual void expandStatement(raw_ostream &OS, const Record *Rec) = 0; + virtual void expandSTIPredicate(raw_ostream &OS, + const STIPredicateFunction &Fn) = 0; }; // Forward declarations. @@ -107,23 +140,132 @@ class STIPredicateExpander : public PredicateExpander { STIPredicateExpander(const PredicateExpander &) = delete; STIPredicateExpander &operator=(const PredicateExpander &) = delete; - void expandHeader(raw_ostream &OS, const STIPredicateFunction &Fn); - void expandPrologue(raw_ostream &OS, const STIPredicateFunction &Fn); + void expandHeader(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandPrologue(raw_ostream &OS, const STIPredicateFunction &Fn) override; void expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group, - bool ShouldUpdateOpcodeMask); - void expandBody(raw_ostream &OS, const STIPredicateFunction &Fn); - void expandEpilogue(raw_ostream &OS, const STIPredicateFunction &Fn); + bool ShouldUpdateOpcodeMask) override; + void expandBody(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandEpilogue(raw_ostream &OS, const STIPredicateFunction &Fn) override; public: STIPredicateExpander(StringRef Target) : PredicateExpander(Target), ExpandDefinition(false) {} +}; - bool shouldExpandDefinition() const { return ExpandDefinition; } - StringRef getClassPrefix() const { return ClassPrefix; } - void setClassPrefix(StringRef S) { ClassPrefix = S; } - void setExpandDefinition(bool Value) { ExpandDefinition = Value; } +class PredicateExpanderLLVM : public PredicateExpander { + using PredicateExpander::PredicateExpander; + + void expandHeader(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandPrologue(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group, + bool ShouldUpdateOpcodeMask) override; + void expandBody(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandEpilogue(raw_ostream &OS, const STIPredicateFunction &Fn) override; + + void expandTrue(raw_ostream &OS) override; + void expandFalse(raw_ostream &OS) override; + void expandCheckImmOperand(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckImmOperand(raw_ostream &OS, int OpIndex, StringRef ImmVal, + StringRef FunctionMapperer) override; + void expandCheckImmOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) override; + void expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckRegOperand(raw_ostream &OS, int OpIndex, const Record *Reg, + StringRef FunctionMapper) override; + void expandCheckRegOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) override; + void expandCheckSameRegOperand(raw_ostream &OS, int First, + int Second) override; + void expandCheckNumOperands(raw_ostream &OS, int NumOps) override; + void expandCheckOpcode(raw_ostream &OS, const Record *Inst) override; + + void expandCheckPseudo(raw_ostream &OS, const RecVec &Opcodes) override; + void expandCheckOpcode(raw_ostream &OS, const RecVec &Opcodes) override; + void expandPredicateSequence(raw_ostream &OS, const RecVec &Sequence, + bool IsCheckAll) override; + void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName) override; + void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn) override; + void expandCheckFunctionPredicateWithTII(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn, + StringRef TIIPtr) override; + void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock) override; + void expandPredicate(raw_ostream &OS, const Record *Rec) override; + void expandReturnStatement(raw_ostream &OS, const Record *Rec) override; + void expandOpcodeSwitchCase(raw_ostream &OS, const Record *Rec) override; + void expandOpcodeSwitchStatement(raw_ostream &OS, const RecVec &Cases, + const Record *Default) override; + void expandStatement(raw_ostream &OS, const Record *Rec) override; + + // STI only + void expandSTIPredicate(raw_ostream &OS, + const STIPredicateFunction &Fn) override; +}; + +class PredicateExpanderCapstone : public PredicateExpander { + using PredicateExpander::PredicateExpander; + + void expandHeader(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandPrologue(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group, + bool ShouldUpdateOpcodeMask) override; + void expandBody(raw_ostream &OS, const STIPredicateFunction &Fn) override; + void expandEpilogue(raw_ostream &OS, const STIPredicateFunction &Fn) override; + + void expandTrue(raw_ostream &OS) override; + void expandFalse(raw_ostream &OS) override; + void expandCheckImmOperand(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckImmOperand(raw_ostream &OS, int OpIndex, StringRef ImmVal, + StringRef FunctionMapperer) override; + void expandCheckImmOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) override; + void expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal, + StringRef FunctionMapper) override; + void expandCheckRegOperand(raw_ostream &OS, int OpIndex, const Record *Reg, + StringRef FunctionMapper) override; + void expandCheckRegOperandSimple(raw_ostream &OS, int OpIndex, + StringRef FunctionMapper) override; + void expandCheckSameRegOperand(raw_ostream &OS, int First, + int Second) override; + void expandCheckNumOperands(raw_ostream &OS, int NumOps) override; + void expandCheckOpcode(raw_ostream &OS, const Record *Inst) override; + + void expandCheckPseudo(raw_ostream &OS, const RecVec &Opcodes) override; + void expandCheckOpcode(raw_ostream &OS, const RecVec &Opcodes) override; + void expandPredicateSequence(raw_ostream &OS, const RecVec &Sequence, + bool IsCheckAll) override; + void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName) override; + void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex) override; + void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn) override; + void expandCheckFunctionPredicateWithTII(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn, + StringRef TIIPtr) override; + void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock) override; + void expandPredicate(raw_ostream &OS, const Record *Rec) override; + void expandReturnStatement(raw_ostream &OS, const Record *Rec) override; + void expandOpcodeSwitchCase(raw_ostream &OS, const Record *Rec) override; + void expandOpcodeSwitchStatement(raw_ostream &OS, const RecVec &Cases, + const Record *Default) override; + void expandStatement(raw_ostream &OS, const Record *Rec) override; - void expandSTIPredicate(raw_ostream &OS, const STIPredicateFunction &Fn); + // STI only + void expandSTIPredicate(raw_ostream &OS, + const STIPredicateFunction &Fn) override; }; } // namespace llvm diff --git a/llvm/utils/TableGen/Printer.h b/llvm/utils/TableGen/Printer.h new file mode 100644 index 000000000000..551fee2ba9e3 --- /dev/null +++ b/llvm/utils/TableGen/Printer.h @@ -0,0 +1,1863 @@ +//===--------------- Printer.h - Printer Interface --------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_PRINTER_H +#define LLVM_UTILS_TABLEGEN_PRINTER_H + +#include "AsmMatcherEmitterTypes.h" +#include "AsmWriterInst.h" +#include "CodeGenRegisters.h" +#include "CodeGenTarget.h" +#include "DecoderEmitterTypes.h" +#include "InstrInfoEmitterTypes.h" +#include "PrinterTypes.h" +#include "RegisterInfoEmitterTypes.h" +#include "SearchableTablesTypes.h" +#include "SubtargetEmitterTypes.h" +#include "SubtargetFeatureInfo.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" + +typedef enum { + ST_NONE, + ST_DECL_OS, + ST_IMPL_OS, + ST_ENUM_SYSOPS_OS, +} StreamType; + +namespace llvm { + +class PrinterBitVectorEmitter { + BitVector Values; + +public: + virtual void add(unsigned V); + virtual void print(raw_ostream &OS); +}; + +void printBitVectorAsHex(raw_ostream &OS, const BitVector &Bits, + unsigned Width); + +class PrinterCapstone; + +//============================== +// +// Implementation: LLVM +// +//============================== + +/// Interface for printing the generated code. +/// Every string which will be in the generated code of a backend originates +/// from here. +/// +/// It also is the only class which writes directly into the output stream for +/// the backend. +/// +/// This class has methods for all classes of backends which emit generated +/// code. If a backend currently does not emit the code in a language you need +/// you simply inherit this class and implement the relevant methods. +/// +/// Printer implementation of LLVM. +/// This is the default printer for all backends. +/// +/// Output language: C++ +class PrinterLLVM { + friend PrinterCapstone; + +private: + formatted_raw_ostream &OS; + + //------------------------- + // Backend: DecoderEmitter and Subtarget + //------------------------- + std::string TargetName; + std::string PredicateNamespace; + std::string GuardPrefix, GuardPostfix; + std::string ReturnOK, ReturnFail; + std::string Locals; + + //---------------------------- + // Backends: InstrInfo + // SubTargetInfo + // SearchableTables + //---------------------------- + PredicateExpander *PE = nullptr; + std::set PreprocessorGuards = std::set(); + + //-------------------------- + // Backend: AsmMatcher + //-------------------------- + + // Convert function stream. + // Write the convert function to a separate stream, so we can drop it after + // the enum. We'll build up the conversion handlers for the individual + // operand types opportunistically as we encounter them. + std::string *ConvertFnBody = new std::string; + raw_string_ostream *CvtOS = new raw_string_ostream(*ConvertFnBody); + // Operand lookup function stream. + std::string *OperandFnBody = new std::string; + raw_string_ostream *OpOS = new raw_string_ostream(*OperandFnBody); + +public: + PrinterLLVM(formatted_raw_ostream &OS); + PrinterLLVM(formatted_raw_ostream &OS, std::string TargetName); + + virtual ~PrinterLLVM(); + + // Backend: DecoderEmitter + PrinterLLVM(formatted_raw_ostream &OS, std::string PredicateNamespace, + std::string GPrefix, std::string GPostfix, std::string ROK, + std::string RFail, std::string L, std::string Target); + + static PrinterLanguage getLanguage(); + + virtual void flushOS() const { OS.flush(); } + + //------------------------------ + // PredicateExpander management + //------------------------------ + void initNewPE(StringRef const &Target) { + if (PE) { + delete PE; + PE = nullptr; + } + PE = getNewPE(Target); + } + virtual PredicateExpander *getNewPE(StringRef const &Target) const { + return new PredicateExpanderLLVM(Target); + } + + //-------------------------- + // General printing methods + //-------------------------- + + virtual void emitIncludeToggle(std::string const &Name, bool Begin, + bool Newline = true, + bool UndefAtEnd = false) const; + virtual void emitPPIf(std::string const &Arg, bool Begin, + bool Newline = true) const; + virtual void emitNewline(unsigned Count) const { + for (unsigned I = Count; I > 0; --I) + OS << "\n"; + } + virtual void emitIfNotDef(std::string const &Name, bool Begin) const { + if (Begin) { + OS << "#ifndef " << Name << "\n"; + } else { + OS << "#endif // " << Name << "\n\n"; + } + } + virtual void emitString(std::string const &Str) const { OS << Str; } + virtual void emitNamespace(std::string const &Name, bool Begin, + std::string const &Comment = "", + bool Newline = true) const; + + //------------------------ + // Backend: RegisterInfo + //------------------------ + + virtual void regInfoEmitSourceFileHeader(std::string const &Desc) const; + virtual void regInfoEmitEnums(CodeGenTarget const &Target, + CodeGenRegBank const &Bank) const; + virtual void + regInfoEmitRegDiffLists(std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const; + virtual void regInfoEmitLaneMaskLists( + std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const; + virtual void regInfoEmitSubRegIdxLists( + std::string const TargetName, + SequenceToOffsetTable>> const + &SubRegIdxSeqs) const; + virtual void regInfoEmitSubRegIdxSizes( + std::string const TargetName, + std::deque const &SubRegIndices) const; + virtual void regInfoEmitSubRegStrTable( + std::string const TargetName, + SequenceToOffsetTable const &RegStrings) const; + virtual void regInfoEmitRegDesc( + SequenceToOffsetTable const &LaneMaskSeqs, + std::deque const &Regs, + SequenceToOffsetTable>> const + &SubRegIdxSeqs, + SequenceToOffsetTable const &DiffSeqs, + SmallVector const &SubRegIdxLists, + SmallVector const &SubRegLists, + SmallVector const &SuperRegLists, + SmallVector const &RegUnitLists, + SmallVector const &RegUnitLaneMasks, + SequenceToOffsetTable const &RegStrings) const; + virtual void regInfoEmitRegUnitRoots(std::string const TargetName, + CodeGenRegBank const &RegBank) const; + virtual void + regInfoEmitRegClasses(std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings, + CodeGenTarget const &Target) const; + virtual void regInfoEmitStrLiteralRegClasses( + std::string const TargetName, + SequenceToOffsetTable const &RegClassStrings) const; + virtual void regInfoEmitMCRegClassesTable( + std::string const TargetName, + std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings) const; + virtual void + regInfoEmitRegEncodingTable(std::string const TargetName, + std::deque const &Regs) const; + virtual void regInfoEmitMCRegInfoInit( + std::string const TargetName, CodeGenRegBank const &RegBank, + std::deque const &Regs, + std::list const &RegClasses, + std::deque const &SubRegIndices) const; + virtual void regInfoEmitInfoDwarfRegs(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, bool IsCtor) const; + virtual void regInfoEmitInfoDwarfRegsRev(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, + bool IsCtor) const; + virtual void regInfoEmitInfoRegMapping(StringRef const &Namespace, + unsigned MaxLength, bool IsCtor) const; + virtual void regInfoEmitHeaderIncludes() const; + virtual void regInfoEmitHeaderExternRegClasses( + std::list const &RegClasses) const; + virtual void regInfoEmitHeaderDecl(std::string const &TargetName, + std::string const &ClassName, + bool SubRegsPresent, + bool DeclareGetPhysRegBaseClass) const; + virtual void + regInfoEmitExternRegClassesArr(std::string const &TargetName) const; + virtual void regInfoEmitVTSeqs( + SequenceToOffsetTable> const &VTSeqs) + const; + virtual void regInfoEmitSubRegIdxTable( + std::deque const &SubRegIndices) const; + virtual void regInfoEmitRegClassInfoTable( + std::list const &RegClasses, + SequenceToOffsetTable> const &VTSeqs, + CodeGenHwModes const &CGH, unsigned NumModes) const; + virtual void regInfoEmitSubClassMaskTable( + std::list const &RegClasses, + SmallVector &SuperRegIdxLists, + SequenceToOffsetTable>> &SuperRegIdxSeqs, + std::deque const &SubRegIndices, + BitVector &MaskBV) const; + virtual void regInfoEmitSuperRegIdxSeqsTable( + SequenceToOffsetTable>> const &SuperRegIdxSeqs) + const; + virtual void regInfoEmitSuperClassesTable( + std::list const &RegClasses) const; + virtual void + regInfoEmitRegClassMethods(std::list const &RegClasses, + std::string const &TargetName) const; + virtual void regInfomitRegClassInstances( + std::list const &RegClasses, + SequenceToOffsetTable>> const &SuperRegIdxSeqs, + SmallVector const &SuperRegIdxLists, + std::string const &TargetName) const; + virtual void regInfoEmitRegClassTable( + std::list const &RegClasses) const; + virtual void + regInfoEmitCostPerUseTable(std::vector const &AllRegCostPerUse, + unsigned NumRegCosts) const; + virtual void + regInfoEmitInAllocatableClassTable(llvm::BitVector const &InAllocClass) const; + virtual void regInfoEmitRegExtraDesc(std::string const &TargetName, + unsigned NumRegCosts) const; + virtual void regInfoEmitSubClassSubRegGetter( + std::string const &ClassName, unsigned SubRegIndicesSize, + std::deque const &SubRegIndices, + std::list const &RegClasses, + CodeGenRegBank &RegBank) const; + virtual void regInfoEmitRegClassWeight(CodeGenRegBank const &RegBank, + std::string const &ClassName) const; + virtual void regInfoEmitRegUnitWeight(CodeGenRegBank const &RegBank, + std::string const &ClassName, + bool RegUnitsHaveUnitWeight) const; + virtual void regInfoEmitGetNumRegPressureSets(std::string const &ClassName, + unsigned NumSets) const; + virtual void regInfoEmitGetRegPressureTables(CodeGenRegBank const &RegBank, + std::string const &ClassName, + unsigned NumSets) const; + virtual void regInfoEmitRCSetsTable( + std::string const &ClassName, unsigned NumRCs, + SequenceToOffsetTable> const &PSetsSeqs, + std::vector> const &PSets) const; + virtual void regInfoEmitGetRegUnitPressureSets( + SequenceToOffsetTable> const &PSetsSeqs, + CodeGenRegBank const &RegBank, std::string const &ClassName, + std::vector> const &PSets) const; + virtual void regInfoEmitExternTableDecl(std::string const &TargetName) const; + virtual void + regInfoEmitRegClassInit(std::string const &TargetName, + std::string const &ClassName, + CodeGenRegBank const &RegBank, + std::list const &RegClasses, + std::deque const &Regs, + unsigned SubRegIndicesSize) const; + virtual void regInfoEmitSaveListTable(Record const *CSRSet, + SetTheory::RecVec const *Regs) const; + virtual void regInfoEmitRegMaskTable(std::string const &CSRSetName, + BitVector &Covered) const; + virtual void + regInfoEmitIsConstantPhysReg(std::deque const &Regs, + std::string const &ClassName) const; + virtual void regInfoEmitGetRegMasks(std::vector const &CSRSets, + std::string const &ClassName) const; + virtual void regInfoEmitGPRCheck( + std::string const &ClassName, + std::list const &RegCategories) const; + virtual void regInfoEmitFixedRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const; + virtual void regInfoEmitArgRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const; + virtual void regInfoEmitGetRegMaskNames(std::vector const &CSRSets, + std::string const &ClassName) const; + virtual void regInfoEmitGetFrameLowering(std::string const &TargetName) const; + virtual void + regInfoEmitComposeSubRegIndicesImplHead(std::string const &ClName) const; + virtual void regInfoEmitComposeSubRegIndicesImplBody( + SmallVector, 4> const &Rows, + unsigned SubRegIndicesSize, SmallVector const &RowMap) const; + virtual void regInfoEmitLaneMaskComposeSeq( + SmallVector, 4> const &Sequences, + SmallVector const &SubReg2SequenceIndexMap, + std::deque const &SubRegIndices) const; + virtual void regInfoEmitComposeSubRegIdxLaneMask( + std::string const &ClName, + std::deque const &SubRegIndices) const; + virtual void regInfoEmitComposeSubRegIdxLaneMaskRev( + std::string const &ClName, + std::deque const &SubRegIndices) const; + virtual void regInfoEmitRegBaseClassMapping( + std::string const &ClassName, + SmallVector BaseClasses, + std::deque const Regs) const; + + //------------------------- + // Backend: DecoderEmitter + //------------------------- + + // FilterChooser printing + + virtual void decoderEmitterEmitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const; + virtual void + decoderEmitterEmitOpBinaryParser(raw_ostream &DecoderOS, + const OperandInfo &OpInfo) const; + virtual bool decoderEmitterEmitPredicateMatchAux(const Init &Val, + bool ParenIfBinOp, + raw_ostream &PredOS) const; + // Emits code to check the Predicates member of an instruction are true. + // Returns true if predicate matches were emitted, false otherwise. + virtual bool decoderEmitterEmitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const; + + // DecoderEmitter printing + + virtual void decoderEmitterEmitCheck() const; + virtual void decoderEmitterEmitFieldFromInstruction() const; + virtual void decoderEmitterEmitInsertBits() const; + virtual void decoderEmitterEmitDecodeInstruction(bool IsVarLenInst) const; + // Emit the decoder state machine table. + virtual void decoderEmitterEmitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector &NumberedEncodings) const; + virtual void + decoderEmitterEmitInstrLenTable(std::vector &InstrLen) const; + virtual void decoderEmitterEmitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const; + virtual void decoderEmitterEmitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const; + virtual void decoderEmitterEmitIncludes() const; + virtual void decoderEmitterEmitSourceFileHeader() const; + + //------------------------- + // Backend: AsmWriter + //------------------------- + + virtual void asmWriterEmitSourceFileHeader(RecordKeeper &Records) const; + virtual void asmWriterEmitGetMnemonic(std::string const &TargetName, + StringRef const &ClassName) const; + virtual void asmWriterEmitAsmStrs( + SequenceToOffsetTable const &StrTable) const; + virtual void asmWriterEmitMnemonicDecodeTable( + unsigned const OpcodeInfoBits, unsigned BitsLeft, + unsigned const &AsmStrBits, + ArrayRef const &NumberedInstructions, + std::vector const &OpcodeInfo) const; + virtual void asmWriterEmitPrintInstruction( + std::string const &TargetName, + std::vector> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits, StringRef const &ClassName, + bool PassSubtarget) const; + virtual void asmWriterEmitOpCases( + std::vector> &OpsToPrint, + bool PassSubtarget) const; + virtual void asmWriterEmitInstrSwitch() const; + virtual void asmWriterEmitCompoundClosure(unsigned Indent, bool Newline, + bool Semicolon) const; + virtual void + asmWriterEmitInstruction(AsmWriterInst const &FirstInst, + std::vector const &SimilarInsts, + unsigned DifferingOperand, bool PassSubtarget) const; + virtual void asmWriterEmitGetRegNameAssert(std::string const &TargetName, + StringRef const &ClassName, + bool HasAltNames, + unsigned RegSize) const; + virtual void asmWriterEmitStringLiteralDef( + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const; + virtual void + asmWriterEmitAltIdxSwitch(bool HasAltNames, + std::vector const &AltNameIndices, + StringRef const &Namespace) const; + virtual void asmWriterEmitRegAsmOffsets( + unsigned RegSizes, SmallVector const &AsmNames, + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const; + virtual char const *asmWriterGetPatCondKIgnore() const; + virtual char const *asmWriterGetPatCondKRegClass() const; + virtual char const *asmWriterGetPatCondKTiedReg() const; + virtual char const *asmWriterGetPatCondKCustom() const; + virtual char const *asmWriterGetPatCondKImm() const; + virtual char const *asmWriterGetPatCondKNoReg() const; + virtual char const *asmWriterGetPatCondKReg() const; + virtual char const *asmWriterGetPatCondKFeature() const; + virtual char const *asmWriterGetPatCondKEndOrFeature() const; + virtual char const *asmWriterGetPatOpcStart() const; + virtual char const *asmWriterGetCondPatStart() const; + virtual std::string asmWriterGetCond(std::string const &Cond) const; + virtual char const *asmWriterGetPatternFormat() const; + virtual char const *asmWriterGetOpcodeFormat() const; + virtual void asmWriterEmitPrintAliasInstrHeader(std::string const &TargetName, + StringRef const &ClassName, + bool PassSubtarget) const; + virtual void asmWriterEmitPrintAliasInstrBodyRetFalse() const; + virtual void asmWriterEmitPrintAliasInstrBody( + raw_string_ostream &OpcodeO, raw_string_ostream &PatternO, + raw_string_ostream &CondO, + std::vector> const &AsmStrings, + std::vector const &MCOpPredicates, + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const; + virtual void asmWriterEmitDeclValid(std::string const &TargetName, + StringRef const &ClassName) const; + virtual void asmWriterEmitPrintAliasOp( + std::string const &TargetName, StringRef const &ClassName, + std::vector> const &PrintMethods, + bool PassSubtarget) const; + virtual void + asmWriterEmitPrintMC(std::string const &TargetName, + StringRef const &ClassName, + std::vector const &MCOpPredicates) const; + + //------------------------- + // Backend: Subtarget + //------------------------- + + virtual void subtargetEmitSourceFileHeader() const; + virtual void + subtargetEmitFeatureEnum(DenseMap &FeatureMap, + std::vector const &DefList, + unsigned N) const; + virtual void subtargetEmitGetSTIMacro(StringRef const &Value, + StringRef const &Attribute) const; + virtual void subtargetEmitHwModes(CodeGenHwModes const &CGH, + std::string const &ClassName) const; + virtual void subtargetEmitFeatureKVHeader(std::string const &Target) const; + virtual void subtargetEmitFeatureKVEnd() const; + virtual void subtargetEmitFeatureKVPartI(std::string const &Target, + StringRef const &CommandLineName, + StringRef const &Name, + StringRef const &Desc) const; + virtual void subtargetEmitFeatureKVPartII() const; + virtual void subtargetEmitPrintFeatureMask( + std::array const &Mask) const; + virtual void subtargetEmitCPUKVHeader(std::string const &Target) const; + virtual void subtargetEmitCPUKVEnd() const; + virtual void subtargetEmitCPUKVPartI(StringRef const &Name) const; + virtual void subtargetEmitCPUKVPartII() const; + virtual void + subtargetEmitCPUKVPartIII(std::string const &ProcModelName) const; + virtual void subtargetEmitDBGMacrosBegin() const; + virtual void subtargetEmitDBGMacrosEnd() const; + virtual void subtargetEmitFunctionalItinaryUnits( + CodeGenSchedModels const &SchedModels) const; + virtual std::string const + subtargetGetBeginStageTable(std::string const &TargetName) const; + virtual std::string const + subtargetGetBeginOperandCycleTable(std::string const &TargetName) const; + virtual std::string const + subtargetGetBeginBypassTable(std::string const &TargetName) const; + virtual std::string const subtargetGetEndStageTable() const; + virtual std::string const subtargetGetEndOperandCycleTable() const; + virtual std::string const subtargetGetEndBypassTable() const; + virtual void subtargetFormItineraryStageString(std::string const &Name, + Record *ItinData, + std::string &ItinString, + unsigned &NStages) const; + virtual void + subtargetFormItineraryOperandCycleString(Record *ItinData, + std::string &ItinString, + unsigned &NOperandCycles) const; + virtual void + subtargetFormItineraryBypassString(const std::string &Name, Record *ItinData, + std::string &ItinString, + unsigned NOperandCycles) const; + virtual std::string + subtargetGetStageEntryPartI(std::string const &ItinStageString, + unsigned StageCount) const; + virtual std::string subtargetGetStageEntryPartII(unsigned StageCount, + unsigned NStages) const; + virtual std::string subtargetGetStageEntryPartIII() const; + virtual std::string subtargetGetOperandCycleEntryPartI( + std::string const &ItinOperandCycleString) const; + virtual std::string + subtargetGetOperandCycleEntryPartII(unsigned OperandCycleCount, + unsigned NOperandCycles) const; + virtual std::string subtargetGetOperandCycleEntryPartIII( + std::string const &OperandIdxComment) const; + virtual std::string subtargetGetOperandCycleEntryPartIV( + std::string const &ItinBypassString, + std::string const &OperandIdxComment) const; + virtual void subtargetEmitProcessorItineraryTable( + std::string const &ItinsDefName, std::vector &ItinList, + CodeGenSchedModels const &SchedModels) const; + virtual void subtargetEmitPreOperandTableComment() const; + virtual void + subtargetEmitSchedClassTables(SchedClassTablesT &SchedTables, + std::string const &TargetName, + CodeGenSchedModels const &SchedModels) const; + virtual unsigned + subtargetEmitRegisterFileTables(CodeGenProcModel const &ProcModel) const; + virtual void subtargetEmitMCExtraProcInfoTableHeader( + std::string const &ProcModelName) const; + virtual void subtargetEmitMCExtraProcInfoTableEnd() const; + virtual void subtargetEmitReorderBufferSize(int64_t ReorderBufferSize) const; + virtual void subtargetEmitMaxRetirePerCycle(int64_t MaxRetirePerCycle) const; + virtual void subtargetEmitRegisterFileInfo(CodeGenProcModel const &ProcModel, + unsigned NumRegisterFiles, + unsigned NumCostEntries) const; + virtual void subtargetEmitResourceDescriptorLoadQueue(unsigned QueueID) const; + virtual void + subtargetEmitResourceDescriptorStoreQueue(unsigned QueueID) const; + virtual void subtargetEmitProcessorResourceSubUnits( + const CodeGenProcModel &ProcModel, + CodeGenSchedModels const &SchedModels) const; + virtual void + subtargetEmitMCProcResourceDescHeader(std::string const &ProcModelName) const; + virtual void subtargetEmitMCProcResourceDescEnd() const; + virtual void + subtargetEmitMCProcResourceDesc(Record const *PRDef, Record const *SuperDef, + std::string const &ProcModelName, + unsigned SubUnitsOffset, unsigned SuperIdx, + unsigned NumUnits, int BufferSize, unsigned I, + unsigned const SubUnitsBeginOffset) const; + virtual void subtargetEmitProcessorProp(Record const *R, StringRef const Name, + char Separator) const; + virtual void subtargetEmitProcModelHeader(std::string const &ModelName) const; + virtual void + subtargetEmitProcModel(CodeGenProcModel const &PM, + CodeGenSchedModels const &SchedModels) const; + virtual void subtargetEmitResolveVariantSchedClassImplHdr() const; + virtual void subtargetEmitResolveVariantSchedClassImplEnd() const; + virtual void subtargetEmitSchedClassSwitch() const; + virtual void subtargetEmitSchedClassSwitchEnd() const; + virtual void subtargetEmitSchedClassCase(unsigned VC, + std::string const &SCName) const; + virtual void + subtargetEmitSchedClassProcGuard(unsigned Pi, bool OnlyExpandMCInstPredicates, + std::string const &ModelName) const; + virtual void subtargetEmitPredicates( + CodeGenSchedTransition const &T, CodeGenSchedClass const &SC, + bool (*IsTruePredicate)(Record const *Rec), int Indent = -1) const; + virtual void subtargetEmitProcTransitionEnd() const; + virtual void + subtargetEmitSchedClassCaseEnd(CodeGenSchedClass const &SC) const; + virtual void + subtargetEmitSchedModelHelperEpilogue(bool ShouldReturnZero) const; + virtual void + subtargetEmitGenMCSubtargetInfoClass(std::string const &TargetName, + bool OverrideGetHwMode) const; + virtual void subtargetEmitMCSubtargetInfoImpl(std::string const &TargetName, + unsigned NumFeatures, + unsigned NumProcs, + bool SchedModelHasItin) const; + virtual void subtargetEmitIncludeSTIDesc() const; + virtual void + subtargetEmitDFAPacketizerClass(CodeGenTarget &TGT, + std::string const &TargetName, + std::string const &ClassName) const; + virtual void subtargetEmitDFAPacketizerClassEnd() const; + virtual void subtargetEmitSTICtor() const; + virtual void subtargetEmitExternKVArrays(std::string const &TargetName, + bool SchedModelsHasItin) const; + virtual void subtargetEmitClassDefs(std::string const &TargetName, + std::string const &ClassName, + unsigned NumFeatures, unsigned NumProcs, + bool SchedModelsHasItin) const; + virtual void + subtargetEmitResolveSchedClassHdr(std::string const &ClassName) const; + virtual void + subtargetEmitResolveSchedClassEnd(std::string const &ClassName) const; + virtual void + subtargetEmitResolveVariantSchedClass(std::string const &TargetName, + std::string const &ClassName) const; + virtual void subtargetEmitPredicateProlog(const RecordKeeper &Records) const; + virtual void subtargetEmitParseFeaturesFunction( + std::string const &TargetName, + std::vector const &Features) const; + virtual void + subtargetEmitExpandedSTIPreds(StringRef const &TargetName, + std::string const &ClassName, + CodeGenSchedModels const &SchedModels); + virtual void subtargetPrepareSchedClassPreds(StringRef const &TargetName, + bool OnlyExpandMCInstPredicates); + virtual void + subtargetEmitExpandedSTIPredsMCAnaDecl(StringRef const &TargetName, + CodeGenSchedModels const &SchedModels); + virtual void subtargetEmitExpandedSTIPredsMCAnaDefs( + StringRef const &TargetName, std::string const &ClassPrefix, + CodeGenSchedModels const &SchedModels) const; + virtual void + subtargetEmitExpandedSTIPredsHeader(StringRef const &TargetName, + CodeGenSchedModels const &SchedModels); + virtual void + subtargetEmitStageAndSycleTables(std::string const &StageTable, + std::string const &OperandCycleTable, + std::string const &BypassTable) const; + virtual void subtargetEmitGetMacroFusions(CodeGenTarget &TGT, + std::string Target, + const std::string &ClassName) const; + virtual void asmMatcherEmitSTFBitEnum(AsmMatcherInfo &Info) const; + virtual void asmMatcherEmitComputeAssemblerAvailableFeatures( + AsmMatcherInfo &Info, StringRef const &ClassName) const; + + //--------------------------- + // Backend: InstrInfoEmitter + //--------------------------- + + virtual void instrInfoEmitSourceFileHeader() const; + virtual void instrInfoEmitSetGetComputeFeatureMacro() const; + virtual void instrInfoSetOperandInfoStr( + std::string &Res, Record const *OpR, + CGIOperandList::OperandInfo const &Op, + CGIOperandList::ConstraintInfo const &Constraint) const; + virtual void instrInfoEmitMCInstrDescHdr(std::string TargetName) const; + virtual void instrInfoEmitMCInstrDescClose() const; + virtual void instrInfoEmitMCInstrDescEnd() const; + virtual void instrInfoEmitMCInstrImplUses( + std::vector> ImplicitLists, + std::map, unsigned> &EmittedLists) const; + virtual void instrInfoEmitRecord(CodeGenSchedModels const &SchedModels, + CodeGenInstruction const &Inst, unsigned Num, + int MinOperands) const; + virtual void + instrInfoEmitTargetIndepFlags(CodeGenInstruction const &Inst, + bool GetAllowRegisterRenaming) const; + virtual void instrInfoEmitTSFFlags(uint64_t Value) const; + virtual void instrInfoEmitUseDefsLists( + StringRef TargetName, const CodeGenInstruction &Inst, + std::map, unsigned> &EmittedLists, + std::vector const &ImplicitOps) const; + virtual void + instrInfoEmitOperandInfo(OperandInfoListTy &OperandInfoList) const; + virtual void + instrInfoEmitOperandInfoOffset(StringRef TargetName, + std::vector const &OperandInfo, + OperandInfoMapTy const &OperandInfoMap) const; + virtual void instrInfoEmitRecordEnd(unsigned InstNum, + std::string const &InstName) const; + virtual void instrInfoEmitMCInstrDescDecl(std::string const &TargetName, + unsigned NumberedInstructionsSize, + unsigned OperandInfoSize, + unsigned ImplicitListSize) const; + virtual void instrInfoEmitStringLiteralDef( + std::string const &TargetName, + SequenceToOffsetTable InstrNames) const; + virtual void instrInfoEmitInstrNameIndices( + std::string const &TargetName, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const; + virtual void instrInfoEmitInstrDeprFeatures( + std::string const &TargetName, std::string const &TargetNamespace, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const; + virtual void instrInfoEmitInstrComplexDeprInfos( + std::string const &TargetName, + ArrayRef const &NumberedInstructions) const; + virtual void instrInfoEmitMCInstrInfoInitRoutine( + std::string const &TargetName, unsigned NumberedInstrSize, + bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const; + virtual void instrInfoEmitHeader(std::string const &TargetName) const; + virtual void instrInfoEmitClassStruct(std::string const &ClassName) const; + virtual void instrInfoEmitTIIHelperMethod(StringRef const &TargetName, + Record const *Rec, + bool ExpandDefinition) const; + virtual void instrInfoEmitExternArrays(std::string const &TargetName, + bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const; + virtual void instrInfoEmitMCInstrInfoInit( + std::string const &TargetName, unsigned NumberedInstrSize, + bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const; + virtual void instrInfoEmitOperandEnum( + std::map const &Operands) const; + virtual void instrInfoEmitGetNamedOperandIdx( + std::map const &Operands, + OpNameMapTy const &OperandMap) const; + virtual void instrInfoEmitOpTypeEnumPartI() const; + virtual void instrInfoEmitOpTypeEnumPartII(StringRef const &OpName, + unsigned EnumVal) const; + virtual void instrInfoEmitOpTypeEnumPartIII() const; + virtual void instrInfoEmitOpTypeOffsetTable( + std::vector OperandOffsets, unsigned OpRecSize, + ArrayRef const &NumberedInstructions) const; + virtual void instrInfoEmitOpcodeOpTypesTable( + unsigned EnumVal, std::vector const &OperandRecords, + std::vector OperandOffsets, + ArrayRef const &NumberedInstructions) const; + virtual void instrInfoEmitGetOpTypeHdr() const; + virtual void instrInfoEmitGetOpTypeReturn() const; + virtual void instrInfoEmitGetOpTypeUnreachable() const; + virtual void instrInfoEmitGetOpTypeEnd() const; + virtual void instrInfoEmitGetMemOpSizeHdr() const; + virtual void instrInfoEmitGetOpMemSizeTbl( + std::map> &SizeToOperandName) const; + virtual std::string + instrInfoGetInstMapEntry(StringRef const &Namespace, + StringRef const &InstrName) const; + virtual void instrInfoEmitGetLogicalOpSizeHdr() const; + virtual void instrInfoEmitGetLogicalOpSizeTable( + size_t LogicalOpListSize, + std::vector *> const &LogicalOpSizeList) + const; + virtual void instrInfoEmitGetLogicalOpSizeSwitch( + std::map> InstMap) const; + virtual void instrInfoEmitGetLogicalOpSizeReturn() const; + virtual void instrInfoEmitGetLogicalOpSizeEnd() const; + virtual void instrInfoEmitGetLogicalOpIdx() const; + virtual std::string + instrInfoGetOpTypeListEntry(StringRef const &Namespace, + StringRef const &OpName) const; + virtual void instrInfoEmitGetLogicalOpTypeHdr() const; + virtual void instrInfoEmitGetLogicalOpTypeTable( + size_t LogicalOpTypeListSize, + std::vector *> const &LogicalOpTypeList) + const; + virtual void instrInfoEmitGetLogicalOpTypeSwitch( + std::map> InstMap) const; + virtual void instrInfoEmitGetLogicalOpTypeReturn() const; + virtual void instrInfoEmitGetLogicalOpTypeEnd() const; + virtual void instrInfoEmitDeclareMCInstFeatureClasses() const; + virtual void instrInfoEmitPredFcnDecl(RecVec const &TIIPredicates) const; + virtual void instrInfoEmitPredFcnImpl(StringRef const &TargetName, + RecVec const &TIIPredicates); + virtual void instrInfoEmitInstrPredVerifierIncludes() const; + virtual void instrInfoEmitMacroDefineCheck() const; + virtual void instrInfoEmitSubtargetFeatureBitEnumeration( + std::map + &SubtargetFeatures) const; + virtual void instrInfoEmitEmitSTFNameTable( + std::map + &SubtargetFeatures) const; + virtual void instrInfoEmitFeatureBitsEnum( + std::vector> const &FeatureBitsets) const; + virtual void instrInfoEmitFeatureBitsArray( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures) const; + virtual void instrInfoEmitRequiredFeatureRefs( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures, + CodeGenTarget const &Target) const; + virtual void instrInfoEmitOpcodeChecker() const; + virtual void + instrInfoEmitPredicateVerifier(StringRef const &TargetName) const; + virtual void instrInfoEmitEnums(CodeGenTarget const &Target, + StringRef const &Namespace, + CodeGenSchedModels const &SchedModels) const; + virtual void instrInfoEmitTIIPredicates(StringRef const &TargetName, + RecVec const &TIIPredicates, + bool ExpandDefinition); + virtual void instrInfoEmitComputeAssemblerAvailableFeatures( + StringRef const &TargetName, + std::map + &SubtargetFeatures) const; + + //-------------------------- + // Backend: AsmMatcher + //-------------------------- + + virtual void asmMatcherEmitSourceFileHeader(std::string const &Desc) const; + virtual void asmMatcherEmitDeclarations(bool HasOptionalOperands, + bool ReportMultipleNearMisses, + bool HasOperandInfos) const; + virtual void + asmMatcherEmitOperandDiagTypes(std::set const Types) const; + + virtual void asmMatcherEmitGetSubtargetFeatureName( + std::map const + SubtargetFeatures) const; + virtual void asmMatcherEmitConversionFunctionI( + StringRef const &TargetName, StringRef const &ClassName, + std::string const &TargetOperandClass, bool HasOptionalOperands, + size_t MaxNumOperands) const; + virtual void + asmMatcherEmitConversionFunctionII(std::string const &EnumName, + StringRef const &AsmMatchConverter) const; + virtual void asmMatcherEmitConversionFunctionIII( + std::string const &EnumName, std::string const TargetOperandClass, + bool HasOptionalOperands, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const; + virtual void asmMatcherEmitConversionFunctionIV(std::string const &EnumName, + int64_t Val) const; + virtual void asmMatcherEmitConversionFunctionV(std::string const &EnumName, + std::string const &Reg) const; + virtual void asmMatcherEmitConversionFunctionVI() const; + virtual void asmMatcherWriteCvtOSToOS() const; + virtual void asmMatcherEmitOperandFunctionI(StringRef const &TargetName, + StringRef const &ClassName) const; + virtual void asmMatcherEmitOperandFunctionII( + std::string const &EnumName, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const; + virtual void + asmMatcherEmitOperandFunctionIII(std::string const &EnumName) const; + virtual void + asmMatcherEmitOperandFunctionIV(std::string const &EnumName) const; + virtual void asmMatcherEmitOperandFunctionV() const; + virtual void asmMatcherEmitTiedOperandEnum( + std::map, std::string> + TiedOperandsEnumMap) const; + virtual void asmMatcherWriteOpOSToOS() const; + virtual void asmMatcherEmitTiedOpTable( + std::map, std::string> + TiedOperandsEnumMap) const; + virtual void asmMatcherEmitTiedOpEmptyTable() const; + virtual void asmMatcherEmitOperandConvKindEnum( + SmallSetVector OperandConversionKinds) const; + virtual void asmMatcherEmitInstrConvKindEnum( + SmallSetVector InstructionConversionKinds) const; + virtual void asmMatcherEmitConversionTable( + size_t MaxRowLength, + std::vector> const ConversionTable, + SmallSetVector InstructionConversionKinds, + SmallSetVector OperandConversionKinds, + std::map, std::string> + TiedOperandsEnumMap) const; + virtual void asmMatcherEmitMatchClassKindEnum( + std::forward_list const &Infos) const; + virtual void + asmMatcherEmitMatchClassDiagStrings(AsmMatcherInfo const &Info) const; + virtual void asmMatcherEmitRegisterMatchErrorFunc(AsmMatcherInfo &Info) const; + virtual void asmMatcherEmitIsSubclassI() const; + virtual bool asmMatcherEmitIsSubclassII(bool EmittedSwitch, + std::string const &Name) const; + virtual void asmMatcherEmitIsSubclassIII(StringRef const &Name) const; + virtual void + asmMatcherEmitIsSubclassIV(std::vector const &SuperClasses) const; + virtual void asmMatcherEmitIsSubclassV(bool EmittedSwitch) const; + virtual void asmMatcherEmitValidateOperandClass(AsmMatcherInfo &Info) const; + virtual void + asmMatcherEmitMatchClassKindNames(std::forward_list &Infos) const; + virtual void + asmMatcherEmitAsmTiedOperandConstraints(CodeGenTarget &Target, + AsmMatcherInfo &Info) const; + virtual std::string + getNameForFeatureBitset(const std::vector &FeatureBitset) const; + virtual void asmMatcherEmitFeatureBitsetEnum( + std::vector> const FeatureBitsets) const; + virtual void asmMatcherEmitFeatureBitsets( + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const; + virtual void asmMatcherEmitMatchEntryStruct( + unsigned MaxMnemonicIndex, unsigned NumConverters, size_t MaxNumOperands, + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const; + virtual void asmMatcherEmitMatchFunction( + CodeGenTarget const &Target, Record const *AsmParser, + StringRef const &ClassName, bool HasMnemonicFirst, + bool HasOptionalOperands, bool ReportMultipleNearMisses, + bool HasMnemonicAliases, size_t MaxNumOperands, bool HasDeprecation, + unsigned int VariantCount) const; + virtual void asmMatcherEmitMnemonicSpellChecker(CodeGenTarget const &Target, + unsigned VariantCount) const; + virtual void asmMatcherEmitMnemonicChecker(CodeGenTarget const &Target, + unsigned VariantCount, + bool HasMnemonicFirst, + bool HasMnemonicAliases) const; + virtual void asmMatcherEmitCustomOperandParsing( + unsigned MaxMask, CodeGenTarget &Target, AsmMatcherInfo const &Info, + StringRef ClassName, StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, + bool HasMnemonicFirst, Record const &AsmParser) const; + virtual void asmMatcherEmitIncludes() const; + virtual void + asmMatcherEmitMnemonicTable(StringToOffsetTable &StringTable) const; + virtual void asmMatcherEmitMatchTable(CodeGenTarget const &Target, + AsmMatcherInfo &Info, + StringToOffsetTable &StringTable, + unsigned VariantCount) const; + virtual void asmMatcherEmitMatchRegisterName( + Record const *AsmParser, + std::vector const Matches) const; + virtual void asmMatcherEmitMatchTokenString( + std::vector const Matches) const; + virtual void asmMatcherEmitMatchRegisterAltName( + Record const *AsmParser, + std::vector const Matches) const; + virtual void asmMatcherEmitMnemonicAliasVariant( + std::vector const &Cases, + unsigned Indent) const; + virtual void asmMatcherAppendMnemonicAlias(Record const *R, + std::string const &FeatureMask, + std::string &MatchCode) const; + virtual void asmMatcherAppendMnemonic(Record const *R, + std::string &MatchCode) const; + virtual void asmMatcherAppendMnemonicAliasEnd(std::string &MatchCode) const; + virtual void asmMatcherEmitApplyMnemonicAliasesI() const; + virtual void + asmMatcherEmitApplyMnemonicAliasesII(int AsmParserVariantNo) const; + virtual void asmMatcherEmitApplyMnemonicAliasesIII() const; + virtual void asmMatcherEmitApplyMnemonicAliasesIV() const; + virtual void asmMatcherEmitApplyMnemonicAliasesV() const; + + //--------------------------- + // Backend: SearchableTables + //--------------------------- + + virtual void searchableTablesWriteFiles() const; + virtual void searchableTablesEmitGenericEnum(const GenericEnum &Enum) const; + virtual void searchableTablesEmitGenericTable(const GenericTable &Enum) const; + virtual void searchableTablesEmitIfdef(const std::string Guard, + StreamType ST = ST_NONE); + virtual void searchableTablesEmitEndif(StreamType ST = ST_NONE) const; + virtual void searchableTablesEmitUndef() const; + virtual void searchableTablesEmitLookupDeclaration(const GenericTable &Table, + const SearchIndex &Index, + StreamType ST); + virtual std::string searchableTablesPrimaryRepresentation( + SMLoc Loc, const GenericField &Field, Init *I, + StringRef const &InstrinsicEnumName) const; + virtual std::string searchableTablesSearchableFieldType( + const GenericTable &Table, const SearchIndex &Index, + const GenericField &Field, TypeContext Ctx) const; + virtual void + searchableTablesEmitKeyTypeStruct(const GenericTable &Table, + const SearchIndex &Index) const; + + virtual void + searchableTablesEmitIfFieldCase(const GenericField &Field, + std::string const &FirstRepr, + std::string const &LastRepr) const; + virtual void searchableTablesEmitIsContiguousCase(StringRef const &IndexName, + const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary); + virtual void searchableTablesEmitIndexArrayV() const; + virtual void searchableTablesEmitIndexArrayIV( + std::pair const &Entry) const; + virtual void searchableTablesEmitIndexArrayIII(ListSeparator &LS, + std::string Repr) const; + virtual void searchableTablesEmitIndexArrayII() const; + virtual void searchableTablesEmitIndexArrayI() const; + virtual void searchableTablesEmitIndexTypeStruct(const GenericTable &Table, + const SearchIndex &Index); + virtual void searchableTablesEmitReturns(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary); + virtual void + searchableTablesEmitIndexLamda(const SearchIndex &Index, + StringRef const &IndexName, + StringRef const &IndexTypeName) const; + virtual void searchableTablesEmitKeyArray(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) const; + virtual void searchableTablesEmitMapI(const GenericTable &Table) const; + virtual void searchableTablesEmitMapII() const; + virtual void searchableTablesEmitMapIII(const GenericTable &Table, + ListSeparator &LS, + GenericField const &Field, + StringRef &Intrinsic, + Record *Entry) const; + virtual void searchableTablesEmitMapIV(unsigned i) const; + virtual void searchableTablesEmitMapV(); +}; + +//============================== +// +// Implementation: Capstone +// +//============================== + +/// Printer implementation of Capstone. +/// +/// Output language: C +class PrinterCapstone : public PrinterLLVM { + // TODO: Toggle a flag is not nice to skip the search functions by strings + // is ugly. We should support them in the future. + bool EmittingNameLookup = false; + +public: + using PrinterLLVM::PrinterLLVM; + virtual void flushOS() const override { OS.flush(); } + + //-------------------------- + // General printing methods + //-------------------------- + + void emitNamespace(std::string const &Name, bool Begin, + std::string const &Comment = "", + bool Newline = true) const override; + void emitIfNotDef(std::string const &Name, bool Begin) const override; + void emitIncludeToggle(std::string const &Name, bool Begin, + bool Newline = true, + bool UndefAtEnd = false) const override; + void emitPPIf(std::string const &Arg, bool Begin, + bool Newline = true) const override; + + static std::string translateToC(std::string const &TargetName, + std::string const &Dec); + + //------------------------ + // Backend: RegisterInfo + //------------------------ + + void regInfoEmitSourceFileHeader(std::string const &Desc) const override; + void regInfoEmitEnums(CodeGenTarget const &Target, + CodeGenRegBank const &Bank) const override; + void regInfoEmitRegDiffLists( + std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const override; + void regInfoEmitLaneMaskLists( + std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const override; + void regInfoEmitSubRegIdxLists( + std::string const TargetName, + SequenceToOffsetTable>> const + &SubRegIdxSeqs) const override; + void regInfoEmitSubRegIdxSizes( + std::string const TargetName, + std::deque const &SubRegIndices) const override; + void regInfoEmitSubRegStrTable( + std::string const TargetName, + SequenceToOffsetTable const &RegStrings) const override; + void regInfoEmitRegDesc( + SequenceToOffsetTable const &LaneMaskSeqs, + std::deque const &Regs, + SequenceToOffsetTable>> const + &SubRegIdxSeqs, + SequenceToOffsetTable const &DiffSeqs, + SmallVector const &SubRegIdxLists, + SmallVector const &SubRegLists, + SmallVector const &SuperRegLists, + SmallVector const &RegUnitLists, + SmallVector const &RegUnitLaneMasks, + SequenceToOffsetTable const &RegStrings) const override; + void regInfoEmitRegUnitRoots(std::string const TargetName, + CodeGenRegBank const &RegBank) const override; + void + regInfoEmitRegClasses(std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings, + CodeGenTarget const &Target) const override; + void regInfoEmitStrLiteralRegClasses( + std::string const TargetName, + SequenceToOffsetTable const &RegClassStrings) const override; + void regInfoEmitMCRegClassesTable( + std::string const TargetName, + std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings) const override; + void regInfoEmitRegEncodingTable( + std::string const TargetName, + std::deque const &Regs) const override; + void regInfoEmitMCRegInfoInit( + std::string const TargetName, CodeGenRegBank const &RegBank, + std::deque const &Regs, + std::list const &RegClasses, + std::deque const &SubRegIndices) const override; + void regInfoEmitInfoDwarfRegs(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, bool IsCtor) const override; + void regInfoEmitInfoDwarfRegsRev(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, + bool IsCtor) const override; + void regInfoEmitInfoRegMapping(StringRef const &Namespace, unsigned MaxLength, + bool IsCtor) const override; + void regInfoEmitHeaderIncludes() const override; + void regInfoEmitHeaderExternRegClasses( + std::list const &RegClasses) const override; + void regInfoEmitHeaderDecl(std::string const &TargetName, + std::string const &ClassName, bool SubRegsPresent, + bool DeclareGetPhysRegBaseClass) const override; + void + regInfoEmitExternRegClassesArr(std::string const &TargetName) const override; + void regInfoEmitVTSeqs( + SequenceToOffsetTable> const &VTSeqs) + const override; + void regInfoEmitSubRegIdxTable( + std::deque const &SubRegIndices) const override; + void regInfoEmitRegClassInfoTable( + std::list const &RegClasses, + SequenceToOffsetTable> const &VTSeqs, + CodeGenHwModes const &CGH, unsigned NumModes) const override; + void regInfoEmitSubClassMaskTable( + std::list const &RegClasses, + SmallVector &SuperRegIdxLists, + SequenceToOffsetTable>> &SuperRegIdxSeqs, + std::deque const &SubRegIndices, + BitVector &MaskBV) const override; + void regInfoEmitSuperRegIdxSeqsTable( + SequenceToOffsetTable>> const &SuperRegIdxSeqs) + const override; + void regInfoEmitSuperClassesTable( + std::list const &RegClasses) const override; + void + regInfoEmitRegClassMethods(std::list const &RegClasses, + std::string const &TargetName) const override; + void regInfomitRegClassInstances( + std::list const &RegClasses, + SequenceToOffsetTable>> const &SuperRegIdxSeqs, + SmallVector const &SuperRegIdxLists, + std::string const &TargetName) const override; + void regInfoEmitRegClassTable( + std::list const &RegClasses) const override; + void regInfoEmitCostPerUseTable(std::vector const &AllRegCostPerUse, + unsigned NumRegCosts) const override; + void regInfoEmitInAllocatableClassTable( + llvm::BitVector const &InAllocClass) const override; + void regInfoEmitRegExtraDesc(std::string const &TargetName, + unsigned NumRegCosts) const override; + void regInfoEmitSubClassSubRegGetter( + std::string const &ClassName, unsigned SubRegIndicesSize, + std::deque const &SubRegIndices, + std::list const &RegClasses, + CodeGenRegBank &RegBank) const override; + void regInfoEmitRegClassWeight(CodeGenRegBank const &RegBank, + std::string const &ClassName) const override; + void regInfoEmitRegUnitWeight(CodeGenRegBank const &RegBank, + std::string const &ClassName, + bool RegUnitsHaveUnitWeight) const override; + void regInfoEmitGetNumRegPressureSets(std::string const &ClassName, + unsigned NumSets) const override; + void regInfoEmitGetRegPressureTables(CodeGenRegBank const &RegBank, + std::string const &ClassName, + unsigned NumSets) const override; + void regInfoEmitRCSetsTable( + std::string const &ClassName, unsigned NumRCs, + SequenceToOffsetTable> const &PSetsSeqs, + std::vector> const &PSets) const override; + void regInfoEmitGetRegUnitPressureSets( + SequenceToOffsetTable> const &PSetsSeqs, + CodeGenRegBank const &RegBank, std::string const &ClassName, + std::vector> const &PSets) const override; + void regInfoEmitExternTableDecl(std::string const &TargetName) const override; + void + regInfoEmitRegClassInit(std::string const &TargetName, + std::string const &ClassName, + CodeGenRegBank const &RegBank, + std::list const &RegClasses, + std::deque const &Regs, + unsigned SubRegIndicesSize) const override; + void regInfoEmitSaveListTable(Record const *CSRSet, + SetTheory::RecVec const *Regs) const override; + void regInfoEmitRegMaskTable(std::string const &CSRSetName, + BitVector &Covered) const override; + void regInfoEmitGetRegMasks(std::vector const &CSRSets, + std::string const &ClassName) const override; + void regInfoEmitGPRCheck( + std::string const &ClassName, + std::list const &RegCategories) const override; + void regInfoEmitFixedRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const override; + void regInfoEmitArgRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const override; + void regInfoEmitGetRegMaskNames(std::vector const &CSRSets, + std::string const &ClassName) const override; + void + regInfoEmitGetFrameLowering(std::string const &TargetName) const override; + void regInfoEmitComposeSubRegIndicesImplHead( + std::string const &ClName) const override; + void regInfoEmitComposeSubRegIndicesImplBody( + SmallVector, 4> const &Rows, + unsigned SubRegIndicesSize, + SmallVector const &RowMap) const override; + void regInfoEmitLaneMaskComposeSeq( + SmallVector, 4> const &Sequences, + SmallVector const &SubReg2SequenceIndexMap, + std::deque const &SubRegIndices) const override; + void regInfoEmitComposeSubRegIdxLaneMask( + std::string const &ClName, + std::deque const &SubRegIndices) const override; + void regInfoEmitComposeSubRegIdxLaneMaskRev( + std::string const &ClName, + std::deque const &SubRegIndices) const override; + void + regInfoEmitIsConstantPhysReg(std::deque const &Regs, + std::string const &ClassName) const override; + + //------------------------- + // Backend: DecoderEmitter + //------------------------- + + void decoderEmitterEmitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const override; + void + decoderEmitterEmitOpBinaryParser(raw_ostream &DecoderOS, + const OperandInfo &OpInfo) const override; + bool decoderEmitterEmitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, + raw_ostream &OS) const override; + bool decoderEmitterEmitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const override; + void decoderEmitterEmitCheck() const override; + void decoderEmitterEmitFieldFromInstruction() const override; + void decoderEmitterEmitInsertBits() const override; + void decoderEmitterEmitDecodeInstruction(bool IsVarLenInst) const override; + void decoderEmitterEmitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector &NumberedEncodings) const override; + void decoderEmitterEmitInstrLenTable( + std::vector &InstrLen) const override; + void decoderEmitterEmitPredicateFunction(PredicateSet &Predicates, + unsigned Indentation) const override; + void decoderEmitterEmitDecoderFunction(DecoderSet &Decoders, + unsigned Indentation) const override; + void decoderEmitterEmitIncludes() const override; + void decoderEmitterEmitSourceFileHeader() const override; + + //------------------------- + // Backend: AsmWriter + //------------------------- + + void asmWriterEmitSourceFileHeader(RecordKeeper &Records) const override; + void asmWriterEmitGetMnemonic(std::string const &TargetName, + StringRef const &ClassName) const override; + void asmWriterEmitAsmStrs( + SequenceToOffsetTable const &StrTable) const override; + void asmWriterEmitMnemonicDecodeTable( + unsigned const OpcodeInfoBits, unsigned BitsLeft, + unsigned const &AsmStrBits, + ArrayRef const &NumberedInstructions, + std::vector const &OpcodeInfo) const override; + void asmWriterEmitPrintInstruction( + std::string const &TargetName, + std::vector> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits, StringRef const &ClassName, + bool PassSubtarget) const override; + void asmWriterEmitOpCases( + std::vector> &OpsToPrint, + bool PassSubtarget) const override; + void asmWriterEmitInstrSwitch() const override; + void asmWriterEmitCompoundClosure(unsigned Indent, bool Newline, + bool Semicolon) const override; + void asmWriterEmitInstruction(AsmWriterInst const &FirstInst, + std::vector const &SimilarInsts, + unsigned DifferingOperand, + bool PassSubtarget) const override; + void asmWriterEmitGetRegNameAssert(std::string const &TargetName, + StringRef const &ClassName, + bool HasAltNames, + unsigned RegSize) const override; + void asmWriterEmitStringLiteralDef( + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const override; + void asmWriterEmitAltIdxSwitch(bool HasAltNames, + std::vector const &AltNameIndices, + StringRef const &Namespace) const override; + void asmWriterEmitRegAsmOffsets( + unsigned RegSizes, SmallVector const &AsmNames, + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const override; + char const *asmWriterGetPatCondKIgnore() const override; + char const *asmWriterGetPatCondKRegClass() const override; + char const *asmWriterGetPatCondKTiedReg() const override; + char const *asmWriterGetPatCondKCustom() const override; + char const *asmWriterGetPatCondKImm() const override; + char const *asmWriterGetPatCondKNoReg() const override; + char const *asmWriterGetPatCondKReg() const override; + char const *asmWriterGetPatCondKFeature() const override; + char const *asmWriterGetPatCondKEndOrFeature() const override; + char const *asmWriterGetPatOpcStart() const override; + char const *asmWriterGetCondPatStart() const override; + std::string asmWriterGetCond(std::string const &Cond) const override; + char const *asmWriterGetPatternFormat() const override; + char const *asmWriterGetOpcodeFormat() const override; + void asmWriterEmitPrintAliasInstrHeader(std::string const &TargetName, + StringRef const &ClassName, + bool PassSubtarget) const override; + void asmWriterEmitPrintAliasInstrBodyRetFalse() const override; + void asmWriterEmitPrintAliasInstrBody( + raw_string_ostream &OpcodeO, raw_string_ostream &PatternO, + raw_string_ostream &CondO, + std::vector> const &AsmStrings, + std::vector const &MCOpPredicates, + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const override; + void asmWriterEmitDeclValid(std::string const &TargetName, + StringRef const &ClassName) const override; + void asmWriterEmitPrintAliasOp( + std::string const &TargetName, StringRef const &ClassName, + std::vector> const &PrintMethods, + bool PassSubtarget) const override; + void asmWriterEmitPrintMC( + std::string const &TargetName, StringRef const &ClassName, + std::vector const &MCOpPredicates) const override; + + //------------------------- + // Backend: Subtarget + //------------------------- + + void subtargetEmitSourceFileHeader() const override; + void subtargetEmitFeatureEnum(DenseMap &FeatureMap, + std::vector const &DefList, + unsigned N) const override; + void subtargetEmitGetSTIMacro(StringRef const &Value, + StringRef const &Attribute) const override; + void subtargetEmitHwModes(CodeGenHwModes const &CGH, + std::string const &ClassName) const override; + void subtargetEmitFeatureKVHeader(std::string const &Target) const override; + void subtargetEmitFeatureKVEnd() const override; + void subtargetEmitFeatureKVPartI(std::string const &Target, + StringRef const &CommandLineName, + StringRef const &Name, + StringRef const &Desc) const override; + void subtargetEmitFeatureKVPartII() const override; + void subtargetEmitPrintFeatureMask( + std::array const &Mask) const override; + void subtargetEmitCPUKVHeader(std::string const &Target) const override; + void subtargetEmitCPUKVEnd() const override; + void subtargetEmitCPUKVPartI(StringRef const &Name) const override; + void subtargetEmitCPUKVPartII() const override; + void + subtargetEmitCPUKVPartIII(std::string const &ProcModelName) const override; + void subtargetEmitDBGMacrosBegin() const override; + void subtargetEmitDBGMacrosEnd() const override; + void subtargetEmitFunctionalItinaryUnits( + CodeGenSchedModels const &SchedModels) const override; + std::string const + subtargetGetBeginStageTable(std::string const &TargetName) const override; + std::string const subtargetGetBeginOperandCycleTable( + std::string const &TargetName) const override; + std::string const + subtargetGetBeginBypassTable(std::string const &TargetName) const override; + std::string const subtargetGetEndStageTable() const override; + std::string const subtargetGetEndOperandCycleTable() const override; + std::string const subtargetGetEndBypassTable() const override; + void subtargetFormItineraryStageString(std::string const &Name, + Record *ItinData, + std::string &ItinString, + unsigned &NStages) const override; + void subtargetFormItineraryOperandCycleString( + Record *ItinData, std::string &ItinString, + unsigned &NOperandCycles) const override; + void + subtargetFormItineraryBypassString(const std::string &Name, Record *ItinData, + std::string &ItinString, + unsigned NOperandCycles) const override; + std::string subtargetGetStageEntryPartI(std::string const &ItinStageString, + unsigned StageCount) const override; + std::string subtargetGetStageEntryPartII(unsigned StageCount, + unsigned NStages) const override; + std::string subtargetGetStageEntryPartIII() const override; + std::string subtargetGetOperandCycleEntryPartI( + std::string const &ItinOperandCycleString) const override; + std::string + subtargetGetOperandCycleEntryPartII(unsigned OperandCycleCount, + unsigned NOperandCycles) const override; + std::string subtargetGetOperandCycleEntryPartIII( + std::string const &OperandIdxComment) const override; + std::string subtargetGetOperandCycleEntryPartIV( + std::string const &ItinBypassString, + std::string const &OperandIdxComment) const override; + void subtargetEmitProcessorItineraryTable( + std::string const &ItinsDefName, std::vector &ItinList, + CodeGenSchedModels const &SchedModels) const override; + void subtargetEmitPreOperandTableComment() const override; + void subtargetEmitSchedClassTables( + SchedClassTablesT &SchedTables, std::string const &TargetName, + CodeGenSchedModels const &SchedModels) const override; + unsigned subtargetEmitRegisterFileTables( + CodeGenProcModel const &ProcModel) const override; + void subtargetEmitMCExtraProcInfoTableHeader( + std::string const &ProcModelName) const override; + void subtargetEmitMCExtraProcInfoTableEnd() const override; + void subtargetEmitReorderBufferSize(int64_t ReorderBufferSize) const override; + void subtargetEmitMaxRetirePerCycle(int64_t MaxRetirePerCycle) const override; + void subtargetEmitRegisterFileInfo(CodeGenProcModel const &ProcModel, + unsigned NumRegisterFiles, + unsigned NumCostEntries) const override; + void + subtargetEmitResourceDescriptorLoadQueue(unsigned QueueID) const override; + void + subtargetEmitResourceDescriptorStoreQueue(unsigned QueueID) const override; + void subtargetEmitProcessorResourceSubUnits( + const CodeGenProcModel &ProcModel, + CodeGenSchedModels const &SchedModels) const override; + void subtargetEmitMCProcResourceDescHeader( + std::string const &ProcModelName) const override; + void subtargetEmitMCProcResourceDescEnd() const override; + void subtargetEmitMCProcResourceDesc( + Record const *PRDef, Record const *SuperDef, + std::string const &ProcModelName, unsigned SubUnitsOffset, + unsigned SuperIdx, unsigned NumUnits, int BufferSize, unsigned I, + unsigned const SubUnitsBeginOffset) const override; + void subtargetEmitProcessorProp(Record const *R, StringRef const Name, + char Separator) const override; + void + subtargetEmitProcModelHeader(std::string const &ModelName) const override; + void + subtargetEmitProcModel(CodeGenProcModel const &PM, + CodeGenSchedModels const &SchedModels) const override; + void subtargetEmitResolveVariantSchedClassImplHdr() const override; + void subtargetEmitResolveVariantSchedClassImplEnd() const override; + void subtargetEmitSchedClassSwitch() const override; + void subtargetEmitSchedClassSwitchEnd() const override; + void subtargetEmitSchedClassCase(unsigned VC, + std::string const &SCName) const override; + void + subtargetEmitSchedClassProcGuard(unsigned Pi, bool OnlyExpandMCInstPredicates, + std::string const &ModelName) const override; + void subtargetEmitPredicates(CodeGenSchedTransition const &T, + CodeGenSchedClass const &SC, + bool (*IsTruePredicate)(Record const *Rec), + int Indent = -1) const override; + void subtargetEmitProcTransitionEnd() const override; + void + subtargetEmitSchedClassCaseEnd(CodeGenSchedClass const &SC) const override; + void + subtargetEmitSchedModelHelperEpilogue(bool ShouldReturnZero) const override; + void + subtargetEmitGenMCSubtargetInfoClass(std::string const &TargetName, + bool OverrideGetHwMode) const override; + void subtargetEmitMCSubtargetInfoImpl(std::string const &TargetName, + unsigned NumFeatures, unsigned NumProcs, + bool SchedModelHasItin) const override; + void subtargetEmitIncludeSTIDesc() const override; + void + subtargetEmitDFAPacketizerClass(CodeGenTarget &TGT, + std::string const &TargetName, + std::string const &ClassName) const override; + void subtargetEmitDFAPacketizerClassEnd() const override; + void subtargetEmitSTICtor() const override; + void subtargetEmitExternKVArrays(std::string const &TargetName, + bool SchedModelsHasItin) const override; + void subtargetEmitClassDefs(std::string const &TargetName, + std::string const &ClassName, + unsigned NumFeatures, unsigned NumProcs, + bool SchedModelsHasItin) const override; + void subtargetEmitResolveSchedClassHdr( + std::string const &ClassName) const override; + void subtargetEmitResolveSchedClassEnd( + std::string const &ClassName) const override; + void subtargetEmitResolveVariantSchedClass( + std::string const &TargetName, + std::string const &ClassName) const override; + void subtargetEmitPredicateProlog(const RecordKeeper &Records) const override; + void subtargetEmitParseFeaturesFunction( + std::string const &TargetName, + std::vector const &Features) const override; + void + subtargetEmitExpandedSTIPreds(StringRef const &TargetName, + std::string const &ClassName, + CodeGenSchedModels const &SchedModels) override; + void + subtargetPrepareSchedClassPreds(StringRef const &TargetName, + bool OnlyExpandMCInstPredicates) override; + void subtargetEmitExpandedSTIPredsMCAnaDecl( + StringRef const &TargetName, + CodeGenSchedModels const &SchedModels) override; + void subtargetEmitExpandedSTIPredsMCAnaDefs( + StringRef const &TargetName, std::string const &ClassPrefix, + CodeGenSchedModels const &SchedModels) const override; + void subtargetEmitExpandedSTIPredsHeader( + StringRef const &TargetName, + CodeGenSchedModels const &SchedModels) override; + void subtargetEmitStageAndSycleTables( + std::string const &StageTable, std::string const &OperandCycleTable, + std::string const &BypassTable) const override; + + //--------------------------- + // Backend: InstrInfoEmitter + //--------------------------- + + void instrInfoEmitSourceFileHeader() const override; + void instrInfoEmitSetGetComputeFeatureMacro() const override; + void instrInfoSetOperandInfoStr( + std::string &Res, Record const *OpR, + CGIOperandList::OperandInfo const &Op, + CGIOperandList::ConstraintInfo const &Constraint) const override; + void instrInfoEmitMCInstrDescHdr(std::string TargetName) const override; + void instrInfoEmitMCInstrDescClose() const override; + void instrInfoEmitMCInstrDescEnd() const override; + void instrInfoEmitMCInstrImplUses( + std::vector> ImplicitLists, + std::map, unsigned> &EmittedLists) const override; + void instrInfoEmitRecord(CodeGenSchedModels const &SchedModels, + CodeGenInstruction const &Inst, unsigned Num, + int MinOperands) const override; + void + instrInfoEmitTargetIndepFlags(CodeGenInstruction const &Inst, + bool GetAllowRegisterRenaming) const override; + void instrInfoEmitTSFFlags(uint64_t Value) const override; + void instrInfoEmitUseDefsLists( + StringRef TargetName, const CodeGenInstruction &Inst, + std::map, unsigned> &EmittedLists, + std::vector const &ImplicitOps) const override; + void + instrInfoEmitOperandInfo(OperandInfoListTy &OperandInfoList) const override; + void instrInfoEmitOperandInfoOffset( + StringRef TargetName, std::vector const &OperandInfo, + OperandInfoMapTy const &OperandInfoMap) const override; + void instrInfoEmitRecordEnd(unsigned InstNum, + std::string const &InstName) const override; + void instrInfoEmitMCInstrDescDecl(std::string const &TargetName, + unsigned NumberedInstructionsSize, + unsigned OperandInfoSize, + unsigned ImplicitListSize) const override; + void instrInfoEmitStringLiteralDef( + std::string const &TargetName, + SequenceToOffsetTable InstrNames) const override; + void instrInfoEmitInstrNameIndices( + std::string const &TargetName, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const override; + void instrInfoEmitInstrDeprFeatures( + std::string const &TargetName, std::string const &TargetNamespace, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const override; + void + instrInfoEmitInstrComplexDeprInfos(std::string const &TargetName, + ArrayRef const + &NumberedInstructions) const override; + void instrInfoEmitMCInstrInfoInitRoutine( + std::string const &TargetName, unsigned NumberedInstrSize, + bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const override; + void instrInfoEmitHeader(std::string const &TargetName) const override; + void instrInfoEmitClassStruct(std::string const &ClassName) const override; + void instrInfoEmitTIIHelperMethod(StringRef const &TargetName, + Record const *Rec, + bool ExpandDefinition) const override; + void + instrInfoEmitExternArrays(std::string const &TargetName, + bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const override; + void + instrInfoEmitMCInstrInfoInit(std::string const &TargetName, + unsigned NumberedInstrSize, + bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const override; + void instrInfoEmitOperandEnum( + std::map const &Operands) const override; + void instrInfoEmitGetNamedOperandIdx( + std::map const &Operands, + OpNameMapTy const &OperandMap) const override; + void instrInfoEmitOpTypeEnumPartI() const override; + void instrInfoEmitOpTypeEnumPartII(StringRef const &OpName, + unsigned EnumVal) const override; + void instrInfoEmitOpTypeEnumPartIII() const override; + void instrInfoEmitOpTypeOffsetTable(std::vector OperandOffsets, + unsigned OpRecSize, + ArrayRef const + &NumberedInstructions) const override; + void instrInfoEmitOpcodeOpTypesTable( + unsigned EnumVal, std::vector const &OperandRecords, + std::vector OperandOffsets, + ArrayRef const &NumberedInstructions) + const override; + void instrInfoEmitGetOpTypeHdr() const override; + void instrInfoEmitGetOpTypeReturn() const override; + void instrInfoEmitGetOpTypeUnreachable() const override; + void instrInfoEmitGetOpTypeEnd() const override; + void instrInfoEmitGetMemOpSizeHdr() const override; + void instrInfoEmitGetOpMemSizeTbl(std::map> + &SizeToOperandName) const override; + std::string + instrInfoGetInstMapEntry(StringRef const &Namespace, + StringRef const &InstrName) const override; + void instrInfoEmitGetLogicalOpSizeHdr() const override; + void instrInfoEmitGetLogicalOpSizeTable( + size_t LogicalOpListSize, + std::vector *> const &LogicalOpSizeList) + const override; + void instrInfoEmitGetLogicalOpSizeSwitch( + std::map> InstMap) const override; + void instrInfoEmitGetLogicalOpSizeReturn() const override; + void instrInfoEmitGetLogicalOpSizeEnd() const override; + void instrInfoEmitGetLogicalOpIdx() const override; + std::string + instrInfoGetOpTypeListEntry(StringRef const &Namespace, + StringRef const &OpName) const override; + void instrInfoEmitGetLogicalOpTypeHdr() const override; + void instrInfoEmitGetLogicalOpTypeTable( + size_t LogicalOpTypeListSize, + std::vector *> const &LogicalOpTypeList) + const override; + void instrInfoEmitGetLogicalOpTypeSwitch( + std::map> InstMap) const override; + void instrInfoEmitGetLogicalOpTypeReturn() const override; + void instrInfoEmitGetLogicalOpTypeEnd() const override; + void instrInfoEmitDeclareMCInstFeatureClasses() const override; + void instrInfoEmitPredFcnDecl(RecVec const &TIIPredicates) const override; + void instrInfoEmitPredFcnImpl(StringRef const &TargetName, + RecVec const &TIIPredicates) override; + void instrInfoEmitInstrPredVerifierIncludes() const override; + void instrInfoEmitMacroDefineCheck() const override; + void instrInfoEmitSubtargetFeatureBitEnumeration( + std::map + &SubtargetFeatures) const override; + void instrInfoEmitEmitSTFNameTable( + std::map + &SubtargetFeatures) const override; + void instrInfoEmitFeatureBitsEnum( + std::vector> const &FeatureBitsets) const override; + void instrInfoEmitFeatureBitsArray( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures) const override; + void instrInfoEmitRequiredFeatureRefs( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures, + CodeGenTarget const &Target) const override; + void instrInfoEmitOpcodeChecker() const override; + void + instrInfoEmitPredicateVerifier(StringRef const &TargetName) const override; + void instrInfoEmitEnums(CodeGenTarget const &Target, + StringRef const &Namespace, + CodeGenSchedModels const &SchedModels) const override; + void instrInfoEmitTIIPredicates(StringRef const &TargetName, + RecVec const &TIIPredicates, + bool ExpandDefinition) override; + void instrInfoEmitComputeAssemblerAvailableFeatures( + StringRef const &TargetName, + std::map + &SubtargetFeatures) const override; + + //-------------------------- + // Backend: AsmMatcher + //-------------------------- + + void asmMatcherEmitSourceFileHeader(std::string const &Desc) const override; + void asmMatcherEmitDeclarations(bool HasOptionalOperands, + bool ReportMultipleNearMisses, + bool HasOperandInfos) const override; + void asmMatcherEmitOperandDiagTypes( + std::set const Types) const override; + + void asmMatcherEmitGetSubtargetFeatureName( + std::map const + SubtargetFeatures) const override; + void asmMatcherEmitConversionFunctionI(StringRef const &TargetName, + StringRef const &ClassName, + std::string const &TargetOperandClass, + bool HasOptionalOperands, + size_t MaxNumOperands) const override; + void asmMatcherEmitConversionFunctionII( + std::string const &EnumName, + StringRef const &AsmMatchConverter) const override; + void asmMatcherEmitConversionFunctionIII( + std::string const &EnumName, std::string const TargetOperandClass, + bool HasOptionalOperands, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const override; + void asmMatcherEmitConversionFunctionIV(std::string const &EnumName, + int64_t Val) const override; + void asmMatcherEmitConversionFunctionV(std::string const &EnumName, + std::string const &Reg) const override; + void asmMatcherEmitConversionFunctionVI() const override; + void asmMatcherWriteCvtOSToOS() const override; + void + asmMatcherEmitOperandFunctionI(StringRef const &TargetName, + StringRef const &ClassName) const override; + void asmMatcherEmitOperandFunctionII( + std::string const &EnumName, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const override; + void + asmMatcherEmitOperandFunctionIII(std::string const &EnumName) const override; + void + asmMatcherEmitOperandFunctionIV(std::string const &EnumName) const override; + void asmMatcherEmitOperandFunctionV() const override; + void asmMatcherEmitTiedOperandEnum( + std::map, std::string> + TiedOperandsEnumMap) const override; + void asmMatcherWriteOpOSToOS() const override; + void asmMatcherEmitTiedOpTable( + std::map, std::string> + TiedOperandsEnumMap) const override; + void asmMatcherEmitTiedOpEmptyTable() const override; + void asmMatcherEmitOperandConvKindEnum( + SmallSetVector OperandConversionKinds) + const override; + void asmMatcherEmitInstrConvKindEnum( + SmallSetVector InstructionConversionKinds) + const override; + void asmMatcherEmitConversionTable( + size_t MaxRowLength, + std::vector> const ConversionTable, + SmallSetVector InstructionConversionKinds, + SmallSetVector OperandConversionKinds, + std::map, std::string> + TiedOperandsEnumMap) const override; + void asmMatcherEmitMatchClassKindEnum( + std::forward_list const &Infos) const override; + void asmMatcherEmitMatchClassDiagStrings( + AsmMatcherInfo const &Info) const override; + void + asmMatcherEmitRegisterMatchErrorFunc(AsmMatcherInfo &Info) const override; + void asmMatcherEmitIsSubclassI() const override; + bool asmMatcherEmitIsSubclassII(bool EmittedSwitch, + std::string const &Name) const override; + void asmMatcherEmitIsSubclassIII(StringRef const &Name) const override; + void asmMatcherEmitIsSubclassIV( + std::vector const &SuperClasses) const override; + void asmMatcherEmitIsSubclassV(bool EmittedSwitch) const override; + void asmMatcherEmitValidateOperandClass(AsmMatcherInfo &Info) const override; + void asmMatcherEmitMatchClassKindNames( + std::forward_list &Infos) const override; + void + asmMatcherEmitAsmTiedOperandConstraints(CodeGenTarget &Target, + AsmMatcherInfo &Info) const override; + std::string getNameForFeatureBitset( + const std::vector &FeatureBitset) const override; + void asmMatcherEmitFeatureBitsetEnum( + std::vector> const FeatureBitsets) const override; + void asmMatcherEmitFeatureBitsets( + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const override; + void asmMatcherEmitMatchEntryStruct( + unsigned MaxMnemonicIndex, unsigned NumConverters, size_t MaxNumOperands, + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const override; + void asmMatcherEmitMatchFunction( + CodeGenTarget const &Target, Record const *AsmParser, + StringRef const &ClassName, bool HasMnemonicFirst, + bool HasOptionalOperands, bool ReportMultipleNearMisses, + bool HasMnemonicAliases, size_t MaxNumOperands, bool HasDeprecation, + unsigned int VariantCount) const override; + void asmMatcherEmitMnemonicSpellChecker(CodeGenTarget const &Target, + unsigned VariantCount) const override; + void asmMatcherEmitMnemonicChecker(CodeGenTarget const &Target, + unsigned VariantCount, + bool HasMnemonicFirst, + bool HasMnemonicAliases) const override; + void asmMatcherEmitCustomOperandParsing( + unsigned MaxMask, CodeGenTarget &Target, AsmMatcherInfo const &Info, + StringRef ClassName, StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, + bool HasMnemonicFirst, Record const &AsmParser) const override; + void asmMatcherEmitIncludes() const override; + void + asmMatcherEmitMnemonicTable(StringToOffsetTable &StringTable) const override; + void asmMatcherEmitMatchTable(CodeGenTarget const &Target, + AsmMatcherInfo &Info, + StringToOffsetTable &StringTable, + unsigned VariantCount) const override; + void asmMatcherEmitMatchRegisterName( + Record const *AsmParser, + std::vector const Matches) const override; + void asmMatcherEmitMatchTokenString( + std::vector const Matches) const override; + void asmMatcherEmitMatchRegisterAltName( + Record const *AsmParser, + std::vector const Matches) const override; + void asmMatcherEmitMnemonicAliasVariant( + std::vector const &Cases, + unsigned Indent) const override; + void asmMatcherAppendMnemonicAlias(Record const *R, + std::string const &FeatureMask, + std::string &MatchCode) const override; + void asmMatcherAppendMnemonic(Record const *R, + std::string &MatchCode) const override; + void asmMatcherAppendMnemonicAliasEnd(std::string &MatchCode) const override; + void asmMatcherEmitApplyMnemonicAliasesI() const override; + void + asmMatcherEmitApplyMnemonicAliasesII(int AsmParserVariantNo) const override; + void asmMatcherEmitApplyMnemonicAliasesIII() const override; + void asmMatcherEmitApplyMnemonicAliasesIV() const override; + void asmMatcherEmitApplyMnemonicAliasesV() const override; + void + subtargetEmitGetMacroFusions(CodeGenTarget &TGT, std::string Target, + const std::string &ClassName) const override; + void asmMatcherEmitSTFBitEnum(AsmMatcherInfo &Info) const override; + void asmMatcherEmitComputeAssemblerAvailableFeatures( + AsmMatcherInfo &Info, StringRef const &ClassName) const override; + + //--------------------------- + // Backend: SearchableTables + //--------------------------- + + raw_string_ostream &searchableTablesGetOS(StreamType G) const; + void searchableTablesWriteFiles() const override; + void searchableTablesEmitGenericEnum(const GenericEnum &Enum) const override; + void + searchableTablesEmitGenericTable(const GenericTable &Enum) const override; + void searchableTablesEmitIfdef(const std::string Guard, + StreamType ST = ST_NONE) override; + void searchableTablesEmitEndif(StreamType ST = ST_NONE) const override; + void searchableTablesEmitUndef() const override; + void searchableTablesEmitLookupDeclaration(const GenericTable &Table, + const SearchIndex &Index, + StreamType ST) override; + std::string searchableTablesPrimaryRepresentation( + SMLoc Loc, const GenericField &Field, Init *I, + StringRef const &InstrinsicEnumName) const override; + std::string searchableTablesSearchableFieldType( + const GenericTable &Table, const SearchIndex &Index, + const GenericField &Field, TypeContext Ctx) const override; + void + searchableTablesEmitKeyTypeStruct(const GenericTable &Table, + const SearchIndex &Index) const override; + + void + searchableTablesEmitIfFieldCase(const GenericField &Field, + std::string const &FirstRepr, + std::string const &LastRepr) const override; + void searchableTablesEmitIsContiguousCase(StringRef const &IndexName, + const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) override; + void searchableTablesEmitIndexArrayV() const override; + void searchableTablesEmitIndexArrayIV( + std::pair const &Entry) const override; + void searchableTablesEmitIndexArrayIII(ListSeparator &LS, + std::string Repr) const override; + void searchableTablesEmitIndexArrayII() const override; + void searchableTablesEmitIndexArrayI() const override; + void searchableTablesEmitIndexTypeStruct(const GenericTable &Table, + const SearchIndex &Index) override; + void searchableTablesEmitReturns(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) override; + void + searchableTablesEmitIndexLamda(const SearchIndex &Index, + StringRef const &IndexName, + StringRef const &IndexTypeName) const override; + void searchableTablesEmitKeyArray(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) const override; + void searchableTablesEmitMapI(const GenericTable &Table) const override; + void searchableTablesEmitMapII() const override; + void searchableTablesEmitMapIII(const GenericTable &Table, ListSeparator &LS, + GenericField const &Field, + StringRef &Intrinsic, + Record *Entry) const override; + void searchableTablesEmitMapIV(unsigned i) const override; + void searchableTablesEmitMapV() override; +}; + +} // end namespace llvm + +#endif // LLVM_UTILS_TABLEGEN_PRINTER_H diff --git a/llvm/utils/TableGen/PrinterCapstone.cpp b/llvm/utils/TableGen/PrinterCapstone.cpp new file mode 100644 index 000000000000..775e79037bab --- /dev/null +++ b/llvm/utils/TableGen/PrinterCapstone.cpp @@ -0,0 +1,4063 @@ +//===------------- PrinterCapstone.cpp - Printer Capstone -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Emits the generated decoder C code for the Capstone. +// +//===----------------------------------------------------------------------===// + +#include "Printer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include + +static void emitDefaultSourceFileHeader(raw_ostream &OS) { + OS << "/* Capstone Disassembly Engine, https://www.capstone-engine.org */\n" + << "/* By Nguyen Anh Quynh , 2013-2022, */\n" + << "/* Rot127 2022-2024 */\n" + << "/* Automatically generated file by Capstone's LLVM TableGen " + "Disassembler " + "Backend. */\n\n" + << "/* LLVM-commit: */\n" + << "/* LLVM-tag: */\n\n" + << "/* Do not edit. */\n\n" + << "/* Capstone's LLVM TableGen Backends: */\n" + << "/* https://github.com/capstone-engine/llvm-capstone */\n\n"; +} + +namespace llvm { + +/// Prints `namespace {` and `} // end namespace ` to the output +/// stream. If Name == "" it emits an anonymous namespace. +void PrinterCapstone::emitNamespace(std::string const &Name, bool Begin, + std::string const &Comment, + bool Newline) const { + return; +} + +/// Prints +/// ``` +/// #if +/// ``` +/// and +/// `#endif // ` +/// Used to control inclusion of a code block via a macro definition. +void PrinterCapstone::emitPPIf(std::string const &Arg, bool Begin, + bool Newline) const { + if (Begin) { + OS << "#if " << Arg << "\n"; + } else { + OS << "#endif // " << Arg << (Newline ? "\n\n" : "\n"); + } +} + +/// Prints +/// ``` +/// #ifdef +/// #undef +/// ``` +/// and +/// `#endif // ` +/// Used to control inclusion of a code block via a macro definition. +void PrinterCapstone::emitIncludeToggle(std::string const &Name, bool Begin, + bool Newline, bool UndefAtEnd) const { + std::set Ignore = {"GET_REGINFO_TARGET_DESC", + "GET_REGINFO_HEADER", + "GET_MNEMONIC_CHECKER", + "GET_MNEMONIC_SPELL_CHECKER", + "GET_MATCHER_IMPLEMENTATION", + "GET_SUBTARGET_FEATURE_NAME", + "GET_REGISTER_MATCHER", + "GET_OPERAND_DIAGNOSTIC_TYPES", + "GET_ASSEMBLER_HEADER", + "GET_INSTRINFO_HEADER", + "GET_INSTRINFO_HELPER_DECLS", + "GET_INSTRINFO_HELPERS", + "GET_INSTRINFO_CTOR_DTOR", + "GET_INSTRINFO_OPERAND_ENUM", + "GET_INSTRINFO_NAMED_OPS", + "GET_INSTRINFO_OPERAND_TYPES_ENUM", + "GET_INSTRINFO_OPERAND_TYPE", + "GET_INSTRINFO_MEM_OPERAND_SIZE", + "GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP", + "GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP", + "GET_INSTRINFO_MC_HELPER_DECLS", + "GET_INSTRINFO_MC_HELPERS", + "ENABLE_INSTR_PREDICATE_VERIFIER", + "GET_GENISTRINFO_MC_HELPERS", + "GET_SUBTARGETINFO_MC_DESC", + "GET_SUBTARGETINFO_TARGET_DESC", + "GET_SUBTARGETINFO_HEADER", + "GET_SUBTARGETINFO_CTOR", + "GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS", + "GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS", + "GET_SUBTARGETINFO_MACRO"}; + if (Ignore.find(Name) != Ignore.end()) + return; + if (Begin) { + OS << "#ifdef " << Name << "\n"; + if (!UndefAtEnd) + OS << "#undef " << Name << "\n\n"; + } else { + if (UndefAtEnd) + OS << "#undef " << Name << "\n"; + OS << "#endif // " << Name << (Newline ? "\n\n" : "\n"); + } +} + +void PrinterCapstone::emitIfNotDef(std::string const &Name, bool Begin) const { + if (Name == "NDEBUG") + return; + if (Begin) { + OS << "#ifndef " << Name << "\n"; + } else { + OS << "#endif // " << Name << "\n\n"; + } +} + +void PrinterCapstone::regInfoEmitSourceFileHeader( + std::string const &Desc) const { + static unsigned Count = 0; + if (Count > 0) { + // Only emit it once at the beginning. + return; + } + emitDefaultSourceFileHeader(OS); + ++Count; +} + +void writeFile(std::string Filename, std::string const &Str) { + std::error_code EC; + ToolOutputFile InsnMapFile(Filename, EC, sys::fs::OF_Text); + if (EC) + PrintFatalNote("Could no write \"" + Filename + "\" Error:\n" + + EC.message()); + InsnMapFile.os() << Str; + InsnMapFile.keep(); +} + +// runEnums - Print out enum values for all of the registers. +void PrinterCapstone::regInfoEmitEnums(CodeGenTarget const &Target, + CodeGenRegBank const &Bank) const { + std::string CSRegEnumStr; + raw_string_ostream CSRegEnum(CSRegEnumStr); + emitDefaultSourceFileHeader(CSRegEnum); + + const auto &Registers = Bank.getRegisters(); + + // Register enums are stored as uint16_t in the tables. Make sure we'll fit. + assert(Registers.size() <= 0xffff && "Too many regs to fit in tables"); + + emitIncludeToggle("GET_REGINFO_ENUM", true); + StringRef TargetName = Target.getName(); + + OS << "enum {\n " << TargetName << "_NoRegister,\n"; + CSRegEnum << "\t" << TargetName << "_REG_INVALID = 0,\n"; + + for (const auto &Reg : Registers) { + OS << " " << TargetName << "_" << Reg.getName() << " = " << Reg.EnumValue + << ",\n"; + CSRegEnum << "\t" << TargetName << "_REG_" << Reg.getName() << " = " + << Reg.EnumValue << ",\n"; + } + assert(Registers.size() == Registers.back().EnumValue && + "Register enum value mismatch!"); + OS << " NUM_TARGET_REGS // " << Registers.size() + 1 << "\n"; + OS << "};\n"; + CSRegEnum << "\t" << TargetName << "_REG_ENDING, // " << Registers.size() + 1 + << "\n"; + + writeFile(TargetName.str() + "GenCSRegEnum.inc", CSRegEnumStr); + + const auto &RegisterClasses = Bank.getRegClasses(); + if (!RegisterClasses.empty()) { + + // RegisterClass enums are stored as uint16_t in the tables. + assert(RegisterClasses.size() <= 0xffff && + "Too many register classes to fit in tables"); + + OS << "\n// Register classes\n\n"; + OS << "enum {\n"; + for (const auto &RC : RegisterClasses) + OS << " " << TargetName << "_" << RC.getName() << "RegClassID" + << " = " << RC.EnumValue << ",\n"; + OS << "\n};\n"; + } + + const std::vector &RegAltNameIndices = + Target.getRegAltNameIndices(); + // If the only definition is the default NoRegAltName, we don't need to + // emit anything. + if (RegAltNameIndices.size() > 1) { + OS << "\n// Register alternate name indices\n\n"; + OS << "enum {\n"; + for (unsigned I = 0, E = RegAltNameIndices.size(); I != E; ++I) + OS << " " << TargetName << "_" << RegAltNameIndices[I]->getName() + << ",\t// " << I << "\n"; + OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; + OS << "};\n"; + } + + auto &SubRegIndices = Bank.getSubRegIndices(); + if (!SubRegIndices.empty()) { + OS << "\n// Subregister indices\n\n"; + std::string const Namespace = SubRegIndices.front().getNamespace(); + OS << "enum {\n " << TargetName << "_NoSubRegister,\n"; + unsigned I = 0; + for (const auto &Idx : SubRegIndices) + OS << " " << TargetName << "_" << Idx.getName() << ",\t// " << ++I + << "\n"; + OS << " " << TargetName << "_NUM_TARGET_SUBREGS\n};\n"; + } + emitIncludeToggle("GET_REGINFO_ENUM", false); +} + +static void printDiff16(raw_ostream &OS, int16_t Val) { OS << Val; } + +void PrinterCapstone::regInfoEmitRegDiffLists( + std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const { + OS << "static const MCPhysReg " << TargetName << "RegDiffLists[] = {\n"; + DiffSeqs.emit(OS, printDiff16); + OS << "};\n\n"; +} + +void PrinterCapstone::regInfoEmitLaneMaskLists( + std::string const TargetName, + SequenceToOffsetTable const &LaneMaskSeqs) const { + return; +} + +void PrinterCapstone::regInfoEmitSubRegIdxLists( + std::string const TargetName, + SequenceToOffsetTable>> const + &SubRegIdxSeqs) const { + OS << "static const uint16_t " << TargetName << "SubRegIdxLists[] = {\n"; + SubRegIdxSeqs.emit(OS, [](raw_ostream &OS, const CodeGenSubRegIndex *Idx) { + OS << Idx->EnumValue; + }); + OS << "};\n\n"; +} + +void PrinterCapstone::regInfoEmitSubRegIdxSizes( + std::string const TargetName, + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitSubRegStrTable( + std::string const TargetName, + SequenceToOffsetTable const &RegStrings) const { + OS << "static const MCRegisterDesc " << TargetName + << "RegDesc[] = { // Descriptors\n"; + OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n"; +} + +void PrinterCapstone::regInfoEmitRegDesc( + SequenceToOffsetTable const &LaneMaskSeqs, + std::deque const &Regs, + SequenceToOffsetTable>> const + &SubRegIdxSeqs, + SequenceToOffsetTable const &DiffSeqs, + SmallVector const &SubRegIdxLists, + SmallVector const &SubRegLists, + SmallVector const &SuperRegLists, + SmallVector const &RegUnitLists, + SmallVector const &RegUnitLaneMasks, + SequenceToOffsetTable const &RegStrings) const { + unsigned i = 0; + for (const auto &Reg : Regs) { + unsigned FirstRU = Reg.getNativeRegUnits().find_first(); + unsigned Offset = DiffSeqs.get(RegUnitLists[i]); + // The value must be kept in sync with MCRegisterInfo.h. + constexpr unsigned RegUnitBits = 12; + assert(isUInt(FirstRU) && "Too many regunits"); + assert(isUInt<32 - RegUnitBits>(Offset) && "Offset is too big"); + OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " + << DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) + << ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " + << (Offset << RegUnitBits | FirstRU) << ", " + << LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n"; + ++i; + } + OS << "};\n\n"; +} + +void PrinterCapstone::regInfoEmitRegUnitRoots( + std::string const TargetName, CodeGenRegBank const &RegBank) const { + return; +} + +static std::string getQualifiedNameCCS(const Record *R) { + std::string Namespace; + if (R->getValue("Namespace")) + Namespace = std::string(R->getValueAsString("Namespace")); + if (Namespace.empty()) + return std::string(R->getName()); + return StringRef(Namespace).str() + "_" + R->getName().str(); +} + +void PrinterCapstone::regInfoEmitRegClasses( + std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings, + CodeGenTarget const &Target) const { + for (const auto &RC : RegClasses) { + ArrayRef const Order = RC.getOrder(); + + // Give the register class a legal C name if it's anonymous. + const std::string &Name = RC.getName(); + + RegClassStrings.add(Name); + + // Emit the register list now (unless it would be a zero-length array). + if (!Order.empty()) { + OS << " // " << Name << " Register Class...\n" + << " static const MCPhysReg " << Name << "[] = {\n "; + for (Record *Reg : Order) { + OS << getQualifiedNameCCS(Reg) << ", "; + } + OS << "\n };\n\n"; + + OS << " // " << Name << " Bit set.\n" + << " static const uint8_t " << Name << "Bits[] = {\n "; + PrinterBitVectorEmitter BVE; + for (Record *Reg : Order) { + BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); + } + BVE.print(OS); + OS << "\n };\n\n"; + } + } +} + +void PrinterCapstone::regInfoEmitStrLiteralRegClasses( + std::string const TargetName, + SequenceToOffsetTable const &RegClassStrings) const { + return; +} + +void PrinterCapstone::regInfoEmitMCRegClassesTable( + std::string const TargetName, + std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings) const { + OS << "static const MCRegisterClass " << TargetName + << "MCRegisterClasses[] = {\n"; + + for (const auto &RC : RegClasses) { + ArrayRef const Order = RC.getOrder(); + std::string const RCName = Order.empty() ? "nullptr" : RC.getName(); + std::string const RCBitsName = + Order.empty() ? "nullptr" : RC.getName() + "Bits"; + std::string const RCBitsSize = + Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; + assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); + // For Capstone we are only interested in: + // RegClass Name, Size group and bit size + OS << " { " << RCName << ", " << RCBitsName << ", " << RCBitsSize + << " },\n"; + } + + OS << "};\n\n"; +} + +void PrinterCapstone::regInfoEmitRegEncodingTable( + std::string const TargetName, + std::deque const &Regs) const { + OS << "static const uint16_t " << TargetName; + OS << "RegEncodingTable[] = {\n"; + // Add entry for NoRegister + OS << " 0,\n"; + for (const auto &RE : Regs) { + Record *Reg = RE.TheDef; + BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); + uint64_t Value = 0; + for (unsigned I = 0, Ie = BI->getNumBits(); I != Ie; ++I) { + if (BitInit *B = dyn_cast(BI->getBit(I))) + Value |= (uint64_t)B->getValue() << I; + } + OS << " " << Value << ",\n"; + } + OS << "};\n"; // End of HW encoding table + return; +} + +void PrinterCapstone::regInfoEmitMCRegInfoInit( + std::string const TargetName, CodeGenRegBank const &RegBank, + std::deque const &Regs, + std::list const &RegClasses, + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitInfoDwarfRegsRev( + StringRef const &Namespace, DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, bool IsCtor) const { + return; +} + +void PrinterCapstone::regInfoEmitInfoDwarfRegs(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, + bool IsCtor) const { + return; +} + +void PrinterCapstone::regInfoEmitInfoRegMapping(StringRef const &Namespace, + unsigned MaxLength, + bool IsCtor) const { + return; +} + +void PrinterCapstone::regInfoEmitHeaderIncludes() const { return; } + +void PrinterCapstone::regInfoEmitHeaderExternRegClasses( + std::list const &RegClasses) const { + return; +} + +void PrinterCapstone::regInfoEmitHeaderDecl( + std::string const &TargetName, std::string const &ClassName, + bool SubRegsPresent, bool DeclareGetPhysRegBaseClass) const { + return; +} + +void PrinterCapstone::regInfoEmitExternRegClassesArr( + std::string const &TargetName) const { + return; +} + +void PrinterCapstone::regInfoEmitVTSeqs( + SequenceToOffsetTable> const &VTSeqs) + const { + return; +} + +void PrinterCapstone::regInfoEmitSubRegIdxTable( + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitRegClassInfoTable( + std::list const &RegClasses, + SequenceToOffsetTable> const &VTSeqs, + CodeGenHwModes const &CGH, unsigned NumModes) const { + return; +} + +void PrinterCapstone::regInfoEmitSubClassMaskTable( + std::list const &RegClasses, + SmallVector &SuperRegIdxLists, + SequenceToOffsetTable>> &SuperRegIdxSeqs, + std::deque const &SubRegIndices, + BitVector &MaskBV) const { + return; +} + +void PrinterCapstone::regInfoEmitSuperRegIdxSeqsTable( + SequenceToOffsetTable>> const &SuperRegIdxSeqs) + const { + return; +} + +void PrinterCapstone::regInfoEmitSuperClassesTable( + std::list const &RegClasses) const { + return; +} + +void PrinterCapstone::regInfoEmitRegClassMethods( + std::list const &RegClasses, + std::string const &TargetName) const { + return; +} + +void PrinterCapstone::regInfomitRegClassInstances( + std::list const &RegClasses, + SequenceToOffsetTable>> const &SuperRegIdxSeqs, + SmallVector const &SuperRegIdxLists, + std::string const &TargetName) const { + return; +} + +void PrinterCapstone::regInfoEmitRegClassTable( + std::list const &RegClasses) const { + return; +} + +void PrinterCapstone::regInfoEmitCostPerUseTable( + std::vector const &AllRegCostPerUse, unsigned NumRegCosts) const { + return; +} + +void PrinterCapstone::regInfoEmitInAllocatableClassTable( + llvm::BitVector const &InAllocClass) const { + return; +} + +void PrinterCapstone::regInfoEmitRegExtraDesc(std::string const &TargetName, + unsigned NumRegCosts) const { + return; +} + +void PrinterCapstone::regInfoEmitSubClassSubRegGetter( + std::string const &ClassName, unsigned SubRegIndicesSize, + std::deque const &SubRegIndices, + std::list const &RegClasses, + CodeGenRegBank &RegBank) const { + return; +} + +void PrinterCapstone::regInfoEmitRegClassWeight( + CodeGenRegBank const &RegBank, std::string const &ClassName) const { + return; +} + +void PrinterCapstone::regInfoEmitRegUnitWeight( + CodeGenRegBank const &RegBank, std::string const &ClassName, + bool RegUnitsHaveUnitWeight) const { + return; +} + +void PrinterCapstone::regInfoEmitGetNumRegPressureSets( + std::string const &ClassName, unsigned NumSets) const { + return; +} + +void PrinterCapstone::regInfoEmitGetRegPressureTables( + CodeGenRegBank const &RegBank, std::string const &ClassName, + unsigned NumSets) const { + return; +} + +void PrinterCapstone::regInfoEmitRCSetsTable( + std::string const &ClassName, unsigned NumRCs, + SequenceToOffsetTable> const &PSetsSeqs, + std::vector> const &PSets) const { + return; +} + +void PrinterCapstone::regInfoEmitGetRegUnitPressureSets( + SequenceToOffsetTable> const &PSetsSeqs, + CodeGenRegBank const &RegBank, std::string const &ClassName, + std::vector> const &PSets) const { + return; +} + +void PrinterCapstone::regInfoEmitExternTableDecl( + std::string const &TargetName) const { + return; +} + +void PrinterCapstone::regInfoEmitRegClassInit( + std::string const &TargetName, std::string const &ClassName, + CodeGenRegBank const &RegBank, + std::list const &RegClasses, + std::deque const &Regs, unsigned SubRegIndicesSize) const { + return; +} + +void PrinterCapstone::regInfoEmitSaveListTable( + Record const *CSRSet, SetTheory::RecVec const *Regs) const { + return; +} + +void PrinterCapstone::regInfoEmitRegMaskTable(std::string const &CSRSetName, + BitVector &Covered) const { + return; +} + +void PrinterCapstone::regInfoEmitGetRegMasks( + std::vector const &CSRSets, std::string const &ClassName) const { + return; +} + +void PrinterCapstone::regInfoEmitGPRCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + return; +} +void PrinterCapstone::regInfoEmitFixedRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + return; +} + +void PrinterCapstone::regInfoEmitArgRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + return; +} + +void PrinterCapstone::regInfoEmitGetRegMaskNames( + std::vector const &CSRSets, std::string const &ClassName) const { + return; +} + +void PrinterCapstone::regInfoEmitGetFrameLowering( + std::string const &TargetName) const { + return; +} + +void PrinterCapstone::regInfoEmitComposeSubRegIndicesImplHead( + std::string const &ClName) const { + return; +} + +void PrinterCapstone::regInfoEmitComposeSubRegIndicesImplBody( + SmallVector, 4> const &Rows, + unsigned SubRegIndicesSize, SmallVector const &RowMap) const { + return; +} + +void PrinterCapstone::regInfoEmitLaneMaskComposeSeq( + SmallVector, 4> const &Sequences, + SmallVector const &SubReg2SequenceIndexMap, + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitComposeSubRegIdxLaneMask( + std::string const &ClName, + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitComposeSubRegIdxLaneMaskRev( + std::string const &ClName, + std::deque const &SubRegIndices) const { + return; +} + +void PrinterCapstone::regInfoEmitIsConstantPhysReg( + std::deque const &Regs, + std::string const &ClassName) const {} + +void patchQualifier(std::string &Code) { + while (Code.find("::") != std::string::npos) + Code = Regex("::").sub("_", Code); +} + +void patchNullptr(std::string &Code) { + while (Code.find("nullptr") != std::string::npos) + Code = Regex("nullptr").sub("NULL", Code); +} + +void patchIsGetImmReg(std::string &Code) { + Regex Pattern = Regex("[a-zA-Z0-9_]+\\.(get|is)(Imm|Reg)\\(\\)"); + SmallVector Matches; + while (Pattern.match(Code, &Matches)) { + StringRef Match = Matches[0]; + StringRef Op = Match.split(".").first; + StringRef Func = Match.split(".").second.trim(")"); + Code = Code.replace(Code.find(Match), Match.size(), + "MCOperand_" + Func.str() + Op.str() + ")"); + } +} + +static std::string handleDefaultArg(const std::string &TargetName, + std::string &Code) { + // Default values of the template function arguments. + // Tuple is (function name, default argument, number of argumetns) + static SmallVector> + AArch64TemplFuncWithDefaults = {// Default is 1 + {"printVectorIndex", "1", 1}, + // Default is false == 0 + {"printPrefetchOp", "0", 1}, + // Default is 0 + {"printSVERegOp", "0", 1}, + {"printMatrixIndex", "1", 1} + }; + static SmallVector> + LoongArchTemplFuncWithDefaults = {// Default is 0 + {"decodeSImmOperand", "0", 2}, + {"decodeUImmOperand", "0", 2}, + }; + SmallVector> *TemplFuncWithDefaults; + if (TargetName == "AArch64") + TemplFuncWithDefaults = &AArch64TemplFuncWithDefaults; + else if (TargetName == "LoongArch") + TemplFuncWithDefaults = &LoongArchTemplFuncWithDefaults; + else + return Code; + + for (std::tuple Func : *TemplFuncWithDefaults) { + // Search for function where default argument is not passed + // e.g. printVectorIndex -> printVectorIndex_1 + // e.g. decodeSImmOperand<1> -> decodeSImmOperand_1_0 + auto Name = std::get<0>(Func); + auto DefaultArg = std::get<1>(Func); + auto ExpectedArgCount = std::get<2>(Func); + SmallVector Matches; + while (Regex(Name + "(<[0-9a-zA-Z,]*>)?($|\\()").match(Code, &Matches)) { + StringRef Arg = Matches[1]; + // Count the number of passed arguments + int ActualArgCount = 0; + if (!Arg.empty() && Arg != "<>") { + ActualArgCount = Arg.count(',') + 1; + } + + std::string NewArg; + NewArg = Regex("<").sub("", Arg); + NewArg = Regex(">").sub("", NewArg); + NewArg = Regex(",").sub("_", NewArg); + if (ActualArgCount != ExpectedArgCount) { + // Add default argument + if (Arg.empty()) { + // e.g. printVectorIndex -> printVectorIndex_1 + NewArg += DefaultArg; + } else { + // e.g. decodeSImmOperand<1> -> decodeSimmOperand_1_0 + NewArg += "_"; + NewArg += DefaultArg; + } + } + + StringRef Match = Matches[0]; + if (Match.ends_with("(")) { + Code = Regex(Name + "(<[0-9a-zA-Z,]*>)?\\(").sub(Name + "_" + NewArg + "(", Code); + } else { + Code = Regex(Name + "(<[0-9a-zA-Z,]*>)?$").sub(Name + "_" + NewArg, Code); + } + } + } + return Code; +} + +/// @brief Replaces template arguments of the form and similar. +/// It also handles default arguments for certain hard-coded function names. +/// +/// @param TargetName The current target name +/// @param Code The C++ code. +static void patchTemplateArgs(const std::string &TargetName, + std::string &Code) { + Code = handleDefaultArg(TargetName, Code); + size_t B = Code.find_first_of("<"); + size_t E = Code.find(">"); + while (B != std::string::npos && E != std::string::npos) { + std::string const &DecName = Code.substr(0, B); + std::string Args = Code.substr(B + 1, E - B - 1); + std::string Rest = Code.substr(E + 1); + if (Args.empty()) { + return; + } + while ((Args.find("true") != std::string::npos) || + (Args.find("false") != std::string::npos) || + (Args.find(",") != std::string::npos) || + (Args.find("'") != std::string::npos)) { + Args = Regex("true").sub("1", Args); + Args = Regex("false").sub("0", Args); + Args = Regex(" *, *").sub("_", Args); + Args = Regex("'").sub("", Args); + } + Code = DecName + "_" + Args + Rest; + E = Code.find(">"); + B = Code.find_first_of("<"); + } +} + +std::string PrinterCapstone::translateToC(std::string const &TargetName, + std::string const &Code) { + std::string PatchedCode(Code); + patchQualifier(PatchedCode); + patchNullptr(PatchedCode); + patchIsGetImmReg(PatchedCode); + patchTemplateArgs(TargetName, PatchedCode); + return PatchedCode; +} + +void PrinterCapstone::decoderEmitterEmitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const { + unsigned const Indent = 4; + DecoderOS.indent(Indent) << GuardPrefix; + DecoderOS << translateToC(TargetName, Op.Decoder); + + DecoderOS << "(MI, insn, Address, Decoder)" << GuardPostfix << " { " + << (Op.HasCompleteDecoder ? "" : "*DecodeComplete = false; ") + << "return " << ReturnFail << "; } \\\n"; +} + +void PrinterCapstone::decoderEmitterEmitOpBinaryParser( + raw_ostream &DecOS, const OperandInfo &OpInfo) const { + unsigned const Indent = 4; + const std::string &Decoder = translateToC(TargetName, OpInfo.Decoder); + + bool const UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; + + if (UseInsertBits) { + DecOS.indent(Indent) << "tmp = 0x"; + DecOS.write_hex(OpInfo.InitValue); + DecOS << "; \\\n"; + } + + for (const EncodingField &EF : OpInfo) { + DecOS.indent(Indent); + if (UseInsertBits) + DecOS << "tmp |= "; + else + DecOS << "tmp = "; + DecOS << "fieldname(insn, " << EF.Base << ", " << EF.Width << ')'; + if (UseInsertBits) + DecOS << " << " << EF.Offset; + else if (EF.Offset != 0) + DecOS << " << " << EF.Offset; + DecOS << "; \\\n"; + } + + if (Decoder != "") { + DecOS.indent(Indent) << GuardPrefix << Decoder + << "(MI, tmp, Address, Decoder)" << GuardPostfix + << " { " + << (OpInfo.HasCompleteDecoder + ? "" + : "*DecodeComplete = false; ") + << "return " << ReturnFail << "; } \\\n"; + } else { + DecOS.indent(Indent) << "MCOperand_CreateImm0(MI, tmp); \\\n"; + } +} + +bool PrinterCapstone::decoderEmitterEmitPredicateMatchAux( + const Init &Val, bool ParenIfBinOp, raw_ostream &PredOS) const { + if (auto *D = dyn_cast(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + + std::string Subtarget = + StringRef(PredicateNamespace).str() + "_" + D->getAsString(); + PredOS << PredicateNamespace << "_getFeatureBits(Inst->csh->mode, " + << Subtarget << ")"; + return false; + } + if (auto *D = dyn_cast(&Val)) { + std::string const Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + PredOS << '!'; + return decoderEmitterEmitPredicateMatchAux(*D->getArg(0), true, PredOS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool const Paren = + D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + PredOS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + PredOS << LS; + if (decoderEmitterEmitPredicateMatchAux(*Arg, ParenIfBinOp, PredOS)) + return true; + } + if (Paren) + PredOS << ')'; + return false; + } + } + return true; +} + +bool PrinterCapstone::decoderEmitterEmitPredicateMatch( + raw_ostream &PredOS, const ListInit *Predicates, unsigned Opc) const { + bool IsFirstEmission = true; + for (unsigned I = 0; I < Predicates->size(); ++I) { + Record *Pred = Predicates->getElementAsRecord(I); + if (!Pred->getValue("AssemblerMatcherPredicate")) + continue; + + if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) + continue; + + if (!IsFirstEmission) + PredOS << " && "; + if (decoderEmitterEmitPredicateMatchAux( + *Pred->getValueAsDag("AssemblerCondDag"), Predicates->size() > 1, + PredOS)) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + IsFirstEmission = false; + } + return !Predicates->empty(); +} + +void PrinterCapstone::decoderEmitterEmitFieldFromInstruction() const { + OS << "// Helper function for extracting fields from encoded instructions.\n" + << "#define FieldFromInstruction(fname, InsnType) \\\n" + << "static InsnType fname(InsnType insn, unsigned startBit, unsigned " + "numBits) \\\n" + << "{ \\\n" + << " InsnType fieldMask; \\\n" + << " if (numBits == sizeof(InsnType) * 8) \\\n" + << " fieldMask = (InsnType)(-1LL); \\\n" + << " else \\\n" + << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit; \\\n" + << " return (insn & fieldMask) >> startBit; \\\n" + << "}\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitInsertBits() const { return; } + +// Helper to propagate SoftFail status. Returns false if the status is Fail; +// callers are expected to early-exit in that condition. (Note, the '&' operator +// is correct to propagate the values of this enum; see comment on 'enum +// DecodeStatus'.) +void PrinterCapstone::decoderEmitterEmitCheck() const { + OS << "static bool Check(DecodeStatus *Out, const DecodeStatus In) {\n" + << " *Out = (DecodeStatus) (*Out & In);\n" + << " return *Out != MCDisassembler_Fail;\n" + << "}\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitDecodeInstruction( + bool IsVarLenInst) const { + OS << "#define DecodeInstruction(fname, fieldname, decoder, InsnType) \\\n" + << "static DecodeStatus fname(const uint8_t DecodeTable[], " + "MCInst *MI, \\\n" + << " InsnType insn, uint64_t " + "Address, const void *Decoder) { \\\n" + << " const uint8_t *Ptr = DecodeTable; \\\n" + << " uint64_t CurFieldValue = 0; \\\n" + << " DecodeStatus S = MCDisassembler_Success; \\\n" + << " while (true) { \\\n" + << " switch (*Ptr) { \\\n" + << " default: \\\n" + << " return MCDisassembler_Fail; \\\n" + << " case MCD_OPC_ExtractField: { \\\n" + << " unsigned Start = *++Ptr; \\\n" + << " unsigned Len = *++Ptr; \\\n" + << " ++Ptr; \\\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len); \\\n"; + } + OS << " CurFieldValue = fieldname(insn, Start, Len); \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_FilterValue: { \\\n" + << " /* Decode the field value. */ \\\n" + << " unsigned Len; \\\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Perform the filter operation. */ \\\n" + << " if (Val != CurFieldValue) \\\n" + << " Ptr += NumToSkip; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_CheckField: { \\\n" + << " unsigned Start = *++Ptr; \\\n" + << " unsigned Len = *++Ptr; \\\n"; + if (IsVarLenInst) { + OS << " makeUp(insn, Start + Len); \\\n"; + } + OS << " uint64_t FieldValue = fieldname(insn, Start, Len); " + "\\\n" + << " /* Decode the field value. */ \\\n" + << " unsigned PtrLen = 0; \\\n" + << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen); \\\n" + << " Ptr += PtrLen; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* If the actual and expected values don't match, skip. */ \\\n" + << " if (ExpectedValue != FieldValue) \\\n" + << " Ptr += NumToSkip; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_CheckPredicate: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Predicate Index value. */ \\\n" + << " unsigned PIdx = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Check the predicate. */ \\\n" + << " bool Pred = checkDecoderPredicate(MI, PIdx); \\\n" + << " if (!Pred) \\\n" + << " Ptr += NumToSkip; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_Decode: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Opcode value. */ \\\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " MCInst_clear(MI); \\\n" + << " MCInst_setOpcode(MI, Opc); \\\n" + << " bool DecodeComplete; \\\n"; + if (IsVarLenInst) { + OS << " Len = InstrLenTable[Opc]; \\\n" + << " makeUp(insn, Len); \\\n"; + } + OS << " S = decoder(S, DecodeIdx, insn, MI, Address, " + "Decoder, &DecodeComplete); \\\n" + << " return S; \\\n" + << " } \\\n" + << " case MCD_OPC_TryDecode: { \\\n" + << " unsigned Len; \\\n" + << " /* Decode the Opcode value. */ \\\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " /* NumToSkip is a plain 24-bit integer. */ \\\n" + << " unsigned NumToSkip = *Ptr++; \\\n" + << " NumToSkip |= (*Ptr++) << 8; \\\n" + << " NumToSkip |= (*Ptr++) << 16; \\\n" + << " /* Perform the decode operation. */ \\\n" + << " MCInst_setOpcode(MI, Opc); \\\n" + << " bool DecodeComplete; \\\n" + << " S = decoder(S, DecodeIdx, insn, MI, Address, " + << "Decoder, &DecodeComplete); \\\n" + << " if (DecodeComplete) { \\\n" + << " /* Decoding complete. */ \\\n" + << " return S; \\\n" + << " } else { \\\n" + << " /* If the decoding was incomplete, skip. */ \\\n" + << " Ptr += NumToSkip; \\\n" + << " /* Reset decode status. This also drops a SoftFail status " + "that could be */ \\\n" + << " /* set before the decode attempt. */ \\\n" + << " S = MCDisassembler_Success; \\\n" + << " } \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_SoftFail: { \\\n" + << " /* Decode the mask values. */ \\\n" + << " unsigned Len; \\\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len); \\\n" + << " Ptr += Len; \\\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0; \\\n" + << " if (Fail) \\\n" + << " S = MCDisassembler_SoftFail; \\\n" + << " break; \\\n" + << " } \\\n" + << " case MCD_OPC_Fail: { \\\n" + << " return MCDisassembler_Fail; \\\n" + << " } \\\n" + << " } \\\n" + << " } \\\n" + << " /* Bogisity detected in disassembler state machine! */ \\\n" + << "}\n\n"; + + std::set HasTwoByteInsns = {"ARM"}; + std::set HasFourByteInsns = {"ARM", "PPC", "AArch64", "LoongArch"}; + + if (HasTwoByteInsns.find(TargetName) != HasTwoByteInsns.end()) + OS << "FieldFromInstruction(fieldFromInstruction_2, uint16_t)\n" + << "DecodeToMCInst(decodeToMCInst_2, fieldFromInstruction_2, uint16_t)\n" + << "DecodeInstruction(decodeInstruction_2, fieldFromInstruction_2, " + "decodeToMCInst_2, uint16_t)\n\n"; + if (HasFourByteInsns.find(TargetName) != HasFourByteInsns.end()) + OS << "FieldFromInstruction(fieldFromInstruction_4, uint32_t)\n" + << "DecodeToMCInst(decodeToMCInst_4, fieldFromInstruction_4, uint32_t)\n" + << "DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, " + "decodeToMCInst_4, uint32_t)\n"; + // Special case: The LLVM disassembler uses uint64_t values for decoding. + // Although PPC instructions are 4 bytes wide. + if (TargetName == "PPC") + OS << "FieldFromInstruction(fieldFromInstruction_4, uint64_t)\n" + << "DecodeToMCInst(decodeToMCInst_4, fieldFromInstruction_4, uint64_t)\n" + << "DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, " + "decodeToMCInst_4, uint64_t)\n"; +} + +void PrinterCapstone::decoderEmitterEmitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector &NumberedEncodings) const { + unsigned Indent = 0; + OS.indent(Indent) << "static const uint8_t DecoderTable" << Namespace + << BitWidth << "[] = {\n"; + + Indent += 2; + + // FIXME: We may be able to use the NumToSkip values to recover + // appropriate indentation levels. + DecoderTable::const_iterator I = Table.begin(); + DecoderTable::const_iterator const E = Table.end(); + while (I != E) { + assert(I < E && "incomplete decode table entry!"); + + uint64_t const Pos = I - Table.begin(); + OS << "/* " << Pos << " */"; + OS.PadToColumn(12); + + switch (*I) { + default: + PrintFatalError("invalid decode table opcode"); + case MCD::OPC_ExtractField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD_OPC_ExtractField, " << Start << ", " << Len + << ", // Inst{"; + if (Len > 1) + OS << (Start + Len - 1) << "-"; + OS << Start << "} ...\n"; + break; + } + case MCD::OPC_FilterValue: { + ++I; + OS.indent(Indent) << "MCD_OPC_FilterValue, "; + // The filter value is ULEB128 encoded. + while (*I >= 128) + OS << (unsigned)*I++ << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD_OPC_CheckField, " << Start << ", " << Len + << ", "; // << Val << ", " << NumToSkip << ",\n"; + // ULEB128 encoded field value. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckPredicate: { + ++I; + OS.indent(Indent) << "MCD_OPC_CheckPredicate, "; + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_Decode: + case MCD::OPC_TryDecode: { + bool const IsTry = *I == MCD::OPC_TryDecode; + ++I; + // Extract the ULEB128 encoded Opcode to a buffer. + uint8_t Buffer[16], *P = Buffer; + while ((*P++ = *I++) >= 128) + assert((P - Buffer) <= (ptrdiff_t)sizeof(Buffer) && + "ULEB128 value too large!"); + // Decode the Opcode value. + unsigned const Opc = decodeULEB128(Buffer); + OS.indent(Indent) << "MCD_OPC_" << (IsTry ? "Try" : "") << "Decode, "; + for (P = Buffer; *P >= 128; ++P) + OS << (unsigned)*P << ", "; + OS << (unsigned)*P << ", "; + + // Decoder index. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + if (!IsTry) { + OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; + break; + } + + // Fallthrough for OPC_TryDecode. + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + + OS << "// Opcode: " << NumberedEncodings[Opc] + << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_SoftFail: { + ++I; + OS.indent(Indent) << "MCD_OPC_SoftFail"; + // Positive mask + uint64_t Value = 0; + unsigned Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + // Negative mask + Value = 0; + Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + OS << ",\n"; + break; + } + case MCD::OPC_Fail: { + ++I; + OS.indent(Indent) << "MCD_OPC_Fail,\n"; + break; + } + } + } + OS.indent(Indent) << "0\n"; + + Indent -= 2; + + OS.indent(Indent) << "};\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitInstrLenTable( + std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned const &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitPredicateFunction( + PredicateSet &Predicates, unsigned Indentation) const { + // The predicate function is just a big switch statement based on the + // input predicate index. + OS.indent(Indentation) + << "static bool checkDecoderPredicate(MCInst *Inst, unsigned Idx" + << ") {\n"; + Indentation += 2; + if (!Predicates.empty()) { + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) + << "default: /* llvm_unreachable(\"Invalid index!\"); */\n"; + unsigned Index = 0; + for (const auto &Predicate : Predicates) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS.indent(Indentation + 2) << "return (" << Predicate << ");\n"; + } + OS.indent(Indentation) << "}\n"; + } else { + // No case statement to emit + OS.indent(Indentation) << "/* llvm_unreachable(\"Invalid index!\"); */\n"; + } + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitDecoderFunction( + DecoderSet &Decoders, unsigned Indentation) const { + // The decoder function is just a big switch statement based on the + // input decoder index. + OS.indent(Indentation) + << "#define DecodeToMCInst(fname, fieldname, InsnType) \\\n" + << "static DecodeStatus fname(DecodeStatus S, unsigned Idx, InsnType " + "insn, MCInst *MI, \\\n" + << " uint64_t Address, const void *Decoder, bool " + "*DecodeComplete) \\\n" + << "{ \\\n"; + Indentation += 2; + OS.indent(Indentation) << "*DecodeComplete = true; \\\n"; + OS.indent(Indentation) << "InsnType tmp; \\\n"; + OS.indent(Indentation) << "switch (Idx) { \\\n"; + OS.indent(Indentation) + << "default: /* llvm_unreachable(\"Invalid index!\"); */ \\\n"; + unsigned Index = 0; + for (const auto &Decoder : Decoders) { + OS.indent(Indentation) << "case " << Index++ << ": \\\n"; + OS << Decoder; + OS.indent(Indentation + 2) << "return S; \\\n"; + } + OS.indent(Indentation) << "} \\\n"; + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitIncludes() const { + OS << "#include \"../../MCInst.h\"\n" + << "#include \"../../LEB128.h\"\n\n"; +} + +void PrinterCapstone::decoderEmitterEmitSourceFileHeader() const { + emitDefaultSourceFileHeader(OS); +} + +//------------------------- +// Backend: AsmWriter +//------------------------- + +void PrinterCapstone::asmWriterEmitSourceFileHeader(RecordKeeper &Records) const { + emitDefaultSourceFileHeader(OS); + OS << "#include \n" + << "#include \n\n"; +} + +void PrinterCapstone::asmWriterEmitGetMnemonic( + std::string const &TargetName, StringRef const &ClassName) const { + OS << "/// getMnemonic - This method is automatically generated by " + "tablegen\n" + "/// from the instruction set description.\n" + "static MnemonicBitsInfo getMnemonic(MCInst *MI, SStream *O) {\n"; +} + +void PrinterCapstone::asmWriterEmitAsmStrs( + SequenceToOffsetTable const &StrTable) const { + StrTable.emitStringLiteralDef(OS, " static const char AsmStrs[]"); +} + +void PrinterCapstone::asmWriterEmitMnemonicDecodeTable( + unsigned const OpcodeInfoBits, unsigned BitsLeft, + unsigned const &AsmStrBits, + ArrayRef const &NumberedInstructions, + std::vector const &OpcodeInfo) const { + // Emit the lookup tables in pieces to minimize wasted bytes. + unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8; + unsigned Table = 0, Shift = 0; + SmallString<128> BitsString; + raw_svector_ostream BitsOS(BitsString); + // If the total bits is more than 32-bits we need to use a 64-bit type. + BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) + << "_t Bits = 0;\n"; + while (BytesNeeded != 0) { + // Figure out how big this table section needs to be, but no bigger than 4. + unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4); + BytesNeeded -= TableSize; + TableSize *= 8; // Convert to bits; + uint64_t const Mask = (1ULL << TableSize) - 1; + OS << " static const uint" << TableSize << "_t OpInfo" << Table + << "[] = {\n"; + for (unsigned I = 0, E = NumberedInstructions.size(); I != E; ++I) { + OS << " " << ((OpcodeInfo[I] >> Shift) & Mask) << "U,\t// " + << NumberedInstructions[I]->TheDef->getName() << "\n"; + } + OS << " };\n\n"; + // Emit string to combine the individual table lookups. + BitsOS << " Bits |= "; + // If the total bits is more than 32-bits we need to use a 64-bit type. + if (BitsLeft < (OpcodeInfoBits - 32)) + BitsOS << "(uint64_t)"; + BitsOS << "OpInfo" << Table << "[MCInst_getOpcode(MI)] << " << Shift + << ";\n"; + // Prepare the shift for the next iteration and increment the table count. + Shift += TableSize; + ++Table; + } + + OS << " // Emit the opcode for the instruction.\n"; + OS << BitsString; + + // Return mnemonic string and bits. + OS << " MnemonicBitsInfo MBI = {\n" + << "#ifndef CAPSTONE_DIET\n" + << " AsmStrs+(Bits & " << (1 << AsmStrBits) - 1 << ")-1,\n" + << "#else\n" + << " NULL,\n" + << "#endif // CAPSTONE_DIET\n" + << " Bits\n" + << " };\n"; + OS << " return MBI;\n"; + OS << "}\n\n"; +} + +void PrinterCapstone::asmWriterEmitPrintInstruction( + std::string const &TargetName, + std::vector> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits, StringRef const &ClassName, + bool PassSubtarget) const { + const unsigned OpcodeInfoBits = 64; + // This function has some huge switch statements that causing excessive + // compile time in LLVM profile instrumenation build. This print function + // usually is not frequently called in compilation. Here we disable the + // profile instrumenation for this function. + OS << "/// printInstruction - This method is automatically generated by " + "tablegen\n" + "/// from the instruction set description.\n" + "static void " + << "printInstruction(MCInst *MI, uint64_t Address, " + << "SStream *O) {\n"; + + // Emit the initial tab character. + OS << " SStream_concat0(O, \"\");\n"; + + // Emit the starting string. + OS << " MnemonicBitsInfo MnemonicInfo = getMnemonic(MI, O);\n\n"; + OS << " SStream_concat0(O, MnemonicInfo.first);\n\n"; + + OS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) + << "_t Bits = MnemonicInfo.second;\n" + << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"; + + // Output the table driven operand information. + BitsLeft = OpcodeInfoBits - AsmStrBits; + for (unsigned I = 0, E = TableDrivenOperandPrinters.size(); I != E; ++I) { + std::vector &Commands = TableDrivenOperandPrinters[I]; + + // Compute the number of bits we need to represent these cases, this is + // ceil(log2(numentries)). + unsigned const NumBits = Log2_32_Ceil(Commands.size()); + assert(NumBits <= BitsLeft && "consistency error"); + + // Emit code to extract this field from Bits. + OS << "\n // Fragment " << I << " encoded into " << NumBits << " bits for " + << Commands.size() << " unique commands.\n"; + + if (Commands.size() == 2) { + // Emit two possibilitys with if/else. + OS << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " + << ((1 << NumBits) - 1) << ") {\n" + << translateToC(TargetName, Commands[1]) << " } else {\n" + << translateToC(TargetName, Commands[0]) << " }\n\n"; + } else if (Commands.size() == 1) { + // Emit a single possibility. + OS << translateToC(TargetName, Commands[0]) << "\n\n"; + } else { + OS << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " + << ((1 << NumBits) - 1) << ") {\n" + << " default: assert(0 && \"Invalid command number.\");\n"; + + // Print out all the cases. + for (unsigned J = 0, F = Commands.size(); J != F; ++J) { + OS << " case " << J << ":\n"; + OS << translateToC(TargetName, Commands[J]); + OS << " break;\n"; + } + OS << " }\n\n"; + } + BitsLeft -= NumBits; + } +} + +void PrinterCapstone::asmWriterEmitOpCases( + std::vector> &OpsToPrint, + bool PassSubtarget) const { + OS << " case " << OpsToPrint.back().first << ":"; + AsmWriterOperand const TheOp = OpsToPrint.back().second; + OpsToPrint.pop_back(); + + // Check to see if any other operands are identical in this list, and if so, + // emit a case label for them. + for (unsigned I = OpsToPrint.size(); I != 0; --I) + if (OpsToPrint[I - 1].second == TheOp) { + OS << "\n case " << OpsToPrint[I - 1].first << ":"; + OpsToPrint.erase(OpsToPrint.begin() + I - 1); + } + + // Finally, emit the code. + OS << "\n " << translateToC(TargetName, TheOp.getCode(PassSubtarget)); + OS << "\n break;\n"; +} + +void PrinterCapstone::asmWriterEmitInstrSwitch() const { + OS << " switch (MCInst_getOpcode(MI)) {\n"; + OS << " default: assert(0 && \"Unexpected opcode.\");\n"; +} + +void PrinterCapstone::asmWriterEmitCompoundClosure(unsigned Indent, + bool Newline, + bool Semicolon) const { + for (; Indent > 0; --Indent) { + OS << " "; + } + OS << "}"; + if (Semicolon) + OS << ";"; + if (Newline) + OS << "\n"; +} + +void PrinterCapstone::asmWriterEmitInstruction( + AsmWriterInst const &FirstInst, + std::vector const &SimilarInsts, unsigned DifferingOperand, + bool PassSubtarget) const { + OS << " case " << FirstInst.CGI->Namespace << "_" + << FirstInst.CGI->TheDef->getName() << ":\n"; + for (const AsmWriterInst &AWI : SimilarInsts) + OS << " case " << AWI.CGI->Namespace << "_" << AWI.CGI->TheDef->getName() + << ":\n"; + for (unsigned I = 0, E = FirstInst.Operands.size(); I != E; ++I) { + if (I != DifferingOperand) { + // If the operand is the same for all instructions, just print it. + OS << " " << translateToC(TargetName, FirstInst.Operands[I].getCode(PassSubtarget)); + } else { + // If this is the operand that varies between all of the instructions, + // emit a switch for just this operand now. + OS << " switch (MCInst_getOpcode(MI)) {\n"; + OS << " default: assert(0 && \"Unexpected opcode.\");\n"; + std::vector> OpsToPrint; + OpsToPrint.push_back( + std::make_pair(FirstInst.CGI->Namespace.str() + "_" + + FirstInst.CGI->TheDef->getName().str(), + FirstInst.Operands[I])); + + for (const AsmWriterInst &AWI : SimilarInsts) { + OpsToPrint.push_back(std::make_pair( + AWI.CGI->Namespace.str() + "_" + AWI.CGI->TheDef->getName().str(), + AWI.Operands[I])); + } + std::reverse(OpsToPrint.begin(), OpsToPrint.end()); + while (!OpsToPrint.empty()) + asmWriterEmitOpCases(OpsToPrint, PassSubtarget); + OS << " }"; + } + OS << "\n"; + } + OS << " break;\n"; +} + +void PrinterCapstone::asmWriterEmitGetRegNameAssert( + std::string const &TargetName, StringRef const &ClassName, bool HasAltNames, + unsigned RegSize) const { + + OS << "\n\n/// getRegisterName - This method is automatically generated by " + "tblgen\n" + "/// from the register set description. This returns the assembler " + "name\n" + "/// for the specified register.\n" + "static const char *"; + if (HasAltNames) + OS << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n"; + else + OS << "getRegisterName(unsigned RegNo) {\n"; + OS << "#ifndef CAPSTONE_DIET\n"; + OS << " assert(RegNo && RegNo < " << (RegSize + 1) + << " && \"Invalid register number!\");\n" + << "\n"; +} + +void PrinterCapstone::asmWriterEmitStringLiteralDef( + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const { + StringTable.emitStringLiteralDef(OS, Twine(" static const char AsmStrs") + + AltName + "[]"); +} + +void PrinterCapstone::asmWriterEmitRegAsmOffsets( + unsigned RegSizes, SmallVector const &AsmNames, + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const { + OS << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32) + << " RegAsmOffset" << AltName << "[] = {"; + for (unsigned I = 0, E = RegSizes; I != E; ++I) { + if ((I % 14) == 0) + OS << "\n "; + OS << StringTable.get(AsmNames[I]) << ", "; + } + OS << "\n };\n" + << "\n"; +} + +void PrinterCapstone::asmWriterEmitAltIdxSwitch( + bool HasAltNames, std::vector const &AltNameIndices, + StringRef const &Namespace) const { + if (HasAltNames) { + OS << " switch(AltIdx) {\n" + << " default: assert(0 && \"Invalid register alt name " + "index!\");\n"; + for (const Record *R : AltNameIndices) { + StringRef const AltName = R->getName(); + OS << " case "; + if (!Namespace.empty()) + OS << Namespace << "_"; + OS << AltName << ":\n"; + if (R->isValueUnset("FallbackRegAltNameIndex")) + OS << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1]) &&\n" + << " \"Invalid alt name index for register!\");\n"; + else { + OS << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1]))\n" + << " return getRegisterName(RegNo, "; + if (!Namespace.empty()) + OS << Namespace << "_"; + OS << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n"; + } + OS << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1];\n"; + } + OS << " }\n"; + } else { + OS << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n" + << " \"Invalid alt name index for register!\");\n" + << " return AsmStrs+RegAsmOffset[RegNo-1];\n"; + } + OS << "#else\n" + << " return NULL;\n" + << "#endif // CAPSTONE_DIET\n"; + OS << "}\n"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKIgnore() const { + return "AliasPatternCond_K_Ignore, 0"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKRegClass() const { + return "AliasPatternCond_K_RegClass, {0}_{1}RegClassID"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKTiedReg() const { + return "AliasPatternCond_K_TiedReg, {0}"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKCustom() const { + return "AliasPatternCond_K_Custom, {0}"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKImm() const { + return "AliasPatternCond_K_Imm, (uint32_t){0}"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKNoReg() const { + return "AliasPatternCond_K_Reg, {0}_NoRegister"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKReg() const { + return "AliasPatternCond_K_Reg, {0}_{1}"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKFeature() const { + return "AliasPatternCond_K_{0}{1}Feature, {2}_{3}"; +} + +char const *PrinterCapstone::asmWriterGetPatCondKEndOrFeature() const { + return "AliasPatternCond_K_EndOrFeatures, 0"; +} + +char const *PrinterCapstone::asmWriterGetPatOpcStart() const { + return " // {0} - {1}\n"; +} + +char const *PrinterCapstone::asmWriterGetCondPatStart() const { + return " // {0} - {1}\n"; +} + +std::string PrinterCapstone::asmWriterGetCond(std::string const &Cond) const { + return formatv(" {{{0}},\n", Cond); +} + +char const *PrinterCapstone::asmWriterGetPatternFormat() const { + return " {{{0}, {1}, {2}, {3} },\n"; +} + +char const *PrinterCapstone::asmWriterGetOpcodeFormat() const { + return " {{{0}, {1}, {2} },\n"; +} + +void PrinterCapstone::asmWriterEmitPrintAliasInstrHeader( + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const { + OS << "static bool printAliasInstr(MCInst" + << " *MI, uint64_t Address, " + << "SStream *OS) {\n" + << "#ifndef CAPSTONE_DIET\n"; +} + +void PrinterCapstone::asmWriterEmitPrintAliasInstrBodyRetFalse() const { + OS << " return false;\n"; + OS << "#endif // CAPSTONE_DIET\n"; + OS << "}\n\n"; +} + +void PrinterCapstone::asmWriterEmitDeclValid(std::string const &TargetName, + StringRef const &ClassName) const { + OS << "static bool " << TargetName << ClassName + << "ValidateMCOperand(const MCOperand *MCOp,\n" + << " unsigned PredicateIndex);\n"; +} + +void PrinterCapstone::asmWriterEmitPrintAliasInstrBody( + raw_string_ostream &OpcodeO, raw_string_ostream &PatternO, + raw_string_ostream &CondO, + std::vector> const &AsmStrings, + std::vector const &MCOpPredicates, + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const { + OS.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n"; + OS << OpcodeO.str(); + OS.indent(2) << "{0},"; // Null terminated to ease binary search. + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const AliasPattern Patterns[] = {\n"; + OS << PatternO.str(); + OS.indent(2) << "{0},"; + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const AliasPatternCond Conds[] = {\n"; + OS << CondO.str(); + OS.indent(2) << "{0},"; + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const char AsmStrings[] =\n"; + for (const auto &P : AsmStrings) { + OS.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n"; + } + + OS.indent(2) << ";\n\n"; + + // Assert that the opcode table is sorted. Use a static local constructor to + // ensure that the check only happens once on first run. + OS << "#ifndef NDEBUG\n"; + OS.indent(2) << "//static struct SortCheck {\n"; + OS.indent(2) << "// SortCheck(ArrayRef OpToPatterns) {\n"; + OS.indent(2) << "// assert(std::is_sorted(\n"; + OS.indent(2) + << "// OpToPatterns.begin(), OpToPatterns.end(),\n"; + OS.indent(2) << "// [](const PatternsForOpcode &L, const " + "//PatternsForOpcode &R) {\n"; + OS.indent(2) << "// return L.Opcode < R.Opcode;\n"; + OS.indent(2) << "// }) &&\n"; + OS.indent(2) + << "// \"tablegen failed to sort opcode patterns\");\n"; + OS.indent(2) << "// }\n"; + OS.indent(2) << "//} sortCheckVar(OpToPatterns);\n"; + OS << "#endif\n\n"; + + OS.indent(2) << "AliasMatchingData M = {\n"; + OS.indent(2) << " OpToPatterns,\n"; + OS.indent(2) << " Patterns,\n"; + OS.indent(2) << " Conds,\n"; + OS.indent(2) << " AsmStrings,\n"; + if (!MCOpPredicates.empty()) + OS.indent(2) << " " << TargetName << ClassName << "ValidateMCOperand,\n"; + else + OS.indent(2) << " NULL,\n"; + OS.indent(2) << "};\n"; + + OS.indent(2) << "const char *AsmString = matchAliasPatterns(MI, &M);\n"; + OS.indent(2) << "if (!AsmString) return false;\n\n"; + + // Code that prints the alias, replacing the operands with the ones from the + // MCInst. + OS << " unsigned I = 0;\n"; + OS << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; + OS << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; + OS << " ++I;\n"; + OS << " SStream_concat1(OS, '\\t');\n" + << " char *substr = malloc(I+1);\n" + << " memcpy(substr, AsmString, I);\n" + << " substr[I] = '\\0';\n" + << " SStream_concat0(OS, substr);\n" + << " free(substr);\n"; + + OS << " if (AsmString[I] != '\\0') {\n"; + OS << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n"; + OS << " SStream_concat1(OS, '\\t');\n"; + OS << " ++I;\n"; + OS << " }\n"; + OS << " do {\n"; + OS << " if (AsmString[I] == '$') {\n"; + OS << " ++I;\n"; + OS << " if (AsmString[I] == (char)0xff) {\n"; + OS << " ++I;\n"; + OS << " int OpIdx = AsmString[I++] - 1;\n"; + OS << " int PrintMethodIdx = AsmString[I++] - 1;\n"; + OS << " printCustomAliasOperand(MI, Address, OpIdx, " + "PrintMethodIdx, "; + OS << "OS);\n"; + OS << " } else\n"; + OS << " printOperand(MI, ((unsigned)AsmString[I++]) - 1, "; + OS << "OS);\n"; + OS << " } else {\n"; + OS << " SStream_concat1(OS, AsmString[I++]);\n"; + OS << " }\n"; + OS << " } while (AsmString[I] != '\\0');\n"; + OS << " }\n\n"; + + OS << " return true;\n"; + OS << "#else\n" + << " return false;\n"; + OS << "#endif // CAPSTONE_DIET\n"; + OS << "}\n\n"; +} + +void PrinterCapstone::asmWriterEmitPrintAliasOp( + std::string const &TargetName, StringRef const &ClassName, + std::vector> const &PrintMethods, + bool PassSubtarget) const { + OS << "static void printCustomAliasOperand(\n" + << " MCInst *MI, uint64_t Address, unsigned OpIdx,\n" + << " unsigned PrintMethodIdx,\n" + << " SStream *OS) {\n" + << "#ifndef CAPSTONE_DIET\n"; + if (PrintMethods.empty()) + OS << " assert(0 && \"Unknown PrintMethod kind\");\n"; + else { + OS << " switch (PrintMethodIdx) {\n" + << " default:\n" + << " assert(0 && \"Unknown PrintMethod kind\");\n" + << " break;\n"; + + for (unsigned I = 0; I < PrintMethods.size(); ++I) { + OS << " case " << I << ":\n"; + std::string PrintMethod = + PrinterCapstone::translateToC(TargetName, PrintMethods[I].first); + OS << " " << PrintMethod << "(MI, " + << (PrintMethods[I].second ? "Address, " : "") << "OpIdx, " + << "OS);\n" + << " break;\n"; + } + OS << " }\n"; + } + OS << "#endif // CAPSTONE_DIET\n"; + OS << "}\n\n"; +} + +void PrinterCapstone::asmWriterEmitPrintMC( + std::string const &TargetName, StringRef const &ClassName, + std::vector const &MCOpPredicates) const { + if (!MCOpPredicates.empty()) { + OS << "static bool " << TargetName << ClassName + << "ValidateMCOperand(const MCOperand *MCOp,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " assert(0 && \"Unknown MCOperandPredicate kind\");\n" + << " return false;\n"; + + for (unsigned I = 0; I < MCOpPredicates.size(); ++I) { + StringRef const MCOpPred = + MCOpPredicates[I]->getValueAsString("MCOperandPredicate"); + OS << " case " << I + 1 << ": {\n"; + std::string PrintMethod = + PrinterCapstone::translateToC(TargetName, MCOpPred.data()); + OS << PrintMethod << "\n" + << " }\n"; + } + OS << " }\n" + << "}\n\n"; + } +} + +//------------------------- +// Backend: Subtarget +//------------------------- + +void PrinterCapstone::subtargetEmitGetMacroFusions(CodeGenTarget &TGT, + std::string Target, + const std::string &ClassName) const { + return; +} + +void PrinterCapstone::subtargetEmitSourceFileHeader() const { + emitDefaultSourceFileHeader(OS); +} + +void PrinterCapstone::subtargetEmitFeatureEnum( + DenseMap &FeatureMap, + std::vector const &DefList, unsigned N) const { + StringRef TN = StringRef(TargetName); + // Open enumeration. + OS << "enum {\n"; + + // For each record + for (unsigned I = 0; I < N; ++I) { + // Next record + Record *Def = DefList[I]; + + // Get and emit name + OS << " " << TN << "_" << Def->getName() << " = " << I << ",\n"; + + // Save the index for this feature. + FeatureMap[Def] = I; + } + + OS << " " << TN << "_" + << "NumSubtargetFeatures = " << N << "\n"; + + // Close enumeration and namespace + OS << "};\n"; +} + +void PrinterCapstone::subtargetEmitGetSTIMacro( + StringRef const &Value, StringRef const &Attribute) const {} + +void PrinterCapstone::subtargetEmitHwModes(CodeGenHwModes const &CGH, + std::string const &ClassName) const { +} + +void PrinterCapstone::subtargetEmitFeatureKVHeader( + std::string const &Target) const { + // Begin feature table +} + +void PrinterCapstone::subtargetEmitFeatureKVPartI( + std::string const &Target, StringRef const &CommandLineName, + StringRef const &Name, StringRef const &Desc) const {} + +void PrinterCapstone::subtargetEmitFeatureKVPartII() const {} + +void PrinterCapstone::subtargetEmitPrintFeatureMask( + std::array const &Mask) const {} + +void PrinterCapstone::subtargetEmitFeatureKVEnd() const {} + +void PrinterCapstone::subtargetEmitCPUKVHeader( + std::string const &Target) const {} + +void PrinterCapstone::subtargetEmitCPUKVEnd() const {} + +void PrinterCapstone::subtargetEmitCPUKVPartI(StringRef const &Name) const {} + +void PrinterCapstone::subtargetEmitCPUKVPartII() const {} + +void PrinterCapstone::subtargetEmitCPUKVPartIII( + std::string const &ProcModelName) const {} + +void PrinterCapstone::subtargetEmitDBGMacrosBegin() const {} + +void PrinterCapstone::subtargetEmitDBGMacrosEnd() const {} + +void PrinterCapstone::subtargetEmitFunctionalItinaryUnits( + CodeGenSchedModels const &SchedModels) const {} + +std::string const PrinterCapstone::subtargetGetBeginStageTable( + std::string const &TargetName) const { + return ""; +} + +std::string const PrinterCapstone::subtargetGetBeginOperandCycleTable( + std::string const &TargetName) const { + return ""; +} + +std::string const PrinterCapstone::subtargetGetBeginBypassTable( + std::string const &TargetName) const { + return ""; +} + +std::string const PrinterCapstone::subtargetGetEndStageTable() const { + return ""; +} + +std::string const PrinterCapstone::subtargetGetEndOperandCycleTable() const { + return ""; +} + +std::string const PrinterCapstone::subtargetGetEndBypassTable() const { + return ""; +} + +// subtargetFormItineraryStageString - Compose a string containing the stage +// data initialization for the specified itinerary. N is the number +// of stages. +void PrinterCapstone::subtargetFormItineraryStageString( + std::string const &Name, Record *ItinData, std::string &ItinString, + unsigned &NStages) const {} + +// FormItineraryOperandCycleString - Compose a string containing the +// operand cycle initialization for the specified itinerary. N is the +// number of operands that has cycles specified. +void PrinterCapstone::subtargetFormItineraryOperandCycleString( + Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) const { +} + +void PrinterCapstone::subtargetFormItineraryBypassString( + const std::string &Name, Record *ItinData, std::string &ItinString, + unsigned NOperandCycles) const {} + +std::string +PrinterCapstone::subtargetGetStageEntryPartI(std::string const &ItinStageString, + unsigned StageCount) const { + return ""; +} +std::string +PrinterCapstone::subtargetGetStageEntryPartII(unsigned StageCount, + unsigned NStages) const { + return ""; +} +std::string PrinterCapstone::subtargetGetStageEntryPartIII() const { + return ""; +} + +std::string PrinterCapstone::subtargetGetOperandCycleEntryPartI( + std::string const &ItinOperandCycleString) const { + return ""; +} + +std::string PrinterCapstone::subtargetGetOperandCycleEntryPartII( + unsigned OperandCycleCount, unsigned NOperandCycles) const { + return ""; +} + +std::string PrinterCapstone::subtargetGetOperandCycleEntryPartIII( + std::string const &OperandIdxComment) const { + return ""; +} + +std::string PrinterCapstone::subtargetGetOperandCycleEntryPartIV( + std::string const &ItinBypassString, + std::string const &OperandIdxComment) const { + return ""; +} + +void PrinterCapstone::subtargetEmitProcessorItineraryTable( + std::string const &ItinsDefName, std::vector &ItinList, + CodeGenSchedModels const &SchedModels) const {} + +void PrinterCapstone::subtargetEmitPreOperandTableComment() const {} + +// Emit SchedClass tables for all processors and associated global tables. +void PrinterCapstone::subtargetEmitSchedClassTables( + SchedClassTablesT &SchedTables, std::string const &TargetName, + CodeGenSchedModels const &SchedModels) const {} + +unsigned PrinterCapstone::subtargetEmitRegisterFileTables( + CodeGenProcModel const &ProcModel) const { + return 0; +} + +void PrinterCapstone::subtargetEmitMCExtraProcInfoTableHeader( + std::string const &ProcModelName) const {} + +void PrinterCapstone::subtargetEmitMCExtraProcInfoTableEnd() const {} + +void PrinterCapstone::subtargetEmitReorderBufferSize( + int64_t ReorderBufferSize) const {} + +void PrinterCapstone::subtargetEmitMaxRetirePerCycle( + int64_t MaxRetirePerCycle) const {} + +void PrinterCapstone::subtargetEmitRegisterFileInfo( + CodeGenProcModel const &ProcModel, unsigned NumRegisterFiles, + unsigned NumCostEntries) const {} + +void PrinterCapstone::subtargetEmitResourceDescriptorLoadQueue( + unsigned QueueID) const {} + +void PrinterCapstone::subtargetEmitResourceDescriptorStoreQueue( + unsigned QueueID) const {} + +void PrinterCapstone::subtargetEmitProcessorResourceSubUnits( + const CodeGenProcModel &ProcModel, + CodeGenSchedModels const &SchedModels) const {} + +void PrinterCapstone::subtargetEmitMCProcResourceDescHeader( + std::string const &ProcModelName) const {} + +void PrinterCapstone::subtargetEmitMCProcResourceDescEnd() const {} + +void PrinterCapstone::subtargetEmitMCProcResourceDesc( + Record const *PRDef, Record const *SuperDef, + std::string const &ProcModelName, unsigned SubUnitsOffset, + unsigned SuperIdx, unsigned NumUnits, int BufferSize, unsigned I, + unsigned const SubUnitsBeginOffset) const {} + +// Emit either the value defined in the TableGen Record, or the default +// value defined in the C++ header. The Record is null if the processor does not +// define a model. +void PrinterCapstone::subtargetEmitProcessorProp(Record const *R, + StringRef const Name, + char Separator) const {} + +void PrinterCapstone::subtargetEmitProcModelHeader( + std::string const &ModelName) const {} + +void PrinterCapstone::subtargetEmitProcModel( + CodeGenProcModel const &PM, CodeGenSchedModels const &SchedModels) const {} + +void PrinterCapstone::subtargetEmitResolveVariantSchedClassImplHdr() const {} + +void PrinterCapstone::subtargetEmitResolveVariantSchedClassImplEnd() const {} + +void PrinterCapstone::subtargetEmitSchedClassSwitch() const {} + +void PrinterCapstone::subtargetEmitSchedClassCase( + unsigned VC, std::string const &SCName) const {} + +void PrinterCapstone::subtargetEmitSchedClassProcGuard( + unsigned Pi, bool OnlyExpandMCInstPredicates, + std::string const &ModelName) const {} + +// Indent <= -1 (default = -1) means previous PE indent level. +void PrinterCapstone::subtargetEmitPredicates( + CodeGenSchedTransition const &T, CodeGenSchedClass const &SC, + bool (*IsTruePredicate)(Record const *Rec), int Indent) const {} + +void PrinterCapstone::subtargetEmitProcTransitionEnd() const {} + +void PrinterCapstone::subtargetEmitSchedClassCaseEnd( + CodeGenSchedClass const &SC) const {} + +void PrinterCapstone::subtargetEmitSchedClassSwitchEnd() const {} + +// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate +// epilogue code for the auto-generated helper. +void PrinterCapstone::subtargetEmitSchedModelHelperEpilogue( + bool ShouldReturnZero) const {} + +void PrinterCapstone::subtargetEmitGenMCSubtargetInfoClass( + std::string const &TargetName, bool OverrideGetHwMode) const {} + +void PrinterCapstone::subtargetEmitMCSubtargetInfoImpl( + std::string const &TargetName, unsigned NumFeatures, unsigned NumProcs, + bool SchedModelHasItin) const {} + +void PrinterCapstone::subtargetEmitIncludeSTIDesc() const {} + +void PrinterCapstone::subtargetEmitDFAPacketizerClass( + CodeGenTarget &TGT, + std::string const &TargetName, std::string const &ClassName) const {} + +void PrinterCapstone::subtargetEmitDFAPacketizerClassEnd() const {} + +void PrinterCapstone::subtargetEmitSTICtor() const {} + +void PrinterCapstone::subtargetEmitExternKVArrays( + std::string const &TargetName, bool SchedModelsHasItin) const {} + +void PrinterCapstone::subtargetEmitClassDefs(std::string const &TargetName, + std::string const &ClassName, + unsigned NumFeatures, + unsigned NumProcs, + bool SchedModelsHasItin) const {} + +void PrinterCapstone::subtargetEmitResolveSchedClassHdr( + std::string const &ClassName) const {} + +void PrinterCapstone::subtargetEmitResolveSchedClassEnd( + std::string const &ClassName) const {} + +void PrinterCapstone::subtargetEmitResolveVariantSchedClass( + std::string const &TargetName, std::string const &ClassName) const {} + +void PrinterCapstone::subtargetEmitPredicateProlog( + const RecordKeeper &Records) const {} + +void PrinterCapstone::subtargetEmitParseFeaturesFunction( + std::string const &TargetName, + std::vector const &Features) const {} + +void PrinterCapstone::subtargetEmitExpandedSTIPreds( + StringRef const &TargetName, std::string const &ClassName, + CodeGenSchedModels const &SchedModels) {} + +void PrinterCapstone::subtargetPrepareSchedClassPreds( + StringRef const &TargetName, bool OnlyExpandMCInstPredicates) {} + +void PrinterCapstone::subtargetEmitExpandedSTIPredsMCAnaDecl( + StringRef const &TargetName, CodeGenSchedModels const &SchedModels) {} + +void PrinterCapstone::subtargetEmitExpandedSTIPredsMCAnaDefs( + StringRef const &TargetName, std::string const &ClassPrefix, + CodeGenSchedModels const &SchedModels) const {} + +void PrinterCapstone::subtargetEmitExpandedSTIPredsHeader( + StringRef const &TargetName, CodeGenSchedModels const &SchedModels) {} + +void PrinterCapstone::subtargetEmitStageAndSycleTables( + std::string const &StageTable, std::string const &OperandCycleTable, + std::string const &BypassTable) const {} + +//--------------------------- +// Backend: InstrInfoEmitter +//--------------------------- + +void PrinterCapstone::instrInfoEmitSourceFileHeader() const { + emitDefaultSourceFileHeader(OS); +} + +void PrinterCapstone::instrInfoEmitSetGetComputeFeatureMacro() const {} + +void PrinterCapstone::instrInfoSetOperandInfoStr( + std::string &Res, Record const *OpR, CGIOperandList::OperandInfo const &Op, + CGIOperandList::ConstraintInfo const &Constraint) const { + if (OpR->isSubClassOf("RegisterOperand")) + OpR = OpR->getValueAsDef("RegClass"); + if (OpR->isSubClassOf("RegisterClass")) + Res += OpR->getValueAsString("Namespace").str() + "_" + + OpR->getName().str() + "RegClassID, "; + else if (OpR->isSubClassOf("PointerLikeRegClass")) + Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; + else + // -1 means the operand does not have a fixed register class. + Res += "-1, "; + + // Fill in applicable flags. + Res += "0"; + + // Ptr value whose register class is resolved via callback. + if (OpR->isSubClassOf("PointerLikeRegClass")) + Res += "|(1<isSubClassOf("PredicateOp")) + Res += "|(1<isSubClassOf("OptionalDefOperand")) + Res += "|(1<isSubClassOf("BranchTargetOperand")) + Res += "|(1<> ImplicitLists, + std::map, unsigned> &EmittedLists) const { + for (auto &List : ImplicitLists) { + OS << " /* " << EmittedLists[List] << " */"; + for (auto &Reg : List) + OS << ' ' << getQualifiedName(Reg) << ','; + OS << '\n'; + } +} + +void PrinterCapstone::instrInfoEmitRecord(CodeGenSchedModels const &SchedModels, + CodeGenInstruction const &Inst, + unsigned Num, int MinOperands) const { + OS << " { " << MinOperands << ", "; +} + +void PrinterCapstone::instrInfoEmitTargetIndepFlags( + CodeGenInstruction const &Inst, bool GetAllowRegisterRenaming) const {} + +void PrinterCapstone::instrInfoEmitTSFFlags(uint64_t Value) const {} + +void PrinterCapstone::instrInfoEmitUseDefsLists( + StringRef TargetName, + const CodeGenInstruction &Inst, + std::map, unsigned> &EmittedLists, + std::vector const &ImplicitOps) const {} + +void PrinterCapstone::instrInfoEmitOperandInfo(OperandInfoListTy &OperandInfoList) const { + unsigned Offset = 0; + for (auto &OperandInfo : OperandInfoList) { + OS << " /* " << Offset << " */"; + for (auto &Info : OperandInfo) + OS << " { " << Info << " },"; + OS << '\n'; + Offset += OperandInfo.size(); + } +} + +void PrinterCapstone::instrInfoEmitOperandInfoOffset( + StringRef TargetName, + std::vector const &OperandInfo, + OperandInfoMapTy const &OperandInfoMap) const { + // We emit the pointer to the MCOperandInfo entry within this array. + OS << "&" << TargetName << "Descs.OperandInfo[" << OperandInfoMap.find(OperandInfo)->second << "]"; +} + +void PrinterCapstone::instrInfoEmitRecordEnd( + unsigned InstNum, std::string const &InstName) const { + OS << " }, // Inst #" << InstNum << " = " << InstName << "\n"; +} + +void PrinterCapstone::instrInfoEmitMCInstrDescDecl( + std::string const &TargetName, + unsigned NumberedInstructionsSize, + unsigned OperandInfoSize, unsigned ImplicitListSize) const { + OS << "typedef struct " << TargetName << "InstrTable {\n"; + OS << " MCInstrDesc Insts[" << NumberedInstructionsSize << "];\n"; + OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n"; + OS << " MCPhysReg ImplicitOps[" << ImplicitListSize << "];\n"; + OS << "} " << TargetName << "InstrTable;\n\n"; +} + +void PrinterCapstone::instrInfoEmitStringLiteralDef( + std::string const &TargetName, + SequenceToOffsetTable InstrNames) const {} + +void PrinterCapstone::instrInfoEmitInstrNameIndices( + std::string const &TargetName, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const {} + +void PrinterCapstone::instrInfoEmitInstrDeprFeatures( + std::string const &TargetName, std::string const &TargetNamespace, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const {} + +void PrinterCapstone::instrInfoEmitInstrComplexDeprInfos( + std::string const &TargetName, + ArrayRef const &NumberedInstructions) const {} + +void PrinterCapstone::instrInfoEmitMCInstrInfoInitRoutine( + std::string const &TargetName, unsigned NumberedInstrSize, + bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const {} + +void PrinterCapstone::instrInfoEmitHeader(std::string const &TargetName) const {} + +void PrinterCapstone::instrInfoEmitClassStruct( + std::string const &ClassName) const {} + +void PrinterCapstone::instrInfoEmitTIIHelperMethod( + StringRef const &TargetName, Record const *Rec, + bool ExpandDefinition) const {} + +void PrinterCapstone::instrInfoEmitExternArrays( + std::string const &TargetName, bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const {} + +void PrinterCapstone::instrInfoEmitMCInstrInfoInit( + std::string const &TargetName, + unsigned NumberedInstrSize, bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const {} + +void PrinterCapstone::instrInfoEmitOperandEnum( + std::map const &Operands) const {} + +void PrinterCapstone::instrInfoEmitGetNamedOperandIdx( + std::map const &Operands, + OpNameMapTy const &OperandMap) const {} + +void PrinterCapstone::instrInfoEmitOpTypeEnumPartI() const {} + +void PrinterCapstone::instrInfoEmitOpTypeEnumPartII(StringRef const &OpName, + unsigned EnumVal) const {} + +void PrinterCapstone::instrInfoEmitOpTypeEnumPartIII() const {} + +void PrinterCapstone::instrInfoEmitOpTypeOffsetTable( + std::vector OperandOffsets, unsigned OpRecSize, + ArrayRef const &NumberedInstructions) const {} + +void PrinterCapstone::instrInfoEmitOpcodeOpTypesTable( + unsigned EnumVal, std::vector const &OperandRecords, + std::vector OperandOffsets, + ArrayRef const &NumberedInstructions) const {} + +void PrinterCapstone::instrInfoEmitGetOpTypeHdr() const {} + +void PrinterCapstone::instrInfoEmitGetOpTypeReturn() const {} + +void PrinterCapstone::instrInfoEmitGetOpTypeUnreachable() const {} + +void PrinterCapstone::instrInfoEmitGetOpTypeEnd() const {} + +void PrinterCapstone::instrInfoEmitGetMemOpSizeHdr() const {} + +void PrinterCapstone::instrInfoEmitGetOpMemSizeTbl( + std::map> &SizeToOperandName) const {} + +std::string +PrinterCapstone::instrInfoGetInstMapEntry(StringRef const &Namespace, + StringRef const &InstrName) const { + return Namespace.str() + "_" + InstrName.str(); +} + +void PrinterCapstone::instrInfoEmitGetLogicalOpSizeHdr() const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpSizeTable( + size_t LogicalOpListSize, + std::vector *> const &LogicalOpSizeList) const { +} + +void PrinterCapstone::instrInfoEmitGetLogicalOpSizeSwitch( + std::map> InstMap) const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpSizeReturn() const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpSizeEnd() const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpIdx() const {} + +std::string +PrinterCapstone::instrInfoGetOpTypeListEntry(StringRef const &Namespace, + StringRef const &OpName) const { + return Namespace.str() + "_OpTypes_" + OpName.str(); +} + +void PrinterCapstone::instrInfoEmitGetLogicalOpTypeHdr() const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpTypeTable( + size_t OpTypeListSize, + std::vector *> const &LogicalOpTypeList) + const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpTypeSwitch( + std::map> InstMap) const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpTypeReturn() const {} + +void PrinterCapstone::instrInfoEmitGetLogicalOpTypeEnd() const {} + +void PrinterCapstone::instrInfoEmitDeclareMCInstFeatureClasses() const {} + +void PrinterCapstone::instrInfoEmitPredFcnDecl( + RecVec const &TIIPredicates) const {} + +void PrinterCapstone::instrInfoEmitPredFcnImpl(StringRef const &TargetName, + RecVec const &TIIPredicates) {} + +void PrinterCapstone::instrInfoEmitInstrPredVerifierIncludes() const {} + +void PrinterCapstone::instrInfoEmitMacroDefineCheck() const {} + +void PrinterCapstone::instrInfoEmitSubtargetFeatureBitEnumeration( + std::map &SubtargetFeatures) + const {} + +void PrinterCapstone::instrInfoEmitEmitSTFNameTable( + std::map &SubtargetFeatures) + const {} + +void PrinterCapstone::instrInfoEmitFeatureBitsEnum( + std::vector> const &FeatureBitsets) const {} + +void PrinterCapstone::instrInfoEmitFeatureBitsArray( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures) const {} + +void PrinterCapstone::instrInfoEmitRequiredFeatureRefs( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures, + CodeGenTarget const &Target) const {} + +void PrinterCapstone::instrInfoEmitOpcodeChecker() const {} + +void PrinterCapstone::instrInfoEmitPredicateVerifier(StringRef const &TargetName) const {} + +void PrinterCapstone::instrInfoEmitEnums( + CodeGenTarget const &Target, StringRef const &Namespace, + CodeGenSchedModels const &SchedModels) const { + emitIncludeToggle("GET_INSTRINFO_ENUM", true); + + unsigned Num = 0; + OS << " enum {\n"; + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) + OS << " " << Namespace << "_" << Inst->TheDef->getName() + << "\t= " << Num++ << ",\n"; + OS << " INSTRUCTION_LIST_END = " << Num << "\n"; + OS << " };\n\n"; + emitIncludeToggle("GET_INSTRINFO_ENUM", false); +} + +void PrinterCapstone::instrInfoEmitTIIPredicates(StringRef const &TargetName, + RecVec const &TIIPredicates, + bool ExpandDefinition) {} + +void PrinterCapstone::instrInfoEmitComputeAssemblerAvailableFeatures( + StringRef const &TargetName, + std::map &SubtargetFeatures) + const {} + +//-------------------------- +// Backend: AsmMatcher +//-------------------------- + +namespace { + +std::string getImplicitUses(StringRef const &TargetName, + CodeGenInstruction const *Inst) { + std::string Flags = "{ "; + for (Record const *U : Inst->ImplicitUses) { + assert(U->isSubClassOf("Register")); + Flags += TargetName.str() + "_REG_" + U->getName().str() + ", "; + } + Flags += "0 }"; + return Flags; +} +std::string getImplicitDefs(StringRef const &TargetName, + CodeGenInstruction const *Inst) { + std::string Flags = "{ "; + for (Record const *U : Inst->ImplicitDefs) { + assert(U->isSubClassOf("Register")); + Flags += TargetName.str() + "_REG_" + U->getName().str() + ", "; + } + Flags += "0 }"; + return Flags; +} + +static inline std::string normalizedMnemonic(StringRef const &Mn, + const bool Upper = true) { + auto Mnemonic = Upper ? Mn.upper() : Mn.str(); + std::replace(Mnemonic.begin(), Mnemonic.end(), '.', '_'); + std::replace(Mnemonic.begin(), Mnemonic.end(), '+', 'p'); + std::replace(Mnemonic.begin(), Mnemonic.end(), '-', 'm'); + std::replace(Mnemonic.begin(), Mnemonic.end(), '/', 's'); + + Mnemonic = StringRef(Regex("[{}]").sub("", Mnemonic)); + return Mnemonic; +} + +static inline std::string +getNormalMnemonic(std::unique_ptr const &MI, + const bool Upper = true) { + return normalizedMnemonic(MI->Mnemonic); +} + +std::string getReqFeatures(StringRef const &TargetName, AsmMatcherInfo &AMI, + std::unique_ptr const &MI, bool UseMI, + CodeGenInstruction const *CGI) { + std::string Flags = "{ "; + std::string Mn = getNormalMnemonic(MI); + // The debug if + if ((CGI->isBranch || CGI->isReturn) && !CGI->isCall) { + Flags += TargetName.str() + "_GRP_JUMP, "; + } + if (CGI->isReturn) { + Flags += TargetName.str() + "_GRP_RET, "; + } + if (CGI->isCall) { + Flags += TargetName.str() + "_GRP_CALL, "; + } + for (const auto &OpInfo : CGI->Operands.OperandList) { + if (OpInfo.OperandType == "MCOI::OPERAND_PCREL" && + (CGI->isBranch || CGI->isReturn || CGI->isIndirectBranch || + CGI->isCall)) { + Flags += TargetName.str() + "_GRP_BRANCH_RELATIVE, "; + } + } + // The group flags _GRP_PRIVILEGE and _GRP_INT (interrupt) are not + // handled here. LLVM does not provide this info. + for (Record *Predicate : CGI->TheDef->getValueAsListOfDefs("Predicates")) { + if (const SubtargetFeatureInfo *Feature = + AMI.getSubtargetFeature(Predicate)) + Flags += TargetName.str() + "_FEATURE_" + + Feature->TheDef->getName().str() + ", "; + } + Flags += "0 }"; + return Flags; +} + +std::string getLLVMInstEnumName(StringRef const &TargetName, + CodeGenInstruction const *CGI) { + std::string UniqueName = CGI->TheDef->getName().str(); + std::string Enum = TargetName.str() + "_" + UniqueName; + std::replace(Enum.begin(), Enum.end(), '/', 's'); + return Enum; +} + +std::string getArchSupplInfoAArch64(CodeGenInstruction const *CGI) { + // Compute memory access type + std::string MemoryAccess; + if (CGI->mayLoad && CGI->mayStore) { + MemoryAccess = "CS_AC_READ_WRITE"; + } else if (CGI->mayLoad && !CGI->mayStore) { + MemoryAccess = "CS_AC_READ"; + } else if (!CGI->mayLoad && CGI->mayStore) { + MemoryAccess = "CS_AC_WRITE"; + } else { + MemoryAccess = "CS_AC_INVALID"; + } + return "{ .aarch64 = { .mem_acc = " + MemoryAccess + " }}"; +} + +std::string getArchSupplInfoPPC(StringRef const &TargetName, + CodeGenInstruction const *CGI, + raw_string_ostream &PPCFormatEnum) { + static std::set Formats; + // Get instruction format + ArrayRef> SCs = CGI->TheDef->getSuperClasses(); + if (SCs.empty()) { + llvm_unreachable("A CGI without superclass should not exist."); + } + + // Get base instruction format class "I" + const Record *PrevSC = nullptr; + // Superclasses are in post-order. So we go through them backwards. + // The class before the "I" class is the format class. + for (int I = SCs.size() - 1; I >= 0; --I) { + const Record *SC = SCs[I].first; + if (SC->getName() == "I") { + if (!PrevSC) + llvm_unreachable("I class has no predecessor."); + std::string Format = "PPC_INSN_FORM_" + PrevSC->getName().upper(); + if (Formats.find(Format) == Formats.end()) { + PPCFormatEnum << Format + ",\n"; + } + Formats.emplace(Format); + return "{{ " + Format + " }}"; + } + PrevSC = SC; + } + // Pseudo instructions + return "{{ 0 }}"; +} + +std::string getArchSupplInfoLoongArch(StringRef const &TargetName, + CodeGenInstruction const *CGI, + raw_string_ostream &LoongArchFormatEnum) { + static std::set Formats; + // Get instruction format + ArrayRef> SCs = CGI->TheDef->getSuperClasses(); + if (SCs.empty()) { + llvm_unreachable("A CGI without superclass should not exist."); + } + + // Compute memory access type + std::string MemoryAccess; + if (CGI->mayLoad && CGI->mayStore) { + MemoryAccess = "CS_AC_READ_WRITE"; + } else if (CGI->mayLoad && !CGI->mayStore) { + MemoryAccess = "CS_AC_READ"; + } else if (!CGI->mayLoad && CGI->mayStore) { + MemoryAccess = "CS_AC_WRITE"; + } else { + MemoryAccess = "CS_AC_INVALID"; + } + + // Get base instruction format class "LAInst" + const Record *PrevSC = nullptr; + // Superclasses are in post-order. So we go through them backwards. + // The class before the "LAInst" class is the format class. + for (int I = SCs.size() - 1; I >= 0; --I) { + const Record *SC = SCs[I].first; + if (SC->getName() == "LAInst") { + if (!PrevSC) + llvm_unreachable("I class has no predecessor."); + std::string Format = "LoongArch_INSN_FORM_" + PrevSC->getName().upper(); + if (Formats.find(Format) == Formats.end()) { + LoongArchFormatEnum << Format + ",\n"; + } + Formats.emplace(Format); + return "{ .loongarch = { " + Format + ", " + MemoryAccess + " }}"; + } + PrevSC = SC; + } + // Pseudo instructions + return "{ .loongarch = { 0, " + MemoryAccess + " }}"; +} + +std::string getArchSupplInfo(StringRef const &TargetName, + CodeGenInstruction const *CGI, + raw_string_ostream &FormatEnum) { + if (TargetName == "PPC") + return getArchSupplInfoPPC(TargetName, CGI, FormatEnum); + else if (TargetName == "AArch64") { + return getArchSupplInfoAArch64(CGI); + } else if (TargetName == "LoongArch") { + return getArchSupplInfoLoongArch(TargetName, CGI, FormatEnum); + } + return "{{ 0 }}"; +} + +Record *argInitOpToRecord(Init *ArgInit) { + DagInit *SubArgDag = dyn_cast(ArgInit); + if (SubArgDag) + ArgInit = SubArgDag->getOperator(); + DefInit *Arg = dyn_cast(ArgInit); + Record *Rec = Arg->getDef(); + return Rec; +} + +std::string getPrimaryCSOperandType(Record const *OpRec) { + std::string OperandType; + if (OpRec->isSubClassOf("PredicateOperand")) + return "CS_OP_PRED"; + + if (OpRec->isSubClassOf("RegisterClass") || + OpRec->isSubClassOf("PointerLikeRegClass")) + OperandType = "OPERAND_REGISTER"; + else if (OpRec->isSubClassOf("Operand") || + OpRec->isSubClassOf("RegisterOperand")) + OperandType = std::string(OpRec->getValueAsString("OperandType")); + else + return "CS_OP_INVALID"; + + if (OperandType == "OPERAND_UNKNOWN") { + if (OpRec->getValueAsDef("Type")->getValueAsInt("Size") == 0) + // Pseudo type + return "CS_OP_INVALID"; + OperandType = "OPERAND_IMMEDIATE"; + } + if (OperandType == "OPERAND_PCREL" || OperandType == "OPERAND_IMMEDIATE") + OperandType = "CS_OP_IMM"; + else if (OperandType == "OPERAND_MEMORY") + OperandType = "CS_OP_MEM"; + else if (OperandType == "OPERAND_REGISTER") + OperandType = "CS_OP_REG"; + // Arch dependent special Op types + else if (OperandType == "OPERAND_VPRED_N" || OperandType == "OPERAND_VPRED_R") + return "CS_OP_INVALID"; + else if (OperandType == "OPERAND_IMPLICIT_IMM_0") + return "CS_OP_IMM"; + else + PrintFatalNote("Unhandled OperandType: " + OperandType); + return OperandType; +} + +/// Compares both lists of super classes for any matches. +/// It ignores very common (Architecture independent) +/// super classes (DAGOperand, RegisterOperand, PatFrags +/// etc.). Because those will certainly lead to false positives. +bool compareTypeSuperClasses(ArrayRef> OpTypeSC, + ArrayRef> PatTypeSC) { + std::vector IgnoredSC = { + "DAGOperand", "Operand", "PatFrag", "PatFrags", + "RegisterClass", "RegisterOperand", "SDPatternOperator", "ValueType"}; + std::vector OpSCToTest; + std::vector PatSCToTest; + + // Go backwards over super clases (backwards over the inheritance tree) until + // we find a SC to ignore. + for (auto SCPair : reverse(OpTypeSC)) { + if (find(IgnoredSC, SCPair.first->getName()) != IgnoredSC.end()) + break; + OpSCToTest.emplace_back(SCPair.first); + } + for (auto SCPair : reverse(PatTypeSC)) { + if (find(IgnoredSC, SCPair.first->getName()) != IgnoredSC.end()) + break; + PatSCToTest.emplace_back(SCPair.first); + } + return any_of(OpSCToTest, [&](Record *OpSCRec) { + return find(PatSCToTest, OpSCRec) != PatSCToTest.end(); + }); +} + +/// @brief Checks if the given operand is part of a pattern of type iPTR. +/// @param OpRec The operand Record. +/// @param OpName The operand name (Rn, imm, offset etc.) +/// @param PatternDag The pattern DAG to search in. +/// @param PartOfPTRPattern True, if the given pattern is of type iPTR. False +/// otherwise. +/// @param MatchByTypeName If true, the same type names are treated as a valid +/// match. +/// @param MatchByTypeSuperClasses If true, a valid match is also if any type +/// super classes are the same. +/// @return True, if the pattern contains a node with the same name (and +/// optionally the same type name or same super class type) as the given +/// operand. False otherwise. +bool opIsPartOfiPTRPattern(Record const *OpRec, StringRef const &OpName, + DagInit *PatternDag, bool PartOfPTRPattern, + bool MatchByTypeName = false, + bool MatchByTypeSuperClasses = false) { + for (unsigned I = 0; I < PatternDag->getNumArgs(); ++I) { + DagInit *DagArg = dyn_cast(PatternDag->getArg(I)); + if (DagArg) { // Another pattern. Search in it. + Record *DagRec = dyn_cast(DagArg->getOperator())->getDef(); + + // Check if DAG operator is of type iPTR. + if (DagRec->getValue("Value") && + getValueType(DagRec) == MVT::SimpleValueType::iPTR) + PartOfPTRPattern = true; + // Complex patterns define their type in "Ty" + if (DagRec->getValue("Ty") && getValueType(DagRec->getValueAsDef("Ty")) == + MVT::SimpleValueType::iPTR) + PartOfPTRPattern = true; + if (opIsPartOfiPTRPattern(OpRec, OpName, DagArg, PartOfPTRPattern, + MatchByTypeName, MatchByTypeSuperClasses)) + return true; + continue; + } + + DefInit *LeaveDef = dyn_cast(PatternDag->getArg(I)); + if (!LeaveDef) + return false; + bool Matches; + StringRef const &PatOpName = PatternDag->getArgNameStr(I); + Matches = OpName.equals(PatOpName); + if (MatchByTypeName) { + std::string OpInitType = OpRec->getNameInitAsString(); + std::string PatOpType = PatternDag->getArg(I)->getAsString(); + Matches |= OpInitType == PatOpType; + } + if (MatchByTypeSuperClasses) { + std::string OpInitType = OpRec->getNameInitAsString(); + std::string PatOpType = PatternDag->getArg(I)->getAsString(); + RecordKeeper &RK = OpRec->getRecords(); + ArrayRef> OpTypeSC = + RK.getDef(OpInitType)->getSuperClasses(); + ArrayRef> PatTypeSC = + RK.getDef(PatOpType)->getSuperClasses(); + Matches |= compareTypeSuperClasses(OpTypeSC, PatTypeSC); + } + if (Matches) { + if (PartOfPTRPattern) + return true; + return false; + } + } + return false; +} + +/// Try to match a patterns resulting instr. ops to the operands of a CGI by +/// type. If it matches it returns the index of the CGI operand from which on +/// the pattern ops match (counted for OutOps + InOps). If it doens't match it +/// returns -1 +int comparePatternResultToCGIOps(CodeGenInstruction const *CGI, + DagInit *PatternResDag) { + if (PatternResDag->getNumArgs() == 0) + return -1; + DagInit *InDI = CGI->TheDef->getValueAsDag("InOperandList"); + DagInit *OutDI = CGI->TheDef->getValueAsDag("OutOperandList"); + unsigned NumOuts = OutDI->getNumArgs(); + unsigned NumOps = OutDI->getNumArgs() + InDI->getNumArgs(); + int32_t PatMatchStart = -1; + for (unsigned I = 0, J = 0; I < NumOps; ++I) { + Init *OpInit; + bool IsOutOp = I < NumOuts; + if (IsOutOp) { + OpInit = OutDI->getArg(I); + } else { + OpInit = InDI->getArg(I - NumOuts); + } + std::string PatOpType = PatternResDag->getArg(J)->getAsString(); + std::string OpType = OpInit->getAsString(); + + if (PatOpType == OpType) { + // Select next pattern op + if (PatMatchStart == -1) + PatMatchStart = I; + J++; + if (J >= PatternResDag->getNumArgs()) + // Done + return PatMatchStart; + } else if (PatMatchStart != -1) { + return -1; + } + } + // Nothing matched + return -1; +} + +/// Returns the pattern record which matches the CGI. +/// Or a nullltr if none matches. +Record *getMatchingPattern( + CodeGenInstruction const *CGI, + std::map> const InsnPatternMap) { + std::vector Patterns = + InsnPatternMap.at(CGI->TheDef->getName().str()); + // Search for pattern which matches this instruction. + int32_t PatStart = -1; + for (Record *Pat : Patterns) { + DagInit *PatternResDag = dyn_cast( + Pat->getValueAsListInit("ResultInstrs")->getValues()[0]); + Pat->dump(); + // Interate over every In and Out operand and get its Def. + // Compare ts type against the pattern. + PatStart = comparePatternResultToCGIOps(CGI, PatternResDag); + if (PatStart < 0) + continue; + return Pat; + } + return nullptr; +} + +std::string getCSOperandType( + StringRef const &TargetName, CodeGenInstruction const *CGI, + Record const *OpRec, StringRef const &OpName, + std::map> const InsnPatternMap) { + std::string OperandType = getPrimaryCSOperandType(OpRec); + + if (TargetName.equals("AArch64") && OperandType != "CS_OP_MEM") { + // The definitions of AArch64 are so flawed, when it comes to memory + // operands (they are not labeled as such), that we just search for the op name enclosed in []. + if (Regex("\\[[^]]*\\$" + OpName.str() + "[^[]*]").match(CGI->AsmString)) { + // Memory operands are always preceded by a ' '. + // Angle brackets not preceded by a ' ' mark offset operands + // of SME/SVE matrix operands. They are bound to the previous operand, so to say. + if (Regex("[\t ]\\[[^]]*\\$" + OpName.str() + "[^[]*]").match(CGI->AsmString)) { + return OperandType += " | CS_OP_MEM"; + } + return OperandType += " | CS_OP_BOUND"; + } + } + + DagInit *PatternDag = nullptr; + if (OperandType == "CS_OP_MEM") + // It is only marked as mem, we treat it as immediate. + OperandType += " | CS_OP_IMM"; + else if (OpRec->getValue("Type") && + getValueType(OpRec->getValueAsDef("Type")) == + MVT::SimpleValueType::iPTR) + OperandType += " | CS_OP_MEM"; + else if (!CGI->TheDef->isValueUnset("Pattern") && + !CGI->TheDef->getValueAsListInit("Pattern")->empty()) { + // Check if operand is part of a pattern with a memory type (iPTR) + ListInit *PatternList = CGI->TheDef->getValueAsListInit("Pattern"); + PatternDag = dyn_cast(PatternList->getValues()[0]); + } else if (!InsnPatternMap.empty()) { + // Pattern field is not set in the CGI. + // But there might be (multiple) patterns in the record keeper + // for this CGI + std::string CGIName = CGI->TheDef->getName().str(); + if (InsnPatternMap.find(CGIName) == InsnPatternMap.end()) + return OperandType; + + bool OpTypeIsPartOfAnyPattern = + any_of(InsnPatternMap.at(CGIName), [&](Record *PatternDag) { + return opIsPartOfiPTRPattern( + OpRec, OpName, PatternDag->getValueAsDag("PatternToMatch"), false, + true); + }); + if (OpTypeIsPartOfAnyPattern) + OperandType += " | CS_OP_MEM"; + return OperandType; + } + if (PatternDag && opIsPartOfiPTRPattern(OpRec, OpName, PatternDag, false)) + OperandType += " | CS_OP_MEM"; + return OperandType; +} + +void printInsnMapEntry(StringRef const &TargetName, AsmMatcherInfo &AMI, + std::unique_ptr const &MI, bool UseMI, + CodeGenInstruction const *CGI, + raw_string_ostream &InsnMap, unsigned InsnNum, + raw_string_ostream &FormatEnum) { + InsnMap << "{\n"; + InsnMap.indent(2) << "/* " + << (CGI->AsmString != "" ? CGI->AsmString + : "") + << " */\n"; + // adds id + InsnMap.indent(2) << getLLVMInstEnumName(TargetName, CGI) << " /* " << InsnNum + << " */"; + InsnMap << ", " << TargetName << "_INS_" + << (UseMI ? getNormalMnemonic(MI) : "INVALID") << ",\n"; + // no diet only + InsnMap.indent(2) << "#ifndef CAPSTONE_DIET\n"; + if (UseMI) { + InsnMap.indent(4) << getImplicitUses(TargetName, CGI) << ", "; + InsnMap << getImplicitDefs(TargetName, CGI) << ", "; + InsnMap << getReqFeatures(TargetName, AMI, MI, UseMI, CGI) << ", "; + InsnMap << ((CGI->isBranch || CGI->isReturn) ? "1" : "0") << ", "; + InsnMap << (CGI->isIndirectBranch ? "1" : "0") << ", "; + InsnMap << getArchSupplInfo(TargetName, CGI, FormatEnum) << "\n"; + } else { + InsnMap.indent(4) << "{ 0 }, { 0 }, { 0 }, 0, 0, {{ 0 }}"; + } + InsnMap << '\n'; + InsnMap.indent(2) << "#endif\n"; + InsnMap << "},\n"; +} + +static std::string getCSAccess(short Access) { + if (Access == 1) + return "CS_AC_READ"; + else if (Access == 2) + return "CS_AC_WRITE"; + else if (Access == 3) + return "CS_AC_READ | CS_AC_WRITE"; + else if (Access == 0) + return "CS_AC_INVALID"; + else + PrintFatalNote("Invalid access flags set."); +} + +/// @brief Returns the operand data type. If it is a float it updates +/// OperandType as well. +/// @param Op The operand. +/// @param OperandType The operand type. +/// @return The strig of data types. +std::string getOperandDataTypes(Record const *Op, std::string &OperandType) { + MVT::SimpleValueType VT; + std::vector OpDataTypes; + + if (!Op->getValue("RegTypes") && Op->getValue("RegClass") && + OperandType.find("CS_OP_REG") != std::string::npos) + Op = Op->getValueAsDef("RegClass"); + + if (!(Op->getValue("Type") || Op->getValue("RegTypes"))) + return "{ CS_DATA_TYPE_LAST }"; + + if (OperandType.find("CS_OP_REG") != std::string::npos && + Op->getValue("RegTypes")) { + OpDataTypes = Op->getValueAsListOfDefs("RegTypes"); + } else { + Record *OpType = Op->getValueAsDef("Type"); + VT = getValueType(OpType); + bool IsFloat = false; + for (uint8_t V = MVT::SimpleValueType::FIRST_FP_VALUETYPE; + V <= MVT::SimpleValueType::LAST_FP_VALUETYPE; V++) + IsFloat |= (VT == V); + + if (IsFloat) + OperandType = (OperandType.find("MEM") != std::string::npos) + ? "CS_OP_MEM | CS_OP_FP" + : "CS_OP_FP"; + StringRef EnumVT = getEnumName(VT); + return "{ CS_DATA_TYPE_" + EnumVT.substr(5).str() + ", CS_DATA_TYPE_LAST }"; + } + + std::string DataTypes = "{ "; + for (Record *Type : OpDataTypes) { + StringRef EnumVT = getEnumName(getValueType(Type)); + DataTypes += "CS_DATA_TYPE_" + EnumVT.substr(5).str() + ", "; + } + DataTypes += "CS_DATA_TYPE_LAST }"; + return DataTypes; +} + +typedef struct OpData { + Record *Rec; + std::string OpAsm; + std::string OpType; + std::string DataTypes; + unsigned Access; ///< 0b00 = unkown, 0b01 = In, 0b10 = Out, 0b11 = In and Out + std::string str() const { + return "Asm: " + OpAsm + " Type: " + OpType + + " Access: " + std::to_string(Access); + } +} OpData; + +uint8_t getOpAccess(CodeGenInstruction const *CGI, std::string OperandType, + bool IsOutOp) { + if (OperandType.find("CS_OP_MEM") != std::string::npos) { + if (CGI->mayLoad_Unset && CGI->mayStore_Unset) { + return 0; + } else if (CGI->mayLoad && CGI->mayStore) + return 3; + else if (CGI->mayLoad) + return 1; + else if (CGI->mayStore) + return 2; + } + return IsOutOp ? 2 : 1; +} + +void addComplexOperand( + StringRef const &TargetName, CodeGenInstruction const *CGI, + Record const *ComplexOp, StringRef const &ArgName, bool IsOutOp, + std::vector &InsOps, + std::map> const InsnPatternMap) { + DagInit *SubOps = ComplexOp->getValueAsDag("MIOperandInfo"); + + unsigned E = SubOps->getNumArgs(); + for (unsigned I = 0; I != E; ++I) { + Init *ArgInit = SubOps->getArg(I); + Record *SubOp = argInitOpToRecord(ArgInit); + // Determine Operand type + std::string OperandType; + std::string SubOperandType = getCSOperandType( + TargetName, CGI, SubOp, SubOp->getName().str(), InsnPatternMap); + std::string ComplOperandType = + getCSOperandType(TargetName, CGI, ComplexOp, ArgName, InsnPatternMap); + if (ComplOperandType.find("CS_OP_MEM") != std::string::npos) + OperandType = "CS_OP_MEM | " + SubOperandType; + else if (!CGI->TheDef->isValueUnset("Pattern") && + !CGI->TheDef->getValueAsListInit("Pattern")->empty()) { + OperandType = SubOperandType; + ListInit *PatternList = CGI->TheDef->getValueAsListInit("Pattern"); + DagInit *PatternDag = dyn_cast(PatternList->getValues()[0]); + if (PatternDag && opIsPartOfiPTRPattern(SubOp, SubOps->getArgNameStr(I), + PatternDag, false)) + OperandType += " | CS_OP_MEM"; + } else + OperandType = SubOperandType; + + unsigned AccessFlag = getOpAccess(CGI, OperandType, IsOutOp); + std::string OpDataTypes = getOperandDataTypes(SubOp, SubOperandType); + + // Check if Operand was already seen before (as In or Out operand). + // If so update its access flags. + std::string OpName = ArgName.str() + " - " + SubOp->getName().str(); + InsOps.push_back(OpData{SubOp, std::move(OpName), std::move(OperandType), + std::move(OpDataTypes), AccessFlag}); + } +} + +void printInsnOpMapEntry( + CodeGenTarget const &Target, std::unique_ptr const &MI, + bool UseMI, CodeGenInstruction const *CGI, raw_string_ostream &InsnOpMap, + unsigned InsnNum, + std::map> const InsnPatternMap) { + StringRef TargetName = Target.getName(); + + // Instruction without mnemonic. + if (!UseMI) { + std::string LLVMEnum = getLLVMInstEnumName(TargetName, CGI); + // Write the C struct of the Instruction operands. + // The many braces are necessary because of this bug from + // medieval times: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 + InsnOpMap << "{{{ /* " + LLVMEnum + " (" << InsnNum + << ") - " + TargetName + "_INS_" + + (UseMI ? getNormalMnemonic(MI) : "INVALID") + " - " + + CGI->AsmString + " */\n"; + InsnOpMap << " 0\n"; + InsnOpMap << "}}},\n"; + return; + } + + DagInit *InDI = CGI->TheDef->getValueAsDag("InOperandList"); + DagInit *OutDI = CGI->TheDef->getValueAsDag("OutOperandList"); + unsigned NumDefs = OutDI->getNumArgs(); + + unsigned E = OutDI->getNumArgs() + InDI->getNumArgs(); + bool IsOutOp; + std::vector InsOps; + // Iterate over every In and Out operand and get its Def. + for (unsigned I = 0; I != E; ++I) { + Init *ArgInit; + StringRef ArgName; + IsOutOp = I < NumDefs; + if (IsOutOp) { + ArgInit = OutDI->getArg(I); + ArgName = OutDI->getArgNameStr(I); + } else { + ArgInit = InDI->getArg(I - NumDefs); + ArgName = InDI->getArgNameStr(I - NumDefs); + } + Record *Rec = argInitOpToRecord(ArgInit); + + // Add complex operands. + // Operands which effectively consists of two or more operands. + if (Rec->getValue("MIOperandInfo")) { + if (Rec->getValueAsDag("MIOperandInfo")->getNumArgs() > 0) { + addComplexOperand(TargetName, CGI, Rec, ArgName, IsOutOp, InsOps, + InsnPatternMap); + continue; + } + } + + // Determine Operand type + std::string OperandType = + getCSOperandType(TargetName, CGI, Rec, ArgName, InsnPatternMap); + if (OperandType == "") + continue; + + std::string OpDataTypes = getOperandDataTypes(Rec, OperandType); + + // Check if Operand was already seen before (as In or Out operand). + // If so update its access flags. + unsigned AccessFlag = getOpAccess(CGI, OperandType, IsOutOp); + InsOps.push_back(OpData{Rec, ArgName.str(), std::move(OperandType), + std::move(OpDataTypes), AccessFlag}); + } + + if (InsOps.size() > 15) { + for (OpData const &OD : InsOps) { + PrintNote(OD.str()); + OD.Rec->dump(); + } + PrintFatalNote("Inst has more then 15 operands: " + CGI->AsmString); + } + + std::string LLVMEnum = getLLVMInstEnumName(TargetName, CGI); + // Write the C struct of the Instruction operands. + InsnOpMap << "{ /* " + LLVMEnum + " (" << InsnNum + << ") - " + TargetName + "_INS_" + + (UseMI ? getNormalMnemonic(MI) : "INVALID") + " - " + + CGI->AsmString + " */\n"; + InsnOpMap << "{\n"; + for (OpData const &OD : InsOps) { + InsnOpMap.indent(2) << "{ " << OD.OpType << ", " << getCSAccess(OD.Access) + << ", " << OD.DataTypes << " }, /* " << OD.OpAsm << " */\n"; + } + InsnOpMap.indent(2) << "{ 0 }\n"; + InsnOpMap << "}},\n"; +} + +void printInsnNameMapEnumEntry(StringRef const &TargetName, + std::unique_ptr const &MI, + raw_string_ostream &InsnNameMap, + raw_string_ostream &InsnEnum) { + static std::set MnemonicsSeen; + static std::set EnumsSeen; + + std::string Mnemonic = normalizedMnemonic(MI->Mnemonic.str(), false); + if (MnemonicsSeen.find(Mnemonic) != MnemonicsSeen.end()) + return; + + std::string EnumName = + TargetName.str() + "_INS_" + normalizedMnemonic(StringRef(Mnemonic)); + InsnNameMap.indent(2) << "\"" + Mnemonic + "\", // " + EnumName + "\n"; + if (EnumsSeen.find(EnumName) == EnumsSeen.end()) + InsnEnum.indent(2) << EnumName + ",\n"; + + MnemonicsSeen.emplace(Mnemonic); + EnumsSeen.emplace(EnumName); +} + +void printFeatureEnumEntry(StringRef const &TargetName, AsmMatcherInfo &AMI, + CodeGenInstruction const *CGI, + raw_string_ostream &FeatureEnum, + raw_string_ostream &FeatureNameArray) { + static std::set Features; + std::string EnumName; + + for (std::pair ST : AMI.SubtargetFeatures) { + const SubtargetFeatureInfo &STF = ST.second; + std::string Feature = STF.TheDef->getName().str(); + if (Features.find(Feature) != Features.end()) + continue; + Features.emplace(Feature); + + // Enum + EnumName = TargetName.str() + "_FEATURE_" + STF.TheDef->getName().str(); + FeatureEnum << EnumName; + if (Features.size() == 1) + FeatureEnum << " = 128"; + FeatureEnum << ",\n"; + + // Enum name map + FeatureNameArray << "{ " + EnumName + ", \"" + STF.TheDef->getName().str() + + "\" },\n"; + } +} + +/// Emits enum entries for each operand group. +/// The operand group name is equal printer method of the operand. +/// printSORegRegOperand -> SORegRegOperand +void printOpPrintGroupEnum(StringRef const &TargetName, + CodeGenInstruction const *CGI, + raw_string_ostream &OpGroupEnum) { + static std::set OpGroups; + // Some operand groups, which exists, are never passed here. + // So we add them manually. + static const std::set ARMExceptions = { + "RegImmShift", + "LdStmModeOperand", + "MandatoryInvertedPredicateOperand", + }; + /// Some groups are hard to generate. Like standard template arguments. + /// Those are added here. + static const std::set AArch64Exceptions = { + "VectorIndex_8", + "PrefetchOp_1", + "LogicalImm_int8_t", + "LogicalImm_int16_t", + "InverseCondCode", + "AMNoIndex", + "PSBHintOp", + "BTIHintOp", + "ImplicitlyTypedVectorList", + "SVERegOp_0", + "SVELogicalImm_int16_t", + "SVELogicalImm_int32_t", + "SVELogicalImm_int64_t", + "MatrixIndex_8", + "MatrixIndex_0", + "MatrixIndex_1", + "AdrLabel", + "AdrpLabel", + "ZPRasFPR_128"}; + static const std::set PPCExceptions = { + "S12ImmOperand", // PS S12 immediates. Used as memory disponent. + }; + + bool NoExceptions = false; + const std::set *Exc; + if (TargetName == "ARM") + Exc = &ARMExceptions; + else if (TargetName == "AArch64") + Exc = &AArch64Exceptions; + else if (TargetName == "PPC") + Exc = &PPCExceptions; + else + NoExceptions = true; + + if (OpGroups.empty() && !NoExceptions) { + for (const std::string &OpGroup : *Exc) { + OpGroupEnum.indent(2) << TargetName + "_OP_GROUP_" + OpGroup + " = " + << OpGroups.size() << ",\n"; + OpGroups.emplace(OpGroup); + } + } + + for (const CGIOperandList::OperandInfo &Op : CGI->Operands) { + std::string OpGroup = + PrinterCapstone::translateToC(TargetName.str(), Op.PrinterMethodName) + .substr(5); + if (OpGroups.find(OpGroup) != OpGroups.end()) + continue; + OpGroupEnum.indent(2) << TargetName + "_OP_GROUP_" + OpGroup + " = " + << OpGroups.size() << ",\n"; + OpGroups.emplace(OpGroup); + } +} + +void printInsnAliasEnum(CodeGenTarget const &Target, + raw_string_ostream &AliasEnum, + raw_string_ostream &AliasMnemMap) { + RecordKeeper &Records = Target.getTargetRecord()->getRecords(); + std::vector AllInstAliases = + Records.getAllDerivedDefinitions("InstAlias"); + std::set AliasMnemonicsSeen; + + for (Record *AliasRec : AllInstAliases) { + int Priority = AliasRec->getValueAsInt("EmitPriority"); + if (Priority < 1) + continue; // Aliases with priority 0 are never emitted. + const DagInit *AliasDag = AliasRec->getValueAsDag("ResultInst"); + DefInit *DI = dyn_cast(AliasDag->getOperator()); + CodeGenInstruction *RealInst = &Target.getInstruction(DI->getDef()); + + StringRef AliasAsm = AliasRec->getValueAsString("AsmString"); + SmallVector Matches; + // Some Alias only differ by operands. Get only the mnemonic part. + Regex("^[a-zA-Z0-9+-.]+").match(AliasAsm, &Matches); + StringRef &AliasMnemonic = Matches[0]; + std::string NormAliasMnem = Target.getName().str() + "_INS_ALIAS_" + + normalizedMnemonic(AliasMnemonic); + if (AliasMnemonicsSeen.find(NormAliasMnem) != AliasMnemonicsSeen.end()) + continue; + + AliasMnemonicsSeen.emplace(NormAliasMnem); + + AliasEnum << "\t" + NormAliasMnem + ", // Real instr.: " + + getLLVMInstEnumName(Target.getName(), RealInst) + "\n"; + + AliasMnemMap << "\t{ " + NormAliasMnem + ", \"" + + normalizedMnemonic(AliasMnemonic, false) + "\" },\n"; + } +} + +void addInsnsToPatternMap(Record *Pattern, + std::map> &Map, + ArrayRef ResInsns) { + for (Init *RI : ResInsns) { + Record *RIRec = + dyn_cast(dyn_cast(RI)->getOperator())->getDef(); + if (!RIRec->getValue("isPseudo")) + continue; // No instruction + if (RIRec->getValueAsBit("isPseudo")) { + if (!RIRec->getValue("ResultInst")) + continue; + // Add the resulting instruction of this pseudo instruction as well. + addInsnsToPatternMap( + Pattern, Map, ArrayRef(RIRec->getValueAsDag("ResultInst"))); + } + std::string RIName = dyn_cast(RI)->getOperator()->getAsString(); + if (Map.find(RIName) == Map.end()) { + std::vector PatVec; + PatVec.emplace_back(Pattern); + Map.emplace(RIName, std::move(PatVec)); + } else { + std::vector &PatternVec = Map.at(RIName); + PatternVec.emplace_back(Pattern); + } + } +} + +/// Returns a map with instruction name and its pattern. +/// Only needed by archs which, very annoyingly, +/// do not set the Pattern field in CGIs (like AArch64). +void getInsnPatternMap(CodeGenTarget const &Target, + std::map> &Map) { + for (Record *P : + Target.getTargetRecord()->getRecords().getAllDerivedDefinitions("Pat")) { + ListInit *ResInsns = P->getValueAsListInit("ResultInstrs"); + addInsnsToPatternMap(P, Map, ResInsns->getValues()); + } +} + +} // namespace + +/// This function emits all the mapping files and +/// Instruction enum for the current architecture. +void PrinterCapstone::asmMatcherEmitMatchTable(CodeGenTarget const &Target, + AsmMatcherInfo &Info, + StringToOffsetTable &StringTable, + unsigned VariantCount) const { + std::string InsnMapStr; + std::string InsnOpMapStr; + std::string InsnNameMapStr; + std::string InsnEnumStr; + std::string FeatureEnumStr; + std::string FeatureNameArrayStr; + std::string OpGroupStr; + std::string FormatEnumStr; + std::string AliasEnumStr; + std::string AliasMnemMapStr; + raw_string_ostream InsnMap(InsnMapStr); + raw_string_ostream InsnOpMap(InsnOpMapStr); + raw_string_ostream InsnNameMap(InsnNameMapStr); + raw_string_ostream InsnEnum(InsnEnumStr); + raw_string_ostream FeatureEnum(FeatureEnumStr); + raw_string_ostream FeatureNameArray(FeatureNameArrayStr); + raw_string_ostream OpGroups(OpGroupStr); + raw_string_ostream FormatEnum(FormatEnumStr); + raw_string_ostream AliasEnum(AliasEnumStr); + raw_string_ostream AliasMnemMap(AliasMnemMapStr); + emitDefaultSourceFileHeader(InsnMap); + emitDefaultSourceFileHeader(InsnOpMap); + emitDefaultSourceFileHeader(InsnNameMap); + emitDefaultSourceFileHeader(InsnEnum); + emitDefaultSourceFileHeader(FeatureEnum); + emitDefaultSourceFileHeader(FeatureNameArray); + emitDefaultSourceFileHeader(OpGroups); + emitDefaultSourceFileHeader(FormatEnum); + emitDefaultSourceFileHeader(AliasEnum); + emitDefaultSourceFileHeader(AliasMnemMap); + + // Currently we ignore any other Asm variant then the primary. + Record *AsmVariant = Target.getAsmParserVariant(0); + + AsmVariantInfo Variant; + Variant.RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); + Variant.TokenizingCharacters = + AsmVariant->getValueAsString("TokenizingCharacters"); + Variant.SeparatorCharacters = + AsmVariant->getValueAsString("SeparatorCharacters"); + Variant.BreakCharacters = AsmVariant->getValueAsString("BreakCharacters"); + Variant.Name = AsmVariant->getValueAsString("Name"); + Variant.AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + SmallPtrSet SingletonRegisters; + + // Map instructino name to DefInit of pattern. + // This is noly necessary for AArch64 currently. + // Because CGI->pattern is not set in the td files. + // So we search all patterns save them under the name + // of the instruciton they belong to. + std::map> InsnPatternMap; + + getInsnPatternMap(Target, InsnPatternMap); + + // The CS mapping tables, for instructions and their operands, + // need an entry for every CodeGenInstruction. + unsigned InsnNum = 0; + for (const CodeGenInstruction *CGI : Target.getInstructionsByEnumValue()) { + auto MI = std::make_unique(*CGI); + bool UseMI = true; + MI->tokenizeAsmString(Info, Variant); + + // Ignore "codegen only" instructions. + if (CGI->TheDef->getValueAsBit("isCodeGenOnly") || + MI->AsmOperands.empty()) { + UseMI = false; + MI->Mnemonic = "invalid"; + } else + MI->Mnemonic = MI->AsmOperands[0].Token; + printInsnNameMapEnumEntry(Target.getName(), MI, InsnNameMap, InsnEnum); + printFeatureEnumEntry(Target.getName(), Info, CGI, FeatureEnum, + FeatureNameArray); + printOpPrintGroupEnum(Target.getName(), CGI, OpGroups); + + printInsnOpMapEntry(Target, MI, UseMI, CGI, InsnOpMap, InsnNum, + InsnPatternMap); + printInsnMapEntry(Target.getName(), Info, MI, UseMI, CGI, InsnMap, InsnNum, + FormatEnum); + + ++InsnNum; + } + printInsnAliasEnum(Target, AliasEnum, AliasMnemMap); + + std::string TName = Target.getName().str(); + std::string InsnMapFilename = TName + "GenCSMappingInsn.inc"; + writeFile(InsnMapFilename, InsnMapStr); + InsnMapFilename = TName + "GenCSMappingInsnOp.inc"; + writeFile(InsnMapFilename, InsnOpMapStr); + InsnMapFilename = TName + "GenCSMappingInsnName.inc"; + writeFile(InsnMapFilename, InsnNameMapStr); + InsnMapFilename = TName + "GenCSInsnEnum.inc"; + writeFile(InsnMapFilename, InsnEnumStr); + InsnMapFilename = TName + "GenCSFeatureEnum.inc"; + writeFile(InsnMapFilename, FeatureEnumStr); + InsnMapFilename = TName + "GenCSFeatureName.inc"; + writeFile(InsnMapFilename, FeatureNameArrayStr); + InsnMapFilename = TName + "GenCSOpGroup.inc"; + writeFile(InsnMapFilename, OpGroupStr); + InsnMapFilename = TName + "GenCSAliasEnum.inc"; + writeFile(InsnMapFilename, AliasEnumStr); + InsnMapFilename = TName + "GenCSAliasMnemMap.inc"; + writeFile(InsnMapFilename, AliasMnemMapStr); + if (TName == "PPC" || TName == "LoongArch") { + InsnMapFilename = TName + "GenCSInsnFormatsEnum.inc"; + writeFile(InsnMapFilename, FormatEnumStr); + } +} + +void PrinterCapstone::asmMatcherEmitSourceFileHeader( + std::string const &Desc) const {} +void PrinterCapstone::asmMatcherEmitDeclarations(bool HasOptionalOperands, + bool ReportMultipleNearMisses, + bool HasOperandInfos) const {} +void PrinterCapstone::asmMatcherEmitOperandDiagTypes( + std::set const Types) const {} + +void PrinterCapstone::asmMatcherEmitGetSubtargetFeatureName( + std::map const + SubtargetFeatures) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionI( + StringRef const &TargetName, StringRef const &ClassName, + std::string const &TargetOperandClass, bool HasOptionalOperands, + size_t MaxNumOperands) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionII( + std::string const &EnumName, StringRef const &AsmMatchConverter) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionIII( + std::string const &EnumName, std::string const TargetOperandClass, + bool HasOptionalOperands, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionIV( + std::string const &EnumName, int64_t Val) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionV( + std::string const &EnumName, std::string const &Reg) const {} +void PrinterCapstone::asmMatcherEmitConversionFunctionVI() const {} +void PrinterCapstone::asmMatcherWriteCvtOSToOS() const {} +void PrinterCapstone::asmMatcherEmitOperandFunctionI( + StringRef const &TargetName, StringRef const &ClassName) const {} +void PrinterCapstone::asmMatcherEmitOperandFunctionII( + std::string const &EnumName, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const {} +void PrinterCapstone::asmMatcherEmitOperandFunctionIII( + std::string const &EnumName) const {} +void PrinterCapstone::asmMatcherEmitOperandFunctionIV( + std::string const &EnumName) const {} +void PrinterCapstone::asmMatcherEmitOperandFunctionV() const {} +void PrinterCapstone::asmMatcherEmitTiedOperandEnum( + std::map, std::string> + TiedOperandsEnumMap) const {} +void PrinterCapstone::asmMatcherWriteOpOSToOS() const {} +void PrinterCapstone::asmMatcherEmitTiedOpTable( + std::map, std::string> + TiedOperandsEnumMap) const {} +void PrinterCapstone::asmMatcherEmitTiedOpEmptyTable() const {} +void PrinterCapstone::asmMatcherEmitOperandConvKindEnum( + SmallSetVector OperandConversionKinds) const {} +void PrinterCapstone::asmMatcherEmitInstrConvKindEnum( + SmallSetVector InstructionConversionKinds) const {} +void PrinterCapstone::asmMatcherEmitConversionTable( + size_t MaxRowLength, + std::vector> const ConversionTable, + SmallSetVector InstructionConversionKinds, + SmallSetVector OperandConversionKinds, + std::map, std::string> + TiedOperandsEnumMap) const {} +void PrinterCapstone::asmMatcherEmitMatchClassKindEnum( + std::forward_list const &Infos) const {} +void PrinterCapstone::asmMatcherEmitMatchClassDiagStrings( + AsmMatcherInfo const &Info) const {} +void PrinterCapstone::asmMatcherEmitRegisterMatchErrorFunc( + AsmMatcherInfo &Info) const {} +void PrinterCapstone::asmMatcherEmitIsSubclassI() const {} +bool PrinterCapstone::asmMatcherEmitIsSubclassII( + bool EmittedSwitch, std::string const &Name) const { + return true; +} +void PrinterCapstone::asmMatcherEmitIsSubclassIII(StringRef const &Name) const { +} +void PrinterCapstone::asmMatcherEmitIsSubclassIV( + std::vector const &SuperClasses) const {} +void PrinterCapstone::asmMatcherEmitIsSubclassV(bool EmittedSwitch) const {} +void PrinterCapstone::asmMatcherEmitValidateOperandClass( + AsmMatcherInfo &Info) const {} +void PrinterCapstone::asmMatcherEmitMatchClassKindNames( + std::forward_list &Infos) const {} +void PrinterCapstone::asmMatcherEmitAsmTiedOperandConstraints( + CodeGenTarget &Target, AsmMatcherInfo &Info) const {} +std::string PrinterCapstone::getNameForFeatureBitset( + const std::vector &FeatureBitset) const { + return ""; +} +void PrinterCapstone::asmMatcherEmitFeatureBitsetEnum( + std::vector> const FeatureBitsets) const {} +void PrinterCapstone::asmMatcherEmitFeatureBitsets( + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const {} +void PrinterCapstone::asmMatcherEmitMatchEntryStruct( + unsigned MaxMnemonicIndex, unsigned NumConverters, size_t MaxNumOperands, + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const {} +void PrinterCapstone::asmMatcherEmitMatchFunction( + CodeGenTarget const &Target, Record const *AsmParser, + StringRef const &ClassName, bool HasMnemonicFirst, bool HasOptionalOperands, + bool ReportMultipleNearMisses, bool HasMnemonicAliases, + size_t MaxNumOperands, bool HasDeprecation, + unsigned int VariantCount) const {} +void PrinterCapstone::asmMatcherEmitMnemonicSpellChecker( + CodeGenTarget const &Target, unsigned VariantCount) const {} +void PrinterCapstone::asmMatcherEmitMnemonicChecker( + CodeGenTarget const &Target, unsigned VariantCount, bool HasMnemonicFirst, + bool HasMnemonicAliases) const {} +void PrinterCapstone::asmMatcherEmitCustomOperandParsing( + unsigned MaxMask, CodeGenTarget &Target, AsmMatcherInfo const &Info, + StringRef ClassName, StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, bool HasMnemonicFirst, + Record const &AsmParser) const {} +void PrinterCapstone::asmMatcherEmitIncludes() const {} +void PrinterCapstone::asmMatcherEmitMnemonicTable( + StringToOffsetTable &StringTable) const {} +void PrinterCapstone::asmMatcherEmitMatchRegisterName( + Record const *AsmParser, + std::vector const Matches) const {} +void PrinterCapstone::asmMatcherEmitMatchTokenString( + std::vector const Matches) const {} +void PrinterCapstone::asmMatcherEmitMatchRegisterAltName( + Record const *AsmParser, + std::vector const Matches) const {} +void PrinterCapstone::asmMatcherEmitMnemonicAliasVariant( + std::vector const &Cases, + unsigned Indent) const {} +void PrinterCapstone::asmMatcherAppendMnemonicAlias( + Record const *R, std::string const &FeatureMask, + std::string &MatchCode) const {} +void PrinterCapstone::asmMatcherAppendMnemonic(Record const *R, + std::string &MatchCode) const {} +void PrinterCapstone::asmMatcherAppendMnemonicAliasEnd( + std::string &MatchCode) const {} +void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesI() const {} +void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesII( + int AsmParserVariantNo) const {} +void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesIII() const {} +void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesIV() const {} +void PrinterCapstone::asmMatcherEmitApplyMnemonicAliasesV() const {} +void PrinterCapstone::asmMatcherEmitSTFBitEnum(AsmMatcherInfo &Info) const {} +void PrinterCapstone::asmMatcherEmitComputeAssemblerAvailableFeatures( + AsmMatcherInfo &Info, StringRef const &ClassName) const {} + +void PrinterCapstone::searchableTablesWriteFiles() const { + std::string Filename = TargetName + "GenSystemRegister.inc"; + std::string HeaderStr; + raw_string_ostream Header(HeaderStr); + emitDefaultSourceFileHeader(Header); + raw_string_ostream &Decl = searchableTablesGetOS(ST_DECL_OS); + raw_string_ostream &Impl = searchableTablesGetOS(ST_IMPL_OS); + writeFile(Filename, Header.str() + Decl.str() + Impl.str()); + + raw_string_ostream &SysOpsEnum = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); + if (!SysOpsEnum.str().empty()) { + Filename = TargetName + "GenCSSystemOperandsEnum.inc"; + writeFile(Filename, Header.str() + SysOpsEnum.str()); + } +} + +raw_string_ostream &PrinterCapstone::searchableTablesGetOS(StreamType G) const { + // Very bad design here. But we only use it for our dirty generation + // for Capstone so it is not meant to be reliable. + static bool Init = false; + static std::string SysRegDecl; + static raw_string_ostream *SysRegDeclOS; + static std::string SysRegEnum; + static raw_string_ostream *SysOpsEnumOS; + static std::string SysRegImpl; + static raw_string_ostream *SysRegImplOS; + if (!Init) { + SysRegDeclOS = new raw_string_ostream(SysRegDecl); + SysRegImplOS = new raw_string_ostream(SysRegImpl); + SysOpsEnumOS = new raw_string_ostream(SysRegEnum); + Init = true; + } + + switch (G) { + default: + assert(0 && "No stream specified."); + case ST_DECL_OS: + return *SysRegDeclOS; + case ST_IMPL_OS: + return *SysRegImplOS; + case ST_ENUM_SYSOPS_OS: + return *SysOpsEnumOS; + } +} + +void PrinterCapstone::searchableTablesEmitGenericEnum( + const GenericEnum &Enum) const { + // We do not emit enums here, but generate them when we print the mapping tables + // Because the table has the type information for its fields, + // we have a chance to distinguish between Sys regs, imms and other alias. + // The generated enums are written to GenCSSystemOperandsEnum.inc +} + +void PrinterCapstone::searchableTablesEmitGenericTable( + const GenericTable &Enum) const {} + +void PrinterCapstone::searchableTablesEmitIfdef(const std::string Guard, + StreamType ST) { + raw_string_ostream &OutS = searchableTablesGetOS(ST); + OutS << "#ifdef " << Guard << "\n"; + PreprocessorGuards.insert(Guard); +} + +void PrinterCapstone::searchableTablesEmitEndif(StreamType ST) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST); + OutS << "#endif\n\n"; +} + +void PrinterCapstone::searchableTablesEmitUndef() const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + for (const auto &Guard : PreprocessorGuards) + OutS << "#undef " << Guard << "\n"; +} + +std::string PrinterCapstone::searchableTablesSearchableFieldType( + const GenericTable &Table, const SearchIndex &Index, + const GenericField &Field, TypeContext Ctx) const { + if (isa(Field.RecType)) { + if (Ctx == TypeInStaticStruct) + return "const char *"; + if (Ctx == TypeInTempStruct) + return "const char *"; + return "const char *"; + } else if (BitsRecTy *BI = dyn_cast(Field.RecType)) { + unsigned NumBits = BI->getNumBits(); + if (NumBits <= 8) + return "uint8_t"; + if (NumBits <= 16) + return "uint16_t"; + if (NumBits <= 32) + return "uint32_t"; + if (NumBits <= 64) + return "uint64_t"; + PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + + "' lookup method '" + Index.Name + + "', key field '" + Field.Name + + "' of type bits is too large"); + } else if (isa(Field.RecType)) { + return "bool"; + } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) + return "unsigned"; + PrintFatalError(Index.Loc, + Twine("In table '") + Table.Name + "' lookup method '" + + Index.Name + "', key field '" + Field.Name + + "' has invalid type: " + Field.RecType->getAsString()); +} + +std::string PrinterCapstone::searchableTablesPrimaryRepresentation( + SMLoc Loc, const GenericField &Field, Init *I, + StringRef const &InstrinsicEnumName) const { + if (StringInit *SI = dyn_cast(I)) { + if (Field.IsCode || SI->hasCodeFormat()) { + std::string Code = Regex("::").sub("_", std::string(SI->getValue())); + while (Code.find("::") != std::string::npos) + Code = Regex("::").sub("_", Code); + return Code; + } else + return Regex("::").sub("_", SI->getAsString()); + } else if (BitsInit *BI = dyn_cast(I)) + return "0x" + utohexstr(getAsInt(BI)); + else if (BitInit *BI = dyn_cast(I)) + return BI->getValue() ? "true" : "false"; + else if (Field.IsIntrinsic) + return "Intrinsic_" + InstrinsicEnumName.str(); + else if (Field.IsInstruction) + return Regex("::").sub("_", I->getAsString()); + else if (Field.Enum) { + auto *Entry = Field.Enum->EntryMap[cast(I)->getDef()]; + if (!Entry) + PrintFatalError(Loc, + Twine("Entry for field '") + Field.Name + "' is null"); + return Regex("::").sub("_", std::string(Entry->first)); + } + PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + + "'; expected: bit, bits, string, or code"); +} + +std::string getTableNamespacePrefix(const GenericTable &Table, + std::string TargetName) { + // Sometimes table type are wrapped into namespaces. + // In Capstone we need to prepend the name to those types in this case. + std::set> AArch64NSTypePairs = { + {"AArch64SysReg", "SysReg"}, + {"AArch64PState", "PStateImm0_15"}, + {"AArch64PState", "PStateImm0_1"}, + {"AArch64SVCR", "SVCR"}, + {"AArch64AT", "AT"}, + {"AArch64DB", "DB"}, + {"AArch64DBnXS", "DBnXS"}, + {"AArch64DC", "DC"}, + {"AArch64IC", "IC"}, + {"AArch64ISB", "ISB"}, + {"AArch64TSB", "TSB"}, + {"AArch64PRFM", "PRFM"}, + {"AArch64SVEPRFM", "SVEPRFM"}, + {"AArch64RPRFM", "RPRFM"}, + {"AArch64SVCR", "SVCR"}, + {"AArch64SVEPredPattern", "SVEPREDPAT"}, + {"AArch64SVEVecLenSpecifier", "SVEVECLENSPECIFIER"}, + {"AArch64ExactFPImm", "ExactFPImm"}, + {"AArch64BTIHint", "BTI"}, + {"AArch64TLBI", "TLBI"}, + {"AArch64PRCTX", "PRCTX"}, + {"AArch64BTIHint", "BTI"}, + {"AArch64PSBHint", "PSB"}, + }; + + std::set> ARMNSTypePairs = { + {"ARMSysReg", "MClassSysReg"}, + {"ARMBankedReg", "BankedReg"}, + }; + + std::set> *NSTable; + + if (TargetName != "AArch64" && TargetName != "ARM") + return Table.CppTypeName + "_"; + + if (TargetName == "AArch64") + NSTable = &AArch64NSTypePairs; + else if (TargetName == "ARM") + NSTable = &ARMNSTypePairs; + else + PrintFatalNote("No Namespace Type table defined for target."); + + for (auto NSTPair : *NSTable) { + if (NSTPair.second == Table.CppTypeName) + return NSTPair.first + "_"; + } + PrintNote("No namespace defined for type: " + Table.CppTypeName); + return ""; +} + +void PrinterCapstone::searchableTablesEmitLookupDeclaration( + const GenericTable &Table, const SearchIndex &Index, StreamType ST) { + raw_string_ostream &OutS = (ST == ST_DECL_OS) + ? searchableTablesGetOS(ST_DECL_OS) + : searchableTablesGetOS(ST_IMPL_OS); + std::string NamespacePre = getTableNamespacePrefix(Table, TargetName); + OutS << "const " << NamespacePre << Table.CppTypeName << " *" << NamespacePre + << Index.Name << "("; + + ListSeparator LS; + for (const auto &Field : Index.Fields) + OutS << LS + << searchableTablesSearchableFieldType(Table, Index, Field, + TypeInArgument) + << " " << Field.Name; + OutS << ")"; + if (ST == ST_DECL_OS) { + OutS << ";\n"; + } else if (ST == ST_IMPL_OS) + OutS << " {\n"; +} + +void PrinterCapstone::searchableTablesEmitIndexTypeStruct( + const GenericTable &Table, const SearchIndex &Index) { + for (const auto &Field : Index.Fields) { + if (isa(Field.RecType)) { + EmittingNameLookup = isa(Field.RecType); + } + } +} + +void PrinterCapstone::searchableTablesEmitIndexArrayI() const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + if (EmittingNameLookup) + OutS << " static const struct IndexTypeStr Index[] = {\n"; + else + OutS << " static const struct IndexType Index[] = {\n"; +} + +void PrinterCapstone::searchableTablesEmitIndexArrayII() const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << " { "; +} + +void PrinterCapstone::searchableTablesEmitIndexArrayIII( + ListSeparator &LS, std::string Repr) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << LS << Repr; +} + +void PrinterCapstone::searchableTablesEmitIndexArrayIV( + std::pair const &Entry) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << ", " << Entry.second << " },\n"; +} + +void PrinterCapstone::searchableTablesEmitIndexArrayV() const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << " };\n\n"; +} + +void PrinterCapstone::searchableTablesEmitIsContiguousCase( + StringRef const &IndexName, const GenericTable &Table, + const SearchIndex &Index, bool IsPrimary) { + searchableTablesEmitReturns(Table, Index, IsPrimary); +} + +void PrinterCapstone::searchableTablesEmitIfFieldCase( + const GenericField &Field, std::string const &FirstRepr, + std::string const &LastRepr) const {} + +void PrinterCapstone::searchableTablesEmitKeyTypeStruct( + const GenericTable &Table, const SearchIndex &Index) const {} + +void PrinterCapstone::searchableTablesEmitKeyArray(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) const {} + +void PrinterCapstone::searchableTablesEmitIndexLamda( + const SearchIndex &Index, StringRef const &IndexName, + StringRef const &IndexTypeName) const {} + +void PrinterCapstone::searchableTablesEmitReturns(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + if (EmittingNameLookup) { + OutS << " unsigned i = binsearch_IndexTypeStrEncoding(Index, " + "ARR_SIZE(Index), "; + EmittingNameLookup = false; + } else + OutS << " unsigned i = binsearch_IndexTypeEncoding(Index, " + "ARR_SIZE(Index), "; + for (const auto &Field : Index.Fields) + OutS << Field.Name; + OutS << ");\n" + << " if (i == -1)\n" + << " return NULL;\n" + << " else\n" + << " return &" << Table.Name << "[Index[i].index];\n"; + OutS << "}\n\n"; +} + +void PrinterCapstone::searchableTablesEmitMapI( + const GenericTable &Table) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << "static const " << getTableNamespacePrefix(Table, TargetName) + << Table.CppTypeName << " " << Table.Name << "[] = {\n"; + + raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); + EnumOS << "#ifdef GET_ENUM_VALUES_" << Table.CppTypeName << "\n"; + EnumOS << "#undef GET_ENUM_VALUES_" << Table.CppTypeName << "\n"; +} + +void PrinterCapstone::searchableTablesEmitMapII() const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << " { "; +} + +uint64_t BitsInitToUInt(const BitsInit *BI) { + uint64_t Value = 0; + for (unsigned I = 0, Ie = BI->getNumBits(); I != Ie; ++I) { + if (BitInit *B = dyn_cast(BI->getBit(I))) + Value |= (uint64_t)B->getValue() << I; + } + return Value; +} + +unsigned getEnumValue(Record *Entry) { + if (!Entry->getValue("EnumValueField") || + Entry->isValueUnset("EnumValueField")) { + // Guess field which has the encoding. + if (Entry->getValue("Encoding")) { + BitsInit *BI = Entry->getValueAsBitsInit("Encoding"); + return BitsInitToUInt(BI); + } + Entry->dump(); + PrintFatalNote("Which of those fields above are the encoding/enum value?"); + } + StringRef EnumValField = Entry->getValueAsString("EnumValueField"); + return BitsInitToUInt(Entry->getValueAsBitsInit(EnumValField)); +} + +void PrinterCapstone::searchableTablesEmitMapIII(const GenericTable &Table, + ListSeparator &LS, + GenericField const &Field, + StringRef &IntrinsicEnum, + Record *Entry) const { + static std::set EnumNamesSeen; + unsigned EnumVal = getEnumValue(Entry); + + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << LS; + std::string EnumName; + std::string Repr = searchableTablesPrimaryRepresentation( + Table.Locs[0], Field, Entry->getValueInit(Field.Name), IntrinsicEnum); + + // Emit table field + if (Field.Name == "Name" || Field.Name == "AltName") { + // Prepend the enum id to the name field + std::string OpName = Repr; + while (OpName.find("\"") != std::string::npos) + OpName = Regex("\"").sub("", OpName); + EnumName = TargetName + "_" + StringRef(Table.CppTypeName).upper() + "_" + + StringRef(OpName).upper(); + Repr = "\"" + OpName + "\", { .raw_val = " + EnumName + " }"; + OutS << Repr; + + // Emit enum name + if (EnumNamesSeen.find(EnumName) != EnumNamesSeen.end()) + return; + EnumNamesSeen.emplace(EnumName); + + raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); + EnumOS << "\t" + EnumName + " = " << format("0x%x", EnumVal) << ",\n"; + } else { + OutS << Regex("{ *}").sub("{0}", Repr); + } +} + +void PrinterCapstone::searchableTablesEmitMapIV(unsigned i) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << " }, // " << i << "\n"; +} + +void PrinterCapstone::searchableTablesEmitMapV() { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + OutS << " };\n\n"; + + raw_string_ostream &EnumOS = searchableTablesGetOS(ST_ENUM_SYSOPS_OS); + EnumOS << "#endif\n\n"; +} + +} // end namespace llvm diff --git a/llvm/utils/TableGen/PrinterLLVM.cpp b/llvm/utils/TableGen/PrinterLLVM.cpp new file mode 100644 index 000000000000..c8f84aea3ccf --- /dev/null +++ b/llvm/utils/TableGen/PrinterLLVM.cpp @@ -0,0 +1,6429 @@ +//===------------ PrinterLLVM.cpp - LLVM C++ code printer -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implementation of the LLVM C++ printer. +// +//===----------------------------------------------------------------------===// + +#include "AsmWriterInst.h" +#include "CodeGenInstruction.h" +#include "CodeGenSchedule.h" +#include "Printer.h" +#include "PrinterTypes.h" +#include "SubtargetEmitterTypes.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/TableGen/TableGenBackend.h" + +namespace llvm { + +cl::OptionCategory PrinterLang("Select output language of backends"); + +static cl::opt + PrinterLangOpt("printerLang", cl::init("C++"), + cl::desc("Output language options: \"C++\" (default), " + "\"CCS\" (C Capstone style)"), + cl::cat(PrinterLang)); + +// Print a BitVector as a sequence of hex numbers using a little-endian mapping. +// Width is the number of bits per hex number. +void printBitVectorAsHex(raw_ostream &OS, const BitVector &Bits, + unsigned Width) { + assert(Width <= 32 && "Width too large"); + unsigned Digits = (Width + 3) / 4; + for (unsigned i = 0, e = Bits.size(); i < e; i += Width) { + unsigned Value = 0; + for (unsigned j = 0; j != Width && i + j != e; ++j) + Value |= Bits.test(i + j) << j; + OS << format("0x%0*x, ", Digits, Value); + } +} + +void PrinterBitVectorEmitter::add(unsigned v) { + if (v >= Values.size()) + Values.resize(((v/8)+1)*8); // Round up to the next byte. + Values[v] = true; +} + +void PrinterBitVectorEmitter::print(raw_ostream &OS) { + printBitVectorAsHex(OS, Values, 8); +} + +// +// General PrinterLLVM methods +// + +PrinterLLVM::PrinterLLVM(formatted_raw_ostream &OS) : OS(OS) {} +PrinterLLVM::PrinterLLVM(formatted_raw_ostream &OS, std::string TargetName) + : OS(OS), TargetName(TargetName) {} +PrinterLLVM::PrinterLLVM(formatted_raw_ostream &OS, + std::string PredicateNamespace, std::string GPrefix, + std::string GPostfix, std::string ROK, + std::string RFail, std::string L, std::string Target) + : OS(OS), TargetName(std::move(Target)), + PredicateNamespace(std::move(PredicateNamespace)), + GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)), + ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)), + Locals(std::move(L)) {} +PrinterLLVM::~PrinterLLVM() {} + +PrinterLanguage PrinterLLVM::getLanguage() { + if (PrinterLangOpt == "C++") + return PRINTER_LANG_CPP; + if (PrinterLangOpt == "CCS") + return PRINTER_LANG_CAPSTONE_C; + + PrintFatalNote("Unkown output language for printer selected."); +} + +/// Prints `namespace {` and `} // end namespace ` to the output +/// stream. If Name == "" it emits an anonymous namespace. +void PrinterLLVM::emitNamespace(std::string const &Name, bool Begin, + std::string const &Comment, + bool Newline) const { + if (Begin) { + OS << "namespace " << Name; + std::string const Bracket = (Name == "" ? "{" : " {"); + if (Comment != "") + OS << Bracket << " // " << Comment << "\n"; + else + OS << Bracket << (Newline ? "\n\n" : "\n"); + return; + } + + if (Name == "") { + OS << "} // end anonymous namespace" << (Newline ? "\n\n" : "\n"); + } else { + OS << "} // end namespace " << Name << (Newline ? "\n\n" : "\n"); + } +} + +/// Prints +/// ``` +/// #if +/// ``` +/// and +/// `#endif // ` +/// Used to control inclusion of a code block via a macro definition. +void PrinterLLVM::emitPPIf(std::string const &Arg, bool Begin, + bool Newline) const { + if (Begin) { + OS << "#if " << Arg << "\n"; + } else { + OS << "#endif // " << Arg << (Newline ? "\n\n" : "\n"); + } +} + +/// Prints +/// ``` +/// #ifdef +/// #undef +/// ``` +/// and +/// `#endif // ` +/// Used to control inclusion of a code block via a macro definition. +void PrinterLLVM::emitIncludeToggle(std::string const &Name, bool Begin, + bool Newline, bool UndefAtEnd) const { + if (Begin) { + OS << "#ifdef " << Name << "\n"; + if (!UndefAtEnd) + OS << "#undef " << Name << "\n\n"; + } else { + if (UndefAtEnd) + OS << "#undef " << Name << "\n"; + OS << "#endif // " << Name << (Newline ? "\n\n" : "\n"); + } +} + +void PrinterLLVM::regInfoEmitSourceFileHeader(std::string const &Desc) const { + emitSourceFileHeader(Desc, OS); +} + +// runEnums - Print out enum values for all of the registers. +void PrinterLLVM::regInfoEmitEnums(CodeGenTarget const &Target, + CodeGenRegBank const &Bank) const { + const auto &Registers = Bank.getRegisters(); + + // Register enums are stored as uint16_t in the tables. Make sure we'll fit. + assert(Registers.size() <= 0xffff && "Too many regs to fit in tables"); + + StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace"); + + emitSourceFileHeader("Target Register Enum Values", OS); + + OS << "\n#ifdef GET_REGINFO_ENUM\n"; + OS << "#undef GET_REGINFO_ENUM\n\n"; + + OS << "namespace llvm {\n\n"; + + OS << "class MCRegisterClass;\n" + << "extern const MCRegisterClass " << Target.getName() + << "MCRegisterClasses[];\n\n"; + + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum {\n NoRegister,\n"; + + for (const auto &Reg : Registers) + OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n"; + assert(Registers.size() == Registers.back().EnumValue && + "Register enum value mismatch!"); + OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n"; + OS << "};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << "\n"; + + const auto &RegisterClasses = Bank.getRegClasses(); + if (!RegisterClasses.empty()) { + + // RegisterClass enums are stored as uint16_t in the tables. + assert(RegisterClasses.size() <= 0xffff && + "Too many register classes to fit in tables"); + + OS << "\n// Register classes\n\n"; + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum {\n"; + for (const auto &RC : RegisterClasses) + OS << " " << RC.getIdName() << " = " << RC.EnumValue << ",\n"; + OS << "\n};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << "\n\n"; + } + + const std::vector &RegAltNameIndices = Target.getRegAltNameIndices(); + // If the only definition is the default NoRegAltName, we don't need to + // emit anything. + if (RegAltNameIndices.size() > 1) { + OS << "\n// Register alternate name indices\n\n"; + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum {\n"; + for (unsigned i = 0, e = RegAltNameIndices.size(); i != e; ++i) + OS << " " << RegAltNameIndices[i]->getName() << ",\t// " << i << "\n"; + OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; + OS << "};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << "\n\n"; + } + + auto &SubRegIndices = Bank.getSubRegIndices(); + if (!SubRegIndices.empty()) { + OS << "\n// Subregister indices\n\n"; + std::string Namespace = SubRegIndices.front().getNamespace(); + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum : uint16_t {\n NoSubRegister,\n"; + unsigned i = 0; + for (const auto &Idx : SubRegIndices) + OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; + OS << " NUM_TARGET_SUBREGS\n};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << "\n\n"; + } + + OS << "// Register pressure sets enum.\n"; + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum RegisterPressureSets {\n"; + unsigned NumSets = Bank.getNumRegPressureSets(); + for (unsigned i = 0; i < NumSets; ++i ) { + const RegUnitSet &RegUnits = Bank.getRegSetAt(i); + OS << " " << RegUnits.Name << " = " << i << ",\n"; + } + OS << "};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << '\n'; + OS << '\n'; + + OS << "} // end namespace llvm\n\n"; + OS << "#endif // GET_REGINFO_ENUM\n\n"; +} + +static void printDiff16(raw_ostream &OS, int16_t Val) { OS << Val; } + +void PrinterLLVM::regInfoEmitRegDiffLists( + std::string const TargetName, + SequenceToOffsetTable const &DiffSeqs) const { + OS << "extern const int16_t " << TargetName << "RegDiffLists[] = {\n"; + DiffSeqs.emit(OS, printDiff16); + OS << "};\n\n"; +} + +static void printMask(raw_ostream &OS, LaneBitmask Val) { + OS << "LaneBitmask(0x" << PrintLaneMask(Val) << ')'; +} + +void PrinterLLVM::regInfoEmitLaneMaskLists( + std::string const TargetName, + SequenceToOffsetTable const &LaneMaskSeqs) const { + // Emit the shared table of regunit lane mask sequences. + OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[] = {\n"; + // TODO: Omit the terminator since it is never used. The length of this list + // is known implicitly from the corresponding reg unit list. + LaneMaskSeqs.emit(OS, printMask, "LaneBitmask::getAll()"); + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitSubRegIdxLists( + std::string const TargetName, + SequenceToOffsetTable>> const + &SubRegIdxSeqs) const { + OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[] = {\n"; + SubRegIdxSeqs.emit(OS, [](raw_ostream &OS, const CodeGenSubRegIndex *Idx) { + OS << Idx->EnumValue; + }); + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitSubRegIdxSizes( + std::string const TargetName, + std::deque const &SubRegIndices) const { + OS << "extern const MCRegisterInfo::SubRegCoveredBits " << TargetName + << "SubRegIdxRanges[] = {\n"; + OS << " { " << (uint16_t)-1 << ", " << (uint16_t)-1 << " },\n"; + for (const auto &Idx : SubRegIndices) { + OS << " { " << Idx.Offset << ", " << Idx.Size << " },\t// " + << Idx.getName() << "\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitSubRegStrTable( + std::string const TargetName, + SequenceToOffsetTable const &RegStrings) const { + RegStrings.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + + "RegStrings[]"); + + OS << "extern const MCRegisterDesc " << TargetName + << "RegDesc[] = { // Descriptors\n"; + OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n"; +} + +void PrinterLLVM::regInfoEmitRegDesc( + SequenceToOffsetTable const &LaneMaskSeqs, + std::deque const &Regs, + SequenceToOffsetTable>> const + &SubRegIdxSeqs, + SequenceToOffsetTable const &DiffSeqs, + SmallVector const &SubRegIdxLists, + SmallVector const &SubRegLists, + SmallVector const &SuperRegLists, + SmallVector const &RegUnitLists, + SmallVector const &RegUnitLaneMasks, + SequenceToOffsetTable const &RegStrings) const { + unsigned i = 0; + for (const auto &Reg : Regs) { + unsigned FirstRU = Reg.getNativeRegUnits().find_first(); + unsigned Offset = DiffSeqs.get(RegUnitLists[i]); + // The value must be kept in sync with MCRegisterInfo.h. + constexpr unsigned RegUnitBits = 12; + assert(isUInt(FirstRU) && "Too many regunits"); + assert(isUInt<32 - RegUnitBits>(Offset) && "Offset is too big"); + OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " + << DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) + << ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " + << (Offset << RegUnitBits | FirstRU) << ", " + << LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n"; + ++i; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitRegUnitRoots(std::string const TargetName, + CodeGenRegBank const &RegBank) const { + OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2] = {\n"; + for (unsigned I = 0, E = RegBank.getNumNativeRegUnits(); I != E; ++I) { + ArrayRef const Roots = + RegBank.getRegUnit(I).getRoots(); + assert(!Roots.empty() && "All regunits must have a root register."); + assert(Roots.size() <= 2 && "More than two roots not supported yet."); + OS << " { "; + ListSeparator LS; + for (const CodeGenRegister *R : Roots) + OS << LS << getQualifiedName(R->TheDef); + OS << " },\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitRegClasses( + std::list const &RegClasses, + SequenceToOffsetTable &RegClassStrings, + CodeGenTarget const &Target) const { + for (const auto &RC : RegClasses) { + ArrayRef const Order = RC.getOrder(); + + // Give the register class a legal C name if it's anonymous. + const std::string &Name = RC.getName(); + + RegClassStrings.add(Name); + + // Emit the register list now (unless it would be a zero-length array). + if (!Order.empty()) { + OS << " // " << Name << " Register Class...\n" + << " const MCPhysReg " << Name << "[] = {\n "; + for (Record *Reg : Order) { + OS << getQualifiedName(Reg) << ", "; + } + OS << "\n };\n\n"; + + OS << " // " << Name << " Bit set.\n" + << " const uint8_t " << Name << "Bits[] = {\n "; + PrinterBitVectorEmitter BVE; + for (Record *Reg : Order) { + BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); + } + BVE.print(OS); + OS << "\n };\n\n"; + } + } +} + +void PrinterLLVM::regInfoEmitStrLiteralRegClasses( + std::string const TargetName, + SequenceToOffsetTable const &RegClassStrings) const { + RegClassStrings.emitStringLiteralDef( + OS, Twine("extern const char ") + TargetName + "RegClassStrings[]"); +} + +void PrinterLLVM::regInfoEmitMCRegClassesTable( + std::string const TargetName, + std::list const &RegisterClasses, + SequenceToOffsetTable &RegClassStrings) const { + OS << "extern const MCRegisterClass " << TargetName + << "MCRegisterClasses[] = {\n"; + + for (const auto &RC : RegisterClasses) { + ArrayRef Order = RC.getOrder(); + std::string RCName = Order.empty() ? "nullptr" : RC.getName(); + std::string RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits"; + std::string RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; + assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); + uint32_t RegSize = 0; + if (RC.RSI.isSimple()) + RegSize = RC.RSI.getSimple().RegSize; + OS << " { " << RCName << ", " << RCBitsName << ", " + << RegClassStrings.get(RC.getName()) << ", " << RC.getOrder().size() + << ", " << RCBitsSize << ", " << RC.getQualifiedIdName() << ", " + << RegSize << ", " << RC.CopyCost << ", " + << (RC.Allocatable ? "true" : "false") << " },\n"; + } + + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitRegEncodingTable( + std::string const TargetName, + std::deque const &Regs) const { + OS << "extern const uint16_t " << TargetName; + OS << "RegEncodingTable[] = {\n"; + // Add entry for NoRegister + OS << " 0,\n"; + for (const auto &RE : Regs) { + Record *Reg = RE.TheDef; + BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); + uint64_t Value = 0; + for (unsigned I = 0, Ie = BI->getNumBits(); I != Ie; ++I) { + if (BitInit *B = dyn_cast(BI->getBit(I))) + Value |= (uint64_t)B->getValue() << I; + } + OS << " " << Value << ",\n"; + } + OS << "};\n"; // End of HW encoding table +} + +void PrinterLLVM::regInfoEmitMCRegInfoInit( + std::string const TargetName, CodeGenRegBank const &RegBank, + std::deque const &Regs, + std::list const &RegClasses, + std::deque const &SubRegIndices) const { + OS << "static inline void Init" << TargetName + << "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, " + << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0, unsigned PC = 0) " + "{\n" + << " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, " + << Regs.size() + 1 << ", RA, PC, " << TargetName << "MCRegisterClasses, " + << RegClasses.size() << ", " << TargetName << "RegUnitRoots, " + << RegBank.getNumNativeRegUnits() << ", " << TargetName << "RegDiffLists, " + << TargetName << "LaneMaskLists, " << TargetName << "RegStrings, " + << TargetName << "RegClassStrings, " << TargetName << "SubRegIdxLists, " + << (std::distance(SubRegIndices.begin(), SubRegIndices.end()) + 1) << ",\n" + << TargetName << "SubRegIdxRanges, " << TargetName + << "RegEncodingTable);\n\n"; +} + +void PrinterLLVM::regInfoEmitInfoDwarfRegsRev(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, + bool IsCtor) const { + OS << "// " << Namespace << " Dwarf<->LLVM register mappings.\n"; + + // Emit reverse information about the dwarf register numbers. + for (unsigned j = 0; j < 2; ++j) { + for (unsigned I = 0, E = MaxLength; I != E; ++I) { + OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; + OS << (j == 0 ? "DwarfFlavour" : "EHFlavour"); + OS << I << "Dwarf2L[]"; + + if (!IsCtor) { + OS << " = {\n"; + + // Store the mapping sorted by the LLVM reg num so lookup can be done + // with a binary search. + std::map Dwarf2LMap; + for (auto &DwarfRegNum : DwarfRegNums) { + int DwarfRegNo = DwarfRegNum.second[I]; + if (DwarfRegNo < 0) + continue; + Dwarf2LMap[DwarfRegNo] = DwarfRegNum.first; + } + + for (auto &I : Dwarf2LMap) + OS << " { " << I.first << "U, " << getQualifiedName(I.second) + << " },\n"; + + OS << "};\n"; + } else { + OS << ";\n"; + } + + // We have to store the size in a const global, it's used in multiple + // places. + OS << "extern const unsigned " << Namespace + << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2LSize"; + if (!IsCtor) + OS << " = std::size(" << Namespace + << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2L);\n\n"; + else + OS << ";\n\n"; + } + } +} + +void PrinterLLVM::regInfoEmitInfoDwarfRegs(StringRef const &Namespace, + DwarfRegNumsVecTy &DwarfRegNums, + unsigned MaxLength, + bool IsCtor) const { + for (unsigned J = 0; J < 2; ++J) { + for (unsigned I = 0, E = MaxLength; I != E; ++I) { + OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; + OS << (J == 0 ? "DwarfFlavour" : "EHFlavour"); + OS << I << "L2Dwarf[]"; + if (!IsCtor) { + OS << " = {\n"; + // Store the mapping sorted by the Dwarf reg num so lookup can be done + // with a binary search. + for (auto &DwarfRegNum : DwarfRegNums) { + int RegNo = DwarfRegNum.second[I]; + if (RegNo == -1) // -1 is the default value, don't emit a mapping. + continue; + + OS << " { " << getQualifiedName(DwarfRegNum.first) << ", " << RegNo + << "U },\n"; + } + OS << "};\n"; + } else { + OS << ";\n"; + } + + // We have to store the size in a const global, it's used in multiple + // places. + OS << "extern const unsigned " << Namespace + << (J == 0 ? "DwarfFlavour" : "EHFlavour") << I << "L2DwarfSize"; + if (!IsCtor) + OS << " = std::size(" << Namespace + << (J == 0 ? "DwarfFlavour" : "EHFlavour") << I << "L2Dwarf);\n\n"; + else + OS << ";\n\n"; + } + } +} + +void PrinterLLVM::regInfoEmitInfoRegMapping(StringRef const &Namespace, + unsigned MaxLength, + bool IsCtor) const { + if (MaxLength == 0) { + OS << "}\n\n"; + return; + } + + // Emit reverse information about the dwarf register numbers. + for (unsigned J = 0; J < 2; ++J) { + OS << " switch ("; + if (J == 0) + OS << "DwarfFlavour"; + else + OS << "EHFlavour"; + OS << ") {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown DWARF flavour\");\n"; + + for (unsigned I = 0, E = MaxLength; I != E; ++I) { + OS << " case " << I << ":\n"; + OS << " "; + if (!IsCtor) + OS << "RI->"; + std::string Tmp; + raw_string_ostream(Tmp) + << Namespace << (J == 0 ? "DwarfFlavour" : "EHFlavour") << I + << "Dwarf2L"; + OS << "mapDwarfRegsToLLVMRegs(" << Tmp << ", " << Tmp << "Size, "; + if (J == 0) + OS << "false"; + else + OS << "true"; + OS << ");\n"; + OS << " break;\n"; + } + OS << " }\n"; + } + + // Emit information about the dwarf register numbers. + for (unsigned J = 0; J < 2; ++J) { + OS << " switch ("; + if (J == 0) + OS << "DwarfFlavour"; + else + OS << "EHFlavour"; + OS << ") {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown DWARF flavour\");\n"; + + for (unsigned I = 0, E = MaxLength; I != E; ++I) { + OS << " case " << I << ":\n"; + OS << " "; + if (!IsCtor) + OS << "RI->"; + std::string Tmp; + raw_string_ostream(Tmp) + << Namespace << (J == 0 ? "DwarfFlavour" : "EHFlavour") << I + << "L2Dwarf"; + OS << "mapLLVMRegsToDwarfRegs(" << Tmp << ", " << Tmp << "Size, "; + if (J == 0) + OS << "false"; + else + OS << "true"; + OS << ");\n"; + OS << " break;\n"; + } + OS << " }\n"; + } + + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitHeaderIncludes() const { + OS << "#include \"llvm/CodeGen/TargetRegisterInfo.h\"\n\n"; +} + +void PrinterLLVM::regInfoEmitHeaderExternRegClasses( + std::list const &RegClasses) const { + for (const auto &RC : RegClasses) { + const std::string &Name = RC.getName(); + + // Output the extern for the instance. + OS << " extern const TargetRegisterClass " << Name << "RegClass;\n"; + } +} + +void PrinterLLVM::regInfoEmitHeaderDecl(std::string const &TargetName, + std::string const &ClassName, + bool SubRegsPresent, + bool DeclareGetPhysRegBaseClass) const { + OS << "class " << TargetName << "FrameLowering;\n\n"; + + OS << "struct " << ClassName << " : public TargetRegisterInfo {\n" + << " explicit " << ClassName + << "(unsigned RA, unsigned D = 0, unsigned E = 0,\n" + << " unsigned PC = 0, unsigned HwMode = 0);\n"; + if (SubRegsPresent) { + OS << " unsigned composeSubRegIndicesImpl" + << "(unsigned, unsigned) const override;\n" + << " LaneBitmask composeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" + << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" + << " const TargetRegisterClass *getSubClassWithSubReg" + << "(const TargetRegisterClass *, unsigned) const override;\n" + << " const TargetRegisterClass *getSubRegisterClass" + << "(const TargetRegisterClass *, unsigned) const override;\n"; + } + OS << " const RegClassWeight &getRegClassWeight(" + << "const TargetRegisterClass *RC) const override;\n" + << " unsigned getRegUnitWeight(unsigned RegUnit) const override;\n" + << " unsigned getNumRegPressureSets() const override;\n" + << " const char *getRegPressureSetName(unsigned Idx) const override;\n" + << " unsigned getRegPressureSetLimit(const MachineFunction &MF, unsigned " + "Idx) const override;\n" + << " const int *getRegClassPressureSets(" + << "const TargetRegisterClass *RC) const override;\n" + << " const int *getRegUnitPressureSets(" + << "unsigned RegUnit) const override;\n" + << " ArrayRef getRegMaskNames() const override;\n" + << " ArrayRef getRegMasks() const override;\n" + << " bool isGeneralPurposeRegister(const MachineFunction &, " + << "MCRegister) const override;\n" + << " bool isFixedRegister(const MachineFunction &, " + << "MCRegister) const override;\n" + << " bool isArgumentRegister(const MachineFunction &, " + << "MCRegister) const override;\n" + << " bool isConstantPhysReg(MCRegister PhysReg) const override final;\n" + << " /// Devirtualized TargetFrameLowering.\n" + << " static const " << TargetName << "FrameLowering *getFrameLowering(\n" + << " const MachineFunction &MF);\n"; + if (DeclareGetPhysRegBaseClass) { + OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) " + "const override;\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitExternRegClassesArr( + std::string const &TargetName) const { + OS << "extern const MCRegisterClass " << TargetName + << "MCRegisterClasses[];\n"; +} + +static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) { + OS << getEnumName(VT); +} + +void PrinterLLVM::regInfoEmitVTSeqs( + SequenceToOffsetTable> const &VTSeqs) + const { + OS << "\nstatic const MVT::SimpleValueType VTLists[] = {\n"; + VTSeqs.emit(OS, printSimpleValueType, "MVT::Other"); + OS << "};\n"; +} + +void PrinterLLVM::regInfoEmitSubRegIdxTable( + std::deque const &SubRegIndices) const { + OS << "\nstatic const char *SubRegIndexNameTable[] = { \""; + + for (const auto &Idx : SubRegIndices) { + OS << Idx.getName(); + OS << "\", \""; + } + OS << "\" };\n\n"; + + // Emit SubRegIndex lane masks, including 0. + OS << "\nstatic const LaneBitmask SubRegIndexLaneMaskTable[] = {\n " + "LaneBitmask::getAll(),\n"; + for (const auto &Idx : SubRegIndices) { + printMask(OS << " ", Idx.LaneMask); + OS << ", // " << Idx.getName() << '\n'; + } + OS << " };\n\n"; + + OS << "\n"; +} + +void PrinterLLVM::regInfoEmitRegClassInfoTable( + std::list const &RegisterClasses, + SequenceToOffsetTable> const &VTSeqs, + CodeGenHwModes const &CGH, unsigned NumModes) const { + OS << "\nstatic const TargetRegisterInfo::RegClassInfo RegClassInfos[]" + << " = {\n"; + for (unsigned M = 0; M < NumModes; ++M) { + unsigned EV = 0; + OS << " // Mode = " << M << " ("; + if (M == 0) + OS << "Default"; + else + OS << CGH.getMode(M).Name; + OS << ")\n"; + for (const auto &RC : RegisterClasses) { + assert(RC.EnumValue == EV && "Unexpected order of register classes"); + ++EV; + (void)EV; + const RegSizeInfo &RI = RC.RSI.get(M); + OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", " + << RI.SpillAlignment; + std::vector VTs; + for (const ValueTypeByHwMode &VVT : RC.VTs) + if (VVT.hasDefault() || VVT.hasMode(M)) + VTs.push_back(VVT.get(M).SimpleTy); + OS << ", /*VTLists+*/" << VTSeqs.get(VTs) << " }, // " + << RC.getName() << '\n'; + } + } + OS << "};\n"; + + + OS << "\nstatic const TargetRegisterClass *const " + << "NullRegClasses[] = { nullptr };\n\n"; +} + +void PrinterLLVM::regInfoEmitSubClassMaskTable( + std::list const &RegClasses, + SmallVector &SuperRegIdxLists, + SequenceToOffsetTable>> &SuperRegIdxSeqs, + std::deque const &SubRegIndices, + BitVector &MaskBV) const { + for (const auto &RC : RegClasses) { + OS << "static const uint32_t " << RC.getName() << "SubClassMask[] = {\n "; + printBitVectorAsHex(OS, RC.getSubClasses(), 32); + + // Emit super-reg class masks for any relevant SubRegIndices that can + // project into RC. + IdxList &SRIList = SuperRegIdxLists[RC.EnumValue]; + for (auto &Idx : SubRegIndices) { + MaskBV.reset(); + RC.getSuperRegClasses(&Idx, MaskBV); + if (MaskBV.none()) + continue; + SRIList.push_back(&Idx); + OS << "\n "; + printBitVectorAsHex(OS, MaskBV, 32); + OS << "// " << Idx.getName(); + } + SuperRegIdxSeqs.add(SRIList); + OS << "\n};\n\n"; + } +} + +static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) { + OS << Idx->EnumValue; +} + +void PrinterLLVM::regInfoEmitSuperRegIdxSeqsTable( + SequenceToOffsetTable>> const &SuperRegIdxSeqs) + const { + OS << "static const uint16_t SuperRegIdxSeqs[] = {\n"; + SuperRegIdxSeqs.emit(OS, printSubRegIndex); + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitSuperClassesTable( + std::list const &RegClasses) const { + for (const auto &RC : RegClasses) { + ArrayRef const Supers = RC.getSuperClasses(); + + // Skip classes without supers. We can reuse NullRegClasses. + if (Supers.empty()) + continue; + + OS << "static const TargetRegisterClass *const " << RC.getName() + << "Superclasses[] = {\n"; + for (const auto *Super : Supers) + OS << " &" << Super->getQualifiedName() << "RegClass,\n"; + OS << " nullptr\n};\n\n"; + } +} + +void PrinterLLVM::regInfoEmitRegClassMethods( + std::list const &RegClasses, + std::string const &TargetName) const { + for (const auto &RC : RegClasses) { + if (!RC.AltOrderSelect.empty()) { + OS << "\nstatic inline unsigned " << RC.getName() + << "AltOrderSelect(const MachineFunction &MF) {" + << RC.AltOrderSelect << "}\n\n" + << "static ArrayRef " << RC.getName() + << "GetRawAllocationOrder(const MachineFunction &MF) {\n"; + for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) { + ArrayRef Elems = RC.getOrder(oi); + if (!Elems.empty()) { + OS << " static const MCPhysReg AltOrder" << oi << "[] = {"; + for (unsigned elem = 0; elem != Elems.size(); ++elem) + OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]); + OS << " };\n"; + } + } + OS << " const MCRegisterClass &MCR = " << TargetName + << "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n" + << " const ArrayRef Order[] = {\n" + << " ArrayRef(MCR.begin(), MCR.getNumRegs()"; + for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) + if (RC.getOrder(oi).empty()) + OS << "),\n ArrayRef("; + else + OS << "),\n ArrayRef(AltOrder" << oi; + OS << ")\n };\n const unsigned Select = " << RC.getName() + << "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders() + << ");\n return Order[Select];\n}\n"; + } + } +} + +void PrinterLLVM::regInfomitRegClassInstances( + std::list const &RegClasses, + SequenceToOffsetTable>> const &SuperRegIdxSeqs, + SmallVector const &SuperRegIdxLists, + std::string const &TargetName) const { + for (const auto &RC : RegClasses) { + OS << " extern const TargetRegisterClass " << RC.getName() + << "RegClass = {\n " << '&' << TargetName << "MCRegisterClasses[" + << RC.getName() << "RegClassID],\n " << RC.getName() + << "SubClassMask,\n SuperRegIdxSeqs + " + << SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n "; + printMask(OS, RC.LaneMask); + OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n " + << (RC.GlobalPriority ? "true" : "false") << ",\n " + << format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n " + << (RC.HasDisjunctSubRegs ? "true" : "false") + << ", /* HasDisjunctSubRegs */\n " + << (RC.CoveredBySubRegs ? "true" : "false") + << ", /* CoveredBySubRegs */\n "; + if (RC.getSuperClasses().empty()) + OS << "NullRegClasses,\n "; + else + OS << RC.getName() << "Superclasses,\n "; + if (RC.AltOrderSelect.empty()) + OS << "nullptr\n"; + else + OS << RC.getName() << "GetRawAllocationOrder\n"; + OS << " };\n\n"; + } +} + +void PrinterLLVM::regInfoEmitRegClassTable( + std::list const &RegClasses) const { + OS << " const TargetRegisterClass *const RegisterClasses[] = {\n"; + for (const auto &RC : RegClasses) + OS << " &" << RC.getQualifiedName() << "RegClass,\n"; + OS << " };\n"; +} + +void PrinterLLVM::regInfoEmitCostPerUseTable( + std::vector const &AllRegCostPerUse, unsigned NumRegCosts) const { + OS << "\nstatic const uint8_t " + << "CostPerUseTable[] = { \n"; + for (unsigned int I = 0; I < NumRegCosts; ++I) { + for (unsigned J = I, E = AllRegCostPerUse.size(); J < E; J += NumRegCosts) + OS << AllRegCostPerUse[J] << ", "; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitInAllocatableClassTable( + llvm::BitVector const &InAllocClass) const { + OS << "\nstatic const bool " + << "InAllocatableClassTable[] = { \n"; + for (unsigned I = 0, E = InAllocClass.size(); I < E; ++I) { + OS << (InAllocClass[I] ? "true" : "false") << ", "; + } + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitRegExtraDesc(std::string const &TargetName, + unsigned NumRegCosts) const { + OS << "\nstatic const TargetRegisterInfoDesc " << TargetName + << "RegInfoDesc = { // Extra Descriptors\n"; + OS << "CostPerUseTable, " << NumRegCosts << ", " + << "InAllocatableClassTable"; + OS << "};\n\n"; +} + +void PrinterLLVM::regInfoEmitSubClassSubRegGetter( + std::string const &ClassName, unsigned SubRegIndicesSize, + std::deque const &SubRegIndices, + std::list const &RegClasses, + CodeGenRegBank &RegBank) const { + // Emit getSubClassWithSubReg. + OS << "const TargetRegisterClass *" << ClassName + << "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)" + << " const {\n"; + // Use the smallest type that can hold a regclass ID with room for a + // sentinel. + if (RegClasses.size() <= UINT8_MAX) + OS << " static const uint8_t Table["; + else if (RegClasses.size() <= UINT16_MAX) + OS << " static const uint16_t Table["; + else + PrintFatalError("Too many register classes."); + OS << RegClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; + for (const auto &RC : RegClasses) { + OS << " {\t// " << RC.getName() << "\n"; + for (auto &Idx : SubRegIndices) { + if (CodeGenRegisterClass *SRC = RC.getSubClassWithSubReg(&Idx)) + OS << " " << SRC->EnumValue + 1 << ",\t// " << Idx.getName() + << " -> " << SRC->getName() << "\n"; + else + OS << " 0,\t// " << Idx.getName() << "\n"; + } + OS << " },\n"; + } + OS << " };\n assert(RC && \"Missing regclass\");\n" + << " if (!Idx) return RC;\n --Idx;\n" + << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" + << " unsigned TV = Table[RC->getID()][Idx];\n" + << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; + + // Emit getSubRegisterClass + OS << "const TargetRegisterClass *" << ClassName + << "::getSubRegisterClass(const TargetRegisterClass *RC, unsigned Idx)" + << " const {\n"; + + // Use the smallest type that can hold a regclass ID with room for a + // sentinel. + if (RegClasses.size() <= UINT8_MAX) + OS << " static const uint8_t Table["; + else if (RegClasses.size() <= UINT16_MAX) + OS << " static const uint16_t Table["; + else + PrintFatalError("Too many register classes."); + + OS << RegClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; + + for (const auto &RC : RegClasses) { + OS << " {\t// " << RC.getName() << '\n'; + for (auto &Idx : SubRegIndices) { + std::optional> + MatchingSubClass = RC.getMatchingSubClassWithSubRegs(RegBank, &Idx); + + unsigned EnumValue = 0; + if (MatchingSubClass) { + CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; + EnumValue = SubRegClass->EnumValue + 1; + } + + OS << " " << EnumValue << ",\t// " << RC.getName() << ':' + << Idx.getName(); + + if (MatchingSubClass) { + CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; + OS << " -> " << SubRegClass->getName(); + } + + OS << '\n'; + } + + OS << " },\n"; + } + OS << " };\n assert(RC && \"Missing regclass\");\n" + << " if (!Idx) return RC;\n --Idx;\n" + << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" + << " unsigned TV = Table[RC->getID()][Idx];\n" + << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; +} + +void PrinterLLVM::regInfoEmitRegClassWeight( + CodeGenRegBank const &RegBank, std::string const &ClassName) const { + OS << "/// Get the weight in units of pressure for this register class.\n" + << "const RegClassWeight &" << ClassName << "::\n" + << "getRegClassWeight(const TargetRegisterClass *RC) const {\n" + << " static const RegClassWeight RCWeightTable[] = {\n"; + for (const auto &RC : RegBank.getRegClasses()) { + const CodeGenRegister::Vec &Regs = RC.getMembers(); + OS << " {" << RC.getWeight(RegBank) << ", "; + if (Regs.empty() || RC.Artificial) + OS << '0'; + else { + std::vector RegUnits; + RC.buildRegUnitSet(RegBank, RegUnits); + OS << RegBank.getRegUnitSetWeight(RegUnits); + } + OS << "}, \t// " << RC.getName() << "\n"; + } + OS << " };\n" + << " return RCWeightTable[RC->getID()];\n" + << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitRegUnitWeight(CodeGenRegBank const &RegBank, + std::string const &ClassName, + bool RegUnitsHaveUnitWeight) const { + OS << "/// Get the weight in units of pressure for this register unit.\n" + << "unsigned " << ClassName << "::\n" + << "getRegUnitWeight(unsigned RegUnit) const {\n" + << " assert(RegUnit < " << RegBank.getNumNativeRegUnits() + << " && \"invalid register unit\");\n"; + if (!RegUnitsHaveUnitWeight) { + OS << " static const uint8_t RUWeightTable[] = {\n "; + for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); + UnitIdx < UnitEnd; ++UnitIdx) { + const RegUnit &RU = RegBank.getRegUnit(UnitIdx); + assert(RU.Weight < 256 && "RegUnit too heavy"); + OS << RU.Weight << ", "; + } + OS << "};\n" + << " return RUWeightTable[RegUnit];\n"; + } else { + OS << " // All register units have unit weight.\n" + << " return 1;\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitGetNumRegPressureSets(std::string const &ClassName, + unsigned NumSets) const { + OS << "\n" + << "// Get the number of dimensions of register pressure.\n" + << "unsigned " << ClassName << "::getNumRegPressureSets() const {\n" + << " return " << NumSets << ";\n}\n\n"; +} + +void PrinterLLVM::regInfoEmitGetRegPressureTables(CodeGenRegBank const &RegBank, + std::string const &ClassName, + unsigned NumSets) const { + OS << "// Get the name of this register unit pressure set.\n" + << "const char *" << ClassName << "::\n" + << "getRegPressureSetName(unsigned Idx) const {\n" + << " static const char *PressureNameTable[] = {\n"; + unsigned MaxRegUnitWeight = 0; + for (unsigned I = 0; I < NumSets; ++I) { + const RegUnitSet &RegUnits = RegBank.getRegSetAt(I); + MaxRegUnitWeight = std::max(MaxRegUnitWeight, RegUnits.Weight); + OS << " \"" << RegUnits.Name << "\",\n"; + } + OS << " };\n" + << " return PressureNameTable[Idx];\n" + << "}\n\n"; + + OS << "// Get the register unit pressure limit for this dimension.\n" + << "// This limit must be adjusted dynamically for reserved registers.\n" + << "unsigned " << ClassName << "::\n" + << "getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const " + "{\n" + << " static const " << getMinimalTypeForRange(MaxRegUnitWeight, 32) + << " PressureLimitTable[] = {\n"; + for (unsigned I = 0; I < NumSets; ++I) { + const RegUnitSet &RegUnits = RegBank.getRegSetAt(I); + OS << " " << RegUnits.Weight << ", \t// " << I << ": " << RegUnits.Name + << "\n"; + } + OS << " };\n" + << " return PressureLimitTable[Idx];\n" + << "}\n\n"; +} + +static void printInt(raw_ostream &OS, int Val) { OS << Val; } + +void PrinterLLVM::regInfoEmitRCSetsTable( + std::string const &ClassName, unsigned NumRCs, + SequenceToOffsetTable> const &PSetsSeqs, + std::vector> const &PSets) const { + OS << "/// Table of pressure sets per register class or unit.\n" + << "static const int RCSetsTable[] = {\n"; + PSetsSeqs.emit(OS, printInt, "-1"); + OS << "};\n\n"; + + OS << "/// Get the dimensions of register pressure impacted by this " + << "register class.\n" + << "/// Returns a -1 terminated array of pressure set IDs\n" + << "const int *" << ClassName << "::\n" + << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"; + OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) + << " RCSetStartTable[] = {\n "; + for (unsigned I = 0, E = NumRCs; I != E; ++I) { + OS << PSetsSeqs.get(PSets[I]) << ","; + } + OS << "};\n" + << " return &RCSetsTable[RCSetStartTable[RC->getID()]];\n" + << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitGetRegUnitPressureSets( + SequenceToOffsetTable> const &PSetsSeqs, + CodeGenRegBank const &RegBank, std::string const &ClassName, + std::vector> const &PSets) const { + OS << "/// Get the dimensions of register pressure impacted by this " + << "register unit.\n" + << "/// Returns a -1 terminated array of pressure set IDs\n" + << "const int *" << ClassName << "::\n" + << "getRegUnitPressureSets(unsigned RegUnit) const {\n" + << " assert(RegUnit < " << RegBank.getNumNativeRegUnits() + << " && \"invalid register unit\");\n"; + OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) + << " RUSetStartTable[] = {\n "; + for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); + UnitIdx < UnitEnd; ++UnitIdx) { + OS << PSetsSeqs.get(PSets[RegBank.getRegUnit(UnitIdx).RegClassUnitSetsIdx]) + << ","; + } + OS << "};\n" + << " return &RCSetsTable[RUSetStartTable[RegUnit]];\n" + << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitExternTableDecl( + std::string const &TargetName) const { + OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n"; + OS << "extern const int16_t " << TargetName << "RegDiffLists[];\n"; + OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[];\n"; + OS << "extern const char " << TargetName << "RegStrings[];\n"; + OS << "extern const char " << TargetName << "RegClassStrings[];\n"; + OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2];\n"; + OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n"; + OS << "extern const MCRegisterInfo::SubRegCoveredBits " + << TargetName << "SubRegIdxRanges[];\n"; + OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n"; +} + +void PrinterLLVM::regInfoEmitRegClassInit( + std::string const &TargetName, std::string const &ClassName, + CodeGenRegBank const &RegBank, + std::list const &RegisterClasses, + std::deque const &Regs, unsigned SubRegIndicesSize) const { + OS << ClassName << "::\n" + << ClassName + << "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,\n" + " unsigned PC, unsigned HwMode)\n" + << " : TargetRegisterInfo(&" << TargetName << "RegInfoDesc" + << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() << ",\n" + << " SubRegIndexNameTable, SubRegIndexLaneMaskTable,\n" + << " "; + printMask(OS, RegBank.CoveringLanes); + OS << ", RegClassInfos, VTLists, HwMode) {\n" + << " InitMCRegisterInfo(" << TargetName << "RegDesc, " << Regs.size() + 1 + << ", RA, PC,\n " << TargetName + << "MCRegisterClasses, " << RegisterClasses.size() << ",\n" + << " " << TargetName << "RegUnitRoots,\n" + << " " << RegBank.getNumNativeRegUnits() << ",\n" + << " " << TargetName << "RegDiffLists,\n" + << " " << TargetName << "LaneMaskLists,\n" + << " " << TargetName << "RegStrings,\n" + << " " << TargetName << "RegClassStrings,\n" + << " " << TargetName << "SubRegIdxLists,\n" + << " " << SubRegIndicesSize + 1 << ",\n" + << " " << TargetName << "SubRegIdxRanges,\n" + << " " << TargetName << "RegEncodingTable);\n\n"; +} + +void PrinterLLVM::regInfoEmitSaveListTable( + Record const *CSRSet, SetTheory::RecVec const *Regs) const { + OS << "static const MCPhysReg " << CSRSet->getName() << "_SaveList[] = { "; + for (unsigned R = 0, Re = Regs->size(); R != Re; ++R) + OS << getQualifiedName((*Regs)[R]) << ", "; + OS << "0 };\n"; +} + +void PrinterLLVM::regInfoEmitRegMaskTable(std::string const &CSRSetName, + BitVector &Covered) const { + OS << "static const uint32_t " << CSRSetName << "_RegMask[] = { "; + printBitVectorAsHex(OS, Covered, 32); + OS << "};\n"; +} + +void PrinterLLVM::regInfoEmitGetRegMasks(std::vector const &CSRSets, + std::string const &ClassName) const { + OS << "ArrayRef " << ClassName + << "::getRegMasks() const {\n"; + if (!CSRSets.empty()) { + OS << " static const uint32_t *const Masks[] = {\n"; + for (Record *CSRSet : CSRSets) + OS << " " << CSRSet->getName() << "_RegMask,\n"; + OS << " };\n"; + OS << " return ArrayRef(Masks);\n"; + } else { + OS << " return std::nullopt;\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitGPRCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + OS << "bool " << ClassName << "::\n" + << "isGeneralPurposeRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "GeneralPurposeRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; +} +void PrinterLLVM::regInfoEmitFixedRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + OS << "bool " << ClassName << "::\n" + << "isFixedRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "FixedRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitArgRegCheck( + std::string const &ClassName, + std::list const &RegCategories) const { + OS << "bool " << ClassName << "::\n" + << "isArgumentRegister(const MachineFunction &MF, " + << "MCRegister PhysReg) const {\n" + << " return\n"; + for (const CodeGenRegisterCategory &Category : RegCategories) + if (Category.getName() == "ArgumentRegisters") { + for (const CodeGenRegisterClass *RC : Category.getClasses()) + OS << " " << RC->getQualifiedName() + << "RegClass.contains(PhysReg) ||\n"; + break; + } + OS << " false;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitIsConstantPhysReg( + std::deque const &Regs, + std::string const &ClassName) const { + OS << "bool " << ClassName << "::\n" + << "isConstantPhysReg(MCRegister PhysReg) const {\n" + << " return\n"; + for (const auto &Reg : Regs) + if (Reg.Constant) + OS << " PhysReg == " << getQualifiedName(Reg.TheDef) << " ||\n"; + OS << " false;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitGetRegMaskNames( + std::vector const &CSRSets, std::string const &ClassName) const { + OS << "ArrayRef " << ClassName + << "::getRegMaskNames() const {\n"; + if (!CSRSets.empty()) { + OS << " static const char *Names[] = {\n"; + for (Record *CSRSet : CSRSets) + OS << " " << '"' << CSRSet->getName() << '"' << ",\n"; + OS << " };\n"; + OS << " return ArrayRef(Names);\n"; + } else { + OS << " return std::nullopt;\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitGetFrameLowering( + std::string const &TargetName) const { + OS << "const " << TargetName << "FrameLowering *\n" + << TargetName + << "GenRegisterInfo::getFrameLowering(const MachineFunction &MF) {\n" + << " return static_cast(\n" + << " MF.getSubtarget().getFrameLowering());\n" + << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitComposeSubRegIndicesImplHead( + std::string const &ClName) const { + OS << "unsigned " << ClName + << "::composeSubRegIndicesImpl(unsigned IdxA, unsigned IdxB) const {\n"; +} + +void PrinterLLVM::regInfoEmitComposeSubRegIndicesImplBody( + SmallVector, 4> const &Rows, + unsigned SubRegIndicesSize, SmallVector const &RowMap) const { + if (Rows.size() > 1) { + OS << " static const " << getMinimalTypeForRange(Rows.size(), 32) + << " RowMap[" << SubRegIndicesSize << "] = {\n "; + for (unsigned I = 0, E = SubRegIndicesSize; I != E; ++I) + OS << RowMap[I] << ", "; + OS << "\n };\n"; + } + + // Output the rows. + OS << " static const " << getMinimalTypeForRange(SubRegIndicesSize + 1, 32) + << " Rows[" << Rows.size() << "][" << SubRegIndicesSize << "] = {\n"; + for (unsigned R = 0, Re = Rows.size(); R != Re; ++R) { + OS << " { "; + for (unsigned I = 0, E = SubRegIndicesSize; I != E; ++I) + if (Rows[R][I]) + OS << Rows[R][I]->getQualifiedName() << ", "; + else + OS << "0, "; + OS << "},\n"; + } + OS << " };\n\n"; + + OS << " --IdxA; assert(IdxA < " << SubRegIndicesSize << "); (void) IdxA;\n" + << " --IdxB; assert(IdxB < " << SubRegIndicesSize << ");\n"; + if (Rows.size() > 1) + OS << " return Rows[RowMap[IdxA]][IdxB];\n"; + else + OS << " return Rows[0][IdxB];\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::regInfoEmitLaneMaskComposeSeq( + SmallVector, 4> const &Sequences, + SmallVector const &SubReg2SequenceIndexMap, + std::deque const &SubRegIndices) const { + OS << " struct MaskRolOp {\n" + " LaneBitmask Mask;\n" + " uint8_t RotateLeft;\n" + " };\n" + " static const MaskRolOp LaneMaskComposeSequences[] = {\n"; + unsigned Idx = 0; + for (size_t S = 0, Se = Sequences.size(); S != Se; ++S) { + OS << " "; + const SmallVectorImpl &Sequence = Sequences[S]; + for (size_t P = 0, Pe = Sequence.size(); P != Pe; ++P) { + const MaskRolPair &MRP = Sequence[P]; + printMask(OS << "{ ", MRP.Mask); + OS << format(", %2u }, ", MRP.RotateLeft); + } + OS << "{ LaneBitmask::getNone(), 0 }"; + if (S + 1 != Se) + OS << ", "; + OS << " // Sequence " << Idx << "\n"; + Idx += Sequence.size() + 1; + } + auto *IntType = getMinimalTypeForRange(*std::max_element( + SubReg2SequenceIndexMap.begin(), SubReg2SequenceIndexMap.end())); + OS << " };\n" + " static const " + << IntType << " CompositeSequences[] = {\n"; + for (size_t I = 0, E = SubRegIndices.size(); I != E; ++I) { + OS << " "; + OS << SubReg2SequenceIndexMap[I]; + if (I + 1 != E) + OS << ","; + OS << " // to " << SubRegIndices[I].getName() << "\n"; + } + OS << " };\n\n"; +} + +void PrinterLLVM::regInfoEmitComposeSubRegIdxLaneMask( + std::string const &ClName, + std::deque const &SubRegIndices) const { + OS << "LaneBitmask " << ClName + << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, " + "LaneBitmask LaneMask) const {\n" + " --IdxA; assert(IdxA < " + << SubRegIndices.size() + << " && \"Subregister index out of bounds\");\n" + " LaneBitmask Result;\n" + " for (const MaskRolOp *Ops =\n" + " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" + " Ops->Mask.any(); ++Ops) {\n" + " LaneBitmask::Type M = LaneMask.getAsInteger() & " + "Ops->Mask.getAsInteger();\n" + " if (unsigned S = Ops->RotateLeft)\n" + " Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - " + "S)));\n" + " else\n" + " Result |= LaneBitmask(M);\n" + " }\n" + " return Result;\n" + "}\n\n"; +} + +void PrinterLLVM::regInfoEmitComposeSubRegIdxLaneMaskRev( + std::string const &ClName, + std::deque const &SubRegIndices) const { + OS << "LaneBitmask " << ClName + << "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, " + " LaneBitmask LaneMask) const {\n" + " LaneMask &= getSubRegIndexLaneMask(IdxA);\n" + " --IdxA; assert(IdxA < " + << SubRegIndices.size() + << " && \"Subregister index out of bounds\");\n" + " LaneBitmask Result;\n" + " for (const MaskRolOp *Ops =\n" + " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" + " Ops->Mask.any(); ++Ops) {\n" + " LaneBitmask::Type M = LaneMask.getAsInteger();\n" + " if (unsigned S = Ops->RotateLeft)\n" + " Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - " + "S)));\n" + " else\n" + " Result |= LaneBitmask(M);\n" + " }\n" + " return Result;\n" + "}\n\n"; +} + +void PrinterLLVM::regInfoEmitRegBaseClassMapping( + std::string const &ClassName, + SmallVector BaseClasses, + std::deque const Regs) const { + OS << "\n// Register to base register class mapping\n\n"; + OS << "\n"; + OS << "const TargetRegisterClass *" << ClassName + << "::getPhysRegBaseClass(MCRegister Reg)" + << " const {\n"; + OS << " static const uint16_t InvalidRegClassID = UINT16_MAX;\n\n"; + OS << " static const uint16_t Mapping[" << Regs.size() + 1 << "] = {\n"; + OS << " InvalidRegClassID, // NoRegister\n"; + for (const CodeGenRegister &Reg : Regs) { + const CodeGenRegisterClass *BaseRC = nullptr; + for (const CodeGenRegisterClass *RC : BaseClasses) { + if (is_contained(RC->getMembers(), &Reg)) { + BaseRC = RC; + break; + } + } + + OS << " " + << (BaseRC ? BaseRC->getQualifiedIdName() : "InvalidRegClassID") + << ", // " << Reg.getName() << "\n"; + } + OS << " };\n\n" + " assert(Reg < ArrayRef(Mapping).size());\n" + " unsigned RCID = Mapping[Reg];\n" + " if (RCID == InvalidRegClassID)\n" + " return nullptr;\n" + " return RegisterClasses[RCID];\n" + "}\n"; +} + +//------------------------- +// Backend: DecoderEmitter +//------------------------- + +void PrinterLLVM::decoderEmitterEmitOpDecoder(raw_ostream &DecoderOS, + const OperandInfo &Op) const { + unsigned const Indent = 4; + DecoderOS.indent(Indent) << GuardPrefix << Op.Decoder + << "(MI, insn, Address, Decoder)" << GuardPostfix + << " { " + << (Op.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return MCDisassembler::Fail; }\n"; +} + +void PrinterLLVM::decoderEmitterEmitOpBinaryParser( + raw_ostream &DecOS, const OperandInfo &OpInfo) const { + unsigned const Indent = 4; + const std::string &Decoder = OpInfo.Decoder; + + bool const UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0; + + if (UseInsertBits) { + DecOS.indent(Indent) << "tmp = 0x"; + DecOS.write_hex(OpInfo.InitValue); + DecOS << ";\n"; + } + + for (const EncodingField &EF : OpInfo) { + DecOS.indent(Indent); + if (UseInsertBits) + DecOS << "insertBits(tmp, "; + else + DecOS << "tmp = "; + DecOS << "fieldFromInstruction(insn, " << EF.Base << ", " << EF.Width + << ')'; + if (UseInsertBits) + DecOS << ", " << EF.Offset << ", " << EF.Width << ')'; + else if (EF.Offset != 0) + DecOS << " << " << EF.Offset; + DecOS << ";\n"; + } + + if (Decoder != "") { + DecOS.indent(Indent) << GuardPrefix << Decoder + << "(MI, tmp, Address, Decoder)" << GuardPostfix + << " { " + << (OpInfo.HasCompleteDecoder + ? "" + : "DecodeComplete = false; ") + << "return MCDisassembler::Fail; }\n"; + } else { + DecOS.indent(Indent) << "MI.addOperand(MCOperand::createImm(tmp));\n"; + } +} + +// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. +bool PrinterLLVM::decoderEmitterEmitPredicateMatchAux( + const Init &Val, bool ParenIfBinOp, raw_ostream &PredOS) const { + if (auto *D = dyn_cast(&Val)) { + if (!D->getDef()->isSubClassOf("SubtargetFeature")) + return true; + PredOS << "Bits[" << PredicateNamespace << "::" << D->getAsString() << "]"; + return false; + } + if (auto *D = dyn_cast(&Val)) { + std::string const Op = D->getOperator()->getAsString(); + if (Op == "not" && D->getNumArgs() == 1) { + PredOS << '!'; + return decoderEmitterEmitPredicateMatchAux(*D->getArg(0), true, PredOS); + } + if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) { + bool const Paren = + D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true); + if (Paren) + PredOS << '('; + ListSeparator LS(Op == "any_of" ? " || " : " && "); + for (auto *Arg : D->getArgs()) { + PredOS << LS; + if (decoderEmitterEmitPredicateMatchAux(*Arg, ParenIfBinOp, PredOS)) + return true; + } + if (Paren) + PredOS << ')'; + return false; + } + } + return true; +} + +bool PrinterLLVM::decoderEmitterEmitPredicateMatch(raw_ostream &PredOS, + const ListInit *Predicates, + unsigned Opc) const { + bool IsFirstEmission = true; + for (unsigned I = 0; I < Predicates->size(); ++I) { + Record *Pred = Predicates->getElementAsRecord(I); + if (!Pred->getValue("AssemblerMatcherPredicate")) + continue; + + if (!isa(Pred->getValue("AssemblerCondDag")->getValue())) + continue; + + if (!IsFirstEmission) + PredOS << " && "; + if (decoderEmitterEmitPredicateMatchAux( + *Pred->getValueAsDag("AssemblerCondDag"), Predicates->size() > 1, + PredOS)) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + IsFirstEmission = false; + } + return !Predicates->empty(); +} + +// emitFieldFromInstruction - Emit the templated helper function +// fieldFromInstruction(). +// On Windows we make sure that this function is not inlined when +// using the VS compiler. It has a bug which causes the function +// to be optimized out in some circustances. See llvm.org/pr38292 +void PrinterLLVM::decoderEmitterEmitFieldFromInstruction() const { + OS << "// Helper functions for extracting fields from encoded instructions.\n" + << "// InsnType must either be integral or an APInt-like object that " + "must:\n" + << "// * be default-constructible and copy-constructible\n" + << "// * be constructible from an APInt (this can be private)\n" + << "// * Support insertBits(bits, startBit, numBits)\n" + << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" + << "// * Support the ~, &, ==, and != operators with other objects of " + "the same type\n" + << "// * Support the != and bitwise & with uint64_t\n" + << "// * Support put (<<) to raw_ostream&\n" + << "template \n" + << "#if defined(_MSC_VER) && !defined(__clang__)\n" + << "__declspec(noinline)\n" + << "#endif\n" + << "static std::enable_if_t::value, InsnType>\n" + << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" + << " unsigned numBits) {\n" + << " assert(startBit + numBits <= 64 && \"Cannot support >64-bit " + "extractions!\");\n" + << " assert(startBit + numBits <= (sizeof(InsnType) * 8) &&\n" + << " \"Instruction field out of bounds!\");\n" + << " InsnType fieldMask;\n" + << " if (numBits == sizeof(InsnType) * 8)\n" + << " fieldMask = (InsnType)(-1LL);\n" + << " else\n" + << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n" + << " return (insn & fieldMask) >> startBit;\n" + << "}\n" + << "\n" + << "template \n" + << "static std::enable_if_t::value, " + "uint64_t>\n" + << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" + << " unsigned numBits) {\n" + << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" + << "}\n\n"; +} + +// emitInsertBits - Emit the templated helper function insertBits(). +void PrinterLLVM::decoderEmitterEmitInsertBits() const { + OS << "// Helper function for inserting bits extracted from an encoded " + "instruction into\n" + << "// a field.\n" + << "template \n" + << "static std::enable_if_t::value>\n" + << "insertBits(InsnType &field, InsnType bits, unsigned startBit, " + "unsigned numBits) {\n" + << " assert(startBit + numBits <= sizeof field * 8);\n" + << " field |= (InsnType)bits << startBit;\n" + << "}\n" + << "\n" + << "template \n" + << "static std::enable_if_t::value>\n" + << "insertBits(InsnType &field, uint64_t bits, unsigned startBit, " + "unsigned numBits) {\n" + << " field.insertBits(bits, startBit, numBits);\n" + << "}\n\n"; +} + +// Helper to propagate SoftFail status. Returns false if the status is Fail; +// callers are expected to early-exit in that condition. (Note, the '&' operator +// is correct to propagate the values of this enum; see comment on 'enum +// DecodeStatus'.) +void PrinterLLVM::decoderEmitterEmitCheck() const { + OS << "static bool Check(DecodeStatus &Out, DecodeStatus In) {\n" + << " Out = static_cast(Out & In);\n" + << " return Out != MCDisassembler::Fail;\n" + << "}\n\n"; +} + +// emitDecodeInstruction - Emit the templated helper function +// decodeInstruction(). +void PrinterLLVM::decoderEmitterEmitDecodeInstruction(bool IsVarLenInst) const { + OS << "template \n" + << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " + "MCInst &MI,\n" + << " InsnType insn, uint64_t " + "Address,\n" + << " const MCDisassembler *DisAsm,\n" + << " const MCSubtargetInfo &STI"; + if (IsVarLenInst) { + OS << ",\n" + << " llvm::function_ref makeUp"; + } + OS << ") {\n" + << " const FeatureBitset &Bits = STI.getFeatureBits();\n" + << "\n" + << " const uint8_t *Ptr = DecodeTable;\n" + << " uint64_t CurFieldValue = 0;\n" + << " DecodeStatus S = MCDisassembler::Success;\n" + << " while (true) {\n" + << " ptrdiff_t Loc = Ptr - DecodeTable;\n" + << " switch (*Ptr) {\n" + << " default:\n" + << " errs() << Loc << \": Unexpected decode table opcode!\\n\";\n" + << " return MCDisassembler::Fail;\n" + << " case MCD::OPC_ExtractField: {\n" + << " unsigned Start = *++Ptr;\n" + << " unsigned Len = *++Ptr;\n" + << " ++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " + "\", \"\n" + << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_FilterValue: {\n" + << " // Decode the field value.\n" + << " unsigned Len;\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // Perform the filter operation.\n" + << " if (Val != CurFieldValue)\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " + "\", \" << NumToSkip\n" + << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " + ": \"PASS:\")\n" + << " << \" continuing at \" << (Ptr - DecodeTable) << " + "\"\\n\");\n" + << "\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_CheckField: {\n" + << " unsigned Start = *++Ptr;\n" + << " unsigned Len = *++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " // Decode the field value.\n" + << " unsigned PtrLen = 0;\n" + << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);\n" + << " Ptr += PtrLen;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // If the actual and expected values don't match, skip.\n" + << " if (ExpectedValue != FieldValue)\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " + "\", \"\n" + << " << Len << \", \" << ExpectedValue << \", \" << " + "NumToSkip\n" + << " << \"): FieldValue = \" << FieldValue << \", " + "ExpectedValue = \"\n" + << " << ExpectedValue << \": \"\n" + << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " + "\"FAIL\\n\"));\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_CheckPredicate: {\n" + << " unsigned Len;\n" + << " // Decode the Predicate Index value.\n" + << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << " // Check the predicate.\n" + << " bool Pred;\n" + << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" + << " Ptr += NumToSkip;\n" + << " (void)Pred;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " + "<< \"): \"\n" + << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" + << "\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_Decode: {\n" + << " unsigned Len;\n" + << " // Decode the Opcode value.\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << "\n" + << " MI.clear();\n" + << " MI.setOpcode(Opc);\n" + << " bool DecodeComplete;\n"; + if (IsVarLenInst) { + OS << " Len = InstrLenTable[Opc];\n" + << " makeUp(insn, Len);\n"; + } + OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + "DecodeComplete);\n" + << " assert(DecodeComplete);\n" + << "\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" + << " << \", using decoder \" << DecodeIdx << \": \"\n" + << " << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" + << " return S;\n" + << " }\n" + << " case MCD::OPC_TryDecode: {\n" + << " unsigned Len;\n" + << " // Decode the Opcode value.\n" + << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << " // NumToSkip is a plain 24-bit integer.\n" + << " unsigned NumToSkip = *Ptr++;\n" + << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" + << "\n" + << " // Perform the decode operation.\n" + << " MCInst TmpMI;\n" + << " TmpMI.setOpcode(Opc);\n" + << " bool DecodeComplete;\n" + << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " + "DecodeComplete);\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " + "Opc\n" + << " << \", using decoder \" << DecodeIdx << \": \");\n" + << "\n" + << " if (DecodeComplete) {\n" + << " // Decoding complete.\n" + << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" + << " MI = TmpMI;\n" + << " return S;\n" + << " } else {\n" + << " assert(S == MCDisassembler::Fail);\n" + << " // If the decoding was incomplete, skip.\n" + << " Ptr += NumToSkip;\n" + << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " + "DecodeTable) << \"\\n\");\n" + << " // Reset decode status. This also drops a SoftFail status " + "that could be\n" + << " // set before the decode attempt.\n" + << " S = MCDisassembler::Success;\n" + << " }\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_SoftFail: {\n" + << " // Decode the mask values.\n" + << " unsigned Len;\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" + << " Ptr += Len;\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" + << " Ptr += Len;\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0;\n" + << " if (Fail)\n" + << " S = MCDisassembler::SoftFail;\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " + "\"FAIL\\n\" : \"PASS\\n\"));\n" + << " break;\n" + << " }\n" + << " case MCD::OPC_Fail: {\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" + << " return MCDisassembler::Fail;\n" + << " }\n" + << " }\n" + << " }\n" + << " llvm_unreachable(\"bogosity detected in disassembler state " + "machine!\");\n" + << "}\n\n"; +} + +// Emit the decoder state machine table. +void PrinterLLVM::decoderEmitterEmitTable( + DecoderTable &Table, unsigned BitWidth, StringRef Namespace, + std::vector &NumberedEncodings) const { + unsigned Indent = 0; + OS.indent(Indent) << "static const uint8_t DecoderTable" << Namespace + << BitWidth << "[] = {\n"; + + Indent += 2; + + // FIXME: We may be able to use the NumToSkip values to recover + // appropriate indentation levels. + DecoderTable::const_iterator I = Table.begin(); + DecoderTable::const_iterator const E = Table.end(); + while (I != E) { + assert(I < E && "incomplete decode table entry!"); + + uint64_t const Pos = I - Table.begin(); + OS << "/* " << Pos << " */"; + OS.PadToColumn(12); + + switch (*I) { + default: + PrintFatalError("invalid decode table opcode"); + case MCD::OPC_ExtractField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD::OPC_ExtractField, " << Start << ", " << Len + << ", // Inst{"; + if (Len > 1) + OS << (Start + Len - 1) << "-"; + OS << Start << "} ...\n"; + break; + } + case MCD::OPC_FilterValue: { + ++I; + OS.indent(Indent) << "MCD::OPC_FilterValue, "; + // The filter value is ULEB128 encoded. + while (*I >= 128) + OS << (unsigned)*I++ << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckField: { + ++I; + unsigned const Start = *I++; + unsigned const Len = *I++; + OS.indent(Indent) << "MCD::OPC_CheckField, " << Start << ", " << Len + << ", "; // << Val << ", " << NumToSkip << ",\n"; + // ULEB128 encoded field value. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_CheckPredicate: { + ++I; + OS.indent(Indent) << "MCD::OPC_CheckPredicate, "; + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_Decode: + case MCD::OPC_TryDecode: { + bool const IsTry = *I == MCD::OPC_TryDecode; + ++I; + // Extract the ULEB128 encoded Opcode to a buffer. + uint8_t Buffer[16], *P = Buffer; + while ((*P++ = *I++) >= 128) + assert((P - Buffer) <= (ptrdiff_t)sizeof(Buffer) && + "ULEB128 value too large!"); + // Decode the Opcode value. + unsigned const Opc = decodeULEB128(Buffer); + OS.indent(Indent) << "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, "; + for (P = Buffer; *P >= 128; ++P) + OS << (unsigned)*P << ", "; + OS << (unsigned)*P << ", "; + + // Decoder index. + for (; *I >= 128; ++I) + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; + + if (!IsTry) { + OS << "// Opcode: " << NumberedEncodings[Opc] << "\n"; + break; + } + + // Fallthrough for OPC_TryDecode. + + // 24-bit numtoskip value. + uint8_t Byte = *I++; + uint32_t NumToSkip = Byte; + OS << (unsigned)Byte << ", "; + Byte = *I++; + OS << (unsigned)Byte << ", "; + NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; + + OS << "// Opcode: " << NumberedEncodings[Opc] + << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; + break; + } + case MCD::OPC_SoftFail: { + ++I; + OS.indent(Indent) << "MCD::OPC_SoftFail"; + // Positive mask + uint64_t Value = 0; + unsigned Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + // Negative mask + Value = 0; + Shift = 0; + do { + OS << ", " << (unsigned)*I; + Value += (*I & 0x7f) << Shift; + Shift += 7; + } while (*I++ >= 128); + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } + OS << ",\n"; + break; + } + case MCD::OPC_Fail: { + ++I; + OS.indent(Indent) << "MCD::OPC_Fail,\n"; + break; + } + } + } + OS.indent(Indent) << "0\n"; + + Indent -= 2; + + OS.indent(Indent) << "};\n\n"; +} + +void PrinterLLVM::decoderEmitterEmitInstrLenTable( + std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned const &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::decoderEmitterEmitPredicateFunction( + PredicateSet &Predicates, unsigned Indentation) const { + // The predicate function is just a big switch statement based on the + // input predicate index. + OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " + << "const FeatureBitset &Bits) {\n"; + Indentation += 2; + if (!Predicates.empty()) { + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) + << "default: llvm_unreachable(\"Invalid index!\");\n"; + unsigned Index = 0; + for (const auto &Predicate : Predicates) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS.indent(Indentation + 2) << "return (" << Predicate << ");\n"; + } + OS.indent(Indentation) << "}\n"; + } else { + // No case statement to emit + OS.indent(Indentation) << "llvm_unreachable(\"Invalid index!\");\n"; + } + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterLLVM::decoderEmitterEmitDecoderFunction( + DecoderSet &Decoders, unsigned Indentation) const { + // The decoder function is just a big switch statement based on the + // input decoder index. + OS.indent(Indentation) << "template \n"; + OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," + << " unsigned Idx, InsnType insn, MCInst &MI,\n"; + OS.indent(Indentation) + << " uint64_t " + << "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n"; + Indentation += 2; + OS.indent(Indentation) << "DecodeComplete = true;\n"; + // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits + // It would be better for emitBinaryParser to use a 64-bit tmp whenever + // possible but fall back to an InsnType-sized tmp for truly large fields. + OS.indent(Indentation) << "using TmpType = " + "std::conditional_t::" + "value, InsnType, uint64_t>;\n"; + OS.indent(Indentation) << "TmpType tmp;\n"; + OS.indent(Indentation) << "switch (Idx) {\n"; + OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n"; + unsigned Index = 0; + for (const auto &Decoder : Decoders) { + OS.indent(Indentation) << "case " << Index++ << ":\n"; + OS << Decoder; + OS.indent(Indentation + 2) << "return S;\n"; + } + OS.indent(Indentation) << "}\n"; + Indentation -= 2; + OS.indent(Indentation) << "}\n\n"; +} + +void PrinterLLVM::decoderEmitterEmitIncludes() const { + OS << "#include \"llvm/MC/MCInst.h\"\n"; + OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; + OS << "#include \"llvm/Support/DataTypes.h\"\n"; + OS << "#include \"llvm/Support/Debug.h\"\n"; + OS << "#include \"llvm/Support/LEB128.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n"; + OS << "#include \"llvm/TargetParser/SubtargetFeature.h\"\n"; + OS << "#include \n"; + OS << '\n'; +} + +void PrinterLLVM::decoderEmitterEmitSourceFileHeader() const { + llvm::emitSourceFileHeader(" * " + TargetName + " Disassembler", OS); +} + +//------------------------- +// Backend: AsmWriter +//------------------------- + +void PrinterLLVM::asmWriterEmitSourceFileHeader(RecordKeeper &Records) const { + emitSourceFileHeader("Assembly Writer Source Fragment", OS, Records); +} + +void PrinterLLVM::asmWriterEmitGetMnemonic(std::string const &TargetName, + StringRef const &ClassName) const { + OS << "/// getMnemonic - This method is automatically generated by " + "tablegen\n" + "/// from the instruction set description.\n" + "std::pair " + << TargetName << ClassName << "::getMnemonic(const MCInst *MI) {\n"; +} + +void PrinterLLVM::asmWriterEmitAsmStrs( + SequenceToOffsetTable const &StrTable) const { + StrTable.emitStringLiteralDef(OS, " static const char AsmStrs[]"); +} + +void PrinterLLVM::asmWriterEmitMnemonicDecodeTable( + unsigned const OpcodeInfoBits, unsigned BitsLeft, + unsigned const &AsmStrBits, + ArrayRef const &NumberedInstructions, + std::vector const &OpcodeInfo) const { + // Emit the lookup tables in pieces to minimize wasted bytes. + unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8; + unsigned Table = 0, Shift = 0; + SmallString<128> BitsString; + raw_svector_ostream BitsOS(BitsString); + // If the total bits is more than 32-bits we need to use a 64-bit type. + BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) + << "_t Bits = 0;\n"; + while (BytesNeeded != 0) { + // Figure out how big this table section needs to be, but no bigger than 4. + unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u); + BytesNeeded -= TableSize; + TableSize *= 8; // Convert to bits; + uint64_t Mask = (1ULL << TableSize) - 1; + OS << " static const uint" << TableSize << "_t OpInfo" << Table + << "[] = {\n"; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + OS << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// " + << NumberedInstructions[i]->TheDef->getName() << "\n"; + } + OS << " };\n\n"; + // Emit string to combine the individual table lookups. + BitsOS << " Bits |= "; + // If the total bits is more than 32-bits we need to use a 64-bit type. + if (BitsLeft < (OpcodeInfoBits - 32)) + BitsOS << "(uint64_t)"; + BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n"; + // Prepare the shift for the next iteration and increment the table count. + Shift += TableSize; + ++Table; + } + + OS << " // Emit the opcode for the instruction.\n"; + OS << BitsString; + + // Make sure we don't return an invalid pointer if bits is 0 + OS << " if (Bits == 0)\n" + " return {nullptr, Bits};\n"; + + // Return mnemonic string and bits. + OS << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1 + << ")-1, Bits};\n\n"; + + OS << "}\n"; +} + +void PrinterLLVM::asmWriterEmitPrintInstruction( + std::string const &TargetName, + std::vector> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits, StringRef const &ClassName, + bool PassSubtarget) const { + const unsigned OpcodeInfoBits = 64; + // This function has some huge switch statements that causing excessive + // compile time in LLVM profile instrumenation build. This print function + // usually is not frequently called in compilation. Here we disable the + // profile instrumenation for this function. + OS << "/// printInstruction - This method is automatically generated by " + "tablegen\n" + "/// from the instruction set description.\n" + "LLVM_NO_PROFILE_INSTRUMENT_FUNCTION\n" + "void " + << TargetName << ClassName + << "::printInstruction(const MCInst *MI, uint64_t Address, " + << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << "raw_ostream &O) {\n"; + + // Emit the initial tab character. + OS << " O << \"\\t\";\n\n"; + + // Emit the starting string. + OS << " auto MnemonicInfo = getMnemonic(MI);\n\n"; + OS << " O << MnemonicInfo.first;\n\n"; + + OS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) + << "_t Bits = MnemonicInfo.second;\n" + << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"; + + // Output the table driven operand information. + BitsLeft = OpcodeInfoBits - AsmStrBits; + for (unsigned I = 0, E = TableDrivenOperandPrinters.size(); I != E; ++I) { + std::vector &Commands = TableDrivenOperandPrinters[I]; + + // Compute the number of bits we need to represent these cases, this is + // ceil(log2(numentries)). + unsigned const NumBits = Log2_32_Ceil(Commands.size()); + assert(NumBits <= BitsLeft && "consistency error"); + + // Emit code to extract this field from Bits. + OS << "\n // Fragment " << I << " encoded into " << NumBits << " bits for " + << Commands.size() << " unique commands.\n"; + + if (Commands.size() == 2) { + // Emit two possibilitys with if/else. + OS << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " + << ((1 << NumBits) - 1) << ") {\n" + << Commands[1] << " } else {\n" + << Commands[0] << " }\n\n"; + } else if (Commands.size() == 1) { + // Emit a single possibility. + OS << Commands[0] << "\n\n"; + } else { + OS << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & " + << ((1 << NumBits) - 1) << ") {\n" + << " default: llvm_unreachable(\"Invalid command number.\");\n"; + + // Print out all the cases. + for (unsigned J = 0, F = Commands.size(); J != F; ++J) { + OS << " case " << J << ":\n"; + OS << Commands[J]; + OS << " break;\n"; + } + OS << " }\n\n"; + } + BitsLeft -= NumBits; + } +} + +void PrinterLLVM::asmWriterEmitOpCases( + std::vector> &OpsToPrint, + bool PassSubtarget) const { + OS << " case " << OpsToPrint.back().first << ":"; + AsmWriterOperand const TheOp = OpsToPrint.back().second; + OpsToPrint.pop_back(); + + // Check to see if any other operands are identical in this list, and if so, + // emit a case label for them. + for (unsigned I = OpsToPrint.size(); I != 0; --I) + if (OpsToPrint[I - 1].second == TheOp) { + OS << "\n case " << OpsToPrint[I - 1].first << ":"; + OpsToPrint.erase(OpsToPrint.begin() + I - 1); + } + + // Finally, emit the code. + OS << "\n " << TheOp.getCode(PassSubtarget); + OS << "\n break;\n"; +} + +void PrinterLLVM::asmWriterEmitInstrSwitch() const { + OS << " switch (MI->getOpcode()) {\n"; + OS << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; +} + +void PrinterLLVM::asmWriterEmitCompoundClosure(unsigned Indent, bool Newline, + bool Semicolon) const { + for (; Indent > 0; --Indent) { + OS << " "; + } + OS << "}"; + if (Semicolon) + OS << ";"; + if (Newline) + OS << "\n"; +} + +void PrinterLLVM::asmWriterEmitInstruction( + AsmWriterInst const &FirstInst, + std::vector const &SimilarInsts, unsigned DifferingOperand, + bool PassSubtarget) const { + OS << " case " << FirstInst.CGI->Namespace + << "::" << FirstInst.CGI->TheDef->getName() << ":\n"; + for (const AsmWriterInst &AWI : SimilarInsts) + OS << " case " << AWI.CGI->Namespace << "::" << AWI.CGI->TheDef->getName() + << ":\n"; + for (unsigned I = 0, E = FirstInst.Operands.size(); I != E; ++I) { + if (I != DifferingOperand) { + // If the operand is the same for all instructions, just print it. + OS << " " << FirstInst.Operands[I].getCode(PassSubtarget); + } else { + // If this is the operand that varies between all of the instructions, + // emit a switch for just this operand now. + OS << " switch (MI->getOpcode()) {\n"; + OS << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; + std::vector> OpsToPrint; + OpsToPrint.push_back( + std::make_pair(FirstInst.CGI->Namespace.str() + + "::" + FirstInst.CGI->TheDef->getName().str(), + FirstInst.Operands[I])); + + for (const AsmWriterInst &AWI : SimilarInsts) { + OpsToPrint.push_back(std::make_pair( + AWI.CGI->Namespace.str() + "::" + AWI.CGI->TheDef->getName().str(), + AWI.Operands[I])); + } + std::reverse(OpsToPrint.begin(), OpsToPrint.end()); + while (!OpsToPrint.empty()) + asmWriterEmitOpCases(OpsToPrint, PassSubtarget); + OS << " }"; + } + OS << "\n"; + } + OS << " break;\n"; +} + +void PrinterLLVM::asmWriterEmitGetRegNameAssert(std::string const &TargetName, + StringRef const &ClassName, + bool hasAltNames, + unsigned RegSize) const { + + OS << + "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" + "/// from the register set description. This returns the assembler name\n" + "/// for the specified register.\n" + "const char *" << TargetName << ClassName << "::"; + if (hasAltNames) + OS << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n"; + else + OS << "getRegisterName(MCRegister Reg) {\n"; + OS << " unsigned RegNo = Reg.id();\n" + << " assert(RegNo && RegNo < " << (RegSize + 1) + << " && \"Invalid register number!\");\n" + << "\n"; +} + +void PrinterLLVM::asmWriterEmitStringLiteralDef( + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const { + StringTable.emitStringLiteralDef(OS, Twine(" static const char AsmStrs") + + AltName + "[]"); +} + +void PrinterLLVM::asmWriterEmitRegAsmOffsets( + unsigned RegSizes, SmallVector const &AsmNames, + SequenceToOffsetTable const &StringTable, + StringRef const &AltName) const { + OS << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32) + << " RegAsmOffset" << AltName << "[] = {"; + for (unsigned I = 0, E = RegSizes; I != E; ++I) { + if ((I % 14) == 0) + OS << "\n "; + OS << StringTable.get(AsmNames[I]) << ", "; + } + OS << "\n };\n" + << "\n"; +} + +void PrinterLLVM::asmWriterEmitAltIdxSwitch( + bool HasAltNames, std::vector const &AltNameIndices, + StringRef const &Namespace) const { + if (HasAltNames) { + OS << " switch(AltIdx) {\n" + << " default: llvm_unreachable(\"Invalid register alt name " + "index!\");\n"; + for (const Record *R : AltNameIndices) { + StringRef const AltName = R->getName(); + OS << " case "; + if (!Namespace.empty()) + OS << Namespace << "::"; + OS << AltName << ":\n"; + if (R->isValueUnset("FallbackRegAltNameIndex")) + OS << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1]) &&\n" + << " \"Invalid alt name index for register!\");\n"; + else { + OS << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1]))\n" + << " return getRegisterName(RegNo, "; + if (!Namespace.empty()) + OS << Namespace << "::"; + OS << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n"; + } + OS << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName + << "[RegNo-1];\n"; + } + OS << " }\n"; + } else { + OS << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n" + << " \"Invalid alt name index for register!\");\n" + << " return AsmStrs+RegAsmOffset[RegNo-1];\n"; + } + OS << "}\n"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKIgnore() const { + return "AliasPatternCond::K_Ignore, 0"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKRegClass() const { + return "AliasPatternCond::K_RegClass, {0}::{1}RegClassID"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKTiedReg() const { + return "AliasPatternCond::K_TiedReg, {0}"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKCustom() const { + return "AliasPatternCond::K_Custom, {0}"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKImm() const { + return "AliasPatternCond::K_Imm, uint32_t({0})"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKNoReg() const { + return "AliasPatternCond::K_Reg, {0}::NoRegister"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKReg() const { + return "AliasPatternCond::K_Reg, {0}::{1}"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKFeature() const { + return "AliasPatternCond::K_{0}{1}Feature, {2}::{3}"; +} + +char const *PrinterLLVM::asmWriterGetPatCondKEndOrFeature() const { + return "AliasPatternCond::K_EndOrFeatures, 0"; +} + +char const *PrinterLLVM::asmWriterGetPatOpcStart() const { + return " // {0} - {1}\n"; +} + +char const *PrinterLLVM::asmWriterGetCondPatStart() const { + return " // {0} - {1}\n"; +} + +std::string PrinterLLVM::asmWriterGetCond(std::string const &Cond) const { + return formatv(" {{{0}},\n", Cond); +} + +char const *PrinterLLVM::asmWriterGetPatternFormat() const { + return " {{{0}, {1}, {2}, {3} },\n"; +} + +char const *PrinterLLVM::asmWriterGetOpcodeFormat() const { + return " {{{0}, {1}, {2} },\n"; +} + +void PrinterLLVM::asmWriterEmitPrintAliasInstrHeader( + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const { + OS << "bool " << TargetName << ClassName << "::printAliasInstr(const MCInst" + << " *MI, uint64_t Address, " + << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << "raw_ostream &OS) {\n"; +} + +void PrinterLLVM::asmWriterEmitPrintAliasInstrBodyRetFalse() const { + OS << " return false;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmWriterEmitDeclValid(std::string const &TargetName, + StringRef const &ClassName) const { + OS << "static bool " << TargetName << ClassName + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex);\n"; +} + +void PrinterLLVM::asmWriterEmitPrintAliasInstrBody( + raw_string_ostream &OpcodeO, raw_string_ostream &PatternO, + raw_string_ostream &CondO, + std::vector> const &AsmStrings, + std::vector const &MCOpPredicates, + std::string const &TargetName, StringRef const &ClassName, + bool PassSubtarget) const { + OS.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n"; + OS << OpcodeO.str(); + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const AliasPattern Patterns[] = {\n"; + OS << PatternO.str(); + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const AliasPatternCond Conds[] = {\n"; + OS << CondO.str(); + OS.indent(2) << "};\n\n"; + OS.indent(2) << "static const char AsmStrings[] =\n"; + for (const auto &P : AsmStrings) { + OS.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n"; + } + + OS.indent(2) << ";\n\n"; + + // Assert that the opcode table is sorted. Use a static local constructor to + // ensure that the check only happens once on first run. + OS << "#ifndef NDEBUG\n"; + OS.indent(2) << "static struct SortCheck {\n"; + OS.indent(2) << " SortCheck(ArrayRef OpToPatterns) {\n"; + OS.indent(2) << " assert(std::is_sorted(\n"; + OS.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n"; + OS.indent(2) << " [](const PatternsForOpcode &L, const " + "PatternsForOpcode &R) {\n"; + OS.indent(2) << " return L.Opcode < R.Opcode;\n"; + OS.indent(2) << " }) &&\n"; + OS.indent(2) << " \"tablegen failed to sort opcode patterns\");\n"; + OS.indent(2) << " }\n"; + OS.indent(2) << "} sortCheckVar(OpToPatterns);\n"; + OS << "#endif\n\n"; + + OS.indent(2) << "AliasMatchingData M {\n"; + OS.indent(2) << " ArrayRef(OpToPatterns),\n"; + OS.indent(2) << " ArrayRef(Patterns),\n"; + OS.indent(2) << " ArrayRef(Conds),\n"; + OS.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n"; + if (MCOpPredicates.empty()) + OS.indent(2) << " nullptr,\n"; + else + OS.indent(2) << " &" << TargetName << ClassName << "ValidateMCOperand,\n"; + OS.indent(2) << "};\n"; + + OS.indent(2) << "const char *AsmString = matchAliasPatterns(MI, " + << (PassSubtarget ? "&STI" : "nullptr") << ", M);\n"; + OS.indent(2) << "if (!AsmString) return false;\n\n"; + + // Code that prints the alias, replacing the operands with the ones from the + // MCInst. + OS << " unsigned I = 0;\n"; + OS << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; + OS << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; + OS << " ++I;\n"; + OS << " OS << '\\t' << StringRef(AsmString, I);\n"; + + OS << " if (AsmString[I] != '\\0') {\n"; + OS << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n"; + OS << " OS << '\\t';\n"; + OS << " ++I;\n"; + OS << " }\n"; + OS << " do {\n"; + OS << " if (AsmString[I] == '$') {\n"; + OS << " ++I;\n"; + OS << " if (AsmString[I] == (char)0xff) {\n"; + OS << " ++I;\n"; + OS << " int OpIdx = AsmString[I++] - 1;\n"; + OS << " int PrintMethodIdx = AsmString[I++] - 1;\n"; + OS << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, "; + OS << (PassSubtarget ? "STI, " : ""); + OS << "OS);\n"; + OS << " } else\n"; + OS << " printOperand(MI, unsigned(AsmString[I++]) - 1, "; + OS << (PassSubtarget ? "STI, " : ""); + OS << "OS);\n"; + OS << " } else {\n"; + OS << " OS << AsmString[I++];\n"; + OS << " }\n"; + OS << " } while (AsmString[I] != '\\0');\n"; + OS << " }\n\n"; + + OS << " return true;\n"; + OS << "}\n\n"; + +} + +void PrinterLLVM::asmWriterEmitPrintAliasOp( + std::string const &TargetName, StringRef const &ClassName, + std::vector> const &PrintMethods, + bool PassSubtarget) const { + OS << "void " << TargetName << ClassName << "::" + << "printCustomAliasOperand(\n" + << " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n" + << " unsigned PrintMethodIdx,\n" + << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "") + << " raw_ostream &OS) {\n"; + if (PrintMethods.empty()) + OS << " llvm_unreachable(\"Unknown PrintMethod kind\");\n"; + else { + OS << " switch (PrintMethodIdx) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown PrintMethod kind\");\n" + << " break;\n"; + + for (unsigned I = 0; I < PrintMethods.size(); ++I) { + OS << " case " << I << ":\n" + << " " << PrintMethods[I].first << "(MI, " + << (PrintMethods[I].second ? "Address, " : "") << "OpIdx, " + << (PassSubtarget ? "STI, " : "") << "OS);\n" + << " break;\n"; + } + OS << " }\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::asmWriterEmitPrintMC( + std::string const &TargetName, StringRef const &ClassName, + std::vector const &MCOpPredicates) const { + if (!MCOpPredicates.empty()) { + OS << "static bool " << TargetName << ClassName + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + for (unsigned I = 0; I < MCOpPredicates.size(); ++I) { + StringRef const MCOpPred = + MCOpPredicates[I]->getValueAsString("MCOperandPredicate"); + OS << " case " << I + 1 << ": {\n" + << MCOpPred.data() << "\n" + << " }\n"; + } + OS << " }\n" + << "}\n\n"; + } +} + +//------------------------- +// Backend: Subtarget +//------------------------- + +void PrinterLLVM::subtargetEmitGetMacroFusions(CodeGenTarget &TGT, + std::string Target, + const std::string &ClassName) const { + if (!TGT.hasMacroFusion()) + return; + + OS << "std::vector " << ClassName + << "::getMacroFusions() const {\n"; + OS.indent(2) << "std::vector Fusions;\n"; + for (auto *Fusion : TGT.getMacroFusions()) { + std::string Name = Fusion->getNameInitAsString(); + OS.indent(2) << "if (hasFeature(" << Target << "::" << Name + << ")) Fusions.push_back(llvm::is" << Name << ");\n"; + } + + OS.indent(2) << "return Fusions;\n"; + OS << "}\n"; +} + +void PrinterLLVM::subtargetEmitSourceFileHeader() const { + emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); +} + +void PrinterLLVM::subtargetEmitFeatureEnum( + DenseMap &FeatureMap, + std::vector const &DefList, unsigned N) const { + // Open enumeration. + OS << "enum {\n"; + + // For each record + for (unsigned I = 0; I < N; ++I) { + // Next record + Record *Def = DefList[I]; + + // Get and emit name + OS << " " << Def->getName() << " = " << I << ",\n"; + + // Save the index for this feature. + FeatureMap[Def] = I; + } + + OS << " " + << "NumSubtargetFeatures = " << N << "\n"; + + // Close enumeration and namespace + OS << "};\n"; +} + +void PrinterLLVM::subtargetEmitGetSTIMacro(StringRef const &Value, + StringRef const &FieldName) const { + // Some features default to true, with values set to false if enabled. + const char *Default = Value == "false" ? "true" : "false"; + + // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; } + const std::string Getter = + FieldName.substr(0, 1).lower() + FieldName.substr(1).str(); + + OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", " + << Getter << ")\n"; +} + +void PrinterLLVM::subtargetEmitHwModes(CodeGenHwModes const &CGH, + std::string const &ClassName) const { + OS << "unsigned " << ClassName << "::getHwMode() const {\n"; + for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) { + const HwMode &HM = CGH.getMode(M); + OS << " if (checkFeatures(\"" << HM.Features << "\")) return " << M + << ";\n"; + } + OS << " return 0;\n}\n"; +} + +void PrinterLLVM::subtargetEmitFeatureKVHeader( + std::string const &Target) const { + // Begin feature table + OS << "// Sorted (by key) array of values for CPU features.\n" + << "extern const llvm::SubtargetFeatureKV " << Target + << "FeatureKV[] = {\n"; +} + +void PrinterLLVM::subtargetEmitFeatureKVPartI(std::string const &Target, + StringRef const &CommandLineName, + StringRef const &Name, + StringRef const &Desc) const { + // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } + OS << " { " + << "\"" << CommandLineName << "\", " + << "\"" << Desc << "\", " << Target << "::" << Name << ", "; +} + +void PrinterLLVM::subtargetEmitFeatureKVPartII() const { OS << " },\n"; } + +void PrinterLLVM::subtargetEmitPrintFeatureMask( + std::array const &Mask) const { + OS << "{ { { "; + for (unsigned I = 0; I != Mask.size(); ++I) { + OS << "0x"; + OS.write_hex(Mask[I]); + OS << "ULL, "; + } + OS << "} } }"; +} + +void PrinterLLVM::subtargetEmitFeatureKVEnd() const { OS << "};\n"; } + +void PrinterLLVM::subtargetEmitCPUKVHeader(std::string const &Target) const { + OS << "// Sorted (by key) array of values for CPU subtype.\n" + << "extern const llvm::SubtargetSubTypeKV " << Target + << "SubTypeKV[] = {\n"; +} + +void PrinterLLVM::subtargetEmitCPUKVEnd() const { OS << "};\n"; } + +void PrinterLLVM::subtargetEmitCPUKVPartI(StringRef const &Name) const { + // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } }, + OS << " { " + << "\"" << Name << "\", "; +} + +void PrinterLLVM::subtargetEmitCPUKVPartII() const { OS << ", "; } + +void PrinterLLVM::subtargetEmitCPUKVPartIII( + std::string const &ProcModelName) const { + OS << ", &" << ProcModelName << " },\n"; +} + +void PrinterLLVM::subtargetEmitDBGMacrosBegin() const { + OS << "#ifdef DBGFIELD\n" + << "#error \"GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" + << "#endif\n" + << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n" + << "#define DBGFIELD(x) x,\n" + << "#else\n" + << "#define DBGFIELD(x)\n" + << "#endif\n"; +} + +void PrinterLLVM::subtargetEmitDBGMacrosEnd() const { + OS << "\n#undef DBGFIELD\n"; +} + +void PrinterLLVM::subtargetEmitFunctionalItinaryUnits( + CodeGenSchedModels const &SchedModels) const { + + // Multiple processor models may share an itinerary record. Emit it once. + SmallPtrSet ItinsDefSet; + + // Emit functional units for all the itineraries. + for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { + + if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) + continue; + + RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); + if (FUs.empty()) + continue; + + StringRef const Name = ProcModel.ItinsDef->getName(); + OS << "\n// Functional units for \"" << Name << "\"\n" + << "namespace " << Name << "FU {\n"; + + for (unsigned J = 0, FUN = FUs.size(); J < FUN; ++J) + OS << " const InstrStage::FuncUnits " << FUs[J]->getName() + << " = 1ULL << " << J << ";\n"; + + OS << "} // end namespace " << Name << "FU\n"; + + RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); + if (!BPs.empty()) { + OS << "\n// Pipeline forwarding paths for itineraries \"" << Name + << "\"\n" + << "namespace " << Name << "Bypass {\n"; + + OS << " const unsigned NoBypass = 0;\n"; + for (unsigned J = 0, BPN = BPs.size(); J < BPN; ++J) + OS << " const unsigned " << BPs[J]->getName() << " = 1 << " << J + << ";\n"; + + OS << "} // end namespace " << Name << "Bypass\n"; + } + } +} + +std::string const +PrinterLLVM::subtargetGetBeginStageTable(std::string const &TargetName) const { + return "\nextern const llvm::InstrStage " + TargetName + "Stages[] = {\n" + + " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; +} + +std::string const PrinterLLVM::subtargetGetBeginOperandCycleTable( + std::string const &TargetName) const { + return "extern const unsigned " + TargetName + "OperandCycles[] = {\n" + + " 0, // No itinerary\n"; +} + +std::string const +PrinterLLVM::subtargetGetBeginBypassTable(std::string const &TargetName) const { + return "extern const unsigned " + TargetName + "ForwardingPaths[] = {\n" + + " 0, // No itinerary\n"; +} + +std::string const PrinterLLVM::subtargetGetEndStageTable() const { + return " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n};\n"; +} + +std::string const PrinterLLVM::subtargetGetEndOperandCycleTable() const { + return " 0 // End operand cycles\n};\n"; +} + +std::string const PrinterLLVM::subtargetGetEndBypassTable() const { + return " 0 // End bypass tables\n};\n"; +} + +// subtargetFormItineraryStageString - Compose a string containing the stage +// data initialization for the specified itinerary. N is the number +// of stages. +void PrinterLLVM::subtargetFormItineraryStageString(std::string const &Name, + Record *ItinData, + std::string &ItinString, + unsigned &NStages) const { + // Get states list + RecVec StageList = ItinData->getValueAsListOfDefs("Stages"); + + // For each stage + unsigned const N = NStages = StageList.size(); + for (unsigned I = 0; I < N;) { + // Next stage + const Record *Stage = StageList[I]; + + // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } + int const Cycles = Stage->getValueAsInt("Cycles"); + ItinString += " { " + itostr(Cycles) + ", "; + + // Get unit list + RecVec UnitList = Stage->getValueAsListOfDefs("Units"); + + // For each unit + for (unsigned J = 0, M = UnitList.size(); J < M;) { + // Add name and bitwise or + ItinString += Name + "FU::" + UnitList[J]->getName().str(); + if (++J < M) + ItinString += " | "; + } + + int const TimeInc = Stage->getValueAsInt("TimeInc"); + ItinString += ", " + itostr(TimeInc); + + int const Kind = Stage->getValueAsInt("Kind"); + ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); + + // Close off stage + ItinString += " }"; + if (++I < N) + ItinString += ", "; + } +} + +// FormItineraryOperandCycleString - Compose a string containing the +// operand cycle initialization for the specified itinerary. N is the +// number of operands that has cycles specified. +void PrinterLLVM::subtargetFormItineraryOperandCycleString( + Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) const { + // Get operand cycle list + std::vector OperandCycleList = + ItinData->getValueAsListOfInts("OperandCycles"); + + // For each operand cycle + NOperandCycles = OperandCycleList.size(); + ListSeparator LS; + for (int OCycle : OperandCycleList) { + // Next operand cycle + ItinString += LS; + ItinString += " " + itostr(OCycle); + } +} + +void PrinterLLVM::subtargetFormItineraryBypassString( + const std::string &Name, Record *ItinData, std::string &ItinString, + unsigned NOperandCycles) const { + RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses"); + unsigned const N = BypassList.size(); + unsigned I = 0; + ListSeparator LS; + for (; I < N; ++I) { + ItinString += LS; + ItinString += Name + "Bypass::" + BypassList[I]->getName().str(); + } + for (; I < NOperandCycles; ++I) { + ItinString += LS; + ItinString += " 0"; + } +} + +std::string +PrinterLLVM::subtargetGetStageEntryPartI(std::string const &ItinStageString, + unsigned StageCount) const { + return ItinStageString + ", // " + itostr(StageCount); +} +std::string PrinterLLVM::subtargetGetStageEntryPartII(unsigned StageCount, + unsigned NStages) const { + return "-" + itostr(StageCount + NStages - 1); +} +std::string PrinterLLVM::subtargetGetStageEntryPartIII() const { return "\n"; } + +std::string PrinterLLVM::subtargetGetOperandCycleEntryPartI( + std::string const &ItinOperandCycleString) const { + return ItinOperandCycleString + ", // "; +} + +std::string PrinterLLVM::subtargetGetOperandCycleEntryPartII( + unsigned OperandCycleCount, unsigned NOperandCycles) const { + return "-" + itostr(OperandCycleCount + NOperandCycles - 1); +} + +std::string PrinterLLVM::subtargetGetOperandCycleEntryPartIII( + std::string const &OperandIdxComment) const { + return OperandIdxComment + "\n"; +} + +std::string PrinterLLVM::subtargetGetOperandCycleEntryPartIV( + std::string const &ItinBypassString, + std::string const &OperandIdxComment) const { + return ItinBypassString + ", // " + OperandIdxComment + "\n"; +} + +void PrinterLLVM::subtargetEmitProcessorItineraryTable( + std::string const &ItinsDefName, std::vector &ItinList, + CodeGenSchedModels const &SchedModels) const { + OS << "\n"; + OS << "static const llvm::InstrItinerary "; + + // Begin processor itinerary table + OS << ItinsDefName << "[] = {\n"; + + // For each itinerary class in CodeGenSchedClass::Index order. + for (unsigned J = 0, M = ItinList.size(); J < M; ++J) { + InstrItinerary const &Intinerary = ItinList[J]; + + // Emit Itinerary in the form of + // { firstStage, lastStage, firstCycle, lastCycle } // index + OS << " { " << Intinerary.NumMicroOps << ", " << Intinerary.FirstStage + << ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle + << ", " << Intinerary.LastOperandCycle << " }" + << ", // " << J << " " << SchedModels.getSchedClass(J).Name << "\n"; + } + // End processor itinerary table + OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }" + "// end marker\n"; + OS << "};\n"; +} + +void PrinterLLVM::subtargetEmitPreOperandTableComment() const { + OS << "\n// ===============================================================\n" + << "// Data tables for the new per-operand machine model.\n"; +} + +// Emit SchedClass tables for all processors and associated global tables. +void PrinterLLVM::subtargetEmitSchedClassTables( + SchedClassTablesT &SchedTables, std::string const &Target, + CodeGenSchedModels const &SchedModels) const { + // Emit global WriteProcResTable. + OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n" + << "extern const llvm::MCWriteProcResEntry " << Target + << "WriteProcResTable[] = {\n" + << " { 0, 0, 0 }, // Invalid\n"; + for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); + WPRIdx != WPREnd; ++WPRIdx) { + MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; + OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " + << format("%2d", WPREntry.ReleaseAtCycle) << ", " + << format("%2d", WPREntry.AcquireAtCycle) << "}"; + if (WPRIdx + 1 < WPREnd) + OS << ','; + OS << " // #" << WPRIdx << '\n'; + } + OS << "}; // " << Target << "WriteProcResTable\n"; + + // Emit global WriteLatencyTable. + OS << "\n// {Cycles, WriteResourceID}\n" + << "extern const llvm::MCWriteLatencyEntry " + << Target << "WriteLatencyTable[] = {\n" + << " { 0, 0}, // Invalid\n"; + for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); + WLIdx != WLEnd; ++WLIdx) { + MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; + OS << " {" << format("%2d", WLEntry.Cycles) << ", " + << format("%2d", WLEntry.WriteResourceID) << "}"; + if (WLIdx + 1 < WLEnd) + OS << ','; + OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; + } + OS << "}; // " << Target << "WriteLatencyTable\n"; + + // Emit global ReadAdvanceTable. + OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" + << "extern const llvm::MCReadAdvanceEntry " + << Target << "ReadAdvanceTable[] = {\n" + << " {0, 0, 0}, // Invalid\n"; + for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); + RAIdx != RAEnd; ++RAIdx) { + MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; + OS << " {" << RAEntry.UseIdx << ", " + << format("%2d", RAEntry.WriteResourceID) << ", " + << format("%2d", RAEntry.Cycles) << "}"; + if (RAIdx + 1 < RAEnd) + OS << ','; + OS << " // #" << RAIdx << '\n'; + } + OS << "}; // " << Target << "ReadAdvanceTable\n"; + + // Emit a SchedClass table for each processor. + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + if (!PI->hasInstrSchedModel()) + continue; + + std::vector &SCTab = + SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; + + OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO," + << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; + OS << "static const llvm::MCSchedClassDesc " + << PI->ModelName << "SchedClasses[] = {\n"; + + // The first class is always invalid. We no way to distinguish it except by + // name and position. + assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" + && "invalid class not first"); + OS << " {DBGFIELD(\"InvalidSchedClass\") " + << MCSchedClassDesc::InvalidNumMicroOps + << ", false, false, false, 0, 0, 0, 0, 0, 0},\n"; + + for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { + MCSchedClassDesc &MCDesc = SCTab[SCIdx]; + const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); + OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; + if (SchedClass.Name.size() < 18) + OS.indent(18 - SchedClass.Name.size()); + OS << MCDesc.NumMicroOps + << ", " << ( MCDesc.BeginGroup ? "true" : "false" ) + << ", " << ( MCDesc.EndGroup ? "true" : "false" ) + << ", " << ( MCDesc.RetireOOO ? "true" : "false" ) + << ", " << format("%2d", MCDesc.WriteProcResIdx) + << ", " << MCDesc.NumWriteProcResEntries + << ", " << format("%2d", MCDesc.WriteLatencyIdx) + << ", " << MCDesc.NumWriteLatencyEntries + << ", " << format("%2d", MCDesc.ReadAdvanceIdx) + << ", " << MCDesc.NumReadAdvanceEntries + << "}, // #" << SCIdx << '\n'; + } + OS << "}; // " << PI->ModelName << "SchedClasses\n"; + } +} + +unsigned PrinterLLVM::subtargetEmitRegisterFileTables( + CodeGenProcModel const &ProcModel) const { + // Print the RegisterCost table first. + OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n"; + OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName + << "RegisterCosts" + << "[] = {\n"; + + for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) { + // Skip register files with a default cost table. + if (RF.hasDefaultCosts()) + continue; + // Add entries to the cost table. + for (const CodeGenRegisterCost &RC : RF.Costs) { + OS << " { "; + Record *Rec = RC.RCDef; + if (Rec->getValue("Namespace")) + OS << Rec->getValueAsString("Namespace") << "::"; + OS << Rec->getName() << "RegClassID, " << RC.Cost << ", " + << RC.AllowMoveElimination << "},\n"; + } + } + OS << "};\n"; + + // Now generate a table with register file info. + OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, " + << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n"; + OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName + << "RegisterFiles" + << "[] = {\n" + << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n"; + unsigned CostTblIndex = 0; + + for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { + OS << " { "; + OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; + unsigned NumCostEntries = RD.Costs.size(); + OS << NumCostEntries << ", " << CostTblIndex << ", " + << RD.MaxMovesEliminatedPerCycle << ", " + << RD.AllowZeroMoveEliminationOnly << "},\n"; + CostTblIndex += NumCostEntries; + } + OS << "};\n"; + + return CostTblIndex; +} + +void PrinterLLVM::subtargetEmitMCExtraProcInfoTableHeader( + std::string const &ProcModelName) const { + OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModelName + << "ExtraInfo = {\n "; +} + +void PrinterLLVM::subtargetEmitMCExtraProcInfoTableEnd() const { OS << "};\n"; } + +void PrinterLLVM::subtargetEmitReorderBufferSize( + int64_t ReorderBufferSize) const { + OS << ReorderBufferSize << ", // ReorderBufferSize\n "; +} + +void PrinterLLVM::subtargetEmitMaxRetirePerCycle( + int64_t MaxRetirePerCycle) const { + OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n "; +} + +void PrinterLLVM::subtargetEmitRegisterFileInfo( + CodeGenProcModel const &ProcModel, unsigned NumRegisterFiles, + unsigned NumCostEntries) const { + if (NumRegisterFiles) + OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles); + else + OS << "nullptr,\n 0"; + + OS << ", // Number of register files.\n "; + if (NumCostEntries) + OS << ProcModel.ModelName << "RegisterCosts,\n "; + else + OS << "nullptr,\n "; + OS << NumCostEntries << ", // Number of register cost entries.\n"; +} + +void PrinterLLVM::subtargetEmitResourceDescriptorLoadQueue( + unsigned QueueID) const { + OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n"; +} + +void PrinterLLVM::subtargetEmitResourceDescriptorStoreQueue( + unsigned QueueID) const { + OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n"; +} + +void PrinterLLVM::subtargetEmitProcessorResourceSubUnits( + const CodeGenProcModel &ProcModel, + CodeGenSchedModels const &SchedModels) const { + OS << "\nstatic const unsigned " << ProcModel.ModelName + << "ProcResourceSubUnits[] = {\n" + << " 0, // Invalid\n"; + + for (unsigned I = 0, E = ProcModel.ProcResourceDefs.size(); I < E; ++I) { + Record *PRDef = ProcModel.ProcResourceDefs[I]; + if (!PRDef->isSubClassOf("ProcResGroup")) + continue; + RecVec const ResUnits = PRDef->getValueAsListOfDefs("Resources"); + for (Record *RUDef : ResUnits) { + Record *const RU = + SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc()); + for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) { + OS << " " << ProcModel.getProcResourceIdx(RU) << ", "; + } + } + OS << " // " << PRDef->getName() << "\n"; + } + OS << "};\n"; +} + +void PrinterLLVM::subtargetEmitMCProcResourceDescHeader( + std::string const &ProcModelName) const { + OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n"; + OS << "static const llvm::MCProcResourceDesc " << ProcModelName + << "ProcResources" + << "[] = {\n" + << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; +} + +void PrinterLLVM::subtargetEmitMCProcResourceDescEnd() const { OS << "};\n"; } + +void PrinterLLVM::subtargetEmitMCProcResourceDesc( + Record const *PRDef, Record const *SuperDef, + std::string const &ProcModelName, unsigned SubUnitsOffset, + unsigned SuperIdx, unsigned NumUnits, int BufferSize, unsigned I, + unsigned const SubUnitsBeginOffset) const { + // Emit the ProcResourceDesc + OS << " {\"" << PRDef->getName() << "\", "; + if (PRDef->getName().size() < 15) + OS.indent(15 - PRDef->getName().size()); + OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; + if (SubUnitsBeginOffset != SubUnitsOffset) { + OS << ProcModelName << "ProcResourceSubUnits + " << SubUnitsBeginOffset; + } else { + OS << "nullptr"; + } + OS << "}, // #" << I + 1; + if (SuperDef) + OS << ", Super=" << SuperDef->getName(); + OS << "\n"; +} + +// Emit either the value defined in the TableGen Record, or the default +// value defined in the C++ header. The Record is null if the processor does not +// define a model. +void PrinterLLVM::subtargetEmitProcessorProp(Record const *R, + StringRef const Name, + char Separator) const { + OS << " "; + int const V = R ? R->getValueAsInt(Name) : -1; + if (V >= 0) + OS << V << Separator << " // " << Name; + else + OS << "MCSchedModel::Default" << Name << Separator; + OS << '\n'; +} + +void PrinterLLVM::subtargetEmitProcModelHeader( + std::string const &ModelName) const { + OS << "\n"; + OS << "static const llvm::MCSchedModel " << ModelName << " = {\n"; +} + +void PrinterLLVM::subtargetEmitProcModel( + CodeGenProcModel const &PM, CodeGenSchedModels const &SchedModels) const { + bool PostRAScheduler = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); + + OS << " " << (PostRAScheduler ? "true" : "false") << ", // " + << "PostRAScheduler\n"; + + bool CompleteModel = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); + + OS << " " << (CompleteModel ? "true" : "false") << ", // " + << "CompleteModel\n"; + + bool EnableIntervals = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false); + + OS << " " << (EnableIntervals ? "true" : "false") << ", // " + << "EnableIntervals\n"; + + OS << " " << PM.Index << ", // Processor ID\n"; + if (PM.hasInstrSchedModel()) + OS << " " << PM.ModelName << "ProcResources" << ",\n" + << " " << PM.ModelName << "SchedClasses" << ",\n" + << " " << PM.ProcResourceDefs.size()+1 << ",\n" + << " " << (SchedModels.schedClassEnd() + - SchedModels.schedClassBegin()) << ",\n"; + else + OS << " nullptr, nullptr, 0, 0," + << " // No instruction-level machine model.\n"; + if (PM.hasItineraries()) + OS << " " << PM.ItinsDef->getName() << ",\n"; + else + OS << " nullptr, // No Itinerary\n"; + if (PM.hasExtraProcessorInfo()) + OS << " &" << PM.ModelName << "ExtraInfo,\n"; + else + OS << " nullptr // No extra processor descriptor\n"; + OS << "};\n"; +} + +void PrinterLLVM::subtargetEmitResolveVariantSchedClassImplHdr() const { + OS << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" + << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n"; +} + +void PrinterLLVM::subtargetEmitResolveVariantSchedClassImplEnd() const { + OS << "}\n"; +} + +void PrinterLLVM::subtargetEmitSchedClassSwitch() const { + OS << " switch (SchedClass) {\n"; +} + +void PrinterLLVM::subtargetEmitSchedClassCase(unsigned VC, + std::string const &SCName) const { + OS << " case " << VC << ": // " << SCName << '\n'; +} + +void PrinterLLVM::subtargetEmitSchedClassProcGuard( + unsigned Pi, bool OnlyExpandMCInstPredicates, + std::string const &ModelName) const { + OS << " "; + + // Emit a guard on the processor ID. + if (Pi != 0) { + OS << (OnlyExpandMCInstPredicates ? "if (CPUID == " + : "if (SchedModel->getProcessorID() == "); + OS << Pi << ") "; + OS << "{ // " << ModelName << '\n'; + } +} + +// Indent <= -1 (default = -1) means previous PE indent level. +void PrinterLLVM::subtargetEmitPredicates( + CodeGenSchedTransition const &T, CodeGenSchedClass const &SC, + bool (*IsTruePredicate)(Record const *Rec), int Indent) const { + if (Indent > -1) + PE->setIndentLevel(Indent); + std::string Buffer; + raw_string_ostream SS(Buffer); + + // If not all predicates are MCTrue, then we need an if-stmt. + unsigned const NumNonTruePreds = + T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate); + + SS.indent(PE->getIndentLevel() * 2); + + if (NumNonTruePreds) { + bool FirstNonTruePredicate = true; + SS << "if ("; + + PE->setIndentLevel(PE->getIndentLevel() + 2); + + for (const Record *Rec : T.PredTerm) { + // Skip predicates that evaluate to "true". + if (IsTruePredicate(Rec)) + continue; + + if (FirstNonTruePredicate) { + FirstNonTruePredicate = false; + } else { + SS << "\n"; + SS.indent(PE->getIndentLevel() * 2); + SS << "&& "; + } + + if (Rec->isSubClassOf("MCSchedPredicate")) { + PE->expandPredicate(SS, Rec->getValueAsDef("Pred")); + continue; + } + + // Expand this legacy predicate and wrap it around braces if there is more + // than one predicate to expand. + SS << ((NumNonTruePreds > 1) ? "(" : "") + << Rec->getValueAsString("Predicate") + << ((NumNonTruePreds > 1) ? ")" : ""); + } + + SS << ")\n"; // end of if-stmt + PE->decreaseIndentLevel(); + SS.indent(PE->getIndentLevel() * 2); + PE->decreaseIndentLevel(); + } + + SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; + OS << Buffer; +} + +void PrinterLLVM::subtargetEmitProcTransitionEnd() const { OS << " }\n"; } + +void PrinterLLVM::subtargetEmitSchedClassCaseEnd( + CodeGenSchedClass const &SC) const { + if (SC.isInferred()) + OS << " return " << SC.Index << ";\n"; + OS << " break;\n"; +} + +void PrinterLLVM::subtargetEmitSchedClassSwitchEnd() const { OS << " };\n"; } + +// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate +// epilogue code for the auto-generated helper. +void PrinterLLVM::subtargetEmitSchedModelHelperEpilogue( + bool ShouldReturnZero) const { + if (ShouldReturnZero) { + OS << " // Don't know how to resolve this scheduling class.\n" + << " return 0;\n"; + return; + } + + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; +} + +void PrinterLLVM::subtargetEmitGenMCSubtargetInfoClass( + std::string const &TargetName, bool OverrideGetHwMode) const { + OS << "struct " << TargetName + << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; + OS << " " << TargetName << "GenMCSubtargetInfo(const Triple &TT,\n" + << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n" + << " ArrayRef PF,\n" + << " ArrayRef PD,\n" + << " const MCWriteProcResEntry *WPR,\n" + << " const MCWriteLatencyEntry *WL,\n" + << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" + << " const unsigned *OC, const unsigned *FP) :\n" + << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n" + << " WPR, WL, RA, IS, OC, FP) { }\n\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" + << " const MCInst *MI, const MCInstrInfo *MCII,\n" + << " unsigned CPUID) const override {\n" + << " return " << TargetName << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"; + OS << " }\n"; + if (OverrideGetHwMode) + OS << " unsigned getHwMode() const override;\n"; + OS << "};\n"; +} + +void PrinterLLVM::subtargetEmitMCSubtargetInfoImpl( + std::string const &Target, unsigned NumFeatures, unsigned NumProcs, + bool SchedModelHasItin) const { + OS << "\nstatic inline MCSubtargetInfo *create" << Target + << "MCSubtargetInfoImpl(" + << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n"; + OS << " return new " << Target + << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, "; + if (NumFeatures) + OS << Target << "FeatureKV, "; + else + OS << "std::nullopt, "; + if (NumProcs) + OS << Target << "SubTypeKV, "; + else + OS << "std::nullopt, "; + OS << '\n'; OS.indent(22); + OS << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; + OS << '\n'; OS.indent(22); + if (SchedModelHasItin) { + OS << Target << "Stages, " + << Target << "OperandCycles, " + << Target << "ForwardingPaths"; + } else + OS << "nullptr, nullptr, nullptr"; + OS << ");\n}\n\n"; +} + +void PrinterLLVM::subtargetEmitIncludeSTIDesc() const { + OS << "#include \"llvm/Support/Debug.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; +} + +void PrinterLLVM::subtargetEmitDFAPacketizerClass( + CodeGenTarget &TGT, + std::string const &Target, std::string const &ClassName) const { + OS << "class DFAPacketizer;\n"; + OS << "namespace " << Target << "_MC {\n" + << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," + << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n" + << "} // end namespace " << Target << "_MC\n\n"; + OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" + << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " + << "StringRef TuneCPU, StringRef FS);\n" + << "public:\n" + << " unsigned resolveSchedClass(unsigned SchedClass, " + << " const MachineInstr *DefMI," + << " const TargetSchedModel *SchedModel) const override;\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass," + << " const MCInst *MI, const MCInstrInfo *MCII," + << " unsigned CPUID) const override;\n" + << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" + << " const;\n"; + if (TGT.getHwModes().getNumModeIds() > 1) + OS << " unsigned getHwMode() const override;\n"; + if (TGT.hasMacroFusion()) + OS << " std::vector getMacroFusions() const " + "override;\n"; +} + +void PrinterLLVM::subtargetEmitDFAPacketizerClassEnd() const { OS << "};\n"; } + +void PrinterLLVM::subtargetEmitSTICtor() const { + OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; +} + +void PrinterLLVM::subtargetEmitExternKVArrays(std::string const &TargetName, + bool SchedModelsHasItin) const { + OS << "extern const llvm::SubtargetFeatureKV " << TargetName + << "FeatureKV[];\n"; + OS << "extern const llvm::SubtargetSubTypeKV " << TargetName + << "SubTypeKV[];\n"; + OS << "extern const llvm::MCWriteProcResEntry " << TargetName + << "WriteProcResTable[];\n"; + OS << "extern const llvm::MCWriteLatencyEntry " << TargetName + << "WriteLatencyTable[];\n"; + OS << "extern const llvm::MCReadAdvanceEntry " << TargetName + << "ReadAdvanceTable[];\n"; + + if (SchedModelsHasItin) { + OS << "extern const llvm::InstrStage " << TargetName << "Stages[];\n"; + OS << "extern const unsigned " << TargetName << "OperandCycles[];\n"; + OS << "extern const unsigned " << TargetName << "ForwardingPaths[];\n"; + } +} + +void PrinterLLVM::subtargetEmitClassDefs(std::string const &Target, + std::string const &ClassName, + unsigned NumFeatures, + unsigned NumProcs, + bool SchedModelsHasItin) const { + OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " + << "StringRef TuneCPU, StringRef FS)\n" + << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; + if (NumFeatures) + OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; + else + OS << "std::nullopt, "; + if (NumProcs) + OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; + else + OS << "std::nullopt, "; + OS << '\n'; OS.indent(24); + OS << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; + OS << '\n'; OS.indent(24); + if (SchedModelsHasItin) { + OS << Target << "Stages, " + << Target << "OperandCycles, " + << Target << "ForwardingPaths"; + } else + OS << "nullptr, nullptr, nullptr"; + OS << ") {}\n\n"; +} + +void PrinterLLVM::subtargetEmitResolveSchedClassHdr( + std::string const &ClassName) const { + OS << "unsigned " << ClassName + << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," + << " const TargetSchedModel *SchedModel) const {\n"; +} + +void PrinterLLVM::subtargetEmitResolveSchedClassEnd( + std::string const &ClassName) const { + OS << "} // " << ClassName << "::resolveSchedClass\n\n"; +} + +void PrinterLLVM::subtargetEmitResolveVariantSchedClass( + std::string const &TargetName, std::string const &ClassName) const { + OS << "unsigned " << ClassName + << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," + << " const MCInstrInfo *MCII, unsigned CPUID) const {\n" + << " return " << TargetName << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n" + << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; +} + +void PrinterLLVM::subtargetEmitPredicateProlog( + const RecordKeeper &Records) const { + std::string Buffer; + raw_string_ostream Stream(Buffer); + + // Collect all the PredicateProlog records and print them to the output + // stream. + std::vector Prologs = + Records.getAllDerivedDefinitions("PredicateProlog"); + llvm::sort(Prologs, LessRecord()); + for (Record *P : Prologs) + Stream << P->getValueAsString("Code") << '\n'; + + OS << Buffer; +} + +void PrinterLLVM::subtargetEmitParseFeaturesFunction( + std::string const &Target, + std::vector const &Features) const { + OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" + << "// subtarget options.\n" + << "void llvm::"; + OS << Target; + OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, " + << "StringRef FS) {\n" + << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" + << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n" + << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n"; + + if (Features.empty()) { + OS << "}\n"; + return; + } + + OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n" + << " const FeatureBitset &Bits = getFeatureBits();\n"; + + for (Record *R : Features) { + // Next record + StringRef Instance = R->getName(); + StringRef Value = R->getValueAsString("Value"); + StringRef FieldName = R->getValueAsString("FieldName"); + + if (Value=="true" || Value=="false") + OS << " if (Bits[" << Target << "::" + << Instance << "]) " + << FieldName << " = " << Value << ";\n"; + else + OS << " if (Bits[" << Target << "::" + << Instance << "] && " + << FieldName << " < " << Value << ") " + << FieldName << " = " << Value << ";\n"; + } + + OS << "}\n"; +} + +void PrinterLLVM::subtargetEmitExpandedSTIPreds( + StringRef const &TargetName, std::string const &ClassName, + CodeGenSchedModels const &SchedModels) { + initNewPE(TargetName); + PE->setClassPrefix(ClassName); + PE->setExpandDefinition(true); + PE->setByRef(false); + PE->setIndentLevel(0); + + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE->expandSTIPredicate(OS, Fn); +} + +void PrinterLLVM::subtargetPrepareSchedClassPreds( + StringRef const &TargetName, bool OnlyExpandMCInstPredicates) { + initNewPE(TargetName); + PE->setByRef(false); + PE->setExpandForMC(OnlyExpandMCInstPredicates); +} + +void PrinterLLVM::subtargetEmitExpandedSTIPredsMCAnaDecl( + StringRef const &TargetName, CodeGenSchedModels const &SchedModels) { + initNewPE(TargetName); + PE->setExpandForMC(true); + PE->setByRef(true); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE->expandSTIPredicate(OS, Fn); +} + +void PrinterLLVM::subtargetEmitExpandedSTIPredsMCAnaDefs( + StringRef const &TargetName, std::string const &ClassPrefix, + CodeGenSchedModels const &SchedModels) const { + // Predicate expander was initialized before. + PE->setExpandDefinition(true); + PE->setClassPrefix(ClassPrefix); + PE->setIndentLevel(0); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE->expandSTIPredicate(OS, Fn); +} + +void PrinterLLVM::subtargetEmitExpandedSTIPredsHeader( + StringRef const &TargetName, CodeGenSchedModels const &SchedModels) { + initNewPE(TargetName); + PE->setByRef(false); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE->expandSTIPredicate(OS, Fn); +} + +void PrinterLLVM::subtargetEmitStageAndSycleTables( + std::string const &StageTable, std::string const &OperandCycleTable, + std::string const &BypassTable) const { + OS << StageTable; + OS << OperandCycleTable; + OS << BypassTable; +} + +//--------------------------- +// Backend: InstrInfoEmitter +//--------------------------- + +void PrinterLLVM::instrInfoEmitSourceFileHeader() const { + emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS); +} + +void PrinterLLVM::instrInfoEmitSetGetComputeFeatureMacro() const { + OS << "#if (defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)) " + << "||\\\n" + << " defined(GET_AVAILABLE_OPCODE_CHECKER)\n" + << "#define GET_COMPUTE_FEATURES\n" + << "#endif\n"; +} + +void PrinterLLVM::instrInfoSetOperandInfoStr( + std::string &Res, Record const *OpR, CGIOperandList::OperandInfo const &Op, + CGIOperandList::ConstraintInfo const &Constraint) const { + if (OpR->isSubClassOf("RegisterOperand")) + OpR = OpR->getValueAsDef("RegClass"); + if (OpR->isSubClassOf("RegisterClass")) + Res += getQualifiedName(OpR) + "RegClassID, "; + else if (OpR->isSubClassOf("PointerLikeRegClass")) + Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; + else + // -1 means the operand does not have a fixed register class. + Res += "-1, "; + + // Fill in applicable flags. + Res += "0"; + + // Ptr value whose register class is resolved via callback. + if (OpR->isSubClassOf("PointerLikeRegClass")) + Res += "|(1<isSubClassOf("PredicateOp")) + Res += "|(1<isSubClassOf("OptionalDefOperand")) + Res += "|(1<isSubClassOf("BranchTargetOperand")) + Res += "|(1<> ImplicitLists, + std::map, unsigned> &EmittedLists + ) const { + for (auto &List : ImplicitLists) { + OS << " /* " << EmittedLists[List] << " */"; + for (auto &Reg : List) + OS << ' ' << getQualifiedName(Reg) << ','; + OS << '\n'; + } +} + +void PrinterLLVM::instrInfoEmitRecord(CodeGenSchedModels const &SchedModels, + CodeGenInstruction const &Inst, + unsigned Num, int MinOperands) const { + OS << " { "; + OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t" + << Inst.TheDef->getValueAsInt("Size") << ",\t" + << SchedModels.getSchedClassIdx(Inst) << ",\t"; +} + +void PrinterLLVM::instrInfoEmitTargetIndepFlags( + CodeGenInstruction const &Inst, bool GetAllowRegisterRenaming) const { + // clang-format off + if (Inst.isPreISelOpcode) OS << "|(1ULL<, unsigned> &EmittedLists, + std::vector const &ImplicitOps) const { + OS << Inst.ImplicitUses.size() << ",\t" << Inst.ImplicitDefs.size() << ",\t"; + OS << TargetName << "ImpOpBase + " << EmittedLists[ImplicitOps] + << ",\t"; +} + +void PrinterLLVM::instrInfoEmitOperandInfoOffset( + StringRef TargetName, + std::vector const &OperandInfo, + OperandInfoMapTy const &OperandInfoMap) const { + OS << OperandInfoMap.find(OperandInfo)->second << ",\t0"; +} + +void PrinterLLVM::instrInfoEmitOperandInfo(OperandInfoListTy &OperandInfoList) const { + unsigned Offset = 0; + for (auto &OperandInfo : OperandInfoList) { + OS << " /* " << Offset << " */"; + for (auto &Info : OperandInfo) + OS << " { " << Info << " },"; + OS << '\n'; + Offset += OperandInfo.size(); + } +} + +void PrinterLLVM::instrInfoEmitRecordEnd(unsigned InstNum, + std::string const &InstName) const { + OS << " }, // Inst #" << InstNum << " = " << InstName << "\n"; +} + +void PrinterLLVM::instrInfoEmitMCInstrDescDecl( + std::string const &TargetName, + unsigned NumberedInstructionsSize, + unsigned OperandInfoSize, unsigned ImplicitListSize) const { + OS << "struct " << TargetName << "InstrTable {\n"; + OS << " MCInstrDesc Insts[" << NumberedInstructionsSize << "];\n"; + OS << " static_assert(alignof(MCInstrDesc) >= alignof(MCOperandInfo), " + "\"Unwanted padding between Insts and OperandInfo\");\n"; + OS << " MCOperandInfo OperandInfo[" << OperandInfoSize << "];\n"; + OS << " static_assert(alignof(MCOperandInfo) >= alignof(MCPhysReg), " + "\"Unwanted padding between OperandInfo and ImplicitOps\");\n"; + OS << " MCPhysReg ImplicitOps[" << ImplicitListSize << "];\n"; + OS << "};\n\n"; +} + +void PrinterLLVM::instrInfoEmitStringLiteralDef( + std::string const &TargetName, + SequenceToOffsetTable InstrNames) const { + InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + + "InstrNameData[]"); +} + +void PrinterLLVM::instrInfoEmitInstrNameIndices( + std::string const &TargetName, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const { + OS << "extern const unsigned " << TargetName << "InstrNameIndices[] = {"; + unsigned Num = 0; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + // Newline every eight entries. + if (Num % 8 == 0) + OS << "\n "; + OS << InstrNames.get(std::string(Inst->TheDef->getName())) << "U, "; + ++Num; + } + OS << "\n};\n\n"; +} + +void PrinterLLVM::instrInfoEmitInstrDeprFeatures( + std::string const &TargetName, std::string const &TargetNamespace, + ArrayRef const &NumberedInstructions, + SequenceToOffsetTable const &InstrNames) const { + OS << "extern const uint8_t " << TargetName + << "InstrDeprecationFeatures[] = {"; + unsigned Num = 0; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + if (Num % 8 == 0) + OS << "\n "; + if (!Inst->HasComplexDeprecationPredicate && + !Inst->DeprecatedReason.empty()) + OS << TargetNamespace << "::" << Inst->DeprecatedReason << ", "; + else + OS << "uint8_t(-1), "; + ++Num; + } + OS << "\n};\n\n"; +} + +void PrinterLLVM::instrInfoEmitInstrComplexDeprInfos( + std::string const &TargetName, + ArrayRef const &NumberedInstructions) const { + OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName + << "InstrComplexDeprecationInfos[] = {"; + unsigned Num = 0; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + if (Num % 8 == 0) + OS << "\n "; + if (Inst->HasComplexDeprecationPredicate) + // Emit a function pointer to the complex predicate method. + OS << "&get" << Inst->DeprecatedReason << "DeprecationInfo, "; + else + OS << "nullptr, "; + ++Num; + } + OS << "\n};\n\n"; +} + +void PrinterLLVM::instrInfoEmitMCInstrInfoInitRoutine( + std::string const &TargetName, unsigned NumberedInstrSize, + bool HasDeprecationFeatures, bool HasComplexDeprecationInfos) const { + OS << "static inline void Init" << TargetName + << "MCInstrInfo(MCInstrInfo *II) {\n"; + OS << " II->InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName + << "InstrNameIndices, " << TargetName << "InstrNameData, "; + if (HasDeprecationFeatures) + OS << TargetName << "InstrDeprecationFeatures, "; + else + OS << "nullptr, "; + if (HasComplexDeprecationInfos) + OS << TargetName << "InstrComplexDeprecationInfos, "; + else + OS << "nullptr, "; + OS << NumberedInstrSize << ");\n}\n\n"; +} + +void PrinterLLVM::instrInfoEmitHeader(std::string const &TargetName) const { + std::string ClassName = TargetName + "GenInstrInfo"; + OS << "struct " << ClassName << " : public TargetInstrInfo {\n" + << " explicit " << ClassName + << "(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, " + "unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u);\n" + << " ~" << ClassName << "() override = default;\n"; + OS << "\n};\n"; +} + +void PrinterLLVM::instrInfoEmitClassStruct(std::string const &ClassName) const { + OS << "struct " << ClassName << " : public TargetInstrInfo {\n" + << " explicit " << ClassName + << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode " + "= -1, int ReturnOpcode = -1);\n" + << " ~" << ClassName << "() override = default;\n"; + OS << "\n};\n"; +} + +void PrinterLLVM::instrInfoEmitTIIHelperMethod(StringRef const &TargetName, + Record const *Rec, + bool ExpandDefinition) const { + OS << (ExpandDefinition ? "" : "static ") << "bool "; + if (ExpandDefinition) + OS << TargetName << "InstrInfo::"; + OS << Rec->getValueAsString("FunctionName"); + OS << "(const MachineInstr &MI)"; + if (!ExpandDefinition) { + OS << ";\n"; + return; + } + + OS << " {\n"; + OS.indent(PE->getIndentLevel() * 2); + PE->expandStatement(OS, Rec->getValueAsDef("Body")); + OS << "\n}\n\n"; +} + +void PrinterLLVM::instrInfoEmitExternArrays( + std::string const &TargetName, bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const { + OS << "extern const " << TargetName << "InstrTable " << TargetName + << "Descs;\n"; + OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; + OS << "extern const char " << TargetName << "InstrNameData[];\n"; + if (HasDeprecationFeatures) + OS << "extern const uint8_t " << TargetName + << "InstrDeprecationFeatures[];\n"; + if (HasComplexDeprecationInfos) + OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName + << "InstrComplexDeprecationInfos[];\n"; +} + +void PrinterLLVM::instrInfoEmitMCInstrInfoInit( + std::string const &TargetName, + unsigned NumberedInstrSize, bool HasDeprecationFeatures, + bool HasComplexDeprecationInfos) const { + std::string ClassName = TargetName + "GenInstrInfo"; + OS << ClassName << "::" << ClassName + << "(unsigned CFSetupOpcode, unsigned CFDestroyOpcode, unsigned " + "CatchRetOpcode, unsigned ReturnOpcode)\n" + << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, " + "ReturnOpcode) {\n" + << " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName + << "InstrNameIndices, " << TargetName << "InstrNameData, "; + if (HasDeprecationFeatures) + OS << TargetName << "InstrDeprecationFeatures, "; + else + OS << "nullptr, "; + if (HasComplexDeprecationInfos) + OS << TargetName << "InstrComplexDeprecationInfos, "; + else + OS << "nullptr, "; + OS << NumberedInstrSize << ");\n}\n"; +} + +void PrinterLLVM::instrInfoEmitOperandEnum( + std::map const &Operands) const { + OS << "enum {\n"; + for (const auto &Op : Operands) + OS << " " << Op.first << " = " << Op.second << ",\n"; + + OS << " OPERAND_LAST"; + OS << "\n};\n"; +} + +void PrinterLLVM::instrInfoEmitGetNamedOperandIdx( + std::map const &Operands, + OpNameMapTy const &OperandMap) const { + OS << "LLVM_READONLY\n"; + OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n"; + if (!Operands.empty()) { + OS << " static const int16_t OperandMap [][" << Operands.size() + << "] = {\n"; + for (const auto &Entry : OperandMap) { + const std::map &OpList = Entry.first; + OS << "{"; + + // Emit a row of the OperandMap table + for (unsigned I = 0, E = Operands.size(); I != E; ++I) + OS << (OpList.count(I) == 0 ? -1 : (int)OpList.find(I)->second) << ", "; + + OS << "},\n"; + } + OS << "};\n"; + + OS << " switch(Opcode) {\n"; + unsigned TableIndex = 0; + for (const auto &Entry : OperandMap) { + for (const std::string &Name : Entry.second) + OS << " case " << Name << ":\n"; + + OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n"; + } + OS << " default: return -1;\n"; + OS << " }\n"; + } else { + // There are no operands, so no need to emit anything + OS << " return -1;\n"; + } + OS << "}\n"; +} + +void PrinterLLVM::instrInfoEmitOpTypeEnumPartI() const { + OS << "enum OperandType {\n"; +} + +void PrinterLLVM::instrInfoEmitOpTypeEnumPartII(StringRef const &OpName, + unsigned EnumVal) const { + OS << " " << OpName << " = " << EnumVal << ",\n"; +} + +void PrinterLLVM::instrInfoEmitOpTypeEnumPartIII() const { + OS << " OPERAND_TYPE_LIST_END" + << "\n};\n"; +} + +void PrinterLLVM::instrInfoEmitOpTypeOffsetTable( + std::vector OperandOffsets, unsigned OpRecSize, + ArrayRef const &NumberedInstructions) const { + auto getInstrName = [&](int I) -> StringRef { + return NumberedInstructions[I]->TheDef->getName(); + }; + OS << " static const " << getMinimalTypeForRange(OpRecSize); + OS << " Offsets[] = {\n"; + for (int I = 0, E = OperandOffsets.size(); I != E; ++I) { + OS << " /* " << getInstrName(I) << " */\n"; + OS << " " << OperandOffsets[I] << ",\n"; + } + OS << " };\n"; +} + +void PrinterLLVM::instrInfoEmitOpcodeOpTypesTable( + unsigned EnumVal, std::vector const &OperandRecords, + std::vector OperandOffsets, + ArrayRef const &NumberedInstructions) const { + auto getInstrName = [&](int I) -> StringRef { + return NumberedInstructions[I]->TheDef->getName(); + }; + OS << "\n using namespace OpTypes;\n"; + OS << " static"; + OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t"); + OS << " OpcodeOperandTypes[] = {\n "; + for (int I = 0, E = OperandRecords.size(), CurOffset = 0; I != E; ++I) { + // We print each Opcode's operands in its own row. + if (I == OperandOffsets[CurOffset]) { + OS << "\n /* " << getInstrName(CurOffset) << " */\n "; + while (OperandOffsets[++CurOffset] == I) + OS << "/* " << getInstrName(CurOffset) << " */\n "; + } + Record *OpR = OperandRecords[I]; + if ((OpR->isSubClassOf("Operand") || + OpR->isSubClassOf("RegisterOperand") || + OpR->isSubClassOf("RegisterClass")) && + !OpR->isAnonymous()) + OS << OpR->getName(); + else + OS << -1; + OS << ", "; + } + OS << "\n };\n"; +} + +void PrinterLLVM::instrInfoEmitGetOpTypeHdr() const { + OS << "LLVM_READONLY\n"; + OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n"; +} + +void PrinterLLVM::instrInfoEmitGetOpTypeReturn() const { + OS << " return OpcodeOperandTypes[Offsets[Opcode] + OpIdx];\n"; +} + +void PrinterLLVM::instrInfoEmitGetOpTypeUnreachable() const { + OS << " llvm_unreachable(\"No instructions defined\");\n"; +} + +void PrinterLLVM::instrInfoEmitGetOpTypeEnd() const { OS << "}\n"; } + +void PrinterLLVM::instrInfoEmitGetMemOpSizeHdr() const { + OS << "LLVM_READONLY\n"; + OS << "static int getMemOperandSize(int OpType) {\n"; + OS << " switch (OpType) {\n"; +} + +void PrinterLLVM::instrInfoEmitGetOpMemSizeTbl( + std::map> &SizeToOperandName) const { + OS << " default: return 0;\n"; + for (const auto &KV : SizeToOperandName) { + for (const StringRef &OperandName : KV.second) + OS << " case OpTypes::" << OperandName << ":\n"; + OS << " return " << KV.first << ";\n\n"; + } + OS << " }\n}\n"; +} + +std::string +PrinterLLVM::instrInfoGetInstMapEntry(StringRef const &Namespace, + StringRef const &InstrName) const { + return Namespace.str() + "::" + InstrName.str(); +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpSizeHdr() const { + OS << "LLVM_READONLY static unsigned\n"; + OS << "getLogicalOperandSize(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpSizeTable( + size_t LogicalOpListSize, + std::vector *> const &LogicalOpSizeList) const { + OS << " static const unsigned SizeMap[][" << LogicalOpListSize << "] = {\n"; + for (auto &R : LogicalOpSizeList) { + const auto &Row = *R; + OS << " {"; + int I; + for (I = 0; I < static_cast(Row.size()); ++I) { + OS << Row[I] << ", "; + } + for (; I < static_cast(LogicalOpListSize); ++I) { + OS << "0, "; + } + OS << "}, "; + OS << "\n"; + } + OS << " };\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpSizeSwitch( + std::map> InstMap) const { + OS << " switch (Opcode) {\n"; + OS << " default: return LogicalOpIdx;\n"; + for (auto &P : InstMap) { + auto OpMapIdx = P.first; + const auto &Insts = P.second; + for (const auto &Inst : Insts) { + OS << " case " << Inst << ":\n"; + } + OS << " return SizeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; + } + OS << " }\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpSizeReturn() const { + OS << " return LogicalOpIdx;\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpSizeEnd() const { OS << "}\n"; } + +void PrinterLLVM::instrInfoEmitGetLogicalOpIdx() const { + OS << "LLVM_READONLY static inline unsigned\n"; + OS << "getLogicalOperandIdx(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + OS << " auto S = 0U;\n"; + OS << " for (auto i = 0U; i < LogicalOpIdx; ++i)\n"; + OS << " S += getLogicalOperandSize(Opcode, i);\n"; + OS << " return S;\n"; + OS << "}\n"; +} + +std::string +PrinterLLVM::instrInfoGetOpTypeListEntry(StringRef const &Namespace, + StringRef const &OpName) const { + return Namespace.str() + "::OpTypes::" + OpName.str(); +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpTypeHdr() const { + OS << "LLVM_READONLY static int\n"; + OS << "getLogicalOperandType(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; +} +void PrinterLLVM::instrInfoEmitGetLogicalOpTypeTable( + size_t OpTypeListSize, + std::vector *> const &LogicalOpTypeList) + const { + OS << " static const int TypeMap[][" << OpTypeListSize << "] = {\n"; + for (int R = 0, Rs = LogicalOpTypeList.size(); R < Rs; ++R) { + const auto &Row = *LogicalOpTypeList[R]; + OS << " {"; + int I, S = Row.size(); + for (I = 0; I < S; ++I) { + if (I > 0) + OS << ", "; + OS << Row[I]; + } + for (; I < static_cast(OpTypeListSize); ++I) { + if (I > 0) + OS << ", "; + OS << "-1"; + } + OS << "}"; + if (R != Rs - 1) + OS << ","; + OS << "\n"; + } + OS << " };\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpTypeSwitch( + std::map> InstMap) const { + OS << " switch (Opcode) {\n"; + OS << " default: return -1;\n"; + for (auto &P : InstMap) { + auto OpMapIdx = P.first; + const auto &Insts = P.second; + for (const auto &Inst : Insts) { + OS << " case " << Inst << ":\n"; + } + OS << " return TypeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; + } + OS << " }\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpTypeReturn() const { + OS << " return -1;\n"; +} + +void PrinterLLVM::instrInfoEmitGetLogicalOpTypeEnd() const { OS << "}\n"; } + +void PrinterLLVM::instrInfoEmitDeclareMCInstFeatureClasses() const { + OS << "class MCInst;\n"; + OS << "class FeatureBitset;\n\n"; +} + +void PrinterLLVM::instrInfoEmitPredFcnDecl(RecVec const &TIIPredicates) const { + for (const Record *Rec : TIIPredicates) { + OS << "bool " << Rec->getValueAsString("FunctionName") + << "(const MCInst &MI);\n"; + } + + OS << "void verifyInstructionPredicates(unsigned Opcode, const FeatureBitset " + "&Features);\n"; +} + +void PrinterLLVM::instrInfoEmitPredFcnImpl(StringRef const &TargetName, + RecVec const &TIIPredicates) { + initNewPE(TargetName); + PE->setExpandForMC(true); + for (const Record *Rec : TIIPredicates) { + OS << "bool " << Rec->getValueAsString("FunctionName"); + OS << "(const MCInst &MI) {\n"; + + OS.indent(PE->getIndentLevel() * 2); + PE->expandStatement(OS, Rec->getValueAsDef("Body")); + OS << "\n}\n\n"; + } +} + +void PrinterLLVM::instrInfoEmitMacroDefineCheck() const { + OS << "#if (defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)) " + << "||\\\n" + << " defined(GET_AVAILABLE_OPCODE_CHECKER)\n" + << "#define GET_COMPUTE_FEATURES\n" + << "#endif\n"; +} + +void PrinterLLVM::instrInfoEmitSubtargetFeatureBitEnumeration( + std::map &SubtargetFeatures) + const { + // Emit the subtarget feature enumeration. + SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, + OS); +} + +void PrinterLLVM::instrInfoEmitEmitSTFNameTable( + std::map &SubtargetFeatures) + const { + OS << "#ifndef NDEBUG\n"; + SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); + OS << "#endif // NDEBUG\n\n"; +} + +void PrinterLLVM::instrInfoEmitFeatureBitsEnum( + std::vector> const &FeatureBitsets) const { + OS << "inline FeatureBitset computeRequiredFeatures(unsigned Opcode) {\n" + << " enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n" + << " CEFBS_None,\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; + } + OS << " };\n\n"; +} + +void PrinterLLVM::instrInfoEmitFeatureBitsArray( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures) const { + OS << " static constexpr FeatureBitset FeatureBitsets[] = {\n" + << " {}, // CEFBS_None\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " {"; + for (const auto &Feature : FeatureBitset) { + const auto &I = SubtargetFeatures.find(Feature); + assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); + OS << I->second.getEnumBitName() << ", "; + } + OS << "},\n"; + } + OS << " };\n"; +} + +void PrinterLLVM::instrInfoEmitRequiredFeatureRefs( + std::vector> const &FeatureBitsets, + std::map const + &SubtargetFeatures, + CodeGenTarget const &Target) const { + OS << " static constexpr " << getMinimalTypeForRange(FeatureBitsets.size()) + << " RequiredFeaturesRefs[] = {\n"; + unsigned InstIdx = 0; + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { + OS << " CEFBS"; + unsigned NumPredicates = 0; + for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) { + const auto &I = SubtargetFeatures.find(Predicate); + if (I != SubtargetFeatures.end()) { + OS << '_' << I->second.TheDef->getName(); + NumPredicates++; + } + } + if (!NumPredicates) + OS << "_None"; + OS << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n"; + InstIdx++; + } + OS << " };\n\n" + << " assert(Opcode < " << InstIdx << ");\n" + << " return FeatureBitsets[RequiredFeaturesRefs[Opcode]];\n" + << "}\n\n"; +} + +void PrinterLLVM::instrInfoEmitOpcodeChecker() const { + OS << "bool isOpcodeAvailable(" + << "unsigned Opcode, const FeatureBitset &Features) {\n" + << " FeatureBitset AvailableFeatures = " + << "computeAvailableFeatures(Features);\n" + << " FeatureBitset RequiredFeatures = " + << "computeRequiredFeatures(Opcode);\n" + << " FeatureBitset MissingFeatures =\n" + << " (AvailableFeatures & RequiredFeatures) ^\n" + << " RequiredFeatures;\n" + << " return !MissingFeatures.any();\n" + << "}\n"; +} + +void PrinterLLVM::instrInfoEmitInstrPredVerifierIncludes() const { + OS << "#include \n\n"; +} + +void PrinterLLVM::instrInfoEmitPredicateVerifier(StringRef const &TargetName) const { + OS << "void verifyInstructionPredicates(\n" + << " unsigned Opcode, const FeatureBitset &Features) {\n" + << "#ifndef NDEBUG\n"; + OS << " FeatureBitset AvailableFeatures = " + "computeAvailableFeatures(Features);\n"; + OS << " FeatureBitset RequiredFeatures = " + << "computeRequiredFeatures(Opcode);\n"; + OS << " FeatureBitset MissingFeatures =\n" + << " (AvailableFeatures & RequiredFeatures) ^\n" + << " RequiredFeatures;\n" + << " if (MissingFeatures.any()) {\n" + << " std::ostringstream Msg;\n" + << " Msg << \"Attempting to emit \" << &" << TargetName + << "InstrNameData[" << TargetName << "InstrNameIndices[Opcode]]\n" + << " << \" instruction but the \";\n" + << " for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)\n" + << " if (MissingFeatures.test(i))\n" + << " Msg << SubtargetFeatureNames[i] << \" \";\n" + << " Msg << \"predicate(s) are not met\";\n" + << " report_fatal_error(Msg.str().c_str());\n" + << " }\n" + << "#endif // NDEBUG\n}\n"; +} + +void PrinterLLVM::instrInfoEmitEnums( + CodeGenTarget const &Target, StringRef const &Namespace, + CodeGenSchedModels const &SchedModels) const { + emitIncludeToggle("GET_INSTRINFO_ENUM", true); + + emitNamespace("llvm", true); + // We must emit the PHI opcode first... + emitNamespace(Namespace.str(), true); + unsigned Num = 0; + OS << " enum {\n"; + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) + OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n"; + OS << " INSTRUCTION_LIST_END = " << Num << "\n"; + OS << " };\n\n"; + emitNamespace(Namespace.str(), false); + emitNamespace("llvm", false); + emitIncludeToggle("GET_INSTRINFO_ENUM", false); + + emitIncludeToggle("GET_INSTRINFO_SCHED_ENUM", true); + emitNamespace("llvm", true); + emitNamespace(Namespace.str(), true); + emitNamespace("Sched", true); + Num = 0; + OS << " enum {\n"; + for (const auto &Class : SchedModels.explicit_classes()) + OS << " " << Class.Name << "\t= " << Num++ << ",\n"; + OS << " SCHED_LIST_END = " << Num << "\n"; + OS << " };\n"; + emitNamespace("Sched", false); + emitNamespace(Namespace.str(), false); + emitNamespace("llvm", false); + + emitIncludeToggle("GET_INSTRINFO_SCHED_ENUM", false); +} + +void PrinterLLVM::instrInfoEmitTIIPredicates(StringRef const &TargetName, + RecVec const &TIIPredicates, + bool ExpandDefinition) { + initNewPE(TargetName); + PE->setExpandForMC(false); + + for (const Record *Rec : TIIPredicates) { + instrInfoEmitTIIHelperMethod(TargetName, Rec, ExpandDefinition); + } +} + +void PrinterLLVM::instrInfoEmitComputeAssemblerAvailableFeatures( + StringRef const &TargetName, + std::map &SubtargetFeatures) + const { + OS << "inline "; + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( + TargetName, "", "computeAvailableFeatures", SubtargetFeatures, OS); +} + +//-------------------------- +// Backend: AsmMatcher +//-------------------------- + +void PrinterLLVM::asmMatcherEmitSourceFileHeader( + std::string const &Desc) const { + emitSourceFileHeader(Desc, OS); +} + +void PrinterLLVM::asmMatcherEmitDeclarations(bool HasOptionalOperands, + bool ReportMultipleNearMisses, + bool HasOperandInfos) const { + OS << " // This should be included into the middle of the declaration of\n"; + OS << " // your subclasses implementation of MCTargetAsmParser.\n"; + OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset &FB) const;\n"; + if (HasOptionalOperands) { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask);\n"; + } else { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands);\n"; + } + OS << " void convertToMapAndConstraints(unsigned Kind,\n "; + OS << " const OperandVector &Operands) override;\n"; + OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" + << " MCInst &Inst,\n"; + if (ReportMultipleNearMisses) + OS << " SmallVectorImpl *NearMisses,\n"; + else + OS << " uint64_t &ErrorInfo,\n" + << " FeatureBitset &MissingFeatures,\n"; + OS << " bool matchingInlineAsm,\n" + << " unsigned VariantID = 0);\n"; + if (!ReportMultipleNearMisses) + OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n" + << " MCInst &Inst,\n" + << " uint64_t &ErrorInfo,\n" + << " bool matchingInlineAsm,\n" + << " unsigned VariantID = 0) {\n" + << " FeatureBitset MissingFeatures;\n" + << " return MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,\n" + << " matchingInlineAsm, VariantID);\n" + << " }\n\n"; + + + if (!HasOperandInfos) { + OS << " ParseStatus MatchOperandParserImpl(\n"; + OS << " OperandVector &Operands,\n"; + OS << " StringRef Mnemonic,\n"; + OS << " bool ParseForAllFeatures = false);\n"; + + OS << " ParseStatus tryCustomParseOperand(\n"; + OS << " OperandVector &Operands,\n"; + OS << " unsigned MCK);\n\n"; + } +} + +void PrinterLLVM::asmMatcherEmitOperandDiagTypes( + std::set const Types) const { + for (StringRef Type : Types) + OS << " Match_" << Type << ",\n"; + OS << " END_OPERAND_DIAGNOSTIC_TYPES\n"; +} + +/// emitGetSubtargetFeatureName - Emit the helper function to get the +/// user-level name for a subtarget feature. +void PrinterLLVM::asmMatcherEmitGetSubtargetFeatureName( + std::map const + SubtargetFeatures) const { + OS << "// User-level names for subtarget features that participate in\n" + << "// instruction matching.\n" + << "static const char *getSubtargetFeatureName(uint64_t Val) {\n"; + if (!SubtargetFeatures.empty()) { + OS << " switch(Val) {\n"; + for (const auto &SF : SubtargetFeatures) { + const SubtargetFeatureInfo &SFI = SF.second; + // FIXME: Totally just a placeholder name to get the algorithm working. + OS << " case " << SFI.getEnumBitName() << ": return \"" + << SFI.TheDef->getValueAsString("PredicateName") << "\";\n"; + } + OS << " default: return \"(unknown)\";\n"; + OS << " }\n"; + } else { + // Nothing to emit, so skip the switch + OS << " return \"(unknown)\";\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionI( + StringRef const &TargetName, StringRef const &ClassName, + std::string const &TargetOperandClass, bool HasOptionalOperands, + size_t MaxNumOperands) const { + if (HasOptionalOperands) { + *CvtOS << "void " << TargetName << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask) {\n"; + } else { + *CvtOS << "void " << TargetName << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands) {\n"; + } + *CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; + *CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n"; + if (HasOptionalOperands) { + *CvtOS << " unsigned DefaultsOffset[" << (MaxNumOperands + 1) + << "] = { 0 };\n"; + *CvtOS << " assert(OptionalOperandsMask.size() == " << (MaxNumOperands) + << ");\n"; + *CvtOS << " for (unsigned i = 0, NumDefaults = 0; i < " << (MaxNumOperands) + << "; ++i) {\n"; + *CvtOS << " DefaultsOffset[i + 1] = NumDefaults;\n"; + *CvtOS << " NumDefaults += (OptionalOperandsMask[i] ? 1 : 0);\n"; + *CvtOS << " }\n"; + } + *CvtOS << " unsigned OpIdx;\n"; + *CvtOS << " Inst.setOpcode(Opcode);\n"; + *CvtOS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; + if (HasOptionalOperands) { + *CvtOS << " OpIdx = *(p + 1) - DefaultsOffset[*(p + 1)];\n"; + } else { + *CvtOS << " OpIdx = *(p + 1);\n"; + } + *CvtOS << " switch (*p) {\n"; + *CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n"; + *CvtOS << " case CVT_Reg:\n"; + *CvtOS << " static_cast<" << TargetOperandClass + << " &>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; + *CvtOS << " break;\n"; + *CvtOS << " case CVT_Tied: {\n"; + *CvtOS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; + *CvtOS + << " std::begin(TiedAsmOperandTable)) &&\n"; + *CvtOS << " \"Tied operand not found\");\n"; + *CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n"; + *CvtOS << " if (TiedResOpnd != (uint8_t)-1)\n"; + *CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n"; + *CvtOS << " break;\n"; + *CvtOS << " }\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionII( + std::string const &EnumName, StringRef const &AsmMatchConverter) const { + *CvtOS << " case CVT_" << EnumName << ":\n" + << " " << AsmMatchConverter << "(Inst, Operands);\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionIII( + std::string const &EnumName, std::string const TargetOperandClass, + bool HasOptionalOperands, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const { + *CvtOS << " case " << EnumName << ":\n"; + if (Op.Class->IsOptional) { + // If optional operand is not present in actual instruction then we + // should call its DefaultMethod before RenderMethod + assert(HasOptionalOperands); + *CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n" + << " " << Op.Class->DefaultMethod << "()" + << "->" << Op.Class->RenderMethod << "(Inst, " + << OpInfo.MINumOperands << ");\n" + << " } else {\n" + << " static_cast<" << TargetOperandClass + << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod << "(Inst, " + << OpInfo.MINumOperands << ");\n" + << " }\n"; + } else { + *CvtOS << " static_cast<" << TargetOperandClass + << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod << "(Inst, " + << OpInfo.MINumOperands << ");\n"; + } + *CvtOS << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionIV( + std::string const &EnumName, int64_t Val) const { + *CvtOS << " case " << EnumName << ":\n" + << " Inst.addOperand(MCOperand::createImm(" << Val << "));\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionV( + std::string const &EnumName, std::string const &Reg) const { + *CvtOS << " case " << EnumName << ":\n" + << " Inst.addOperand(MCOperand::createReg(" << Reg << "));\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionFunctionVI() const { + *CvtOS << " }\n }\n}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandFunctionI( + StringRef const &TargetName, StringRef const &ClassName) const { + *OpOS << "void " << TargetName << ClassName << "::\n" + << "convertToMapAndConstraints(unsigned Kind,\n"; + OpOS->indent(27); + *OpOS << "const OperandVector &Operands) {\n" + << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" + << " unsigned NumMCOperands = 0;\n" + << " const uint8_t *Converter = ConversionTable[Kind];\n" + << " for (const uint8_t *p = Converter; *p; p += 2) {\n" + << " switch (*p) {\n" + << " default: llvm_unreachable(\"invalid conversion entry!\");\n" + << " case CVT_Reg:\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"r\");\n" + << " ++NumMCOperands;\n" + << " break;\n" + << " case CVT_Tied:\n" + << " ++NumMCOperands;\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandFunctionII( + std::string const &EnumName, MatchableInfo::AsmOperand const &Op, + MatchableInfo::ResOperand const &OpInfo) const { + // Add a handler for the operand number lookup. + *OpOS << " case " << EnumName << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n"; + + if (Op.Class->isRegisterClass()) + *OpOS << " Operands[*(p + 1)]->setConstraint(\"r\");\n"; + else + *OpOS << " Operands[*(p + 1)]->setConstraint(\"m\");\n"; + *OpOS << " NumMCOperands += " << OpInfo.MINumOperands << ";\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandFunctionIII( + std::string const &EnumName) const { + *OpOS << " case " << EnumName << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"\");\n" + << " ++NumMCOperands;\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandFunctionIV( + std::string const &EnumName) const { + *OpOS << " case " << EnumName << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"m\");\n" + << " ++NumMCOperands;\n" + << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandFunctionV() const { + *OpOS << " }\n }\n}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitTiedOperandEnum( + std::map, std::string> + TiedOperandsEnumMap) const { + OS << "enum {\n"; + for (auto &KV : TiedOperandsEnumMap) { + OS << " " << KV.second << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitTiedOpTable( + std::map, std::string> + TiedOperandsEnumMap) const { + OS << "static const uint8_t TiedAsmOperandTable[][3] = {\n"; + for (auto &KV : TiedOperandsEnumMap) { + OS << " /* " << KV.second << " */ { " << utostr(std::get<0>(KV.first)) + << ", " << utostr(std::get<1>(KV.first)) << ", " + << utostr(std::get<2>(KV.first)) << " },\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitTiedOpEmptyTable() const { + OS << "static const uint8_t TiedAsmOperandTable[][3] = " + "{ /* empty */ {0, 0, 0} };\n\n"; +} + +void PrinterLLVM::asmMatcherEmitOperandConvKindEnum( + SmallSetVector OperandConversionKinds) const { + OS << "enum OperatorConversionKind {\n"; + for (const auto &Converter : OperandConversionKinds) + OS << " " << Converter << ",\n"; + OS << " CVT_NUM_CONVERTERS\n"; + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitInstrConvKindEnum( + SmallSetVector InstructionConversionKinds) const { + OS << "enum InstructionConversionKind {\n"; + for (const auto &Signature : InstructionConversionKinds) + OS << " " << Signature << ",\n"; + OS << " CVT_NUM_SIGNATURES\n"; + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitConversionTable( + size_t MaxRowLength, + std::vector> const ConversionTable, + SmallSetVector InstructionConversionKinds, + SmallSetVector OperandConversionKinds, + std::map, std::string> + TiedOperandsEnumMap) const { + OS << "static const uint8_t ConversionTable[CVT_NUM_SIGNATURES][" + << MaxRowLength << "] = {\n"; + + for (unsigned Row = 0, ERow = ConversionTable.size(); Row != ERow; ++Row) { + assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!"); + OS << " // " << InstructionConversionKinds[Row] << "\n"; + OS << " { "; + for (unsigned I = 0, E = ConversionTable[Row].size(); I != E; I += 2) { + OS << OperandConversionKinds[ConversionTable[Row][I]] << ", "; + if (OperandConversionKinds[ConversionTable[Row][I]] != + CachedHashString("CVT_Tied")) { + OS << (unsigned)(ConversionTable[Row][I + 1]) << ", "; + continue; + } + + // For a tied operand, emit a reference to the TiedAsmOperandTable + // that contains the operand to copy, and the parsed operands to + // check for their tied constraints. + auto Key = std::make_tuple((uint8_t)ConversionTable[Row][I + 1], + (uint8_t)ConversionTable[Row][I + 2], + (uint8_t)ConversionTable[Row][I + 3]); + auto TiedOpndEnum = TiedOperandsEnumMap.find(Key); + assert(TiedOpndEnum != TiedOperandsEnumMap.end() && + "No record for tied operand pair"); + OS << TiedOpndEnum->second << ", "; + I += 2; + } + OS << "CVT_Done },\n"; + } + + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherWriteCvtOSToOS() const { OS << CvtOS->str(); } + +void PrinterLLVM::asmMatcherWriteOpOSToOS() const { OS << OpOS->str(); } + +void PrinterLLVM::asmMatcherEmitMatchClassKindEnum( + std::forward_list const &Infos) const { + OS << "/// MatchClassKind - The kinds of classes which participate in\n" + << "/// instruction matching.\n"; + OS << "enum MatchClassKind {\n"; + OS << " InvalidMatchClass = 0,\n"; + OS << " OptionalMatchClass = 1,\n"; + ClassInfo::ClassInfoKind LastKind = ClassInfo::Token; + StringRef LastName = "OptionalMatchClass"; + for (const auto &CI : Infos) { + if (LastKind == ClassInfo::Token && CI.Kind != ClassInfo::Token) { + OS << " MCK_LAST_TOKEN = " << LastName << ",\n"; + } else if (LastKind < ClassInfo::UserClass0 && + CI.Kind >= ClassInfo::UserClass0) { + OS << " MCK_LAST_REGISTER = " << LastName << ",\n"; + } + LastKind = (ClassInfo::ClassInfoKind)CI.Kind; + LastName = CI.Name; + + OS << " " << CI.Name << ", // "; + if (CI.Kind == ClassInfo::Token) { + OS << "'" << CI.ValueName << "'\n"; + } else if (CI.isRegisterClass()) { + if (!CI.ValueName.empty()) + OS << "register class '" << CI.ValueName << "'\n"; + else + OS << "derived register class\n"; + } else { + OS << "user defined class '" << CI.ValueName << "'\n"; + } + } + OS << " NumMatchClassKinds\n"; + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchClassDiagStrings( + AsmMatcherInfo const &Info) const { + OS << "static const char *getMatchKindDiag(" << Info.Target.getName() + << "AsmParser::" << Info.Target.getName() + << "MatchResultTy MatchResult) {\n"; + OS << " switch (MatchResult) {\n"; + + for (const auto &CI : Info.Classes) { + if (!CI.DiagnosticString.empty()) { + assert(!CI.DiagnosticType.empty() && + "DiagnosticString set without DiagnosticType"); + OS << " case " << Info.Target.getName() << "AsmParser::Match_" + << CI.DiagnosticType << ":\n"; + OS << " return \"" << CI.DiagnosticString << "\";\n"; + } + } + + OS << " default:\n"; + OS << " return nullptr;\n"; + + OS << " }\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitRegisterMatchErrorFunc( + AsmMatcherInfo &Info) const { + OS << "static unsigned getDiagKindFromRegisterClass(MatchClassKind " + "RegisterClass) {\n"; + if (none_of(Info.Classes, [](const ClassInfo &CI) { + return CI.isRegisterClass() && !CI.DiagnosticType.empty(); + })) { + OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; + } else { + OS << " switch (RegisterClass) {\n"; + for (const auto &CI : Info.Classes) { + if (CI.isRegisterClass() && !CI.DiagnosticType.empty()) { + OS << " case " << CI.Name << ":\n"; + OS << " return " << Info.Target.getName() << "AsmParser::Match_" + << CI.DiagnosticType << ";\n"; + } + } + + OS << " default:\n"; + OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; + + OS << " }\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitIsSubclassI() const { + OS << "/// isSubclass - Compute whether \\p A is a subclass of \\p B.\n"; + OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n"; + OS << " if (A == B)\n"; + OS << " return true;\n\n"; +} + +bool PrinterLLVM::asmMatcherEmitIsSubclassII(bool EmittedSwitch, + std::string const &Name) const { + bool ESTmp = EmittedSwitch; + if (!EmittedSwitch) { + OS << " switch (A) {\n"; + OS << " default:\n"; + OS << " return false;\n"; + ESTmp = true; + } + + OS << "\n case " << Name << ":\n"; + return ESTmp; +} + +void PrinterLLVM::asmMatcherEmitIsSubclassIII(StringRef const &Class) const { + OS << " return B == " << Class << ";\n"; +} + +void PrinterLLVM::asmMatcherEmitIsSubclassIV( + std::vector const &SuperClasses) const { + if (!SuperClasses.empty()) { + OS << " switch (B) {\n"; + OS << " default: return false;\n"; + for (StringRef SC : SuperClasses) + OS << " case " << SC << ": return true;\n"; + OS << " }\n"; + } else { + // No case statement to emit + OS << " return false;\n"; + } +} + +void PrinterLLVM::asmMatcherEmitIsSubclassV(bool EmittedSwitch) const { + if (EmittedSwitch) + OS << " }\n"; + else + OS << " return false;\n"; + + OS << "}\n\n"; +} + +/// emitValidateOperandClass - Emit the function to validate an operand class. +void PrinterLLVM::asmMatcherEmitValidateOperandClass( + AsmMatcherInfo &Info) const { + OS << "static unsigned validateOperandClass(MCParsedAsmOperand &GOp, " + << "MatchClassKind Kind) {\n"; + OS << " " << Info.Target.getName() << "Operand &Operand = (" + << Info.Target.getName() << "Operand &)GOp;\n"; + + // The InvalidMatchClass is not to match any operand. + OS << " if (Kind == InvalidMatchClass)\n"; + OS << " return MCTargetAsmParser::Match_InvalidOperand;\n\n"; + + // Check for Token operands first. + // FIXME: Use a more specific diagnostic type. + OS << " if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)\n"; + OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n" + << " MCTargetAsmParser::Match_Success :\n" + << " MCTargetAsmParser::Match_InvalidOperand;\n\n"; + + // Check the user classes. We don't care what order since we're only + // actually matching against one of them. + OS << " switch (Kind) {\n" + " default: break;\n"; + for (const auto &CI : Info.Classes) { + if (!CI.isUserClass()) + continue; + + OS << " // '" << CI.ClassName << "' class\n"; + OS << " case " << CI.Name << ": {\n"; + OS << " DiagnosticPredicate DP(Operand." << CI.PredicateMethod + << "());\n"; + OS << " if (DP.isMatch())\n"; + OS << " return MCTargetAsmParser::Match_Success;\n"; + if (!CI.DiagnosticType.empty()) { + OS << " if (DP.isNearMatch())\n"; + OS << " return " << Info.Target.getName() << "AsmParser::Match_" + << CI.DiagnosticType << ";\n"; + OS << " break;\n"; + } else + OS << " break;\n"; + OS << " }\n"; + } + OS << " } // end switch (Kind)\n\n"; + + // Check for register operands, including sub-classes. + OS << " if (Operand.isReg()) {\n"; + OS << " MatchClassKind OpKind;\n"; + OS << " switch (Operand.getReg()) {\n"; + OS << " default: OpKind = InvalidMatchClass; break;\n"; + for (const auto &RC : Info.RegisterClasses) + OS << " case " << RC.first->getValueAsString("Namespace") + << "::" << RC.first->getName() << ": OpKind = " << RC.second->Name + << "; break;\n"; + OS << " }\n"; + OS << " return isSubclass(OpKind, Kind) ? " + << "(unsigned)MCTargetAsmParser::Match_Success :\n " + << " getDiagKindFromRegisterClass(Kind);\n }\n\n"; + + // Expected operand is a register, but actual is not. + OS << " if (Kind > MCK_LAST_TOKEN && Kind <= MCK_LAST_REGISTER)\n"; + OS << " return getDiagKindFromRegisterClass(Kind);\n\n"; + + // Generic fallthrough match failure case for operands that don't have + // specialized diagnostic types. + OS << " return MCTargetAsmParser::Match_InvalidOperand;\n"; + OS << "}\n\n"; +} + +// Emit a function mapping match classes to strings, for debugging. +void PrinterLLVM::asmMatcherEmitMatchClassKindNames( + std::forward_list &Infos) const { + OS << "#ifndef NDEBUG\n"; + OS << "const char *getMatchClassName(MatchClassKind Kind) {\n"; + OS << " switch (Kind) {\n"; + + OS << " case InvalidMatchClass: return \"InvalidMatchClass\";\n"; + OS << " case OptionalMatchClass: return \"OptionalMatchClass\";\n"; + for (const auto &CI : Infos) { + OS << " case " << CI.Name << ": return \"" << CI.Name << "\";\n"; + } + OS << " case NumMatchClassKinds: return \"NumMatchClassKinds\";\n"; + + OS << " }\n"; + OS << " llvm_unreachable(\"unhandled MatchClassKind!\");\n"; + OS << "}\n\n"; + OS << "#endif // NDEBUG\n"; +} + +void PrinterLLVM::asmMatcherEmitAsmTiedOperandConstraints( + CodeGenTarget &Target, AsmMatcherInfo &Info) const { + std::string AsmParserName = + std::string(Info.AsmParser->getValueAsString("AsmParserClassName")); + OS << "static bool "; + OS << "checkAsmTiedOperandConstraints(const " << Target.getName() + << AsmParserName << "&AsmParser,\n"; + OS << " unsigned Kind,\n"; + OS << " const OperandVector &Operands,\n"; + OS << " uint64_t &ErrorInfo) {\n"; + OS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; + OS << " const uint8_t *Converter = ConversionTable[Kind];\n"; + OS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; + OS << " switch (*p) {\n"; + OS << " case CVT_Tied: {\n"; + OS << " unsigned OpIdx = *(p + 1);\n"; + OS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; + OS << " std::begin(TiedAsmOperandTable)) &&\n"; + OS << " \"Tied operand not found\");\n"; + OS << " unsigned OpndNum1 = TiedAsmOperandTable[OpIdx][1];\n"; + OS << " unsigned OpndNum2 = TiedAsmOperandTable[OpIdx][2];\n"; + OS << " if (OpndNum1 != OpndNum2) {\n"; + OS << " auto &SrcOp1 = Operands[OpndNum1];\n"; + OS << " auto &SrcOp2 = Operands[OpndNum2];\n"; + OS << " if (!AsmParser.areEqualRegs(*SrcOp1, *SrcOp2)) {\n"; + OS << " ErrorInfo = OpndNum2;\n"; + OS << " return false;\n"; + OS << " }\n"; + OS << " }\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " default:\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " }\n"; + OS << " return true;\n"; + OS << "}\n\n"; +} + +std::string +PrinterLLVM::getNameForFeatureBitset(const std::vector &FeatureBitset) const { + std::string Name = "CEFBS"; + for (const auto &Feature : FeatureBitset) + Name += ("_" + Feature->getName()).str(); + return Name; +} + +void PrinterLLVM::asmMatcherEmitFeatureBitsetEnum( + std::vector> const FeatureBitsets) const { + OS << "// Feature bitsets.\n" + << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n" + << " AMFBS_None,\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitFeatureBitsets( + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const { + OS << "static constexpr FeatureBitset FeatureBitsets[] = {\n" + << " {}, // AMFBS_None\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " {"; + for (const auto &Feature : FeatureBitset) { + const auto &I = Info.SubtargetFeatures.find(Feature); + assert(I != Info.SubtargetFeatures.end() && "Didn't import predicate?"); + OS << I->second.getEnumBitName() << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchEntryStruct( + unsigned MaxMnemonicIndex, unsigned NumConverters, size_t MaxNumOperands, + std::vector> const FeatureBitsets, + AsmMatcherInfo const &Info) const { + OS << " struct MatchEntry {\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) << " Mnemonic;\n"; + OS << " uint16_t Opcode;\n"; + OS << " " << getMinimalTypeForRange(NumConverters) << " ConvertFn;\n"; + OS << " " << getMinimalTypeForRange(FeatureBitsets.size()) + << " RequiredFeaturesIdx;\n"; + OS << " " + << getMinimalTypeForRange( + std::distance(Info.Classes.begin(), Info.Classes.end())) + << " Classes[" << MaxNumOperands << "];\n"; + OS << " StringRef getMnemonic() const {\n"; + OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; + OS << " MnemonicTable[Mnemonic]);\n"; + OS << " }\n"; + OS << " };\n"; + OS << " // Predicate for searching for an opcode.\n"; + OS << " struct LessOpcode {\n"; + OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n"; + OS << " return LHS.getMnemonic() < RHS;\n"; + OS << " }\n"; + OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n"; + OS << " return LHS < RHS.getMnemonic();\n"; + OS << " }\n"; + OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n"; + OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; + OS << " }\n"; + OS << " };\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchFunction( + CodeGenTarget const &Target, Record const *AsmParser, + StringRef const &ClassName, bool HasMnemonicFirst, bool HasOptionalOperands, + bool ReportMultipleNearMisses, bool HasMnemonicAliases, + size_t MaxNumOperands, bool HasDeprecation, + unsigned int VariantCount) const { + OS << "unsigned " << Target.getName() << ClassName << "::\n" + << "MatchInstructionImpl(const OperandVector &Operands,\n"; + OS << " MCInst &Inst,\n"; + if (ReportMultipleNearMisses) + OS << " SmallVectorImpl *NearMisses,\n"; + else + OS << " uint64_t &ErrorInfo,\n" + << " FeatureBitset &MissingFeatures,\n"; + OS << " bool matchingInlineAsm, unsigned VariantID) {\n"; + + if (!ReportMultipleNearMisses) { + OS << " // Eliminate obvious mismatches.\n"; + OS << " if (Operands.size() > " << (MaxNumOperands + HasMnemonicFirst) + << ") {\n"; + OS << " ErrorInfo = " << (MaxNumOperands + HasMnemonicFirst) << ";\n"; + OS << " return Match_InvalidOperand;\n"; + OS << " }\n\n"; + } + + // Emit code to get the available features. + OS << " // Get the current feature set.\n"; + OS << " const FeatureBitset &AvailableFeatures = " + "getAvailableFeatures();\n\n"; + + OS << " // Get the instruction mnemonic, which is the first token.\n"; + if (HasMnemonicFirst) { + OS << " StringRef Mnemonic = ((" << Target.getName() + << "Operand &)*Operands[0]).getToken();\n\n"; + } else { + OS << " StringRef Mnemonic;\n"; + OS << " if (Operands[0]->isToken())\n"; + OS << " Mnemonic = ((" << Target.getName() + << "Operand &)*Operands[0]).getToken();\n\n"; + } + + if (HasMnemonicAliases) { + OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; + OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);\n\n"; + } + + // Emit code to compute the class list for this operand vector. + if (!ReportMultipleNearMisses) { + OS << " // Some state to try to produce better error messages.\n"; + OS << " bool HadMatchOtherThanFeatures = false;\n"; + OS << " bool HadMatchOtherThanPredicate = false;\n"; + OS << " unsigned RetCode = Match_InvalidOperand;\n"; + OS << " MissingFeatures.set();\n"; + OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; + OS << " // wrong for all instances of the instruction.\n"; + OS << " ErrorInfo = ~0ULL;\n"; + } + + if (HasOptionalOperands) { + OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n"; + } + + // Emit code to search the table. + OS << " // Find the appropriate table for this asm variant.\n"; + OS << " const MatchEntry *Start, *End;\n"; + OS << " switch (VariantID) {\n"; + OS << " default: llvm_unreachable(\"invalid variant!\");\n"; + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC + << "); End = std::end(MatchTable" << VC << "); break;\n"; + } + OS << " }\n"; + + OS << " // Search the table.\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange = " + "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; + OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange = " + "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; + } + + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"AsmMatcher: found \" " + "<<\n" + << " std::distance(MnemonicRange.first, MnemonicRange.second) <<\n" + << " \" encodings with mnemonic '\" << Mnemonic << \"'\\n\");\n\n"; + + OS << " // Return a more specific error code if no mnemonics match.\n"; + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return Match_MnemonicFail;\n\n"; + + OS << " for (const MatchEntry *it = MnemonicRange.first, " + << "*ie = MnemonicRange.second;\n"; + OS << " it != ie; ++it) {\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[it->RequiredFeaturesIdx];\n"; + OS << " bool HasRequiredFeatures =\n"; + OS << " (AvailableFeatures & RequiredFeatures) == RequiredFeatures;\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Trying to match " + "opcode \"\n"; + OS << " << MII.getName(it->Opcode) " + "<< \"\\n\");\n"; + + if (ReportMultipleNearMisses) { + OS << " // Some state to record ways in which this instruction did not " + "match.\n"; + OS << " NearMissInfo OperandNearMiss = NearMissInfo::getSuccess();\n"; + OS << " NearMissInfo FeaturesNearMiss = NearMissInfo::getSuccess();\n"; + OS << " NearMissInfo EarlyPredicateNearMiss = " + "NearMissInfo::getSuccess();\n"; + OS << " NearMissInfo LatePredicateNearMiss = " + "NearMissInfo::getSuccess();\n"; + OS << " bool MultipleInvalidOperands = false;\n"; + } + + if (HasMnemonicFirst) { + OS << " // equal_range guarantees that instruction mnemonic matches.\n"; + OS << " assert(Mnemonic == it->getMnemonic());\n"; + } + + // Emit check that the subclasses match. + if (!ReportMultipleNearMisses) + OS << " bool OperandsValid = true;\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n"; + } + OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex") + << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex") + << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n"; + OS << " auto Formal = " + << "static_cast(it->Classes[FormalIdx]);\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; + OS << " dbgs() << \" Matching formal operand class \" " + "<< getMatchClassName(Formal)\n"; + OS << " << \" against actual operand at index \" " + "<< ActualIdx);\n"; + OS << " if (ActualIdx < Operands.size())\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \" (\";\n"; + OS << " Operands[ActualIdx]->print(dbgs()); dbgs() << " + "\"): \");\n"; + OS << " else\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n"; + OS << " if (ActualIdx >= Operands.size()) {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand " + "index out of range\\n\");\n"; + if (ReportMultipleNearMisses) { + OS << " bool ThisOperandValid = (Formal == " + << "InvalidMatchClass) || " + "isSubclass(Formal, OptionalMatchClass);\n"; + OS << " if (!ThisOperandValid) {\n"; + OS << " if (!OperandNearMiss) {\n"; + OS << " // Record info about match failure for later use.\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"recording " + "too-few-operands near miss\\n\");\n"; + OS << " OperandNearMiss =\n"; + OS << " NearMissInfo::getTooFewOperands(Formal, " + "it->Opcode);\n"; + OS << " } else if (OperandNearMiss.getKind() != " + "NearMissInfo::NearMissTooFewOperands) {\n"; + OS << " // If more than one operand is invalid, give up on this " + "match entry.\n"; + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs() << \"second invalid operand, giving up on " + "this opcode\\n\");\n"; + OS << " MultipleInvalidOperands = true;\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " } else {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal " + "operand not required\\n\");\n"; + OS << " }\n"; + OS << " continue;\n"; + } else { + OS << " if (Formal == InvalidMatchClass) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands + << ");\n"; + } + OS << " break;\n"; + OS << " }\n"; + OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx);\n"; + } + OS << " continue;\n"; + OS << " }\n"; + OS << " OperandsValid = false;\n"; + OS << " ErrorInfo = ActualIdx;\n"; + OS << " break;\n"; + } + OS << " }\n"; + OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n"; + OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n"; + OS << " if (Diag == Match_Success) {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; + OS << " dbgs() << \"match success using generic " + "matcher\\n\");\n"; + OS << " ++ActualIdx;\n"; + OS << " continue;\n"; + OS << " }\n"; + OS << " // If the generic handler indicates an invalid operand\n"; + OS << " // failure, check for a special case.\n"; + OS << " if (Diag != Match_Success) {\n"; + OS << " unsigned TargetDiag = validateTargetOperandClass(Actual, " + "Formal);\n"; + OS << " if (TargetDiag == Match_Success) {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; + OS << " dbgs() << \"match success using target " + "matcher\\n\");\n"; + OS << " ++ActualIdx;\n"; + OS << " continue;\n"; + OS << " }\n"; + OS << " // If the target matcher returned a specific error code use\n"; + OS << " // that, else use the one from the generic matcher.\n"; + OS << " if (TargetDiag != Match_InvalidOperand && " + "HasRequiredFeatures)\n"; + OS << " Diag = TargetDiag;\n"; + OS << " }\n"; + OS << " // If current formal operand wasn't matched and it is optional\n" + << " // then try to match next formal operand\n"; + OS << " if (Diag == Match_InvalidOperand " + << "&& isSubclass(Formal, OptionalMatchClass)) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx);\n"; + } + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"ignoring " + "optional operand\\n\");\n"; + OS << " continue;\n"; + OS << " }\n"; + + if (ReportMultipleNearMisses) { + OS << " if (!OperandNearMiss) {\n"; + OS << " // If this is the first invalid operand we have seen, " + "record some\n"; + OS << " // information about it.\n"; + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs()\n"; + OS << " << \"operand match failed, recording near-miss with " + "diag code \"\n"; + OS << " << Diag << \"\\n\");\n"; + OS << " OperandNearMiss =\n"; + OS << " NearMissInfo::getMissedOperand(Diag, Formal, " + "it->Opcode, ActualIdx);\n"; + OS << " ++ActualIdx;\n"; + OS << " } else {\n"; + OS << " // If more than one operand is invalid, give up on this " + "match entry.\n"; + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs() << \"second operand mismatch, skipping this " + "opcode\\n\");\n"; + OS << " MultipleInvalidOperands = true;\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " }\n\n"; + } else { + OS << " // If this operand is broken for all of the instances of " + "this\n"; + OS << " // mnemonic, keep track of it so we can report loc info.\n"; + OS << " // If we already had a match that only failed due to a\n"; + OS << " // target predicate, that diagnostic is preferred.\n"; + OS << " if (!HadMatchOtherThanPredicate &&\n"; + OS << " (it == MnemonicRange.first || ErrorInfo <= ActualIdx)) " + "{\n"; + OS << " if (HasRequiredFeatures && (ErrorInfo != ActualIdx || Diag " + "!= Match_InvalidOperand))\n"; + OS << " RetCode = Diag;\n"; + OS << " ErrorInfo = ActualIdx;\n"; + OS << " }\n"; + OS << " // Otherwise, just reject this instance of the mnemonic.\n"; + OS << " OperandsValid = false;\n"; + OS << " break;\n"; + OS << " }\n\n"; + } + + if (ReportMultipleNearMisses) + OS << " if (MultipleInvalidOperands) {\n"; + else + OS << " if (!OperandsValid) {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: " + "multiple \"\n"; + OS << " \"operand mismatches, " + "ignoring \"\n"; + OS << " \"this opcode\\n\");\n"; + OS << " continue;\n"; + OS << " }\n"; + + // Emit check that the required features are available. + OS << " if (!HasRequiredFeatures) {\n"; + if (!ReportMultipleNearMisses) + OS << " HadMatchOtherThanFeatures = true;\n"; + OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & " + "~AvailableFeatures;\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target " + "features:\";\n"; + OS << " for (unsigned I = 0, E = " + "NewMissingFeatures.size(); I != E; ++I)\n"; + OS << " if (NewMissingFeatures[I])\n"; + OS << " dbgs() << ' ' << I;\n"; + OS << " dbgs() << \"\\n\");\n"; + if (ReportMultipleNearMisses) { + OS << " FeaturesNearMiss = " + "NearMissInfo::getMissedFeature(NewMissingFeatures);\n"; + } else { + OS << " if (NewMissingFeatures.count() <=\n" + " MissingFeatures.count())\n"; + OS << " MissingFeatures = NewMissingFeatures;\n"; + OS << " continue;\n"; + } + OS << " }\n"; + OS << "\n"; + OS << " Inst.clear();\n\n"; + OS << " Inst.setOpcode(it->Opcode);\n"; + // Verify the instruction with the target-specific match predicate function. + OS << " // We have a potential match but have not rendered the operands.\n" + << " // Check the target predicate to handle any context sensitive\n" + " // constraints.\n" + << " // For example, Ties that are referenced multiple times must be\n" + " // checked here to ensure the input is the same for each match\n" + " // constraints. If we leave it any later the ties will have been\n" + " // canonicalized\n" + << " unsigned MatchResult;\n" + << " if ((MatchResult = checkEarlyTargetMatchPredicate(Inst, " + "Operands)) != Match_Success) {\n" + << " Inst.clear();\n"; + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs() << \"Early target match predicate failed with diag " + "code \"\n"; + OS << " << MatchResult << \"\\n\");\n"; + if (ReportMultipleNearMisses) { + OS << " EarlyPredicateNearMiss = " + "NearMissInfo::getMissedPredicate(MatchResult);\n"; + } else { + OS << " RetCode = MatchResult;\n" + << " HadMatchOtherThanPredicate = true;\n" + << " continue;\n"; + } + OS << " }\n\n"; + + if (ReportMultipleNearMisses) { + OS << " // If we did not successfully match the operands, then we can't " + "convert to\n"; + OS << " // an MCInst, so bail out on this instruction variant now.\n"; + OS << " if (OperandNearMiss) {\n"; + OS << " // If the operand mismatch was the only problem, reprrt it as " + "a near-miss.\n"; + OS << " if (NearMisses && !FeaturesNearMiss && " + "!EarlyPredicateNearMiss) {\n"; + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs()\n"; + OS << " << \"Opcode result: one mismatched operand, adding " + "near-miss\\n\");\n"; + OS << " NearMisses->push_back(OperandNearMiss);\n"; + OS << " } else {\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: " + "multiple \"\n"; + OS << " \"types of " + "mismatch, so not \"\n"; + OS << " \"reporting " + "near-miss\\n\");\n"; + OS << " }\n"; + OS << " continue;\n"; + OS << " }\n\n"; + } + + OS << " if (matchingInlineAsm) {\n"; + OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n"; + if (!ReportMultipleNearMisses) { + OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, " + "Operands, ErrorInfo))\n"; + OS << " return Match_InvalidTiedOperand;\n"; + OS << "\n"; + } + OS << " return Match_Success;\n"; + OS << " }\n\n"; + OS << " // We have selected a definite instruction, convert the parsed\n" + << " // operands into the appropriate MCInst.\n"; + if (HasOptionalOperands) { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n" + << " OptionalOperandsMask);\n"; + } else { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; + } + OS << "\n"; + + // Verify the instruction with the target-specific match predicate function. + OS << " // We have a potential match. Check the target predicate to\n" + << " // handle any context sensitive constraints.\n" + << " if ((MatchResult = checkTargetMatchPredicate(Inst)) !=" + << " Match_Success) {\n" + << " DEBUG_WITH_TYPE(\"asm-matcher\",\n" + << " dbgs() << \"Target match predicate failed with " + "diag code \"\n" + << " << MatchResult << \"\\n\");\n" + << " Inst.clear();\n"; + if (ReportMultipleNearMisses) { + OS << " LatePredicateNearMiss = " + "NearMissInfo::getMissedPredicate(MatchResult);\n"; + } else { + OS << " RetCode = MatchResult;\n" + << " HadMatchOtherThanPredicate = true;\n" + << " continue;\n"; + } + OS << " }\n\n"; + + if (ReportMultipleNearMisses) { + OS << " int NumNearMisses = ((int)(bool)OperandNearMiss +\n"; + OS << " (int)(bool)FeaturesNearMiss +\n"; + OS << " (int)(bool)EarlyPredicateNearMiss +\n"; + OS << " (int)(bool)LatePredicateNearMiss);\n"; + OS << " if (NumNearMisses == 1) {\n"; + OS << " // We had exactly one type of near-miss, so add that to the " + "list.\n"; + OS << " assert(!OperandNearMiss && \"OperandNearMiss was handled " + "earlier\");\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: " + "found one type of \"\n"; + OS << " \"mismatch, so " + "reporting a \"\n"; + OS << " \"near-miss\\n\");\n"; + OS << " if (NearMisses && FeaturesNearMiss)\n"; + OS << " NearMisses->push_back(FeaturesNearMiss);\n"; + OS << " else if (NearMisses && EarlyPredicateNearMiss)\n"; + OS << " NearMisses->push_back(EarlyPredicateNearMiss);\n"; + OS << " else if (NearMisses && LatePredicateNearMiss)\n"; + OS << " NearMisses->push_back(LatePredicateNearMiss);\n"; + OS << "\n"; + OS << " continue;\n"; + OS << " } else if (NumNearMisses > 1) {\n"; + OS << " // This instruction missed in more than one way, so ignore " + "it.\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: " + "multiple \"\n"; + OS << " \"types of mismatch, " + "so not \"\n"; + OS << " \"reporting " + "near-miss\\n\");\n"; + OS << " continue;\n"; + OS << " }\n"; + } + + // Call the post-processing function, if used. + StringRef InsnCleanupFn = AsmParser->getValueAsString("AsmParserInstCleanup"); + if (!InsnCleanupFn.empty()) + OS << " " << InsnCleanupFn << "(Inst);\n"; + + if (HasDeprecation) { + OS << " std::string Info;\n"; + OS << " if " + "(!getParser().getTargetParser().getTargetOptions()." + "MCNoDeprecatedWarn &&\n"; + OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; + OS << " SMLoc Loc = ((" << Target.getName() + << "Operand &)*Operands[0]).getStartLoc();\n"; + OS << " getParser().Warning(Loc, Info, std::nullopt);\n"; + OS << " }\n"; + } + + if (!ReportMultipleNearMisses) { + OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, " + "Operands, ErrorInfo))\n"; + OS << " return Match_InvalidTiedOperand;\n"; + OS << "\n"; + } + + OS << " DEBUG_WITH_TYPE(\n"; + OS << " \"asm-matcher\",\n"; + OS << " dbgs() << \"Opcode result: complete match, selecting this " + "opcode\\n\");\n"; + OS << " return Match_Success;\n"; + OS << " }\n\n"; + + if (ReportMultipleNearMisses) { + OS << " // No instruction variants matched exactly.\n"; + OS << " return Match_NearMisses;\n"; + } else { + OS << " // Okay, we had no match. Try to return a useful error code.\n"; + OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n"; + OS << " return RetCode;\n\n"; + OS << " ErrorInfo = 0;\n"; + OS << " return Match_MissingFeature;\n"; + } + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMnemonicSpellChecker( + CodeGenTarget const &Target, unsigned VariantCount) const { + OS << "static std::string " << Target.getName() + << "MnemonicSpellCheck(StringRef S, const FeatureBitset &FBS," + << " unsigned VariantID) {\n"; + if (!VariantCount) + OS << " return \"\";"; + else { + OS << " const unsigned MaxEditDist = 2;\n"; + OS << " std::vector Candidates;\n"; + OS << " StringRef Prev = \"\";\n\n"; + + OS << " // Find the appropriate table for this asm variant.\n"; + OS << " const MatchEntry *Start, *End;\n"; + OS << " switch (VariantID) {\n"; + OS << " default: llvm_unreachable(\"invalid variant!\");\n"; + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC + << "); End = std::end(MatchTable" << VC << "); break;\n"; + } + OS << " }\n\n"; + OS << " for (auto I = Start; I < End; I++) {\n"; + OS << " // Ignore unsupported instructions.\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[I->RequiredFeaturesIdx];\n"; + OS << " if ((FBS & RequiredFeatures) != RequiredFeatures)\n"; + OS << " continue;\n"; + OS << "\n"; + OS << " StringRef T = I->getMnemonic();\n"; + OS << " // Avoid recomputing the edit distance for the same string.\n"; + OS << " if (T.equals(Prev))\n"; + OS << " continue;\n"; + OS << "\n"; + OS << " Prev = T;\n"; + OS << " unsigned Dist = S.edit_distance(T, false, MaxEditDist);\n"; + OS << " if (Dist <= MaxEditDist)\n"; + OS << " Candidates.push_back(T);\n"; + OS << " }\n"; + OS << "\n"; + OS << " if (Candidates.empty())\n"; + OS << " return \"\";\n"; + OS << "\n"; + OS << " std::string Res = \", did you mean: \";\n"; + OS << " unsigned i = 0;\n"; + OS << " for (; i < Candidates.size() - 1; i++)\n"; + OS << " Res += Candidates[i].str() + \", \";\n"; + OS << " return Res + Candidates[i].str() + \"?\";\n"; + } + OS << "}\n"; + OS << "\n"; +} + +void PrinterLLVM::asmMatcherEmitMnemonicChecker(CodeGenTarget const &Target, + unsigned VariantCount, + bool HasMnemonicFirst, + bool HasMnemonicAliases) const { + OS << "static bool " << Target.getName() + << "CheckMnemonic(StringRef Mnemonic,\n"; + OS << " " + << "const FeatureBitset &AvailableFeatures,\n"; + OS << " " + << "unsigned VariantID) {\n"; + + if (!VariantCount) { + OS << " return false;\n"; + } else { + if (HasMnemonicAliases) { + OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; + OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);"; + OS << "\n\n"; + } + OS << " // Find the appropriate table for this asm variant.\n"; + OS << " const MatchEntry *Start, *End;\n"; + OS << " switch (VariantID) {\n"; + OS << " default: llvm_unreachable(\"invalid variant!\");\n"; + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC + << "); End = std::end(MatchTable" << VC << "); break;\n"; + } + OS << " }\n\n"; + + OS << " // Search the table.\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange = " + "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; + OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange = " + << "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; + } + + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return false;\n\n"; + + OS << " for (const MatchEntry *it = MnemonicRange.first, " + << "*ie = MnemonicRange.second;\n"; + OS << " it != ie; ++it) {\n"; + OS << " const FeatureBitset &RequiredFeatures =\n"; + OS << " FeatureBitsets[it->RequiredFeaturesIdx];\n"; + OS << " if ((AvailableFeatures & RequiredFeatures) == "; + OS << "RequiredFeatures)\n"; + OS << " return true;\n"; + OS << " }\n"; + OS << " return false;\n"; + } + OS << "}\n"; + OS << "\n"; +} + +void PrinterLLVM::asmMatcherEmitIncludes() const { + OS << "#include \"llvm/Support/Debug.h\"\n"; + OS << "#include \"llvm/Support/Format.h\"\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMnemonicTable( + StringToOffsetTable &StringTable) const { + OS << "static const char MnemonicTable[] =\n"; + StringTable.EmitString(OS); + OS << ";\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchTable(CodeGenTarget const &Target, + AsmMatcherInfo &Info, + StringToOffsetTable &StringTable, + unsigned VariantCount) const { + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + + OS << "static const MatchEntry MatchTable" << VC << "[] = {\n"; + + for (const auto &MI : Info.Matchables) { + if (MI->AsmVariantID != AsmVariantNo) + continue; + + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = + char(MI->Mnemonic.size()) + MI->Mnemonic.lower(); + OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false) + << " /* " << MI->Mnemonic << " */, " << Target.getInstNamespace() + << "::" << MI->getResultInst()->TheDef->getName() << ", " + << MI->ConversionFnKind << ", "; + + // Write the required features mask. + OS << "AMFBS"; + if (MI->RequiredFeatures.empty()) + OS << "_None"; + else + for (unsigned I = 0, E = MI->RequiredFeatures.size(); I != E; ++I) + OS << '_' << MI->RequiredFeatures[I]->TheDef->getName(); + + OS << ", { "; + ListSeparator LS; + for (const MatchableInfo::AsmOperand &Op : MI->AsmOperands) + OS << LS << Op.Class->Name; + OS << " }, },\n"; + } + + OS << "};\n\n"; + } +} + +void PrinterLLVM::asmMatcherEmitCustomOperandParsing( + unsigned MaxMask, CodeGenTarget &Target, AsmMatcherInfo const &Info, + StringRef ClassName, StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, bool HasMnemonicFirst, + Record const &AsmParser) const { + for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { + MaxMask |= OMI.OperandMask; + } + + // Emit the static custom operand parsing table; + emitNamespace("", true); + OS << " struct OperandMatchEntry {\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) + << " Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(MaxMask) + << " OperandMask;\n"; + OS << " " << getMinimalTypeForRange(std::distance( + Info.Classes.begin(), Info.Classes.end())) << " Class;\n"; + OS << " " << getMinimalTypeForRange(MaxFeaturesIndex) + << " RequiredFeaturesIdx;\n\n"; + OS << " StringRef getMnemonic() const {\n"; + OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; + OS << " MnemonicTable[Mnemonic]);\n"; + OS << " }\n"; + OS << " };\n\n"; + + OS << " // Predicate for searching for an opcode.\n"; + OS << " struct LessOpcodeOperand {\n"; + OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n"; + OS << " return LHS.getMnemonic() < RHS;\n"; + OS << " }\n"; + OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n"; + OS << " return LHS < RHS.getMnemonic();\n"; + OS << " }\n"; + OS << " bool operator()(const OperandMatchEntry &LHS,"; + OS << " const OperandMatchEntry &RHS) {\n"; + OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n"; + OS << " }\n"; + OS << " };\n"; + + OS << "} // end anonymous namespace\n\n"; + + OS << "static const OperandMatchEntry OperandMatchTable[" + << Info.OperandMatchInfo.size() << "] = {\n"; + + OS << " /* Operand List Mnemonic, Mask, Operand Class, Features */\n"; + for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { + const MatchableInfo &II = *OMI.MI; + + OS << " { "; + + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.lower(); + OS << StringTable.GetOrAddStringOffset(LenMnemonic, false) + << " /* " << II.Mnemonic << " */, "; + + OS << OMI.OperandMask; + OS << " /* "; + ListSeparator LS; + for (int i = 0, e = 31; i !=e; ++i) + if (OMI.OperandMask & (1 << i)) + OS << LS << i; + OS << " */, "; + + OS << OMI.CI->Name; + + // Write the required features mask. + OS << ", AMFBS"; + if (II.RequiredFeatures.empty()) + OS << "_None"; + else + for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) + OS << '_' << II.RequiredFeatures[i]->TheDef->getName(); + + OS << " },\n"; + } + OS << "};\n\n"; + + // Emit the operand class switch to call the correct custom parser for + // the found operand class. + OS << "ParseStatus " << Target.getName() << ClassName << "::\n" + << "tryCustomParseOperand(OperandVector" + << " &Operands,\n unsigned MCK) {\n\n" + << " switch(MCK) {\n"; + + for (const auto &CI : Info.Classes) { + if (CI.ParserMethod.empty()) + continue; + OS << " case " << CI.Name << ":\n" + << " return " << CI.ParserMethod << "(Operands);\n"; + } + + OS << " default:\n"; + OS << " return ParseStatus::NoMatch;\n"; + OS << " }\n"; + OS << " return ParseStatus::NoMatch;\n"; + OS << "}\n\n"; + + // Emit the static custom operand parser. This code is very similar with + // the other matcher. Also use MatchResultTy here just in case we go for + // a better error handling. + OS << "ParseStatus " << Target.getName() << ClassName << "::\n" + << "MatchOperandParserImpl(OperandVector" + << " &Operands,\n StringRef Mnemonic,\n" + << " bool ParseForAllFeatures) {\n"; + + // Emit code to get the available features. + OS << " // Get the current feature set.\n"; + OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n"; + + OS << " // Get the next operand index.\n"; + OS << " unsigned NextOpNum = Operands.size()" + << (HasMnemonicFirst ? " - 1" : "") << ";\n"; + + // Emit code to search the table. + OS << " // Search the table.\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange =\n"; + OS << " std::equal_range(std::begin(OperandMatchTable), " + "std::end(OperandMatchTable),\n"; + OS << " Mnemonic, LessOpcodeOperand());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(std::begin(OperandMatchTable)," + " std::end(OperandMatchTable));\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange =\n"; + OS << " std::equal_range(std::begin(OperandMatchTable), " + "std::end(OperandMatchTable),\n"; + OS << " Mnemonic, LessOpcodeOperand());\n\n"; + } + + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return ParseStatus::NoMatch;\n\n"; + + OS << " for (const OperandMatchEntry *it = MnemonicRange.first,\n" + << " *ie = MnemonicRange.second; it != ie; ++it) {\n"; + + OS << " // equal_range guarantees that instruction mnemonic matches.\n"; + OS << " assert(Mnemonic == it->getMnemonic());\n\n"; + + // Emit check that the required features are available. + OS << " // check if the available features match\n"; + OS << " const FeatureBitset &RequiredFeatures = " + "FeatureBitsets[it->RequiredFeaturesIdx];\n"; + OS << " if (!ParseForAllFeatures && (AvailableFeatures & " + "RequiredFeatures) != RequiredFeatures)\n"; + OS << " continue;\n\n"; + + // Emit check to ensure the operand number matches. + OS << " // check if the operand in question has a custom parser.\n"; + OS << " if (!(it->OperandMask & (1 << NextOpNum)))\n"; + OS << " continue;\n\n"; + + // Emit call to the custom parser method + StringRef ParserName = AsmParser.getValueAsString("OperandParserMethod"); + if (ParserName.empty()) + ParserName = "tryCustomParseOperand"; + OS << " // call custom parse method to handle the operand\n"; + OS << " ParseStatus Result = " << ParserName << "(Operands, it->Class);\n"; + OS << " if (!Result.isNoMatch())\n"; + OS << " return Result;\n"; + OS << " }\n\n"; + + OS << " // Okay, we had no match.\n"; + OS << " return ParseStatus::NoMatch;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchRegisterName( + Record const *AsmParser, + std::vector const Matches) const { + OS << "static unsigned MatchRegisterName(StringRef Name) {\n"; + + bool IgnoreDuplicates = + AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); + StringMatcher("Name", Matches, OS, PRINTER_LANG_CPP) + .Emit(0, IgnoreDuplicates); + + OS << " return 0;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchRegisterAltName( + Record const *AsmParser, + std::vector const Matches) const { + OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n"; + + bool IgnoreDuplicates = + AsmParser->getValueAsBit("AllowDuplicateRegisterNames"); + StringMatcher("Name", Matches, OS, PRINTER_LANG_CPP) + .Emit(0, IgnoreDuplicates); + + OS << " return 0;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMatchTokenString( + std::vector const Matches) const { + OS << "static MatchClassKind matchTokenString(StringRef Name) {\n"; + + StringMatcher("Name", Matches, OS, PRINTER_LANG_CPP).Emit(); + + OS << " return InvalidMatchClass;\n"; + OS << "}\n\n"; +} + +void PrinterLLVM::asmMatcherEmitMnemonicAliasVariant( + std::vector const &Cases, + unsigned Indent) const { + StringMatcher("Mnemonic", Cases, OS, PRINTER_LANG_CPP).Emit(Indent); +} + +void PrinterLLVM::asmMatcherAppendMnemonicAlias(Record const *R, + std::string const &FeatureMask, + std::string &MatchCode) const { + if (!MatchCode.empty()) + MatchCode += "else "; + MatchCode += "if (" + FeatureMask + ")\n"; + MatchCode += " Mnemonic = \""; + MatchCode += R->getValueAsString("ToMnemonic").lower(); + MatchCode += "\";\n"; +} + +void PrinterLLVM::asmMatcherAppendMnemonic(Record const *R, + std::string &MatchCode) const { + if (!MatchCode.empty()) + MatchCode += "else\n "; + MatchCode += "Mnemonic = \""; + MatchCode += R->getValueAsString("ToMnemonic").lower(); + MatchCode += "\";\n"; +} + +void PrinterLLVM::asmMatcherAppendMnemonicAliasEnd( + std::string &MatchCode) const { + MatchCode += "return;"; +} + +void PrinterLLVM::asmMatcherEmitApplyMnemonicAliasesI() const { + OS << "static void applyMnemonicAliases(StringRef &Mnemonic, " + "const FeatureBitset &Features, unsigned VariantID) {\n"; + OS << " switch (VariantID) {\n"; +} + +void PrinterLLVM::asmMatcherEmitApplyMnemonicAliasesII( + int AsmParserVariantNo) const { + OS << " case " << AsmParserVariantNo << ":\n"; +} + +void PrinterLLVM::asmMatcherEmitApplyMnemonicAliasesIII() const { + OS << " break;\n"; +} + +void PrinterLLVM::asmMatcherEmitApplyMnemonicAliasesIV() const { + OS << " }\n"; +} + +void PrinterLLVM::asmMatcherEmitApplyMnemonicAliasesV() const { OS << "}\n\n"; } + +void PrinterLLVM::asmMatcherEmitSTFBitEnum(AsmMatcherInfo &Info) const { + SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( + Info.SubtargetFeatures, OS); +} + +void PrinterLLVM::asmMatcherEmitComputeAssemblerAvailableFeatures( + AsmMatcherInfo &Info, StringRef const &ClassName) const { + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( + Info.Target.getName(), ClassName, "ComputeAvailableFeatures", + Info.SubtargetFeatures, OS); +} + +void PrinterLLVM::searchableTablesWriteFiles() const {} + +void PrinterLLVM::searchableTablesEmitGenericEnum( + const GenericEnum &Enum) const { + OS << "enum " << Enum.Name << " {\n"; + for (const auto &Entry : Enum.Entries) + OS << " " << Entry->first << " = " << Entry->second << ",\n"; + OS << "};\n"; +} + +void PrinterLLVM::searchableTablesEmitGenericTable( + const GenericTable &Enum) const {} + +void PrinterLLVM::searchableTablesEmitIfdef(const std::string Guard, + StreamType ST) { + OS << "#ifdef " << Guard << "\n"; + PreprocessorGuards.insert(Guard); +} + +void PrinterLLVM::searchableTablesEmitEndif(StreamType ST) const { + OS << "#endif\n\n"; +} + +void PrinterLLVM::searchableTablesEmitUndef() const { + for (const auto &Guard : PreprocessorGuards) + OS << "#undef " << Guard << "\n"; +} + +std::string PrinterLLVM::searchableTablesSearchableFieldType( + const GenericTable &Table, const SearchIndex &Index, + const GenericField &Field, TypeContext Ctx) const { + if (isa(Field.RecType)) { + if (Ctx == TypeInStaticStruct) + return "const char *"; + if (Ctx == TypeInTempStruct) + return "std::string"; + return "StringRef"; + } else if (BitsRecTy *BI = dyn_cast(Field.RecType)) { + unsigned NumBits = BI->getNumBits(); + if (NumBits <= 8) + return "uint8_t"; + if (NumBits <= 16) + return "uint16_t"; + if (NumBits <= 32) + return "uint32_t"; + if (NumBits <= 64) + return "uint64_t"; + PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + + "' lookup method '" + Index.Name + + "', key field '" + Field.Name + + "' of type bits is too large"); + } else if (isa(Field.RecType)) { + return "bool"; + } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) + return "unsigned"; + PrintFatalError(Index.Loc, + Twine("In table '") + Table.Name + "' lookup method '" + + Index.Name + "', key field '" + Field.Name + + "' has invalid type: " + Field.RecType->getAsString()); +} + +std::string PrinterLLVM::searchableTablesPrimaryRepresentation( + SMLoc Loc, const GenericField &Field, Init *I, + StringRef const &InstrinsicEnumName) const { + if (StringInit *SI = dyn_cast(I)) { + if (Field.IsCode || SI->hasCodeFormat()) + return std::string(SI->getValue()); + else + return SI->getAsString(); + } else if (BitsInit *BI = dyn_cast(I)) + return "0x" + utohexstr(getAsInt(BI)); + else if (BitInit *BI = dyn_cast(I)) + return BI->getValue() ? "true" : "false"; + else if (Field.IsIntrinsic) + return "Intrinsic::" + InstrinsicEnumName.str(); + else if (Field.IsInstruction) + return I->getAsString(); + else if (Field.Enum) { + auto *Entry = Field.Enum->EntryMap[cast(I)->getDef()]; + if (!Entry) + PrintFatalError(Loc, + Twine("Entry for field '") + Field.Name + "' is null"); + return std::string(Entry->first); + } + PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + + "'; expected: bit, bits, string, or code"); +} + +void PrinterLLVM::searchableTablesEmitLookupDeclaration( + const GenericTable &Table, const SearchIndex &Index, StreamType ST) { + OS << "const " << Table.CppTypeName << " *" << Index.Name << "("; + + ListSeparator LS; + for (const auto &Field : Index.Fields) + OS << LS + << searchableTablesSearchableFieldType(Table, Index, Field, + TypeInArgument) + << " " << Field.Name; + OS << ")"; + if (ST == ST_DECL_OS) + OS << ";\n"; + else if (ST == ST_IMPL_OS) + OS << " {\n"; +} + +void PrinterLLVM::searchableTablesEmitIndexTypeStruct( + const GenericTable &Table, const SearchIndex &Index) { + OS << " struct IndexType {\n"; + for (const auto &Field : Index.Fields) { + OS << " " + << searchableTablesSearchableFieldType(Table, Index, Field, + TypeInStaticStruct) + << " " << Field.Name << ";\n"; + } + OS << " unsigned _index;\n"; + OS << " };\n"; +} + +void PrinterLLVM::searchableTablesEmitIndexArrayI() const { + OS << " static const struct IndexType Index[] = {\n"; +} + +void PrinterLLVM::searchableTablesEmitIndexArrayII() const { OS << " { "; } + +void PrinterLLVM::searchableTablesEmitIndexArrayIII(ListSeparator &LS, + std::string Repr) const { + OS << LS << Repr; +} + +void PrinterLLVM::searchableTablesEmitIndexArrayIV( + std::pair const &Entry) const { + OS << ", " << Entry.second << " },\n"; +} +void PrinterLLVM::searchableTablesEmitIndexArrayV() const { OS << " };\n\n"; } + +void PrinterLLVM::searchableTablesEmitIsContiguousCase( + StringRef const &IndexName, const GenericTable &Table, + const SearchIndex &Index, bool IsPrimary) { + OS << " auto Table = ArrayRef(" << IndexName << ");\n"; + OS << " size_t Idx = " << Index.Fields[0].Name << ";\n"; + OS << " return Idx >= Table.size() ? nullptr : "; + if (IsPrimary) + OS << "&Table[Idx]"; + else + OS << "&" << Table.Name << "[Table[Idx]._index]"; + OS << ";\n"; + OS << "}\n"; +} + +void PrinterLLVM::searchableTablesEmitIfFieldCase( + const GenericField &Field, std::string const &FirstRepr, + std::string const &LastRepr) const { + OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n"; + OS << " (" << Field.Name << " > " << LastRepr << "))\n"; + OS << " return nullptr;\n\n"; +} + +void PrinterLLVM::searchableTablesEmitKeyTypeStruct( + const GenericTable &Table, const SearchIndex &Index) const { + OS << " struct KeyType {\n"; + for (const auto &Field : Index.Fields) { + OS << " " + << searchableTablesSearchableFieldType(Table, Index, Field, + TypeInTempStruct) + << " " << Field.Name << ";\n"; + } + OS << " };\n"; +} + +void PrinterLLVM::searchableTablesEmitKeyArray(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) const { + OS << " KeyType Key = {"; + ListSeparator LS; + for (const auto &Field : Index.Fields) { + OS << LS << Field.Name; + if (isa(Field.RecType)) { + OS << ".upper()"; + if (IsPrimary) + PrintFatalError(Index.Loc, + Twine("In table '") + Table.Name + + "', use a secondary lookup method for " + "case-insensitive comparison of field '" + + Field.Name + "'"); + } + } + OS << "};\n"; +} + +void PrinterLLVM::searchableTablesEmitIndexLamda( + const SearchIndex &Index, StringRef const &IndexName, + StringRef const &IndexTypeName) const { + OS << " auto Table = ArrayRef(" << IndexName << ");\n"; + OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; + OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n"; + + for (const auto &Field : Index.Fields) { + if (isa(Field.RecType)) { + OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name + << ").compare(RHS." << Field.Name << ");\n"; + OS << " if (Cmp" << Field.Name << " < 0) return true;\n"; + OS << " if (Cmp" << Field.Name << " > 0) return false;\n"; + } else if (Field.Enum) { + // Explicitly cast to unsigned, because the signedness of enums is + // compiler-dependent. + OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS." + << Field.Name << ")\n"; + OS << " return true;\n"; + OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS." + << Field.Name << ")\n"; + OS << " return false;\n"; + } else { + OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n"; + OS << " return true;\n"; + OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n"; + OS << " return false;\n"; + } + } + OS << " return false;\n"; + OS << " });\n\n"; +} + +void PrinterLLVM::searchableTablesEmitReturns(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary) { + OS << " if (Idx == Table.end()"; + + for (const auto &Field : Index.Fields) + OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name; + OS << ")\n return nullptr;\n"; + + if (IsPrimary) + OS << " return &*Idx;\n"; + else + OS << " return &" << Table.Name << "[Idx->_index];\n"; + + OS << "}\n"; +} + +void PrinterLLVM::searchableTablesEmitMapI(const GenericTable &Table) const { + OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; +} + +void PrinterLLVM::searchableTablesEmitMapII() const { OS << " { "; } + +void PrinterLLVM::searchableTablesEmitMapIII(const GenericTable &Table, + ListSeparator &LS, + GenericField const &Field, + StringRef &IntrinsicEnum, + Record *Entry) const { + OS << LS + << searchableTablesPrimaryRepresentation(Table.Locs[0], Field, + Entry->getValueInit(Field.Name), + IntrinsicEnum); +} + +void PrinterLLVM::searchableTablesEmitMapIV(unsigned i) const { + OS << " }, // " << i << "\n"; +} + +void PrinterLLVM::searchableTablesEmitMapV() { OS << " };\n\n"; } +} // end namespace llvm diff --git a/llvm/utils/TableGen/PrinterTypes.h b/llvm/utils/TableGen/PrinterTypes.h new file mode 100644 index 000000000000..2407e0cd7834 --- /dev/null +++ b/llvm/utils/TableGen/PrinterTypes.h @@ -0,0 +1,23 @@ +//===------------- PrinterTypes.h - Printer Interface -----------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_PRINTERTYPES_H +#define LLVM_UTILS_TABLEGEN_PRINTERTYPES_H + +#include "llvm/ADT/BitVector.h" + +namespace llvm { + +enum PrinterLanguage { + PRINTER_LANG_CPP, + PRINTER_LANG_CAPSTONE_C, +}; + +} // end namespace llvm + +#endif // LLVM_UTILS_TABLEGEN_PRINTERTYPES_H diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 92ef9199cc47..aafab2eb3ce6 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -12,37 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenHwModes.h" -#include "CodeGenRegisters.h" -#include "CodeGenTarget.h" -#include "InfoByHwMode.h" -#include "SequenceToOffsetTable.h" -#include "Types.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/SparseBitVector.h" -#include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/MachineValueType.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/SetTheory.h" -#include "llvm/TableGen/TableGenBackend.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "Printer.h" +#include "RegisterInfoEmitterTypes.h" using namespace llvm; @@ -58,179 +29,53 @@ namespace { class RegisterInfoEmitter { CodeGenTarget Target; RecordKeeper &Records; + PrinterLLVM &PI; public: - RegisterInfoEmitter(RecordKeeper &R) : Target(R), Records(R) { + RegisterInfoEmitter(RecordKeeper &R, PrinterLLVM &PI) + : Target(R), Records(R), PI(PI) { CodeGenRegBank &RegBank = Target.getRegBank(); RegBank.computeDerivedInfo(); } - // runEnums - Print out enum values for all of the registers. - void runEnums(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank); - // runMCDesc - Print out MC register descriptions. - void runMCDesc(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank); + void runMCDesc(CodeGenTarget &Target, CodeGenRegBank &Bank); // runTargetHeader - Emit a header fragment for the register info emitter. - void runTargetHeader(raw_ostream &o, CodeGenTarget &Target, + void runTargetHeader(CodeGenTarget &Target, CodeGenRegBank &Bank); // runTargetDesc - Output the target register and register file descriptions. - void runTargetDesc(raw_ostream &o, CodeGenTarget &Target, + void runTargetDesc(CodeGenTarget &Target, CodeGenRegBank &Bank); // run - Output the register file description. - void run(raw_ostream &o); + void run(); void debugDump(raw_ostream &OS); private: - void EmitRegMapping(raw_ostream &o, const std::deque &Regs, + void EmitRegMapping(const std::deque &Regs, bool isCtor); - void EmitRegMappingTables(raw_ostream &o, - const std::deque &Regs, + void EmitRegMappingTables(const std::deque &Regs, bool isCtor); - void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, + void EmitRegUnitPressure(const CodeGenRegBank &RegBank, const std::string &ClassName); - void emitComposeSubRegIndices(raw_ostream &OS, CodeGenRegBank &RegBank, + void emitComposeSubRegIndices(CodeGenRegBank &RegBank, const std::string &ClassName); - void emitComposeSubRegIndexLaneMask(raw_ostream &OS, CodeGenRegBank &RegBank, + void emitComposeSubRegIndexLaneMask(CodeGenRegBank &RegBank, const std::string &ClassName); }; } // end anonymous namespace -// runEnums - Print out enum values for all of the registers. -void RegisterInfoEmitter::runEnums(raw_ostream &OS, - CodeGenTarget &Target, CodeGenRegBank &Bank) { - const auto &Registers = Bank.getRegisters(); - - // Register enums are stored as uint16_t in the tables. Make sure we'll fit. - assert(Registers.size() <= 0xffff && "Too many regs to fit in tables"); - - StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace"); - - emitSourceFileHeader("Target Register Enum Values", OS); - - OS << "\n#ifdef GET_REGINFO_ENUM\n"; - OS << "#undef GET_REGINFO_ENUM\n\n"; - - OS << "namespace llvm {\n\n"; - - OS << "class MCRegisterClass;\n" - << "extern const MCRegisterClass " << Target.getName() - << "MCRegisterClasses[];\n\n"; - - if (!Namespace.empty()) - OS << "namespace " << Namespace << " {\n"; - OS << "enum {\n NoRegister,\n"; - - for (const auto &Reg : Registers) - OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n"; - assert(Registers.size() == Registers.back().EnumValue && - "Register enum value mismatch!"); - OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n"; - OS << "};\n"; - if (!Namespace.empty()) - OS << "} // end namespace " << Namespace << "\n"; - - const auto &RegisterClasses = Bank.getRegClasses(); - if (!RegisterClasses.empty()) { - - // RegisterClass enums are stored as uint16_t in the tables. - assert(RegisterClasses.size() <= 0xffff && - "Too many register classes to fit in tables"); - - OS << "\n// Register classes\n\n"; - if (!Namespace.empty()) - OS << "namespace " << Namespace << " {\n"; - OS << "enum {\n"; - for (const auto &RC : RegisterClasses) - OS << " " << RC.getIdName() << " = " << RC.EnumValue << ",\n"; - OS << "\n};\n"; - if (!Namespace.empty()) - OS << "} // end namespace " << Namespace << "\n\n"; - } - - const std::vector &RegAltNameIndices = Target.getRegAltNameIndices(); - // If the only definition is the default NoRegAltName, we don't need to - // emit anything. - if (RegAltNameIndices.size() > 1) { - OS << "\n// Register alternate name indices\n\n"; - if (!Namespace.empty()) - OS << "namespace " << Namespace << " {\n"; - OS << "enum {\n"; - for (unsigned i = 0, e = RegAltNameIndices.size(); i != e; ++i) - OS << " " << RegAltNameIndices[i]->getName() << ",\t// " << i << "\n"; - OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; - OS << "};\n"; - if (!Namespace.empty()) - OS << "} // end namespace " << Namespace << "\n\n"; - } - - auto &SubRegIndices = Bank.getSubRegIndices(); - if (!SubRegIndices.empty()) { - OS << "\n// Subregister indices\n\n"; - std::string Namespace = SubRegIndices.front().getNamespace(); - if (!Namespace.empty()) - OS << "namespace " << Namespace << " {\n"; - OS << "enum : uint16_t {\n NoSubRegister,\n"; - unsigned i = 0; - for (const auto &Idx : SubRegIndices) - OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; - OS << " NUM_TARGET_SUBREGS\n};\n"; - if (!Namespace.empty()) - OS << "} // end namespace " << Namespace << "\n\n"; - } - - OS << "// Register pressure sets enum.\n"; - if (!Namespace.empty()) - OS << "namespace " << Namespace << " {\n"; - OS << "enum RegisterPressureSets {\n"; - unsigned NumSets = Bank.getNumRegPressureSets(); - for (unsigned i = 0; i < NumSets; ++i ) { - const RegUnitSet &RegUnits = Bank.getRegSetAt(i); - OS << " " << RegUnits.Name << " = " << i << ",\n"; - } - OS << "};\n"; - if (!Namespace.empty()) - OS << "} // end namespace " << Namespace << '\n'; - OS << '\n'; - - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_ENUM\n\n"; -} - -static void printInt(raw_ostream &OS, int Val) { - OS << Val; -} - void RegisterInfoEmitter:: -EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, +EmitRegUnitPressure(const CodeGenRegBank &RegBank, const std::string &ClassName) { unsigned NumRCs = RegBank.getRegClasses().size(); unsigned NumSets = RegBank.getNumRegPressureSets(); - OS << "/// Get the weight in units of pressure for this register class.\n" - << "const RegClassWeight &" << ClassName << "::\n" - << "getRegClassWeight(const TargetRegisterClass *RC) const {\n" - << " static const RegClassWeight RCWeightTable[] = {\n"; - for (const auto &RC : RegBank.getRegClasses()) { - const CodeGenRegister::Vec &Regs = RC.getMembers(); - OS << " {" << RC.getWeight(RegBank) << ", "; - if (Regs.empty() || RC.Artificial) - OS << '0'; - else { - std::vector RegUnits; - RC.buildRegUnitSet(RegBank, RegUnits); - OS << RegBank.getRegUnitSetWeight(RegUnits); - } - OS << "}, \t// " << RC.getName() << "\n"; - } - OS << " };\n" - << " return RCWeightTable[RC->getID()];\n" - << "}\n\n"; - + PI.regInfoEmitRegClassWeight(RegBank, ClassName); // Reasonable targets (not ARMv7) have unit weight for all units, so don't // bother generating a table. bool RegUnitsHaveUnitWeight = true; @@ -239,64 +84,11 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, if (RegBank.getRegUnit(UnitIdx).Weight > 1) RegUnitsHaveUnitWeight = false; } - OS << "/// Get the weight in units of pressure for this register unit.\n" - << "unsigned " << ClassName << "::\n" - << "getRegUnitWeight(unsigned RegUnit) const {\n" - << " assert(RegUnit < " << RegBank.getNumNativeRegUnits() - << " && \"invalid register unit\");\n"; - if (!RegUnitsHaveUnitWeight) { - OS << " static const uint8_t RUWeightTable[] = {\n "; - for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); - UnitIdx < UnitEnd; ++UnitIdx) { - const RegUnit &RU = RegBank.getRegUnit(UnitIdx); - assert(RU.Weight < 256 && "RegUnit too heavy"); - OS << RU.Weight << ", "; - } - OS << "};\n" - << " return RUWeightTable[RegUnit];\n"; - } - else { - OS << " // All register units have unit weight.\n" - << " return 1;\n"; - } - OS << "}\n\n"; - - OS << "\n" - << "// Get the number of dimensions of register pressure.\n" - << "unsigned " << ClassName << "::getNumRegPressureSets() const {\n" - << " return " << NumSets << ";\n}\n\n"; - - OS << "// Get the name of this register unit pressure set.\n" - << "const char *" << ClassName << "::\n" - << "getRegPressureSetName(unsigned Idx) const {\n" - << " static const char *PressureNameTable[] = {\n"; - unsigned MaxRegUnitWeight = 0; - for (unsigned i = 0; i < NumSets; ++i ) { - const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); - MaxRegUnitWeight = std::max(MaxRegUnitWeight, RegUnits.Weight); - OS << " \"" << RegUnits.Name << "\",\n"; - } - OS << " };\n" - << " return PressureNameTable[Idx];\n" - << "}\n\n"; - - OS << "// Get the register unit pressure limit for this dimension.\n" - << "// This limit must be adjusted dynamically for reserved registers.\n" - << "unsigned " << ClassName << "::\n" - << "getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const " - "{\n" - << " static const " << getMinimalTypeForRange(MaxRegUnitWeight, 32) - << " PressureLimitTable[] = {\n"; - for (unsigned i = 0; i < NumSets; ++i ) { - const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); - OS << " " << RegUnits.Weight << ", \t// " << i << ": " - << RegUnits.Name << "\n"; - } - OS << " };\n" - << " return PressureLimitTable[Idx];\n" - << "}\n\n"; + PI.regInfoEmitRegUnitWeight(RegBank, ClassName, RegUnitsHaveUnitWeight); + PI.regInfoEmitGetNumRegPressureSets(ClassName, NumSets); + PI.regInfoEmitGetRegPressureTables(RegBank, ClassName, NumSets); - SequenceToOffsetTable> PSetsSeqs; + SequenceToOffsetTable> PSetsSeqs(PI.getLanguage()); // This table may be larger than NumRCs if some register units needed a list // of unit sets that did not correspond to a register class. @@ -314,48 +106,11 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, } PSetsSeqs.layout(); - - OS << "/// Table of pressure sets per register class or unit.\n" - << "static const int RCSetsTable[] = {\n"; - PSetsSeqs.emit(OS, printInt, "-1"); - OS << "};\n\n"; - - OS << "/// Get the dimensions of register pressure impacted by this " - << "register class.\n" - << "/// Returns a -1 terminated array of pressure set IDs\n" - << "const int *" << ClassName << "::\n" - << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"; - OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) - << " RCSetStartTable[] = {\n "; - for (unsigned i = 0, e = NumRCs; i != e; ++i) { - OS << PSetsSeqs.get(PSets[i]) << ","; - } - OS << "};\n" - << " return &RCSetsTable[RCSetStartTable[RC->getID()]];\n" - << "}\n\n"; - - OS << "/// Get the dimensions of register pressure impacted by this " - << "register unit.\n" - << "/// Returns a -1 terminated array of pressure set IDs\n" - << "const int *" << ClassName << "::\n" - << "getRegUnitPressureSets(unsigned RegUnit) const {\n" - << " assert(RegUnit < " << RegBank.getNumNativeRegUnits() - << " && \"invalid register unit\");\n"; - OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) - << " RUSetStartTable[] = {\n "; - for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); - UnitIdx < UnitEnd; ++UnitIdx) { - OS << PSetsSeqs.get(PSets[RegBank.getRegUnit(UnitIdx).RegClassUnitSetsIdx]) - << ","; - } - OS << "};\n" - << " return &RCSetsTable[RUSetStartTable[RegUnit]];\n" - << "}\n\n"; + PI.regInfoEmitRCSetsTable(ClassName, NumRCs, PSetsSeqs, PSets); + PI.regInfoEmitGetRegUnitPressureSets(PSetsSeqs, RegBank, + ClassName, PSets); } -using DwarfRegNumsMapPair = std::pair>; -using DwarfRegNumsVecTy = std::vector; - static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { // Sort and unique to get a map-like vector. We want the last assignment to // match previous behaviour. @@ -381,7 +136,7 @@ static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { } void RegisterInfoEmitter::EmitRegMappingTables( - raw_ostream &OS, const std::deque &Regs, bool isCtor) { + const std::deque &Regs, bool isCtor) { // Collect all information about dwarf register numbers DwarfRegNumsVecTy DwarfRegNums; @@ -404,49 +159,7 @@ void RegisterInfoEmitter::EmitRegMappingTables( DwarfRegNum.second.push_back(-1); StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); - - OS << "// " << Namespace << " Dwarf<->LLVM register mappings.\n"; - - // Emit reverse information about the dwarf register numbers. - for (unsigned j = 0; j < 2; ++j) { - for (unsigned I = 0, E = maxLength; I != E; ++I) { - OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; - OS << (j == 0 ? "DwarfFlavour" : "EHFlavour"); - OS << I << "Dwarf2L[]"; - - if (!isCtor) { - OS << " = {\n"; - - // Store the mapping sorted by the LLVM reg num so lookup can be done - // with a binary search. - std::map Dwarf2LMap; - for (auto &DwarfRegNum : DwarfRegNums) { - int DwarfRegNo = DwarfRegNum.second[I]; - if (DwarfRegNo < 0) - continue; - Dwarf2LMap[DwarfRegNo] = DwarfRegNum.first; - } - - for (auto &I : Dwarf2LMap) - OS << " { " << I.first << "U, " << getQualifiedName(I.second) - << " },\n"; - - OS << "};\n"; - } else { - OS << ";\n"; - } - - // We have to store the size in a const global, it's used in multiple - // places. - OS << "extern const unsigned " << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2LSize"; - if (!isCtor) - OS << " = std::size(" << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2L);\n\n"; - else - OS << ";\n\n"; - } - } + PI.regInfoEmitInfoDwarfRegsRev(Namespace, DwarfRegNums, maxLength, isCtor); for (auto &RE : Regs) { Record *Reg = RE.TheDef; @@ -472,43 +185,11 @@ void RegisterInfoEmitter::EmitRegMappingTables( } // Emit information about the dwarf register numbers. - for (unsigned j = 0; j < 2; ++j) { - for (unsigned i = 0, e = maxLength; i != e; ++i) { - OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; - OS << (j == 0 ? "DwarfFlavour" : "EHFlavour"); - OS << i << "L2Dwarf[]"; - if (!isCtor) { - OS << " = {\n"; - // Store the mapping sorted by the Dwarf reg num so lookup can be done - // with a binary search. - for (auto &DwarfRegNum : DwarfRegNums) { - int RegNo = DwarfRegNum.second[i]; - if (RegNo == -1) // -1 is the default value, don't emit a mapping. - continue; - - OS << " { " << getQualifiedName(DwarfRegNum.first) << ", " << RegNo - << "U },\n"; - } - OS << "};\n"; - } else { - OS << ";\n"; - } - - // We have to store the size in a const global, it's used in multiple - // places. - OS << "extern const unsigned " << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2DwarfSize"; - if (!isCtor) - OS << " = std::size(" << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2Dwarf);\n\n"; - else - OS << ";\n\n"; - } - } + PI.regInfoEmitInfoDwarfRegs(Namespace, DwarfRegNums, maxLength, isCtor); } void RegisterInfoEmitter::EmitRegMapping( - raw_ostream &OS, const std::deque &Regs, bool isCtor) { + const std::deque &Regs, bool isCtor) { // Emit the initializer so the tables from EmitRegMappingTables get wired up // to the MCRegisterInfo object. unsigned maxLength = 0; @@ -518,125 +199,10 @@ void RegisterInfoEmitter::EmitRegMapping( Reg->getValueAsListOfInts("DwarfNumbers").size()); } - if (!maxLength) - return; - StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); - - // Emit reverse information about the dwarf register numbers. - for (unsigned j = 0; j < 2; ++j) { - OS << " switch ("; - if (j == 0) - OS << "DwarfFlavour"; - else - OS << "EHFlavour"; - OS << ") {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown DWARF flavour\");\n"; - - for (unsigned i = 0, e = maxLength; i != e; ++i) { - OS << " case " << i << ":\n"; - OS << " "; - if (!isCtor) - OS << "RI->"; - std::string Tmp; - raw_string_ostream(Tmp) << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i - << "Dwarf2L"; - OS << "mapDwarfRegsToLLVMRegs(" << Tmp << ", " << Tmp << "Size, "; - if (j == 0) - OS << "false"; - else - OS << "true"; - OS << ");\n"; - OS << " break;\n"; - } - OS << " }\n"; - } - - // Emit information about the dwarf register numbers. - for (unsigned j = 0; j < 2; ++j) { - OS << " switch ("; - if (j == 0) - OS << "DwarfFlavour"; - else - OS << "EHFlavour"; - OS << ") {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown DWARF flavour\");\n"; - - for (unsigned i = 0, e = maxLength; i != e; ++i) { - OS << " case " << i << ":\n"; - OS << " "; - if (!isCtor) - OS << "RI->"; - std::string Tmp; - raw_string_ostream(Tmp) << Namespace - << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i - << "L2Dwarf"; - OS << "mapLLVMRegsToDwarfRegs(" << Tmp << ", " << Tmp << "Size, "; - if (j == 0) - OS << "false"; - else - OS << "true"; - OS << ");\n"; - OS << " break;\n"; - } - OS << " }\n"; - } -} - -// Print a BitVector as a sequence of hex numbers using a little-endian mapping. -// Width is the number of bits per hex number. -static void printBitVectorAsHex(raw_ostream &OS, - const BitVector &Bits, - unsigned Width) { - assert(Width <= 32 && "Width too large"); - unsigned Digits = (Width + 3) / 4; - for (unsigned i = 0, e = Bits.size(); i < e; i += Width) { - unsigned Value = 0; - for (unsigned j = 0; j != Width && i + j != e; ++j) - Value |= Bits.test(i + j) << j; - OS << format("0x%0*x, ", Digits, Value); - } -} - -// Helper to emit a set of bits into a constant byte array. -class BitVectorEmitter { - BitVector Values; -public: - void add(unsigned v) { - if (v >= Values.size()) - Values.resize(((v/8)+1)*8); // Round up to the next byte. - Values[v] = true; - } - - void print(raw_ostream &OS) { - printBitVectorAsHex(OS, Values, 8); - } -}; - -static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) { - OS << getEnumName(VT); + PI.regInfoEmitInfoRegMapping(Namespace, maxLength, isCtor); } -static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) { - OS << Idx->EnumValue; -} - -// Differentially encoded register and regunit lists allow for better -// compression on regular register banks. The sequence is computed from the -// differential list as: -// -// out[0] = InitVal; -// out[n+1] = out[n] + diff[n]; // n = 0, 1, ... -// -// The initial value depends on the specific list. The list is terminated by a -// 0 differential which means we can't encode repeated elements. - -typedef SmallVector DiffVec; -typedef SmallVector MaskVec; - // Fills V with differentials between every two consecutive elements of List. static DiffVec &diffEncode(DiffVec &V, SparseBitVector<> List) { assert(V.empty() && "Clear DiffVec before diffEncode."); @@ -663,12 +229,6 @@ DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) { return V; } -static void printDiff16(raw_ostream &OS, int16_t Val) { OS << Val; } - -static void printMask(raw_ostream &OS, LaneBitmask Val) { - OS << "LaneBitmask(0x" << PrintLaneMask(Val) << ')'; -} - // Try to combine Idx's compose map into Vec if it is compatible. // Return false if it's not possible. static bool combine(const CodeGenSubRegIndex *Idx, @@ -691,13 +251,10 @@ static bool combine(const CodeGenSubRegIndex *Idx, } void -RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS, - CodeGenRegBank &RegBank, +RegisterInfoEmitter::emitComposeSubRegIndices(CodeGenRegBank &RegBank, const std::string &ClName) { const auto &SubRegIndices = RegBank.getSubRegIndices(); - OS << "unsigned " << ClName - << "::composeSubRegIndicesImpl(unsigned IdxA, unsigned IdxB) const {\n"; - + PI.regInfoEmitComposeSubRegIndicesImplHead(ClName); // Many sub-register indexes are composition-compatible, meaning that // // compose(IdxA, IdxB) == compose(IdxA', IdxB) @@ -729,40 +286,11 @@ RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS, } // Output the row map if there is multiple rows. - if (Rows.size() > 1) { - OS << " static const " << getMinimalTypeForRange(Rows.size(), 32) - << " RowMap[" << SubRegIndicesSize << "] = {\n "; - for (unsigned i = 0, e = SubRegIndicesSize; i != e; ++i) - OS << RowMap[i] << ", "; - OS << "\n };\n"; - } - - // Output the rows. - OS << " static const " << getMinimalTypeForRange(SubRegIndicesSize + 1, 32) - << " Rows[" << Rows.size() << "][" << SubRegIndicesSize << "] = {\n"; - for (unsigned r = 0, re = Rows.size(); r != re; ++r) { - OS << " { "; - for (unsigned i = 0, e = SubRegIndicesSize; i != e; ++i) - if (Rows[r][i]) - OS << Rows[r][i]->getQualifiedName() << ", "; - else - OS << "0, "; - OS << "},\n"; - } - OS << " };\n\n"; - - OS << " --IdxA; assert(IdxA < " << SubRegIndicesSize << "); (void) IdxA;\n" - << " --IdxB; assert(IdxB < " << SubRegIndicesSize << ");\n"; - if (Rows.size() > 1) - OS << " return Rows[RowMap[IdxA]][IdxB];\n"; - else - OS << " return Rows[0][IdxB];\n"; - OS << "}\n\n"; + PI.regInfoEmitComposeSubRegIndicesImplBody(Rows, SubRegIndicesSize, RowMap); } void -RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, - CodeGenRegBank &RegBank, +RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(CodeGenRegBank &RegBank, const std::string &ClName) { // See the comments in computeSubRegLaneMasks() for our goal here. const auto &SubRegIndices = RegBank.getSubRegIndices(); @@ -792,113 +320,38 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, SubReg2SequenceIndexMap.push_back(Found); } - OS << " struct MaskRolOp {\n" - " LaneBitmask Mask;\n" - " uint8_t RotateLeft;\n" - " };\n" - " static const MaskRolOp LaneMaskComposeSequences[] = {\n"; - unsigned Idx = 0; - for (size_t s = 0, se = Sequences.size(); s != se; ++s) { - OS << " "; - const SmallVectorImpl &Sequence = Sequences[s]; - for (size_t p = 0, pe = Sequence.size(); p != pe; ++p) { - const MaskRolPair &P = Sequence[p]; - printMask(OS << "{ ", P.Mask); - OS << format(", %2u }, ", P.RotateLeft); - } - OS << "{ LaneBitmask::getNone(), 0 }"; - if (s+1 != se) - OS << ", "; - OS << " // Sequence " << Idx << "\n"; - Idx += Sequence.size() + 1; - } - auto *IntType = getMinimalTypeForRange(*std::max_element( - SubReg2SequenceIndexMap.begin(), SubReg2SequenceIndexMap.end())); - OS << " };\n" - " static const " - << IntType << " CompositeSequences[] = {\n"; - for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { - OS << " "; - OS << SubReg2SequenceIndexMap[i]; - if (i+1 != e) - OS << ","; - OS << " // to " << SubRegIndices[i].getName() << "\n"; - } - OS << " };\n\n"; - - OS << "LaneBitmask " << ClName - << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)" - " const {\n" - " --IdxA; assert(IdxA < " << SubRegIndices.size() - << " && \"Subregister index out of bounds\");\n" - " LaneBitmask Result;\n" - " for (const MaskRolOp *Ops =\n" - " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" - " Ops->Mask.any(); ++Ops) {\n" - " LaneBitmask::Type M = LaneMask.getAsInteger() & Ops->Mask.getAsInteger();\n" - " if (unsigned S = Ops->RotateLeft)\n" - " Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - S)));\n" - " else\n" - " Result |= LaneBitmask(M);\n" - " }\n" - " return Result;\n" - "}\n\n"; - - OS << "LaneBitmask " << ClName - << "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, " - " LaneBitmask LaneMask) const {\n" - " LaneMask &= getSubRegIndexLaneMask(IdxA);\n" - " --IdxA; assert(IdxA < " << SubRegIndices.size() - << " && \"Subregister index out of bounds\");\n" - " LaneBitmask Result;\n" - " for (const MaskRolOp *Ops =\n" - " &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" - " Ops->Mask.any(); ++Ops) {\n" - " LaneBitmask::Type M = LaneMask.getAsInteger();\n" - " if (unsigned S = Ops->RotateLeft)\n" - " Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - S)));\n" - " else\n" - " Result |= LaneBitmask(M);\n" - " }\n" - " return Result;\n" - "}\n\n"; + PI.regInfoEmitLaneMaskComposeSeq(Sequences, SubReg2SequenceIndexMap, SubRegIndices); + PI.regInfoEmitComposeSubRegIdxLaneMask(ClName, SubRegIndices); + PI.regInfoEmitComposeSubRegIdxLaneMaskRev(ClName, SubRegIndices); + } // // runMCDesc - Print out MC register descriptions. // void -RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, +RegisterInfoEmitter::runMCDesc(CodeGenTarget &Target, CodeGenRegBank &RegBank) { - emitSourceFileHeader("MC Register Information", OS); - - OS << "\n#ifdef GET_REGINFO_MC_DESC\n"; - OS << "#undef GET_REGINFO_MC_DESC\n\n"; + PI.regInfoEmitSourceFileHeader("MC Register Information"); const auto &Regs = RegBank.getRegisters(); auto &SubRegIndices = RegBank.getSubRegIndices(); - // The lists of sub-registers and super-registers go in the same array. That - // allows us to share suffixes. - typedef std::vector RegVec; // Differentially encoded lists. - SequenceToOffsetTable DiffSeqs; + SequenceToOffsetTable DiffSeqs(PI.getLanguage()); SmallVector SubRegLists(Regs.size()); SmallVector SuperRegLists(Regs.size()); SmallVector RegUnitLists(Regs.size()); // List of lane masks accompanying register unit sequences. - SequenceToOffsetTable LaneMaskSeqs; + SequenceToOffsetTable LaneMaskSeqs(PI.getLanguage()); SmallVector RegUnitLaneMasks(Regs.size()); - // Keep track of sub-register names as well. These are not differentially - // encoded. - typedef SmallVector SubRegIdxVec; - SequenceToOffsetTable>> SubRegIdxSeqs; + SequenceToOffsetTable>> SubRegIdxSeqs(PI.getLanguage()); SmallVector SubRegIdxLists(Regs.size()); - SequenceToOffsetTable RegStrings; + SequenceToOffsetTable RegStrings(PI.getLanguage()); // Precompute register lists for the SequenceToOffsetTable. unsigned i = 0; @@ -939,279 +392,106 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, LaneMaskSeqs.layout(); SubRegIdxSeqs.layout(); - OS << "namespace llvm {\n\n"; + PI.emitIncludeToggle("GET_REGINFO_MC_DESC", true); + PI.emitNamespace("llvm", true); const std::string &TargetName = std::string(Target.getName()); // Emit the shared table of differential lists. - OS << "extern const int16_t " << TargetName << "RegDiffLists[] = {\n"; - DiffSeqs.emit(OS, printDiff16); - OS << "};\n\n"; + PI.regInfoEmitRegDiffLists(TargetName, DiffSeqs); // Emit the shared table of regunit lane mask sequences. - OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[] = {\n"; - // TODO: Omit the terminator since it is never used. The length of this list - // is known implicitly from the corresponding reg unit list. - LaneMaskSeqs.emit(OS, printMask, "LaneBitmask::getAll()"); - OS << "};\n\n"; + PI.regInfoEmitLaneMaskLists(TargetName, LaneMaskSeqs); // Emit the table of sub-register indexes. - OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[] = {\n"; - SubRegIdxSeqs.emit(OS, printSubRegIndex); - OS << "};\n\n"; + PI.regInfoEmitSubRegIdxLists(TargetName, SubRegIdxSeqs); // Emit the table of sub-register index sizes. - OS << "extern const MCRegisterInfo::SubRegCoveredBits " - << TargetName << "SubRegIdxRanges[] = {\n"; - OS << " { " << (uint16_t)-1 << ", " << (uint16_t)-1 << " },\n"; - for (const auto &Idx : SubRegIndices) { - OS << " { " << Idx.Offset << ", " << Idx.Size << " },\t// " - << Idx.getName() << "\n"; - } - OS << "};\n\n"; + PI.regInfoEmitSubRegIdxSizes(TargetName, SubRegIndices); // Emit the string table. RegStrings.layout(); - RegStrings.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + - "RegStrings[]"); - - OS << "extern const MCRegisterDesc " << TargetName - << "RegDesc[] = { // Descriptors\n"; - OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n"; + PI.regInfoEmitSubRegStrTable(TargetName, RegStrings); // Emit the register descriptors now. - i = 0; - for (const auto &Reg : Regs) { - unsigned FirstRU = Reg.getNativeRegUnits().find_first(); - unsigned Offset = DiffSeqs.get(RegUnitLists[i]); - // The value must be kept in sync with MCRegisterInfo.h. - constexpr unsigned RegUnitBits = 12; - assert(isUInt(FirstRU) && "Too many regunits"); - assert(isUInt<32 - RegUnitBits>(Offset) && "Offset is too big"); - OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " - << DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) - << ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " - << (Offset << RegUnitBits | FirstRU) << ", " - << LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n"; - ++i; - } - OS << "};\n\n"; // End of register descriptors... + PI.regInfoEmitRegDesc(LaneMaskSeqs, + Regs, SubRegIdxSeqs, DiffSeqs, + SubRegIdxLists, SubRegLists, + SuperRegLists, RegUnitLists, + RegUnitLaneMasks, + RegStrings); // Emit the table of register unit roots. Each regunit has one or two root // registers. - OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2] = {\n"; - for (unsigned i = 0, e = RegBank.getNumNativeRegUnits(); i != e; ++i) { - ArrayRef Roots = RegBank.getRegUnit(i).getRoots(); - assert(!Roots.empty() && "All regunits must have a root register."); - assert(Roots.size() <= 2 && "More than two roots not supported yet."); - OS << " { "; - ListSeparator LS; - for (const CodeGenRegister *R : Roots) - OS << LS << getQualifiedName(R->TheDef); - OS << " },\n"; - } - OS << "};\n\n"; + PI.regInfoEmitRegUnitRoots(TargetName, RegBank); const auto &RegisterClasses = RegBank.getRegClasses(); // Loop over all of the register classes... emitting each one. - OS << "namespace { // Register classes...\n"; + PI.emitNamespace("", true, "Register classes..."); - SequenceToOffsetTable RegClassStrings; + SequenceToOffsetTable RegClassStrings(PI.getLanguage()); // Emit the register enum value arrays for each RegisterClass - for (const auto &RC : RegisterClasses) { - ArrayRef Order = RC.getOrder(); - - // Give the register class a legal C name if it's anonymous. - const std::string &Name = RC.getName(); - - RegClassStrings.add(Name); - - // Emit the register list now (unless it would be a zero-length array). - if (!Order.empty()) { - OS << " // " << Name << " Register Class...\n" - << " const MCPhysReg " << Name << "[] = {\n "; - for (Record *Reg : Order) { - OS << getQualifiedName(Reg) << ", "; - } - OS << "\n };\n\n"; - - OS << " // " << Name << " Bit set.\n" - << " const uint8_t " << Name << "Bits[] = {\n "; - BitVectorEmitter BVE; - for (Record *Reg : Order) { - BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); - } - BVE.print(OS); - OS << "\n };\n\n"; - } - } - OS << "} // end anonymous namespace\n\n"; + PI.regInfoEmitRegClasses(RegisterClasses, RegClassStrings, Target); + PI.emitNamespace("", false); RegClassStrings.layout(); - RegClassStrings.emitStringLiteralDef( - OS, Twine("extern const char ") + TargetName + "RegClassStrings[]"); - - OS << "extern const MCRegisterClass " << TargetName - << "MCRegisterClasses[] = {\n"; - - for (const auto &RC : RegisterClasses) { - ArrayRef Order = RC.getOrder(); - std::string RCName = Order.empty() ? "nullptr" : RC.getName(); - std::string RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits"; - std::string RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; - assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); - uint32_t RegSize = 0; - if (RC.RSI.isSimple()) - RegSize = RC.RSI.getSimple().RegSize; - OS << " { " << RCName << ", " << RCBitsName << ", " - << RegClassStrings.get(RC.getName()) << ", " << RC.getOrder().size() - << ", " << RCBitsSize << ", " << RC.getQualifiedIdName() << ", " - << RegSize << ", " << RC.CopyCost << ", " - << (RC.Allocatable ? "true" : "false") << " },\n"; - } + PI.regInfoEmitStrLiteralRegClasses(TargetName, RegClassStrings); - OS << "};\n\n"; + PI.regInfoEmitMCRegClassesTable(TargetName, RegisterClasses, RegClassStrings); - EmitRegMappingTables(OS, Regs, false); + EmitRegMappingTables(Regs, false); // Emit Reg encoding table - OS << "extern const uint16_t " << TargetName; - OS << "RegEncodingTable[] = {\n"; - // Add entry for NoRegister - OS << " 0,\n"; - for (const auto &RE : Regs) { - Record *Reg = RE.TheDef; - BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); - uint64_t Value = 0; - for (unsigned b = 0, be = BI->getNumBits(); b != be; ++b) { - if (BitInit *B = dyn_cast(BI->getBit(b))) - Value |= (uint64_t)B->getValue() << b; - } - OS << " " << Value << ",\n"; - } - OS << "};\n"; // End of HW encoding table + PI.regInfoEmitRegEncodingTable(TargetName, Regs); // MCRegisterInfo initialization routine. - OS << "static inline void Init" << TargetName - << "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, " - << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0, unsigned PC = 0) " - "{\n" - << " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, " - << Regs.size() + 1 << ", RA, PC, " << TargetName << "MCRegisterClasses, " - << RegisterClasses.size() << ", " << TargetName << "RegUnitRoots, " - << RegBank.getNumNativeRegUnits() << ", " << TargetName << "RegDiffLists, " - << TargetName << "LaneMaskLists, " << TargetName << "RegStrings, " - << TargetName << "RegClassStrings, " << TargetName << "SubRegIdxLists, " - << (std::distance(SubRegIndices.begin(), SubRegIndices.end()) + 1) << ",\n" - << TargetName << "SubRegIdxRanges, " << TargetName - << "RegEncodingTable);\n\n"; - - EmitRegMapping(OS, Regs, false); - - OS << "}\n\n"; - - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_MC_DESC\n\n"; + PI.regInfoEmitMCRegInfoInit(TargetName, RegBank, Regs, RegisterClasses, SubRegIndices); + + EmitRegMapping(Regs, false); + + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_REGINFO_MC_DESC", false); } void -RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, +RegisterInfoEmitter::runTargetHeader(CodeGenTarget &Target, CodeGenRegBank &RegBank) { - emitSourceFileHeader("Register Information Header Fragment", OS); - - OS << "\n#ifdef GET_REGINFO_HEADER\n"; - OS << "#undef GET_REGINFO_HEADER\n\n"; + PI.regInfoEmitSourceFileHeader("Register Information Header Fragment"); + PI.emitIncludeToggle("GET_REGINFO_HEADER", true); const std::string &TargetName = std::string(Target.getName()); std::string ClassName = TargetName + "GenRegisterInfo"; + PI.regInfoEmitHeaderIncludes(); - OS << "#include \"llvm/CodeGen/TargetRegisterInfo.h\"\n\n"; - - OS << "namespace llvm {\n\n"; - - OS << "class " << TargetName << "FrameLowering;\n\n"; - - OS << "struct " << ClassName << " : public TargetRegisterInfo {\n" - << " explicit " << ClassName - << "(unsigned RA, unsigned D = 0, unsigned E = 0,\n" - << " unsigned PC = 0, unsigned HwMode = 0);\n"; - if (!RegBank.getSubRegIndices().empty()) { - OS << " unsigned composeSubRegIndicesImpl" - << "(unsigned, unsigned) const override;\n" - << " LaneBitmask composeSubRegIndexLaneMaskImpl" - << "(unsigned, LaneBitmask) const override;\n" - << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" - << "(unsigned, LaneBitmask) const override;\n" - << " const TargetRegisterClass *getSubClassWithSubReg" - << "(const TargetRegisterClass *, unsigned) const override;\n" - << " const TargetRegisterClass *getSubRegisterClass" - << "(const TargetRegisterClass *, unsigned) const override;\n"; - } - OS << " const RegClassWeight &getRegClassWeight(" - << "const TargetRegisterClass *RC) const override;\n" - << " unsigned getRegUnitWeight(unsigned RegUnit) const override;\n" - << " unsigned getNumRegPressureSets() const override;\n" - << " const char *getRegPressureSetName(unsigned Idx) const override;\n" - << " unsigned getRegPressureSetLimit(const MachineFunction &MF, unsigned " - "Idx) const override;\n" - << " const int *getRegClassPressureSets(" - << "const TargetRegisterClass *RC) const override;\n" - << " const int *getRegUnitPressureSets(" - << "unsigned RegUnit) const override;\n" - << " ArrayRef getRegMaskNames() const override;\n" - << " ArrayRef getRegMasks() const override;\n" - << " bool isGeneralPurposeRegister(const MachineFunction &, " - << "MCRegister) const override;\n" - << " bool isFixedRegister(const MachineFunction &, " - << "MCRegister) const override;\n" - << " bool isArgumentRegister(const MachineFunction &, " - << "MCRegister) const override;\n" - << " bool isConstantPhysReg(MCRegister PhysReg) const override final;\n" - << " /// Devirtualized TargetFrameLowering.\n" - << " static const " << TargetName << "FrameLowering *getFrameLowering(\n" - << " const MachineFunction &MF);\n"; - + PI.emitNamespace("llvm", true); const auto &RegisterClasses = RegBank.getRegClasses(); - if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) { - OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n"; - } - - OS << "};\n\n"; + PI.regInfoEmitHeaderDecl(TargetName, ClassName, !RegBank.getSubRegIndices().empty(), + llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })); if (!RegisterClasses.empty()) { - OS << "namespace " << RegisterClasses.front().Namespace - << " { // Register classes\n"; - - for (const auto &RC : RegisterClasses) { - const std::string &Name = RC.getName(); - - // Output the extern for the instance. - OS << " extern const TargetRegisterClass " << Name << "RegClass;\n"; - } - OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n"; + PI.emitNamespace(RegisterClasses.front().Namespace.str(), true, "Register classes"); + PI.regInfoEmitHeaderExternRegClasses(RegisterClasses); + PI.emitNamespace(RegisterClasses.front().Namespace.str(), false); } - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_HEADER\n\n"; + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_REGINFO_HEADER", false); } // // runTargetDesc - Output the target register and register file descriptions. // void -RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, +RegisterInfoEmitter::runTargetDesc(CodeGenTarget &Target, CodeGenRegBank &RegBank){ - emitSourceFileHeader("Target Register and Register Classes Information", OS); - - OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; - OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; + PI.regInfoEmitSourceFileHeader("Target Register and Register Classes Information"); - OS << "namespace llvm {\n\n"; + PI.emitIncludeToggle("GET_REGINFO_TARGET_DESC", true); + PI.emitNamespace("llvm", true); // Get access to MCRegisterClass data. - OS << "extern const MCRegisterClass " << Target.getName() - << "MCRegisterClasses[];\n"; + PI.regInfoEmitExternRegClassesArr(Target.getName().str()); // Start out by emitting each of the register classes. const auto &RegisterClasses = RegBank.getRegClasses(); @@ -1232,7 +512,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, unsigned NumModes = CGH.getNumModeIds(); // Build a shared array of value types. - SequenceToOffsetTable> VTSeqs; + SequenceToOffsetTable> VTSeqs(PI.getLanguage()); for (unsigned M = 0; M < NumModes; ++M) { for (const auto &RC : RegisterClasses) { std::vector S; @@ -1243,62 +523,14 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } } VTSeqs.layout(); - OS << "\nstatic const MVT::SimpleValueType VTLists[] = {\n"; - VTSeqs.emit(OS, printSimpleValueType, "MVT::Other"); - OS << "};\n"; + PI.regInfoEmitVTSeqs(VTSeqs); // Emit SubRegIndex names, skipping 0. - OS << "\nstatic const char *SubRegIndexNameTable[] = { \""; - - for (const auto &Idx : SubRegIndices) { - OS << Idx.getName(); - OS << "\", \""; - } - OS << "\" };\n\n"; - - // Emit SubRegIndex lane masks, including 0. - OS << "\nstatic const LaneBitmask SubRegIndexLaneMaskTable[] = {\n " - "LaneBitmask::getAll(),\n"; - for (const auto &Idx : SubRegIndices) { - printMask(OS << " ", Idx.LaneMask); - OS << ", // " << Idx.getName() << '\n'; - } - OS << " };\n\n"; - - OS << "\n"; + PI.regInfoEmitSubRegIdxTable(SubRegIndices); // Now that all of the structs have been emitted, emit the instances. if (!RegisterClasses.empty()) { - OS << "\nstatic const TargetRegisterInfo::RegClassInfo RegClassInfos[]" - << " = {\n"; - for (unsigned M = 0; M < NumModes; ++M) { - unsigned EV = 0; - OS << " // Mode = " << M << " ("; - if (M == 0) - OS << "Default"; - else - OS << CGH.getMode(M).Name; - OS << ")\n"; - for (const auto &RC : RegisterClasses) { - assert(RC.EnumValue == EV && "Unexpected order of register classes"); - ++EV; - (void)EV; - const RegSizeInfo &RI = RC.RSI.get(M); - OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", " - << RI.SpillAlignment; - std::vector VTs; - for (const ValueTypeByHwMode &VVT : RC.VTs) - if (VVT.hasDefault() || VVT.hasMode(M)) - VTs.push_back(VVT.get(M).SimpleTy); - OS << ", /*VTLists+*/" << VTSeqs.get(VTs) << " }, // " - << RC.getName() << '\n'; - } - } - OS << "};\n"; - - - OS << "\nstatic const TargetRegisterClass *const " - << "NullRegClasses[] = { nullptr };\n\n"; + PI.regInfoEmitRegClassInfoTable(RegisterClasses, VTSeqs, CGH, NumModes); // Emit register class bit mask tables. The first bit mask emitted for a // register class, RC, is the set of sub-classes, including RC itself. @@ -1318,124 +550,37 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // // Every bit mask present in the list has at least one bit set. - // Compress the sub-reg index lists. - typedef std::vector IdxList; SmallVector SuperRegIdxLists(RegisterClasses.size()); - SequenceToOffsetTable>> SuperRegIdxSeqs; + SequenceToOffsetTable>> SuperRegIdxSeqs(PI.getLanguage()); BitVector MaskBV(RegisterClasses.size()); - for (const auto &RC : RegisterClasses) { - OS << "static const uint32_t " << RC.getName() - << "SubClassMask[] = {\n "; - printBitVectorAsHex(OS, RC.getSubClasses(), 32); - - // Emit super-reg class masks for any relevant SubRegIndices that can - // project into RC. - IdxList &SRIList = SuperRegIdxLists[RC.EnumValue]; - for (auto &Idx : SubRegIndices) { - MaskBV.reset(); - RC.getSuperRegClasses(&Idx, MaskBV); - if (MaskBV.none()) - continue; - SRIList.push_back(&Idx); - OS << "\n "; - printBitVectorAsHex(OS, MaskBV, 32); - OS << "// " << Idx.getName(); - } - SuperRegIdxSeqs.add(SRIList); - OS << "\n};\n\n"; - } + PI.regInfoEmitSubClassMaskTable(RegisterClasses, + SuperRegIdxLists, + SuperRegIdxSeqs, + SubRegIndices, + MaskBV); - OS << "static const uint16_t SuperRegIdxSeqs[] = {\n"; SuperRegIdxSeqs.layout(); - SuperRegIdxSeqs.emit(OS, printSubRegIndex); - OS << "};\n\n"; + PI.regInfoEmitSuperRegIdxSeqsTable(SuperRegIdxSeqs); // Emit NULL terminated super-class lists. - for (const auto &RC : RegisterClasses) { - ArrayRef Supers = RC.getSuperClasses(); - - // Skip classes without supers. We can reuse NullRegClasses. - if (Supers.empty()) - continue; - - OS << "static const TargetRegisterClass *const " - << RC.getName() << "Superclasses[] = {\n"; - for (const auto *Super : Supers) - OS << " &" << Super->getQualifiedName() << "RegClass,\n"; - OS << " nullptr\n};\n\n"; - } + PI.regInfoEmitSuperClassesTable(RegisterClasses); // Emit methods. - for (const auto &RC : RegisterClasses) { - if (!RC.AltOrderSelect.empty()) { - OS << "\nstatic inline unsigned " << RC.getName() - << "AltOrderSelect(const MachineFunction &MF) {" - << RC.AltOrderSelect << "}\n\n" - << "static ArrayRef " << RC.getName() - << "GetRawAllocationOrder(const MachineFunction &MF) {\n"; - for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) { - ArrayRef Elems = RC.getOrder(oi); - if (!Elems.empty()) { - OS << " static const MCPhysReg AltOrder" << oi << "[] = {"; - for (unsigned elem = 0; elem != Elems.size(); ++elem) - OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]); - OS << " };\n"; - } - } - OS << " const MCRegisterClass &MCR = " << Target.getName() - << "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n" - << " const ArrayRef Order[] = {\n" - << " ArrayRef(MCR.begin(), MCR.getNumRegs()"; - for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) - if (RC.getOrder(oi).empty()) - OS << "),\n ArrayRef("; - else - OS << "),\n ArrayRef(AltOrder" << oi; - OS << ")\n };\n const unsigned Select = " << RC.getName() - << "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders() - << ");\n return Order[Select];\n}\n"; - } - } + PI.regInfoEmitRegClassMethods(RegisterClasses, Target.getName().str()); // Now emit the actual value-initialized register class instances. - OS << "\nnamespace " << RegisterClasses.front().Namespace - << " { // Register class instances\n"; - - for (const auto &RC : RegisterClasses) { - OS << " extern const TargetRegisterClass " << RC.getName() - << "RegClass = {\n " << '&' << Target.getName() - << "MCRegisterClasses[" << RC.getName() << "RegClassID],\n " - << RC.getName() << "SubClassMask,\n SuperRegIdxSeqs + " - << SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n "; - printMask(OS, RC.LaneMask); - OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n " - << (RC.GlobalPriority ? "true" : "false") << ",\n " - << format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n " - << (RC.HasDisjunctSubRegs ? "true" : "false") - << ", /* HasDisjunctSubRegs */\n " - << (RC.CoveredBySubRegs ? "true" : "false") - << ", /* CoveredBySubRegs */\n "; - if (RC.getSuperClasses().empty()) - OS << "NullRegClasses,\n "; - else - OS << RC.getName() << "Superclasses,\n "; - if (RC.AltOrderSelect.empty()) - OS << "nullptr\n"; - else - OS << RC.getName() << "GetRawAllocationOrder\n"; - OS << " };\n\n"; - } - - OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n"; + PI.emitNamespace(RegisterClasses.front().Namespace.str(), true, "Register class instances"); + PI.regInfomitRegClassInstances(RegisterClasses, + SuperRegIdxSeqs, + SuperRegIdxLists, + Target.getName().str()); + PI.emitNamespace(RegisterClasses.front().Namespace.str(), false); } - OS << "\nnamespace {\n"; - OS << " const TargetRegisterClass *const RegisterClasses[] = {\n"; - for (const auto &RC : RegisterClasses) - OS << " &" << RC.getQualifiedName() << "RegClass,\n"; - OS << " };\n"; - OS << "} // end anonymous namespace\n"; + PI.emitNamespace("", true); + PI.regInfoEmitRegClassTable(RegisterClasses); + PI.emitNamespace("", false); // Emit extra information about registers. const std::string &TargetName = std::string(Target.getName()); @@ -1465,26 +610,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // Emit the cost values as a 1D-array after grouping them by their indices, // i.e. the costs for all registers corresponds to index 0, 1, 2, etc. // Size of the emitted array should be NumRegCosts * (Regs.size() + 1). - OS << "\nstatic const uint8_t " - << "CostPerUseTable[] = { \n"; - for (unsigned int I = 0; I < NumRegCosts; ++I) { - for (unsigned J = I, E = AllRegCostPerUse.size(); J < E; J += NumRegCosts) - OS << AllRegCostPerUse[J] << ", "; - } - OS << "};\n\n"; - - OS << "\nstatic const bool " - << "InAllocatableClassTable[] = { \n"; - for (unsigned I = 0, E = InAllocClass.size(); I < E; ++I) { - OS << (InAllocClass[I] ? "true" : "false") << ", "; - } - OS << "};\n\n"; - - OS << "\nstatic const TargetRegisterInfoDesc " << TargetName - << "RegInfoDesc = { // Extra Descriptors\n"; - OS << "CostPerUseTable, " << NumRegCosts << ", " - << "InAllocatableClassTable"; - OS << "};\n\n"; // End of register descriptors... + PI.regInfoEmitCostPerUseTable(AllRegCostPerUse, NumRegCosts); + PI.regInfoEmitInAllocatableClassTable(InAllocClass); + PI.regInfoEmitRegExtraDesc(TargetName, NumRegCosts); + // End of register descriptors... std::string ClassName = Target.getName().str() + "GenRegisterInfo"; @@ -1492,90 +621,19 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, std::distance(SubRegIndices.begin(), SubRegIndices.end()); if (!SubRegIndices.empty()) { - emitComposeSubRegIndices(OS, RegBank, ClassName); - emitComposeSubRegIndexLaneMask(OS, RegBank, ClassName); + emitComposeSubRegIndices(RegBank, ClassName); + emitComposeSubRegIndexLaneMask(RegBank, ClassName); } if (!SubRegIndices.empty()) { - // Emit getSubClassWithSubReg. - OS << "const TargetRegisterClass *" << ClassName - << "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)" - << " const {\n"; - // Use the smallest type that can hold a regclass ID with room for a - // sentinel. - if (RegisterClasses.size() <= UINT8_MAX) - OS << " static const uint8_t Table["; - else if (RegisterClasses.size() <= UINT16_MAX) - OS << " static const uint16_t Table["; - else - PrintFatalError("Too many register classes."); - OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; - for (const auto &RC : RegisterClasses) { - OS << " {\t// " << RC.getName() << "\n"; - for (auto &Idx : SubRegIndices) { - if (CodeGenRegisterClass *SRC = RC.getSubClassWithSubReg(&Idx)) - OS << " " << SRC->EnumValue + 1 << ",\t// " << Idx.getName() - << " -> " << SRC->getName() << "\n"; - else - OS << " 0,\t// " << Idx.getName() << "\n"; - } - OS << " },\n"; - } - OS << " };\n assert(RC && \"Missing regclass\");\n" - << " if (!Idx) return RC;\n --Idx;\n" - << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" - << " unsigned TV = Table[RC->getID()][Idx];\n" - << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; - - // Emit getSubRegisterClass - OS << "const TargetRegisterClass *" << ClassName - << "::getSubRegisterClass(const TargetRegisterClass *RC, unsigned Idx)" - << " const {\n"; - - // Use the smallest type that can hold a regclass ID with room for a - // sentinel. - if (RegisterClasses.size() <= UINT8_MAX) - OS << " static const uint8_t Table["; - else if (RegisterClasses.size() <= UINT16_MAX) - OS << " static const uint16_t Table["; - else - PrintFatalError("Too many register classes."); - - OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; - - for (const auto &RC : RegisterClasses) { - OS << " {\t// " << RC.getName() << '\n'; - for (auto &Idx : SubRegIndices) { - std::optional> - MatchingSubClass = RC.getMatchingSubClassWithSubRegs(RegBank, &Idx); - - unsigned EnumValue = 0; - if (MatchingSubClass) { - CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; - EnumValue = SubRegClass->EnumValue + 1; - } - - OS << " " << EnumValue << ",\t// " - << RC.getName() << ':' << Idx.getName(); - - if (MatchingSubClass) { - CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; - OS << " -> " << SubRegClass->getName(); - } - - OS << '\n'; - } - - OS << " },\n"; - } - OS << " };\n assert(RC && \"Missing regclass\");\n" - << " if (!Idx) return RC;\n --Idx;\n" - << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" - << " unsigned TV = Table[RC->getID()][Idx];\n" - << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; + PI.regInfoEmitSubClassSubRegGetter(ClassName, + SubRegIndicesSize, + SubRegIndices, + RegisterClasses, + RegBank); } - EmitRegUnitPressure(OS, RegBank, ClassName); + EmitRegUnitPressure(RegBank, ClassName); // Emit register base class mapper if (!RegisterClasses.empty()) { @@ -1598,78 +656,23 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, }; llvm::stable_sort(BaseClasses, BaseClassOrdering()); - OS << "\n// Register to base register class mapping\n\n"; - OS << "\n"; - OS << "const TargetRegisterClass *" << ClassName - << "::getPhysRegBaseClass(MCRegister Reg)" - << " const {\n"; - OS << " static const uint16_t InvalidRegClassID = UINT16_MAX;\n\n"; - OS << " static const uint16_t Mapping[" << Regs.size() + 1 << "] = {\n"; - OS << " InvalidRegClassID, // NoRegister\n"; - for (const CodeGenRegister &Reg : Regs) { - const CodeGenRegisterClass *BaseRC = nullptr; - for (const CodeGenRegisterClass *RC : BaseClasses) { - if (is_contained(RC->getMembers(), &Reg)) { - BaseRC = RC; - break; - } - } - - OS << " " - << (BaseRC ? BaseRC->getQualifiedIdName() : "InvalidRegClassID") - << ", // " << Reg.getName() << "\n"; - } - OS << " };\n\n" - " assert(Reg < ArrayRef(Mapping).size());\n" - " unsigned RCID = Mapping[Reg];\n" - " if (RCID == InvalidRegClassID)\n" - " return nullptr;\n" - " return RegisterClasses[RCID];\n" - "}\n"; + PI.regInfoEmitRegBaseClassMapping(ClassName, BaseClasses, Regs); } } // Emit the constructor of the class... - OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n"; - OS << "extern const int16_t " << TargetName << "RegDiffLists[];\n"; - OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[];\n"; - OS << "extern const char " << TargetName << "RegStrings[];\n"; - OS << "extern const char " << TargetName << "RegClassStrings[];\n"; - OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2];\n"; - OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n"; - OS << "extern const MCRegisterInfo::SubRegCoveredBits " - << TargetName << "SubRegIdxRanges[];\n"; - OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n"; - - EmitRegMappingTables(OS, Regs, true); - - OS << ClassName << "::\n" - << ClassName - << "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,\n" - " unsigned PC, unsigned HwMode)\n" - << " : TargetRegisterInfo(&" << TargetName << "RegInfoDesc" - << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() << ",\n" - << " SubRegIndexNameTable, SubRegIndexLaneMaskTable,\n" - << " "; - printMask(OS, RegBank.CoveringLanes); - OS << ", RegClassInfos, VTLists, HwMode) {\n" - << " InitMCRegisterInfo(" << TargetName << "RegDesc, " << Regs.size() + 1 - << ", RA, PC,\n " << TargetName - << "MCRegisterClasses, " << RegisterClasses.size() << ",\n" - << " " << TargetName << "RegUnitRoots,\n" - << " " << RegBank.getNumNativeRegUnits() << ",\n" - << " " << TargetName << "RegDiffLists,\n" - << " " << TargetName << "LaneMaskLists,\n" - << " " << TargetName << "RegStrings,\n" - << " " << TargetName << "RegClassStrings,\n" - << " " << TargetName << "SubRegIdxLists,\n" - << " " << SubRegIndicesSize + 1 << ",\n" - << " " << TargetName << "SubRegIdxRanges,\n" - << " " << TargetName << "RegEncodingTable);\n\n"; - - EmitRegMapping(OS, Regs, true); - - OS << "}\n\n"; + PI.regInfoEmitExternTableDecl(TargetName); + + EmitRegMappingTables(Regs, true); + + PI.regInfoEmitRegClassInit(TargetName, + ClassName, + RegBank, + RegisterClasses, + Regs, + SubRegIndicesSize); + + EmitRegMapping(Regs, true); // Emit CalleeSavedRegs information. std::vector CSRSets = @@ -1680,11 +683,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, assert(Regs && "Cannot expand CalleeSavedRegs instance"); // Emit the *_SaveList list of callee-saved registers. - OS << "static const MCPhysReg " << CSRSet->getName() - << "_SaveList[] = { "; - for (unsigned r = 0, re = Regs->size(); r != re; ++r) - OS << getQualifiedName((*Regs)[r]) << ", "; - OS << "0 };\n"; + PI.regInfoEmitSaveListTable(CSRSet, Regs); // Emit the *_RegMask bit mask of call-preserved registers. BitVector Covered = RegBank.computeCoveredRegisters(*Regs); @@ -1708,121 +707,46 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, Covered |= RegBank.computeCoveredRegisters( ArrayRef(ConstantSet.begin(), ConstantSet.end())); - OS << "static const uint32_t " << CSRSet->getName() - << "_RegMask[] = { "; - printBitVectorAsHex(OS, Covered, 32); - OS << "};\n"; - } - OS << "\n\n"; - - OS << "ArrayRef " << ClassName - << "::getRegMasks() const {\n"; - if (!CSRSets.empty()) { - OS << " static const uint32_t *const Masks[] = {\n"; - for (Record *CSRSet : CSRSets) - OS << " " << CSRSet->getName() << "_RegMask,\n"; - OS << " };\n"; - OS << " return ArrayRef(Masks);\n"; - } else { - OS << " return std::nullopt;\n"; + PI.regInfoEmitRegMaskTable(CSRSet->getName().str(), Covered); } - OS << "}\n\n"; + PI.emitNewline(2); + PI.regInfoEmitGetRegMasks(CSRSets, ClassName); const std::list &RegCategories = RegBank.getRegCategories(); - OS << "bool " << ClassName << "::\n" - << "isGeneralPurposeRegister(const MachineFunction &MF, " - << "MCRegister PhysReg) const {\n" - << " return\n"; - for (const CodeGenRegisterCategory &Category : RegCategories) - if (Category.getName() == "GeneralPurposeRegisters") { - for (const CodeGenRegisterClass *RC : Category.getClasses()) - OS << " " << RC->getQualifiedName() - << "RegClass.contains(PhysReg) ||\n"; - break; - } - OS << " false;\n"; - OS << "}\n\n"; - - OS << "bool " << ClassName << "::\n" - << "isFixedRegister(const MachineFunction &MF, " - << "MCRegister PhysReg) const {\n" - << " return\n"; - for (const CodeGenRegisterCategory &Category : RegCategories) - if (Category.getName() == "FixedRegisters") { - for (const CodeGenRegisterClass *RC : Category.getClasses()) - OS << " " << RC->getQualifiedName() - << "RegClass.contains(PhysReg) ||\n"; - break; - } - OS << " false;\n"; - OS << "}\n\n"; - - OS << "bool " << ClassName << "::\n" - << "isArgumentRegister(const MachineFunction &MF, " - << "MCRegister PhysReg) const {\n" - << " return\n"; - for (const CodeGenRegisterCategory &Category : RegCategories) - if (Category.getName() == "ArgumentRegisters") { - for (const CodeGenRegisterClass *RC : Category.getClasses()) - OS << " " << RC->getQualifiedName() - << "RegClass.contains(PhysReg) ||\n"; - break; - } - OS << " false;\n"; - OS << "}\n\n"; + PI.regInfoEmitGPRCheck(ClassName, RegCategories); + PI.regInfoEmitFixedRegCheck(ClassName, RegCategories); + PI.regInfoEmitArgRegCheck(ClassName, RegCategories); - OS << "bool " << ClassName << "::\n" - << "isConstantPhysReg(MCRegister PhysReg) const {\n" - << " return\n"; - for (const auto &Reg : Regs) - if (Reg.Constant) - OS << " PhysReg == " << getQualifiedName(Reg.TheDef) << " ||\n"; - OS << " false;\n"; - OS << "}\n\n"; - - OS << "ArrayRef " << ClassName - << "::getRegMaskNames() const {\n"; - if (!CSRSets.empty()) { - OS << " static const char *Names[] = {\n"; - for (Record *CSRSet : CSRSets) - OS << " " << '"' << CSRSet->getName() << '"' << ",\n"; - OS << " };\n"; - OS << " return ArrayRef(Names);\n"; - } else { - OS << " return std::nullopt;\n"; - } - OS << "}\n\n"; + PI.regInfoEmitIsConstantPhysReg(Regs, ClassName); + PI.regInfoEmitGetRegMaskNames(CSRSets, ClassName); - OS << "const " << TargetName << "FrameLowering *\n" << TargetName - << "GenRegisterInfo::getFrameLowering(const MachineFunction &MF) {\n" - << " return static_cast(\n" - << " MF.getSubtarget().getFrameLowering());\n" - << "}\n\n"; + PI.regInfoEmitGetFrameLowering(TargetName); - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_TARGET_DESC\n\n"; + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_REGINFO_TARGET_DESC", false); } -void RegisterInfoEmitter::run(raw_ostream &OS) { +void RegisterInfoEmitter::run() { CodeGenRegBank &RegBank = Target.getRegBank(); Records.startTimer("Print enums"); - runEnums(OS, Target, RegBank); + + PI.regInfoEmitEnums(Target, RegBank); Records.startTimer("Print MC registers"); - runMCDesc(OS, Target, RegBank); + runMCDesc(Target, RegBank); Records.startTimer("Print header fragment"); - runTargetHeader(OS, Target, RegBank); + runTargetHeader(Target, RegBank); Records.startTimer("Print target registers"); - runTargetDesc(OS, Target, RegBank); + runTargetDesc(Target, RegBank); if (RegisterInfoDebug) debugDump(errs()); } -void RegisterInfoEmitter::debugDump(raw_ostream &OS) { +void RegisterInfoEmitter::debugDump(raw_ostream &ErrOS) { CodeGenRegBank &RegBank = Target.getRegBank(); const CodeGenHwModes &CGH = Target.getHwModes(); unsigned NumModes = CGH.getNumModeIds(); @@ -1833,60 +757,80 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) { }; for (const CodeGenRegisterClass &RC : RegBank.getRegClasses()) { - OS << "RegisterClass " << RC.getName() << ":\n"; - OS << "\tSpillSize: {"; + ErrOS << "RegisterClass " << RC.getName() << ":\n"; + ErrOS << "\tSpillSize: {"; for (unsigned M = 0; M != NumModes; ++M) - OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillSize; - OS << " }\n\tSpillAlignment: {"; + ErrOS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillSize; + ErrOS << " }\n\tSpillAlignment: {"; for (unsigned M = 0; M != NumModes; ++M) - OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillAlignment; - OS << " }\n\tNumRegs: " << RC.getMembers().size() << '\n'; - OS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n'; - OS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n'; - OS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n'; - OS << "\tAllocatable: " << RC.Allocatable << '\n'; - OS << "\tAllocationPriority: " << unsigned(RC.AllocationPriority) << '\n'; - OS << "\tRegs:"; + ErrOS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillAlignment; + ErrOS << " }\n\tNumRegs: " << RC.getMembers().size() << '\n'; + ErrOS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n'; + ErrOS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n'; + ErrOS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n'; + ErrOS << "\tAllocatable: " << RC.Allocatable << '\n'; + ErrOS << "\tAllocationPriority: " << unsigned(RC.AllocationPriority) << '\n'; + ErrOS << "\tRegs:"; for (const CodeGenRegister *R : RC.getMembers()) { - OS << " " << R->getName(); + ErrOS << " " << R->getName(); } - OS << '\n'; - OS << "\tSubClasses:"; + ErrOS << '\n'; + ErrOS << "\tSubClasses:"; const BitVector &SubClasses = RC.getSubClasses(); for (const CodeGenRegisterClass &SRC : RegBank.getRegClasses()) { if (!SubClasses.test(SRC.EnumValue)) continue; - OS << " " << SRC.getName(); + ErrOS << " " << SRC.getName(); } - OS << '\n'; - OS << "\tSuperClasses:"; + ErrOS << '\n'; + ErrOS << "\tSuperClasses:"; for (const CodeGenRegisterClass *SRC : RC.getSuperClasses()) { - OS << " " << SRC->getName(); + ErrOS << " " << SRC->getName(); } - OS << '\n'; + ErrOS << '\n'; } for (const CodeGenSubRegIndex &SRI : RegBank.getSubRegIndices()) { - OS << "SubRegIndex " << SRI.getName() << ":\n"; - OS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n'; - OS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n'; - OS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n'; + ErrOS << "SubRegIndex " << SRI.getName() << ":\n"; + ErrOS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n'; + ErrOS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n'; + ErrOS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n'; } for (const CodeGenRegister &R : RegBank.getRegisters()) { - OS << "Register " << R.getName() << ":\n"; - OS << "\tCostPerUse: "; + ErrOS << "Register " << R.getName() << ":\n"; + ErrOS << "\tCostPerUse: "; for (const auto &Cost : R.CostPerUse) - OS << Cost << " "; - OS << '\n'; - OS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n'; - OS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n'; + ErrOS << Cost << " "; + ErrOS << '\n'; + ErrOS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n'; + ErrOS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n'; for (std::pair P : R.getSubRegs()) { - OS << "\tSubReg " << P.first->getName() + ErrOS << "\tSubReg " << P.first->getName() << " = " << P.second->getName() << '\n'; } } } -static TableGen::Emitter::OptClass - X("gen-register-info", "Generate registers and register classes info"); +void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) { + formatted_raw_ostream FOS(OS); + PrinterLanguage const PLang = PrinterLLVM::getLanguage(); + PrinterLLVM *PI = nullptr; + switch (PLang) { + default: + PrintFatalNote( + "RegisterInfo backend does not support the selected ouput language."); + return; + case PRINTER_LANG_CPP: + PI = new PrinterLLVM(FOS); + break; + case PRINTER_LANG_CAPSTONE_C: + PI = new PrinterCapstone(FOS); + break; + } + RegisterInfoEmitter(RK, *PI).run(); + delete PI; +} + +static TableGen::Emitter::Opt X("gen-register-info", EmitRegisterInfo, + "Generate registers and register classes info"); diff --git a/llvm/utils/TableGen/RegisterInfoEmitterTypes.h b/llvm/utils/TableGen/RegisterInfoEmitterTypes.h new file mode 100644 index 000000000000..fa96506eb9cb --- /dev/null +++ b/llvm/utils/TableGen/RegisterInfoEmitterTypes.h @@ -0,0 +1,72 @@ +//===- RegisterInfoEmitterTypes.h - Register Emitter Types -*- 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 +// +//===-----------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_REGISTERINFOEMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_REGISTERINFOEMITTERTYPES_H + +#include "CodeGenHwModes.h" +#include "CodeGenRegisters.h" +#include "CodeGenTarget.h" +#include "InfoByHwMode.h" +#include "SequenceToOffsetTable.h" +#include "Types.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +// Compress the sub-reg index lists. +typedef std::vector IdxList; + +// Keep track of sub-register names as well. These are not differentially +// encoded. +typedef SmallVector SubRegIdxVec; + +// Differentially encoded register and regunit lists allow for better +// compression on regular register banks. The sequence is computed from the +// differential list as: +// +// out[0] = InitVal; +// out[n+1] = out[n] + diff[n]; // n = 0, 1, ... +// +// The initial value depends on the specific list. The list is terminated by a +// 0 differential which means we can't encode repeated elements. +typedef SmallVector DiffVec; +typedef SmallVector MaskVec; + +// The lists of sub-registers and super-registers go in the same array. That +// allows us to share suffixes. +typedef std::vector RegVec; + +using DwarfRegNumsMapPair = std::pair>; +using DwarfRegNumsVecTy = std::vector; + +#endif // LLVM_UTILS_TABLEGEN_REGISTERINFOEMITTERTYPES_H diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp index 9987d1ec73d9..a28a4082de62 100644 --- a/llvm/utils/TableGen/SearchableTableEmitter.cpp +++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp @@ -12,18 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenIntrinsics.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include -#include -#include -#include +#include "Printer.h" +#include "PrinterTypes.h" +#include "SearchableTablesTypes.h" using namespace llvm; @@ -31,62 +22,10 @@ using namespace llvm; namespace { -int64_t getAsInt(Init *B) { - return cast( - B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper()))) - ->getValue(); -} int64_t getInt(Record *R, StringRef Field) { return getAsInt(R->getValueInit(Field)); } -struct GenericEnum { - using Entry = std::pair; - - std::string Name; - Record *Class = nullptr; - std::string PreprocessorGuard; - std::vector> Entries; - DenseMap EntryMap; -}; - -struct GenericField { - std::string Name; - RecTy *RecType = nullptr; - bool IsCode = false; - bool IsIntrinsic = false; - bool IsInstruction = false; - GenericEnum *Enum = nullptr; - - GenericField(StringRef Name) : Name(std::string(Name)) {} -}; - -struct SearchIndex { - std::string Name; - SMLoc Loc; // Source location of PrimaryKey or Key field definition. - SmallVector Fields; - bool EarlyOut = false; -}; - -struct GenericTable { - std::string Name; - ArrayRef Locs; // Source locations from the Record instance. - std::string PreprocessorGuard; - std::string CppTypeName; - SmallVector Fields; - std::vector Entries; - - std::unique_ptr PrimaryKey; - SmallVector, 2> Indices; - - const GenericField *getFieldByName(StringRef Name) const { - for (const auto &Field : Fields) { - if (Name == Field.Name) - return &Field; - } - return nullptr; - } -}; class SearchableTableEmitter { RecordKeeper &Records; @@ -94,47 +33,16 @@ class SearchableTableEmitter { std::vector> Enums; DenseMap EnumMap; std::set PreprocessorGuards; + PrinterLLVM &PI; public: - SearchableTableEmitter(RecordKeeper &R) : Records(R) {} + SearchableTableEmitter(RecordKeeper &R, PrinterLLVM &PI) : Records(R), PI(PI) {} - void run(raw_ostream &OS); + void run(); private: typedef std::pair SearchTableEntry; - enum TypeContext { - TypeInStaticStruct, - TypeInTempStruct, - TypeInArgument, - }; - - std::string primaryRepresentation(SMLoc Loc, const GenericField &Field, - Init *I) { - if (StringInit *SI = dyn_cast(I)) { - if (Field.IsCode || SI->hasCodeFormat()) - return std::string(SI->getValue()); - else - return SI->getAsString(); - } else if (BitsInit *BI = dyn_cast(I)) - return "0x" + utohexstr(getAsInt(BI)); - else if (BitInit *BI = dyn_cast(I)) - return BI->getValue() ? "true" : "false"; - else if (Field.IsIntrinsic) - return "Intrinsic::" + getIntrinsic(I).EnumName; - else if (Field.IsInstruction) - return I->getAsString(); - else if (Field.Enum) { - auto *Entry = Field.Enum->EntryMap[cast(I)->getDef()]; - if (!Entry) - PrintFatalError(Loc, - Twine("Entry for field '") + Field.Name + "' is null"); - return std::string(Entry->first); - } - PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + - "'; expected: bit, bits, string, or code"); - } - bool isIntrinsic(Init *I) { if (DefInit *DI = dyn_cast(I)) return DI->getDef()->isSubClassOf("Intrinsic"); @@ -144,52 +52,17 @@ class SearchableTableEmitter { CodeGenIntrinsic &getIntrinsic(Init *I) { std::unique_ptr &Intr = Intrinsics[I]; if (!Intr) - Intr = std::make_unique(cast(I)->getDef(), + Intr = std::make_unique(dyn_cast(I)->getDef(), std::vector()); return *Intr; } bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index); - std::string searchableFieldType(const GenericTable &Table, - const SearchIndex &Index, - const GenericField &Field, TypeContext Ctx) { - if (isa(Field.RecType)) { - if (Ctx == TypeInStaticStruct) - return "const char *"; - if (Ctx == TypeInTempStruct) - return "std::string"; - return "StringRef"; - } else if (BitsRecTy *BI = dyn_cast(Field.RecType)) { - unsigned NumBits = BI->getNumBits(); - if (NumBits <= 8) - return "uint8_t"; - if (NumBits <= 16) - return "uint16_t"; - if (NumBits <= 32) - return "uint32_t"; - if (NumBits <= 64) - return "uint64_t"; - PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + - "' lookup method '" + Index.Name + - "', key field '" + Field.Name + - "' of type bits is too large"); - } else if (isa(Field.RecType)) { - return "bool"; - } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) - return "unsigned"; - PrintFatalError(Index.Loc, - Twine("In table '") + Table.Name + "' lookup method '" + - Index.Name + "', key field '" + Field.Name + - "' has invalid type: " + Field.RecType->getAsString()); - } - - void emitGenericTable(const GenericTable &Table, raw_ostream &OS); + void emitGenericTable(const GenericTable &Table); void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS); - void emitLookupDeclaration(const GenericTable &Table, - const SearchIndex &Index, raw_ostream &OS); void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index, - bool IsPrimary, raw_ostream &OS); + bool IsPrimary); void emitIfdef(StringRef Guard, raw_ostream &OS); bool parseFieldType(GenericField &Field, Init *II); @@ -269,8 +142,10 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, if (LHSv > RHSv) return false; } else { - std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI); - std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI); + StringRef LHSIEnum = (Field.IsIntrinsic ? getIntrinsic(LHSI).EnumName : ""); + StringRef RHSIEnum = (Field.IsIntrinsic ? getIntrinsic(LHSI).EnumName : ""); + std::string LHSs = PI.searchableTablesPrimaryRepresentation(Index.Loc, Field, LHSI, LHSIEnum); + std::string RHSs = PI.searchableTablesPrimaryRepresentation(Index.Loc, Field, RHSI, RHSIEnum); if (isa(Field.RecType)) { LHSs = StringRef(LHSs).upper(); @@ -287,31 +162,10 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, return false; } -void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) { - OS << "#ifdef " << Guard << "\n"; - PreprocessorGuards.insert(std::string(Guard)); -} - -/// Emit a generic enum. -void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum, - raw_ostream &OS) { - emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS); - - OS << "enum " << Enum.Name << " {\n"; - for (const auto &Entry : Enum.Entries) - OS << " " << Entry->first << " = " << Entry->second << ",\n"; - OS << "};\n"; - - OS << "#endif\n\n"; -} - void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, const SearchIndex &Index, - bool IsPrimary, - raw_ostream &OS) { - OS << "\n"; - emitLookupDeclaration(Table, Index, OS); - OS << " {\n"; + bool IsPrimary) { + PI.searchableTablesEmitLookupDeclaration(Table, Index, ST_IMPL_OS); std::vector IndexRowsStorage; ArrayRef IndexRows; @@ -323,16 +177,9 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, IndexName = Table.Name; IndexRows = Table.Entries; } else { - OS << " struct IndexType {\n"; - for (const auto &Field : Index.Fields) { - OS << " " - << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " " - << Field.Name << ";\n"; - } - OS << " unsigned _index;\n"; - OS << " };\n"; + PI.searchableTablesEmitIndexTypeStruct(Table, Index); - OS << " static const struct IndexType Index[] = {\n"; + PI.searchableTablesEmitIndexArrayI(); std::vector> Entries; Entries.reserve(Table.Entries.size()); @@ -348,19 +195,20 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, for (const auto &Entry : Entries) { IndexRowsStorage.push_back(Entry.first); - OS << " { "; + PI.searchableTablesEmitIndexArrayII(); ListSeparator LS; for (const auto &Field : Index.Fields) { - std::string Repr = primaryRepresentation( - Index.Loc, Field, Entry.first->getValueInit(Field.Name)); + StringRef EnumName = (Field.IsIntrinsic ? getIntrinsic(Entry.first->getValueInit(Field.Name)).EnumName : ""); + std::string Repr = PI.searchableTablesPrimaryRepresentation( + Index.Loc, Field, Entry.first->getValueInit(Field.Name), + EnumName); if (isa(Field.RecType)) Repr = StringRef(Repr).upper(); - OS << LS << Repr; + PI.searchableTablesEmitIndexArrayIII(LS, Repr); } - OS << ", " << Entry.second << " },\n"; + PI.searchableTablesEmitIndexArrayIV(Entry); } - - OS << " };\n\n"; + PI.searchableTablesEmitIndexArrayV(); IndexTypeName = "IndexType"; IndexName = "Index"; @@ -381,149 +229,75 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, } if (IsContiguous) { - OS << " auto Table = ArrayRef(" << IndexName << ");\n"; - OS << " size_t Idx = " << Index.Fields[0].Name << ";\n"; - OS << " return Idx >= Table.size() ? nullptr : "; - if (IsPrimary) - OS << "&Table[Idx]"; - else - OS << "&" << Table.Name << "[Table[Idx]._index]"; - OS << ";\n"; - OS << "}\n"; + PI.searchableTablesEmitIsContiguousCase(IndexName, Table, Index, IsPrimary); return; } if (Index.EarlyOut) { const GenericField &Field = Index.Fields[0]; - std::string FirstRepr = primaryRepresentation( - Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name)); - std::string LastRepr = primaryRepresentation( - Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name)); - OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n"; - OS << " (" << Field.Name << " > " << LastRepr << "))\n"; - OS << " return nullptr;\n\n"; - } - - OS << " struct KeyType {\n"; - for (const auto &Field : Index.Fields) { - OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct) - << " " << Field.Name << ";\n"; - } - OS << " };\n"; - OS << " KeyType Key = {"; - ListSeparator LS; - for (const auto &Field : Index.Fields) { - OS << LS << Field.Name; - if (isa(Field.RecType)) { - OS << ".upper()"; - if (IsPrimary) - PrintFatalError(Index.Loc, - Twine("In table '") + Table.Name + - "', use a secondary lookup method for " - "case-insensitive comparison of field '" + - Field.Name + "'"); - } - } - OS << "};\n"; - - OS << " auto Table = ArrayRef(" << IndexName << ");\n"; - OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; - OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n"; - - for (const auto &Field : Index.Fields) { - if (isa(Field.RecType)) { - OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name - << ").compare(RHS." << Field.Name << ");\n"; - OS << " if (Cmp" << Field.Name << " < 0) return true;\n"; - OS << " if (Cmp" << Field.Name << " > 0) return false;\n"; - } else if (Field.Enum) { - // Explicitly cast to unsigned, because the signedness of enums is - // compiler-dependent. - OS << " if ((unsigned)LHS." << Field.Name << " < (unsigned)RHS." - << Field.Name << ")\n"; - OS << " return true;\n"; - OS << " if ((unsigned)LHS." << Field.Name << " > (unsigned)RHS." - << Field.Name << ")\n"; - OS << " return false;\n"; - } else { - OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n"; - OS << " return true;\n"; - OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n"; - OS << " return false;\n"; - } + StringRef EnumNameA = (Field.IsIntrinsic ? + getIntrinsic(IndexRows[0]->getValueInit(Field.Name)).EnumName : + ""); + std::string FirstRepr = PI.searchableTablesPrimaryRepresentation( + Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name), + EnumNameA); + + StringRef EnumNameB = (Field.IsIntrinsic ? + getIntrinsic(IndexRows.back()->getValueInit(Field.Name)).EnumName : + ""); + std::string LastRepr = PI.searchableTablesPrimaryRepresentation( + Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name), + EnumNameB); + PI.searchableTablesEmitIfFieldCase(Field, FirstRepr, LastRepr); } - OS << " return false;\n"; - OS << " });\n\n"; - - OS << " if (Idx == Table.end()"; - - for (const auto &Field : Index.Fields) - OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name; - OS << ")\n return nullptr;\n"; - - if (IsPrimary) - OS << " return &*Idx;\n"; - else - OS << " return &" << Table.Name << "[Idx->_index];\n"; - - OS << "}\n"; + PI.searchableTablesEmitKeyTypeStruct(Table, Index); + PI.searchableTablesEmitKeyArray(Table, Index, IsPrimary); + PI.searchableTablesEmitIndexLamda(Index, IndexName, IndexTypeName); + PI.searchableTablesEmitReturns(Table, Index, IsPrimary); } -void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table, - const SearchIndex &Index, - raw_ostream &OS) { - OS << "const " << Table.CppTypeName << " *" << Index.Name << "("; - - ListSeparator LS; - for (const auto &Field : Index.Fields) - OS << LS << searchableFieldType(Table, Index, Field, TypeInArgument) << " " - << Field.Name; - OS << ")"; -} - -void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, - raw_ostream &OS) { - emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS); +void SearchableTableEmitter::emitGenericTable(const GenericTable &Table) { + PI.searchableTablesEmitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), + ST_DECL_OS); // Emit the declarations for the functions that will perform lookup. if (Table.PrimaryKey) { - emitLookupDeclaration(Table, *Table.PrimaryKey, OS); - OS << ";\n"; + PI.searchableTablesEmitLookupDeclaration(Table, *Table.PrimaryKey, ST_DECL_OS); } for (const auto &Index : Table.Indices) { - emitLookupDeclaration(Table, *Index, OS); - OS << ";\n"; + PI.searchableTablesEmitLookupDeclaration(Table, *Index, ST_DECL_OS); } + PI.searchableTablesEmitEndif(ST_DECL_OS); - OS << "#endif\n\n"; - - emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS); + PI.searchableTablesEmitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), + ST_IMPL_OS); + PI.searchableTablesEmitMapI(Table); // The primary data table contains all the fields defined for this map. - OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; for (unsigned i = 0; i < Table.Entries.size(); ++i) { Record *Entry = Table.Entries[i]; - OS << " { "; + PI.searchableTablesEmitMapII(); ListSeparator LS; - for (const auto &Field : Table.Fields) - OS << LS - << primaryRepresentation(Table.Locs[0], Field, - Entry->getValueInit(Field.Name)); + for (const auto &Field : Table.Fields) { + StringRef EnumName = (Field.IsIntrinsic ? getIntrinsic(Entry->getValueInit(Field.Name)).EnumName : ""); + PI.searchableTablesEmitMapIII(Table, LS, Field, + EnumName, Entry); + } - OS << " }, // " << i << "\n"; + PI.searchableTablesEmitMapIV(i); } - OS << " };\n"; + PI.searchableTablesEmitMapV(); // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary // search can be performed by "Thing". if (Table.PrimaryKey) - emitLookupFunction(Table, *Table.PrimaryKey, true, OS); + emitLookupFunction(Table, *Table.PrimaryKey, true); for (const auto &Index : Table.Indices) - emitLookupFunction(Table, *Index, false, OS); + emitLookupFunction(Table, *Index, false); - OS << "#endif\n\n"; + PI.searchableTablesEmitEndif(ST_IMPL_OS); } bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) { @@ -659,7 +433,7 @@ void SearchableTableEmitter::collectTableEntries( }); } -void SearchableTableEmitter::run(raw_ostream &OS) { +void SearchableTableEmitter::run() { // Emit tables in a deterministic order to avoid needless rebuilds. SmallVector, 4> Tables; DenseMap TableMap; @@ -829,17 +603,50 @@ void SearchableTableEmitter::run(raw_ostream &OS) { } // Emit everything. - for (const auto &Enum : Enums) - emitGenericEnum(*Enum, OS); + for (const auto &Enum : Enums) { + std::string Guard = (Twine("GET_") + Enum->PreprocessorGuard + "_DECL").str(); + PreprocessorGuards.insert(Guard); + PI.searchableTablesEmitIfdef(Guard, ST_DECL_OS); + PI.searchableTablesEmitGenericEnum(*Enum); + PI.searchableTablesEmitEndif(ST_DECL_OS); + } for (const auto &Table : Tables) - emitGenericTable(*Table, OS); + emitGenericTable(*Table); // Put all #undefs last, to allow multiple sections guarded by the same // define. - for (const auto &Guard : PreprocessorGuards) - OS << "#undef " << Guard << "\n"; + PI.searchableTablesEmitUndef(); +} + +void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) { + formatted_raw_ostream FOS(OS); + PrinterLanguage const PLang = PrinterLLVM::getLanguage(); + PrinterLLVM *PI = nullptr; + switch (PLang) { + default: + PrintFatalNote( + "RegisterInfo backend does not support the selected ouput language."); + return; + case PRINTER_LANG_CPP: + PI = new PrinterLLVM(FOS); + break; + case PRINTER_LANG_CAPSTONE_C: + Record *IDef = RK.getClass("I"); + if (!IDef) + // If this is reached we need to implement the search for other classes which have Namespace set. + llvm_unreachable("Base instruction class \"I\" does not exist for this target."); + if (!IDef->getValue("Namespace")) + llvm_unreachable("Field \"Namespace\" does not exist."); + std::string TName = IDef->getValueAsString("Namespace").str(); + PI = new PrinterCapstone(FOS, TName); + break; + } + + SearchableTableEmitter(RK, *PI).run(); + PI->searchableTablesWriteFiles(); + delete PI; } -static TableGen::Emitter::OptClass - X("gen-searchable-tables", "Generate generic binary-searchable table"); +static TableGen::Emitter::Opt + X("gen-searchable-tables", EmitSearchableTables, "Generate generic binary-searchable table"); diff --git a/llvm/utils/TableGen/SearchableTablesTypes.h b/llvm/utils/TableGen/SearchableTablesTypes.h new file mode 100644 index 000000000000..2a124c8c314b --- /dev/null +++ b/llvm/utils/TableGen/SearchableTablesTypes.h @@ -0,0 +1,87 @@ +//===-- SearchableTableEmitter.h - Generate efficiently searchable tables --==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_SEARCHABLETABLESTYPES_H +#define LLVM_UTILS_TABLEGEN_SEARCHABLETABLESTYPES_H + +#include "CodeGenIntrinsics.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +#include + +using namespace llvm; + +static inline int64_t getAsInt(Init *B) { + return cast( + B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper()))) + ->getValue(); +} + +struct GenericEnum { + using Entry = std::pair; + + std::string Name; + Record *Class = nullptr; + std::string PreprocessorGuard; + std::vector> Entries; + DenseMap EntryMap; +}; + +struct GenericField { + std::string Name; + RecTy *RecType = nullptr; + bool IsCode = false; + bool IsIntrinsic = false; + bool IsInstruction = false; + GenericEnum *Enum = nullptr; + + GenericField(StringRef Name) : Name(std::string(Name)) {} +}; + +struct SearchIndex { + std::string Name; + SMLoc Loc; // Source location of PrimaryKey or Key field definition. + SmallVector Fields; + bool EarlyOut = false; +}; + +struct GenericTable { + std::string Name; + ArrayRef Locs; // Source locations from the Record instance. + std::string PreprocessorGuard; + std::string CppTypeName; + SmallVector Fields; + std::vector Entries; + + std::unique_ptr PrimaryKey; + SmallVector, 2> Indices; + + const GenericField *getFieldByName(StringRef Name) const { + for (const auto &Field : Fields) { + if (Name == Field.Name) + return &Field; + } + return nullptr; + } +}; + +enum TypeContext { + TypeInStaticStruct, + TypeInTempStruct, + TypeInArgument, +}; + +#endif // LLVM_UTILS_TABLEGEN_SEARCHABLETABLESTYPES_H \ No newline at end of file diff --git a/llvm/utils/TableGen/SequenceToOffsetTable.h b/llvm/utils/TableGen/SequenceToOffsetTable.h index 77a404d07b7d..fcadfc9d2120 100644 --- a/llvm/utils/TableGen/SequenceToOffsetTable.h +++ b/llvm/utils/TableGen/SequenceToOffsetTable.h @@ -15,6 +15,7 @@ #ifndef LLVM_UTILS_TABLEGEN_SEQUENCETOOFFSETTABLE_H #define LLVM_UTILS_TABLEGEN_SEQUENCETOOFFSETTABLE_H +#include "PrinterTypes.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" #include @@ -68,13 +69,19 @@ class SequenceToOffsetTable { // Entries in the final table, or 0 before layout was called. unsigned Entries; + // The output language of the table. + PrinterLanguage PL; + // If set it will wrap the table content into a #ifndef CAPSTONE_DIET guard; + bool CSDietGuard; + // isSuffix - Returns true if A is a suffix of B. static bool isSuffix(const SeqT &A, const SeqT &B) { return A.size() <= B.size() && std::equal(A.rbegin(), A.rend(), B.rbegin()); } public: - SequenceToOffsetTable() : Entries(0) {} + SequenceToOffsetTable() : Entries(0), PL(PRINTER_LANG_CPP), CSDietGuard(false) {} + SequenceToOffsetTable(PrinterLanguage PL, bool CSDiet = false) : Entries(0), PL(PL), CSDietGuard(CSDiet) {} /// add - Add a sequence to the table. /// This must be called before layout(). @@ -122,11 +129,39 @@ class SequenceToOffsetTable { return I->second + (I->first.size() - Seq.size()); } + void emitStringLiteralDef(raw_ostream &OS, const llvm::Twine &Decl) const { + switch (PL) { + default: + llvm_unreachable("Language not specified to print table in."); + case PRINTER_LANG_CPP: + emitStringLiteralDefCPP(OS, Decl); + break; + case PRINTER_LANG_CAPSTONE_C: + emitStringLiteralDefCCS(OS, Decl); + break; + } + } + + void emit(raw_ostream &OS, + void (*Print)(raw_ostream&, ElemT), + const char *Term = "0") const { + switch (PL) { + default: + llvm_unreachable("Language not specified to print table in."); + case PRINTER_LANG_CPP: + emitCPP(OS, Print, Term); + break; + case PRINTER_LANG_CAPSTONE_C: + emitCCS(OS, Print, Term); + break; + } + } + /// `emitStringLiteralDef` - Print out the table as the body of an array /// initializer, where each element is a C string literal terminated by /// `\0`. Falls back to emitting a comma-separated integer list if /// `EmitLongStrLiterals` is false - void emitStringLiteralDef(raw_ostream &OS, const llvm::Twine &Decl) const { + void emitStringLiteralDefCPP(raw_ostream &OS, const llvm::Twine &Decl) const { assert(Entries && "Call layout() before emitStringLiteralDef()"); if (!EmitLongStrLiterals) { OS << Decl << " = {\n"; @@ -151,11 +186,54 @@ class SequenceToOffsetTable { << "#endif\n\n"; } + void emitStringLiteralDefCCS(raw_ostream &OS, const llvm::Twine &Decl) const { + assert(Entries && "Call layout() before emitStringLiteralDef()"); + if (!EmitLongStrLiterals) { + if (CSDietGuard) + OS << "#ifndef CAPSTONE_DIET\n"; + OS << Decl << " = {\n"; + emit(OS, printChar, "0"); + OS << " 0\n};\n"; + if (CSDietGuard) + OS << "#endif // CAPSTONE_DIET\n\n"; + OS << "\n"; + return; + } + + if (CSDietGuard) + OS << "#ifndef CAPSTONE_DIET\n"; + OS << Decl << " = {\n"; + for (auto I : Seqs) { + OS << " /* " << I.second << " */ \""; + OS.write_escaped(I.first); + OS << "\\0\"\n"; + } + OS << "};\n"; + if (CSDietGuard) + OS << "#endif // CAPSTONE_DIET\n\n"; + } + /// emit - Print out the table as the body of an array initializer. /// Use the Print function to print elements. - void emit(raw_ostream &OS, + void emitCPP(raw_ostream &OS, void (*Print)(raw_ostream&, ElemT), - const char *Term = "0") const { + const char *Term) const { + assert((empty() || Entries) && "Call layout() before emit()"); + for (typename SeqMap::const_iterator I = Seqs.begin(), E = Seqs.end(); + I != E; ++I) { + OS << " /* " << I->second << " */ "; + for (typename SeqT::const_iterator SI = I->first.begin(), + SE = I->first.end(); SI != SE; ++SI) { + Print(OS, *SI); + OS << ", "; + } + OS << Term << ",\n"; + } + } + + void emitCCS(raw_ostream &OS, + void (*Print)(raw_ostream&, ElemT), + const char *Term) const { assert((empty() || Entries) && "Call layout() before emit()"); for (typename SeqMap::const_iterator I = Seqs.begin(), E = Seqs.end(); I != E; ++I) { diff --git a/llvm/lib/TableGen/StringMatcher.cpp b/llvm/utils/TableGen/StringMatcher.cpp similarity index 88% rename from llvm/lib/TableGen/StringMatcher.cpp rename to llvm/utils/TableGen/StringMatcher.cpp index c169b4e0a362..cd31cfa424dc 100644 --- a/llvm/lib/TableGen/StringMatcher.cpp +++ b/llvm/utils/TableGen/StringMatcher.cpp @@ -10,10 +10,12 @@ // //===----------------------------------------------------------------------===// +#include "Printer.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" #include #include #include @@ -49,6 +51,18 @@ FindFirstNonCommonLetter(const std::vector &Matches, unsigned CharNo, unsigned IndentCount, bool IgnoreDuplicates) const { + switch(PrinterLLVM::getLanguage()) { + default: + PrintFatalNote("Printer language not known to StringMatcher."); + case PRINTER_LANG_CPP: + return EmitStringMatcherForCharCPP(Matches, CharNo, IndentCount, IgnoreDuplicates); + } + return false; +} + +bool StringMatcher::EmitStringMatcherForCharCPP( + const std::vector &Matches, unsigned CharNo, + unsigned IndentCount, bool IgnoreDuplicates) const { assert(!Matches.empty() && "Must have at least one string to match!"); std::string Indent(IndentCount * 2 + 4, ' '); @@ -129,6 +143,16 @@ bool StringMatcher::EmitStringMatcherForChar( /// Emit - Top level entry point. /// void StringMatcher::Emit(unsigned Indent, bool IgnoreDuplicates) const { + switch(PrinterLLVM::getLanguage()) { + default: + PrintFatalNote("Printer language not known to StringMatcher."); + case PRINTER_LANG_CPP: + EmitCPP(Indent, IgnoreDuplicates); + break; + } +} + +void StringMatcher::EmitCPP(unsigned Indent, bool IgnoreDuplicates) const { // If nothing to match, just fall through. if (Matches.empty()) return; diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 39225182a4c2..413b3caab720 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -10,30 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenHwModes.h" -#include "CodeGenSchedule.h" -#include "CodeGenTarget.h" -#include "PredicateExpander.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/MC/MCInstrItineraries.h" -#include "llvm/MC/MCSchedule.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include "llvm/TargetParser/SubtargetFeature.h" -#include -#include -#include -#include -#include -#include -#include +#include "Printer.h" +#include "PrinterTypes.h" +#include "SubtargetEmitterTypes.h" using namespace llvm; @@ -51,25 +30,8 @@ struct LessRecordFieldFieldName { }; class SubtargetEmitter { - // Each processor has a SchedClassDesc table with an entry for each SchedClass. - // The SchedClassDesc table indexes into a global write resource table, write - // latency table, and read advance table. - struct SchedClassTables { - std::vector> ProcSchedClasses; - std::vector WriteProcResources; - std::vector WriteLatencies; - std::vector WriterNames; - std::vector ReadAdvanceEntries; - // Reserve an invalid entry at index 0 - SchedClassTables() { - ProcSchedClasses.resize(1); - WriteProcResources.resize(1); - WriteLatencies.resize(1); - WriterNames.push_back("InvalidWrite"); - ReadAdvanceEntries.resize(1); - } - }; + SchedClassTablesT SchedClassTables; struct LessWriteProcResources { bool operator()(const MCWriteProcResEntry &LHS, @@ -82,39 +44,23 @@ class SubtargetEmitter { RecordKeeper &Records; CodeGenSchedModels &SchedModels; std::string Target; + PrinterLLVM &PI; - void Enumeration(raw_ostream &OS, DenseMap &FeatureMap); - void EmitSubtargetInfoMacroCalls(raw_ostream &OS); - unsigned FeatureKeyValues(raw_ostream &OS, + void Enumeration(DenseMap &FeatureMap); + void EmitSubtargetInfoMacroCalls(); + unsigned FeatureKeyValues( const DenseMap &FeatureMap); - unsigned CPUKeyValues(raw_ostream &OS, + unsigned CPUKeyValues( const DenseMap &FeatureMap); - void FormItineraryStageString(const std::string &Names, - Record *ItinData, std::string &ItinString, - unsigned &NStages); - void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, - unsigned &NOperandCycles); - void FormItineraryBypassString(const std::string &Names, - Record *ItinData, - std::string &ItinString, unsigned NOperandCycles); - void EmitStageAndOperandCycleData(raw_ostream &OS, + void EmitStageAndOperandCycleData( std::vector> &ProcItinLists); - void EmitItineraries(raw_ostream &OS, + void EmitItineraries( std::vector> &ProcItinLists); - unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel, - raw_ostream &OS); - void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, - raw_ostream &OS); - void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, - raw_ostream &OS); - void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name, - char Separator); - void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel, - raw_ostream &OS); - void EmitProcessorResources(const CodeGenProcModel &ProcModel, - raw_ostream &OS); + void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel); + void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel); + void EmitProcessorResources(const CodeGenProcModel &ProcModel); Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel); Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, @@ -123,26 +69,25 @@ class SubtargetEmitter { std::vector &AcquireAtCycles, const CodeGenProcModel &ProcModel); void GenSchedClassTables(const CodeGenProcModel &ProcModel, - SchedClassTables &SchedTables); - void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); - void EmitProcessorModels(raw_ostream &OS); - void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); - void emitSchedModelHelpersImpl(raw_ostream &OS, - bool OnlyExpandMCInstPredicates = false); - void emitGenMCSubtargetInfo(raw_ostream &OS); - void EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS); - - void EmitSchedModel(raw_ostream &OS); - void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS); - void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); - void ParseFeaturesFunction(raw_ostream &OS); + SchedClassTablesT &SchedTables); + void EmitSchedClassTables(SchedClassTablesT &SchedTables); + void EmitProcessorModels(); + void EmitSchedModelHelpers(const std::string &ClassName); + void emitSchedModelHelpersImpl(bool OnlyExpandMCInstPredicates = false); + void emitGenMCSubtargetInfo(); + void EmitMCInstrAnalysisPredicateFunctions(); + + void EmitSchedModel(); + void emitGetMacroFusions(const std::string &ClassName); + void EmitHwModeCheck(const std::string &ClassName); + void ParseFeaturesFunction(); public: - SubtargetEmitter(RecordKeeper &R) + SubtargetEmitter(RecordKeeper &R, PrinterLLVM &PI) : TGT(R), Records(R), SchedModels(TGT.getSchedModels()), - Target(TGT.getName()) {} + Target(TGT.getName()), PI(PI) {} - void run(raw_ostream &o); + void run(); }; } // end anonymous namespace @@ -150,7 +95,7 @@ class SubtargetEmitter { // // Enumeration - Emit the specified class as an enumeration. // -void SubtargetEmitter::Enumeration(raw_ostream &OS, +void SubtargetEmitter::Enumeration( DenseMap &FeatureMap) { // Get all records of class and sort std::vector DefList = @@ -163,52 +108,25 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS, if (N + 1 > MAX_SUBTARGET_FEATURES) PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); - OS << "namespace " << Target << " {\n"; - - // Open enumeration. - OS << "enum {\n"; - - // For each record - for (unsigned i = 0; i < N; ++i) { - // Next record - Record *Def = DefList[i]; - - // Get and emit name - OS << " " << Def->getName() << " = " << i << ",\n"; - - // Save the index for this feature. - FeatureMap[Def] = i; - } - - OS << " " - << "NumSubtargetFeatures = " << N << "\n"; - - // Close enumeration and namespace - OS << "};\n"; - OS << "} // end namespace " << Target << "\n"; + PI.emitNamespace(Target, true); + PI.subtargetEmitFeatureEnum(FeatureMap, DefList, N); + PI.emitNamespace(Target, false); } -static void printFeatureMask(raw_ostream &OS, RecVec &FeatureList, +static void printFeatureMask(PrinterLLVM const &PI, RecVec &FeatureList, const DenseMap &FeatureMap) { std::array Mask = {}; for (const Record *Feature : FeatureList) { unsigned Bit = FeatureMap.lookup(Feature); Mask[Bit / 64] |= 1ULL << (Bit % 64); } - - OS << "{ { { "; - for (unsigned i = 0; i != Mask.size(); ++i) { - OS << "0x"; - OS.write_hex(Mask[i]); - OS << "ULL, "; - } - OS << "} } }"; + PI.subtargetEmitPrintFeatureMask(Mask); } /// Emit some information about the SubtargetFeature as calls to a macro so /// that they can be used from C++. -void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) { - OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n"; +void SubtargetEmitter::EmitSubtargetInfoMacroCalls() { + PI.emitIncludeToggle("GET_SUBTARGETINFO_MACRO", true, true, true); std::vector FeatureList = Records.getAllDerivedDefinitions("SubtargetFeature"); @@ -224,21 +142,9 @@ void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) { if (!IsBool) continue; - // Some features default to true, with values set to false if enabled. - const char *Default = Value == "false" ? "true" : "false"; - - // Define the getter with lowercased first char: xxxYyy() { return XxxYyy; } - const std::string Getter = - FieldName.substr(0, 1).lower() + FieldName.substr(1).str(); - - OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", " - << Getter << ")\n"; + PI.subtargetEmitGetSTIMacro(Value, FieldName); } - OS << "#undef GET_SUBTARGETINFO_MACRO\n"; - OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n"; - - OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_MACRO", false, true, true); } // @@ -246,7 +152,7 @@ void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) { // command line. // unsigned SubtargetEmitter::FeatureKeyValues( - raw_ostream &OS, const DenseMap &FeatureMap) { + const DenseMap &FeatureMap) { // Gather and sort all the features std::vector FeatureList = Records.getAllDerivedDefinitions("SubtargetFeature"); @@ -257,9 +163,7 @@ unsigned SubtargetEmitter::FeatureKeyValues( llvm::sort(FeatureList, LessRecordFieldName()); // Begin feature table - OS << "// Sorted (by key) array of values for CPU features.\n" - << "extern const llvm::SubtargetFeatureKV " << Target - << "FeatureKV[] = {\n"; + PI.subtargetEmitFeatureKVHeader(Target); // For each feature unsigned NumFeatures = 0; @@ -271,22 +175,19 @@ unsigned SubtargetEmitter::FeatureKeyValues( if (CommandLineName.empty()) continue; - // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } } - OS << " { " - << "\"" << CommandLineName << "\", " - << "\"" << Desc << "\", " - << Target << "::" << Name << ", "; + PI.subtargetEmitFeatureKVPartI(Target, CommandLineName, Name, Desc); RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies"); - printFeatureMask(OS, ImpliesList, FeatureMap); + printFeatureMask(PI, ImpliesList, FeatureMap); + + PI.subtargetEmitFeatureKVPartII(); - OS << " },\n"; ++NumFeatures; } // End feature table - OS << "};\n"; + PI.subtargetEmitFeatureKVEnd(); return NumFeatures; } @@ -296,7 +197,7 @@ unsigned SubtargetEmitter::FeatureKeyValues( // line. // unsigned -SubtargetEmitter::CPUKeyValues(raw_ostream &OS, +SubtargetEmitter::CPUKeyValues( const DenseMap &FeatureMap) { // Gather and sort processor information std::vector ProcessorList = @@ -304,9 +205,7 @@ SubtargetEmitter::CPUKeyValues(raw_ostream &OS, llvm::sort(ProcessorList, LessRecordFieldName()); // Begin processor table - OS << "// Sorted (by key) array of values for CPU subtype.\n" - << "extern const llvm::SubtargetSubTypeKV " << Target - << "SubTypeKV[] = {\n"; + PI.subtargetEmitCPUKVHeader(Target); // For each processor for (Record *Processor : ProcessorList) { @@ -314,169 +213,42 @@ SubtargetEmitter::CPUKeyValues(raw_ostream &OS, RecVec FeatureList = Processor->getValueAsListOfDefs("Features"); RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures"); - // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } }, - OS << " { " - << "\"" << Name << "\", "; + PI.subtargetEmitCPUKVPartI(Name); - printFeatureMask(OS, FeatureList, FeatureMap); - OS << ", "; - printFeatureMask(OS, TuneFeatureList, FeatureMap); + printFeatureMask(PI, FeatureList, FeatureMap); + PI.subtargetEmitCPUKVPartII(); + printFeatureMask(PI, TuneFeatureList, FeatureMap); // Emit the scheduler model pointer. const std::string &ProcModelName = SchedModels.getModelForProc(Processor).ModelName; - OS << ", &" << ProcModelName << " },\n"; + PI.subtargetEmitCPUKVPartIII(ProcModelName); } // End processor table - OS << "};\n"; - + PI.subtargetEmitCPUKVEnd(); return ProcessorList.size(); } -// -// FormItineraryStageString - Compose a string containing the stage -// data initialization for the specified itinerary. N is the number -// of stages. -// -void SubtargetEmitter::FormItineraryStageString(const std::string &Name, - Record *ItinData, - std::string &ItinString, - unsigned &NStages) { - // Get states list - RecVec StageList = ItinData->getValueAsListOfDefs("Stages"); - - // For each stage - unsigned N = NStages = StageList.size(); - for (unsigned i = 0; i < N;) { - // Next stage - const Record *Stage = StageList[i]; - - // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } - int Cycles = Stage->getValueAsInt("Cycles"); - ItinString += " { " + itostr(Cycles) + ", "; - - // Get unit list - RecVec UnitList = Stage->getValueAsListOfDefs("Units"); - - // For each unit - for (unsigned j = 0, M = UnitList.size(); j < M;) { - // Add name and bitwise or - ItinString += Name + "FU::" + UnitList[j]->getName().str(); - if (++j < M) ItinString += " | "; - } - - int TimeInc = Stage->getValueAsInt("TimeInc"); - ItinString += ", " + itostr(TimeInc); - - int Kind = Stage->getValueAsInt("Kind"); - ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); - - // Close off stage - ItinString += " }"; - if (++i < N) ItinString += ", "; - } -} - -// -// FormItineraryOperandCycleString - Compose a string containing the -// operand cycle initialization for the specified itinerary. N is the -// number of operands that has cycles specified. -// -void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, - std::string &ItinString, unsigned &NOperandCycles) { - // Get operand cycle list - std::vector OperandCycleList = - ItinData->getValueAsListOfInts("OperandCycles"); - - // For each operand cycle - NOperandCycles = OperandCycleList.size(); - ListSeparator LS; - for (int OCycle : OperandCycleList) { - // Next operand cycle - ItinString += LS; - ItinString += " " + itostr(OCycle); - } -} - -void SubtargetEmitter::FormItineraryBypassString(const std::string &Name, - Record *ItinData, - std::string &ItinString, - unsigned NOperandCycles) { - RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses"); - unsigned N = BypassList.size(); - unsigned i = 0; - ListSeparator LS; - for (; i < N; ++i) { - ItinString += LS; - ItinString += Name + "Bypass::" + BypassList[i]->getName().str(); - } - for (; i < NOperandCycles; ++i) { - ItinString += LS; - ItinString += " 0"; - } -} - // // EmitStageAndOperandCycleData - Generate unique itinerary stages and operand // cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed // by CodeGenSchedClass::Index. // void SubtargetEmitter:: -EmitStageAndOperandCycleData(raw_ostream &OS, - std::vector> - &ProcItinLists) { - // Multiple processor models may share an itinerary record. Emit it once. - SmallPtrSet ItinsDefSet; +EmitStageAndOperandCycleData(std::vector> + &ProcItinLists) { - // Emit functional units for all the itineraries. - for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { - - if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) - continue; - - RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); - if (FUs.empty()) - continue; - - StringRef Name = ProcModel.ItinsDef->getName(); - OS << "\n// Functional units for \"" << Name << "\"\n" - << "namespace " << Name << "FU {\n"; - - for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j) - OS << " const InstrStage::FuncUnits " << FUs[j]->getName() - << " = 1ULL << " << j << ";\n"; - - OS << "} // end namespace " << Name << "FU\n"; - - RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); - if (!BPs.empty()) { - OS << "\n// Pipeline forwarding paths for itineraries \"" << Name - << "\"\n" << "namespace " << Name << "Bypass {\n"; - - OS << " const unsigned NoBypass = 0;\n"; - for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j) - OS << " const unsigned " << BPs[j]->getName() - << " = 1 << " << j << ";\n"; - - OS << "} // end namespace " << Name << "Bypass\n"; - } - } + PI.subtargetEmitFunctionalItinaryUnits(SchedModels); // Begin stages table - std::string StageTable = "\nextern const llvm::InstrStage " + Target + - "Stages[] = {\n"; - StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; + std::string StageTable = PI.subtargetGetBeginStageTable(Target); // Begin operand cycle table - std::string OperandCycleTable = "extern const unsigned " + Target + - "OperandCycles[] = {\n"; - OperandCycleTable += " 0, // No itinerary\n"; + std::string OperandCycleTable = PI.subtargetGetBeginOperandCycleTable(Target); // Begin pipeline bypass table - std::string BypassTable = "extern const unsigned " + Target + - "ForwardingPaths[] = {\n"; - BypassTable += " 0, // No itinerary\n"; + std::string BypassTable = PI.subtargetGetBeginBypassTable(Target); // For each Itinerary across all processors, add a unique entry to the stages, // operand cycles, and pipeline bypass tables. Then add the new Itinerary @@ -508,19 +280,24 @@ EmitStageAndOperandCycleData(raw_ostream &OS, std::string ItinStageString; unsigned NStages = 0; if (ItinData) - FormItineraryStageString(std::string(Name), ItinData, ItinStageString, - NStages); + PI.subtargetFormItineraryStageString(std::string(Name), + ItinData, + ItinStageString, + NStages); // Get string and operand cycle count std::string ItinOperandCycleString; unsigned NOperandCycles = 0; std::string ItinBypassString; if (ItinData) { - FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, - NOperandCycles); - - FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString, - NOperandCycles); + PI.subtargetFormItineraryOperandCycleString(ItinData, + ItinOperandCycleString, + NOperandCycles); + + PI.subtargetFormItineraryBypassString(std::string(Name), + ItinData, + ItinBypassString, + NOperandCycles); } // Check to see if stage already exists and create if it doesn't @@ -529,10 +306,10 @@ EmitStageAndOperandCycleData(raw_ostream &OS, FindStage = ItinStageMap[ItinStageString]; if (FindStage == 0) { // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices - StageTable += ItinStageString + ", // " + itostr(StageCount); + StageTable += PI.subtargetGetStageEntryPartI(ItinStageString, StageCount); if (NStages > 1) - StageTable += "-" + itostr(StageCount + NStages - 1); - StageTable += "\n"; + StageTable += PI.subtargetGetStageEntryPartII(StageCount, NStages); + StageTable += PI.subtargetGetStageEntryPartIII(); // Record Itin class number. ItinStageMap[ItinStageString] = FindStage = StageCount; StageCount += NStages; @@ -546,17 +323,20 @@ EmitStageAndOperandCycleData(raw_ostream &OS, FindOperandCycle = ItinOperandMap[ItinOperandString]; if (FindOperandCycle == 0) { // Emit as cycle, // index - OperandCycleTable += ItinOperandCycleString + ", // "; + OperandCycleTable += PI.subtargetGetOperandCycleEntryPartI( + ItinOperandCycleString); std::string OperandIdxComment = itostr(OperandCycleCount); if (NOperandCycles > 1) - OperandIdxComment += "-" - + itostr(OperandCycleCount + NOperandCycles - 1); - OperandCycleTable += OperandIdxComment + "\n"; + OperandIdxComment += PI.subtargetGetOperandCycleEntryPartII( + OperandCycleCount, NOperandCycles); + OperandCycleTable += PI.subtargetGetOperandCycleEntryPartIII( + OperandIdxComment); // Record Itin class number. ItinOperandMap[ItinOperandCycleString] = FindOperandCycle = OperandCycleCount; // Emit as bypass, // index - BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n"; + BypassTable += PI.subtargetGetOperandCycleEntryPartIV( + ItinBypassString, OperandIdxComment); OperandCycleCount += NOperandCycles; } } @@ -577,20 +357,15 @@ EmitStageAndOperandCycleData(raw_ostream &OS, } // Closing stage - StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n"; - StageTable += "};\n"; + StageTable += PI.subtargetGetEndStageTable(); // Closing operand cycles - OperandCycleTable += " 0 // End operand cycles\n"; - OperandCycleTable += "};\n"; + OperandCycleTable += PI.subtargetGetEndOperandCycleTable(); - BypassTable += " 0 // End bypass tables\n"; - BypassTable += "};\n"; + BypassTable += PI.subtargetGetEndBypassTable(); // Emit tables. - OS << StageTable; - OS << OperandCycleTable; - OS << BypassTable; + PI.subtargetEmitStageAndSycleTables(StageTable, OperandCycleTable, BypassTable); } // @@ -600,7 +375,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, // CodeGenSchedClass::Index. // void SubtargetEmitter:: -EmitItineraries(raw_ostream &OS, +EmitItineraries( std::vector> &ProcItinLists) { // Multiple processor models may share an itinerary record. Emit it once. SmallPtrSet ItinsDefSet; @@ -608,10 +383,10 @@ EmitItineraries(raw_ostream &OS, // For each processor's machine model std::vector>::iterator ProcItinListsIter = ProcItinLists.begin(); - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) { + for (CodeGenSchedModels::ProcIter PIM = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PIM != PE; ++PIM, ++ProcItinListsIter) { - Record *ItinsDef = PI->ItinsDef; + Record *ItinsDef = PIM->ItinsDef; if (!ItinsDefSet.insert(ItinsDef).second) continue; @@ -624,72 +399,14 @@ EmitItineraries(raw_ostream &OS, if (ItinList.empty()) continue; - OS << "\n"; - OS << "static const llvm::InstrItinerary "; - - // Begin processor itinerary table - OS << ItinsDef->getName() << "[] = {\n"; - - // For each itinerary class in CodeGenSchedClass::Index order. - for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { - InstrItinerary &Intinerary = ItinList[j]; - - // Emit Itinerary in the form of - // { firstStage, lastStage, firstCycle, lastCycle } // index - OS << " { " << - Intinerary.NumMicroOps << ", " << - Intinerary.FirstStage << ", " << - Intinerary.LastStage << ", " << - Intinerary.FirstOperandCycle << ", " << - Intinerary.LastOperandCycle << " }" << - ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; - } - // End processor itinerary table - OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }" - "// end marker\n"; - OS << "};\n"; + PI.subtargetEmitProcessorItineraryTable(ItinsDef->getName().str(), + ItinList, + SchedModels); } } -// Emit either the value defined in the TableGen Record, or the default -// value defined in the C++ header. The Record is null if the processor does not -// define a model. -void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, - StringRef Name, char Separator) { - OS << " "; - int V = R ? R->getValueAsInt(Name) : -1; - if (V >= 0) - OS << V << Separator << " // " << Name; - else - OS << "MCSchedModel::Default" << Name << Separator; - OS << '\n'; -} - -void SubtargetEmitter::EmitProcessorResourceSubUnits( - const CodeGenProcModel &ProcModel, raw_ostream &OS) { - OS << "\nstatic const unsigned " << ProcModel.ModelName - << "ProcResourceSubUnits[] = {\n" - << " 0, // Invalid\n"; - - for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { - Record *PRDef = ProcModel.ProcResourceDefs[i]; - if (!PRDef->isSubClassOf("ProcResGroup")) - continue; - RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); - for (Record *RUDef : ResUnits) { - Record *const RU = - SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc()); - for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) { - OS << " " << ProcModel.getProcResourceIdx(RU) << ", "; - } - } - OS << " // " << PRDef->getName() << "\n"; - } - OS << "};\n"; -} - static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { + PrinterLLVM &PI) { int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0; if (Record *RCU = ProcModel.RetireControlUnit) { ReorderBufferSize = @@ -698,88 +415,18 @@ static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel, std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle")); } - OS << ReorderBufferSize << ", // ReorderBufferSize\n "; - OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n "; -} - -static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel, - unsigned NumRegisterFiles, - unsigned NumCostEntries, raw_ostream &OS) { - if (NumRegisterFiles) - OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles); - else - OS << "nullptr,\n 0"; - - OS << ", // Number of register files.\n "; - if (NumCostEntries) - OS << ProcModel.ModelName << "RegisterCosts,\n "; - else - OS << "nullptr,\n "; - OS << NumCostEntries << ", // Number of register cost entries.\n"; -} - -unsigned -SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { - if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) { - return RF.hasDefaultCosts(); - })) - return 0; - - // Print the RegisterCost table first. - OS << "\n// {RegisterClassID, Register Cost, AllowMoveElimination }\n"; - OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName - << "RegisterCosts" - << "[] = {\n"; - - for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) { - // Skip register files with a default cost table. - if (RF.hasDefaultCosts()) - continue; - // Add entries to the cost table. - for (const CodeGenRegisterCost &RC : RF.Costs) { - OS << " { "; - Record *Rec = RC.RCDef; - if (Rec->getValue("Namespace")) - OS << Rec->getValueAsString("Namespace") << "::"; - OS << Rec->getName() << "RegClassID, " << RC.Cost << ", " - << RC.AllowMoveElimination << "},\n"; - } - } - OS << "};\n"; - - // Now generate a table with register file info. - OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl, " - << "MaxMovesEliminatedPerCycle, AllowZeroMoveEliminationOnly }\n"; - OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName - << "RegisterFiles" - << "[] = {\n" - << " { \"InvalidRegisterFile\", 0, 0, 0, 0, 0 },\n"; - unsigned CostTblIndex = 0; - - for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { - OS << " { "; - OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; - unsigned NumCostEntries = RD.Costs.size(); - OS << NumCostEntries << ", " << CostTblIndex << ", " - << RD.MaxMovesEliminatedPerCycle << ", " - << RD.AllowZeroMoveEliminationOnly << "},\n"; - CostTblIndex += NumCostEntries; - } - OS << "};\n"; - - return CostTblIndex; + PI.subtargetEmitReorderBufferSize(ReorderBufferSize); + PI.subtargetEmitMaxRetirePerCycle(MaxRetirePerCycle); } -void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { +void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel) { unsigned QueueID = 0; if (ProcModel.LoadQueue) { const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor"); QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), find(ProcModel.ProcResourceDefs, Queue)); } - OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n"; + PI.subtargetEmitResourceDescriptorLoadQueue(QueueID); QueueID = 0; if (ProcModel.StoreQueue) { @@ -788,42 +435,40 @@ void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), find(ProcModel.ProcResourceDefs, Queue)); } - OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n"; + PI.subtargetEmitResourceDescriptorStoreQueue(QueueID); } -void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { +void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel) { // Generate a table of register file descriptors (one entry per each user // defined register file), and a table of register costs. - unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS); + unsigned NumCostEntries; + if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) { + return RF.hasDefaultCosts(); + })) + NumCostEntries = 0; + else + NumCostEntries = PI.subtargetEmitRegisterFileTables(ProcModel); // Now generate a table for the extra processor info. - OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName - << "ExtraInfo = {\n "; + PI.subtargetEmitMCExtraProcInfoTableHeader(ProcModel.ModelName); // Add information related to the retire control unit. - EmitRetireControlUnitInfo(ProcModel, OS); + EmitRetireControlUnitInfo(ProcModel, PI); // Add information related to the register files (i.e. where to find register // file descriptors and register costs). - EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), - NumCostEntries, OS); + PI.subtargetEmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), + NumCostEntries); // Add information about load/store queues. - EmitLoadStoreQueueInfo(ProcModel, OS); - - OS << "};\n"; + EmitLoadStoreQueueInfo(ProcModel); + PI.subtargetEmitMCExtraProcInfoTableEnd(); } -void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, - raw_ostream &OS) { - EmitProcessorResourceSubUnits(ProcModel, OS); +void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel) { + PI.subtargetEmitProcessorResourceSubUnits(ProcModel, SchedModels); - OS << "\n// {Name, NumUnits, SuperIdx, BufferSize, SubUnitsIdxBegin}\n"; - OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName - << "ProcResources" - << "[] = {\n" - << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; + PI.subtargetEmitMCProcResourceDescHeader(ProcModel.ModelName); unsigned SubUnitsOffset = 1; for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { @@ -851,23 +496,16 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, } NumUnits = PRDef->getValueAsInt("NumUnits"); } - // Emit the ProcResourceDesc - OS << " {\"" << PRDef->getName() << "\", "; - if (PRDef->getName().size() < 15) - OS.indent(15 - PRDef->getName().size()); - OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; - if (SubUnitsBeginOffset != SubUnitsOffset) { - OS << ProcModel.ModelName << "ProcResourceSubUnits + " - << SubUnitsBeginOffset; - } else { - OS << "nullptr"; - } - OS << "}, // #" << i+1; - if (SuperDef) - OS << ", Super=" << SuperDef->getName(); - OS << "\n"; + PI.subtargetEmitMCProcResourceDesc(PRDef, + SuperDef, + ProcModel.ModelName, + SubUnitsOffset, + SuperIdx, + NumUnits, + BufferSize, + i, SubUnitsBeginOffset); } - OS << "};\n"; + PI.subtargetEmitMCProcResourceDescEnd(); } // Find the WriteRes Record that defines processor resources for this @@ -1027,7 +665,7 @@ void SubtargetEmitter::ExpandProcResources( // Generate the SchedClass table for this processor and update global // tables. Must be called for each processor in order. void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, - SchedClassTables &SchedTables) { + SchedClassTablesT &SchedTables) { SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); if (!ProcModel.hasInstrSchedModel()) return; @@ -1333,213 +971,56 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } } -// Emit SchedClass tables for all processors and associated global tables. -void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, - raw_ostream &OS) { - // Emit global WriteProcResTable. - OS << "\n// {ProcResourceIdx, ReleaseAtCycle, AcquireAtCycle}\n" - << "extern const llvm::MCWriteProcResEntry " << Target - << "WriteProcResTable[] = {\n" - << " { 0, 0, 0 }, // Invalid\n"; - for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); - WPRIdx != WPREnd; ++WPRIdx) { - MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; - OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " - << format("%2d", WPREntry.ReleaseAtCycle) << ", " - << format("%2d", WPREntry.AcquireAtCycle) << "}"; - if (WPRIdx + 1 < WPREnd) - OS << ','; - OS << " // #" << WPRIdx << '\n'; - } - OS << "}; // " << Target << "WriteProcResTable\n"; - - // Emit global WriteLatencyTable. - OS << "\n// {Cycles, WriteResourceID}\n" - << "extern const llvm::MCWriteLatencyEntry " - << Target << "WriteLatencyTable[] = {\n" - << " { 0, 0}, // Invalid\n"; - for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); - WLIdx != WLEnd; ++WLIdx) { - MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; - OS << " {" << format("%2d", WLEntry.Cycles) << ", " - << format("%2d", WLEntry.WriteResourceID) << "}"; - if (WLIdx + 1 < WLEnd) - OS << ','; - OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; - } - OS << "}; // " << Target << "WriteLatencyTable\n"; - - // Emit global ReadAdvanceTable. - OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" - << "extern const llvm::MCReadAdvanceEntry " - << Target << "ReadAdvanceTable[] = {\n" - << " {0, 0, 0}, // Invalid\n"; - for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); - RAIdx != RAEnd; ++RAIdx) { - MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; - OS << " {" << RAEntry.UseIdx << ", " - << format("%2d", RAEntry.WriteResourceID) << ", " - << format("%2d", RAEntry.Cycles) << "}"; - if (RAIdx + 1 < RAEnd) - OS << ','; - OS << " // #" << RAIdx << '\n'; - } - OS << "}; // " << Target << "ReadAdvanceTable\n"; - - // Emit a SchedClass table for each processor. - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - if (!PI->hasInstrSchedModel()) - continue; - - std::vector &SCTab = - SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; - - OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO," - << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; - OS << "static const llvm::MCSchedClassDesc " - << PI->ModelName << "SchedClasses[] = {\n"; - - // The first class is always invalid. We no way to distinguish it except by - // name and position. - assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" - && "invalid class not first"); - OS << " {DBGFIELD(\"InvalidSchedClass\") " - << MCSchedClassDesc::InvalidNumMicroOps - << ", false, false, false, 0, 0, 0, 0, 0, 0},\n"; - - for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { - MCSchedClassDesc &MCDesc = SCTab[SCIdx]; - const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); - OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; - if (SchedClass.Name.size() < 18) - OS.indent(18 - SchedClass.Name.size()); - OS << MCDesc.NumMicroOps - << ", " << ( MCDesc.BeginGroup ? "true" : "false" ) - << ", " << ( MCDesc.EndGroup ? "true" : "false" ) - << ", " << ( MCDesc.RetireOOO ? "true" : "false" ) - << ", " << format("%2d", MCDesc.WriteProcResIdx) - << ", " << MCDesc.NumWriteProcResEntries - << ", " << format("%2d", MCDesc.WriteLatencyIdx) - << ", " << MCDesc.NumWriteLatencyEntries - << ", " << format("%2d", MCDesc.ReadAdvanceIdx) - << ", " << MCDesc.NumReadAdvanceEntries - << "}, // #" << SCIdx << '\n'; - } - OS << "}; // " << PI->ModelName << "SchedClasses\n"; - } -} - -void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { +void SubtargetEmitter::EmitProcessorModels() { // For each processor model. for (const CodeGenProcModel &PM : SchedModels.procModels()) { // Emit extra processor info if available. if (PM.hasExtraProcessorInfo()) - EmitExtraProcessorInfo(PM, OS); + EmitExtraProcessorInfo(PM); // Emit processor resource table. if (PM.hasInstrSchedModel()) - EmitProcessorResources(PM, OS); + EmitProcessorResources(PM); else if(!PM.ProcResourceDefs.empty()) PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines " "ProcResources without defining WriteRes SchedWriteRes"); // Begin processor itinerary properties - OS << "\n"; - OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n"; - EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ','); - EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ','); - EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ','); - EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ','); - EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); - EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); - - bool PostRAScheduler = - (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); - - OS << " " << (PostRAScheduler ? "true" : "false") << ", // " - << "PostRAScheduler\n"; - - bool CompleteModel = - (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); - - OS << " " << (CompleteModel ? "true" : "false") << ", // " - << "CompleteModel\n"; - - bool EnableIntervals = - (PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false); - - OS << " " << (EnableIntervals ? "true" : "false") << ", // " - << "EnableIntervals\n"; - - OS << " " << PM.Index << ", // Processor ID\n"; - if (PM.hasInstrSchedModel()) - OS << " " << PM.ModelName << "ProcResources" << ",\n" - << " " << PM.ModelName << "SchedClasses" << ",\n" - << " " << PM.ProcResourceDefs.size()+1 << ",\n" - << " " << (SchedModels.schedClassEnd() - - SchedModels.schedClassBegin()) << ",\n"; - else - OS << " nullptr, nullptr, 0, 0," - << " // No instruction-level machine model.\n"; - if (PM.hasItineraries()) - OS << " " << PM.ItinsDef->getName() << ",\n"; - else - OS << " nullptr, // No Itinerary\n"; - if (PM.hasExtraProcessorInfo()) - OS << " &" << PM.ModelName << "ExtraInfo,\n"; - else - OS << " nullptr // No extra processor descriptor\n"; - OS << "};\n"; + PI.subtargetEmitProcModelHeader(PM.ModelName); + PI.subtargetEmitProcessorProp(PM.ModelDef, "IssueWidth", ','); + PI.subtargetEmitProcessorProp(PM.ModelDef, "MicroOpBufferSize", ','); + PI.subtargetEmitProcessorProp(PM.ModelDef, "LoopMicroOpBufferSize", ','); + PI.subtargetEmitProcessorProp(PM.ModelDef, "LoadLatency", ','); + PI.subtargetEmitProcessorProp(PM.ModelDef, "HighLatency", ','); + PI.subtargetEmitProcessorProp(PM.ModelDef, "MispredictPenalty", ','); + + PI.subtargetEmitProcModel(PM, SchedModels); } } // // EmitSchedModel - Emits all scheduling model tables, folding common patterns. // -void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { - OS << "#ifdef DBGFIELD\n" - << "#error \"GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" - << "#endif\n" - << "#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)\n" - << "#define DBGFIELD(x) x,\n" - << "#else\n" - << "#define DBGFIELD(x)\n" - << "#endif\n"; +void SubtargetEmitter::EmitSchedModel() { + PI.subtargetEmitDBGMacrosBegin(); if (SchedModels.hasItineraries()) { std::vector> ProcItinLists; // Emit the stage data - EmitStageAndOperandCycleData(OS, ProcItinLists); - EmitItineraries(OS, ProcItinLists); + EmitStageAndOperandCycleData(ProcItinLists); + EmitItineraries(ProcItinLists); } - OS << "\n// ===============================================================\n" - << "// Data tables for the new per-operand machine model.\n"; + PI.subtargetEmitPreOperandTableComment(); - SchedClassTables SchedTables; + SchedClassTablesT SchedTables; for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { GenSchedClassTables(ProcModel, SchedTables); } - EmitSchedClassTables(SchedTables, OS); + PI.subtargetEmitSchedClassTables(SchedTables, Target, SchedModels); - OS << "\n#undef DBGFIELD\n"; + PI.subtargetEmitDBGMacrosEnd(); // Emit the processor machine model - EmitProcessorModels(OS); -} - -static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { - std::string Buffer; - raw_string_ostream Stream(Buffer); - - // Collect all the PredicateProlog records and print them to the output - // stream. - std::vector Prologs = - Records.getAllDerivedDefinitions("PredicateProlog"); - llvm::sort(Prologs, LessRecord()); - for (Record *P : Prologs) - Stream << P->getValueAsString("Code") << '\n'; - - OS << Buffer; + EmitProcessorModels(); } static bool isTruePredicate(const Record *Rec) { @@ -1547,72 +1028,6 @@ static bool isTruePredicate(const Record *Rec) { Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); } -static void emitPredicates(const CodeGenSchedTransition &T, - const CodeGenSchedClass &SC, PredicateExpander &PE, - raw_ostream &OS) { - std::string Buffer; - raw_string_ostream SS(Buffer); - - // If not all predicates are MCTrue, then we need an if-stmt. - unsigned NumNonTruePreds = - T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate); - - SS.indent(PE.getIndentLevel() * 2); - - if (NumNonTruePreds) { - bool FirstNonTruePredicate = true; - SS << "if ("; - - PE.setIndentLevel(PE.getIndentLevel() + 2); - - for (const Record *Rec : T.PredTerm) { - // Skip predicates that evaluate to "true". - if (isTruePredicate(Rec)) - continue; - - if (FirstNonTruePredicate) { - FirstNonTruePredicate = false; - } else { - SS << "\n"; - SS.indent(PE.getIndentLevel() * 2); - SS << "&& "; - } - - if (Rec->isSubClassOf("MCSchedPredicate")) { - PE.expandPredicate(SS, Rec->getValueAsDef("Pred")); - continue; - } - - // Expand this legacy predicate and wrap it around braces if there is more - // than one predicate to expand. - SS << ((NumNonTruePreds > 1) ? "(" : "") - << Rec->getValueAsString("Predicate") - << ((NumNonTruePreds > 1) ? ")" : ""); - } - - SS << ")\n"; // end of if-stmt - PE.decreaseIndentLevel(); - SS.indent(PE.getIndentLevel() * 2); - PE.decreaseIndentLevel(); - } - - SS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; - OS << Buffer; -} - -// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate -// epilogue code for the auto-generated helper. -static void emitSchedModelHelperEpilogue(raw_ostream &OS, - bool ShouldReturnZero) { - if (ShouldReturnZero) { - OS << " // Don't know how to resolve this scheduling class.\n" - << " return 0;\n"; - return; - } - - OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; -} - static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { return all_of(T.PredTerm, [](const Record *Rec) { return Rec->isSubClassOf("MCSchedPredicate"); @@ -1656,13 +1071,13 @@ static bool isAlwaysTrue(const CodeGenSchedTransition &T) { } void SubtargetEmitter::emitSchedModelHelpersImpl( - raw_ostream &OS, bool OnlyExpandMCInstPredicates) { + bool OnlyExpandMCInstPredicates) { IdxVec VariantClasses; collectVariantClasses(SchedModels, VariantClasses, OnlyExpandMCInstPredicates); if (VariantClasses.empty()) { - emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); + PI.subtargetEmitSchedModelHelperEpilogue(OnlyExpandMCInstPredicates); return; } @@ -1673,33 +1088,23 @@ void SubtargetEmitter::emitSchedModelHelpersImpl( // a variant scheduling class to another scheduling class. Rules are // described by instances of CodeGenSchedTransition. Note that transitions may // not be valid for all processors. - OS << " switch (SchedClass) {\n"; + PI.subtargetEmitSchedClassSwitch(); for (unsigned VC : VariantClasses) { IdxVec ProcIndices; const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); collectProcessorIndices(SC, ProcIndices); - OS << " case " << VC << ": // " << SC.Name << '\n'; - - PredicateExpander PE(Target); - PE.setByRef(false); - PE.setExpandForMC(OnlyExpandMCInstPredicates); - for (unsigned PI : ProcIndices) { - OS << " "; - - // Emit a guard on the processor ID. - if (PI != 0) { - OS << (OnlyExpandMCInstPredicates - ? "if (CPUID == " - : "if (SchedModel->getProcessorID() == "); - OS << PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; - } + PI.subtargetEmitSchedClassCase(VC, SC.Name); + + PI.subtargetPrepareSchedClassPreds(Target, OnlyExpandMCInstPredicates); + for (unsigned Pi : ProcIndices) { + PI.subtargetEmitSchedClassProcGuard(Pi, OnlyExpandMCInstPredicates, + (SchedModels.procModelBegin() + Pi)->ModelName); // Now emit transitions associated with processor PI. const CodeGenSchedTransition *FinalT = nullptr; for (const CodeGenSchedTransition &T : SC.Transitions) { - if (PI != 0 && T.ProcIndex != PI) + if (Pi != 0 && T.ProcIndex != Pi) continue; // Emit only transitions based on MCSchedPredicate, if it's the case. @@ -1717,363 +1122,191 @@ void SubtargetEmitter::emitSchedModelHelpersImpl( FinalT = &T; continue; } - PE.setIndentLevel(3); - emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); + PI.subtargetEmitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), + isTruePredicate, 3); } if (FinalT) - emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx), - PE, OS); + PI.subtargetEmitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx), + isTruePredicate); - OS << " }\n"; + PI.subtargetEmitProcTransitionEnd(); - if (PI == 0) + if (Pi == 0) break; } - if (SC.isInferred()) - OS << " return " << SC.Index << ";\n"; - OS << " break;\n"; + PI.subtargetEmitSchedClassCaseEnd(SC); } - OS << " };\n"; + PI.subtargetEmitSchedClassSwitchEnd(); - emitSchedModelHelperEpilogue(OS, OnlyExpandMCInstPredicates); + PI.subtargetEmitSchedModelHelperEpilogue(OnlyExpandMCInstPredicates); } -void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, - raw_ostream &OS) { - OS << "unsigned " << ClassName - << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," - << " const TargetSchedModel *SchedModel) const {\n"; +void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName) { + PI.subtargetEmitResolveSchedClassHdr(ClassName); // Emit the predicate prolog code. - emitPredicateProlog(Records, OS); + PI.subtargetEmitPredicateProlog(Records); // Emit target predicates. - emitSchedModelHelpersImpl(OS); + emitSchedModelHelpersImpl(); - OS << "} // " << ClassName << "::resolveSchedClass\n\n"; + PI.subtargetEmitResolveSchedClassEnd(ClassName); - OS << "unsigned " << ClassName - << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," - << " const MCInstrInfo *MCII, unsigned CPUID) const {\n" - << " return " << Target << "_MC" - << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n" - << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; + PI.subtargetEmitResolveVariantSchedClass(Target, ClassName); - STIPredicateExpander PE(Target); - PE.setClassPrefix(ClassName); - PE.setExpandDefinition(true); - PE.setByRef(false); - PE.setIndentLevel(0); - - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); + PI.subtargetEmitExpandedSTIPreds(Target, ClassName, SchedModels); } -void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, - raw_ostream &OS) { +void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName) { const CodeGenHwModes &CGH = TGT.getHwModes(); assert(CGH.getNumModeIds() > 0); if (CGH.getNumModeIds() == 1) return; - OS << "unsigned " << ClassName << "::getHwMode() const {\n"; - for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) { - const HwMode &HM = CGH.getMode(M); - OS << " if (checkFeatures(\"" << HM.Features - << "\")) return " << M << ";\n"; - } - OS << " return 0;\n}\n"; -} - -void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName, - raw_ostream &OS) { - if (!TGT.hasMacroFusion()) - return; - - OS << "std::vector " << ClassName - << "::getMacroFusions() const {\n"; - OS.indent(2) << "std::vector Fusions;\n"; - for (auto *Fusion : TGT.getMacroFusions()) { - std::string Name = Fusion->getNameInitAsString(); - OS.indent(2) << "if (hasFeature(" << Target << "::" << Name - << ")) Fusions.push_back(llvm::is" << Name << ");\n"; - } - - OS.indent(2) << "return Fusions;\n"; - OS << "}\n"; + PI.subtargetEmitHwModes(CGH, ClassName); } // Produces a subtarget specific function for parsing // the subtarget features string. -void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) { +void SubtargetEmitter::ParseFeaturesFunction() { std::vector Features = Records.getAllDerivedDefinitions("SubtargetFeature"); llvm::sort(Features, LessRecord()); - - OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" - << "// subtarget options.\n" - << "void llvm::"; - OS << Target; - OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, " - << "StringRef FS) {\n" - << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" - << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n" - << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n"; - - if (Features.empty()) { - OS << "}\n"; - return; - } - - OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n" - << " const FeatureBitset &Bits = getFeatureBits();\n"; - - for (Record *R : Features) { - // Next record - StringRef Instance = R->getName(); - StringRef Value = R->getValueAsString("Value"); - StringRef FieldName = R->getValueAsString("FieldName"); - - if (Value=="true" || Value=="false") - OS << " if (Bits[" << Target << "::" - << Instance << "]) " - << FieldName << " = " << Value << ";\n"; - else - OS << " if (Bits[" << Target << "::" - << Instance << "] && " - << FieldName << " < " << Value << ") " - << FieldName << " = " << Value << ";\n"; - } - - OS << "}\n"; + PI.subtargetEmitParseFeaturesFunction(Target, Features); } -void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { - OS << "namespace " << Target << "_MC {\n" - << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" - << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n"; - emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); - OS << "}\n"; - OS << "} // end namespace " << Target << "_MC\n\n"; - - OS << "struct " << Target - << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; - OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n" - << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n" - << " ArrayRef PF,\n" - << " ArrayRef PD,\n" - << " const MCWriteProcResEntry *WPR,\n" - << " const MCWriteLatencyEntry *WL,\n" - << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" - << " const unsigned *OC, const unsigned *FP) :\n" - << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n" - << " WPR, WL, RA, IS, OC, FP) { }\n\n" - << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" - << " const MCInst *MI, const MCInstrInfo *MCII,\n" - << " unsigned CPUID) const override {\n" - << " return " << Target << "_MC" - << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"; - OS << " }\n"; - if (TGT.getHwModes().getNumModeIds() > 1) - OS << " unsigned getHwMode() const override;\n"; - OS << "};\n"; - EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS); +void SubtargetEmitter::emitGenMCSubtargetInfo() { + PI.emitNamespace(Target + "_MC", true); + PI.subtargetEmitResolveVariantSchedClassImplHdr(); + emitSchedModelHelpersImpl(/* OnlyExpandMCPredicates */ true); + PI.subtargetEmitResolveVariantSchedClassImplEnd(); + PI.emitNamespace(Target + "_MC", false); + + PI.subtargetEmitGenMCSubtargetInfoClass(Target, TGT.getHwModes().getNumModeIds() > 1); + EmitHwModeCheck(Target + "GenMCSubtargetInfo"); } -void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) { - OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n"; - OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; +void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions() { + PI.emitIncludeToggle("GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS", true); - STIPredicateExpander PE(Target); - PE.setExpandForMC(true); - PE.setByRef(true); - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); + PI.subtargetEmitExpandedSTIPredsMCAnaDecl(Target, SchedModels); - OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n"; + PI.emitIncludeToggle("GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS", false); - OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n"; - OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; + PI.emitIncludeToggle("GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS", true); std::string ClassPrefix = Target + "MCInstrAnalysis"; - PE.setExpandDefinition(true); - PE.setClassPrefix(ClassPrefix); - PE.setIndentLevel(0); - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); + PI.subtargetEmitExpandedSTIPreds(Target, ClassPrefix, SchedModels); - OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n"; + PI.emitIncludeToggle("GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS", false); } // // SubtargetEmitter::run - Main subtarget enumeration emitter. // -void SubtargetEmitter::run(raw_ostream &OS) { - emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); +void SubtargetEmitter::run() { + PI.subtargetEmitSourceFileHeader(); - OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; - OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_ENUM", true); DenseMap FeatureMap; - OS << "namespace llvm {\n"; - Enumeration(OS, FeatureMap); - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; + PI.emitNamespace("llvm", true); + Enumeration(FeatureMap); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_SUBTARGETINFO_ENUM", false); - EmitSubtargetInfoMacroCalls(OS); + EmitSubtargetInfoMacroCalls(); + PI.emitIncludeToggle("GET_SUBTARGETINFO_MC_DESC", true); - OS << "namespace llvm {\n"; + PI.emitNamespace("llvm", true); #if 0 - OS << "namespace {\n"; + PI.emitNamespace("", true); #endif - unsigned NumFeatures = FeatureKeyValues(OS, FeatureMap); - OS << "\n"; - EmitSchedModel(OS); - OS << "\n"; - unsigned NumProcs = CPUKeyValues(OS, FeatureMap); - OS << "\n"; + unsigned NumFeatures = FeatureKeyValues(FeatureMap); + EmitSchedModel(); + PI.emitString("\n"); + unsigned NumProcs = CPUKeyValues(FeatureMap); + PI.emitString("\n"); #if 0 - OS << "} // end anonymous namespace\n\n"; + PI.emitNamespace("", false); #endif // MCInstrInfo initialization routine. - emitGenMCSubtargetInfo(OS); - - OS << "\nstatic inline MCSubtargetInfo *create" << Target - << "MCSubtargetInfoImpl(" - << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n"; - OS << " return new " << Target - << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, "; - if (NumFeatures) - OS << Target << "FeatureKV, "; - else - OS << "std::nullopt, "; - if (NumProcs) - OS << Target << "SubTypeKV, "; - else - OS << "std::nullopt, "; - OS << '\n'; OS.indent(22); - OS << Target << "WriteProcResTable, " - << Target << "WriteLatencyTable, " - << Target << "ReadAdvanceTable, "; - OS << '\n'; OS.indent(22); - if (SchedModels.hasItineraries()) { - OS << Target << "Stages, " - << Target << "OperandCycles, " - << Target << "ForwardingPaths"; - } else - OS << "nullptr, nullptr, nullptr"; - OS << ");\n}\n\n"; + emitGenMCSubtargetInfo(); + + PI.subtargetEmitMCSubtargetInfoImpl(Target, NumFeatures, NumProcs, SchedModels.hasItineraries()); + + PI.emitNamespace("llvm", false); - OS << "} // end namespace llvm\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_MC_DESC", false); - OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_TARGET_DESC", true); - OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; + PI.subtargetEmitIncludeSTIDesc(); - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; - ParseFeaturesFunction(OS); + ParseFeaturesFunction(); - OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_TARGET_DESC", false); // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. - OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; - OS << "#undef GET_SUBTARGETINFO_HEADER\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_HEADER", true); std::string ClassName = Target + "GenSubtargetInfo"; - OS << "namespace llvm {\n"; - OS << "class DFAPacketizer;\n"; - OS << "namespace " << Target << "_MC {\n" - << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," - << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n" - << "} // end namespace " << Target << "_MC\n\n"; - OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" - << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " - << "StringRef TuneCPU, StringRef FS);\n" - << "public:\n" - << " unsigned resolveSchedClass(unsigned SchedClass, " - << " const MachineInstr *DefMI," - << " const TargetSchedModel *SchedModel) const override;\n" - << " unsigned resolveVariantSchedClass(unsigned SchedClass," - << " const MCInst *MI, const MCInstrInfo *MCII," - << " unsigned CPUID) const override;\n" - << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" - << " const;\n"; - if (TGT.getHwModes().getNumModeIds() > 1) - OS << " unsigned getHwMode() const override;\n"; - if (TGT.hasMacroFusion()) - OS << " std::vector getMacroFusions() const " - "override;\n"; - - STIPredicateExpander PE(Target); - PE.setByRef(false); - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); - - OS << "};\n" - << "} // end namespace llvm\n\n"; - - OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; - - OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; - OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; - - OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; - OS << "namespace llvm {\n"; - OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; - OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n"; - OS << "extern const llvm::MCWriteProcResEntry " - << Target << "WriteProcResTable[];\n"; - OS << "extern const llvm::MCWriteLatencyEntry " - << Target << "WriteLatencyTable[];\n"; - OS << "extern const llvm::MCReadAdvanceEntry " - << Target << "ReadAdvanceTable[];\n"; + PI.emitNamespace("llvm", true); + PI.subtargetEmitDFAPacketizerClass(TGT, Target, ClassName); - if (SchedModels.hasItineraries()) { - OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; - OS << "extern const unsigned " << Target << "OperandCycles[];\n"; - OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; - } + PI.subtargetEmitExpandedSTIPredsHeader(Target, SchedModels); + PI.subtargetEmitDFAPacketizerClassEnd(); - OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " - << "StringRef TuneCPU, StringRef FS)\n" - << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; - if (NumFeatures) - OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; - else - OS << "std::nullopt, "; - if (NumProcs) - OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; - else - OS << "std::nullopt, "; - OS << '\n'; OS.indent(24); - OS << Target << "WriteProcResTable, " - << Target << "WriteLatencyTable, " - << Target << "ReadAdvanceTable, "; - OS << '\n'; OS.indent(24); - if (SchedModels.hasItineraries()) { - OS << Target << "Stages, " - << Target << "OperandCycles, " - << Target << "ForwardingPaths"; - } else - OS << "nullptr, nullptr, nullptr"; - OS << ") {}\n\n"; + PI.emitNamespace("llvm", false); + + PI.emitIncludeToggle("GET_SUBTARGETINFO_HEADER", false); + + PI.emitIncludeToggle("GET_SUBTARGETINFO_CTOR", true); - EmitSchedModelHelpers(ClassName, OS); - EmitHwModeCheck(ClassName, OS); - emitGetMacroFusions(ClassName, OS); + PI.subtargetEmitSTICtor(); + PI.emitNamespace("llvm", true); + PI.subtargetEmitExternKVArrays(Target, SchedModels.hasItineraries()); - OS << "} // end namespace llvm\n\n"; + PI.subtargetEmitClassDefs(Target, + ClassName, + NumFeatures, + NumProcs, + SchedModels.hasItineraries()); - OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; + EmitSchedModelHelpers(ClassName); + EmitHwModeCheck(ClassName); - EmitMCInstrAnalysisPredicateFunctions(OS); + PI.subtargetEmitGetMacroFusions(TGT, Target, ClassName); + PI.emitNamespace("llvm", false); + + PI.emitIncludeToggle("GET_SUBTARGETINFO_CTOR", false); + + EmitMCInstrAnalysisPredicateFunctions(); +} + +void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { + CodeGenTarget CGTarget(RK); + + PrinterLanguage const PL = PrinterLLVM::getLanguage(); + PrinterLLVM *PI; + formatted_raw_ostream FOS(OS); + switch(PL) { + default: + llvm_unreachable("Subtarget backend does not support the selected printer language."); + case PRINTER_LANG_CPP: + PI = new PrinterLLVM(FOS, CGTarget.getName().str()); + break; + case PRINTER_LANG_CAPSTONE_C: + PI = new PrinterCapstone(FOS, CGTarget.getName().str()); + break; + } + SubtargetEmitter(RK, *PI).run(); + delete PI; } -static TableGen::Emitter::OptClass - X("gen-subtarget", "Generate subtarget enumerations"); +static TableGen::Emitter::Opt + X("gen-subtarget", EmitSubtarget, "Generate subtarget enumerations"); diff --git a/llvm/utils/TableGen/SubtargetEmitterTypes.h b/llvm/utils/TableGen/SubtargetEmitterTypes.h new file mode 100644 index 000000000000..0850febc7e6c --- /dev/null +++ b/llvm/utils/TableGen/SubtargetEmitterTypes.h @@ -0,0 +1,59 @@ +//===- SubtargetEmitterTypes.h - Generate subtarget enumerations types ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_SUBTARGETEMITTERTYPES_H +#define LLVM_UTILS_TABLEGEN_SUBTARGETEMITTERTYPES_H + +#include "CodeGenHwModes.h" +#include "CodeGenSchedule.h" +#include "CodeGenTarget.h" +#include "PredicateExpander.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/MCSchedule.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/TargetParser/SubtargetFeature.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +// Each processor has a SchedClassDesc table with an entry for each SchedClass. +// The SchedClassDesc table indexes into a global write resource table, write +// latency table, and read advance table. +typedef struct SchedClassTablesStruct { + std::vector> ProcSchedClasses; + std::vector WriteProcResources; + std::vector WriteLatencies; + std::vector WriterNames; + std::vector ReadAdvanceEntries; + + // Reserve an invalid entry at index 0 + SchedClassTablesStruct() { + ProcSchedClasses.resize(1); + WriteProcResources.resize(1); + WriteLatencies.resize(1); + WriterNames.push_back("InvalidWrite"); + ReadAdvanceEntries.resize(1); + } +} SchedClassTablesT; + +#endif // LLVM_UTILS_TABLEGEN_SUBTARGETEMITTERTYPES_H diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h index 3afe6b01467b..688cfbc6c15d 100644 --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -15,6 +15,7 @@ #ifndef LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H #define LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H +#include "CodeGenTarget.h" #include // A TableGen backend is a function that looks like @@ -63,11 +64,11 @@ namespace llvm { class raw_ostream; class RecordKeeper; -void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); +void EmitMapTable(RecordKeeper &RK, raw_ostream &OS, bool EmitC); // Defined in DecoderEmitter.cpp void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace); + CodeGenTarget &Target); } // namespace llvm