From c0317ac800b2c010fb84d0dd37750db074fde633 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 28 Oct 2022 01:12:10 -0400 Subject: [PATCH] Rebase refactored TableGen backends onto LLVM 18. The MCInstDesc table changed. Bsides this only minor changes were done and some additional code is emitted now for LLVM. This commit is the combination of all previous Auto-Sync commits. The list of commit messages follows: ----------- Combination of all commits of the refactored tablegen backends. These are the changes made for LLVM 16. Refactor Capstone relevant TableGen Emitter backends. This commit extracts the code which emits generated tables into two printer classes. The Printer is called whenever actual code is written to a file. There is the PrinterLLVM which emits tht code as before and PrinterCapstone which is tailored to or needs (emitting C and generates more info). Additionally missing memory access properties were added to ARMs td files. Emit a single header for all files. Captialize Target name for enums. Add lay metric to emit enum value for Banked and system regs. Malloc substr Sort instructions in ascending order. Free substr after use Add vanished constrainsts Fix `regInfoEmitEnums()` and indent Fix `GenDisassemblerTables.inc#checkDecoderPredicate()` Fix `TriCoreGenRegisterInfo.inc` | `PrinterCapstone::regInfoEmitRegClasses` revert changes to NEON instructions Add instructions with duplicate operands as Matchables. Add memory load and store info Correct memory access and out operand info Set register lists again as read ops due to https://github.com/llvm/llvm-project/issues/62455 Make printAliasInstr and getMnemonic static. Generate CS instruction enums from actual mnemonic. Not via the flawed AsmMatcher. Fix typo in InstrInfoEmitter.cpp Add deprecated QPX feature Replace + and - with p and m Add AssemblerPredicates to PPC Generate RegEncodingTable Define functions which are called by the Mapper as static. Necessary because these functions are present in each arch' Remove set_mem_access(). The cases where this is used to mark access to actual memory operands are either very rare, or those are neon lane indicies. Generate correct op type for absolute addresses. Check for RegisterPointer operands first to prevent mis-categorization. Add missing Operand types Generate Instruction formats for PPC. Add Paired Single instructions. Partly revert 94e41ce23a7fd863a96288ec05b6c7202c3cfbf1 (introduces accidentially removed code.) Set correct operand types for PS operands Add memory read/write attributes Add missing operand types Add mayLoad and mayStore information. Add documentation. Handle special AArch64 operand Replace C++ with C code. Check for duplicate enum instr. names Check for duplicate defintions of system registers. Add note about missing target names. Resolve templates in a single static method and add docs about it. Revert printing target name in upper case. Revert partially C++ syntax fixes in .td files. They break the TemplateCOllector since it searches for exactly those references but can't find any' Add all SubtargetFeatures to feature enum. Not just the one used by CGIs. Pass Decoder Enable to check specific table fields to determine if reg enum must be emitted. Allow to add namespace to type name/ Formatting Rework emitting of tables. The system operands are now emitted in reg, imm and aliass groups. Also a bug was fixed which emitted incorrect code.. Check for rename IMPLICIT_IMM operand types Pass DecodeComplete as pointer not as reference Print undef when it needs to be printed. Add namespace ids to all types and functions. Rework C translation. Pass MCOp as pointer not as ref Add missing SysImm type Fix syntax mistakes Generate additonal sys immediates and op groups. Handle edge case for printSVERegOp Handle default arguments of template functions. Add two missing op groups Generate a static RecEncodingTable Set enum values to encodings of the sys ops Generate a single Enum value file for system operands. Replace System operand groups with their operand types Fix missing braces warning Emit MCOperand validator. Emit lookupByName functions for sys operands Add namespaces for ARM. Check for Target if default arguments of template functions are resolved. auto-sync opcode & operand encoding info generation (#14) * Added operand and opcode info generation * Wrapped deprecated macro under an intellisense check Basically intellisense fails, causing multiple errors in other files, so when intellisense parses the code it will use the different version of the macro * Fixed a small bug Used double braces to prevent an old bug Removed extra new line and fixed a bug regarding move semantics --- DeprecatedFeatures.md | 41 + README.md | 113 +- llvm/include/llvm/Support/Compiler.h | 2 +- llvm/include/llvm/TableGen/StringMatcher.h | 11 +- .../llvm/TableGen/StringToOffsetTable.h | 16 + llvm/lib/Support/BLAKE3/CMakeLists.txt | 1 + llvm/lib/TableGen/CMakeLists.txt | 1 - llvm/lib/Target/ARM/ARMInstrFormats.td | 15 + llvm/lib/Target/ARM/ARMInstrInfo.td | 14 + llvm/lib/Target/ARM/ARMInstrMVE.td | 4 +- llvm/lib/Target/ARM/ARMInstrNEON.td | 28 +- llvm/lib/Target/ARM/ARMInstrThumb.td | 9 +- llvm/lib/Target/ARM/ARMInstrThumb2.td | 19 + llvm/lib/Target/ARM/ARMInstrVFP.td | 18 +- llvm/lib/Target/PowerPC/PPC.td | 8 + llvm/lib/Target/PowerPC/PPCDeprecated.td | 1510 ++++ llvm/lib/Target/PowerPC/PPCInstr64Bit.td | 9 +- llvm/lib/Target/PowerPC/PPCInstrAltivec.td | 2 + llvm/lib/Target/PowerPC/PPCInstrFormats.td | 4 + llvm/lib/Target/PowerPC/PPCInstrInfo.td | 111 +- .../Target/PowerPC/PPCInstrPairedSingle.td | 384 + llvm/lib/Target/PowerPC/PPCInstrSPE.td | 8 + llvm/lib/Target/PowerPC/PPCRegisterInfo.td | 15 + llvm/lib/Target/PowerPC/PPCScheduleP10.td | 2 +- llvm/lib/Target/PowerPC/PPCScheduleP9.td | 3 +- llvm/utils/TableGen/AsmMatcherEmitter.cpp | 2298 +----- llvm/utils/TableGen/AsmMatcherEmitterTypes.h | 480 ++ llvm/utils/TableGen/AsmWriterEmitter.cpp | 532 +- llvm/utils/TableGen/AsmWriterInst.cpp | 34 +- llvm/utils/TableGen/CMakeLists.txt | 3 + llvm/utils/TableGen/CodeGenTarget.cpp | 7 +- llvm/utils/TableGen/DecoderEmitter.cpp | 1152 +-- llvm/utils/TableGen/DecoderEmitter.md | 232 + llvm/utils/TableGen/DecoderEmitterTypes.h | 142 + llvm/utils/TableGen/DisassemblerEmitter.cpp | 14 +- llvm/utils/TableGen/InstrInfoEmitter.cpp | 1017 +-- llvm/utils/TableGen/InstrInfoEmitterTypes.h | 49 + .../TableGen/MacroFusionPredicatorEmitter.cpp | 2 +- llvm/utils/TableGen/PredicateExpander.cpp | 700 +- llvm/utils/TableGen/PredicateExpander.h | 244 +- llvm/utils/TableGen/Printer.h | 1856 +++++ llvm/utils/TableGen/PrinterCapstone.cpp | 3757 ++++++++++ llvm/utils/TableGen/PrinterLLVM.cpp | 6418 +++++++++++++++++ llvm/utils/TableGen/PrinterTypes.h | 23 + llvm/utils/TableGen/RegisterInfoEmitter.cpp | 1458 +--- .../utils/TableGen/RegisterInfoEmitterTypes.h | 72 + .../utils/TableGen/SearchableTableEmitter.cpp | 403 +- llvm/utils/TableGen/SearchableTablesTypes.h | 87 + llvm/utils/TableGen/SequenceToOffsetTable.h | 86 +- .../{lib => utils}/TableGen/StringMatcher.cpp | 24 + llvm/utils/TableGen/SubtargetEmitter.cpp | 1288 +--- llvm/utils/TableGen/SubtargetEmitterTypes.h | 59 + llvm/utils/TableGen/TableGenBackends.h | 3 +- 53 files changed, 17898 insertions(+), 6890 deletions(-) create mode 100644 DeprecatedFeatures.md create mode 100644 llvm/lib/Target/PowerPC/PPCDeprecated.td create mode 100644 llvm/lib/Target/PowerPC/PPCInstrPairedSingle.td create mode 100644 llvm/utils/TableGen/AsmMatcherEmitterTypes.h create mode 100644 llvm/utils/TableGen/DecoderEmitter.md create mode 100644 llvm/utils/TableGen/DecoderEmitterTypes.h create mode 100644 llvm/utils/TableGen/InstrInfoEmitterTypes.h create mode 100644 llvm/utils/TableGen/Printer.h create mode 100644 llvm/utils/TableGen/PrinterCapstone.cpp create mode 100644 llvm/utils/TableGen/PrinterLLVM.cpp create mode 100644 llvm/utils/TableGen/PrinterTypes.h create mode 100644 llvm/utils/TableGen/RegisterInfoEmitterTypes.h create mode 100644 llvm/utils/TableGen/SearchableTablesTypes.h rename llvm/{lib => utils}/TableGen/StringMatcher.cpp (88%) create mode 100644 llvm/utils/TableGen/SubtargetEmitterTypes.h 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..86865ccfbe80 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,93 @@ -# 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. +Please note that within LLVM we speak of a `Target` if we refer to an architecture. -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. +## Code generation -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. +### Relevant files -Other components include: -the [libc++ C++ standard library](https://libcxx.llvm.org), -the [LLD linker](https://lld.llvm.org), and more. +The TableGen emitter backends are located in `llvm/utils/TableGen/`. -## Getting the Source Code and Building LLVM +The target definition files (`.td`), which define the +instructions, operands, features etc., can be +found in `llvm/lib/Target//`. -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. +### Code generation overview -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. +Generating code for a target has 6 steps: -## Getting in touch +``` + 5 6 + ┌──────────┐ ┌──────────┐ + │Printer │ │CS .inc │ + 1 2 3 4 ┌──►│Capstone ├─────►│files │ +┌───────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐ │ └──────────┘ └──────────┘ +│ .td │ │ │ │ │ │ Code- │ │ +│ files ├────►│ TableGen ├────►│ CodeGen ├────►│ Emitter │◄─┤ +└───────┘ └──────┬────┘ └───────────┘ └──────────┘ │ + │ ▲ │ ┌──────────┐ ┌──────────┐ + └─────────────────────────────────┘ └──►│Printer ├─────►│LLVM .inc │ + │LLVM │ │files │ + └──────────┘ └──────────┘ +``` -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). +1. LLVM targets are defined in `.td` files. They describe instructions, operands, +features and other properties. -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. +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()`. + +- 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/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 @@ private: 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 @@ public: } 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; +#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..43a42f88970f --- /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:$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:$src), + "qvlfdx $FRT, $src", IIC_LdStLFD, []>; + + let RC = 1 in + def QVLFDXA : XForm_1<31, 583, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfdxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFDUX : XForm_1<31, 615, + (outs qfrc:$FRT, ptr_rc_nor0:$ea_result), + (ins memrr:$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:$src), + "qvlfduxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFSX : XForm_1_memOp<31, 519, + (outs qfrc:$FRT), (ins memrr:$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:$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:$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:$src), + "qvlfsxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFSUX : XForm_1<31, 551, + (outs qsrc:$FRT, ptr_rc_nor0:$ea_result), + (ins memrr:$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:$src), + "qvlfsuxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCDX : XForm_1<31, 71, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcdx $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCDXA : XForm_1<31, 71, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcdxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCDUX : XForm_1<31, 103, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcdux $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCDUXA : XForm_1<31, 103, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcduxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCSX : XForm_1<31, 7, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcsx $FRT, $src", IIC_LdStLFD, []>; + let isCodeGenOnly = 1 in + def QVLFCSXs : XForm_1<31, 7, + (outs qsrc:$FRT), (ins memrr:$src), + "qvlfcsx $FRT, $src", IIC_LdStLFD, []>; + + let RC = 1 in + def QVLFCSXA : XForm_1<31, 7, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcsxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFCSUX : XForm_1<31, 39, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcsux $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFCSUXA : XForm_1<31, 39, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfcsuxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFIWAX : XForm_1<31, 871, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfiwax $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFIWAXA : XForm_1<31, 871, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfiwaxa $FRT, $src", IIC_LdStLFD, []>; + + def QVLFIWZX : XForm_1<31, 839, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfiwzx $FRT, $src", IIC_LdStLFD, []>; + let RC = 1 in + def QVLFIWZXA : XForm_1<31, 839, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlfiwzxa $FRT, $src", IIC_LdStLFD, []>; + + + def QVLPCLDX : XForm_1<31, 582, + (outs qfrc:$FRT), (ins memrr:$src), + "qvlpcldx $FRT, $src", IIC_LdStLFD, []>; + def QVLPCLSX : XForm_1<31, 518, + (outs qfrc:$FRT), (ins memrr:$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:$src), + "qvlpcrdx $FRT, $src", IIC_LdStLFD, []>; + def QVLPCRSX : XForm_1<31, 6, + (outs qfrc:$FRT), (ins memrr:$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:$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:$dst), + "qvstfdx $FRT, $dst", IIC_LdStSTFD, []>; + + let RC = 1 in + def QVSTFDXA : XForm_8<31, 711, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfdxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDUX : XForm_8<31, 743, (outs ptr_rc_nor0:$ea_res), + (ins qfrc:$FRT, memrr:$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:$dst), + "qvstfduxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDXI : XForm_8<31, 709, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfdxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFDXIA : XForm_8<31, 709, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfdxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFDUXI : XForm_8<31, 741, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfduxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFDUXIA : XForm_8<31, 741, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfduxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSX : XForm_8_memOp<31, 647, + (outs), (ins qfrc:$FRT, memrr:$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:$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:$dst), + "qvstfsxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSUX : XForm_8<31, 679, (outs ptr_rc_nor0:$ea_res), + (ins qsrc:$FRT, memrr:$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:$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:$dst), + "qvstfsuxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSXI : XForm_8<31, 645, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfsxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFSXIA : XForm_8<31, 645, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfsxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFSUXI : XForm_8<31, 677, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfsuxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFSUXIA : XForm_8<31, 677, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfsuxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDX : XForm_8<31, 199, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcdx $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDXA : XForm_8<31, 199, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcdxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSX : XForm_8<31, 135, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsx $FRT, $dst", IIC_LdStSTFD, []>; + let isCodeGenOnly = 1 in + def QVSTFCSXs : XForm_8<31, 135, + (outs), (ins qsrc:$FRT, memrr:$dst), + "qvstfcsx $FRT, $dst", IIC_LdStSTFD, []>; + + let RC = 1 in + def QVSTFCSXA : XForm_8<31, 135, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDUX : XForm_8<31, 231, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcdux $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDUXA : XForm_8<31, 231, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcduxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSUX : XForm_8<31, 167, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsux $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSUXA : XForm_8<31, 167, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsuxa $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDXI : XForm_8<31, 197, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcdxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDXIA : XForm_8<31, 197, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcdxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSXI : XForm_8<31, 133, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSXIA : XForm_8<31, 133, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCDUXI : XForm_8<31, 229, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcduxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCDUXIA : XForm_8<31, 229, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcduxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFCSUXI : XForm_8<31, 165, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsuxi $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFCSUXIA : XForm_8<31, 165, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfcsuxia $FRT, $dst", IIC_LdStSTFD, []>; + + def QVSTFIWX : XForm_8<31, 967, + (outs), (ins qfrc:$FRT, memrr:$dst), + "qvstfiwx $FRT, $dst", IIC_LdStSTFD, []>; + let RC = 1 in + def QVSTFIWXA : XForm_8<31, 967, + (outs), (ins qfrc:$FRT, memrr:$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..63faceeced14 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, []>; @@ -4405,6 +4440,7 @@ def LDCIX : XForm_base_r3xo_memOp<31, 885, (outs gprc:$RST), (ins gprc:$RA, gprc:$RB), "ldcix $RST, $RA, $RB", IIC_LdStLoad, []>; +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, []>; @@ -4420,6 +4456,7 @@ def STDCIX : XForm_base_r3xo_memOp<31, 1013, (outs), // 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 +4472,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 +4490,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 +4512,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 +4545,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 +4745,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 +5364,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..74abd681035f --- /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:$src, u1imm:$W, u3imm: $I), + "psq_l $FRT, $src, $W, $I", IIC_FPGeneral>; +def PSQ_LU : PSForm_qd<57, + (outs f8rc:$FRT), (ins memrid12:$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:$dst, u1imm:$W, u3imm: $I), + "psq_st $FRT, $dst, $W, $I", IIC_FPGeneral>; +def PSQ_STU : PSForm_qd<61, + (outs), (ins f8rc:$FRT, memrid12:$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..94f77ddca9b2 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,6 +806,8 @@ 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))]>; + +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)]>; @@ -808,6 +815,7 @@ def SPESTWX : XForm_8<31, 151, (outs), (ins spe4rc:$RST, (memrr $RA, $RB): "stwx $RST, $addr", IIC_LdStStore, [(store f32:$RST, xaddr:$addr)]>; } +} } // 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..89a2f3c480f3 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,42 @@ 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; +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) class AsmMatcherEmitter { RecordKeeper &Records; -public: - AsmMatcherEmitter(RecordKeeper &R) : Records(R) {} + PrinterLLVM &PI; - void run(raw_ostream &o); +public: + AsmMatcherEmitter(RecordKeeper &R, PrinterLLVM &PI) : Records(R), PI(PI) {} + + void run(); }; -/// 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, +// +// ClassInfo implementation +// - /// 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 { +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 +153,98 @@ public: 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 +253,47 @@ public: // 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 +317,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 AsmMatcherInfo::hasOptionalOperands() const { +return any_of(Classes, + [](const ClassInfo &Class) { return Class.IsOptional; }); +} - bool hasOptionalOperands() const { - return any_of(Classes, - [](const ClassInfo &Class) { return Class.IsOptional; }); - } -}; - -} // end anonymous namespace - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MatchableInfo::dump() const { errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n"; @@ -1104,7 +678,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 +1529,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 +1538,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"; + size_t MaxNumOperands = 0; + for (const auto &MI : Infos) { + MaxNumOperands = std::max(MaxNumOperands, MI->AsmOperands.size()); } - 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"; - } - 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"; + PI.asmMatcherEmitConversionFunctionI(Target.getName(), ClassName, + TargetOperandClass, HasOptionalOperands, + MaxNumOperands); - std::string OperandFnBody; - raw_string_ostream OpOS(OperandFnBody); // 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 +1584,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 +1643,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 +1692,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 +1717,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 +1739,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 +1753,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"; + PI.asmMatcherEmitTiedOperandEnum(TiedOperandsEnumMap); - 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.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 +1787,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 +1824,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 +1851,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 +1869,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 +1894,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 +1913,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 +1940,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 +1995,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 +2022,33 @@ 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"; - - 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"; -} - -static std::string -getNameForFeatureBitset(const std::vector &FeatureBitset) { - std::string Name = "AMFBS"; - for (const auto &Feature : FeatureBitset) - Name += ("_" + Feature->getName()).str(); - return Name; -} - -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 +2111,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 +2191,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 +2219,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 +2232,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"); + PI.asmMatcherEmitMatchTable(Target, Info, StringTable, VariantCount); - 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"; - } - - 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"; + PI.asmMatcherEmitMatchFunction( + Target, AsmParser, ClassName, HasMnemonicFirst, HasOptionalOperands, + ReportMultipleNearMisses, HasMnemonicAliases, MaxNumOperands, + HasDeprecation, VariantCount); - 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"; - - if (!Info.OperandMatchInfo.empty()) - emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, - MaxMnemonicIndex, FeatureBitsets.size(), + 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); - OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; + PI.emitIncludeToggle("GET_MNEMONIC_SPELL_CHECKER", true); + PI.asmMatcherEmitMnemonicSpellChecker(Target, VariantCount); + PI.emitIncludeToggle("GET_MNEMONIC_SPELL_CHECKER", false); - 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, + PI.emitIncludeToggle("GET_MNEMONIC_CHECKER", true); + PI.asmMatcherEmitMnemonicChecker(Target, VariantCount, HasMnemonicFirst, HasMnemonicAliases); - - OS << "#endif // GET_MNEMONIC_CHECKER\n\n"; + PI.emitIncludeToggle("GET_MNEMONIC_CHECKER", false); } -static TableGen::Emitter::OptClass - X("gen-asm-matcher", "Generate assembly instruction matcher"); +namespace llvm { + +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; + } + + AsmMatcherEmitter(RK, *PI).run(); + delete PI; +} + +} // end namespace llvm 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..5dabaf2ff0c7 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 @@ private: } // 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"; + PI.asmWriterEmitDeclValid(Target.getName().str(), ClassName); - 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.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"; + PI.asmWriterEmitPrintAliasOp(Target.getName().str(), + ClassName, + PrintMethods, + PassSubtarget); - 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"; - } - - 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,35 @@ 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(); + EmitGetMnemonic(TableDrivenOperandPrinters, BitsLeft, AsmStrBits); + EmitPrintInstruction(TableDrivenOperandPrinters, BitsLeft, AsmStrBits); + EmitGetRegisterName(); + EmitPrintAliasInstruction(); } -static TableGen::Emitter::OptClass - X("gen-asm-writer", "Generate assembly writer"); +namespace llvm { + +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; +} + +} // end namespace llvm diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp index c9558593e142..2d4b7f4da3ec 100644 --- a/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -12,9 +12,12 @@ #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; @@ -22,15 +25,38 @@ static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } std::string AsmWriterOperand::getCode(bool PassSubtarget) const { if (OperandType == isLiteralTextOperand) { - if (Str.size() == 1) - return "O << '" + Str + "';"; - return "O << \"" + Str + "\";"; + std::string Res; + if (Str.size() == 1) { + Res = "SStream_concat1(O, '" + Str + "');"; + return Res; + } + + Res = "SStream_concat0(O, \"" + Str + "\");"; + return Res; } if (OperandType == isLiteralStatementOperand) return Str; - std::string Result = Str + "(MI"; + bool LangCS = PrinterLLVM::getLanguage() == PRINTER_LANG_CAPSTONE_C; + PassSubtarget = LangCS ? false : PassSubtarget; + + std::string Result; + if (LangCS && PCRel) { + // Those two functions have two different signatures which is not supported + // in C. For the PCRel version (gets the Address as parameter), we add an + // "Addr" to the name. + if (Str.find("printOperand") == 0) + Result = Str + "Addr"; + else if (Str.find("printAdrLabelOperand") == 0) { + unsigned TemplArgsIdx = Str.find("<"); + Result = Str.substr(0, TemplArgsIdx) + "Addr" + Str.substr(TemplArgsIdx); + } + } else + 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/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index 37fa30349eea..1d294bb95b8e 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" @@ -277,7 +278,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..82e0c2a77cc7 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; -public: - DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace) - : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)) {} + 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; - // 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; +public: + // 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 @@ public: } // 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 @@ protected: // 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 @@ public: 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 @@ protected: 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 @@ protected: 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; - } - } +// 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); } - 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"; - } - 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,115 @@ 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) { + // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. + if (Target.getName() == "ARM" || Target.getName() == "Thumb" || + Target.getName() == "AArch64" || Target.getName() == "ARM64") { + 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 = "))"; + } else { + PredicateNamespace = Target.getName().str(); + GPrefix = "if ("; + L = ""; + + switch (PL) { + default: + PrintFatalNote("DecoderEmitter does not support the given output language."); + case llvm::PRINTER_LANG_CPP: + GPostfix = " == MCDisassembler::Fail)"; + break; + case llvm::PRINTER_LANG_CAPSTONE_C: + GPostfix = " == MCDisassembler_Fail)"; + break; + } + } + + 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..119579174ba6 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -11,31 +11,8 @@ // //===----------------------------------------------------------------------===// -#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" using namespace llvm; @@ -49,70 +26,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 +90,7 @@ private: // Operand Info Emission. //===----------------------------------------------------------------------===// -InstrInfoEmitter::OperandInfoTy +OperandInfoTy InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { OperandInfoTy Result; @@ -153,57 +121,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 +190,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 +202,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"; + 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); + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_ENUM", false); - 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_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); + 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 +235,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"; + 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(); - 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(); - }; // TODO: Factor out duplicate operand lists to compress the tables. if (!NumberedInstructions.empty()) { std::vector OperandOffsets; @@ -421,13 +288,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 +297,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"; + PI.instrInfoEmitGetOpTypeEnd(); + PI.emitNamespace(Namespace.str(), false); + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_OPERAND_TYPE", false); - 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.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 +321,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 +354,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"; + PI.instrInfoEmitGetLogicalOpSizeTable(LogicalOpListSize, LogicalOpSizeList); - 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.instrInfoEmitGetLogicalOpSizeSwitch(InstMap); } else { - OS << " return LogicalOpIdx;\n"; + PI.instrInfoEmitGetLogicalOpSizeReturn(); } - OS << "}\n"; + PI.instrInfoEmitGetLogicalOpSizeEnd(); - 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"; + PI.instrInfoEmitGetLogicalOpIdx(); - OS << "} // end namespace " << Namespace << "\n"; - OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n\n"; + 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 +403,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 +414,77 @@ 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"; - } + PI.emitNamespace(TargetName.str() + "_MC", false); + PI.emitNamespace("llvm", false); - OS << "void verifyInstructionPredicates(unsigned Opcode, const FeatureBitset " - "&Features);\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_HELPER_DECLS", false); - OS << "\n} // end namespace " << TargetName << "_MC\n"; - OS << "} // end namespace llvm\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_HELPERS", true); - OS << "#endif // GET_INSTRINFO_MC_HELPER_DECLS\n\n"; + PI.emitNamespace("llvm", true); + PI.emitNamespace(TargetName.str() + "_MC", true); - OS << "#ifdef GET_INSTRINFO_MC_HELPERS\n"; - OS << "#undef GET_INSTRINFO_MC_HELPERS\n\n"; + PI.instrInfoEmitPredFcnImpl(TargetName, TIIPredicates); - OS << "namespace llvm {\n"; - OS << "namespace " << TargetName << "_MC {\n\n"; + PI.emitNamespace(TargetName.str() + "_MC", false); + PI.emitNamespace("llvm", false); - 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"; - } - - OS << "} // end namespace " << TargetName << "_MC\n"; - OS << "} // end namespace llvm\n\n"; - - OS << "#endif // GET_GENISTRINFO_MC_HELPERS\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_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 +513,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"; - - // Emit the name table for error messages. - OS << "#ifndef NDEBUG\n"; - SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); - OS << "#endif // NDEBUG\n\n"; + PI.instrInfoEmitFeatureBitsEnum(FeatureBitsets); + PI.instrInfoEmitFeatureBitsArray(FeatureBitsets, 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.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. + PI.instrInfoEmitEmitSTFNameTable(SubtargetFeatures); + + // Emit the predicate verifier. + 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 +563,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 +594,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"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", true); + PI.emitNamespace("llvm", true); - 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"; + PI.instrInfoEmitMCInstrDescDecl(TargetName, + NumberedInstructions.size(), + OperandInfoSize, + std::max(ImplicitListSize, 1U)); - OS << "} // end namespace llvm\n"; - OS << "#endif // defined(GET_INSTRINFO_MC_DESC) || " - "defined(GET_INSTRINFO_CTOR_DTOR)\n\n"; + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", false); - OS << "#ifdef GET_INSTRINFO_MC_DESC\n"; - OS << "#undef GET_INSTRINFO_MC_DESC\n"; - OS << "namespace llvm {\n\n"; + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", true); + PI.emitNamespace("llvm", true); - // Emit all of the MCInstrDesc records in reverse ENUM ordering. + // 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 +647,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 +658,82 @@ 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"; + PI.instrInfoEmitMCInstrInfoInitRoutine(TargetName, + NumberedInstructions.size(), + HasDeprecationFeatures, + HasComplexDeprecationInfos); - OS << "#endif // GET_INSTRINFO_MC_DESC\n\n"; + PI.emitNamespace("llvm", false); + PI.emitIncludeToggle("GET_INSTRINFO_MC_DESC", false); - // Create a TargetInstrInfo subclass to hide the MC layer initialization. - OS << "#ifdef GET_INSTRINFO_HEADER\n"; - OS << "#undef GET_INSTRINFO_HEADER\n"; + PI.emitIncludeToggle("GET_INSTRINFO_HELPERS", true); + emitTIIHelperMethods(TargetName, /* ExpandDefinition = */ true); - 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"; + 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); - 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.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); 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(OperandInfo, OperandInfoMap); // Emit all of the target independent flags... - if (Inst.isPreISelOpcode) OS << "|(1ULL<getValueAsBitsInit("TSFlags"); @@ -1258,62 +747,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); + 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,8 @@ 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"); @@ -460,8 +462,8 @@ void STIPredicateExpander::expandHeader(raw_ostream &OS, OS << ";\n"; } -void STIPredicateExpander::expandPrologue(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderLLVM::expandPrologue(raw_ostream &OS, + const STIPredicateFunction &Fn) { RecVec Delegates = Fn.getDeclaration()->getValueAsListOfDefs("Delegates"); bool UpdatesOpcodeMask = Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); @@ -487,8 +489,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 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; @@ -526,8 +529,8 @@ void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup } } -void STIPredicateExpander::expandBody(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderLLVM::expandBody(raw_ostream &OS, + const STIPredicateFunction &Fn) { bool UpdatesOpcodeMask = Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask"); @@ -559,8 +562,8 @@ void STIPredicateExpander::expandBody(raw_ostream &OS, OS << "}\n"; } -void STIPredicateExpander::expandEpilogue(raw_ostream &OS, - const STIPredicateFunction &Fn) { +void PredicateExpanderLLVM::expandEpilogue(raw_ostream &OS, + const STIPredicateFunction &Fn) { OS << '\n'; OS.indent(getIndentLevel() * 2); OS << "return "; @@ -573,8 +576,573 @@ void STIPredicateExpander::expandEpilogue(raw_ostream &OS, OS << "} // " << ClassPrefix << "::" << FunctionName << "\n\n"; } -void STIPredicateExpander::expandSTIPredicate(raw_ostream &OS, - const STIPredicateFunction &Fn) { +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"); + + 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 PredicateExpanderCapstone::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 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; + 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 PredicateExpanderCapstone::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 PredicateExpanderCapstone::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 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 @@ public: 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 expandSTIPredicate(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) 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; + + // 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..45a3455e4cf8 --- /dev/null +++ b/llvm/utils/TableGen/Printer.h @@ -0,0 +1,1856 @@ +//===--------------- 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 + //---------------------------- + PredicateExpander *PE = nullptr; + + //-------------------------- + // 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 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 = "") 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() 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 subtargetEmitDFASubtargetInfoImpl(std::string const &TargetName, + std::string const &ClassName, + unsigned NumFeatures, + unsigned NumProcs, + bool SchedModelHasItin) 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 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(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 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) const; + virtual void searchableTablesEmitEndif(StreamType ST = ST_NONE) const; + virtual void searchableTablesEmitUndef(std::string const &Guard) 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) 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; + + 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() 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; + void subtargetEmitDFASubtargetInfoImpl(std::string const &TargetName, + std::string const &ClassName, + unsigned NumFeatures, + unsigned NumProcs, + bool SchedModelHasItin) const override; + + //--------------------------- + // Backend: InstrInfoEmitter + //--------------------------- + + void instrInfoEmitSourceFileHeader() 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(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 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) const override; + void searchableTablesEmitEndif(StreamType ST = ST_NONE) const override; + void searchableTablesEmitUndef(std::string const &Guard) 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..5e4024daad5a --- /dev/null +++ b/llvm/utils/TableGen/PrinterCapstone.cpp @@ -0,0 +1,3757 @@ +//===------------- 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-2023 */\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 = "") const { + return; +} + +/// 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_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 int16_t " << 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() + ")"); + } +} + +std::string edgeCaseTemplArg(std::string &Code) { + size_t const B = Code.find_first_of("<"); + size_t const E = Code.find(">"); + if (B == std::string::npos) { + // No template + PrintFatalNote("Edge case for C++ code not handled: " + Code); + } + 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 (Code.find("printSVERegOp") != std::string::npos) + // AArch64: Template argument is of type char and + // no argument is interpreded as 0 + return DecName + "_0" + Rest; + + PrintFatalNote("Edge case for C++ code not handled: " + Code); +} + +static std::string handleDefaultArg(const std::string &TargetName, + std::string &Code) { + static SmallVector> + AArch64TemplFuncWithDefaults = {// Default is 1 + {"printVectorIndex", "1"}, + // Default is false == 0 + {"printPrefetchOp", "0"}}; + SmallVector> *TemplFuncWithDefaults; + if (TargetName == "AArch64") + TemplFuncWithDefaults = &AArch64TemplFuncWithDefaults; + else + return Code; + + for (std::pair Func : *TemplFuncWithDefaults) { + if (Code.find(Func.first) != std::string::npos) { + unsigned long const B = + Code.find(Func.first) + std::string(Func.first).size(); + if (Code[B] == '<' || Code[B] == '_') + // False positive or already fixed. + continue; + std::string const &DecName = Code.substr(0, B); + std::string Rest = Code.substr(B); + return DecName + "_" + Func.second + Rest; + } + } + // No template function, false positive or fixed + return Code; +} + +static void patchTemplateArgs(const std::string &TargetName, + std::string &Code) { + size_t const B = Code.find_first_of("<"); + size_t const E = Code.find(">"); + if (B == std::string::npos) { + Code = handleDefaultArg(TargetName, Code); + return; + } + 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()) { + Code = edgeCaseTemplArg(Code); + 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; +} + +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; + if (Op.Decoder.find("<") != std::string::npos) { + DecoderOS << translateToC(TargetName, Op.Decoder); + } else { + DecoderOS << 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 = (OpInfo.Decoder.find("<") != std::string::npos) + ? translateToC(TargetName, OpInfo.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 << "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"}; + + 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"; +} + +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) << "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() 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; + + // Make sure we don't return an invalid pointer if bits is 0 + OS << " if (Bits == 0)\n" + " return NULL;\n"; + + // 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 << " llvm_unreachable(\"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" + << " break;\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::subtargetEmitDFASubtargetInfoImpl( + std::string const &TargetName, std::string const &ClassName, + unsigned NumFeatures, unsigned NumProcs, bool SchedModelHasItin) 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::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( + std::vector const &OperandInfo, + OperandInfoMapTy const &OperandInfoMap) const { + OS << OperandInfoMap.find(OperandInfo)->second << ",\t0"; +} + +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 << "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 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::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'); + 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->isCall) { + Flags += TargetName.str() + "_GRP_JUMP, "; + } + if (CGI->isCall) { + Flags += TargetName.str() + "_GRP_CALL, "; + } + for (const auto &OpInfo : CGI->Operands.OperandList) { + if (OpInfo.OperandType == "MCOI::OPERAND_PCREL" && + (CGI->isBranch || 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; + return Enum; +} + +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 getArchSupplInfo(StringRef const &TargetName, + CodeGenInstruction const *CGI, + raw_string_ostream &PPCFormatEnum) { + if (TargetName == "PPC") + return getArchSupplInfoPPC(TargetName, CGI, PPCFormatEnum); + 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; +} + +std::string getCSOperandType(Record const *OpRec) { + std::string OperandType = getPrimaryCSOperandType(OpRec); + if (OperandType == "CS_OP_MEM") + OperandType += " | CS_OP_IMM"; + return OperandType; +} + +std::string getCSOperandEncoding(CodeGenInstruction const *CGI, + Record const *OpRec, StringRef const &OpName) { + BitsInit const *const InstrBits = + !CGI->TheDef->getValueAsBit("isPseudo") + ? CGI->TheDef->getValueAsBitsInit("Inst") + : nullptr; + if (!InstrBits) + return "{ 0 }"; + + std::string ResultStr; + raw_string_ostream Result(ResultStr); + int64_t const Size = CGI->TheDef->getValueAsInt("Size") * 8; + // For some reason even on 2 byte THUMB instructions the Inst field has 32 + // bits with the first 16 left as 0, so we skip them. + // I assume the same may happen for other architectures as well. + unsigned const BitCount = InstrBits->getNumBits(); + unsigned const StartIdx = BitCount - Size; + + struct { + unsigned OperandPiecesCount; + std::array Indexes; + std::array Sizes; + } EncodingData{}; + + // scan all bits one by one to try and find any references of the operand + for (unsigned InstrBitIdx = StartIdx; InstrBitIdx != BitCount; + ++InstrBitIdx) { + VarBitInit const *VarBit; + if ((VarBit = dyn_cast( + InstrBits->getBit(BitCount - InstrBitIdx - 1))) && + VarBit->getBitVar()->getAsString() == OpName) { + unsigned const BitNum = (InstrBitIdx + VarBit->getBitNum()) >= BitCount + ? BitCount - InstrBitIdx - 1 + : VarBit->getBitNum(); + if (EncodingData.OperandPiecesCount == 8) + llvm_unreachable("Too many operand pieces in the instruction!"); + + // place current index + EncodingData.Indexes[EncodingData.OperandPiecesCount] = + InstrBitIdx - StartIdx; + + unsigned VarBitIdx; + // this is meant for getting the size of the operand and to also see + // whether there are more pieces of the operand further + for (VarBitIdx = 1; VarBitIdx <= BitNum; ++VarBitIdx) { + VarBit = dyn_cast( + InstrBits->getBit(BitCount - (InstrBitIdx + VarBitIdx) - 1)); + + if (VarBit && VarBit->getBitVar()->getAsString() == OpName) + continue; + break; + } + // place current size + EncodingData.Sizes[EncodingData.OperandPiecesCount] = VarBitIdx; + ++EncodingData.OperandPiecesCount; + + // if we broke out of the loop before it finishes, it means we aren't + // done here. more pieces of the operand are to be found + if (VarBitIdx <= BitNum) { + InstrBitIdx += VarBitIdx - 1; + continue; + } + break; + } + } + + // if no references were found we exit, otherwise we add the encoding to the string + if (!EncodingData.OperandPiecesCount) + return "{ 0 }"; + Result << "{ " << EncodingData.OperandPiecesCount << ", { "; + + for (unsigned i = 0; i != EncodingData.OperandPiecesCount; ++i) { + if (i) + Result << ", "; + Result << EncodingData.Indexes[i]; + } + Result << " }, { "; + for (unsigned i = 0; i != EncodingData.OperandPiecesCount; ++i) { + if (i) + Result << ", "; + Result << EncodingData.Sizes[i]; + } + Result << " } }"; + return ResultStr; +} + +std::string getCSOpcodeEncoding(CodeGenInstruction const *CGI) { + BitsInit const *const InstrBits = + !CGI->TheDef->getValueAsBit("isPseudo") + ? CGI->TheDef->getValueAsBitsInit("Inst") + : nullptr; + if (!InstrBits) + return "{ 0 }"; + + std::string ResultStr; + raw_string_ostream Result(ResultStr); + int64_t const Size = CGI->TheDef->getValueAsInt("Size") * 8; + unsigned const BitCount = InstrBits->getNumBits(); + unsigned const StartIdx = BitCount - Size; + + struct { + std::bitset<64> Bits; + std::array Indexes; + unsigned BitCount; + } OpcodeData{}; + + for (unsigned InstrBitIdx = StartIdx; InstrBitIdx != BitCount; + ++InstrBitIdx) { + if (auto const *const Bit = + dyn_cast(InstrBits->getBit(BitCount - InstrBitIdx - 1))) { + if (OpcodeData.BitCount == 64) + llvm_unreachable("Instruction's opcode size is greater than 8 bytes!"); + OpcodeData.Bits.set(OpcodeData.BitCount, Bit->getValue()); + OpcodeData.Indexes[OpcodeData.BitCount] = InstrBitIdx - StartIdx; + ++OpcodeData.BitCount; + } + } + + // Most likely unreachable since there is no instruction to my knowledge that doesn't have any opcode bits + if (!OpcodeData.BitCount) + llvm_unreachable("Instruction without opcode bits!"); + + Result << "{ " << OpcodeData.Bits.to_ullong() << ", { "; + for (auto Current = OpcodeData.Indexes.begin(), + end = Current + OpcodeData.BitCount; + Current != end; ++Current) { + if (Current != OpcodeData.Indexes.begin()) + Result << ", "; + Result << *Current; + } + Result << " }, " << OpcodeData.BitCount << " }"; + return ResultStr; +} + +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 &PPCFormatEnum) { + 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 ? "1" : "0") << ", "; + InsnMap << (CGI->isIndirectBranch ? "1" : "0") << ", "; + InsnMap << getArchSupplInfo(TargetName, CGI, PPCFormatEnum) << ",\n"; + InsnMap.indent(4) << getCSOpcodeEncoding(CGI); + } else { + InsnMap.indent(4) << "{ 0 }, { 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."); +} + +std::string getOperandDataTypes(Record const *Op, std::string &OperandType) { + MVT::SimpleValueType VT; + std::vector OpDataTypes; + + if (!Op->getValue("RegTypes") && Op->getValue("RegClass") && + OperandType == "CS_OP_REG") + Op = Op->getValueAsDef("RegClass"); + + if (!(Op->getValue("Type") || Op->getValue("RegTypes"))) + return "{ CS_DATA_TYPE_LAST }"; + + if (OperandType == "CS_OP_REG" && 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 OpEncoding; + 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(CodeGenInstruction const *CGI, + Record const *ComplexOp, StringRef const &ArgName, + bool IsOutOp, std::string const &Encoding, + std::vector &InsOps) { + DagInit *SubOps = ComplexOp->getValueAsDag("MIOperandInfo"); + + std::string const &ComplOperandType = getPrimaryCSOperandType(ComplexOp); + + 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 = getPrimaryCSOperandType(SubOp); + if (ComplOperandType == "CS_OP_MEM") + OperandType = ComplOperandType + " | " + SubOperandType; + 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, Encoding}); + } +} + +void printInsnOpMapEntry(CodeGenTarget const &Target, + std::unique_ptr const &MI, bool UseMI, + CodeGenInstruction const *CGI, + raw_string_ostream &InsnOpMap, unsigned InsnNum) { + 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; + // Interate 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); + + std::string const &Encoding = getCSOperandEncoding(CGI, Rec, ArgName); + + // Add complex operands. + // Operands which effectively consists of two or more operands. + if (Rec->getValue("MIOperandInfo")) { + if (Rec->getValueAsDag("MIOperandInfo")->getNumArgs() > 0) { + addComplexOperand(CGI, Rec, ArgName, IsOutOp, Encoding, InsOps); + continue; + } + } + + // Determine Operand type + std::string OperandType = getCSOperandType(Rec); + 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, + std::move(Encoding)}); + } + + 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.OpEncoding + << " }, /* " << 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 = MI->Mnemonic.str(); + 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", + }; + 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", + "ZPRasFPR_128"}; + + bool NoExceptions = false; + const std::set *Exc; + if (TargetName == "ARM") + Exc = &ARMExceptions; + else if (TargetName == "AArch64") + Exc = &AArch64Exceptions; + 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); + } +} + +} // 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 PPCFormatEnumStr; + 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 PPCFormatEnum(PPCFormatEnumStr); + emitDefaultSourceFileHeader(InsnMap); + emitDefaultSourceFileHeader(InsnOpMap); + emitDefaultSourceFileHeader(InsnNameMap); + emitDefaultSourceFileHeader(InsnEnum); + emitDefaultSourceFileHeader(FeatureEnum); + emitDefaultSourceFileHeader(FeatureNameArray); + emitDefaultSourceFileHeader(OpGroups); + emitDefaultSourceFileHeader(PPCFormatEnum); + + // 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; + + // 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); + printInsnMapEntry(Target.getName(), Info, MI, UseMI, CGI, InsnMap, InsnNum, + PPCFormatEnum); + + ++InsnNum; + } + + 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); + if (TName == "PPC") { + InsnMapFilename = "PPCGenCSInsnFormatsEnum.inc"; + writeFile(InsnMapFilename, PPCFormatEnumStr); + } +} + +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 tables + // Because the table has the type information for its fields, + // we have a chance to distinguish between Sys regs, imms and other alias. +} + +void PrinterCapstone::searchableTablesEmitGenericTable( + const GenericTable &Enum) const {} + +void PrinterCapstone::searchableTablesEmitIfdef(const std::string Guard, + StreamType ST) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST); + OutS << "#ifdef " << Guard << "\n"; +} + +void PrinterCapstone::searchableTablesEmitEndif(StreamType ST) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST); + OutS << "#endif\n\n"; +} + +void PrinterCapstone::searchableTablesEmitUndef( + std::string const &Guard) const { + raw_string_ostream &OutS = searchableTablesGetOS(ST_IMPL_OS); + 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 + "\", { " + 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..8aa66dfb6af4 --- /dev/null +++ b/llvm/utils/TableGen/PrinterLLVM.cpp @@ -0,0 +1,6418 @@ +//===------------ 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) const { + if (Begin) { + OS << "namespace " << Name; + std::string const Bracket = (Name == "" ? "{" : " {"); + if (Comment != "") + OS << Bracket << " // " << Comment << "\n"; + else + OS << Bracket << "\n\n"; + return; + } + + if (Name == "") { + OS << "} // end anonymous namespace\n\n"; + } else { + OS << "} // end namespace " << Name << "\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/MC/SubtargetFeature.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 \n"; + OS << '\n'; +} + +void PrinterLLVM::decoderEmitterEmitSourceFileHeader() const { + llvm::emitSourceFileHeader(" * " + TargetName + " Disassembler", OS); +} + +//------------------------- +// Backend: AsmWriter +//------------------------- + +void PrinterLLVM::asmWriterEmitSourceFileHeader() const { + emitSourceFileHeader("Assembly Writer Source Fragment", OS); +} + +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::subtargetEmitDFASubtargetInfoImpl( + std::string const &TargetName, std::string const &ClassName, + unsigned NumFeatures, unsigned NumProcs, bool SchedModelHasItin) const { + OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " + << "StringRef TuneCPU, StringRef FS)\n" + << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; + if (NumFeatures) + OS << "makeArrayRef(" << TargetName << "FeatureKV, " << NumFeatures + << "), "; + else + OS << "std::nullopt, "; + if (NumProcs) + OS << "makeArrayRef(" << TargetName << "SubTypeKV, " << NumProcs << "), "; + else + OS << "None, "; + OS << '\n'; + OS.indent(24); + OS << TargetName << "WriteProcResTable, " << TargetName + << "WriteLatencyTable, " << TargetName << "ReadAdvanceTable, "; + OS << '\n'; + OS.indent(24); + if (SchedModelHasItin) { + OS << TargetName << "Stages, " << TargetName << "OperandCycles, " + << TargetName << "ForwardingPaths"; + } else + OS << "nullptr, nullptr, nullptr"; + OS << ") {}\n\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::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( + 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::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"; +} + +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 = "AMFBS"; + 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) const { + OS << "#ifdef " << Guard << "\n"; +} + +void PrinterLLVM::searchableTablesEmitEndif(StreamType ST) const { + OS << "#endif\n\n"; +} + +void PrinterLLVM::searchableTablesEmitUndef(std::string const &Guard) const { + 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"; + } + } +} + +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..11b6166b45e4 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"; + PI.regInfoEmitRegUnitWeight(RegBank, ClassName, RegUnitsHaveUnitWeight); + PI.regInfoEmitGetNumRegPressureSets(ClassName, NumSets); + PI.regInfoEmitGetRegPressureTables(RegBank, ClassName, NumSets); - 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"; - - 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"; - } + PI.regInfoEmitInfoRegMapping(Namespace, maxLength, isCtor); } -// 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); -} - -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"; + PI.regInfoEmitLaneMaskComposeSeq(Sequences, SubReg2SequenceIndexMap, SubRegIndices); + PI.regInfoEmitComposeSubRegIdxLaneMask(ClName, SubRegIndices); + PI.regInfoEmitComposeSubRegIdxLaneMaskRev(ClName, SubRegIndices); - 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"; } // // 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[]"); + PI.regInfoEmitStrLiteralRegClasses(TargetName, RegClassStrings); - OS << "extern const MCRegisterClass " << TargetName - << "MCRegisterClasses[] = {\n"; + PI.regInfoEmitMCRegClassesTable(TargetName, RegisterClasses, RegClassStrings); - 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"; - - 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"; + PI.regInfoEmitMCRegInfoInit(TargetName, RegBank, Regs, RegisterClasses, SubRegIndices); - EmitRegMapping(OS, Regs, false); + EmitRegMapping(Regs, false); - OS << "}\n\n"; - - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_MC_DESC\n\n"; + 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); + PI.regInfoEmitSourceFileHeader("Target Register and Register Classes Information"); - OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; - OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; - - 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); + PI.regInfoEmitSubClassMaskTable(RegisterClasses, + SuperRegIdxLists, + SuperRegIdxSeqs, + SubRegIndices, + MaskBV); - // 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"; - } - - 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"; + PI.regInfoEmitExternTableDecl(TargetName); - EmitRegMappingTables(OS, Regs, true); + EmitRegMappingTables(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"; + PI.regInfoEmitRegClassInit(TargetName, + ClassName, + RegBank, + RegisterClasses, + Regs, + SubRegIndicesSize); - EmitRegMapping(OS, Regs, true); - - OS << "}\n\n"; + 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,47 @@ 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"; + PI.regInfoEmitRegMaskTable(CSRSet->getName().str(), Covered); } - 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"; - } - 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"; + PI.regInfoEmitGPRCheck(ClassName, RegCategories); + PI.regInfoEmitFixedRegCheck(ClassName, RegCategories); + PI.regInfoEmitArgRegCheck(ClassName, RegCategories); - 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"; + PI.regInfoEmitIsConstantPhysReg(Regs, ClassName); + PI.regInfoEmitGetRegMaskNames(CSRSets, ClassName); - 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.regInfoEmitGetFrameLowering(TargetName); - 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"; - - OS << "const " << TargetName << "FrameLowering *\n" << TargetName - << "GenRegisterInfo::getFrameLowering(const MachineFunction &MF) {\n" - << " return static_cast(\n" - << " MF.getSubtarget().getFrameLowering());\n" - << "}\n\n"; - - 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.regInfoEmitSourceFileHeader("Target Register Enum Values"); + 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 +758,81 @@ 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"); +namespace llvm { + +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; +} + +} // end namespace llvm 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..ac672cdcc8d8 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 @@ private: 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"; + 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 << " 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"; - } - } - - 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,52 @@ 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(Guard); } -static TableGen::Emitter::OptClass - X("gen-searchable-tables", "Generate generic binary-searchable table"); +namespace llvm { + +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; +} + +} // End llvm namespace. 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 @@ public: 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 @@ public: << "#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..fb8e17f401ff 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); + 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(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); + 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 @@ public: // // 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); + PI.subtargetFormItineraryOperandCycleString(ItinData, + ItinOperandCycleString, + NOperandCycles); - FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString, - 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 "; + PI.subtargetEmitReorderBufferSize(ReorderBufferSize); + PI.subtargetEmitMaxRetirePerCycle(MaxRetirePerCycle); } -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; -} - -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", ','); + 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", ','); - 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.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'; + PI.subtargetEmitSchedClassCase(VC, SC.Name); - 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.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,194 @@ 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"; +void SubtargetEmitter::emitGenMCSubtargetInfo() { + PI.emitNamespace(Target + "_MC", true); + PI.subtargetEmitResolveVariantSchedClassImplHdr(); + emitSchedModelHelpersImpl(/* OnlyExpandMCPredicates */ true); + PI.subtargetEmitResolveVariantSchedClassImplEnd(); + PI.emitNamespace(Target + "_MC", false); - 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); + 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); + emitGenMCSubtargetInfo(); - 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"; + PI.subtargetEmitMCSubtargetInfoImpl(Target, NumFeatures, NumProcs, SchedModels.hasItineraries()); - OS << "} // end namespace llvm\n\n"; + PI.emitNamespace("llvm", false); - OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_MC_DESC", false); - OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_TARGET_DESC", true); - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; - ParseFeaturesFunction(OS); + PI.subtargetEmitIncludeSTIDesc(); - OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; + ParseFeaturesFunction(); + + 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"; + PI.emitNamespace("llvm", true); + PI.subtargetEmitDFAPacketizerClass(TGT, Target, ClassName); - STIPredicateExpander PE(Target); - PE.setByRef(false); - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); + PI.subtargetEmitExpandedSTIPredsHeader(Target, SchedModels); + PI.subtargetEmitDFASubtargetInfoImpl(Target, ClassName, NumFeatures, NumProcs, + SchedModels.hasItineraries()); + PI.subtargetEmitDFAPacketizerClassEnd(); - OS << "};\n" - << "} // end namespace llvm\n\n"; + PI.emitNamespace("llvm", false); - OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_HEADER", false); - OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; - OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_CTOR", true); - 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.subtargetEmitSTICtor(); + PI.emitNamespace("llvm", true); + PI.subtargetEmitExternKVArrays(Target, SchedModels.hasItineraries()); - 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.subtargetEmitClassDefs(Target, + ClassName, + NumFeatures, + NumProcs, + SchedModels.hasItineraries()); - 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"; + EmitSchedModelHelpers(ClassName); + EmitHwModeCheck(ClassName); - EmitSchedModelHelpers(ClassName, OS); - EmitHwModeCheck(ClassName, OS); - emitGetMacroFusions(ClassName, OS); + PI.subtargetEmitGetMacroFusions(TGT, Target, ClassName); + PI.emitNamespace("llvm", false); - OS << "} // end namespace llvm\n\n"; + PI.emitIncludeToggle("GET_SUBTARGETINFO_CTOR", false); - OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; - - EmitMCInstrAnalysisPredicateFunctions(OS); + EmitMCInstrAnalysisPredicateFunctions(); } -static TableGen::Emitter::OptClass - X("gen-subtarget", "Generate subtarget enumerations"); +namespace llvm { + +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; +} + +} // end namespace llvm 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..2d1301a84dbd 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 @@ -67,7 +68,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); // Defined in DecoderEmitter.cpp void EmitDecoder(RecordKeeper &RK, raw_ostream &OS, - const std::string &PredicateNamespace); + CodeGenTarget &Target); } // namespace llvm