xref: /llvm-project/offload/liboffload/include/OffloadImpl.hpp (revision fd3907ccb583df99e9c19d2fe84e4e7c52d75de9)
1 //===- offload_impl.hpp- Implementation helpers for the Offload library ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #pragma once
9 
10 #include <OffloadAPI.h>
11 #include <iostream>
12 #include <memory>
13 #include <optional>
14 #include <set>
15 #include <string>
16 #include <unordered_set>
17 #include <vector>
18 
19 #include "llvm/ADT/DenseSet.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/ADT/StringSet.h"
22 
23 struct OffloadConfig {
24   bool TracingEnabled = false;
25 };
26 
27 OffloadConfig &offloadConfig();
28 
29 // Use the StringSet container to efficiently deduplicate repeated error
30 // strings (e.g. if the same error is hit constantly in a long running program)
31 llvm::StringSet<> &errorStrs();
32 
33 // Use an unordered_set to avoid duplicates of error structs themselves.
34 // We cannot store the structs directly as returned pointers to them must always
35 // be valid, and a rehash of the set may invalidate them. This requires
36 // custom hash and equal_to function objects.
37 using ErrPtrT = std::unique_ptr<ol_error_struct_t>;
38 struct ErrPtrEqual {
39   bool operator()(const ErrPtrT &lhs, const ErrPtrT &rhs) const {
40     if (!lhs && !rhs) {
41       return true;
42     }
43     if (!lhs || !rhs) {
44       return false;
45     }
46 
47     bool StrsEqual = false;
48     if (lhs->Details == NULL && rhs->Details == NULL) {
49       StrsEqual = true;
50     } else if (lhs->Details != NULL && rhs->Details != NULL) {
51       StrsEqual = (std::strcmp(lhs->Details, rhs->Details) == 0);
52     }
53     return (lhs->Code == rhs->Code) && StrsEqual;
54   }
55 };
56 struct ErrPtrHash {
57   size_t operator()(const ErrPtrT &e) const {
58     if (!e) {
59       // We shouldn't store empty errors (i.e. success), but just in case
60       return 0lu;
61     } else {
62       return std::hash<int>{}(e->Code);
63     }
64   }
65 };
66 using ErrSetT = std::unordered_set<ErrPtrT, ErrPtrHash, ErrPtrEqual>;
67 ErrSetT &errors();
68 
69 struct ol_impl_result_t {
70   ol_impl_result_t(std::nullptr_t) : Result(OL_SUCCESS) {}
71   ol_impl_result_t(ol_errc_t Code) {
72     if (Code == OL_ERRC_SUCCESS) {
73       Result = nullptr;
74     } else {
75       auto Err = std::unique_ptr<ol_error_struct_t>(
76           new ol_error_struct_t{Code, nullptr});
77       Result = errors().emplace(std::move(Err)).first->get();
78     }
79   }
80 
81   ol_impl_result_t(ol_errc_t Code, llvm::StringRef Details) {
82     assert(Code != OL_ERRC_SUCCESS);
83     Result = nullptr;
84     auto DetailsStr = errorStrs().insert(Details).first->getKeyData();
85     auto Err = std::unique_ptr<ol_error_struct_t>(
86         new ol_error_struct_t{Code, DetailsStr});
87     Result = errors().emplace(std::move(Err)).first->get();
88   }
89 
90   operator ol_result_t() { return Result; }
91 
92 private:
93   ol_result_t Result;
94 };
95