2023-05-08 10:40:49 +00:00
|
|
|
// Copyright 2019, VIXL authors
|
2019-01-07 20:50:46 +00:00
|
|
|
// 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.
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
#include <string>
|
|
|
|
|
2019-01-07 20:50:46 +00:00
|
|
|
#include "../globals-vixl.h"
|
|
|
|
#include "../utils-vixl.h"
|
|
|
|
|
|
|
|
#include "decoder-aarch64.h"
|
2023-05-08 10:40:49 +00:00
|
|
|
#include "decoder-constants-aarch64.h"
|
2019-01-07 20:50:46 +00:00
|
|
|
|
|
|
|
namespace vixl {
|
|
|
|
namespace aarch64 {
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
void Decoder::Decode(Instruction* instr) {
|
|
|
|
compiled_decoder_root_->Decode(const_cast<const Instruction*>(instr));
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
void Decoder::AddDecodeNode(const DecodeNode& node) {
|
|
|
|
if (decode_nodes_.count(node.GetName()) == 0) {
|
|
|
|
decode_nodes_.insert(std::make_pair(node.GetName(), node));
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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];
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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));
|
|
|
|
|
|
|
|
// Add a node for each instruction form named, identified by having no '_'
|
|
|
|
// prefix on the node name.
|
|
|
|
const DecodeMapping& map = kDecodeMapping[i];
|
|
|
|
for (unsigned j = 0; j < map.mapping.size(); j++) {
|
|
|
|
if ((map.mapping[j].handler != NULL) &&
|
|
|
|
(map.mapping[j].handler[0] != '_')) {
|
|
|
|
AddDecodeNode(DecodeNode(map.mapping[j].handler, this));
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
|
|
|
|
// Add an "unallocated" node, used when an instruction encoding is not
|
|
|
|
// recognised by the decoding graph.
|
|
|
|
AddDecodeNode(DecodeNode("unallocated", this));
|
|
|
|
|
|
|
|
// Compile the graph from the root.
|
|
|
|
compiled_decoder_root_ = GetDecodeNode("Root")->Compile(this);
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
|
|
|
|
visitors_.push_back(new_visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
|
|
|
|
visitors_.push_front(new_visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
|
|
|
DecoderVisitor* registered_visitor) {
|
|
|
|
std::list<DecoderVisitor*>::iterator it;
|
|
|
|
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
|
|
|
if (*it == registered_visitor) {
|
|
|
|
visitors_.insert(it, new_visitor);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We reached the end of the list. The last element must be
|
|
|
|
// registered_visitor.
|
|
|
|
VIXL_ASSERT(*it == registered_visitor);
|
|
|
|
visitors_.insert(it, new_visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
|
|
|
DecoderVisitor* registered_visitor) {
|
|
|
|
std::list<DecoderVisitor*>::iterator it;
|
|
|
|
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
|
|
|
if (*it == registered_visitor) {
|
|
|
|
it++;
|
|
|
|
visitors_.insert(it, new_visitor);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We reached the end of the list. The last element must be
|
|
|
|
// registered_visitor.
|
|
|
|
VIXL_ASSERT(*it == registered_visitor);
|
|
|
|
visitors_.push_back(new_visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
|
|
|
visitors_.remove(visitor);
|
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
void Decoder::VisitNamedInstruction(const Instruction* instr,
|
|
|
|
const std::string& name) {
|
|
|
|
std::list<DecoderVisitor*>::iterator it;
|
|
|
|
Metadata m = {{"form", name}};
|
|
|
|
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
|
|
|
(*it)->Visit(&m, instr);
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Initialise empty vectors for sampled bits and pattern table.
|
|
|
|
const std::vector<uint8_t> DecodeNode::kEmptySampledBits;
|
|
|
|
const std::vector<DecodePattern> DecodeNode::kEmptyPatternTable;
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
#define INSTANTIATE_TEMPLATE_M(M) \
|
|
|
|
case 0x##M: \
|
|
|
|
bit_extract_fn = &Instruction::ExtractBits<0x##M>; \
|
|
|
|
break;
|
|
|
|
#define INSTANTIATE_TEMPLATE_MV(M, V) \
|
|
|
|
case 0x##M##V: \
|
|
|
|
bit_extract_fn = &Instruction::IsMaskedValue<0x##M, 0x##V>; \
|
|
|
|
break;
|
|
|
|
|
|
|
|
BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// The arguments x and y represent the mask and value. If y is 0, x is the
|
|
|
|
// mask. Otherwise, y is the mask, and x is the value to compare against a
|
|
|
|
// masked result.
|
|
|
|
uint64_t signature = (static_cast<uint64_t>(y) << 32) | x;
|
|
|
|
switch (signature) {
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000002);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000060);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000000df);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000100);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000200);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000c10);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00000fc0);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00001000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00001400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00001800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00001c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00002000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00002010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00002400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00003000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00003020);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00003400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00003800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00003c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00013000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000203e0);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000303e0);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00040000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00040010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00060000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00061000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00070000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000703c0);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00080000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00090000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(000f0010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00100000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00180000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(001b1c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(001f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(001f0018);
|
|
|
|
INSTANTIATE_TEMPLATE_M(001f2000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(001f3000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00400018);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00400800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00403000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00500000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00500800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00583000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(005f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00800000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00800400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00800c1d);
|
|
|
|
INSTANTIATE_TEMPLATE_M(0080101f);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00801c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00803000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00803c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(009f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(009f2000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c0001f);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00200);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c00c19);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c01000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c01400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c01c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c02000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c03000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c03c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c70000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00c83000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d00200);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d80800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d81800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d81c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d82800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d82c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d92400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00d93000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00db0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00db2000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00dc0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00dc2000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(00df0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40000000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40000010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40000c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40002000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40002010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40003000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40003c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(401f2000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40400800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40400c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40403c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(405f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40800000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40800c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40802000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40802010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40803400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40803c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c00000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c00400);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c00800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c00c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c00c10);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c02000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c02010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c02c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c03c00);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c80000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40c90000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40cf0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40d02000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40d02010);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40d80000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40d81800);
|
|
|
|
INSTANTIATE_TEMPLATE_M(40dc0000);
|
|
|
|
INSTANTIATE_TEMPLATE_M(bf20c000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000006, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000006, 00000006);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000007, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(0000001f, 0000001f);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000210, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000003e0, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000003e0, 000003e0);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000003e2, 000003e0);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000003e6, 000003e0);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000003e6, 000003e6);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000c00, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00000fc0, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000013e0, 00001000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00001c00, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00002400, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003000, 00001000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003000, 00002000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003000, 00003000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003010, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00003c00, 00003c00);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00040010, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00060000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00061000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00070000, 00030000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00073ee0, 00033060);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00073f9f, 0000001f);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000f0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(000f0010, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00100200, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00100210, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00160000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00170000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001c0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001d0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001e0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f0000, 00010000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f0000, 00100000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f0000, 001f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f3000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f3000, 00001000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f3000, 001f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f300f, 0000000d);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f301f, 0000000d);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f33e0, 000103e0);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(001f3800, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00401000, 00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(005f3000, 001f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(005f3000, 001f1000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00800010, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00800400, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00800410, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00803000, 00002000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00870000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(009f0000, 00010000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c00000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c00000, 00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c0001f, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c001ff, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c00200, 00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c0020f, 00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c003e0, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00c00800, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00d80800, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00df0000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(00df3800, 001f0800);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40002000, 40000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40003c00, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40040000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(401f2000, 401f0000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40800c00, 40000400);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40c00000, 00000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40c00000, 00400000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40c00000, 40000000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40c00000, 40800000);
|
|
|
|
INSTANTIATE_TEMPLATE_MV(40df0000, 00000000);
|
|
|
|
default: {
|
|
|
|
static bool printed_preamble = false;
|
|
|
|
if (!printed_preamble) {
|
|
|
|
printf("One or more missing template instantiations.\n");
|
|
|
|
printf(
|
|
|
|
"Add the following to either GetBitExtractFunction() "
|
|
|
|
"implementations\n");
|
|
|
|
printf("in %s near line %d:\n", __FILE__, __LINE__);
|
|
|
|
printed_preamble = true;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
|
|
|
|
if (y == 0) {
|
|
|
|
printf(" INSTANTIATE_TEMPLATE_M(%08x);\n", x);
|
|
|
|
bit_extract_fn = &Instruction::ExtractBitsAbsent;
|
2019-01-07 20:50:46 +00:00
|
|
|
} else {
|
2023-05-08 10:40:49 +00:00
|
|
|
printf(" INSTANTIATE_TEMPLATE_MV(%08x, %08x);\n", y, x);
|
|
|
|
bit_extract_fn = &Instruction::IsMaskedValueAbsent;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
return bit_extract_fn;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
#undef INSTANTIATE_TEMPLATE_M
|
|
|
|
#undef INSTANTIATE_TEMPLATE_MV
|
|
|
|
|
|
|
|
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.
|
|
|
|
size_t table_size = pattern_table_.size();
|
|
|
|
if ((table_size <= 2) && (GetSampledBitsCount() > 1)) {
|
|
|
|
// TODO: support 'x' in this optimisation by dropping the sampled bit
|
|
|
|
// positions before making the mask/value.
|
|
|
|
if (!PatternContainsSymbol(pattern_table_[0].pattern,
|
|
|
|
PatternSymbol::kSymbolX) &&
|
|
|
|
(table_size == 1)) {
|
|
|
|
// A pattern table consisting of a fixed pattern with no x's, and an
|
|
|
|
// "otherwise" or absent case. Optimise this into an instruction mask and
|
|
|
|
// value test.
|
|
|
|
uint32_t single_decode_mask = 0;
|
|
|
|
uint32_t single_decode_value = 0;
|
|
|
|
const std::vector<uint8_t>& bits = GetSampledBits();
|
|
|
|
|
|
|
|
// Construct the instruction mask and value from the pattern.
|
|
|
|
VIXL_ASSERT(bits.size() == GetPatternLength(pattern_table_[0].pattern));
|
|
|
|
for (size_t i = 0; i < bits.size(); i++) {
|
|
|
|
single_decode_mask |= 1U << bits[i];
|
|
|
|
if (GetSymbolAt(pattern_table_[0].pattern, i) ==
|
|
|
|
PatternSymbol::kSymbol1) {
|
|
|
|
single_decode_value |= 1U << bits[i];
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
BitExtractFn bit_extract_fn =
|
|
|
|
GetBitExtractFunction(single_decode_mask, single_decode_value);
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Create a compiled node that contains a two entry table for the
|
|
|
|
// either/or cases.
|
|
|
|
CreateCompiledNode(bit_extract_fn, 2);
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Set DecodeNode for when the instruction after masking doesn't match the
|
|
|
|
// value.
|
|
|
|
CompileNodeForBits(decoder, "unallocated", 0);
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Set DecodeNode for when it does match.
|
|
|
|
CompileNodeForBits(decoder, pattern_table_[0].handler, 1);
|
|
|
|
|
|
|
|
return true;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
return false;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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 = "unallocated";
|
|
|
|
|
|
|
|
// 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++) {
|
|
|
|
matches.push_back(GenerateMaskValuePair(
|
|
|
|
GenerateOrderedPattern(pattern_table_[i].pattern)));
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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,
|
|
|
|
static_cast<size_t>(1) << 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;
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// 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);
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
VIXL_ASSERT(compiled_node_ != NULL);
|
|
|
|
return compiled_node_;
|
|
|
|
}
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
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_->VisitNamedInstruction(instr, instruction_name_);
|
2019-01-07 20:50:46 +00:00
|
|
|
} else {
|
2023-05-08 10:40:49 +00:00
|
|
|
// 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);
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
DecodeNode::MaskValuePair DecodeNode::GenerateMaskValuePair(
|
|
|
|
uint32_t pattern) const {
|
|
|
|
uint32_t mask = 0, value = 0;
|
|
|
|
for (size_t i = 0; i < GetPatternLength(pattern); i++) {
|
|
|
|
PatternSymbol sym = GetSymbolAt(pattern, i);
|
|
|
|
mask = (mask << 1) | ((sym == PatternSymbol::kSymbolX) ? 0 : 1);
|
|
|
|
value = (value << 1) | (static_cast<uint32_t>(sym) & 1);
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
return std::make_pair(mask, value);
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
uint32_t DecodeNode::GenerateOrderedPattern(uint32_t pattern) const {
|
|
|
|
const std::vector<uint8_t>& sampled_bits = GetSampledBits();
|
|
|
|
uint64_t temp = 0xffffffffffffffff;
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Place symbols into the field of set bits. Symbols are two bits wide and
|
|
|
|
// take values 0, 1 or 2, so 3 will represent "no symbol".
|
|
|
|
for (size_t i = 0; i < sampled_bits.size(); i++) {
|
|
|
|
int shift = sampled_bits[i] * 2;
|
|
|
|
temp ^= static_cast<uint64_t>(kEndOfPattern) << shift;
|
|
|
|
temp |= static_cast<uint64_t>(GetSymbolAt(pattern, i)) << shift;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Iterate over temp and extract new pattern ordered by sample position.
|
|
|
|
uint32_t result = kEndOfPattern; // End of pattern marker.
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// Iterate over the pattern one symbol (two bits) at a time.
|
|
|
|
for (int i = 62; i >= 0; i -= 2) {
|
|
|
|
uint32_t sym = (temp >> i) & kPatternSymbolMask;
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// If this is a valid symbol, shift into the result.
|
|
|
|
if (sym != kEndOfPattern) {
|
|
|
|
result = (result << 2) | sym;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
// The length of the ordered pattern must be the same as the input pattern,
|
|
|
|
// and the number of sampled bits.
|
|
|
|
VIXL_ASSERT(GetPatternLength(result) == GetPatternLength(pattern));
|
|
|
|
VIXL_ASSERT(GetPatternLength(result) == sampled_bits.size());
|
2019-01-07 20:50:46 +00:00
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
return result;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 10:40:49 +00:00
|
|
|
uint32_t DecodeNode::GenerateSampledBitsMask() const {
|
|
|
|
uint32_t mask = 0;
|
|
|
|
for (int bit : GetSampledBits()) {
|
|
|
|
mask |= 1 << bit;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
2023-05-08 10:40:49 +00:00
|
|
|
return mask;
|
2019-01-07 20:50:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace aarch64
|
|
|
|
} // namespace vixl
|