///===- 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(PropVal)); break; case 1: J.attribute(PropName, encodeBase64(std::get(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 auto createStringErrorV(Ts &&...Args) { return createStringError(formatv(std::forward(Args)...)); } Expected readPropertyValueFromJSON(const json::Value &PropValueVal) { if (std::optional Val = PropValueVal.getAsUINT64()) return PropertyValue(static_cast(*Val)); if (std::optional Val = PropValueVal.getAsString()) { std::vector 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 llvm::offloading::readPropertiesFromJSON(MemoryBufferRef Buf) { PropertySetRegistry Res; Expected 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 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; }