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
This commit is contained in:
Rot127 2022-10-28 01:12:10 -04:00 committed by Rot127
parent 7fd9979eb9
commit c0317ac800
53 changed files with 17898 additions and 6890 deletions

41
DeprecatedFeatures.md Normal file
View File

@ -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 `<ARCH>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 "<ARCH>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<DeprecatedFeature>`) added
to their `UnsupportedFeatures` list.

113
README.md
View File

@ -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/<ARCH>/`.
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).

View File

@ -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)]]

View File

@ -13,6 +13,7 @@
#ifndef LLVM_TABLEGEN_STRINGMATCHER_H
#define LLVM_TABLEGEN_STRINGMATCHER_H
#include "PrinterTypes.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <utility>
@ -35,18 +36,26 @@ private:
StringRef StrVariableName;
const std::vector<StringPair> &Matches;
raw_ostream &OS;
PrinterLanguage PL;
public:
StringMatcher(StringRef strVariableName,
const std::vector<StringPair> &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<StringPair> &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<const StringPair *> &Matches,
unsigned CharNo, unsigned IndentCount,
bool IgnoreDuplicates) const;
bool EmitStringMatcherForCharCPP(const std::vector<const StringPair *> &Matches,
unsigned CharNo, unsigned IndentCount,
bool IgnoreDuplicates) const;
};
} // end namespace llvm

View File

@ -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 <cctype>
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<unsigned> 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);

View File

@ -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)

View File

@ -6,7 +6,6 @@ add_llvm_component_library(LLVMTableGen
Parser.cpp
Record.cpp
SetTheory.cpp
StringMatcher.cpp
TableGenBackend.cpp
TableGenBackendSkeleton.cpp
TGLexer.cpp

View File

@ -669,6 +669,7 @@ class AIldr_ex_or_acq<bits<2> 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<bits<2> opcod, bits<2> opcod2, dag oops, dag iops, InstrItinClass itin,
string opc, string asm, list<dag> pattern>
@ -684,6 +685,7 @@ class AIstr_ex_or_rel<bits<2> 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<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
@ -695,6 +697,7 @@ class AIstrex<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
: AIstr_ex_or_rel<opcod, 0b11, oops, iops, itin, opc, asm, pattern> {
bits<4> Rd;
let Inst{15-12} = Rd;
let mayLoad = 1;
}
// Exclusive load/store instructions
@ -792,6 +795,8 @@ class AI2ldstidx<bit isLd, bit isByte, bit isPre, dag oops, dag iops,
let Inst{21} = isPre; // W bit
let Inst{20} = isLd; // L bit
let Inst{15-12} = Rt;
let mayLoad = isLd;
let mayStore = !eq(isLd, 0);
}
class AI2stridx_reg<bit isByte, bit isPre, dag oops, dag iops,
IndexMode im, Format f, InstrItinClass itin, string opc,
@ -809,6 +814,7 @@ class AI2stridx_reg<bit isByte, bit isPre, dag oops, dag iops,
let Inst{11-5} = offset{11-5};
let Inst{4} = 0;
let Inst{3-0} = offset{3-0};
let mayStore = 1;
}
class AI2stridx_imm<bit isByte, bit isPre, dag oops, dag iops,
@ -825,6 +831,7 @@ class AI2stridx_imm<bit isByte, bit isPre, dag oops, dag iops,
let Inst{23} = offset{12};
let Inst{19-16} = Rn;
let Inst{11-0} = offset{11-0};
let mayStore = 1;
}
@ -845,6 +852,7 @@ class AI2stridxT<bit isByte, bit isPre, dag oops, dag iops,
let Inst{23} = addr{12};
let Inst{19-16} = addr{17-14};
let Inst{11-0} = addr{11-0};
let mayStore = 1;
}
// addrmode3 instructions
@ -865,6 +873,8 @@ class AI3ld<bits<4> 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<bits<4> 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<bits<4> 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<bits<4> 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

View File

@ -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<bit load, bit Dbit, string asm, list<dag> 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"

View File

@ -6186,8 +6186,8 @@ class MVE_VLDRSTR_base<MVE_ldst_direction dir, bit U, bit P, bit W, bit opc,
let Inst{12} = opc;
let Inst{11-9} = 0b111;
let mayLoad = dir.load;
let mayStore = !eq(dir.load,0);
let mayLoad = !eq(dir, MVE_ld);
let mayStore = !eq(dir, MVE_st);
let hasSideEffects = 0;
let validForTailPredication = 1;
}

View File

@ -998,6 +998,7 @@ def VLD4q32oddPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD4u>, 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<InstrItinClass itin>
@ -1072,6 +1073,7 @@ def VLD1LNd32 : VLD1LN32<0b1000, {?,0,?,?}, "32", v2i32, load> {
def VLD1LNq8Pseudo : VLD1QLNPseudo<v16i8, extloadi8>;
def VLD1LNq16Pseudo : VLD1QLNPseudo<v8i16, extloadi16>;
def VLD1LNq32Pseudo : VLD1QLNPseudo<v4i32, load>;
} // mayLoad = 1
let Predicates = [HasNEON] in {
def : Pat<(vector_insert (v4f16 DPR:$src),
@ -1366,6 +1368,7 @@ def VLD4LNq32Pseudo_UPD : VLDQQQQLNWBPseudo<IIC_VLD4lnu>, Sched<[WriteVLD2]>;
} // mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1
let mayLoad = 1 in {
// VLD1DUP : Vector Load (single element to all lanes)
class VLD1DUP<bits<4> 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<bits<4> 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<IIC_VST4u>, 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<InstrItinClass itin>
@ -2182,6 +2189,7 @@ def VST1LNd32 : VST1LN<0b1000, {?,0,?,?}, "32", v2i32, store, extractelt,
def VST1LNq8Pseudo : VST1QLNPseudo<v16i8, truncstorei8, ARMvgetlaneu>;
def VST1LNq16Pseudo : VST1QLNPseudo<v8i16, truncstorei16, ARMvgetlaneu>;
def VST1LNq32Pseudo : VST1QLNPseudo<v4i32, store, extractelt>;
} // 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<bits<4> 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<v16i8, post_truncsti8, ARMvgetlaneu>;
def VST1LNq16Pseudo_UPD : VST1QLNWBPseudo<v8i16, post_truncsti16,ARMvgetlaneu>;
def VST1LNq32Pseudo_UPD : VST1QLNWBPseudo<v4i32, post_store, extractelt>;
} // 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",

View File

@ -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,

View File

@ -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<bits<2> 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<bits<2> bit54, dag oops, dag iops,
string opc, string asm, list<dag> pattern>
: Thumb2I<oops, iops, AddrModeNone, 4, NoItinerary, opc,
@ -1904,6 +1911,7 @@ def t2STLB : T2Istrrel<0b00, (outs), (ins rGPR:$Rt, addr_offset_none:$addr),
"stlb", "\t$Rt, $addr", []>;
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<bits<1> 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<bits<1> inst, string opc> : T2Ipc<(outs), (ins t2ldrlabel:$addr),
IIC_Preload, opc, "\t$addr",
[(ARMPreload (ARMWrapper tconstpool:$addr),
@ -2025,6 +2036,7 @@ class T2Iplpci<bits<1> 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<string asm, InstrItinClass itin,
InstrItinClass itin_upd, bit L_bit> {
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<bits<4> op31_28, bit load, bit Dbit, string asm, list<dag>
}
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]>;
}
}
//===----------------------------------------------------------------------===//

View File

@ -149,7 +149,7 @@ def fbits16 : Operand<i32> {
// 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<string asm, bit L_bit,
let Inst{24-23} = 0b01; // Increment After
let Inst{21} = 0; // No writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
}
def DIA_UPD :
AXDI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, dpr_reglist:$regs,
@ -243,6 +247,8 @@ multiclass vfp_ldst_mult<string asm, bit L_bit,
let Inst{24-23} = 0b01; // Increment After
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
}
def DDB_UPD :
AXDI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, dpr_reglist:$regs,
@ -252,6 +258,8 @@ multiclass vfp_ldst_mult<string asm, bit L_bit,
let Inst{24-23} = 0b10; // Decrement Before
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
}
// Single Precision
@ -262,6 +270,8 @@ multiclass vfp_ldst_mult<string asm, bit L_bit,
let Inst{24-23} = 0b01; // Increment After
let Inst{21} = 0; // No writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
// Some single precision VFP instructions may be executed on both NEON and
// VFP pipelines.
@ -275,6 +285,8 @@ multiclass vfp_ldst_mult<string asm, bit L_bit,
let Inst{24-23} = 0b01; // Increment After
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
// Some single precision VFP instructions may be executed on both NEON and
// VFP pipelines.
@ -288,6 +300,8 @@ multiclass vfp_ldst_mult<string asm, bit L_bit,
let Inst{24-23} = 0b10; // Decrement Before
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
let mayLoad = L_bit;
let mayStore = !if(L_bit, 0b0, 0b1);
// Some single precision VFP instructions may be executed on both NEON and
// VFP pipelines.

View File

@ -338,6 +338,11 @@ def FeaturePredictableSelectIsExpensive :
def FeatureFastMFLR : SubtargetFeature<"fast-MFLR", "HasFastMFLR", "true",
"MFLR is a fast instruction">;
#define CAPSTONE_DEPR_FEATURE
include "PPCDeprecated.td"
#define CAPSTONE_PS_FEATURE
include "PPCInstrPairedSingle.td"
// Since new processors generally contain a superset of features of those that
// came before them, the idea is to make implementations of new processors
// less error prone and easier to read.
@ -673,6 +678,9 @@ def : ProcessorModel<"ppc64", G5Model,
FeatureMFTB]>;
def : ProcessorModel<"ppc64le", P8Model, ProcessorFeatures.P8Features>;
#define CAPSTONE_PS_PROCESSOR
include "PPCInstrPairedSingle.td"
//===----------------------------------------------------------------------===//
// Calling Conventions
//===----------------------------------------------------------------------===//

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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),

View File

@ -2380,3 +2380,7 @@ class PPCPostRAExpPseudo<dag OOL, dag IOL, string asmstr, list<dag> pattern>
class PseudoXFormMemOp<dag OOL, dag IOL, string asmstr, list<dag> pattern>
: PPCPostRAExpPseudo<OOL, IOL, asmstr, pattern>, XFormMemOp;
#define CAPSTONE_PS_FORMATS
include "PPCInstrPairedSingle.td"
#define CAPSTONE_DEPR_FORMATS
include "PPCDeprecated.td"

View File

@ -694,39 +694,66 @@ def PDForm : ComplexPattern<iPTR, 2, "SelectPDForm", [], [SDNPWantParent]>;
//===----------------------------------------------------------------------===//
// 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"

View File

@ -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<iPTR> {
let ParserMatchClass = PPCDispRID12Operand;
let OperandType = "OPERAND_IMMEDIATE";
}
def memrid12 : Operand<iPTR> { // 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<bits<6> op, dag OOL, dag IOL, string asmstr,
InstrItinClass itin>
: I<op, OOL, IOL, asmstr, itin> {
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<bits<6> 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<bits<5> 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<bits<10> 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<bits<10> 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<bits<10> 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<bits<5> psxop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_x<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_x<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
isRecordForm;
}
}
// op FRT, FRA, FRB
class PSForm_x1<bits<5> psxop, dag OOL, dag IOL, string asmstr,
InstrItinClass itin>
: PSForm_x<psxop, OOL, IOL, asmstr, itin> {
let FRC = 0;
}
// op. FRT, FRA, FRB
multiclass PSForm_x1r<bits<5> psxop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_x1<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_x1<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
isRecordForm;
}
}
// op FRT, FRB
class PSForm_x2<bits<5> psxop, dag OOL, dag IOL, string asmstr,
InstrItinClass itin>
: PSForm_x<psxop, OOL, IOL, asmstr, itin> {
let FRA = 0;
let FRC = 0;
}
// op. FRT, FRB
multiclass PSForm_x2r<bits<5> psxop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_x2<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_x2<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
isRecordForm;
}
}
// op FRT, FRA, FRC
class PSForm_x3<bits<5> psxop, dag OOL, dag IOL, string asmstr,
InstrItinClass itin>
: PSForm_x<psxop, OOL, IOL, asmstr, itin> {
let FRB = 0;
}
// op. FRT, FRA, FRC
multiclass PSForm_x3r<bits<5> psxop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_x3<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_x3<psxop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
isRecordForm;
}
}
// op. FRT, FRA, FRB
multiclass PSForm_yr<bits<10> psyop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_y<psyop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_y<psyop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
isRecordForm;
}
}
// op FRT, FRA, FRB
class PSForm_y2<bits<10> psyop, dag OOL, dag IOL, string asmstr,
InstrItinClass itin>
: PSForm_y<psyop, OOL, IOL, asmstr, itin> {
let FRA = 0;
}
// op. FRT, FRB
multiclass PSForm_y2r<bits<10> psyop, dag OOL, dag IOL, string asmbase,
string asmstr, InstrItinClass itin> {
let BaseName = asmbase in {
def NAME : PSForm_y2<psyop, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin>;
let Defs = [CR1] in
def o : PSForm_y2<psyop, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin>,
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

View File

@ -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

View File

@ -803,6 +803,7 @@ def absdirectbrtarget : Operand<OtherVT> {
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<OtherVT> {
let EncoderMethod = "getAbsCondBrEncoding";
let DecoderMethod = "decodeCondBrTarget";
let ParserMatchClass = PPCCondBrAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
def calltarget : Operand<iPTR> {
let PrintMethod = "printBranchOperand";
@ -833,6 +835,7 @@ def abscalltarget : Operand<iPTR> {
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<iPTR> {
let ParserMatchClass = PPCDispRI34Operand;
let EncoderMethod = "getDispRI34Encoding";
let DecoderMethod = "decodeSImmOperand<34>";
let OperandType = "OPERAND_IMMEDIATE";
}
def dispRI34_pcrel : Operand<iPTR> {
let ParserMatchClass = PPCDispRI34Operand;
let EncoderMethod = "getDispRI34PCRelEncoding";
let DecoderMethod = "decodeSImmOperand<34>";
let OperandType = "OPERAND_IMMEDIATE";
}
def memri34 : Operand<iPTR> { // memri, imm is a 34-bit value.
let PrintMethod = "printMemRegImm34";
@ -893,6 +898,7 @@ def PPCDispRIOperand : AsmOperandClass {
def dispRI : Operand<iPTR> {
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<iPTR> {
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<iPTR> {
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<iPTR> {
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<iPTR> {
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<iPTR> {
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<iPTR> {
let ParserMatchClass = PPCDispSPE2Operand;
let DecoderMethod = "decodeDispSPE2Operand";
let EncoderMethod = "getDispSPE2Encoding";
let OperandType = "OPERAND_IMMEDIATE";
}
def memri : Operand<iPTR> {
@ -1123,3 +1135,6 @@ def PPCRegDMRpRCAsmOperand : AsmOperandClass {
def dmrp : RegisterOperand<DMRpRC> {
let ParserMatchClass = PPCRegDMRpRCAsmOperand;
}
#define CAPSTONE_DEPR_REGS
include "PPCDeprecated.td"

View File

@ -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 {

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -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 <cassert>
#include <cctype>
#include <forward_list>
#include <map>
#include <set>
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<Record *, LessRecordByID> 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<ClassInfo *> 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<const CodeGenInstruction*, const CodeGenInstAlias*> DefRec;
const CodeGenInstruction *getResultInst() const {
if (isa<const CodeGenInstruction *>(DefRec))
return cast<const CodeGenInstruction *>(DefRec);
return cast<const CodeGenInstAlias *>(DefRec)->ResultInst;
}
/// ResOperands - This is the operand list that should be built for the result
/// MCInst.
SmallVector<ResOperand, 8> 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<AsmOperand, 8> AsmOperands;
/// Predicates - The required subtarget features to match this instruction.
SmallVector<const SubtargetFeatureInfo *, 4> 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<const CodeGenInstAlias> 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<const CodeGenInstAlias *>(DefRec));
}
~MatchableInfo() {
delete dyn_cast_if_present<const CodeGenInstAlias *>(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<Record*> &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<ClassInfo> Classes;
/// The information on the matchables to match.
std::vector<std::unique_ptr<MatchableInfo>> Matchables;
/// Info for custom matching operands by user defined methods.
std::vector<OperandMatchEntry> OperandMatchInfo;
/// Map of Register records to their class information.
typedef std::map<Record *, ClassInfo *, LessRecordByID> RegisterClassesTy;
RegisterClassesTy RegisterClasses;
/// Map of Predicate records to their subtarget information.
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
/// Map of AsmOperandClass records to their class information.
std::map<Record *, ClassInfo *> AsmOperandClasses;
/// Map of RegisterClass records to their class information.
std::map<Record *, ClassInfo *> RegisterClassClasses;
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo *> 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<Record *> &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

View File

@ -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<const CodeGenInstruction *> NumberedInstructions;
std::vector<AsmWriterInst> 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<std::vector<std::string>> &TableDrivenOperandPrinters,
unsigned &BitsLeft, unsigned &AsmStrBits);
void EmitPrintInstruction(
raw_ostream &o,
std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
unsigned &BitsLeft, unsigned &AsmStrBits);
void EmitGetRegisterName(raw_ostream &o);
void EmitPrintAliasInstruction(raw_ostream &O);
void EmitInstructions(std::vector<AsmWriterInst> &Insts,
bool PassSubtarget);
void EmitGetRegisterName();
void EmitRegisterNameString(StringRef AltName,
const std::deque<CodeGenRegister> &Registers);
void EmitPrintAliasInstruction();
void FindUniqueOperandCommands(std::vector<std::string> &UOC,
std::vector<std::vector<unsigned>> &InstIdxs,
@ -84,30 +88,10 @@ private:
} // end anonymous namespace
static void PrintCases(std::vector<std::pair<std::string,
AsmWriterOperand>> &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<AsmWriterInst> &Insts,
raw_ostream &O, bool PassSubtarget) {
void AsmWriterEmitter::EmitInstructions(std::vector<AsmWriterInst> &Insts,
bool PassSubtarget) {
AsmWriterInst FirstInst = Insts.back();
Insts.pop_back();
@ -127,39 +111,11 @@ static void EmitInstructions(std::vector<AsmWriterInst> &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<std::pair<std::string, AsmWriterOperand>> 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<std::vector<std::string>> &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<const char *, uint64_t> "
<< 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<std::string> StringTable;
SequenceToOffsetTable<std::string> 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<std::vector<std::string>> &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<std::string> &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<CodeGenRegister> &Registers) {
SequenceToOffsetTable<std::string> StringTable;
void AsmWriterEmitter::EmitRegisterNameString(
StringRef AltName,
const std::deque<CodeGenRegister> &Registers) {
SequenceToOffsetTable<std::string> StringTable(PrinterLLVM::getLanguage());
SmallVector<std::string, 4> 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<PatternsForOpcode> 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<std::vector<std::string>> 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<AsmWriterEmitter>
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

View File

@ -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 <regex>
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)

View File

@ -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

View File

@ -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();
}

File diff suppressed because it is too large Load Diff

View File

@ -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._
<hr>
This generator will build the states for several instruction groups (the `uint8_t decoder<InstrGroup>[]` 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).

View File

@ -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 <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
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<EncodingField> 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<EncodingField>::const_iterator const_iterator;
const_iterator begin() const { return Fields.begin(); }
const_iterator end() const { return Fields.end(); }
};
typedef std::vector<uint8_t> DecoderTable;
typedef uint32_t DecoderFixup;
typedef std::vector<DecoderFixup> FixupList;
typedef std::vector<FixupList> FixupScopeList;
typedef SmallSetVector<CachedHashString, 16> PredicateSet;
typedef SmallSetVector<CachedHashString, 16> 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<bit_value_t> 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

View File

@ -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<const CodeGenInstruction*> numberedInstructions =
Target.getInstructionsByEnumValue();
ArrayRef<const CodeGenInstruction *> 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,

File diff suppressed because it is too large Load Diff

View File

@ -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 <cassert>
#include <cstdint>
#include <iterator>
#include <map>
#include <string>
#include <utility>
#include <vector>
typedef std::vector<std::string> OperandInfoTy;
typedef std::vector<OperandInfoTy> OperandInfoListTy;
typedef std::map<OperandInfoTy, unsigned> 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::map<unsigned, unsigned>,
std::vector<std::string>> OpNameMapTy;
typedef std::map<std::string, unsigned>::iterator StrUintMapIter;
#endif // LLVM_UTILS_TABLEGEN_INSTRINFOEMITTERTYPES_H

View File

@ -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);

View File

@ -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;

View File

@ -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<Record *>;
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <iterator>
#include <set>
#include <string>
#include <vector>
using namespace llvm;
// Compress the sub-reg index lists.
typedef std::vector<const CodeGenSubRegIndex *> IdxList;
// Keep track of sub-register names as well. These are not differentially
// encoded.
typedef SmallVector<const CodeGenSubRegIndex *, 4> 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<int16_t, 4> DiffVec;
typedef SmallVector<LaneBitmask, 4> MaskVec;
// The lists of sub-registers and super-registers go in the same array. That
// allows us to share suffixes.
typedef std::vector<const CodeGenRegister *> RegVec;
using DwarfRegNumsMapPair = std::pair<Record*, std::vector<int64_t>>;
using DwarfRegNumsVecTy = std::vector<DwarfRegNumsMapPair>;
#endif // LLVM_UTILS_TABLEGEN_REGISTERINFOEMITTERTYPES_H

View File

@ -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 <algorithm>
#include <set>
#include <string>
#include <vector>
#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<IntInit>(
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<StringRef, int64_t>;
std::string Name;
Record *Class = nullptr;
std::string PreprocessorGuard;
std::vector<std::unique_ptr<Entry>> Entries;
DenseMap<Record *, Entry *> 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<GenericField, 1> Fields;
bool EarlyOut = false;
};
struct GenericTable {
std::string Name;
ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
std::string PreprocessorGuard;
std::string CppTypeName;
SmallVector<GenericField, 2> Fields;
std::vector<Record *> Entries;
std::unique_ptr<SearchIndex> PrimaryKey;
SmallVector<std::unique_ptr<SearchIndex>, 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<std::unique_ptr<GenericEnum>> Enums;
DenseMap<Record *, GenericEnum *> EnumMap;
std::set<std::string> 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<Init *, int> SearchTableEntry;
enum TypeContext {
TypeInStaticStruct,
TypeInTempStruct,
TypeInArgument,
};
std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
Init *I) {
if (StringInit *SI = dyn_cast<StringInit>(I)) {
if (Field.IsCode || SI->hasCodeFormat())
return std::string(SI->getValue());
else
return SI->getAsString();
} else if (BitsInit *BI = dyn_cast<BitsInit>(I))
return "0x" + utohexstr(getAsInt(BI));
else if (BitInit *BI = dyn_cast<BitInit>(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<DefInit>(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<DefInit>(I))
return DI->getDef()->isSubClassOf("Intrinsic");
@ -144,52 +52,17 @@ private:
CodeGenIntrinsic &getIntrinsic(Init *I) {
std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
if (!Intr)
Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
Intr = std::make_unique<CodeGenIntrinsic>(dyn_cast<DefInit>(I)->getDef(),
std::vector<Record *>());
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<StringRecTy>(Field.RecType)) {
if (Ctx == TypeInStaticStruct)
return "const char *";
if (Ctx == TypeInTempStruct)
return "std::string";
return "StringRef";
} else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(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<BitRecTy>(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<StringRecTy>(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<Record *> IndexRowsStorage;
ArrayRef<Record *> 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<std::pair<Record *, unsigned>> 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<StringRecTy>(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<StringRecTy>(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<StringRecTy>(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<std::unique_ptr<GenericTable>, 4> Tables;
DenseMap<Record *, GenericTable *> 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<SearchableTableEmitter>
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.

View File

@ -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 <algorithm>
#include <set>
#include <string>
#include <vector>
using namespace llvm;
static inline int64_t getAsInt(Init *B) {
return cast<IntInit>(
B->convertInitializerTo(IntRecTy::get(B->getRecordKeeper())))
->getValue();
}
struct GenericEnum {
using Entry = std::pair<StringRef, int64_t>;
std::string Name;
Record *Class = nullptr;
std::string PreprocessorGuard;
std::vector<std::unique_ptr<Entry>> Entries;
DenseMap<Record *, Entry *> 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<GenericField, 1> Fields;
bool EarlyOut = false;
};
struct GenericTable {
std::string Name;
ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
std::string PreprocessorGuard;
std::string CppTypeName;
SmallVector<GenericField, 2> Fields;
std::vector<Record *> Entries;
std::unique_ptr<SearchIndex> PrimaryKey;
SmallVector<std::unique_ptr<SearchIndex>, 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

View File

@ -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 <algorithm>
@ -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) {

View File

@ -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 <cassert>
#include <map>
#include <string>
@ -49,6 +51,18 @@ FindFirstNonCommonLetter(const std::vector<const
bool StringMatcher::EmitStringMatcherForChar(
const std::vector<const StringPair *> &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<const StringPair *> &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;

File diff suppressed because it is too large Load Diff

View File

@ -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 <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <map>
#include <string>
#include <vector>
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<std::vector<MCSchedClassDesc>> ProcSchedClasses;
std::vector<MCWriteProcResEntry> WriteProcResources;
std::vector<MCWriteLatencyEntry> WriteLatencies;
std::vector<std::string> WriterNames;
std::vector<MCReadAdvanceEntry> 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

View File

@ -15,6 +15,7 @@
#ifndef LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H
#define LLVM_UTILS_TABLEGEN_TABLEGENBACKENDS_H
#include "CodeGenTarget.h"
#include <string>
// 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