diff options
author | Martyn Capewell <martyn.capewell@arm.com> | 2019-01-17 15:07:28 +0000 |
---|---|---|
committer | Jacob Bramley <jacob.bramley@arm.com> | 2019-01-17 16:31:52 +0000 |
commit | 91fea40cc9ac4ca26f5fd26e2393aafe383f66cd (patch) | |
tree | b8e149f012e5289fe686fd474386a50ebb5c0107 /src | |
parent | 7fcd70d4afa05749967d54658fd1894e246f993e (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.cc | 1259 | ||||
-rw-r--r-- | src/aarch64/decoder-aarch64.h | 351 | ||||
-rw-r--r-- | src/aarch64/decoder-constants-aarch64.h | 1387 | ||||
-rw-r--r-- | src/aarch64/instructions-aarch64.h | 31 |
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); |