| //===- ToolUtilities.cpp - MLIR Tool Utilities ----------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines common utilities for implementing MLIR tools. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/Support/ToolUtilities.h" |
| #include "mlir/Support/LLVM.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <string> |
| #include <utility> |
| |
| using namespace mlir; |
| |
| LogicalResult |
| mlir::splitAndProcessBuffer(std::unique_ptr<llvm::MemoryBuffer> originalBuffer, |
| ChunkBufferHandler processChunkBuffer, |
| raw_ostream &os, llvm::StringRef inputSplitMarker, |
| llvm::StringRef outputSplitMarker) { |
| llvm::MemoryBufferRef originalBufferRef = originalBuffer->getMemBufferRef(); |
| // If splitting is disabled, we process the full input buffer. |
| if (inputSplitMarker.empty()) |
| return processChunkBuffer(std::move(originalBuffer), originalBufferRef, os); |
| |
| const int inputSplitMarkerLen = inputSplitMarker.size(); |
| |
| SmallVector<StringRef, 8> rawSourceBuffers; |
| const int checkLen = 2; |
| // Split dropping the last checkLen chars to enable flagging near misses. |
| originalBufferRef.getBuffer().split(rawSourceBuffers, |
| inputSplitMarker.drop_back(checkLen)); |
| if (rawSourceBuffers.empty()) |
| return success(); |
| |
| // Add the original buffer to the source manager. |
| llvm::SourceMgr fileSourceMgr; |
| fileSourceMgr.AddNewSourceBuffer(std::move(originalBuffer), SMLoc()); |
| |
| // Flag near misses by iterating over all the sub-buffers found when splitting |
| // with the prefix of the splitMarker. Use a sliding window where we only add |
| // a buffer as a sourceBuffer if terminated by a full match of the |
| // splitMarker, else flag a warning (if near miss) and extend the size of the |
| // buffer under consideration. |
| SmallVector<StringRef, 8> sourceBuffers; |
| StringRef prev; |
| for (auto buffer : rawSourceBuffers) { |
| if (prev.empty()) { |
| prev = buffer; |
| continue; |
| } |
| |
| // Check that suffix is as expected and doesn't have any dash post. |
| bool expectedSuffix = |
| buffer.starts_with(inputSplitMarker.take_back(checkLen)) && |
| buffer.size() > checkLen && buffer[checkLen] != '0'; |
| if (expectedSuffix) { |
| sourceBuffers.push_back(prev); |
| prev = buffer.drop_front(checkLen); |
| } else { |
| // TODO: Consider making this a failure. |
| auto splitLoc = SMLoc::getFromPointer(buffer.data()); |
| fileSourceMgr.PrintMessage(llvm::errs(), splitLoc, |
| llvm::SourceMgr::DK_Warning, |
| "near miss with file split marker"); |
| prev = StringRef(prev.data(), prev.size() + inputSplitMarkerLen - |
| checkLen + buffer.size()); |
| } |
| } |
| if (!prev.empty()) |
| sourceBuffers.push_back(prev); |
| |
| // Process each chunk in turn. |
| bool hadFailure = false; |
| auto interleaveFn = [&](StringRef subBuffer) { |
| auto splitLoc = SMLoc::getFromPointer(subBuffer.data()); |
| unsigned splitLine = fileSourceMgr.getLineAndColumn(splitLoc).first; |
| std::string name((Twine("within split at ") + |
| originalBufferRef.getBufferIdentifier() + ":" + |
| Twine(splitLine) + " offset ") |
| .str()); |
| // Use MemoryBufferRef to avoid copying the buffer & keep at same location |
| // relative to the original buffer. |
| auto subMemBuffer = |
| llvm::MemoryBuffer::getMemBuffer(llvm::MemoryBufferRef(subBuffer, name), |
| /*RequiresNullTerminator=*/false); |
| if (failed( |
| processChunkBuffer(std::move(subMemBuffer), originalBufferRef, os))) |
| hadFailure = true; |
| }; |
| llvm::interleave(sourceBuffers, os, interleaveFn, |
| (llvm::Twine(outputSplitMarker) + "\n").str()); |
| |
| // If any fails, then return a failure of the tool. |
| return failure(hadFailure); |
| } |
| |
| LogicalResult |
| mlir::splitAndProcessBuffer(std::unique_ptr<llvm::MemoryBuffer> originalBuffer, |
| NoSourceChunkBufferHandler processChunkBuffer, |
| raw_ostream &os, llvm::StringRef inputSplitMarker, |
| llvm::StringRef outputSplitMarker) { |
| auto process = [&](std::unique_ptr<llvm::MemoryBuffer> chunkBuffer, |
| const llvm::MemoryBufferRef &, raw_ostream &os) { |
| return processChunkBuffer(std::move(chunkBuffer), os); |
| }; |
| return splitAndProcessBuffer(std::move(originalBuffer), process, os, |
| inputSplitMarker, outputSplitMarker); |
| } |