aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartyn Capewell <martyn.capewell@arm.com>2019-01-17 15:07:28 +0000
committerJacob Bramley <jacob.bramley@arm.com>2019-01-17 16:31:52 +0000
commit91fea40cc9ac4ca26f5fd26e2393aafe383f66cd (patch)
treeb8e149f012e5289fe686fd474386a50ebb5c0107 /src
parent7fcd70d4afa05749967d54658fd1894e246f993e (diff)
Rewrite the AArch64 decoder using a tree structure.
The decode tree is now expressed using bit pattern strings and named nodes. On constructing a Decoder, this representation is compiled into array lookups for pointers to the next node in the graph, eventually reaching a visitor function. Change-Id: I7c4d312268964554e1acbb8ee265fb9b30a8a2f2
Diffstat (limited to 'src')
-rw-r--r--src/aarch64/decoder-aarch64.cc1259
-rw-r--r--src/aarch64/decoder-aarch64.h351
-rw-r--r--src/aarch64/decoder-constants-aarch64.h1387
-rw-r--r--src/aarch64/instructions-aarch64.h31
4 files changed, 2031 insertions, 997 deletions
diff --git a/src/aarch64/decoder-aarch64.cc b/src/aarch64/decoder-aarch64.cc
index a01890ce..756d9b06 100644
--- a/src/aarch64/decoder-aarch64.cc
+++ b/src/aarch64/decoder-aarch64.cc
@@ -1,4 +1,4 @@
-// Copyright 2014, VIXL authors
+// Copyright 2019, VIXL authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -24,106 +24,55 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <string>
+
#include "../globals-vixl.h"
#include "../utils-vixl.h"
#include "decoder-aarch64.h"
+#include "decoder-constants-aarch64.h"
namespace vixl {
namespace aarch64 {
-void Decoder::DecodeInstruction(const Instruction* instr) {
- if (instr->ExtractBits(28, 27) == 0) {
- VisitUnallocated(instr);
- } else {
- switch (instr->ExtractBits(27, 24)) {
- // 0: PC relative addressing.
- case 0x0:
- DecodePCRelAddressing(instr);
- break;
-
- // 1: Add/sub immediate.
- case 0x1:
- DecodeAddSubImmediate(instr);
- break;
-
- // A: Logical shifted register.
- // Add/sub with carry.
- // Conditional compare register.
- // Conditional compare immediate.
- // Conditional select.
- // Data processing 1 source.
- // Data processing 2 source.
- // B: Add/sub shifted register.
- // Add/sub extended register.
- // Data processing 3 source.
- case 0xA:
- case 0xB:
- DecodeDataProcessing(instr);
- break;
+void Decoder::Decode(const Instruction* instr) {
+ std::list<DecoderVisitor*>::iterator it;
+ for (it = visitors_.begin(); it != visitors_.end(); it++) {
+ VIXL_ASSERT((*it)->IsConstVisitor());
+ }
+ VIXL_ASSERT(compiled_decoder_root_ != NULL);
+ compiled_decoder_root_->Decode(instr);
+}
- // 2: Logical immediate.
- // Move wide immediate.
- case 0x2:
- DecodeLogical(instr);
- break;
+void Decoder::Decode(Instruction* instr) {
+ compiled_decoder_root_->Decode(const_cast<const Instruction*>(instr));
+}
- // 3: Bitfield.
- // Extract.
- case 0x3:
- DecodeBitfieldExtract(instr);
- break;
+void Decoder::AddDecodeNode(const DecodeNode& node) {
+ decode_nodes_.insert(std::make_pair(node.GetName(), node));
+}
- // 4: Unconditional branch immediate.
- // Exception generation.
- // Compare and branch immediate.
- // 5: Compare and branch immediate.
- // Conditional branch.
- // System.
- // 6,7: Unconditional branch.
- // Test and branch immediate.
- case 0x4:
- case 0x5:
- case 0x6:
- case 0x7:
- DecodeBranchSystemException(instr);
- break;
+DecodeNode* Decoder::GetDecodeNode(std::string name) {
+ if (decode_nodes_.count(name) != 1) {
+ std::string msg = "Can't find decode node " + name + ".\n";
+ VIXL_ABORT_WITH_MSG(msg.c_str());
+ }
+ return &decode_nodes_[name];
+}
- // 8,9: Load/store register pair post-index.
- // Load register literal.
- // Load/store register unscaled immediate.
- // Load/store register immediate post-index.
- // Load/store register immediate pre-index.
- // Load/store register offset.
- // Load/store exclusive.
- // C,D: Load/store register pair offset.
- // Load/store register pair pre-index.
- // Load/store register unsigned immediate.
- // Advanced SIMD.
- case 0x8:
- case 0x9:
- case 0xC:
- case 0xD:
- DecodeLoadStore(instr);
- break;
+void Decoder::ConstructDecodeGraph() {
+ // Add all of the decoding nodes to the Decoder.
+ for (unsigned i = 0; i < ArrayLength(kDecodeMapping); i++) {
+ AddDecodeNode(DecodeNode(kDecodeMapping[i], this));
+ }
- // E: FP fixed point conversion.
- // FP integer conversion.
- // FP data processing 1 source.
- // FP compare.
- // FP immediate.
- // FP data processing 2 source.
- // FP conditional compare.
- // FP conditional select.
- // Advanced SIMD.
- // F: FP data processing 3 source.
- // Advanced SIMD.
- case 0xE:
- case 0xF:
- DecodeFP(instr);
- break;
- }
+ // Add the visitor function wrapping nodes to the Decoder.
+ for (unsigned i = 0; i < ArrayLength(kVisitorNodes); i++) {
+ AddDecodeNode(DecodeNode(kVisitorNodes[i], this));
}
+
+ // Compile the graph from the root.
+ compiled_decoder_root_ = GetDecodeNode("Root")->Compile(this);
}
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
@@ -173,895 +122,347 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
visitors_.remove(visitor);
}
+#define DEFINE_VISITOR_CALLERS(A) \
+ void Decoder::Visit##A(const Instruction* instr) { \
+ VIXL_ASSERT(((A##FMask == 0) && (A##Fixed == 0)) || \
+ (instr->Mask(A##FMask) == A##Fixed)); \
+ std::list<DecoderVisitor*>::iterator it; \
+ for (it = visitors_.begin(); it != visitors_.end(); it++) { \
+ (*it)->Visit##A(instr); \
+ } \
+ }
+VISITOR_LIST(DEFINE_VISITOR_CALLERS)
+#undef DEFINE_VISITOR_CALLERS
+
+void DecodeNode::SetSampledBits(const uint8_t* bits, int bit_count) {
+ VIXL_ASSERT(!IsCompiled());
-void Decoder::DecodePCRelAddressing(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(27, 24) == 0x0);
- // We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
- // decode.
- VIXL_ASSERT(instr->ExtractBit(28) == 0x1);
- VisitPCRelAddressing(instr);
+ sampled_bits_.resize(bit_count);
+ for (int i = 0; i < bit_count; i++) {
+ sampled_bits_[i] = bits[i];
+ }
}
+std::vector<uint8_t> DecodeNode::GetSampledBits() const {
+ return sampled_bits_;
+}
-void Decoder::DecodeBranchSystemException(const Instruction* instr) {
- VIXL_ASSERT((instr->ExtractBits(27, 24) == 0x4) ||
- (instr->ExtractBits(27, 24) == 0x5) ||
- (instr->ExtractBits(27, 24) == 0x6) ||
- (instr->ExtractBits(27, 24) == 0x7));
+size_t DecodeNode::GetSampledBitsCount() const { return sampled_bits_.size(); }
- switch (instr->ExtractBits(31, 29)) {
- case 0:
- case 4: {
- VisitUnconditionalBranch(instr);
- break;
- }
- case 1:
- case 5: {
- if (instr->ExtractBit(25) == 0) {
- VisitCompareBranch(instr);
- } else {
- VisitTestBranch(instr);
- }
- break;
- }
- case 2: {
- if (instr->ExtractBit(25) == 0) {
- if ((instr->ExtractBit(24) == 0x1) ||
- (instr->Mask(0x01000010) == 0x00000010)) {
- VisitUnallocated(instr);
- } else {
- VisitConditionalBranch(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- break;
- }
- case 6: {
- if (instr->ExtractBit(25) == 0) {
- if (instr->ExtractBit(24) == 0) {
- if ((instr->ExtractBits(4, 2) != 0) ||
- (instr->Mask(0x00E0001D) == 0x00200001) ||
- (instr->Mask(0x00E0001D) == 0x00400001) ||
- (instr->Mask(0x00E0001E) == 0x00200002) ||
- (instr->Mask(0x00E0001E) == 0x00400002) ||
- (instr->Mask(0x00E0001C) == 0x00600000) ||
- (instr->Mask(0x00E0001C) == 0x00800000) ||
- (instr->Mask(0x00E0001F) == 0x00A00000) ||
- (instr->Mask(0x00C0001C) == 0x00C00000)) {
- VisitUnallocated(instr);
- } else {
- VisitException(instr);
- }
- } else {
- if (instr->ExtractBits(23, 22) == 0) {
- const Instr masked_003FF0E0 = instr->Mask(0x003FF0E0);
- if ((instr->ExtractBits(21, 19) == 0x4) ||
- (masked_003FF0E0 == 0x00033000) ||
- (masked_003FF0E0 == 0x003FF020) ||
- (masked_003FF0E0 == 0x003FF060) ||
- (masked_003FF0E0 == 0x003FF0E0) ||
- (instr->Mask(0x00388000) == 0x00008000) ||
- (instr->Mask(0x0038E000) == 0x00000000) ||
- (instr->Mask(0x0039E000) == 0x00002000) ||
- (instr->Mask(0x003AE000) == 0x00002000) ||
- (instr->Mask(0x003CE000) == 0x00042000) ||
- (instr->Mask(0x0038F000) == 0x00005000) ||
- (instr->Mask(0x0038E000) == 0x00006000)) {
- VisitUnallocated(instr);
- } else {
- VisitSystem(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- if (((instr->ExtractBit(24) == 0x1) &&
- (instr->ExtractBits(23, 21) > 0x1)) ||
- (instr->ExtractBits(20, 16) != 0x1F) ||
- (instr->ExtractBits(15, 10) == 0x1) ||
- (instr->ExtractBits(15, 10) > 0x3) ||
- (instr->ExtractBits(24, 21) == 0x3) ||
- (instr->ExtractBits(24, 22) == 0x3)) {
- VisitUnallocated(instr);
- } else {
- VisitUnconditionalBranchToRegister(instr);
- }
- }
- break;
- }
- case 3:
- case 7: {
- VisitUnallocated(instr);
- break;
- }
+void DecodeNode::AddPatterns(const DecodePattern* patterns) {
+ VIXL_ASSERT(!IsCompiled());
+ for (unsigned i = 0; i < kMaxDecodeMappings; i++) {
+ // Empty string indicates end of patterns.
+ if (patterns[i].pattern == NULL) break;
+ VIXL_ASSERT((strlen(patterns[i].pattern) == GetSampledBitsCount()) ||
+ (strcmp(patterns[i].pattern, "otherwise") == 0));
+ pattern_table_.push_back(patterns[i]);
}
}
-
-void Decoder::DecodeLoadStore(const Instruction* instr) {
- VIXL_ASSERT((instr->ExtractBits(27, 24) == 0x8) ||
- (instr->ExtractBits(27, 24) == 0x9) ||
- (instr->ExtractBits(27, 24) == 0xC) ||
- (instr->ExtractBits(27, 24) == 0xD));
- // TODO(all): rearrange the tree to integrate this branch.
- if ((instr->ExtractBit(28) == 0) && (instr->ExtractBit(29) == 0) &&
- (instr->ExtractBit(26) == 1)) {
- DecodeNEONLoadStore(instr);
- return;
+void DecodeNode::CompileNodeForBits(Decoder* decoder,
+ std::string name,
+ uint32_t bits) {
+ DecodeNode* n = decoder->GetDecodeNode(name);
+ VIXL_ASSERT(n != NULL);
+ if (!n->IsCompiled()) {
+ n->Compile(decoder);
}
+ VIXL_ASSERT(n->IsCompiled());
+ compiled_node_->SetNodeForBits(bits, n->GetCompiledNode());
+}
- if (instr->ExtractBit(24) == 0) {
- if (instr->ExtractBit(28) == 0) {
- if (instr->ExtractBit(29) == 0) {
- if (instr->ExtractBit(26) == 0) {
- VisitLoadStoreExclusive(instr);
- } else {
- VIXL_UNREACHABLE();
- }
- } else {
- if ((instr->ExtractBits(31, 30) == 0x3) ||
- (instr->Mask(0xC4400000) == 0x40000000)) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(23) == 0) {
- if (instr->Mask(0xC4400000) == 0xC0400000) {
- VisitUnallocated(instr);
- } else {
- VisitLoadStorePairNonTemporal(instr);
- }
- } else {
- VisitLoadStorePairPostIndex(instr);
- }
- }
- }
- } else {
- if (instr->ExtractBit(29) == 0) {
- if (instr->Mask(0xC4000000) == 0xC4000000) {
- VisitUnallocated(instr);
- } else {
- VisitLoadLiteral(instr);
- }
- } else {
- if ((instr->Mask(0x44800000) == 0x44800000) ||
- (instr->Mask(0x84800000) == 0x84800000)) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(21) == 0) {
- switch (instr->ExtractBits(11, 10)) {
- case 0: {
- VisitLoadStoreUnscaledOffset(instr);
- break;
- }
- case 1: {
- if (instr->Mask(0xC4C00000) == 0xC0800000) {
- VisitUnallocated(instr);
- } else {
- VisitLoadStorePostIndex(instr);
- }
- break;
- }
- case 2: {
- // TODO: VisitLoadStoreRegisterOffsetUnpriv.
- VisitUnimplemented(instr);
- break;
- }
- case 3: {
- if (instr->Mask(0xC4C00000) == 0xC0800000) {
- VisitUnallocated(instr);
- } else {
- VisitLoadStorePreIndex(instr);
- }
- break;
- }
- }
- } else {
- if (instr->ExtractBits(11, 10) == 0x2) {
- if (instr->ExtractBit(14) == 0) {
- VisitUnallocated(instr);
- } else {
- VisitLoadStoreRegisterOffset(instr);
- }
- } else {
- if (instr->ExtractBits(11, 10) == 0x0) {
- if (instr->ExtractBit(25) == 0) {
- if (instr->ExtractBit(26) == 0) {
- if ((instr->ExtractBit(15) == 1) &&
- ((instr->ExtractBits(14, 12) == 0x1) ||
- (instr->ExtractBit(13) == 1) ||
- (instr->ExtractBits(14, 12) == 0x5) ||
- ((instr->ExtractBits(14, 12) == 0x4) &&
- ((instr->ExtractBit(23) == 0) ||
- (instr->ExtractBits(23, 22) == 0x3))))) {
- VisitUnallocated(instr);
- } else {
- VisitAtomicMemory(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- } else {
- if (instr->ExtractBit(25) == 0) {
- if (instr->ExtractBit(26) == 0) {
- if (instr->ExtractBits(31, 30) == 0x3) {
- VisitLoadStorePAC(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- }
- }
- }
- }
- }
- } else {
- if (instr->ExtractBit(28) == 0) {
- if (instr->ExtractBit(29) == 0) {
- VisitUnallocated(instr);
- } else {
- if ((instr->ExtractBits(31, 30) == 0x3) ||
- (instr->Mask(0xC4400000) == 0x40000000)) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(23) == 0) {
- VisitLoadStorePairOffset(instr);
- } else {
- VisitLoadStorePairPreIndex(instr);
- }
- }
- }
- } else {
- if (instr->ExtractBit(29) == 0) {
- if ((instr->ExtractBit(26) == 0) && (instr->ExtractBit(21) == 0) &&
- (instr->ExtractBits(11, 10) == 0x0) &&
- ((instr->ExtractBits(31, 30) < 0x2) ||
- ((instr->ExtractBits(31, 30) == 0x2) &&
- (instr->ExtractBits(23, 22) != 0x3)) ||
- ((instr->ExtractBits(31, 30) == 0x3) &&
- (instr->ExtractBits(23, 22) < 0x2)))) {
- VisitLoadStoreRCpcUnscaledOffset(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- if ((instr->Mask(0x84C00000) == 0x80C00000) ||
- (instr->Mask(0x44800000) == 0x44800000) ||
- (instr->Mask(0x84800000) == 0x84800000)) {
- VisitUnallocated(instr);
- } else {
- VisitLoadStoreUnsignedOffset(instr);
- }
- }
- }
+BitExtractFn DecodeNode::GetBitExtractFunction(uint32_t mask) {
+ // Instantiate a templated bit extraction function for every pattern we
+ // might encounter. If the assertion in the default clause is reached, add a
+ // new instantiation below using the information in the failure message.
+ BitExtractFn bit_extract_fn = NULL;
+ switch (mask) {
+#define INSTANTIATE_TEMPLATE(M) \
+ case M: \
+ bit_extract_fn = &Instruction::ExtractBits<M>; \
+ break;
+ INSTANTIATE_TEMPLATE(0x00000800);
+ INSTANTIATE_TEMPLATE(0x00000c00);
+ INSTANTIATE_TEMPLATE(0x00001c00);
+ INSTANTIATE_TEMPLATE(0x00004000);
+ INSTANTIATE_TEMPLATE(0x00008000);
+ INSTANTIATE_TEMPLATE(0x0000f000);
+ INSTANTIATE_TEMPLATE(0x0000fc00);
+ INSTANTIATE_TEMPLATE(0x001f0000);
+ INSTANTIATE_TEMPLATE(0x0020fc00);
+ INSTANTIATE_TEMPLATE(0x0038f000);
+ INSTANTIATE_TEMPLATE(0x00400000);
+ INSTANTIATE_TEMPLATE(0x0040f000);
+ INSTANTIATE_TEMPLATE(0x00800000);
+ INSTANTIATE_TEMPLATE(0x00c00000);
+ INSTANTIATE_TEMPLATE(0x00c78000);
+ INSTANTIATE_TEMPLATE(0x00db0000);
+ INSTANTIATE_TEMPLATE(0x00e00003);
+ INSTANTIATE_TEMPLATE(0x00f80400);
+ INSTANTIATE_TEMPLATE(0x01e00000);
+ INSTANTIATE_TEMPLATE(0x03800000);
+ INSTANTIATE_TEMPLATE(0x04c0f000);
+ INSTANTIATE_TEMPLATE(0x10800400);
+ INSTANTIATE_TEMPLATE(0x1e000000);
+ INSTANTIATE_TEMPLATE(0x20000000);
+ INSTANTIATE_TEMPLATE(0x20000410);
+ INSTANTIATE_TEMPLATE(0x20007000);
+ INSTANTIATE_TEMPLATE(0x20007800);
+ INSTANTIATE_TEMPLATE(0x2000f000);
+ INSTANTIATE_TEMPLATE(0x2000f800);
+ INSTANTIATE_TEMPLATE(0x201e0c00);
+ INSTANTIATE_TEMPLATE(0x20803800);
+ INSTANTIATE_TEMPLATE(0x20c0cc00);
+ INSTANTIATE_TEMPLATE(0x20c0f000);
+ INSTANTIATE_TEMPLATE(0x20c0f800);
+ INSTANTIATE_TEMPLATE(0x20c1f000);
+ INSTANTIATE_TEMPLATE(0x51e00000);
+ INSTANTIATE_TEMPLATE(0x60007800);
+ INSTANTIATE_TEMPLATE(0x6000f800);
+ INSTANTIATE_TEMPLATE(0x601e0000);
+ INSTANTIATE_TEMPLATE(0x80007c00);
+ INSTANTIATE_TEMPLATE(0x80017c00);
+ INSTANTIATE_TEMPLATE(0x80408000);
+ INSTANTIATE_TEMPLATE(0x80a07c00);
+ INSTANTIATE_TEMPLATE(0x80df0000);
+ INSTANTIATE_TEMPLATE(0x80e08000);
+ INSTANTIATE_TEMPLATE(0xa0c00000);
+ INSTANTIATE_TEMPLATE(0xb5a00000);
+ INSTANTIATE_TEMPLATE(0xc0c00c00);
+ INSTANTIATE_TEMPLATE(0xc4400000);
+ INSTANTIATE_TEMPLATE(0xc4c00000);
+ INSTANTIATE_TEMPLATE(0xe3c00000);
+ INSTANTIATE_TEMPLATE(0xf1200000);
+#undef INSTANTIATE_TEMPLATE
+ default:
+ printf("Node %s: No template instantiated for extracting 0x%08x.\n",
+ GetName().c_str(),
+ GenerateSampledBitsMask());
+ printf("Add one in %s above line %d:\n", __FILE__, __LINE__);
+ printf(" INSTANTIATE_TEMPLATE(0x%08x);\n", GenerateSampledBitsMask());
+ VIXL_UNREACHABLE();
}
+ return bit_extract_fn;
}
-
-void Decoder::DecodeLogical(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(27, 24) == 0x2);
-
- if (instr->Mask(0x80400000) == 0x00400000) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(23) == 0) {
- VisitLogicalImmediate(instr);
- } else {
- if (instr->ExtractBits(30, 29) == 0x1) {
- VisitUnallocated(instr);
- } else {
- VisitMoveWideImmediate(instr);
- }
- }
+BitExtractFn DecodeNode::GetBitExtractFunction(uint32_t mask, uint32_t value) {
+ // Instantiate a templated bit extraction function for every pattern we
+ // might encounter. If the assertion in the following check fails, add a
+ // new instantiation below using the information in the failure message.
+ bool instantiated = false;
+ BitExtractFn bit_extract_fn = NULL;
+#define INSTANTIATE_TEMPLATE(M, V) \
+ if ((mask == M) && (value == V)) { \
+ bit_extract_fn = &Instruction::IsMaskedValue<M, V>; \
+ instantiated = true; \
}
+ INSTANTIATE_TEMPLATE(0x0000001c, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x00003000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x00007800, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x0000f000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x0003801f, 0x0000000d);
+ INSTANTIATE_TEMPLATE(0x000f0000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x001f0000, 0x001f0000);
+ INSTANTIATE_TEMPLATE(0x0038e000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x0039e000, 0x00002000);
+ INSTANTIATE_TEMPLATE(0x003ae000, 0x00002000);
+ INSTANTIATE_TEMPLATE(0x003ce000, 0x00042000);
+ INSTANTIATE_TEMPLATE(0x00780000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x00c00000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x00c00000, 0x00800000);
+ INSTANTIATE_TEMPLATE(0x00c00000, 0x00c00000);
+ INSTANTIATE_TEMPLATE(0x01000010, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x20000800, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x20008000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x20040000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x201e8000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x60000000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x60000000, 0x20000000);
+ INSTANTIATE_TEMPLATE(0x60000000, 0x60000000);
+ INSTANTIATE_TEMPLATE(0x60200000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x80008000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0x80008000, 0x00008000);
+ INSTANTIATE_TEMPLATE(0x80400000, 0x00400000);
+ INSTANTIATE_TEMPLATE(0xa00003e0, 0x00000000);
+ INSTANTIATE_TEMPLATE(0xa000c007, 0x00000000);
+ INSTANTIATE_TEMPLATE(0xa0180000, 0x00000000);
+ INSTANTIATE_TEMPLATE(0xc4000000, 0xc0000000);
+ INSTANTIATE_TEMPLATE(0xc4000000, 0xc4000000);
+ INSTANTIATE_TEMPLATE(0xe0000010, 0xa0000000);
+ INSTANTIATE_TEMPLATE(0xe01c0000, 0x20000000);
+#undef INSTANTIATE_TEMPLATE
+
+ if (!instantiated) {
+ printf(
+ "Node %s: no template instantiated for mask 0x%08x, value = "
+ "0x%08x.\n",
+ GetName().c_str(),
+ mask,
+ value);
+ printf("Add one in %s above line %d:\n", __FILE__, __LINE__);
+ printf(" INSTANTIATE_TEMPLATE(0x%08x, 0x%08x);\n", mask, value);
+ VIXL_UNREACHABLE();
+ }
+ return bit_extract_fn;
}
+bool DecodeNode::TryCompileOptimisedDecodeTable(Decoder* decoder) {
+ // EitherOr optimisation: if there are only one or two patterns in the table,
+ // try to optimise the node to exploit that.
+ if ((pattern_table_.size() == 2) && (GetSampledBitsCount() > 1)) {
+ // TODO: support 'x' in this optimisation by dropping the sampled bit
+ // positions before making the mask/value.
+ if ((strchr(pattern_table_[0].pattern, 'x') == NULL) &&
+ (strcmp(pattern_table_[1].pattern, "otherwise") == 0)) {
+ // A pattern table consisting of a fixed pattern with no x's, and an
+ // "otherwise" case. Optimise this into an instruction mask and value
+ // test.
+ uint32_t single_decode_mask = 0;
+ uint32_t single_decode_value = 0;
+ std::vector<uint8_t> bits = GetSampledBits();
+
+ // Construct the instruction mask and value from the pattern.
+ VIXL_ASSERT(bits.size() == strlen(pattern_table_[0].pattern));
+ for (size_t i = 0; i < bits.size(); i++) {
+ single_decode_mask |= 1U << bits[i];
+ if (pattern_table_[0].pattern[i] == '1') {
+ single_decode_value |= 1U << bits[i];
+ }
+ }
-void Decoder::DecodeBitfieldExtract(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(27, 24) == 0x3);
+ BitExtractFn bit_extract_fn =
+ GetBitExtractFunction(single_decode_mask, single_decode_value);
- if ((instr->Mask(0x80400000) == 0x80000000) ||
- (instr->Mask(0x80400000) == 0x00400000) ||
- (instr->Mask(0x80008000) == 0x00008000)) {
- VisitUnallocated(instr);
- } else if (instr->ExtractBit(23) == 0) {
- if ((instr->Mask(0x80200000) == 0x00200000) ||
- (instr->Mask(0x60000000) == 0x60000000)) {
- VisitUnallocated(instr);
- } else {
- VisitBitfield(instr);
- }
- } else {
- if ((instr->Mask(0x60200000) == 0x00200000) ||
- (instr->Mask(0x60000000) != 0x00000000)) {
- VisitUnallocated(instr);
- } else {
- VisitExtract(instr);
- }
- }
-}
+ // Create a compiled node that contains a two entry table for the
+ // either/or cases.
+ CreateCompiledNode(bit_extract_fn, 2);
+ // Set DecodeNode for when the instruction after masking doesn't match the
+ // value.
+ CompileNodeForBits(decoder, pattern_table_[1].handler, 0);
-void Decoder::DecodeAddSubImmediate(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(27, 24) == 0x1);
- if (instr->ExtractBit(23) == 1) {
- VisitUnallocated(instr);
- } else {
- VisitAddSubImmediate(instr);
+ // Set DecodeNode for when it does match.
+ CompileNodeForBits(decoder, pattern_table_[0].handler, 1);
+
+ return true;
+ }
}
+ return false;
}
-
-void Decoder::DecodeDataProcessing(const Instruction* instr) {
- VIXL_ASSERT((instr->ExtractBits(27, 24) == 0xA) ||
- (instr->ExtractBits(27, 24) == 0xB));
-
- if (instr->ExtractBit(24) == 0) {
- if (instr->ExtractBit(28) == 0) {
- if (instr->Mask(0x80008000) == 0x00008000) {
- VisitUnallocated(instr);
+CompiledDecodeNode* DecodeNode::Compile(Decoder* decoder) {
+ if (IsLeafNode()) {
+ // A leaf node is a simple wrapper around a visitor function, with no
+ // instruction decoding to do.
+ CreateVisitorNode();
+ } else if (!TryCompileOptimisedDecodeTable(decoder)) {
+ // The "otherwise" node is the default next node if no pattern matches.
+ std::string otherwise = "VisitUnallocated";
+
+ // For each pattern in pattern_table_, create an entry in matches that
+ // has a corresponding mask and value for the pattern.
+ std::vector<MaskValuePair> matches;
+ for (size_t i = 0; i < pattern_table_.size(); i++) {
+ if (strcmp(pattern_table_[i].pattern, "otherwise") == 0) {
+ // "otherwise" must be the last pattern in the list, otherwise the
+ // indices won't match for pattern_table_ and matches.
+ VIXL_ASSERT(i == pattern_table_.size() - 1);
+ otherwise = pattern_table_[i].handler;
} else {
- VisitLogicalShifted(instr);
- }
- } else {
- switch (instr->ExtractBits(23, 21)) {
- case 0: {
- if (instr->ExtractBits(15, 10) != 0) {
- if (instr->ExtractBits(14, 10) == 0x1) {
- if (instr->Mask(0xE0000010) == 0xA0000000) {
- VisitRotateRightIntoFlags(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- if (instr->ExtractBits(13, 10) == 0x2) {
- if (instr->Mask(0xE01F801F) == 0x2000000D) {
- VisitEvaluateIntoFlags(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- VisitAddSubWithCarry(instr);
- }
- break;
- }
- case 2: {
- if ((instr->ExtractBit(29) == 0) || (instr->Mask(0x00000410) != 0)) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(11) == 0) {
- VisitConditionalCompareRegister(instr);
- } else {
- VisitConditionalCompareImmediate(instr);
- }
- }
- break;
- }
- case 4: {
- if (instr->Mask(0x20000800) != 0x00000000) {
- VisitUnallocated(instr);
- } else {
- VisitConditionalSelect(instr);
- }
- break;
- }
- case 6: {
- if (instr->ExtractBit(29) == 0x1) {
- VisitUnallocated(instr);
- VIXL_FALLTHROUGH();
- } else {
- if (instr->ExtractBit(30) == 0) {
- if ((instr->ExtractBit(15) == 0x1) ||
- (instr->ExtractBits(15, 11) == 0) ||
- (instr->ExtractBits(15, 12) == 0x1) ||
- ((instr->ExtractBits(15, 12) == 0x3) &&
- (instr->ExtractBit(31) == 0)) ||
- (instr->ExtractBits(15, 13) == 0x3) ||
- (instr->Mask(0x8000EC00) == 0x00004C00) ||
- (instr->Mask(0x8000E800) == 0x80004000) ||
- (instr->Mask(0x8000E400) == 0x80004000)) {
- VisitUnallocated(instr);
- } else {
- VisitDataProcessing2Source(instr);
- }
- } else {
- if ((instr->ExtractBits(20, 17) != 0) ||
- (instr->ExtractBit(15) == 1) ||
- ((instr->ExtractBit(16) == 1) &&
- ((instr->ExtractBits(14, 10) > 17) ||
- (instr->ExtractBit(31) == 0))) ||
- ((instr->ExtractBit(16) == 0) &&
- ((instr->ExtractBits(14, 13) != 0) ||
- (instr->Mask(0xA01FFC00) == 0x00000C00) ||
- (instr->Mask(0x201FF800) == 0x00001800)))) {
- VisitUnallocated(instr);
- } else {
- VisitDataProcessing1Source(instr);
- }
- }
- break;
- }
- }
- case 1:
- case 3:
- case 5:
- case 7:
- VisitUnallocated(instr);
- break;
+ matches.push_back(GenerateMaskValuePair(
+ GenerateOrderedPattern(pattern_table_[i].pattern)));
}
}
- } else {
- if (instr->ExtractBit(28) == 0) {
- if (instr->ExtractBit(21) == 0) {
- if ((instr->ExtractBits(23, 22) == 0x3) ||
- (instr->Mask(0x80008000) == 0x00008000)) {
- VisitUnallocated(instr);
- } else {
- VisitAddSubShifted(instr);
- }
- } else {
- if ((instr->Mask(0x00C00000) != 0x00000000) ||
- (instr->Mask(0x00001400) == 0x00001400) ||
- (instr->Mask(0x00001800) == 0x00001800)) {
- VisitUnallocated(instr);
- } else {
- VisitAddSubExtended(instr);
+
+ BitExtractFn bit_extract_fn =
+ GetBitExtractFunction(GenerateSampledBitsMask());
+
+ // Create a compiled node that contains a table with an entry for every bit
+ // pattern.
+ CreateCompiledNode(bit_extract_fn, 1U << GetSampledBitsCount());
+ VIXL_ASSERT(compiled_node_ != NULL);
+
+ // When we find a pattern matches the representation, set the node's decode
+ // function for that representation to the corresponding function.
+ for (uint32_t bits = 0; bits < (1U << GetSampledBitsCount()); bits++) {
+ for (size_t i = 0; i < matches.size(); i++) {
+ if ((bits & matches[i].first) == matches[i].second) {
+ // Only one instruction class should match for each value of bits, so
+ // if we get here, the node pointed to should still be unallocated.
+ VIXL_ASSERT(compiled_node_->GetNodeForBits(bits) == NULL);
+ CompileNodeForBits(decoder, pattern_table_[i].handler, bits);
+ break;
}
}
- } else {
- if ((instr->ExtractBit(30) == 0x1) ||
- (instr->ExtractBits(30, 29) == 0x1) ||
- (instr->Mask(0xE0600000) == 0x00200000) ||
- (instr->Mask(0xE0608000) == 0x00400000) ||
- (instr->Mask(0x60608000) == 0x00408000) ||
- (instr->Mask(0x60E00000) == 0x00E00000) ||
- (instr->Mask(0x60E00000) == 0x00800000) ||
- (instr->Mask(0x60E00000) == 0x00600000)) {
- VisitUnallocated(instr);
- } else {
- VisitDataProcessing3Source(instr);
+
+ // If the decode_table_ entry for these bits is still NULL, the
+ // instruction must be handled by the "otherwise" case, which by default
+ // is the Unallocated visitor.
+ if (compiled_node_->GetNodeForBits(bits) == NULL) {
+ CompileNodeForBits(decoder, otherwise, bits);
}
}
}
-}
+ VIXL_ASSERT(compiled_node_ != NULL);
+ return compiled_node_;
+}
-void Decoder::DecodeFP(const Instruction* instr) {
- VIXL_ASSERT((instr->ExtractBits(27, 24) == 0xE) ||
- (instr->ExtractBits(27, 24) == 0xF));
- if (instr->ExtractBit(28) == 0) {
- DecodeNEONVectorDataProcessing(instr);
+void CompiledDecodeNode::Decode(const Instruction* instr) const {
+ if (IsLeafNode()) {
+ // If this node is a leaf, call the registered visitor function.
+ VIXL_ASSERT(decoder_ != NULL);
+ (decoder_->*visitor_fn_)(instr);
} else {
- if (instr->ExtractBits(31, 30) == 0x3) {
- VisitUnallocated(instr);
- } else if (instr->ExtractBits(31, 30) == 0x1) {
- DecodeNEONScalarDataProcessing(instr);
- } else {
- if (instr->ExtractBit(29) == 0) {
- if (instr->ExtractBit(24) == 0) {
- if (instr->ExtractBit(21) == 0) {
- if ((instr->ExtractBits(23, 22) == 0x2) ||
- (instr->ExtractBit(18) == 1) ||
- (instr->Mask(0x80008000) == 0x00000000) ||
- (instr->Mask(0x000E0000) == 0x00000000) ||
- (instr->Mask(0x000E0000) == 0x000A0000) ||
- (instr->Mask(0x00160000) == 0x00000000) ||
- (instr->Mask(0x00160000) == 0x00120000)) {
- VisitUnallocated(instr);
- } else {
- VisitFPFixedPointConvert(instr);
- }
- } else {
- if (instr->ExtractBits(15, 10) == 32) {
- VisitUnallocated(instr);
- } else if (instr->ExtractBits(15, 10) == 0) {
- if ((instr->Mask(0x000E0000) == 0x000A0000) ||
- (instr->Mask(0x000E0000) == 0x000C0000) ||
- (instr->Mask(0x00160000) == 0x00120000) ||
- (instr->Mask(0x00160000) == 0x00140000) ||
- (instr->Mask(0x20C40000) == 0x00800000) ||
- (instr->Mask(0x20C60000) == 0x00840000) ||
- (instr->Mask(0xA0C60000) == 0x80060000) ||
- (instr->Mask(0xA0C60000) == 0x00860000) ||
- (instr->Mask(0xA0CE0000) == 0x80860000) ||
- (instr->Mask(0xA0CE0000) == 0x804E0000) ||
- (instr->Mask(0xA0CE0000) == 0x000E0000) ||
- (instr->Mask(0xA0D60000) == 0x00160000) ||
- (instr->Mask(0xA0D60000) == 0x80560000) ||
- (instr->Mask(0xA0D60000) == 0x80960000)) {
- VisitUnallocated(instr);
- } else {
- VisitFPIntegerConvert(instr);
- }
- } else if (instr->ExtractBits(14, 10) == 16) {
- const Instr masked_A0DF8000 = instr->Mask(0xA0DF8000);
- if ((instr->Mask(0x80180000) != 0) ||
- (masked_A0DF8000 == 0x00020000) ||
- (masked_A0DF8000 == 0x00030000) ||
- (masked_A0DF8000 == 0x00068000) ||
- (masked_A0DF8000 == 0x00428000) ||
- (masked_A0DF8000 == 0x00430000) ||
- (masked_A0DF8000 == 0x00468000) ||
- (instr->Mask(0xA0D80000) == 0x00800000) ||
- (instr->Mask(0xA0DF0000) == 0x00C30000) ||
- (instr->Mask(0xA0DF8000) == 0x00C68000)) {
- VisitUnallocated(instr);
- } else {
- VisitFPDataProcessing1Source(instr);
- }
- } else if (instr->ExtractBits(13, 10) == 8) {
- if ((instr->ExtractBits(15, 14) != 0) ||
- (instr->ExtractBits(2, 0) != 0) ||
- (instr->ExtractBit(31) == 1) ||
- (instr->ExtractBits(23, 22) == 0x2)) {
- VisitUnallocated(instr);
- } else {
- VisitFPCompare(instr);
- }
- } else if (instr->ExtractBits(12, 10) == 4) {
- if ((instr->ExtractBits(9, 5) != 0) ||
- // Valid enc: 01d, 00s, 11h.
- (instr->ExtractBits(23, 22) == 0x2) ||
- (instr->ExtractBit(31) == 1)) {
- VisitUnallocated(instr);
- } else {
- VisitFPImmediate(instr);
- }
- } else {
- if ((instr->ExtractBits(23, 22) == 0x2) ||
- (instr->ExtractBit(31) == 1)) {
- VisitUnallocated(instr);
- } else {
- switch (instr->ExtractBits(11, 10)) {
- case 1: {
- VisitFPConditionalCompare(instr);
- break;
- }
- case 2: {
- if (instr->ExtractBits(15, 12) > 0x8) {
- VisitUnallocated(instr);
- } else {
- VisitFPDataProcessing2Source(instr);
- }
- break;
- }
- case 3: {
- VisitFPConditionalSelect(instr);
- break;
- }
- default:
- VIXL_UNREACHABLE();
- }
- }
- }
- }
- } else {
- // Bit 30 == 1 has been handled earlier.
- VIXL_ASSERT(instr->ExtractBit(30) == 0);
- if ((instr->Mask(0xA0000000) != 0) ||
- (instr->ExtractBits(23, 22) == 0x2)) {
- VisitUnallocated(instr);
- } else {
- VisitFPDataProcessing3Source(instr);
- }
- }
- } else {
- VisitUnallocated(instr);
- }
- }
+ // Otherwise, using the sampled bit extractor for this node, look up the
+ // next node in the decode tree, and call its Decode method.
+ VIXL_ASSERT(bit_extract_fn_ != NULL);
+ VIXL_ASSERT((instr->*bit_extract_fn_)() < decode_table_size_);
+ VIXL_ASSERT(decode_table_[(instr->*bit_extract_fn_)()] != NULL);
+ decode_table_[(instr->*bit_extract_fn_)()]->Decode(instr);
}
}
-
-void Decoder::DecodeNEONLoadStore(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(29, 25) == 0x6);
- if (instr->ExtractBit(31) == 0) {
- if ((instr->ExtractBit(24) == 0) && (instr->ExtractBit(21) == 1)) {
- VisitUnallocated(instr);
- return;
- }
-
- if (instr->ExtractBit(23) == 0) {
- if (instr->ExtractBits(20, 16) == 0) {
- if (instr->ExtractBit(24) == 0) {
- VisitNEONLoadStoreMultiStruct(instr);
- } else {
- VisitNEONLoadStoreSingleStruct(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- } else {
- if (instr->ExtractBit(24) == 0) {
- VisitNEONLoadStoreMultiStructPostIndex(instr);
- } else {
- VisitNEONLoadStoreSingleStructPostIndex(instr);
- }
- }
- } else {
- VisitUnallocated(instr);
+DecodeNode::MaskValuePair DecodeNode::GenerateMaskValuePair(
+ std::string pattern) const {
+ uint32_t mask = 0, value = 0;
+ for (size_t i = 0; i < pattern.size(); i++) {
+ mask |= ((pattern[i] == 'x') ? 0 : 1) << i;
+ value |= ((pattern[i] == '1') ? 1 : 0) << i;
}
+ return std::make_pair(mask, value);
}
+std::string DecodeNode::GenerateOrderedPattern(std::string pattern) const {
+ std::vector<uint8_t> sampled_bits = GetSampledBits();
+ // Construct a temporary 32-character string containing '_', then at each
+ // sampled bit position, set the corresponding pattern character.
+ std::string temp(32, '_');
+ for (size_t i = 0; i < sampled_bits.size(); i++) {
+ temp[sampled_bits[i]] = pattern[i];
+ }
-void Decoder::DecodeNEONVectorDataProcessing(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(28, 25) == 0x7);
- if (instr->ExtractBit(31) == 0) {
- if (instr->ExtractBit(24) == 0) {
- if (instr->ExtractBit(21) == 0) {
- if (instr->ExtractBit(15) == 0) {
- if (instr->ExtractBit(10) == 0) {
- if (instr->ExtractBit(29) == 0) {
- if (instr->ExtractBit(11) == 0) {
- VisitNEONTable(instr);
- } else {
- VisitNEONPerm(instr);
- }
- } else {
- VisitNEONExtract(instr);
- }
- } else {
- if (instr->ExtractBits(23, 22) == 0) {
- VisitNEONCopy(instr);
- } else if (instr->ExtractBit(14) == 0x0 &&
- instr->ExtractBit(22) == 0x1) {
- // U + a + opcode.
- uint8_t decode_field =
- (instr->ExtractBit(29) << 1) | instr->ExtractBit(23);
- decode_field = (decode_field << 3) | instr->ExtractBits(13, 11);
- switch (decode_field) {
- case 0x5:
- case 0xB:
- case 0xC:
- case 0xD:
- case 0x11:
- case 0x19:
- case 0x1B:
- case 0x1F:
- VisitUnallocated(instr);
- break;
- default:
- VisitNEON3SameFP16(instr);
- break;
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- } else if (instr->ExtractBit(10) == 0) {
- VisitUnallocated(instr);
- } else if ((instr->ExtractBits(14, 11) == 0x3) ||
- (instr->ExtractBits(14, 13) == 0x1)) {
- // opcode = 0b0011
- // opcode = 0b01xx
- VisitUnallocated(instr);
- } else if (instr->ExtractBit(29) == 0) {
- // U == 0
- if (instr->ExtractBits(14, 11) == 0x2) {
- // opcode = 0b0010
- VisitNEON3SameExtra(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- // U == 1
- if ((instr->ExtractBits(14, 11) == 0xd) ||
- (instr->ExtractBits(14, 11) == 0xf)) {
- // opcode = 0b11x1
- VisitUnallocated(instr);
- } else {
- VisitNEON3SameExtra(instr);
- }
- }
- } else {
- if (instr->ExtractBit(10) == 0) {
- if (instr->ExtractBit(11) == 0) {
- VisitNEON3Different(instr);
- } else {
- if (instr->ExtractBits(18, 17) == 0) {
- if (instr->ExtractBit(20) == 0) {
- if (instr->ExtractBit(19) == 0) {
- VisitNEON2RegMisc(instr);
- } else {
- if (instr->ExtractBits(30, 29) == 0x2) {
- VisitCryptoAES(instr);
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- if (instr->ExtractBit(19) == 0) {
- VisitNEONAcrossLanes(instr);
- } else {
- if (instr->ExtractBit(22) == 0) {
- VisitUnallocated(instr);
- } else {
- if ((instr->ExtractBits(16, 15) == 0x0) ||
- (instr->ExtractBits(16, 14) == 0x2) ||
- (instr->ExtractBits(16, 15) == 0x2) ||
- (instr->ExtractBits(16, 12) == 0x1e) ||
- ((instr->ExtractBit(23) == 0) &&
- ((instr->ExtractBits(16, 14) == 0x3) ||
- (instr->ExtractBits(16, 12) == 0x1f))) ||
- ((instr->ExtractBit(23) == 1) &&
- (instr->ExtractBits(16, 12) == 0x1c))) {
- VisitUnallocated(instr);
- } else {
- VisitNEON2RegMiscFP16(instr);
- }
- }
- }
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- VisitNEON3Same(instr);
- }
- }
- } else {
- if (instr->ExtractBit(10) == 0) {
- VisitNEONByIndexedElement(instr);
- } else {
- if (instr->ExtractBit(23) == 0) {
- if (instr->ExtractBits(22, 19) == 0) {
- VisitNEONModifiedImmediate(instr);
- } else {
- VisitNEONShiftImmediate(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- }
+ // Iterate through the temporary string, filtering out the non-'_' characters
+ // into a new ordered pattern result string.
+ std::string result;
+ for (size_t i = 0; i < temp.size(); i++) {
+ if (temp[i] != '_') {
+ result.push_back(temp[i]);
}
- } else {
- VisitUnallocated(instr);
}
+ VIXL_ASSERT(result.size() == sampled_bits.size());
+ return result;
}
-
-void Decoder::DecodeNEONScalarDataProcessing(const Instruction* instr) {
- VIXL_ASSERT(instr->ExtractBits(28, 25) == 0xF);
- if (instr->ExtractBit(24) == 0) {
- if (instr->ExtractBit(21) == 0) {
- if (instr->ExtractBit(15) == 0) {
- if (instr->ExtractBit(10) == 0) {
- if (instr->ExtractBit(29) == 0) {
- if (instr->ExtractBit(11) == 0) {
- VisitCrypto3RegSHA(instr);
- } else {
- VisitUnallocated(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- } else {
- if (instr->ExtractBits(23, 22) == 0) {
- VisitNEONScalarCopy(instr);
- } else {
- if (instr->Mask(0x00404000) == 0x00400000) {
- if ((instr->ExtractBits(13, 11) == 0x6) ||
- (instr->ExtractBits(13, 11) < 2) ||
- ((instr->Mask(0x20800000) == 0x00000000) &&
- ((instr->ExtractBits(13, 11) < 0x3) ||
- (instr->ExtractBits(13, 11) == 0x5))) ||
- ((instr->Mask(0x20800000) == 0x00800000) &&
- (instr->ExtractBits(13, 11) < 0x7)) ||
- ((instr->Mask(0x20800000) == 0x20000000) &&
- ((instr->ExtractBits(13, 11) < 0x4) ||
- (instr->ExtractBits(13, 11) == 0x7))) ||
- ((instr->Mask(0x20800000) == 0x20800000) &&
- (instr->ExtractBits(12, 11) == 0x3))) {
- VisitUnallocated(instr);
- } else {
- VisitNEONScalar3SameFP16(instr);
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- }
- } else {
- if (instr->ExtractBit(29) == 0) {
- VisitUnallocated(instr);
- } else {
- if (instr->ExtractBit(10) == 0) {
- VisitUnallocated(instr);
- } else {
- VisitNEONScalar3SameExtra(instr);
- }
- }
- }
- } else {
- if (instr->ExtractBit(10) == 0) {
- if (instr->ExtractBit(11) == 0) {
- VisitNEONScalar3Diff(instr);
- } else {
- if (instr->ExtractBits(18, 17) == 0) {
- if (instr->ExtractBit(20) == 0) {
- if (instr->ExtractBit(19) == 0) {
- VisitNEONScalar2RegMisc(instr);
- } else {
- if (instr->ExtractBit(29) == 0) {
- VisitCrypto2RegSHA(instr);
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- if (instr->ExtractBit(19) == 0) {
- VisitNEONScalarPairwise(instr);
- } else {
- if (instr->ExtractBit(22) == 0) {
- VisitUnallocated(instr);
- } else {
- if ((instr->ExtractBits(16, 15) == 0x0) ||
- (instr->ExtractBits(16, 14) == 0x2) ||
- (instr->ExtractBits(16, 15) == 0x2) ||
- (instr->ExtractBits(16, 13) == 0xc) ||
- (instr->ExtractBits(16, 12) == 0x1e) ||
- ((instr->ExtractBit(23) == 0) &&
- ((instr->ExtractBits(16, 14) == 0x3) ||
- (instr->ExtractBits(16, 12) == 0x1f))) ||
- ((instr->ExtractBit(23) == 1) &&
- ((instr->ExtractBits(16, 12) == 0xf) ||
- (instr->ExtractBits(16, 12) == 0x1c) ||
- ((instr->ExtractBit(29) == 1) &&
- ((instr->ExtractBits(16, 12) == 0xe) ||
- (instr->ExtractBits(16, 12) == 0x1f)))))) {
- VisitUnallocated(instr);
- } else {
- VisitNEONScalar2RegMiscFP16(instr);
- }
- }
- }
- }
- } else {
- VisitUnallocated(instr);
- }
- }
- } else {
- VisitNEONScalar3Same(instr);
- }
- }
- } else {
- if (instr->ExtractBit(10) == 0) {
- VisitNEONScalarByIndexedElement(instr);
- } else {
- if (instr->ExtractBit(23) == 0) {
- VisitNEONScalarShiftImmediate(instr);
- } else {
- VisitUnallocated(instr);
- }
- }
+uint32_t DecodeNode::GenerateSampledBitsMask() const {
+ std::vector<uint8_t> sampled_bits = GetSampledBits();
+ uint32_t mask = 0;
+ for (size_t i = 0; i < sampled_bits.size(); i++) {
+ mask |= 1 << sampled_bits[i];
}
+ return mask;
}
-
-#define DEFINE_VISITOR_CALLERS(A) \
- void Decoder::Visit##A(const Instruction* instr) { \
- VIXL_ASSERT(((A##FMask == 0) && (A##Fixed == 0)) || \
- (instr->Mask(A##FMask) == A##Fixed)); \
- std::list<DecoderVisitor*>::iterator it; \
- for (it = visitors_.begin(); it != visitors_.end(); it++) { \
- (*it)->Visit##A(instr); \
- } \
- }
-VISITOR_LIST(DEFINE_VISITOR_CALLERS)
-#undef DEFINE_VISITOR_CALLERS
} // namespace aarch64
} // namespace vixl
diff --git a/src/aarch64/decoder-aarch64.h b/src/aarch64/decoder-aarch64.h
index 94928bed..5f467152 100644
--- a/src/aarch64/decoder-aarch64.h
+++ b/src/aarch64/decoder-aarch64.h
@@ -1,4 +1,4 @@
-// Copyright 2014, VIXL authors
+// Copyright 2019, VIXL authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -28,6 +28,8 @@
#define VIXL_AARCH64_DECODER_AARCH64_H_
#include <list>
+#include <map>
+#include <string>
#include "../globals-vixl.h"
@@ -152,22 +154,22 @@ class DecoderVisitor {
const VisitorConstness constness_;
};
+class DecodeNode;
+class CompiledDecodeNode;
+// The instruction decoder is constructed from a graph of decode nodes. At each
+// node, a number of bits are sampled from the instruction being decoded. The
+// resulting value is used to look up the next node in the graph, which then
+// samples other bits, and moves to other decode nodes. Eventually, a visitor
+// node is reached, and the corresponding visitor function is called, which
+// handles the instruction.
class Decoder {
public:
- Decoder() {}
+ Decoder() { ConstructDecodeGraph(); }
// Top-level wrappers around the actual decoding function.
- void Decode(const Instruction* instr) {
- std::list<DecoderVisitor*>::iterator it;
- for (it = visitors_.begin(); it != visitors_.end(); it++) {
- VIXL_ASSERT((*it)->IsConstVisitor());
- }
- DecodeInstruction(instr);
- }
- void Decode(Instruction* instr) {
- DecodeInstruction(const_cast<const Instruction*>(instr));
- }
+ void Decode(const Instruction* instr);
+ void Decode(Instruction* instr);
// Decode all instructions from start (inclusive) to end (exclusive).
template <typename T>
@@ -220,72 +222,285 @@ class Decoder {
VISITOR_LIST(DECLARE)
#undef DECLARE
-
std::list<DecoderVisitor*>* visitors() { return &visitors_; }
+ // Get a DecodeNode by name from the Decoder's map.
+ DecodeNode* GetDecodeNode(std::string name);
+
private:
// Decodes an instruction and calls the visitor functions registered with the
// Decoder class.
void DecodeInstruction(const Instruction* instr);
- // Decode the PC relative addressing instruction, and call the corresponding
- // visitors.
- // On entry, instruction bits 27:24 = 0x0.
- void DecodePCRelAddressing(const Instruction* instr);
-
- // Decode the add/subtract immediate instruction, and call the correspoding
- // visitors.
- // On entry, instruction bits 27:24 = 0x1.
- void DecodeAddSubImmediate(const Instruction* instr);
-
- // Decode the branch, system command, and exception generation parts of
- // the instruction tree, and call the corresponding visitors.
- // On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
- void DecodeBranchSystemException(const Instruction* instr);
-
- // Decode the load and store parts of the instruction tree, and call
- // the corresponding visitors.
- // On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
- void DecodeLoadStore(const Instruction* instr);
-
- // Decode the logical immediate and move wide immediate parts of the
- // instruction tree, and call the corresponding visitors.
- // On entry, instruction bits 27:24 = 0x2.
- void DecodeLogical(const Instruction* instr);
-
- // Decode the bitfield and extraction parts of the instruction tree,
- // and call the corresponding visitors.
- // On entry, instruction bits 27:24 = 0x3.
- void DecodeBitfieldExtract(const Instruction* instr);
-
- // Decode the data processing parts of the instruction tree, and call the
- // corresponding visitors.
- // On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
- void DecodeDataProcessing(const Instruction* instr);
-
- // Decode the floating point parts of the instruction tree, and call the
- // corresponding visitors.
- // On entry, instruction bits 27:24 = {0xE, 0xF}.
- void DecodeFP(const Instruction* instr);
-
- // Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
- // and call the corresponding visitors.
- // On entry, instruction bits 29:25 = 0x6.
- void DecodeNEONLoadStore(const Instruction* instr);
-
- // Decode the Advanced SIMD (NEON) vector data processing part of the
- // instruction tree, and call the corresponding visitors.
- // On entry, instruction bits 28:25 = 0x7.
- void DecodeNEONVectorDataProcessing(const Instruction* instr);
-
- // Decode the Advanced SIMD (NEON) scalar data processing part of the
- // instruction tree, and call the corresponding visitors.
- // On entry, instruction bits 28:25 = 0xF.
- void DecodeNEONScalarDataProcessing(const Instruction* instr);
+ // Add an initialised DecodeNode to the decode_node_ map.
+ void AddDecodeNode(const DecodeNode& node);
- private:
// Visitors are registered in a list.
std::list<DecoderVisitor*> visitors_;
+
+ // Compile the dynamically generated decode graph based on the static
+ // information in kDecodeMapping and kVisitorNodes.
+ void ConstructDecodeGraph();
+
+ // Root node for the compiled decoder graph, stored here to avoid a map lookup
+ // for every instruction decoded.
+ CompiledDecodeNode* compiled_decoder_root_;
+
+ // Map of node names to DecodeNodes.
+ std::map<std::string, DecodeNode> decode_nodes_;
+};
+
+const int kMaxDecodeSampledBits = 16;
+const int kMaxDecodeMappings = 22;
+typedef void (Decoder::*DecodeFnPtr)(const Instruction*);
+typedef uint32_t (Instruction::*BitExtractFn)(void) const;
+
+// A Visitor node maps the name of a visitor to the function that handles it.
+struct VisitorNode {
+ const char* name;
+ const DecodeFnPtr visitor_fn;
+};
+
+// DecodePattern and DecodeMapping represent the input data to the decoder
+// compilation stage. After compilation, the decoder is embodied in the graph
+// of CompiledDecodeNodes pointer to by compiled_decoder_root_.
+
+// A DecodePattern maps a pattern of set/unset/don't care (1, 0, x) bits as a
+// string to the name of its handler.
+struct DecodePattern {
+ const char* pattern;
+ const char* handler;
+};
+
+// A DecodeMapping consists of the name of a handler, the bits sampled in the
+// instruction by that handler, and a mapping from the pattern that those
+// sampled bits match to the corresponding name of a node.
+struct DecodeMapping {
+ const char* name;
+ const uint8_t sampled_bits[kMaxDecodeSampledBits];
+ const DecodePattern mapping[kMaxDecodeMappings];
+};
+
+// For speed, before nodes can be used for decoding instructions, they must
+// be compiled. This converts the mapping "bit pattern strings to decoder name
+// string" stored in DecodeNodes to an array look up for the pointer to the next
+// node, stored in CompiledDecodeNodes. Compilation may also apply other
+// optimisations for simple decode patterns.
+class CompiledDecodeNode {
+ public:
+ // Constructor for decode node, containing a decode table and pointer to a
+ // function that extracts the bits to be sampled.
+ CompiledDecodeNode(BitExtractFn bit_extract_fn, size_t decode_table_size)
+ : bit_extract_fn_(bit_extract_fn),
+ visitor_fn_(NULL),
+ decode_table_size_(decode_table_size),
+ decoder_(NULL) {
+ decode_table_ = new CompiledDecodeNode*[decode_table_size_];
+ memset(decode_table_, 0, decode_table_size_ * sizeof(decode_table_[0]));
+ }
+
+ // Constructor for wrappers around visitor functions. These require no
+ // decoding, so no bit extraction function or decode table is assigned.
+ explicit CompiledDecodeNode(DecodeFnPtr visitor_fn, Decoder* decoder)
+ : bit_extract_fn_(NULL),
+ visitor_fn_(visitor_fn),
+ decode_table_(NULL),
+ decode_table_size_(0),
+ decoder_(decoder) {}
+
+ ~CompiledDecodeNode() {
+ // Free the decode table, if this is a compiled, non-leaf node.
+ if (decode_table_ != NULL) {
+ VIXL_ASSERT(!IsLeafNode());
+ delete[] decode_table_;
+ }
+ }
+
+ // Decode the instruction by either sampling the bits using the bit extract
+ // function to find the next node, or, if we're at a leaf, calling the visitor
+ // function.
+ void Decode(const Instruction* instr) const;
+
+ // A leaf node is a wrapper for a visitor function.
+ bool IsLeafNode() const {
+ VIXL_ASSERT(((visitor_fn_ == NULL) && (bit_extract_fn_ != NULL)) ||
+ ((visitor_fn_ != NULL) && (bit_extract_fn_ == NULL)));
+ return visitor_fn_ != NULL;
+ }
+
+ // Get a pointer to the next node required in the decode process, based on the
+ // bits sampled by the current node.
+ CompiledDecodeNode* GetNodeForBits(uint32_t bits) const {
+ VIXL_ASSERT(bits < decode_table_size_);
+ return decode_table_[bits];
+ }
+
+ // Set the next node in the decode process for the pattern of sampled bits in
+ // the current node.
+ void SetNodeForBits(uint32_t bits, CompiledDecodeNode* n) {
+ VIXL_ASSERT(bits < decode_table_size_);
+ VIXL_ASSERT(n != NULL);
+ decode_table_[bits] = n;
+ }
+
+ private:
+ // Pointer to an instantiated template function for extracting the bits
+ // sampled by this node. Set to NULL for leaf nodes.
+ const BitExtractFn bit_extract_fn_;
+
+ // Visitor function that handles the instruction identified. Set only for
+ // leaf nodes, where no extra decoding is required, otherwise NULL.
+ const DecodeFnPtr visitor_fn_;
+
+ // Mapping table from instruction bits to next decode stage.
+ CompiledDecodeNode** decode_table_;
+ const size_t decode_table_size_;
+
+ // Pointer to the decoder containing this node, used to call its visitor
+ // function for leaf nodes. Set to NULL for non-leaf nodes.
+ Decoder* decoder_;
+};
+
+class DecodeNode {
+ public:
+ // Default constructor needed for map initialisation.
+ DecodeNode() : compiled_node_(NULL) {}
+
+ // Constructor for DecodeNode wrappers around visitor functions. These are
+ // marked as "compiled", as there is no decoding left to do.
+ explicit DecodeNode(const VisitorNode& visitor, Decoder* decoder)
+ : name_(visitor.name),
+ visitor_fn_(visitor.visitor_fn),
+ decoder_(decoder),
+ compiled_node_(NULL) {}
+
+ // Constructor for DecodeNodes that map bit patterns to other DecodeNodes.
+ explicit DecodeNode(const DecodeMapping& map, Decoder* decoder = NULL)
+ : name_(map.name),
+ visitor_fn_(NULL),
+ decoder_(decoder),
+ compiled_node_(NULL) {
+ // The length of the bit string in the first mapping determines the number
+ // of sampled bits. When adding patterns later, we assert that all mappings
+ // sample the same number of bits.
+ VIXL_CHECK(strcmp(map.mapping[0].pattern, "otherwise") != 0);
+ int bit_count = static_cast<int>(strlen(map.mapping[0].pattern));
+ VIXL_CHECK((bit_count > 0) && (bit_count <= 32));
+ SetSampledBits(map.sampled_bits, bit_count);
+ AddPatterns(map.mapping);
+ }
+
+ ~DecodeNode() {
+ // Delete the compiled version of this node, if one was created.
+ if (compiled_node_ != NULL) {
+ delete compiled_node_;
+ }
+ }
+
+ // Set the bits sampled from the instruction by this node.
+ void SetSampledBits(const uint8_t* bits, int bit_count);
+
+ // Get the bits sampled from the instruction by this node.
+ std::vector<uint8_t> GetSampledBits() const;
+
+ // Get the number of bits sampled from the instruction by this node.
+ size_t GetSampledBitsCount() const;
+
+ // Add patterns to this node's internal pattern table.
+ void AddPatterns(const DecodePattern* patterns);
+
+ // A leaf node is a DecodeNode that wraps the visitor function for the
+ // identified instruction class.
+ bool IsLeafNode() const { return visitor_fn_ != NULL; }
+
+ std::string GetName() const { return name_; }
+
+ // Create a CompiledDecodeNode of specified table size that uses
+ // bit_extract_fn to sample bits from the instruction.
+ void CreateCompiledNode(BitExtractFn bit_extract_fn, size_t table_size) {
+ VIXL_ASSERT(bit_extract_fn != NULL);
+ VIXL_ASSERT(table_size > 0);
+ compiled_node_ = new CompiledDecodeNode(bit_extract_fn, table_size);
+ }
+
+ // Create a CompiledDecodeNode wrapping a visitor function. No decoding is
+ // required for this node; the visitor function is called instead.
+ void CreateVisitorNode() {
+ compiled_node_ = new CompiledDecodeNode(visitor_fn_, decoder_);
+ }
+
+ // Find and compile the DecodeNode named "name", and set it as the node for
+ // the pattern "bits".
+ void CompileNodeForBits(Decoder* decoder, std::string name, uint32_t bits);
+
+ // Get a pointer to an instruction method that extracts the instruction bits
+ // specified by the mask argument, and returns those sampled bits as a
+ // contiguous sequence, suitable for indexing an array.
+ // For example, a mask of 0b1010 returns a function that, given an instruction
+ // 0bXYZW, will return 0bXZ.
+ BitExtractFn GetBitExtractFunction(uint32_t mask);
+
+ // Get a pointer to an Instruction method that applies a mask to the
+ // instruction bits, and tests if the result is equal to value. The returned
+ // function gives a 1 result if (inst & mask == value), 0 otherwise.
+ BitExtractFn GetBitExtractFunction(uint32_t mask, uint32_t value);
+
+ // Compile this DecodeNode into a new CompiledDecodeNode and returns a pointer
+ // to it. This pointer is also stored inside the DecodeNode itself. Destroying
+ // a DecodeNode frees its associated CompiledDecodeNode.
+ CompiledDecodeNode* Compile(Decoder* decoder);
+
+ // Get a pointer to the CompiledDecodeNode associated with this DecodeNode.
+ // Returns NULL if the node has not been compiled yet.
+ CompiledDecodeNode* GetCompiledNode() const { return compiled_node_; }
+ bool IsCompiled() const { return GetCompiledNode() != NULL; }
+
+ private:
+ // Generate a mask and value pair from a string constructed from 0, 1 and x
+ // (don't care) characters.
+ // For example "10x1" should return mask = 0b1101, value = 0b1001.
+ typedef std::pair<Instr, Instr> MaskValuePair;
+ MaskValuePair GenerateMaskValuePair(std::string pattern) const;
+
+ // Generate a pattern string ordered by the bit positions sampled by this
+ // node. The first character in the string corresponds to the lowest sampled
+ // bit.
+ // For example, a pattern of "1x0" expected when sampling bits 31, 1 and 30
+ // returns the pattern "x01"; bit 1 should be 'x', bit 30 '0' and bit 31 '1'.
+ // This output makes comparisons easier between the pattern and bits sampled
+ // from an instruction using the fast "compress" algorithm. See
+ // Instruction::Compress().
+ std::string GenerateOrderedPattern(std::string pattern) const;
+
+ // Generate a mask with a bit set at each sample position.
+ uint32_t GenerateSampledBitsMask() const;
+
+ // Try to compile a more optimised decode operation for this node, returning
+ // true if successful.
+ bool TryCompileOptimisedDecodeTable(Decoder* decoder);
+
+ // Name of this decoder node, used to construct edges in the decode graph.
+ std::string name_;
+
+ // Vector of bits sampled from an instruction to determine which node to look
+ // up next in the decode process.
+ std::vector<uint8_t> sampled_bits_;
+
+ // Visitor function that handles the instruction identified. Set only for leaf
+ // nodes, where no extra decoding is required. For non-leaf decoding nodes,
+ // this pointer is NULL.
+ DecodeFnPtr visitor_fn_;
+
+ // Source mapping from bit pattern to name of next decode stage.
+ std::vector<DecodePattern> pattern_table_;
+
+ // Pointer to the decoder containing this node, used to call its visitor
+ // function for leaf nodes.
+ Decoder* decoder_;
+
+ // Pointer to the compiled version of this node. Is this node hasn't been
+ // compiled yet, this pointer is NULL.
+ CompiledDecodeNode* compiled_node_;
};
} // namespace aarch64
diff --git a/src/aarch64/decoder-constants-aarch64.h b/src/aarch64/decoder-constants-aarch64.h
new file mode 100644
index 00000000..e4b72d95
--- /dev/null
+++ b/src/aarch64/decoder-constants-aarch64.h
@@ -0,0 +1,1387 @@
+// Copyright 2019, VIXL authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of ARM Limited nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace vixl {
+namespace aarch64 {
+
+// This decode table is derived from the AArch64 ISA XML specification,
+// available from https://developer.arm.com/products/architecture/a-profile/
+//
+// The data below are based on the "Index by Encoding" tables, reformatted into
+// structures of C++ strings, suitable for processing into an instruction
+// decoding tree.
+
+// clang-format off
+static const DecodeMapping kDecodeMapping[] = {
+ { "Root",
+ {28, 27, 26, 25},
+ { {"100x", "DecodeDataProcessingImmediate"},
+ {"101x", "DecodeBranchesExceptionAndSystem"},
+ {"x1x0", "DecodeLoadsAndStores"},
+ {"x101", "DecodeDataProcessingRegister"},
+ {"x111", "DecodeDataProcessingFPAndNEON"},
+ },
+ },
+
+ { "DecodeDataProcessingImmediate",
+ {25, 24, 23},
+ { {"00x", "VisitPCRelAddressing"},
+ {"01x", "UnallocAddSubImmediate"},
+ {"100", "UnallocLogicalImmediate"},
+ {"101", "UnallocMoveWideImmediate"},
+ {"110", "UnallocBitfield"},
+ {"111", "UnallocExtract"},
+ },
+ },
+
+ { "DecodeBranchesExceptionAndSystem",
+ {31, 30, 29, 25, 24, 23, 22},
+ { {"0100xxx", "UnallocConditionalBranch"},
+ {"11000xx", "UnallocException"},
+ {"1100100", "UnallocSystem"},
+ {"1101xxx", "UnallocUnconditionalBranchToRegister"},
+ {"x00xxxx", "VisitUnconditionalBranch"},
+ {"x010xxx", "VisitCompareBranch"},
+ {"x011xxx", "VisitTestBranch"},
+ },
+ },
+
+ { "DecodeLoadsAndStores",
+ {31, 29, 28, 26, 24, 23, 21},
+ { {"x0000xx", "UnallocLoadStoreExclusive"},
+ {"x01x0xx", "UnallocLoadLiteral"},
+ {"x0101x0", "UnallocLoadStoreRCpcUnscaledOffset"},
+ {"x10x00x", "UnallocLoadStorePairNonTemporal"},
+ {"x10x01x", "UnallocLoadStorePairPostIndex"},
+ {"x10x10x", "UnallocLoadStorePairOffset"},
+ {"x10x11x", "UnallocLoadStorePairPreIndex"},
+ {"0001000", "DecodeNEONLoadStoreMulti"},
+ {"0001010", "UnallocNEONLoadStoreMultiStructPostIndex"},
+ {"000110x", "DecodeNEONLoadStoreSingle"},
+ {"000111x", "UnallocNEONLoadStoreSingleStructPostIndex"},
+ {"x11x0x0", "DecodeLoadStore"},
+ {"x11x0x1", "DecodeLoadStoreRegister"},
+ {"x11x1xx", "UnallocLoadStoreUnsignedOffset"},
+ },
+ },
+
+ { "DecodeDataProcessingRegister",
+ {30, 28, 24, 23, 22, 21},
+ { {"010110", "UnallocDataProcessing2Source"},
+ {"110110", "UnallocDataProcessing1Source"},
+ {"x00xxx", "UnallocLogicalShifted"},
+ {"x01xx0", "UnallocAddSubShifted"},
+ {"x01xx1", "UnallocAddSubExtended"},
+ {"x10000", "UnallocAddSubWithCarry"},
+ {"x10010", "DecodeCondCmp"},
+ {"x10100", "UnallocConditionalSelect"},
+ {"x11xxx", "UnallocDataProcessing3Source"},
+ },
+ },
+
+ { "DecodeDataProcessingFPAndNEON",
+ {31, 30, 29, 28, 24, 21},
+ { {"0xx000", "DecodeNEONOther"},
+ {"0xx001", "DecodeNEON3Op"},
+ {"0xx01x", "DecodeNEONImmAndIndex"},
+ {"01x100", "DecodeNEONScalarAnd3SHA"},
+ {"01x101", "DecodeNEONScalarAnd2SHA"},
+ {"01x11x", "DecodeNEONScalar"},
+ {"x0x100", "UnallocFPFixedPointConvert"},
+ {"x0x101", "DecodeFP"},
+ {"x0x11x", "UnallocFPDataProcessing3Source"},
+ },
+ },
+
+ { "DecodeNEONScalarAnd3SHA",
+ {29, 23, 22, 15, 14, 11, 10},
+ { {"0xx0x00", "VisitCrypto3RegSHA"},
+ {"x000xx1", "UnallocNEONScalarCopy"},
+ {"xxx1xx1", "UnallocNEONScalar3SameExtra"},
+ {"xx100x1", "UnallocNEONScalar3SameFP16"},
+ },
+ },
+
+ { "DecodeNEONScalarAnd2SHA",
+ {29, 20, 19, 18, 17, 11, 10},
+ { {"0010010", "VisitCrypto2RegSHA"},
+ {"x000010", "UnallocNEONScalar2RegMisc"},
+ {"x100010", "UnallocNEONScalarPairwise"},
+ {"x110010", "UnallocNEONScalar2RegMiscFP16"},
+ {"xxxxxx1", "UnallocNEONScalar3Same"},
+ {"xxxxx00", "UnallocNEONScalar3Diff"},
+ },
+ },
+
+ { "DecodeNEONScalar",
+ {28, 23, 10},
+ { {"101", "UnallocNEONScalarShiftImmediate"},
+ {"1x0", "UnallocNEONScalarByIndexedElement"},
+ },
+ },
+
+ { "DecodeNEONLoadStoreMulti",
+ {20, 19, 18, 17, 16},
+ { {"00000", "UnallocNEONLoadStoreMultiStruct"},
+ },
+ },
+
+ { "DecodeNEONLoadStoreSingle",
+ {20, 19, 18, 17, 16},
+ { {"00000", "UnallocNEONLoadStoreSingleStruct"},
+ },
+ },
+
+ { "DecodeNEONOther",
+ {29, 23, 22, 15, 14, 11, 10},
+ { {"0xx0x00", "UnallocNEONTable"},
+ {"0xx0x10", "UnallocNEONPerm"},
+ {"1xx0xx0", "UnallocNEONExtract"},
+ {"x000xx1", "UnallocNEONCopy"},
+ {"xx100x1", "UnallocNEON3SameFP16"},
+ {"xxx1xx1", "UnallocNEON3SameExtra"},
+ },
+ },
+
+ { "DecodeNEON2OpAndAcross",
+ {30, 29, 20, 19, 18, 17},
+ { {"100100", "VisitCryptoAES"},
+ {"xx1100", "UnallocNEON2RegMiscFP16"},
+ {"xx0000", "UnallocNEON2RegMisc"},
+ {"xx1000", "UnallocNEONAcrossLanes"},
+ },
+ },
+
+ { "DecodeNEON3Op",
+ {11, 10},
+ { {"00", "UnallocNEON3Different"},
+ {"10", "DecodeNEON2OpAndAcross"},
+ {"x1", "UnallocNEON3Same"},
+ },
+ },
+
+ { "DecodeNEONImmAndIndex",
+ {23, 22, 21, 20, 19, 10},
+ { {"000001", "UnallocNEONModifiedImmediate"},
+ {"0xxx11", "UnallocNEONShiftImmediate"},
+ {"0xx1x1", "UnallocNEONShiftImmediate"},
+ {"0x1xx1", "UnallocNEONShiftImmediate"},
+ {"01xxx1", "UnallocNEONShiftImmediate"},
+ {"xxxxx0", "UnallocNEONByIndexedElement"},
+ },
+ },
+
+ { "DecodeFP",
+ {15, 14, 13, 12, 11, 10},
+ { {"000000", "UnallocFPIntegerConvert"},
+ {"x10000", "UnallocFPDataProcessing1Source"},
+ {"xx1000", "UnallocFPCompare"},
+ {"xxx100", "UnallocFPImmediate"},
+ {"xxxx01", "UnallocFPConditionalCompare"},
+ {"xxxx10", "UnallocFPDataProcessing2Source"},
+ {"xxxx11", "UnallocFPConditionalSelect"},
+ },
+ },
+
+ { "DecodeLoadStore",
+ {11, 10},
+ { {"00", "UnallocLoadStoreUnscaledOffset"},
+ {"01", "UnallocLoadStorePostIndex"},
+ {"10", "VisitUnimplemented"}, // LoadStoreUnprivileged.
+ {"11", "UnallocLoadStorePreIndex"},
+ },
+ },
+
+ { "DecodeLoadStoreRegister",
+ {11, 10},
+ { {"00", "UnallocAtomicMemory"},
+ {"10", "UnallocLoadStoreRegisterOffset"},
+ {"x1", "UnallocLoadStorePAC"},
+ },
+ },
+
+ { "DecodeCondCmp",
+ {11},
+ { {"0", "UnallocConditionalCompareRegister"},
+ {"1", "UnallocConditionalCompareImmediate"},
+ },
+ },
+
+ // Unallocation decode nodes. These are used to mark encodings within an
+ // instruction class as unallocated.
+ { "UnallocAddSubExtended",
+ {12, 11, 10},
+ { {"1x1", "VisitUnallocated"},
+ {"11x", "VisitUnallocated"},
+ {"otherwise", "UnallocAddSubExtended_2"},
+ },
+ },
+
+ { "UnallocAddSubExtended_2",
+ {23, 22},
+ { {"1x", "VisitUnallocated"},
+ {"x1", "VisitUnallocated"},
+ {"otherwise", "VisitAddSubExtended"},
+ },
+ },
+
+ { "UnallocAddSubImmediate",
+ {23},
+ { {"0", "VisitAddSubImmediate"},
+ {"1", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocAddSubShifted",
+ {23, 22},
+ { {"11", "VisitUnallocated"},
+ {"otherwise", "UnallocAddSubShifted_2"},
+ },
+ },
+
+ { "UnallocAddSubShifted_2",
+ {31, 15},
+ { {"01", "VisitUnallocated"},
+ {"otherwise", "VisitAddSubShifted"},
+ },
+ },
+
+ { "UnallocAddSubWithCarry",
+ {15, 14, 13, 12, 11, 10},
+ { {"000000", "VisitAddSubWithCarry"},
+ {"x00001", "UnallocRotateRightIntoFlags"},
+ {"xx0010", "UnallocEvaluateIntoFlags"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocAtomicMemory",
+ {26, 23, 22, 15, 14, 13, 12},
+ { {"0xx1001", "VisitUnallocated"},
+ {"0xx101x", "VisitUnallocated"},
+ {"0xx1101", "VisitUnallocated"},
+ {"0xx111x", "VisitUnallocated"},
+ {"00x1100", "VisitUnallocated"},
+ {"0111100", "VisitUnallocated"},
+ {"1xxxxxx", "VisitUnallocated"},
+ {"otherwise", "VisitAtomicMemory"},
+ },
+ },
+
+ { "UnallocBitfield",
+ {30, 29},
+ { {"11", "VisitUnallocated"},
+ {"otherwise", "VisitBitfield"},
+ },
+ },
+
+ { "UnallocConditionalBranch",
+ {24, 4},
+ { {"00", "VisitConditionalBranch"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocConditionalCompareImmediate",
+ {10, 4, 29},
+ { {"1xx", "VisitUnallocated"},
+ {"x1x", "VisitUnallocated"},
+ {"xx0", "VisitUnallocated"},
+ {"otherwise", "VisitConditionalCompareImmediate"},
+ },
+ },
+
+ { "UnallocConditionalCompareRegister",
+ {10, 4, 29},
+ { {"1xx", "VisitUnallocated"},
+ {"x1x", "VisitUnallocated"},
+ {"xx0", "VisitUnallocated"},
+ {"otherwise", "VisitConditionalCompareRegister"},
+ },
+ },
+
+ { "UnallocConditionalSelect",
+ {11, 29},
+ { {"00", "VisitConditionalSelect"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocDataProcessing1Source",
+ {31, 16, 14, 13, 12, 11, 10},
+ { {"x0xx11x", "VisitUnallocated"},
+ {"0000011", "VisitUnallocated"},
+ {"1001xxx", "VisitUnallocated"},
+ {"x01xxxx", "VisitUnallocated"},
+ {"x0x1xxx", "VisitUnallocated"},
+ {"01xxxxx", "VisitUnallocated"},
+ {"111xx1x", "VisitUnallocated"},
+ {"111x1xx", "VisitUnallocated"},
+ {"1111xxx", "VisitUnallocated"},
+ {"otherwise", "UnallocDataProcessing1Source_2"},
+ },
+ },
+
+ { "UnallocDataProcessing1Source_2",
+ {29, 20, 19, 18, 17, 15},
+ { {"000000", "VisitDataProcessing1Source"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocDataProcessing2Source",
+ {31, 14, 13, 12, 11, 10},
+ { {"x0000x", "VisitUnallocated"},
+ {"x11xxx", "VisitUnallocated"},
+ {"010x11", "VisitUnallocated"},
+ {"110xx0", "VisitUnallocated"},
+ {"110x0x", "VisitUnallocated"},
+ {"otherwise", "UnallocDataProcessing2Source_2"},
+ },
+ },
+
+ { "UnallocDataProcessing2Source_2",
+ {29, 15},
+ { {"00", "VisitDataProcessing2Source"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocDataProcessing3Source",
+ {23, 22, 21, 15, 31},
+ { {"00100", "VisitUnallocated"},
+ {"00110", "VisitUnallocated"},
+ {"01000", "VisitUnallocated"},
+ {"0101x", "VisitUnallocated"},
+ {"011xx", "VisitUnallocated"},
+ {"100xx", "VisitUnallocated"},
+ {"10100", "VisitUnallocated"},
+ {"10110", "VisitUnallocated"},
+ {"11000", "VisitUnallocated"},
+ {"1101x", "VisitUnallocated"},
+ {"111xx", "VisitUnallocated"},
+ {"otherwise", "UnallocDataProcessing3Source_2"},
+ },
+ },
+
+ { "UnallocDataProcessing3Source_2",
+ {30, 29},
+ { {"00", "VisitDataProcessing3Source"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocEvaluateIntoFlags",
+ {31, 30, 29, 20, 19, 18},
+ { {"001000", "UnallocEvaluateIntoFlags_2"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocEvaluateIntoFlags_2",
+ {17, 16, 15, 4, 3, 2, 1, 0},
+ { {"00001101", "VisitEvaluateIntoFlags"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocException",
+ {23, 22, 21, 1, 0},
+ { {"00000", "VisitUnallocated"},
+ {"001x1", "VisitUnallocated"},
+ {"0011x", "VisitUnallocated"},
+ {"010x1", "VisitUnallocated"},
+ {"0101x", "VisitUnallocated"},
+ {"011xx", "VisitUnallocated"},
+ {"100xx", "VisitUnallocated"},
+ {"10100", "VisitUnallocated"},
+ {"11xxx", "VisitUnallocated"},
+ {"otherwise", "UnallocException_2"},
+ },
+ },
+
+ { "UnallocException_2",
+ {4, 3, 2},
+ { {"000", "VisitException"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocExtract",
+ {30, 29, 21},
+ { {"000", "UnallocExtract_2"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocExtract_2",
+ {31, 22, 15},
+ { {"10x", "VisitUnallocated"},
+ {"01x", "VisitUnallocated"},
+ {"0x1", "VisitUnallocated"},
+ {"otherwise", "VisitExtract"},
+ },
+ },
+
+ { "UnallocFPCompare",
+ {31, 29, 15, 14, 2, 1, 0},
+ { {"0000000", "UnallocFPCompare_2"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocFPCompare_2",
+ {23, 22},
+ { {"10", "VisitUnallocated"},
+ {"otherwise", "VisitFPCompare"},
+ },
+ },
+
+ { "UnallocFPConditionalCompare",
+ {31, 29, 23, 22},
+ { {"xx10", "VisitUnallocated"},
+ {"x1xx", "VisitUnallocated"},
+ {"1xxx", "VisitUnallocated"},
+ {"otherwise", "VisitFPConditionalCompare"},
+ },
+ },
+
+ { "UnallocFPConditionalSelect",
+ {31, 29, 23, 22},
+ { {"xx10", "VisitUnallocated"},
+ {"x1xx", "VisitUnallocated"},
+ {"1xxx", "VisitUnallocated"},
+ {"otherwise", "VisitFPConditionalSelect"},
+ },
+ },
+
+ { "UnallocFPDataProcessing1Source",
+ {23, 22, 18, 17, 16, 15},
+ { {"000100", "VisitUnallocated"},
+ {"000110", "VisitUnallocated"},
+ {"001101", "VisitUnallocated"},
+ {"010101", "VisitUnallocated"},
+ {"010110", "VisitUnallocated"},
+ {"011101", "VisitUnallocated"},
+ {"10xxxx", "VisitUnallocated"},
+ {"11011x", "VisitUnallocated"},
+ {"otherwise", "UnallocFPDataProcessing1Source_2"},
+ },
+ },
+
+ { "UnallocFPDataProcessing1Source_2",
+ {31, 29, 20, 19},
+ { {"0000", "VisitFPDataProcessing1Source"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocFPDataProcessing2Source",
+ {15, 14, 13, 12},
+ { {"1xx1", "VisitUnallocated"},
+ {"1x1x", "VisitUnallocated"},
+ {"11xx", "VisitUnallocated"},
+ {"otherwise", "UnallocFPDataProcessing2Source_2"},
+ },
+ },
+
+ { "UnallocFPDataProcessing2Source_2",
+ {31, 29, 23, 22},
+ { {"xx10", "VisitUnallocated"},
+ {"x1xx", "VisitUnallocated"},
+ {"1xxx", "VisitUnallocated"},
+ {"otherwise", "VisitFPDataProcessing2Source"},
+ },
+ },
+
+ { "UnallocFPDataProcessing3Source",
+ {31, 29, 23, 22},
+ { {"xx10", "VisitUnallocated"},
+ {"x1xx", "VisitUnallocated"},
+ {"1xxx", "VisitUnallocated"},
+ {"otherwise", "VisitFPDataProcessing3Source"},
+ },
+ },
+
+ { "UnallocFPFixedPointConvert",
+ {23, 22, 20, 19, 17, 16},
+ { {"10xxxx", "VisitUnallocated"},
+ {"xxx00x", "VisitUnallocated"},
+ {"xxx11x", "VisitUnallocated"},
+ {"xx0x0x", "VisitUnallocated"},
+ {"xx1x1x", "VisitUnallocated"},
+ {"otherwise", "UnallocFPFixedPointConvert_2"},
+ },
+ },
+
+ { "UnallocFPFixedPointConvert_2",
+ {29, 18},
+ { {"00", "UnallocFPFixedPointConvert_3"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocFPFixedPointConvert_3",
+ {31, 15},
+ { {"00", "VisitUnallocated"},
+ {"otherwise", "VisitFPFixedPointConvert"},
+ },
+ },
+
+ { "UnallocFPImmediate",
+ {23, 22},
+ { {"10", "VisitUnallocated"},
+ {"otherwise", "UnallocFPImmediate_2"},
+ },
+ },
+
+ { "UnallocFPImmediate_2",
+ {31, 29, 9, 8, 7, 6, 5},
+ { {"0000000", "VisitFPImmediate"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocFPIntegerConvert",
+ {29},
+ { {"0", "UnallocFPIntegerConvert_2"},
+ {"1", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocFPIntegerConvert_2",
+ {31, 23, 22, 20, 19, 18, 17, 16},
+ { {"0001x11x", "VisitUnallocated"},
+ {"0010x11x", "VisitUnallocated"},
+ {"0011011x", "VisitUnallocated"},
+ {"00111111", "VisitUnallocated"},
+ {"010xx11x", "VisitUnallocated"},
+ {"100xx11x", "VisitUnallocated"},
+ {"1011x11x", "VisitUnallocated"},
+ {"101x111x", "VisitUnallocated"},
+ {"1101x11x", "VisitUnallocated"},
+ {"110x011x", "VisitUnallocated"},
+ {"xxx1x01x", "VisitUnallocated"},
+ {"xxx1x10x", "VisitUnallocated"},
+ {"xxxx110x", "VisitUnallocated"},
+ {"xxxx101x", "VisitUnallocated"},
+ {"otherwise", "VisitFPIntegerConvert"},
+ },
+ },
+
+ { "UnallocLoadLiteral",
+ {26, 31, 30},
+ { {"111", "VisitUnallocated"},
+ {"otherwise", "VisitLoadLiteral"},
+ },
+ },
+
+ { "UnallocLoadStoreExclusive",
+ {31, 23, 21, 14, 13, 12, 11, 10},
+ { {"001xxxx0", "VisitUnallocated"},
+ {"001xxx0x", "VisitUnallocated"},
+ {"001xx0xx", "VisitUnallocated"},
+ {"001x0xxx", "VisitUnallocated"},
+ {"0010xxxx", "VisitUnallocated"},
+ {"x11xxxx0", "VisitUnallocated"},
+ {"x11xxx0x", "VisitUnallocated"},
+ {"x11xx0xx", "VisitUnallocated"},
+ {"x11x0xxx", "VisitUnallocated"},
+ {"x110xxxx", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStoreExclusive"},
+ },
+ },
+
+ { "UnallocLoadStorePAC",
+ {31, 30, 26},
+ { {"110", "VisitLoadStorePAC"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocLoadStoreRCpcUnscaledOffset",
+ {31, 30, 23, 22, 11, 10},
+ { {"xxxxx1", "VisitUnallocated"},
+ {"xxxx1x", "VisitUnallocated"},
+ {"101100", "VisitUnallocated"},
+ {"111000", "VisitUnallocated"},
+ {"111100", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStoreRCpcUnscaledOffset"},
+ },
+ },
+
+ { "UnallocLoadStorePairNonTemporal",
+ {26, 31, 30, 22},
+ { {"001x", "VisitUnallocated"},
+ {"x11x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePairNonTemporal"},
+ },
+ },
+
+ { "UnallocLoadStorePairOffset",
+ {26, 31, 30, 22},
+ { {"0010", "VisitUnallocated"},
+ {"x11x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePairOffset"},
+ },
+ },
+
+ { "UnallocLoadStorePairPostIndex",
+ {26, 31, 30, 22},
+ { {"0010", "VisitUnallocated"},
+ {"x11x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePairPostIndex"},
+ },
+ },
+
+ { "UnallocLoadStorePairPreIndex",
+ {26, 31, 30, 22},
+ { {"0010", "VisitUnallocated"},
+ {"x11x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePairPreIndex"},
+ },
+ },
+
+ { "UnallocLoadStorePostIndex",
+ {26, 23, 22, 31, 30},
+ { {"01011", "VisitUnallocated"},
+ {"0111x", "VisitUnallocated"},
+ {"11xx1", "VisitUnallocated"},
+ {"11x1x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePostIndex"},
+ },
+ },
+
+ { "UnallocLoadStorePreIndex",
+ {26, 23, 22, 31, 30},
+ { {"01011", "VisitUnallocated"},
+ {"0111x", "VisitUnallocated"},
+ {"11xx1", "VisitUnallocated"},
+ {"11x1x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStorePreIndex"},
+ },
+ },
+
+ { "UnallocLoadStoreRegisterOffset",
+ {14},
+ { {"0", "VisitUnallocated"},
+ {"1", "UnallocLoadStoreRegisterOffset_2"},
+ },
+ },
+
+ { "UnallocLoadStoreRegisterOffset_2",
+ {26, 23, 22, 31, 30},
+ { {"0111x", "VisitUnallocated"},
+ {"11xx1", "VisitUnallocated"},
+ {"11x1x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStoreRegisterOffset"},
+ },
+ },
+
+ { "UnallocLoadStoreUnscaledOffset",
+ {26, 23, 22, 31, 30},
+ { {"0111x", "VisitUnallocated"},
+ {"11xx1", "VisitUnallocated"},
+ {"11x1x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStoreUnscaledOffset"},
+ },
+ },
+
+ { "UnallocLoadStoreUnsignedOffset",
+ {26, 23, 22, 31, 30},
+ { {"0111x", "VisitUnallocated"},
+ {"11xx1", "VisitUnallocated"},
+ {"11x1x", "VisitUnallocated"},
+ {"otherwise", "VisitLoadStoreUnsignedOffset"},
+ },
+ },
+
+ { "UnallocLogicalImmediate",
+ {31, 22},
+ { {"01", "VisitUnallocated"},
+ {"otherwise", "VisitLogicalImmediate"},
+ },
+ },
+
+ { "UnallocLogicalShifted",
+ {31, 15},
+ { {"01", "VisitUnallocated"},
+ {"otherwise", "VisitLogicalShifted"},
+ },
+ },
+
+ { "UnallocMoveWideImmediate",
+ {30, 29},
+ { {"01", "VisitUnallocated"},
+ {"otherwise", "UnallocMoveWideImmediate_2"},
+ },
+ },
+
+ { "UnallocMoveWideImmediate_2",
+ {31, 22},
+ { {"01", "VisitUnallocated"},
+ {"otherwise", "VisitMoveWideImmediate"},
+ },
+ },
+
+ { "UnallocNEON2RegMisc",
+ {16, 15, 14, 13, 12, 23, 22, 29},
+ { {"00001xx1", "VisitUnallocated"},
+ {"001011x1", "VisitUnallocated"},
+ {"01010xx1", "VisitUnallocated"},
+ {"011xx0xx", "VisitUnallocated"},
+ {"011101x1", "VisitUnallocated"},
+ {"1000xxxx", "VisitUnallocated"},
+ {"10011xx0", "VisitUnallocated"},
+ {"10101xxx", "VisitUnallocated"},
+ {"101101xx", "VisitUnallocated"},
+ {"101110x1", "VisitUnallocated"},
+ {"101111xx", "VisitUnallocated"},
+ {"110001x1", "VisitUnallocated"},
+ {"11110xxx", "VisitUnallocated"},
+ {"111110xx", "VisitUnallocated"},
+ {"111111x0", "VisitUnallocated"},
+ {"otherwise", "VisitNEON2RegMisc"},
+ },
+ },
+
+ { "UnallocNEON2RegMiscFP16",
+ {29, 23, 22, 16, 15, 14, 13, 12},
+ { {"xx0xxxxx", "VisitUnallocated"},
+ {"xxx00xxx", "VisitUnallocated"},
+ {"xxx010xx", "VisitUnallocated"},
+ {"xxx10xxx", "VisitUnallocated"},
+ {"xxx11110", "VisitUnallocated"},
+ {"x0x011xx", "VisitUnallocated"},
+ {"x0x11111", "VisitUnallocated"},
+ {"x1x11100", "VisitUnallocated"},
+ {"01x11111", "VisitUnallocated"},
+ {"11x01110", "VisitUnallocated"},
+ {"11x11000", "VisitUnallocated"},
+ {"otherwise", "VisitNEON2RegMiscFP16"},
+ },
+ },
+
+ { "UnallocNEON3Different",
+ {15, 14, 13, 12, 29},
+ { {"10011", "VisitUnallocated"},
+ {"10111", "VisitUnallocated"},
+ {"11011", "VisitUnallocated"},
+ {"11101", "VisitUnallocated"},
+ {"1111x", "VisitUnallocated"},
+ {"otherwise", "VisitNEON3Different"},
+ },
+ },
+
+ { "UnallocNEON3Same",
+ {29, 23, 22, 15, 14, 13, 12, 11},
+ { {"00111101", "VisitUnallocated"},
+ {"01x11011", "VisitUnallocated"},
+ {"01x11100", "VisitUnallocated"},
+ {"01111101", "VisitUnallocated"},
+ {"1xx10111", "VisitUnallocated"},
+ {"10111001", "VisitUnallocated"},
+ {"11x11011", "VisitUnallocated"},
+ {"11x11111", "VisitUnallocated"},
+ {"11111001", "VisitUnallocated"},
+ {"otherwise", "VisitNEON3Same"},
+ },
+ },
+
+ { "UnallocNEON3SameExtra",
+ {29, 14, 13, 12, 11},
+ { {"x0011", "VisitUnallocated"},
+ {"x01xx", "VisitUnallocated"},
+ {"00000", "VisitUnallocated"},
+ {"00001", "VisitUnallocated"},
+ {"01xxx", "VisitUnallocated"},
+ {"111x1", "VisitUnallocated"},
+ {"otherwise", "VisitNEON3SameExtra"},
+ },
+ },
+
+ { "UnallocNEON3SameFP16",
+ {29, 23, 13, 12, 11},
+ { {"00101", "VisitUnallocated"},
+ {"01011", "VisitUnallocated"},
+ {"01100", "VisitUnallocated"},
+ {"01101", "VisitUnallocated"},
+ {"10001", "VisitUnallocated"},
+ {"11001", "VisitUnallocated"},
+ {"11011", "VisitUnallocated"},
+ {"11111", "VisitUnallocated"},
+ {"otherwise", "VisitNEON3SameFP16"},
+ },
+ },
+
+ { "UnallocNEONAcrossLanes",
+ {29, 23, 22, 16, 15, 14, 13, 12},
+ { {"xxx0000x", "VisitUnallocated"},
+ {"xxx00010", "VisitUnallocated"},
+ {"xxx001xx", "VisitUnallocated"},
+ {"xxx0100x", "VisitUnallocated"},
+ {"xxx01011", "VisitUnallocated"},
+ {"xxx01101", "VisitUnallocated"},
+ {"xxx01110", "VisitUnallocated"},
+ {"xxx10xxx", "VisitUnallocated"},
+ {"xxx1100x", "VisitUnallocated"},
+ {"xxx111xx", "VisitUnallocated"},
+ {"00101100", "VisitUnallocated"},
+ {"00101111", "VisitUnallocated"},
+ {"01101100", "VisitUnallocated"},
+ {"01101111", "VisitUnallocated"},
+ {"1xx11011", "VisitUnallocated"},
+ {"otherwise", "VisitNEONAcrossLanes"},
+ },
+ },
+
+ { "UnallocNEONByIndexedElement",
+ {29, 23, 22, 15, 14, 13, 12},
+ { {"0010001", "VisitUnallocated"},
+ {"0010101", "VisitUnallocated"},
+ {"0011001", "VisitUnallocated"},
+ {"00x0000", "VisitUnallocated"},
+ {"00x0100", "VisitUnallocated"},
+ {"0xx1111", "VisitUnallocated"},
+ {"1000001", "VisitUnallocated"},
+ {"1000011", "VisitUnallocated"},
+ {"1000101", "VisitUnallocated"},
+ {"1000111", "VisitUnallocated"},
+ {"10x1000", "VisitUnallocated"},
+ {"10x1100", "VisitUnallocated"},
+ {"1110001", "VisitUnallocated"},
+ {"1110011", "VisitUnallocated"},
+ {"1110101", "VisitUnallocated"},
+ {"1110111", "VisitUnallocated"},
+ {"1xx1011", "VisitUnallocated"},
+ {"x011001", "VisitUnallocated"},
+ {"otherwise", "VisitNEONByIndexedElement"},
+ },
+ },
+
+ { "UnallocNEONCopy",
+ {14, 13, 12, 11, 30, 29},
+ { {"xxxx01", "VisitUnallocated"},
+ {"0010x0", "VisitUnallocated"},
+ {"001100", "VisitUnallocated"},
+ {"0100x0", "VisitUnallocated"},
+ {"0110x0", "VisitUnallocated"},
+ {"1xxxx0", "VisitUnallocated"},
+ {"otherwise", "UnallocNEONCopy_2"},
+ },
+ },
+
+ { "UnallocNEONCopy_2",
+ {19, 18, 17, 16},
+ { {"0000", "VisitUnallocated"},
+ {"otherwise", "VisitNEONCopy"},
+ },
+ },
+
+ { "UnallocNEONExtract",
+ {23, 22},
+ { {"00", "VisitNEONExtract"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocNEONLoadStoreMultiStruct",
+ {22, 15, 14, 13, 12},
+ { {"00001", "VisitUnallocated"},
+ {"00011", "VisitUnallocated"},
+ {"00101", "VisitUnallocated"},
+ {"01001", "VisitUnallocated"},
+ {"01011", "VisitUnallocated"},
+ {"011xx", "VisitUnallocated"},
+ {"10001", "VisitUnallocated"},
+ {"10011", "VisitUnallocated"},
+ {"10101", "VisitUnallocated"},
+ {"11001", "VisitUnallocated"},
+ {"11011", "VisitUnallocated"},
+ {"111xx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreMultiStruct"},
+ },
+ },
+
+ { "UnallocNEONLoadStoreMultiStructPostIndex",
+ {22, 15, 14, 13, 12},
+ { {"00001", "VisitUnallocated"},
+ {"00011", "VisitUnallocated"},
+ {"00101", "VisitUnallocated"},
+ {"01001", "VisitUnallocated"},
+ {"01011", "VisitUnallocated"},
+ {"011xx", "VisitUnallocated"},
+ {"10001", "VisitUnallocated"},
+ {"10011", "VisitUnallocated"},
+ {"10101", "VisitUnallocated"},
+ {"11001", "VisitUnallocated"},
+ {"11011", "VisitUnallocated"},
+ {"111xx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreMultiStructPostIndex"},
+ },
+ },
+
+ { "UnallocNEONLoadSingleStruct",
+ {21, 15, 14, 13, 12, 11, 10},
+ { {"0010xx1", "VisitUnallocated"},
+ {"0011xx1", "VisitUnallocated"},
+ {"0100101", "VisitUnallocated"},
+ {"0100x1x", "VisitUnallocated"},
+ {"0101011", "VisitUnallocated"},
+ {"01011x1", "VisitUnallocated"},
+ {"0101x10", "VisitUnallocated"},
+ {"01101xx", "VisitUnallocated"},
+ {"01111xx", "VisitUnallocated"},
+ {"1010xx1", "VisitUnallocated"},
+ {"1011xx1", "VisitUnallocated"},
+ {"1100011", "VisitUnallocated"},
+ {"11001x1", "VisitUnallocated"},
+ {"1100x10", "VisitUnallocated"},
+ {"1101011", "VisitUnallocated"},
+ {"11011x1", "VisitUnallocated"},
+ {"1101x10", "VisitUnallocated"},
+ {"11101xx", "VisitUnallocated"},
+ {"11111xx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreSingleStruct"},
+ },
+ },
+
+ { "UnallocNEONLoadStoreSingleStruct",
+ {22},
+ { {"0", "UnallocNEONStoreSingleStruct"},
+ {"1", "UnallocNEONLoadSingleStruct"},
+ },
+ },
+
+ { "UnallocNEONLoadSingleStructPostIndex",
+ {21, 15, 14, 13, 12, 11, 10},
+ { {"0010xx1", "VisitUnallocated"},
+ {"0011xx1", "VisitUnallocated"},
+ {"0100101", "VisitUnallocated"},
+ {"0100x1x", "VisitUnallocated"},
+ {"0101011", "VisitUnallocated"},
+ {"01011x1", "VisitUnallocated"},
+ {"0101x10", "VisitUnallocated"},
+ {"01101xx", "VisitUnallocated"},
+ {"01111xx", "VisitUnallocated"},
+ {"1010xx1", "VisitUnallocated"},
+ {"1011xx1", "VisitUnallocated"},
+ {"1100011", "VisitUnallocated"},
+ {"11001x1", "VisitUnallocated"},
+ {"1100x10", "VisitUnallocated"},
+ {"1101011", "VisitUnallocated"},
+ {"11011x1", "VisitUnallocated"},
+ {"1101x10", "VisitUnallocated"},
+ {"11101xx", "VisitUnallocated"},
+ {"11111xx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreSingleStructPostIndex"},
+ },
+ },
+
+ { "UnallocNEONLoadStoreSingleStructPostIndex",
+ {22},
+ { {"0", "UnallocNEONStoreSingleStructPostIndex"},
+ {"1", "UnallocNEONLoadSingleStructPostIndex"},
+ },
+ },
+
+ { "UnallocNEONModifiedImmediate",
+ {30, 29, 15, 14, 13, 12, 11},
+ { { "x00xxx1", "VisitUnallocated"},
+ { "x010xx1", "VisitUnallocated"},
+ { "x0110x1", "VisitUnallocated"},
+ { "x011101", "VisitUnallocated"},
+ { "0111110", "VisitUnallocated"},
+ { "x1xxxx1", "VisitUnallocated"},
+ { "otherwise", "VisitNEONModifiedImmediate"},
+ },
+ },
+
+ { "UnallocNEONPerm",
+ {13, 12},
+ { {"00", "VisitUnallocated"},
+ {"otherwise", "VisitNEONPerm"},
+ },
+ },
+
+ { "UnallocNEONScalar2RegMisc",
+ {16, 15, 14, 13, 12, 23, 22, 29},
+ { {"0000xxxx", "VisitUnallocated"},
+ {"00010xxx", "VisitUnallocated"},
+ {"0010xxxx", "VisitUnallocated"},
+ {"00110xxx", "VisitUnallocated"},
+ {"01010xx1", "VisitUnallocated"},
+ {"011xx0xx", "VisitUnallocated"},
+ {"011101x1", "VisitUnallocated"},
+ {"01111xxx", "VisitUnallocated"},
+ {"1000xxxx", "VisitUnallocated"},
+ {"10010xx0", "VisitUnallocated"},
+ {"10011xxx", "VisitUnallocated"},
+ {"10101xxx", "VisitUnallocated"},
+ {"101100x0", "VisitUnallocated"},
+ {"101101xx", "VisitUnallocated"},
+ {"10111xxx", "VisitUnallocated"},
+ {"1100xxxx", "VisitUnallocated"},
+ {"111001xx", "VisitUnallocated"},
+ {"11110xxx", "VisitUnallocated"},
+ {"111110xx", "VisitUnallocated"},
+ {"111111x1", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalar2RegMisc"},
+ },
+ },
+
+ { "UnallocNEONScalar2RegMiscFP16",
+ {29, 23, 22, 16, 15, 14, 13, 12},
+ { {"xx0xxxxx", "VisitUnallocated"},
+ {"xx100xxx", "VisitUnallocated"},
+ {"xx1010xx", "VisitUnallocated"},
+ {"xx110xxx", "VisitUnallocated"},
+ {"xx11100x", "VisitUnallocated"},
+ {"xx111110", "VisitUnallocated"},
+ {"x01011xx", "VisitUnallocated"},
+ {"x0111111", "VisitUnallocated"},
+ {"x1101111", "VisitUnallocated"},
+ {"x1111100", "VisitUnallocated"},
+ {"11101110", "VisitUnallocated"},
+ {"11111111", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalar2RegMiscFP16"},
+ },
+ },
+
+ { "UnallocNEONScalar3Diff",
+ {14, 13, 12, 29},
+ { {"000x", "VisitUnallocated"},
+ {"0011", "VisitUnallocated"},
+ {"010x", "VisitUnallocated"},
+ {"0111", "VisitUnallocated"},
+ {"100x", "VisitUnallocated"},
+ {"1011", "VisitUnallocated"},
+ {"11xx", "VisitUnallocated"},
+ {"otherwise", "UnallocNEONScalar3Diff_2"},
+ },
+ },
+
+ { "UnallocNEONScalar3Diff_2",
+ {15},
+ { {"0", "VisitUnallocated"},
+ {"1", "VisitNEONScalar3Diff"},
+ },
+ },
+
+ { "UnallocNEONScalar3Same",
+ {15, 14, 13, 12, 11, 23, 22, 29},
+ { {"00000xxx", "VisitUnallocated"},
+ {"0001xxxx", "VisitUnallocated"},
+ {"00100xxx", "VisitUnallocated"},
+ {"011xxxxx", "VisitUnallocated"},
+ {"1001xxxx", "VisitUnallocated"},
+ {"1010xxxx", "VisitUnallocated"},
+ {"10111xxx", "VisitUnallocated"},
+ {"1100xxxx", "VisitUnallocated"},
+ {"110100xx", "VisitUnallocated"},
+ {"110101x0", "VisitUnallocated"},
+ {"110110x1", "VisitUnallocated"},
+ {"110111xx", "VisitUnallocated"},
+ {"111001x0", "VisitUnallocated"},
+ {"111010x0", "VisitUnallocated"},
+ {"111011x0", "VisitUnallocated"},
+ {"11110xxx", "VisitUnallocated"},
+ {"111110x1", "VisitUnallocated"},
+ {"111111x1", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalar3Same"},
+ },
+ },
+
+ { "UnallocNEONScalar3SameExtra",
+ {29, 14, 13, 12, 11},
+ { {"x001x", "VisitUnallocated"},
+ {"x01xx", "VisitUnallocated"},
+ {"x1xxx", "VisitUnallocated"},
+ {"00000", "VisitUnallocated"},
+ {"00001", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalar3SameExtra"},
+ },
+ },
+
+ { "UnallocNEONScalar3SameFP16",
+ {29, 23, 13, 12, 11},
+ { {"00011", "VisitNEONScalar3SameFP16"},
+ {"00100", "VisitNEONScalar3SameFP16"},
+ {"00111", "VisitNEONScalar3SameFP16"},
+ {"01111", "VisitNEONScalar3SameFP16"},
+ {"10100", "VisitNEONScalar3SameFP16"},
+ {"10101", "VisitNEONScalar3SameFP16"},
+ {"11010", "VisitNEONScalar3SameFP16"},
+ {"11100", "VisitNEONScalar3SameFP16"},
+ {"11101", "VisitNEONScalar3SameFP16"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocNEONScalarByIndexedElement",
+ {29, 23, 22, 15, 14, 13, 12},
+ { {"0xx1111", "VisitUnallocated"},
+ {"1000001", "VisitUnallocated"},
+ {"1000101", "VisitUnallocated"},
+ {"11x0001", "VisitUnallocated"},
+ {"11x0101", "VisitUnallocated"},
+ {"1xx0011", "VisitUnallocated"},
+ {"1xx0111", "VisitUnallocated"},
+ {"1xx1011", "VisitUnallocated"},
+ {"1xx1100", "VisitUnallocated"},
+ {"x010001", "VisitUnallocated"},
+ {"x010101", "VisitUnallocated"},
+ {"x011001", "VisitUnallocated"},
+ {"xxx0000", "VisitUnallocated"},
+ {"xxx0010", "VisitUnallocated"},
+ {"xxx0100", "VisitUnallocated"},
+ {"xxx0110", "VisitUnallocated"},
+ {"xxx1000", "VisitUnallocated"},
+ {"xxx1010", "VisitUnallocated"},
+ {"xxx1110", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalarByIndexedElement"},
+ },
+ },
+
+ { "UnallocNEONScalarCopy",
+ {14, 13, 12, 11},
+ { {"0000", "UnallocNEONScalarCopy_2"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocNEONScalarCopy_2",
+ {19, 18, 17, 16},
+ { {"0000", "VisitUnallocated"},
+ {"otherwise", "UnallocNEONScalarCopy_3"},
+ },
+ },
+
+ { "UnallocNEONScalarCopy_3",
+ {29},
+ { {"0", "VisitNEONScalarCopy"},
+ {"1", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocNEONScalarPairwise",
+ {29, 23, 22, 16, 15, 14, 13, 12},
+ { {"xxx00xxx", "VisitUnallocated"},
+ {"xxx010xx", "VisitUnallocated"},
+ {"xxx01110", "VisitUnallocated"},
+ {"xxx10xxx", "VisitUnallocated"},
+ {"xxx1100x", "VisitUnallocated"},
+ {"xxx11010", "VisitUnallocated"},
+ {"xxx111xx", "VisitUnallocated"},
+ {"x1x01101", "VisitUnallocated"},
+ {"00101100", "VisitUnallocated"},
+ {"00101101", "VisitUnallocated"},
+ {"00101111", "VisitUnallocated"},
+ {"01101100", "VisitUnallocated"},
+ {"01101111", "VisitUnallocated"},
+ {"1xx11011", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalarPairwise"},
+ },
+ },
+
+ { "UnallocNEONScalarShiftImmediate",
+ {15, 14, 13, 12, 11, 29},
+ { {"00001x", "VisitUnallocated"},
+ {"00011x", "VisitUnallocated"},
+ {"00101x", "VisitUnallocated"},
+ {"00111x", "VisitUnallocated"},
+ {"010000", "VisitUnallocated"},
+ {"01001x", "VisitUnallocated"},
+ {"01011x", "VisitUnallocated"},
+ {"011000", "VisitUnallocated"},
+ {"01101x", "VisitUnallocated"},
+ {"01111x", "VisitUnallocated"},
+ {"100000", "VisitUnallocated"},
+ {"100010", "VisitUnallocated"},
+ {"101xxx", "VisitUnallocated"},
+ {"110xxx", "VisitUnallocated"},
+ {"11101x", "VisitUnallocated"},
+ {"11110x", "VisitUnallocated"},
+ {"otherwise", "UnallocNEONScalarShiftImmediate_2"},
+ },
+ },
+
+ { "UnallocNEONScalarShiftImmediate_2",
+ {22, 21, 20, 19},
+ { {"0000", "VisitUnallocated"},
+ {"otherwise", "VisitNEONScalarShiftImmediate"},
+ },
+ },
+
+ { "UnallocNEONShiftImmediate",
+ {15, 14, 13, 12, 11, 29},
+ { {"00001x", "VisitUnallocated"},
+ {"00011x", "VisitUnallocated"},
+ {"00101x", "VisitUnallocated"},
+ {"00111x", "VisitUnallocated"},
+ {"010000", "VisitUnallocated"},
+ {"01001x", "VisitUnallocated"},
+ {"01011x", "VisitUnallocated"},
+ {"011000", "VisitUnallocated"},
+ {"01101x", "VisitUnallocated"},
+ {"01111x", "VisitUnallocated"},
+ {"10101x", "VisitUnallocated"},
+ {"1011xx", "VisitUnallocated"},
+ {"110xxx", "VisitUnallocated"},
+ {"11101x", "VisitUnallocated"},
+ {"11110x", "VisitUnallocated"},
+ {"otherwise", "VisitNEONShiftImmediate"},
+ },
+ },
+
+ { "UnallocNEONStoreSingleStruct",
+ {21, 15, 14, 13, 12, 11, 10},
+ { {"0010xx1", "VisitUnallocated"},
+ {"0011xx1", "VisitUnallocated"},
+ {"0100101", "VisitUnallocated"},
+ {"0100x1x", "VisitUnallocated"},
+ {"0101011", "VisitUnallocated"},
+ {"01011x1", "VisitUnallocated"},
+ {"0101x10", "VisitUnallocated"},
+ {"1010xx1", "VisitUnallocated"},
+ {"1011xx1", "VisitUnallocated"},
+ {"1100011", "VisitUnallocated"},
+ {"11001x1", "VisitUnallocated"},
+ {"1100x10", "VisitUnallocated"},
+ {"1101011", "VisitUnallocated"},
+ {"11011x1", "VisitUnallocated"},
+ {"1101x10", "VisitUnallocated"},
+ {"x11xxxx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreSingleStruct"},
+ },
+ },
+
+ { "UnallocNEONStoreSingleStructPostIndex",
+ {21, 15, 14, 13, 12, 11, 10},
+ { {"0010xx1", "VisitUnallocated"},
+ {"0011xx1", "VisitUnallocated"},
+ {"0100101", "VisitUnallocated"},
+ {"0100x1x", "VisitUnallocated"},
+ {"0101011", "VisitUnallocated"},
+ {"01011x1", "VisitUnallocated"},
+ {"0101x10", "VisitUnallocated"},
+ {"1010xx1", "VisitUnallocated"},
+ {"1011xx1", "VisitUnallocated"},
+ {"1100011", "VisitUnallocated"},
+ {"11001x1", "VisitUnallocated"},
+ {"1100x10", "VisitUnallocated"},
+ {"1101011", "VisitUnallocated"},
+ {"11011x1", "VisitUnallocated"},
+ {"1101x10", "VisitUnallocated"},
+ {"x11xxxx", "VisitUnallocated"},
+ {"otherwise", "VisitNEONLoadStoreSingleStructPostIndex"},
+ },
+ },
+
+ { "UnallocNEONTable",
+ {23, 22},
+ { {"00", "VisitNEONTable"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocRotateRightIntoFlags",
+ {31, 30, 29, 4},
+ { {"1010", "VisitRotateRightIntoFlags"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocSystem",
+ {21, 20, 19, 15, 14, 13, 12},
+ { {"0000101", "VisitUnallocated"},
+ {"000011x", "VisitUnallocated"},
+ {"0001xxx", "VisitUnallocated"},
+ {"100xxxx", "VisitUnallocated"},
+ {"otherwise", "UnallocSystem_2"},
+ },
+ },
+
+ { "UnallocSystem_2",
+ {21, 20, 19, 15, 14, 13},
+ { {"000000", "VisitUnallocated"},
+ {"otherwise", "UnallocSystem_3"},
+ },
+ },
+
+ { "UnallocSystem_3",
+ {21, 20, 19, 16, 15, 14, 13},
+ { {"0000001", "VisitUnallocated"},
+ {"otherwise", "UnallocSystem_4"},
+ },
+ },
+
+ { "UnallocSystem_4",
+ {21, 20, 19, 17, 15, 14, 13},
+ { {"0000001", "VisitUnallocated"},
+ {"otherwise", "UnallocSystem_5"},
+ },
+ },
+
+ { "UnallocSystem_5",
+ {21, 20, 19, 18, 15, 14, 13},
+ { {"0001001", "VisitUnallocated"},
+ {"otherwise", "VisitSystem"},
+ },
+ },
+
+ { "UnallocUnconditionalBranchToRegister",
+ {15, 14, 13, 12},
+ { {"0000", "UnallocUnconditionalBranchToRegister_2"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocUnconditionalBranchToRegister_2",
+ {20, 19, 18, 17, 16},
+ { {"11111", "UnallocUnconditionalBranchToRegister_3"},
+ {"otherwise", "VisitUnallocated"},
+ },
+ },
+
+ { "UnallocUnconditionalBranchToRegister_3",
+ {24, 23, 22, 21},
+ { {"0011", "VisitUnallocated"},
+ {"011x", "VisitUnallocated"},
+ {"otherwise", "VisitUnconditionalBranchToRegister"},
+ },
+ },
+};
+// clang-format on
+
+static const VisitorNode kVisitorNodes[] = {
+#define VISITOR_NODES(A) {"Visit" #A, &Decoder::Visit##A},
+ VISITOR_LIST(VISITOR_NODES)
+#undef VISITOR_NODES
+};
+
+} // namespace aarch64
+} // namespace vixl
diff --git a/src/aarch64/instructions-aarch64.h b/src/aarch64/instructions-aarch64.h
index 759d03b3..6d4f96b4 100644
--- a/src/aarch64/instructions-aarch64.h
+++ b/src/aarch64/instructions-aarch64.h
@@ -178,6 +178,37 @@ class Instruction {
return ExtractBits(msb, lsb);
}
+ // Compress bit extraction operation from Hacker's Delight.
+ // https://github.com/hcs0/Hackers-Delight/blob/master/compress.c.txt
+ uint32_t Compress(uint32_t mask) const {
+ uint32_t mk, mp, mv, t;
+ uint32_t x = GetInstructionBits() & mask; // Clear irrelevant bits.
+ mk = ~mask << 1; // We will count 0's to right.
+ for (int i = 0; i < 5; i++) {
+ mp = mk ^ (mk << 1); // Parallel suffix.
+ mp = mp ^ (mp << 2);
+ mp = mp ^ (mp << 4);
+ mp = mp ^ (mp << 8);
+ mp = mp ^ (mp << 16);
+ mv = mp & mask; // Bits to move.
+ mask = (mask ^ mv) | (mv >> (1 << i)); // Compress mask.
+ t = x & mv;
+ x = (x ^ t) | (t >> (1 << i)); // Compress x.
+ mk = mk & ~mp;
+ }
+ return x;
+ }
+
+ template <uint32_t M>
+ uint32_t ExtractBits() const {
+ return Compress(M);
+ }
+
+ template <uint32_t M, uint32_t V>
+ uint32_t IsMaskedValue() const {
+ return (Mask(M) == V) ? 1 : 0;
+ }
+
int32_t ExtractSignedBits(int msb, int lsb) const {
int32_t bits = *(reinterpret_cast<const int32_t*>(this));
return ExtractSignedBitfield32(msb, lsb, bits);