`llvm::Error`s containing errors must be explicitly handled or an assert will be raised. With this change, `ol_impl_result_t` can accept and consume an `llvm::Error` for errors raised by PluginInterface that have multiple causes and other places now call `llvm::consumeError`. Note that there is currently no facility for PluginInterface to communicate exact error codes, but the constructor is designed in such a way that it can be easily added later. This MR is to convert a crash into an error code. A new test was added, however due to the aforementioned issue with error codes, it does not pass and instead is marked as a skip.
110 lines
3.3 KiB
C++
110 lines
3.3 KiB
C++
//===- offload_impl.hpp- Implementation helpers for the Offload library ---===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#pragma once
|
|
|
|
#include <OffloadAPI.h>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
struct OffloadConfig {
|
|
bool TracingEnabled = false;
|
|
bool ValidationEnabled = true;
|
|
};
|
|
|
|
OffloadConfig &offloadConfig();
|
|
|
|
// Use the StringSet container to efficiently deduplicate repeated error
|
|
// strings (e.g. if the same error is hit constantly in a long running program)
|
|
llvm::StringSet<> &errorStrs();
|
|
|
|
// Use an unordered_set to avoid duplicates of error structs themselves.
|
|
// We cannot store the structs directly as returned pointers to them must always
|
|
// be valid, and a rehash of the set may invalidate them. This requires
|
|
// custom hash and equal_to function objects.
|
|
using ErrPtrT = std::unique_ptr<ol_error_struct_t>;
|
|
struct ErrPtrEqual {
|
|
bool operator()(const ErrPtrT &lhs, const ErrPtrT &rhs) const {
|
|
if (!lhs && !rhs) {
|
|
return true;
|
|
}
|
|
if (!lhs || !rhs) {
|
|
return false;
|
|
}
|
|
|
|
bool StrsEqual = false;
|
|
if (lhs->Details == NULL && rhs->Details == NULL) {
|
|
StrsEqual = true;
|
|
} else if (lhs->Details != NULL && rhs->Details != NULL) {
|
|
StrsEqual = (std::strcmp(lhs->Details, rhs->Details) == 0);
|
|
}
|
|
return (lhs->Code == rhs->Code) && StrsEqual;
|
|
}
|
|
};
|
|
struct ErrPtrHash {
|
|
size_t operator()(const ErrPtrT &e) const {
|
|
if (!e) {
|
|
// We shouldn't store empty errors (i.e. success), but just in case
|
|
return 0lu;
|
|
} else {
|
|
return std::hash<int>{}(e->Code);
|
|
}
|
|
}
|
|
};
|
|
using ErrSetT = std::unordered_set<ErrPtrT, ErrPtrHash, ErrPtrEqual>;
|
|
ErrSetT &errors();
|
|
|
|
struct ol_impl_result_t {
|
|
ol_impl_result_t(std::nullptr_t) : Result(OL_SUCCESS) {}
|
|
ol_impl_result_t(ol_errc_t Code) {
|
|
if (Code == OL_ERRC_SUCCESS) {
|
|
Result = nullptr;
|
|
} else {
|
|
auto Err = std::unique_ptr<ol_error_struct_t>(
|
|
new ol_error_struct_t{Code, nullptr});
|
|
Result = errors().emplace(std::move(Err)).first->get();
|
|
}
|
|
}
|
|
|
|
ol_impl_result_t(ol_errc_t Code, llvm::StringRef Details) {
|
|
assert(Code != OL_ERRC_SUCCESS);
|
|
Result = nullptr;
|
|
auto DetailsStr = errorStrs().insert(Details).first->getKeyData();
|
|
auto Err = std::unique_ptr<ol_error_struct_t>(
|
|
new ol_error_struct_t{Code, DetailsStr});
|
|
Result = errors().emplace(std::move(Err)).first->get();
|
|
}
|
|
|
|
static ol_impl_result_t fromError(llvm::Error &&Error) {
|
|
ol_errc_t ErrCode;
|
|
llvm::StringRef Details;
|
|
llvm::handleAllErrors(std::move(Error), [&](llvm::StringError &Err) {
|
|
// TODO: PluginInterface doesn't yet have a way to communicate offload
|
|
// error codes
|
|
ErrCode = OL_ERRC_UNKNOWN;
|
|
Details = errorStrs().insert(Err.getMessage()).first->getKeyData();
|
|
});
|
|
|
|
return ol_impl_result_t{ErrCode, Details};
|
|
}
|
|
|
|
operator ol_result_t() { return Result; }
|
|
|
|
private:
|
|
ol_result_t Result;
|
|
};
|