summaryrefslogtreecommitdiff
path: root/src/amd/compiler/aco_print_asm.cpp
diff options
context:
space:
mode:
authorDaniel Schürmann <daniel@schuermann.dev>2019-09-17 13:22:17 +0200
committerDaniel Schürmann <daniel@schuermann.dev>2019-09-19 12:10:00 +0200
commit93c8ebfa780ebd1495095e794731881aef29e7d3 (patch)
tree547268dbeabb0d17f14202d4429b3f6abfdb01c5 /src/amd/compiler/aco_print_asm.cpp
parent99cbec0a5f463fef4d9c61f34482d9eb00293704 (diff)
aco: Initial commit of independent AMD compiler
ACO (short for AMD Compiler) is a new compiler backend with the goal to replace LLVM for Radeon hardware for the RADV driver. ACO currently supports only VS, PS and CS on VI and Vega. There are some optimizations missing because of unmerged NIR changes which may decrease performance. Full commit history can be found at https://github.com/daniel-schuermann/mesa/commits/backend Co-authored-by: Daniel Schürmann <daniel@schuermann.dev> Co-authored-by: Rhys Perry <pendingchaos02@gmail.com> Co-authored-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Co-authored-by: Connor Abbott <cwabbott0@gmail.com> Co-authored-by: Michael Schellenberger Costa <mschellenbergercosta@googlemail.com> Co-authored-by: Timur Kristóf <timur.kristof@gmail.com> Acked-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Diffstat (limited to 'src/amd/compiler/aco_print_asm.cpp')
-rw-r--r--src/amd/compiler/aco_print_asm.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/amd/compiler/aco_print_asm.cpp b/src/amd/compiler/aco_print_asm.cpp
new file mode 100644
index 00000000000..31079aa1c4a
--- /dev/null
+++ b/src/amd/compiler/aco_print_asm.cpp
@@ -0,0 +1,104 @@
+
+#include <iomanip>
+#include "aco_ir.h"
+#include "llvm-c/Disassembler.h"
+#include "ac_llvm_util.h"
+
+#include <llvm/ADT/StringRef.h>
+
+namespace aco {
+
+void print_asm(Program *program, std::vector<uint32_t>& binary,
+ unsigned exec_size, enum radeon_family family, std::ostream& out)
+{
+ std::vector<bool> referenced_blocks(program->blocks.size());
+ referenced_blocks[0] = true;
+ for (Block& block : program->blocks) {
+ for (unsigned succ : block.linear_succs)
+ referenced_blocks[succ] = true;
+ }
+
+ std::vector<std::tuple<uint64_t, llvm::StringRef, uint8_t>> symbols;
+ std::vector<std::array<char,16>> block_names;
+ block_names.reserve(program->blocks.size());
+ for (Block& block : program->blocks) {
+ if (!referenced_blocks[block.index])
+ continue;
+ std::array<char, 16> name;
+ sprintf(name.data(), "BB%u", block.index);
+ block_names.push_back(name);
+ symbols.emplace_back(block.offset * 4, llvm::StringRef(block_names[block_names.size() - 1].data()), 0);
+ }
+
+ LLVMDisasmContextRef disasm = LLVMCreateDisasmCPU("amdgcn-mesa-mesa3d",
+ ac_get_llvm_processor_name(family),
+ &symbols, 0, NULL, NULL);
+
+ char outline[1024];
+ size_t pos = 0;
+ bool invalid = false;
+ unsigned next_block = 0;
+ while (pos < exec_size) {
+ while (next_block < program->blocks.size() && pos == program->blocks[next_block].offset) {
+ if (referenced_blocks[next_block])
+ out << "BB" << std::dec << next_block << ":" << std::endl;
+ next_block++;
+ }
+
+ size_t l = LLVMDisasmInstruction(disasm, (uint8_t *) &binary[pos],
+ (exec_size - pos) * sizeof(uint32_t), pos * 4,
+ outline, sizeof(outline));
+
+ size_t new_pos;
+ const int align_width = 60;
+ if (program->chip_class == GFX9 && !l && ((binary[pos] & 0xffff8000) == 0xd1348000)) { /* not actually an invalid instruction */
+ out << std::left << std::setw(align_width) << std::setfill(' ') << "\tv_add_u32_e64 + clamp";
+ new_pos = pos + 2;
+ } else if (!l) {
+ out << std::left << std::setw(align_width) << std::setfill(' ') << "(invalid instruction)";
+ new_pos = pos + 1;
+ invalid = true;
+ } else {
+ out << std::left << std::setw(align_width) << std::setfill(' ') << outline;
+ assert(l % 4 == 0);
+ new_pos = pos + l / 4;
+ }
+ out << std::right;
+
+ out << " ;";
+ for (; pos < new_pos; pos++)
+ out << " " << std::setfill('0') << std::setw(8) << std::hex << binary[pos];
+ out << std::endl;
+ }
+ out << std::setfill(' ') << std::setw(0) << std::dec;
+ assert(next_block == program->blocks.size());
+
+ LLVMDisasmDispose(disasm);
+
+ if (program->constant_data.size()) {
+ out << std::endl << "/* constant data */" << std::endl;
+ for (unsigned i = 0; i < program->constant_data.size(); i += 32) {
+ out << '[' << std::setw(6) << std::setfill('0') << std::dec << i << ']';
+ unsigned line_size = std::min<size_t>(program->constant_data.size() - i, 32);
+ for (unsigned j = 0; j < line_size; j += 4) {
+ unsigned size = std::min<size_t>(program->constant_data.size() - (i + j), 4);
+ uint32_t v = 0;
+ memcpy(&v, &program->constant_data[i + j], size);
+ out << " " << std::setw(8) << std::setfill('0') << std::hex << v;
+ }
+ out << std::endl;
+ }
+ }
+
+ out << std::setfill(' ') << std::setw(0) << std::dec;
+
+ if (invalid) {
+ /* Invalid instructions usually lead to GPU hangs, which can make
+ * getting the actual invalid instruction hard. Abort here so that we
+ * can find the problem.
+ */
+ abort();
+ }
+}
+
+}