Add convention for lexer if the last file is contained in the first, then the first is used for error reporting. This requires that these two overlap to make it easy to find the corresponding spots. Enables going from ``` within split at mlir/test/IR/invalid.mlir::10 offset :6:9: error: reference to an undefined block ``` to ``` mlir/test/IR/invalid.mlir:15:9: error: reference to an undefined block ``` This does change the split to not produce always null terminated buffers and tools that need it, need to do so themselves (which is mostly by copying - this may have little actual impact as previously this was a copy too).
116 lines
4.8 KiB
C++
116 lines
4.8 KiB
C++
//===- 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);
|
|
}
|