| 1 | ///===- llvm/Frontend/Offloading/PropertySet.cpp --------------------------===// |
| 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 | |
| 9 | #include "llvm/Frontend/Offloading/PropertySet.h" |
| 10 | #include "llvm/Support/Base64.h" |
| 11 | #include "llvm/Support/JSON.h" |
| 12 | #include "llvm/Support/MemoryBufferRef.h" |
| 13 | |
| 14 | using namespace llvm; |
| 15 | using namespace llvm::offloading; |
| 16 | |
| 17 | void llvm::offloading::writePropertiesToJSON( |
| 18 | const PropertySetRegistry &PSRegistry, raw_ostream &Out) { |
| 19 | json::OStream J(Out); |
| 20 | J.object(Contents: [&] { |
| 21 | for (const auto &[CategoryName, PropSet] : PSRegistry) { |
| 22 | auto PropSetCapture = PropSet; |
| 23 | J.attributeObject(Key: CategoryName, Contents: [&] { |
| 24 | for (const auto &[PropName, PropVal] : PropSetCapture) { |
| 25 | switch (PropVal.index()) { |
| 26 | case 0: |
| 27 | J.attribute(Key: PropName, Contents: std::get<uint32_t>(v: PropVal)); |
| 28 | break; |
| 29 | case 1: |
| 30 | J.attribute(Key: PropName, Contents: encodeBase64(Bytes: std::get<ByteArray>(v: PropVal))); |
| 31 | break; |
| 32 | default: |
| 33 | llvm_unreachable("unsupported property type" ); |
| 34 | } |
| 35 | } |
| 36 | }); |
| 37 | } |
| 38 | }); |
| 39 | } |
| 40 | |
| 41 | // note: createStringError has an overload that takes a format string, |
| 42 | // but it uses llvm::format instead of llvm::formatv, which does |
| 43 | // not work with json::Value. This is a helper function to use |
| 44 | // llvm::formatv with createStringError. |
| 45 | template <typename... Ts> auto createStringErrorV(Ts &&...Args) { |
| 46 | return createStringError(formatv(std::forward<Ts>(Args)...)); |
| 47 | } |
| 48 | |
| 49 | Expected<PropertyValue> |
| 50 | readPropertyValueFromJSON(const json::Value &PropValueVal) { |
| 51 | if (std::optional<uint64_t> Val = PropValueVal.getAsUINT64()) |
| 52 | return PropertyValue(static_cast<uint32_t>(*Val)); |
| 53 | |
| 54 | if (std::optional<StringRef> Val = PropValueVal.getAsString()) { |
| 55 | std::vector<char> Decoded; |
| 56 | if (Error E = decodeBase64(Input: *Val, Output&: Decoded)) |
| 57 | return createStringErrorV(Args: "unable to base64 decode the string {0}: {1}" , |
| 58 | Args&: Val, Args: toString(E: std::move(E))); |
| 59 | return PropertyValue(ByteArray(Decoded.begin(), Decoded.end())); |
| 60 | } |
| 61 | |
| 62 | return createStringErrorV(Args: "expected a uint64 or a string, got {0}" , |
| 63 | Args: PropValueVal); |
| 64 | } |
| 65 | |
| 66 | Expected<PropertySetRegistry> |
| 67 | llvm::offloading::readPropertiesFromJSON(MemoryBufferRef Buf) { |
| 68 | PropertySetRegistry Res; |
| 69 | Expected<json::Value> V = json::parse(JSON: Buf.getBuffer()); |
| 70 | if (Error E = V.takeError()) |
| 71 | return E; |
| 72 | |
| 73 | const json::Object *O = V->getAsObject(); |
| 74 | if (!O) |
| 75 | return createStringErrorV( |
| 76 | Args: "error while deserializing property set registry: " |
| 77 | "expected JSON object, got {0}" , |
| 78 | Args&: *V); |
| 79 | |
| 80 | for (const auto &[CategoryName, Value] : *O) { |
| 81 | const json::Object *PropSetVal = Value.getAsObject(); |
| 82 | if (!PropSetVal) |
| 83 | return createStringErrorV(Args: "error while deserializing property set {0}: " |
| 84 | "expected JSON array, got {1}" , |
| 85 | Args: CategoryName.str(), Args: Value); |
| 86 | |
| 87 | PropertySet &PropSet = Res[CategoryName.str()]; |
| 88 | for (const auto &[PropName, PropValueVal] : *PropSetVal) { |
| 89 | Expected<PropertyValue> Prop = readPropertyValueFromJSON(PropValueVal); |
| 90 | if (Error E = Prop.takeError()) |
| 91 | return createStringErrorV( |
| 92 | Args: "error while deserializing property {0} in property set {1}: {2}" , |
| 93 | Args: PropName.str(), Args: CategoryName.str(), Args: toString(E: std::move(E))); |
| 94 | |
| 95 | auto [It, Inserted] = |
| 96 | PropSet.try_emplace(k: PropName.str(), args: std::move(*Prop)); |
| 97 | assert(Inserted && "Property already exists in PropertySet" ); |
| 98 | (void)Inserted; |
| 99 | } |
| 100 | } |
| 101 | return Res; |
| 102 | } |
| 103 | |