blob: 2dbb50569b2c2cc18864aca007f4e4a1b5ca437d [file] [log] [blame]
// Copyright 2020 The IREE Authors
//
// Licensed 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 "iree/compiler/Utils/FlatbufferUtils.h"
#include <assert.h>
#include <stdlib.h>
#include <cstdint>
#include <type_traits>
#include "mlir/IR/BuiltinTypes.h"
namespace mlir {
namespace iree_compiler {
// Combines all pages of the FlatBuffer builder into a single contiguous byte
// buffer and returns the result.
//
// NOTE: this is a alloc/copy. We need to have a single contiguous buffer to
// pass into the elements factory function and the data we have in the
// builder is paged. If we end up with a custom attribute type for this that
// does not support storage uniquing then we can directly allocate and copy
// the pages into the buffer without the extra copy.
static SmallVector<uint8_t, 32> cloneBufferIntoContiguousBytes(
FlatbufferBuilder &fbb) {
size_t packedSize = flatcc_builder_get_buffer_size(fbb);
SmallVector<uint8_t, 32> packedData(packedSize);
void *result =
flatcc_builder_copy_buffer(fbb, packedData.data(), packedData.size());
assert(result && "flatcc_emitter_t impl failed (non-default?)");
(void)result;
return packedData;
}
FlatbufferBuilder::FlatbufferBuilder() { flatcc_builder_init(&builder); }
FlatbufferBuilder::~FlatbufferBuilder() { flatcc_builder_clear(&builder); }
flatbuffers_uint8_vec_ref_t FlatbufferBuilder::streamUint8Vec(
std::function<bool(raw_ostream &stream)> fn, size_t alignment) {
flatcc_builder_start_vector(*this, 1, alignment, FLATBUFFERS_COUNT_MAX(1));
raw_flatbuffer_uint8_vec_ostream stream(*this);
if (!fn(stream)) {
return 0;
}
stream.flush();
return flatbuffers_uint8_vec_end(*this);
}
DenseIntElementsAttr FlatbufferBuilder::getBufferAttr(MLIRContext *context) {
// We require direct access to the FlatBuffer bytes so we can pass them to
// the attribute constructor (which needs to inspect them all for uniquing).
auto bufferData = cloneBufferIntoContiguousBytes(*this);
// NOTE: ew. OpaqueAttr may be better? It does equality checks but won't try
// to unique and would let us get a mutable buffer out.
return DenseIntElementsAttr::get(
VectorType::get({static_cast<int64_t>(bufferData.size())},
IntegerType::get(context, 8)),
std::move(bufferData));
}
LogicalResult FlatbufferBuilder::copyToStream(llvm::raw_ostream &output) {
// NOTE: expected to be the default emitter.
auto *E = reinterpret_cast<flatcc_emitter_t *>(
flatcc_builder_get_emit_context(*this));
if (!E->front) {
return failure();
}
if (E->front == E->back) {
output.write(reinterpret_cast<char *>(E->front_cursor), E->used);
return success();
}
size_t len = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
output.write(reinterpret_cast<char *>(E->front_cursor), len);
flatcc_emitter_page_t *p = E->front->next;
while (p != E->back) {
output.write(reinterpret_cast<char *>(p->page), FLATCC_EMITTER_PAGE_SIZE);
p = p->next;
}
output.write(reinterpret_cast<char *>(p->page),
FLATCC_EMITTER_PAGE_SIZE - E->back_left);
return success();
}
LogicalResult FlatbufferBuilder::printJsonToStream(bool pretty,
bool includeDefaults,
print_json_fn_t printJsonFn,
llvm::raw_ostream &output) {
// The printer requires direct access to the FlatBuffer bytes so clone here.
auto bufferData = cloneBufferIntoContiguousBytes(*this);
auto moduleData = ArrayRef<uint8_t>(bufferData.data(), bufferData.size())
.drop_front(sizeof(flatbuffers_uoffset_t));
flatcc_json_printer_t printer;
flatcc_json_printer_init_dynamic_buffer(&printer, /*buffer_size=*/0);
flatcc_json_printer_set_indent(&printer, pretty ? 2 : 0);
flatcc_json_printer_set_skip_default(&printer, !includeDefaults);
flatcc_json_printer_set_force_default(&printer, includeDefaults);
// Print into the dynamically-resizing buffer. May fail if OOM.
int rv =
printJsonFn(&printer, reinterpret_cast<const char *>(moduleData.data()),
moduleData.size());
if (rv == -1) {
flatcc_json_printer_clear(&printer);
return failure();
}
// Take the buffer from the printer; note that it is 0 terminated and can be
// used directly as a cstr if needed.
size_t outputSize = 0;
char *outputBytes = reinterpret_cast<char *>(
flatcc_json_printer_finalize_dynamic_buffer(&printer, &outputSize));
output.write(outputBytes, outputSize);
free(outputBytes);
return success();
}
} // namespace iree_compiler
} // namespace mlir