| //===- 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 "PluginInterface.h" | |
| #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" | |
| namespace llvm { | |
| namespace offload { | |
| bool isTracingEnabled(); | |
| bool isValidationEnabled(); | |
| bool isOffloadInitialized(); | |
| } // namespace offload | |
| } // namespace llvm | |
| // 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(); | |
| namespace { | |
| ol_errc_t GetErrorCode(std::error_code Code) { | |
| if (Code.category() == | |
| error::make_error_code(error::ErrorCode::SUCCESS).category()) | |
| return static_cast<ol_errc_t>(Code.value()); | |
| return OL_ERRC_UNKNOWN; | |
| } | |
| } // namespace | |
| inline ol_result_t llvmErrorToOffloadError(llvm::Error &&Err) { | |
| if (!Err) { | |
| // No error | |
| return nullptr; | |
| } | |
| ol_errc_t ErrCode; | |
| llvm::StringRef Details; | |
| llvm::handleAllErrors(std::move(Err), [&](llvm::StringError &Err) { | |
| ErrCode = GetErrorCode(Err.convertToErrorCode()); | |
| Details = errorStrs().insert(Err.getMessage()).first->getKeyData(); | |
| }); | |
| auto NewErr = std::unique_ptr<ol_error_struct_t>( | |
| new ol_error_struct_t{ErrCode, Details.data()}); | |
| return errors().emplace(std::move(NewErr)).first->get(); | |
| } |