#include <array>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>

#include <poplar/DeviceManager.hpp>
#include <poplar/Engine.hpp>
#include <poplar/Executable.hpp>

using namespace poplar;

int main(int argc, char **argv) {
  if (argc != 2) {
    std::cerr << "usage: run_matmul_executable EXECUTABLE\n";
    return 2;
  }
  std::ifstream input(argv[1], std::ios::binary);
  if (!input) {
    std::cerr << "failed to open executable: " << argv[1] << '\n';
    return 2;
  }
  Executable executable = Executable::deserialize(input);
  Engine engine(executable);

  DeviceManager manager;
  auto devices = manager.getDevices(TargetType::IPU, 1);
  if (devices.empty() || !devices[0].attach()) {
    std::cerr << "failed to attach an IPU\n";
    return 3;
  }
  engine.load(devices[0]);
  engine.run(0);

  constexpr std::array<int, 16> expected = {
      4, 24, 9, 14, 20, 48, 25, 38, -12, 14, 3, 0, 22, 10, 8, 31};
  std::vector<int> results(1472);
  engine.readTensor("resultsRead", results.data(),
                    results.data() + results.size());
  bool ok = true;
  for (unsigned i = 0; i < expected.size(); ++i)
    ok &= results[8 + i] == expected[i];
  std::cout << "precompiledExecutable=yes graphConstruction=no codeletCompile=no "
            << (ok ? "PASS\n" : "FAIL\n");
  return ok ? 0 : 1;
}
