blob: 71086bc81f9b5d810daf11040f21a0aa8d28712b [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkVMVisualizer_DEFINED
#define SkVMVisualizer_DEFINED
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTHash.h"
#include "src/core/SkVM.h"
#include <cstddef>
#include <type_traits>
#include <vector>
class SkWStream;
namespace SkSL { class SkVMDebugTrace; }
namespace skvm::viz {
enum InstructionFlags : uint8_t {
kNormal = 0x00,
kHoisted = 0x01,
kDead = 0x02,
};
struct MachineCommand {
size_t address;
SkString label;
SkString command;
SkString extra;
};
struct Instruction {
InstructionFlags kind = InstructionFlags::kNormal;
// Machine commands range (for disassembling):
size_t startCode = 0;
size_t endCode = 0;
int instructionIndex; // index in the actual instructions list
int duplicates = 0; // number of duplicates;
// -1 means it's a duplicate itself; 0 - it does not have dups
skvm::Instruction instruction;
bool operator == (const Instruction& o) const;
SkString classes() const;
};
struct InstructionHash {
uint32_t operator()(const Instruction& i) const;
};
class Visualizer {
public:
explicit Visualizer(SkSL::SkVMDebugTrace* debugInfo);
~Visualizer() = default;
void dump(SkWStream* output, const char* code);
void markAsDeadCode(std::vector<bool>& live, const std::vector<int>& newIds);
void finalize(const std::vector<skvm::Instruction>& all,
const std::vector<skvm::OptimizedInstruction>& optimized);
void addInstructions(std::vector<skvm::Instruction>& program);
void markAsDuplicate(int origin, int id) {
++fInstructions[origin].duplicates;
}
void addInstruction(Instruction skvm);
void addMachineCommands(int id, size_t start, size_t end);
SkString V(int reg) const;
private:
void parseDisassembler(SkWStream* output, const char* code);
void dumpInstruction(int id) const;
void dumpHead() const;
void dumpTail() const;
void formatVV(const char* op, int v1, int v2) const;
void formatPV(const char* op, int imm, int v1) const;
void formatPVV(const char* op, int imm, int v1, int v2) const;
void formatPVVVV(const char* op, int imm, int v1, int v2, int v3, int v4) const;
void formatA_(int id, const char* op) const;
void formatA_P(int id, const char* op, int imm) const;
void formatA_PH(int id, const char* op, int immA, int immB) const;
void formatA_PHH(int id, const char* op, int immA, int immB, int immC) const;
void formatA_PHV(int id, const char* op, int immA, int immB, int v) const;
void formatA_S(int id, const char* op, int imm) const;
void formatA_V(int id, const char* op, int v) const;
void formatA_VV(int id, const char* op, int v1, int v2) const;
void formatA_VVV(int id, const char* op, int v1, int v2, int v3) const;
void formatA_VC(int id, const char* op, int v, int imm) const;
void writeText(const char* format, ...) const SK_PRINTF_LIKE(2, 3);
#if defined(SK_ENABLE_SKSL)
SkSL::SkVMDebugTrace* fDebugInfo;
#endif
SkTHashMap<Instruction, size_t, InstructionHash> fIndex;
SkTArray<Instruction> fInstructions;
SkWStream* fOutput;
SkTHashMap<int, size_t> fToDisassembler;
SkTArray<MachineCommand> fAsm;
mutable size_t fAsmLine = 0;
size_t fAsmStart = 0;
size_t fAsmEnd = 0;
};
} // namespace skvm::viz
namespace sknonstd {
template <typename T> struct is_bitmask_enum;
template <> struct is_bitmask_enum<skvm::viz::InstructionFlags> : std::true_type {};
} // namespace sknonstd
#endif // SkVMVisualizer_DEFINED