mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
C++ Pro
- Different from C++ amateur. - Addresses code review suggestions to step up the C++
This commit is contained in:
parent
a412e34fa6
commit
2c6d3dde67
@ -19,7 +19,7 @@ namespace rsx::assembler
|
|||||||
bool set_cond;
|
bool set_cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unordered_map<std::string, FP_opcode_encoding_t> s_opcode_lookup
|
static std::unordered_map<std::string_view, FP_opcode_encoding_t> s_opcode_lookup
|
||||||
{
|
{
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
{ "NOP", { .op = RSX_FP_OPCODE_NOP, .exec_if_lt = true, .exec_if_eq = true, .exec_if_gt = true, .set_cond = false } },
|
{ "NOP", { .op = RSX_FP_OPCODE_NOP, .exec_if_lt = true, .exec_if_eq = true, .exec_if_gt = true, .set_cond = false } },
|
||||||
@ -168,10 +168,9 @@ namespace rsx::assembler
|
|||||||
std::vector<u32> result;
|
std::vector<u32> result;
|
||||||
result.reserve(m_instructions.size() * 4);
|
result.reserve(m_instructions.size() * 4);
|
||||||
|
|
||||||
for (u32 i = 0; i < m_instructions.size(); ++i)
|
for (const auto& inst : m_instructions)
|
||||||
{
|
{
|
||||||
const auto& inst = m_instructions[i];
|
const auto src = reinterpret_cast<const be_t<u16>*>(inst.bytecode);
|
||||||
auto src = reinterpret_cast<const be_t<u16>*>(inst.bytecode);
|
|
||||||
for (u32 j = 0; j < inst.length; ++j)
|
for (u32 j = 0; j < inst.length; ++j)
|
||||||
{
|
{
|
||||||
const u16 low = src[j * 2];
|
const u16 low = src[j * 2];
|
||||||
@ -184,7 +183,7 @@ namespace rsx::assembler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FPIR FPIR::from_source(const std::string& asm_)
|
FPIR FPIR::from_source(std::string_view asm_)
|
||||||
{
|
{
|
||||||
std::vector<std::string> instructions = fmt::split(asm_, { "\n", ";" });
|
std::vector<std::string> instructions = fmt::split(asm_, { "\n", ";" });
|
||||||
if (instructions.empty())
|
if (instructions.empty())
|
||||||
@ -192,13 +191,13 @@ namespace rsx::assembler
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto transform_inst = [](const std::string& s)
|
auto transform_inst = [](std::string_view s)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(s.size());
|
result.reserve(s.size());
|
||||||
|
|
||||||
bool literal = false;
|
bool literal = false;
|
||||||
for (auto& c : s)
|
for (const auto& c : s)
|
||||||
{
|
{
|
||||||
if (c == ' ')
|
if (c == ' ')
|
||||||
{
|
{
|
||||||
@ -235,7 +234,7 @@ namespace rsx::assembler
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode_instruction = [&](const std::string& inst, std::string& op, std::string& dst, std::vector<std::string>& sources)
|
auto decode_instruction = [&](std::string_view inst, std::string& op, std::string& dst, std::vector<std::string>& sources)
|
||||||
{
|
{
|
||||||
const auto i = transform_inst(inst);
|
const auto i = transform_inst(inst);
|
||||||
if (i.empty())
|
if (i.empty())
|
||||||
@ -259,7 +258,7 @@ namespace rsx::assembler
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto get_ref = [](const std::string& reg)
|
auto get_ref = [](std::string_view reg)
|
||||||
{
|
{
|
||||||
ensure(reg.length() > 1, "Invalid register specifier");
|
ensure(reg.length() > 1, "Invalid register specifier");
|
||||||
|
|
||||||
@ -291,15 +290,15 @@ namespace rsx::assembler
|
|||||||
return ref;
|
return ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto get_constants = [](const std::string& reg) -> std::array<f32, 4>
|
auto get_constants = [](std::string_view reg) -> std::array<f32, 4>
|
||||||
{
|
{
|
||||||
float x, y, z, w;
|
float x, y, z, w;
|
||||||
if (sscanf_s(reg.c_str(), "#{%f|%f|%f|%f}", &x, &y, &z, &w) == 4)
|
if (sscanf_s(reg.data(), "#{%f|%f|%f|%f}", &x, &y, &z, &w) == 4)
|
||||||
{
|
{
|
||||||
return { x, y, z, w };
|
return { x, y, z, w };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf_s(reg.c_str(), "#{%f}", &x) == 1)
|
if (sscanf_s(reg.data(), "#{%f}", &x) == 1)
|
||||||
{
|
{
|
||||||
return { x, x, x, x };
|
return { x, x, x, x };
|
||||||
}
|
}
|
||||||
@ -328,35 +327,29 @@ namespace rsx::assembler
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto encode_opcode = [](const std::string& op, Instruction* inst)
|
auto encode_opcode = [](std::string_view op, Instruction* inst)
|
||||||
{
|
{
|
||||||
OPDEST d0 { .HEX = inst->bytecode[0] };
|
OPDEST d0 { .HEX = inst->bytecode[0] };
|
||||||
SRC0 s0 { .HEX = inst->bytecode[1] };
|
SRC0 s0 { .HEX = inst->bytecode[1] };
|
||||||
SRC1 s1 { .HEX = inst->bytecode[2] };
|
SRC1 s1 { .HEX = inst->bytecode[2] };
|
||||||
|
|
||||||
#define SET_OPCODE(encoding) \
|
|
||||||
do { \
|
|
||||||
inst->opcode = encoding.op; \
|
|
||||||
d0.opcode = encoding.op & 0x3F; \
|
|
||||||
s1.opcode_hi = (encoding.op > 0x3F)? 1 : 0; \
|
|
||||||
s0.exec_if_eq = encoding.exec_if_eq ? 1 : 0; \
|
|
||||||
s0.exec_if_gr = encoding.exec_if_gt ? 1 : 0; \
|
|
||||||
s0.exec_if_lt = encoding.exec_if_lt ? 1 : 0; \
|
|
||||||
d0.set_cond = encoding.set_cond ? 1 : 0; \
|
|
||||||
inst->bytecode[0] = d0.HEX; \
|
|
||||||
inst->bytecode[1] = s0.HEX; \
|
|
||||||
inst->bytecode[2] = s1.HEX; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
const auto found = s_opcode_lookup.find(op);
|
const auto found = s_opcode_lookup.find(op);
|
||||||
if (found == s_opcode_lookup.end())
|
if (found == s_opcode_lookup.end())
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Unhandled instruction '%s'", op);
|
fmt::throw_exception("Unhandled instruction '%s'", op);
|
||||||
}
|
}
|
||||||
|
const auto& encoding = found->second;
|
||||||
|
|
||||||
SET_OPCODE(found->second);
|
inst->opcode = encoding.op;
|
||||||
|
d0.opcode = encoding.op & 0x3F;
|
||||||
#undef SET_OPCODE
|
s1.opcode_hi = (encoding.op > 0x3F)? 1 : 0;
|
||||||
|
s0.exec_if_eq = encoding.exec_if_eq ? 1 : 0;
|
||||||
|
s0.exec_if_gr = encoding.exec_if_gt ? 1 : 0;
|
||||||
|
s0.exec_if_lt = encoding.exec_if_lt ? 1 : 0;
|
||||||
|
d0.set_cond = encoding.set_cond ? 1 : 0;
|
||||||
|
inst->bytecode[0] = d0.HEX;
|
||||||
|
inst->bytecode[1] = s0.HEX;
|
||||||
|
inst->bytecode[2] = s1.HEX;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string op, dst;
|
std::string op, dst;
|
||||||
|
|||||||
@ -16,7 +16,7 @@ namespace rsx::assembler
|
|||||||
const std::vector<Instruction>& instructions() const;
|
const std::vector<Instruction>& instructions() const;
|
||||||
std::vector<u32> compile() const;
|
std::vector<u32> compile() const;
|
||||||
|
|
||||||
static FPIR from_source(const std::string& asm_);
|
static FPIR from_source(std::string_view asm_);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Instruction* load(const RegisterRef& reg, int operand, Instruction* target = nullptr);
|
Instruction* load(const RegisterRef& reg, int operand, Instruction* target = nullptr);
|
||||||
|
|||||||
@ -16,9 +16,9 @@ namespace rsx::assembler::FP
|
|||||||
|
|
||||||
bool is_delay_slot(const Instruction& instruction)
|
bool is_delay_slot(const Instruction& instruction)
|
||||||
{
|
{
|
||||||
OPDEST dst{ .HEX = instruction.bytecode[0] };
|
const OPDEST dst{ .HEX = instruction.bytecode[0] };
|
||||||
SRC0 src0{ .HEX = instruction.bytecode[1] };
|
const SRC0 src0{ .HEX = instruction.bytecode[1] };
|
||||||
SRC1 src1{ .HEX = instruction.bytecode[2] };
|
const SRC1 src1{ .HEX = instruction.bytecode[2] };
|
||||||
|
|
||||||
if (dst.opcode != RSX_FP_OPCODE_MOV || // These slots are always populated with MOV
|
if (dst.opcode != RSX_FP_OPCODE_MOV || // These slots are always populated with MOV
|
||||||
dst.no_dest || // Must have a sink
|
dst.no_dest || // Must have a sink
|
||||||
@ -70,21 +70,14 @@ namespace rsx::assembler::FP
|
|||||||
|
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
results.push_back(ref);
|
results.push_back(std::move(ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to check a span for 32-bit access
|
// Helper to check a span for 32-bit access
|
||||||
auto match_any_32 = [](const std::span<const char> lanes)
|
auto match_any_32 = [](const std::span<const char> lanes)
|
||||||
{
|
{
|
||||||
for (const auto& c : lanes)
|
return std::any_of(lanes.begin(), lanes.end(), FN(x == content_dual || x == content_float32));
|
||||||
{
|
|
||||||
if (c == content_dual || c == content_float32)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// F32 register processing
|
// F32 register processing
|
||||||
@ -115,7 +108,7 @@ namespace rsx::assembler::FP
|
|||||||
|
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
results.push_back(ref);
|
results.push_back(std::move(ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,13 +135,13 @@ namespace rsx::assembler::FP
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
instruction.srcs.push_back(reg);
|
instruction.srcs.push_back(std::move(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterRef dst = get_dst_register(&instruction);
|
RegisterRef dst = get_dst_register(&instruction);
|
||||||
if (dst)
|
if (dst)
|
||||||
{
|
{
|
||||||
instruction.dsts.push_back(dst);
|
instruction.dsts.push_back(std::move(dst));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ namespace rsx::assembler::FP
|
|||||||
|
|
||||||
RegisterRef ref{ .reg{.id = static_cast<int>(index), .f16 = true } };
|
RegisterRef ref{ .reg{.id = static_cast<int>(index), .f16 = true } };
|
||||||
ref.mask = mask;
|
ref.mask = mask;
|
||||||
result.push_back(ref);
|
result.push_back(std::move(ref));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ namespace rsx::assembler::FP
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref.reg = {.id = static_cast<int>(index), .f16 = false };
|
ref.reg = {.id = static_cast<int>(index), .f16 = false };
|
||||||
result.push_back(barrier);
|
result.push_back(std::move(barrier));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -190,7 +190,7 @@ namespace rsx::assembler::FP
|
|||||||
Register src_reg{ .id = static_cast<int>(src_reg_id), .f16 = true };
|
Register src_reg{ .id = static_cast<int>(src_reg_id), .f16 = true };
|
||||||
instruction.srcs.push_back({ .reg = src_reg, .mask = 0xF });
|
instruction.srcs.push_back({ .reg = src_reg, .mask = 0xF });
|
||||||
instruction.dsts.push_back({ .reg{ .id = reg_id, .f16 = false }, .mask = (1u << ch) });
|
instruction.dsts.push_back({ .reg{ .id = reg_id, .f16 = false }, .mask = (1u << ch) });
|
||||||
result.push_back(instruction);
|
result.push_back(std::move(instruction));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -258,7 +258,7 @@ namespace rsx::assembler::FP
|
|||||||
Register src_reg{ .id = static_cast<int>(src_reg_id), .f16 = true };
|
Register src_reg{ .id = static_cast<int>(src_reg_id), .f16 = true };
|
||||||
instruction.srcs.push_back({ .reg = src_reg, .mask = 0xF });
|
instruction.srcs.push_back({ .reg = src_reg, .mask = 0xF });
|
||||||
instruction.dsts.push_back({ .reg{.id = reg.reg.id, .f16 = false }, .mask = dst.write_mask });
|
instruction.dsts.push_back({ .reg{.id = reg.reg.id, .f16 = false }, .mask = dst.write_mask });
|
||||||
result.push_back(instruction);
|
result.push_back(std::move(instruction));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -284,7 +284,7 @@ namespace rsx::assembler::FP
|
|||||||
for (const auto& barrier : barriers)
|
for (const auto& barrier : barriers)
|
||||||
{
|
{
|
||||||
auto instructions = build_barrier32(barrier);
|
auto instructions = build_barrier32(barrier);
|
||||||
result.insert(result.end(), instructions.begin(), instructions.end());
|
result.insert(result.end(), std::make_move_iterator(instructions.begin()), std::make_move_iterator(instructions.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -351,10 +351,10 @@ namespace rsx::assembler::FP
|
|||||||
for (const auto& reg : barrier16_in)
|
for (const auto& reg : barrier16_in)
|
||||||
{
|
{
|
||||||
auto barrier = build_barrier16(reg);
|
auto barrier = build_barrier16(reg);
|
||||||
instructions.insert(instructions.end(), barrier.begin(), barrier.end());
|
instructions.insert(instructions.end(), std::make_move_iterator(barrier.begin()), std::make_move_iterator(barrier.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
it = block->instructions.insert(it, instructions.begin(), instructions.end());
|
it = block->instructions.insert(it, std::make_move_iterator(instructions.begin()), std::make_move_iterator(instructions.end()));
|
||||||
std::advance(it, instructions.size());
|
std::advance(it, instructions.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,10 +367,10 @@ namespace rsx::assembler::FP
|
|||||||
for (const auto& reg : barrier32_in)
|
for (const auto& reg : barrier32_in)
|
||||||
{
|
{
|
||||||
auto barrier = build_barrier32(reg);
|
auto barrier = build_barrier32(reg);
|
||||||
instructions.insert(instructions.end(), barrier.begin(), barrier.end());
|
instructions.insert(instructions.end(), std::make_move_iterator(barrier.begin()), std::make_move_iterator(barrier.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
it = block->instructions.insert(it, instructions.begin(), instructions.end());
|
it = block->instructions.insert(it, std::make_move_iterator(instructions.begin()), std::make_move_iterator(instructions.end()));
|
||||||
std::advance(it, instructions.size());
|
std::advance(it, instructions.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,8 +431,8 @@ namespace rsx::assembler::FP
|
|||||||
|
|
||||||
if (!clobbered_lanes.empty())
|
if (!clobbered_lanes.empty())
|
||||||
{
|
{
|
||||||
const auto instructions = resolve_dependencies(clobbered_lanes, f16);
|
auto instructions = resolve_dependencies(clobbered_lanes, f16);
|
||||||
target->epilogue.insert(target->epilogue.end(), instructions.begin(), instructions.end());
|
target->epilogue.insert(target->epilogue.end(), std::make_move_iterator(instructions.begin()), std::make_move_iterator(instructions.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lanes_to_search.empty())
|
if (lanes_to_search.empty())
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user