| ///===- llvm/Frontend/Offloading/PropertySet.cpp --------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Frontend/Offloading/PropertySet.h" |
| #include "llvm/Support/Base64.h" |
| #include "llvm/Support/JSON.h" |
| #include "llvm/Support/MemoryBufferRef.h" |
| |
| using namespace llvm; |
| using namespace llvm::offloading; |
| |
| void llvm::offloading::writePropertiesToJSON( |
| const PropertySetRegistry &PSRegistry, raw_ostream &Out) { |
| json::OStream J(Out); |
| J.object([&] { |
| for (const auto &[CategoryName, PropSet] : PSRegistry) { |
| auto PropSetCapture = PropSet; |
| J.attributeObject(CategoryName, [&] { |
| for (const auto &[PropName, PropVal] : PropSetCapture) { |
| switch (PropVal.index()) { |
| case 0: |
| J.attribute(PropName, std::get<uint32_t>(PropVal)); |
| break; |
| case 1: |
| J.attribute(PropName, encodeBase64(std::get<ByteArray>(PropVal))); |
| break; |
| default: |
| llvm_unreachable("unsupported property type"); |
| } |
| } |
| }); |
| } |
| }); |
| } |
| |
| // note: createStringError has an overload that takes a format string, |
| // but it uses llvm::format instead of llvm::formatv, which does |
| // not work with json::Value. This is a helper function to use |
| // llvm::formatv with createStringError. |
| template <typename... Ts> auto createStringErrorV(Ts &&...Args) { |
| return createStringError(formatv(std::forward<Ts>(Args)...)); |
| } |
| |
| Expected<PropertyValue> |
| readPropertyValueFromJSON(const json::Value &PropValueVal) { |
| if (std::optional<uint64_t> Val = PropValueVal.getAsUINT64()) |
| return PropertyValue(static_cast<uint32_t>(*Val)); |
| |
| if (std::optional<StringRef> Val = PropValueVal.getAsString()) { |
| std::vector<char> Decoded; |
| if (Error E = decodeBase64(*Val, Decoded)) |
| return createStringErrorV("unable to base64 decode the string {0}: {1}", |
| Val, toString(std::move(E))); |
| return PropertyValue(ByteArray(Decoded.begin(), Decoded.end())); |
| } |
| |
| return createStringErrorV("expected a uint64 or a string, got {0}", |
| PropValueVal); |
| } |
| |
| Expected<PropertySetRegistry> |
| llvm::offloading::readPropertiesFromJSON(MemoryBufferRef Buf) { |
| PropertySetRegistry Res; |
| Expected<json::Value> V = json::parse(Buf.getBuffer()); |
| if (Error E = V.takeError()) |
| return E; |
| |
| const json::Object *O = V->getAsObject(); |
| if (!O) |
| return createStringErrorV( |
| "error while deserializing property set registry: " |
| "expected JSON object, got {0}", |
| *V); |
| |
| for (const auto &[CategoryName, Value] : *O) { |
| const json::Object *PropSetVal = Value.getAsObject(); |
| if (!PropSetVal) |
| return createStringErrorV("error while deserializing property set {0}: " |
| "expected JSON array, got {1}", |
| CategoryName.str(), Value); |
| |
| PropertySet &PropSet = Res[CategoryName.str()]; |
| for (const auto &[PropName, PropValueVal] : *PropSetVal) { |
| Expected<PropertyValue> Prop = readPropertyValueFromJSON(PropValueVal); |
| if (Error E = Prop.takeError()) |
| return createStringErrorV( |
| "error while deserializing property {0} in property set {1}: {2}", |
| PropName.str(), CategoryName.str(), toString(std::move(E))); |
| |
| auto [It, Inserted] = |
| PropSet.try_emplace(PropName.str(), std::move(*Prop)); |
| assert(Inserted && "Property already exists in PropertySet"); |
| (void)Inserted; |
| } |
| } |
| return Res; |
| } |