blob: 9b26d02f184b113ee2ad5525beae40293544141e [file] [log] [blame]
// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_LANG_CORE_IR_DISASSEMBLER_H_
#define SRC_TINT_LANG_CORE_IR_DISASSEMBLER_H_
#include <string>
#include "src/tint/lang/core/ir/binary.h"
#include "src/tint/lang/core/ir/block.h"
#include "src/tint/lang/core/ir/call.h"
#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/switch.h"
#include "src/tint/lang/core/ir/unary.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/hashset.h"
#include "src/tint/utils/text/string_stream.h"
// Forward declarations.
namespace tint::type {
class Struct;
}
namespace tint::ir {
/// Helper class to disassemble the IR
class Disassembler {
public:
/// Constructor
/// @param mod the module
explicit Disassembler(Module& mod);
~Disassembler();
/// Returns the module as a string
/// @returns the string representation of the module
std::string Disassemble();
/// @returns the string representation
std::string AsString() const { return out_.str(); }
/// @param inst the instruction to retrieve
/// @returns the source for the instruction
Source InstructionSource(Instruction* inst) {
return instruction_to_src_.Get(inst).value_or(Source{});
}
/// @param operand the operand to retrieve
/// @returns the source for the operand
Source OperandSource(Usage operand) { return operand_to_src_.Get(operand).value_or(Source{}); }
/// @param result the result to retrieve
/// @returns the source for the result
Source ResultSource(Usage result) { return result_to_src_.Get(result).value_or(Source{}); }
/// @param blk teh block to retrieve
/// @returns the source for the block
Source BlockSource(Block* blk) { return block_to_src_.Get(blk).value_or(Source{}); }
/// Stores the given @p src location for @p inst instruction
/// @param inst the instruction to store
/// @param src the source location
void SetSource(Instruction* inst, Source src) { instruction_to_src_.Add(inst, src); }
/// Stores the given @p src location for @p blk block
/// @param blk the block to store
/// @param src the source location
void SetSource(Block* blk, Source src) { block_to_src_.Add(blk, src); }
/// Stores the given @p src location for @p op operand
/// @param op the operand to store
/// @param src the source location
void SetSource(Usage op, Source src) { operand_to_src_.Add(op, src); }
/// Stores the given @p src location for @p result
/// @param result the result to store
/// @param src the source location
void SetResultSource(Usage result, Source src) { result_to_src_.Add(result, src); }
/// @returns the source location for the current emission location
Source::Location MakeCurrentLocation();
private:
class SourceMarker {
public:
explicit SourceMarker(Disassembler* d) : dis_(d), begin_(dis_->MakeCurrentLocation()) {}
~SourceMarker() = default;
void Store(Instruction* inst) { dis_->SetSource(inst, MakeSource()); }
void Store(Block* blk) { dis_->SetSource(blk, MakeSource()); }
void Store(Usage operand) { dis_->SetSource(operand, MakeSource()); }
void StoreResult(Usage result) { dis_->SetResultSource(result, MakeSource()); }
Source MakeSource() const {
return Source(Source::Range(begin_, dis_->MakeCurrentLocation()));
}
private:
Disassembler* dis_ = nullptr;
Source::Location begin_;
};
utils::StringStream& Indent();
size_t IdOf(Block* blk);
std::string IdOf(Value* node);
std::string NameOf(If* inst);
std::string NameOf(Loop* inst);
std::string NameOf(Switch* inst);
void EmitBlock(Block* blk, std::string_view comment = "");
void EmitFunction(Function* func);
void EmitParamAttributes(FunctionParam* p);
void EmitReturnAttributes(Function* func);
void EmitBindingPoint(BindingPoint p);
void EmitLocation(Location loc);
void EmitInstruction(Instruction* inst);
void EmitValueWithType(Instruction* val);
void EmitValueWithType(Value* val);
void EmitValue(Value* val);
void EmitValueList(utils::Slice<ir::Value* const> values);
void EmitBinary(Binary* b);
void EmitUnary(Unary* b);
void EmitTerminator(Terminator* b);
void EmitSwitch(Switch* s);
void EmitLoop(Loop* l);
void EmitIf(If* i);
void EmitStructDecl(const type::Struct* str);
void EmitLine();
void EmitOperand(Instruction* inst, size_t index);
void EmitOperandList(Instruction* inst, size_t start_index = 0);
void EmitInstructionName(std::string_view name, Instruction* inst);
Module& mod_;
utils::StringStream out_;
utils::Hashmap<Block*, size_t, 32> block_ids_;
utils::Hashmap<Value*, std::string, 32> value_ids_;
utils::Hashset<std::string, 32> ids_;
uint32_t indent_size_ = 0;
bool in_function_ = false;
uint32_t current_output_line_ = 1;
uint32_t current_output_start_pos_ = 0;
utils::Hashmap<Block*, Source, 8> block_to_src_;
utils::Hashmap<Instruction*, Source, 8> instruction_to_src_;
utils::Hashmap<Usage, Source, 8, Usage::Hasher> operand_to_src_;
utils::Hashmap<Usage, Source, 8, Usage::Hasher> result_to_src_;
utils::Hashmap<If*, std::string, 8> if_names_;
utils::Hashmap<Loop*, std::string, 8> loop_names_;
utils::Hashmap<Switch*, std::string, 8> switch_names_;
};
} // namespace tint::ir
#endif // SRC_TINT_LANG_CORE_IR_DISASSEMBLER_H_