blob: a05a9cbe74ca86cec9e9ebd30d1c53ad5d682544 [file]
//===- Remarks.cpp - C Interface for the MLIR Remark Engine ---------------===//
//
// 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 "mlir-c/Remarks.h"
#include "mlir/CAPI/IR.h"
#include "mlir/CAPI/Remarks.h"
#include "mlir/CAPI/Support.h"
#include "mlir/CAPI/Utils.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Remarks.h"
#include "mlir/Remark/RemarkStreamer.h"
#include "llvm/Remarks/RemarkFormat.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
using namespace mlir;
using mlir::remark::detail::Remark;
//===----------------------------------------------------------------------===//
// Helpers
//===----------------------------------------------------------------------===//
namespace {
/// A streamer forwarding every reported remark to a C callback.
class CallbackRemarkStreamer : public remark::detail::MLIRRemarkStreamerBase {
public:
CallbackRemarkStreamer(MlirRemarkCallback callback, void *userData,
void (*deleteUserData)(void *))
: callback(callback), userData(userData), deleteUserData(deleteUserData) {
}
~CallbackRemarkStreamer() override {
if (deleteUserData)
deleteUserData(userData);
}
void streamOptimizationRemark(const Remark &remark) override {
callback(wrap(&remark), userData);
}
private:
MlirRemarkCallback callback;
void *userData;
void (*deleteUserData)(void *);
};
} // namespace
/// Every filter reaches the engine as a (possibly empty) string, as with
/// mlir-opt's options: a kind is reported when its own filter or `all` matches.
static remark::RemarkCategories unwrap(MlirRemarkCategories categories) {
return remark::RemarkCategories{
unwrap(categories.all).str(), unwrap(categories.passed).str(),
unwrap(categories.missed).str(), unwrap(categories.analysis).str(),
unwrap(categories.failed).str()};
}
static std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
createPolicy(MlirRemarkPolicy policy) {
switch (policy) {
case MlirRemarkPolicyAll:
return std::make_unique<remark::RemarkEmittingPolicyAll>();
case MlirRemarkPolicyFinal:
return std::make_unique<remark::RemarkEmittingPolicyFinal>();
}
llvm_unreachable("unknown remark policy");
}
static llvm::remarks::Format unwrap(MlirRemarkFileFormat format) {
switch (format) {
case MlirRemarkFileFormatYAML:
return llvm::remarks::Format::YAML;
case MlirRemarkFileFormatBitstream:
return llvm::remarks::Format::Bitstream;
}
llvm_unreachable("unknown remark file format");
}
static MlirRemarkKind wrap(remark::RemarkKind kind) {
switch (kind) {
case remark::RemarkKind::RemarkUnknown:
return MlirRemarkKindUnknown;
case remark::RemarkKind::RemarkPassed:
return MlirRemarkKindPassed;
case remark::RemarkKind::RemarkMissed:
return MlirRemarkKindMissed;
case remark::RemarkKind::RemarkFailure:
return MlirRemarkKindFailure;
case remark::RemarkKind::RemarkAnalysis:
return MlirRemarkKindAnalysis;
}
llvm_unreachable("unknown remark kind");
}
//===----------------------------------------------------------------------===//
// Enabling and finalizing
//===----------------------------------------------------------------------===//
MlirLogicalResult mlirContextEnableOptimizationRemarks(
MlirContext context, MlirRemarkCategories categories,
MlirRemarkPolicy policy, bool printAsEmitRemarks) {
MLIRContext *ctx = unwrap(context);
if (ctx->getRemarkEngine())
return mlirLogicalResultFailure();
return wrap(remark::enableOptimizationRemarks(
*ctx, /*streamer=*/nullptr, createPolicy(policy), unwrap(categories),
printAsEmitRemarks));
}
MlirLogicalResult mlirContextEnableOptimizationRemarksToFile(
MlirContext context, MlirRemarkCategories categories,
MlirRemarkPolicy policy, MlirRemarkFileFormat format, MlirStringRef path,
bool printAsEmitRemarks) {
MLIRContext *ctx = unwrap(context);
if (ctx->getRemarkEngine())
return mlirLogicalResultFailure();
return wrap(remark::enableOptimizationRemarksWithLLVMStreamer(
*ctx, unwrap(path), unwrap(format), createPolicy(policy),
unwrap(categories), printAsEmitRemarks));
}
MlirLogicalResult mlirContextEnableOptimizationRemarksWithCallback(
MlirContext context, MlirRemarkCategories categories,
MlirRemarkPolicy policy, MlirRemarkCallback callback, void *userData,
void (*deleteUserData)(void *), bool printAsEmitRemarks) {
assert(callback && "unexpected null remark callback");
MLIRContext *ctx = unwrap(context);
if (ctx->getRemarkEngine()) {
// The caller handed over `userData`; release it as on success.
if (deleteUserData)
deleteUserData(userData);
return mlirLogicalResultFailure();
}
return wrap(remark::enableOptimizationRemarks(
*ctx,
std::make_unique<CallbackRemarkStreamer>(callback, userData,
deleteUserData),
createPolicy(policy), unwrap(categories), printAsEmitRemarks));
}
void mlirContextFinalizeOptimizationRemarks(MlirContext context) {
// The engine destructor reports the postponed remarks, then destroys the
// streamer.
unwrap(context)->setRemarkEngine(nullptr);
}
bool mlirContextHasRemarkEngine(MlirContext context) {
return unwrap(context)->getRemarkEngine() != nullptr;
}
//===----------------------------------------------------------------------===//
// Remark accessors
//===----------------------------------------------------------------------===//
MlirRemarkKind mlirRemarkGetKind(MlirRemark remark) {
return wrap(unwrap(remark)->getRemarkKind());
}
MlirStringRef mlirRemarkGetRemarkName(MlirRemark remark) {
return wrap(unwrap(remark)->getRemarkName());
}
MlirStringRef mlirRemarkGetCategoryName(MlirRemark remark) {
return wrap(unwrap(remark)->getCategoryName());
}
MlirStringRef mlirRemarkGetFullCategoryName(MlirRemark remark) {
return wrap(unwrap(remark)->getCombinedCategoryName());
}
MlirStringRef mlirRemarkGetFunctionName(MlirRemark remark) {
return wrap(unwrap(remark)->getFunction());
}
MlirLocation mlirRemarkGetLocation(MlirRemark remark) {
return wrap(unwrap(remark)->getLocation());
}
uint64_t mlirRemarkGetId(MlirRemark remark) {
return unwrap(remark)->getId().getValue();
}
intptr_t mlirRemarkGetNumArgs(MlirRemark remark) {
return static_cast<intptr_t>(unwrap(remark)->getArgs().size());
}
MlirStringRef mlirRemarkGetArgKey(MlirRemark remark, intptr_t pos) {
ArrayRef<Remark::Arg> args = unwrap(remark)->getArgs();
assert(pos >= 0 && static_cast<size_t>(pos) < args.size() &&
"remark argument index out of range");
return wrap(llvm::StringRef(args[pos].key));
}
MlirStringRef mlirRemarkGetArgValue(MlirRemark remark, intptr_t pos) {
ArrayRef<Remark::Arg> args = unwrap(remark)->getArgs();
assert(pos >= 0 && static_cast<size_t>(pos) < args.size() &&
"remark argument index out of range");
return wrap(llvm::StringRef(args[pos].val));
}
void mlirRemarkPrint(MlirRemark remark, MlirStringCallback callback,
void *userData) {
detail::CallbackOstream stream(callback, userData);
unwrap(remark)->print(stream);
}
//===----------------------------------------------------------------------===//
// Emission
//===----------------------------------------------------------------------===//
bool mlirEmitOptimizationRemark(
MlirLocation location, MlirRemarkKind kind, MlirStringRef remarkName,
MlirStringRef categoryName, MlirStringRef subCategoryName,
MlirStringRef functionName, MlirStringRef message, intptr_t numArgs,
const MlirStringRef *argKeys, const MlirStringRef *argValues) {
assert((numArgs == 0 || (argKeys && argValues)) &&
"remark arguments require both keys and values");
Location loc = unwrap(location);
remark::RemarkOpts opts = remark::RemarkOpts::name(unwrap(remarkName))
.category(unwrap(categoryName))
.subCategory(unwrap(subCategoryName))
.function(unwrap(functionName));
remark::detail::InFlightRemark inFlight;
switch (kind) {
case MlirRemarkKindUnknown:
return false;
case MlirRemarkKindPassed:
inFlight = remark::passed(loc, opts);
break;
case MlirRemarkKindMissed:
inFlight = remark::missed(loc, opts);
break;
case MlirRemarkKindFailure:
inFlight = remark::failed(loc, opts);
break;
case MlirRemarkKindAnalysis:
inFlight = remark::analysis(loc, opts);
break;
}
if (!inFlight)
return false;
if (message.length != 0)
inFlight << unwrap(message);
for (intptr_t i = 0; i < numArgs; ++i)
inFlight << Remark::Arg(unwrap(argKeys[i]), unwrap(argValues[i]));
// The remark is reported when `inFlight` goes out of scope.
return true;
}