| //===- 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" | |
| struct OffloadConfig { | |
| bool TracingEnabled = false; | |
| }; | |
| 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(); | |
| } | |
| operator ol_result_t() { return Result; } | |
| private: | |
| ol_result_t Result; | |
| }; |