Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Hexagon] Remove uses of LLVM from simulator runtime #8821

Merged
merged 3 commits into from
Aug 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 126 additions & 48 deletions src/runtime/hexagon/sim/hexagon_device_sim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
* under the License.
*/

#include <llvm/ADT/Optional.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Process.h>
#include <dmlc/optional.h>
#include <stdlib.h>
#include <tvm/runtime/logging.h>
#include <unistd.h>

#include <algorithm>
#include <deque>
Expand All @@ -31,6 +29,7 @@
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "../hexagon_module.h"
Expand Down Expand Up @@ -84,6 +83,18 @@ std::unique_ptr<T> make_unique(size_t size) {
return std::unique_ptr<T>(new U[size]());
}

// An "Optional" class, originally a replacement for llvm::Optional, then an
// extension of dmlc::optional to make it compatible with C++17's std::optional.
template <typename T>
struct Optional : public dmlc::optional<T> {
using dmlc::optional<T>::optional;
using dmlc::optional<T>::operator=;
Optional(const T& val) : dmlc::optional<T>(val) {} // NOLINT(*)

T* operator->() { return &this->operator*(); }
const T* operator->() const { return &this->operator*(); }
};

// Converter class to translate vector<string> to char**. This relieves the
// user from memory reallocation and copying.
struct non_const_str {
Expand Down Expand Up @@ -117,7 +128,7 @@ struct non_const_str {
std::vector<std::unique_ptr<char[]>> storage_;
};

using MaybeString = llvm::Optional<std::string>;
using MaybeString = Optional<std::string>;

MaybeString front(const string_list& deq) {
return !deq.empty() ? MaybeString(deq.front()) : MaybeString();
Expand All @@ -130,47 +141,47 @@ MaybeString pop_front(string_list& deq) { // NOLINT(*)
return MaybeString(f);
}

llvm::Optional<int64_t> to_int(const MaybeString& str) {
auto none = llvm::Optional<int64_t>();
if (str.hasValue()) {
Optional<int64_t> to_int(const MaybeString& str) {
auto none = Optional<int64_t>();
if (str.has_value()) {
try {
size_t pos;
int64_t val = std::stoll(*str, &pos, 0);
return pos == str->size() ? llvm::Optional<int64_t>(val) : none;
return pos == str->size() ? Optional<int64_t>(val) : none;
} catch (std::invalid_argument) {
}
}
return none;
}

llvm::Optional<uint64_t> to_uint(const MaybeString& str) {
auto none = llvm::Optional<uint64_t>();
if (str.hasValue()) {
Optional<uint64_t> to_uint(const MaybeString& str) {
auto none = Optional<uint64_t>();
if (str.has_value()) {
try {
size_t pos;
uint64_t val = std::stoull(*str, &pos, 0);
return pos == str->size() ? llvm::Optional<uint64_t>(val) : none;
return pos == str->size() ? Optional<uint64_t>(val) : none;
} catch (std::invalid_argument) {
}
}
return none;
}

llvm::Optional<float> to_float(const MaybeString& str) {
auto none = llvm::Optional<float>();
if (str.hasValue()) {
Optional<float> to_float(const MaybeString& str) {
auto none = Optional<float>();
if (str.has_value()) {
try {
size_t pos;
float val = std::stof(*str, &pos);
return pos == str->size() ? llvm::Optional<float>(val) : none;
return pos == str->size() ? Optional<float>(val) : none;
} catch (std::invalid_argument) {
}
}
return none;
}

llvm::Optional<bool> to_bool(const MaybeString& str) {
auto none = llvm::Optional<bool>();
Optional<bool> to_bool(const MaybeString& str) {
auto none = Optional<bool>();
if (auto num = to_int(str)) {
if (*num == 0) return false;
if (*num == 1) return true;
Expand All @@ -184,9 +195,9 @@ llvm::Optional<bool> to_bool(const MaybeString& str) {
}

template <typename T>
using MaybeRange = llvm::Optional<std::pair<T, T>>;
using MaybeRange = Optional<std::pair<T, T>>;

template <typename T, llvm::Optional<T> Parse(const MaybeString&)>
template <typename T, Optional<T> Parse(const MaybeString&)>
MaybeRange<T> to_range(const MaybeString& str) {
auto none = MaybeRange<T>();
if (str && !str->empty()) {
Expand All @@ -202,6 +213,72 @@ MaybeRange<T> to_range(const MaybeString& str) {
return none;
}

// Replacement for llvm::StringSwitch.
template <typename T>
class StringSwitch {
public:
explicit StringSwitch(const std::string& key) : key(key) {}
operator T() const {
auto f = map.find(key);
if (f != map.end()) {
return f->second;
}
ICHECK(static_cast<bool>(def_val)) << "default value not set";
return *def_val;
}
StringSwitch& Case(const std::string& key, T val) {
map.insert(std::make_pair(key, val));
return *this;
}
StringSwitch& Default(T val) {
ICHECK(!static_cast<bool>(def_val)) << "default value already set";
def_val = val;
return *this;
}

private:
const std::string key;
std::map<std::string, T> map;
Optional<T> def_val;
};

// Replacement for llvm::sys::fs::access with AccessMode = Execute.
bool FileExists(const std::string& file) { return access(file.c_str(), X_OK) == 0; }

// Replacement for llvm::sys::Process::FindInEnvPath.
MaybeString FindInEnvPath(const std::string& env_var, const std::string& file) {
auto none = MaybeString();
if (file.empty() || file[0] == '/') {
return none;
}

const char* e = getenv(env_var.c_str());
std::string env_val = e != nullptr ? std::string(e) : std::string();

std::vector<std::string> paths;
// Split the environment variable into individual paths.
size_t first = 0, env_size = env_val.size();
for (size_t last = 0; last != env_size; ++last) {
if (env_val[last] == ':') {
if (last > first) {
paths.emplace_back(env_val, first, last - first);
}
first = last + 1;
}
}
if (first < env_size) {
paths.emplace_back(env_val, first, env_size - first);
}

// Search for the file.
for (const std::string& dir : paths) {
std::string full = dir + '/' + file;
if (FileExists(full)) {
return full;
}
}
return none;
}
} // namespace detail

class HexagonSimulator final : public tvm::runtime::hexagon::Device {
Expand Down Expand Up @@ -304,17 +381,17 @@ class HexagonSimulator final : public tvm::runtime::hexagon::Device {
bool HandleV2PTranslation(string_list& rest); // NOLINT(*)
bool HandleVerbose(string_list& rest); // NOLINT(*)

using MaybeUInt64 = llvm::Optional<uint64_t>;
using MaybeUInt64 = detail::Optional<uint64_t>;
using MaybeUIntRange = std::pair<MaybeUInt64, MaybeUInt64>;

bool should_parse_next(const string_list& rest);
llvm::Optional<HEXAPI_Interval> to_interval(const detail::MaybeString& str);
llvm::Optional<HEXAPI_TimingMode> to_timingmode(const detail::MaybeString& str);
llvm::Optional<HEXAPI_VerboseMode> to_verbosemode(const detail::MaybeString& str);
llvm::Optional<HEXAPI_Nullptr> to_nullptr(const detail::MaybeString& str);
detail::Optional<HEXAPI_Interval> to_interval(const detail::MaybeString& str);
detail::Optional<HEXAPI_TimingMode> to_timingmode(const detail::MaybeString& str);
detail::Optional<HEXAPI_VerboseMode> to_verbosemode(const detail::MaybeString& str);
detail::Optional<HEXAPI_Nullptr> to_nullptr(const detail::MaybeString& str);

MaybeUIntRange ahb_, axi2_;
llvm::Optional<uint32_t> debug_port_;
detail::Optional<uint32_t> debug_port_;
detail::non_const_str sim_dev_args_;

using OptionHandler = bool (HexagonSimulator::*)(string_list&);
Expand Down Expand Up @@ -556,13 +633,13 @@ HexagonSimulator::HexagonSimulator(bool enable_queuing) {
LOG(INFO) << "HexagonSimulator: Core version: " << arch_;

// Locate the sim_dev binary in PATH, or in the current working directory.
llvm::StringRef sim_dev = "sim_dev";
detail::MaybeString path_sim_dev = llvm::sys::Process::FindInEnvPath("PATH", sim_dev);
std::string sim_dev = "sim_dev";
detail::MaybeString path_sim_dev = detail::FindInEnvPath("PATH", sim_dev);
if (!path_sim_dev) {
if (!llvm::sys::fs::exists(sim_dev)) {
if (!detail::FileExists(sim_dev)) {
LOG(FATAL) << "Cannot find sim_dev in PATH.";
}
path_sim_dev = sim_dev.str();
path_sim_dev = sim_dev;
}

CHECKED_CALL(ConfigureExecutableBinary, path_sim_dev->c_str());
Expand Down Expand Up @@ -767,19 +844,19 @@ bool HexagonSimulator::Configure(string_list& opts) {
}

// Check AHB.
if (ahb_.first.hasValue() && ahb_.second.hasValue()) {
if (ahb_.first.has_value() && ahb_.second.has_value()) {
CHECKED_CALL(ConfigureAHB, *ahb_.first, *ahb_.second);
} else {
ICHECK(!ahb_.first.hasValue() && !ahb_.second.hasValue())
ICHECK(!ahb_.first.has_value() && !ahb_.second.has_value())
<< "HexagonSimulator: please specify both low and high addresses "
"for AHB";
}

// Check AXI2.
if (axi2_.first.hasValue() && axi2_.second.hasValue()) {
if (axi2_.first.has_value() && axi2_.second.has_value()) {
CHECKED_CALL(ConfigureAXI2, *axi2_.first, *axi2_.second);
} else {
ICHECK(!axi2_.first.hasValue() && !axi2_.second.hasValue())
ICHECK(!axi2_.first.has_value() && !axi2_.second.has_value())
<< "HexagonSimulator: please specify both low and high addresses "
"for AXI2";
}
Expand Down Expand Up @@ -1260,8 +1337,8 @@ bool HexagonSimulator::should_parse_next(const string_list& rest) {
return false;
}

llvm::Optional<HEXAPI_Interval> HexagonSimulator::to_interval(const detail::MaybeString& str) {
auto none = llvm::Optional<HEXAPI_Interval>();
detail::Optional<HEXAPI_Interval> HexagonSimulator::to_interval(const detail::MaybeString& str) {
auto none = detail::Optional<HEXAPI_Interval>();
if (!str) return none;

if (auto val = detail::to_int(*str)) {
Expand All @@ -1275,7 +1352,7 @@ llvm::Optional<HEXAPI_Interval> HexagonSimulator::to_interval(const detail::Mayb
}
}

return llvm::StringSwitch<llvm::Optional<HEXAPI_Interval>>(*str)
return detail::StringSwitch<detail::Optional<HEXAPI_Interval>>(*str)
.Case("MILLISEC", HEX_MILLISEC)
.Case("MICROSEC", HEX_MICROSEC)
.Case("NANOSEC", HEX_NANOSEC)
Expand All @@ -1284,8 +1361,9 @@ llvm::Optional<HEXAPI_Interval> HexagonSimulator::to_interval(const detail::Mayb
.Default(none);
}

llvm::Optional<HEXAPI_TimingMode> HexagonSimulator::to_timingmode(const detail::MaybeString& str) {
auto none = llvm::Optional<HEXAPI_TimingMode>();
detail::Optional<HEXAPI_TimingMode> HexagonSimulator::to_timingmode(
const detail::MaybeString& str) {
auto none = detail::Optional<HEXAPI_TimingMode>();
if (!str) return none;

if (auto val = detail::to_int(*str)) {
Expand All @@ -1298,17 +1376,17 @@ llvm::Optional<HEXAPI_TimingMode> HexagonSimulator::to_timingmode(const detail::
}
}

return llvm::StringSwitch<llvm::Optional<HEXAPI_TimingMode>>(*str)
return detail::StringSwitch<detail::Optional<HEXAPI_TimingMode>>(*str)
.Case("NOTIMING", HEX_NOTIMING)
.Case("TIMING_NODBC", HEX_TIMING_NODBC)
.Case("TIMING", HEX_TIMING)
.Case("TIMING_COHERENCY", HEX_TIMING_COHERENCY)
.Default(none);
}

llvm::Optional<HEXAPI_VerboseMode> HexagonSimulator::to_verbosemode(
detail::Optional<HEXAPI_VerboseMode> HexagonSimulator::to_verbosemode(
const detail::MaybeString& str) {
auto none = llvm::Optional<HEXAPI_VerboseMode>();
auto none = detail::Optional<HEXAPI_VerboseMode>();
if (!str) return none;

if (auto val = detail::to_int(*str)) {
Expand All @@ -1322,7 +1400,7 @@ llvm::Optional<HEXAPI_VerboseMode> HexagonSimulator::to_verbosemode(
}
}

return llvm::StringSwitch<llvm::Optional<HEXAPI_VerboseMode>>(*str)
return detail::StringSwitch<detail::Optional<HEXAPI_VerboseMode>>(*str)
.Case("SILENT", HEX_SILENT)
.Case("QUIET", HEX_QUIET)
.Case("NORMAL", HEX_NORMAL)
Expand All @@ -1331,8 +1409,8 @@ llvm::Optional<HEXAPI_VerboseMode> HexagonSimulator::to_verbosemode(
.Default(none);
}

llvm::Optional<HEXAPI_Nullptr> HexagonSimulator::to_nullptr(const detail::MaybeString& str) {
auto none = llvm::Optional<HEXAPI_Nullptr>();
detail::Optional<HEXAPI_Nullptr> HexagonSimulator::to_nullptr(const detail::MaybeString& str) {
auto none = detail::Optional<HEXAPI_Nullptr>();
if (!str) return none;

if (auto val = detail::to_int(*str)) {
Expand All @@ -1345,7 +1423,7 @@ llvm::Optional<HEXAPI_Nullptr> HexagonSimulator::to_nullptr(const detail::MaybeS
}
}

return llvm::StringSwitch<llvm::Optional<HEXAPI_Nullptr>>(*str)
return detail::StringSwitch<detail::Optional<HEXAPI_Nullptr>>(*str)
.Case("IGNORE", HEX_NULLPTR_IGNORE)
.Case("WARN", HEX_NULLPTR_WARN)
.Case("FATAL", HEX_NULLPTR_FATAL)
Expand Down