272 lines
9.4 KiB
C++
272 lines
9.4 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 generating C++ from tablegen
|
|
// structures.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_TABLEGEN_CODEGENHELPERS_H
|
|
#define MLIR_TABLEGEN_CODEGENHELPERS_H
|
|
|
|
#include "mlir/TableGen/Constraint.h"
|
|
#include "mlir/TableGen/Dialect.h"
|
|
#include "mlir/TableGen/Format.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/MapVector.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/TableGen/CodeGenHelpers.h"
|
|
#include <utility>
|
|
|
|
namespace llvm {
|
|
class RecordKeeper;
|
|
} // namespace llvm
|
|
|
|
namespace mlir {
|
|
namespace tblgen {
|
|
class Constraint;
|
|
class DagLeaf;
|
|
|
|
// Format into a std::string
|
|
template <typename... Parameters>
|
|
std::string strfmt(const char *fmt, Parameters &&...parameters) {
|
|
return llvm::formatv(fmt, std::forward<Parameters>(parameters)...).str();
|
|
}
|
|
|
|
// A helper RAII class to emit nested namespaces for a dialect.
|
|
class DialectNamespaceEmitter {
|
|
public:
|
|
DialectNamespaceEmitter(raw_ostream &os, const Dialect &dialect) {
|
|
if (!dialect)
|
|
return;
|
|
nsEmitter.emplace(os, dialect.getCppNamespace());
|
|
}
|
|
|
|
private:
|
|
std::optional<llvm::NamespaceEmitter> nsEmitter;
|
|
};
|
|
|
|
/// This class represents how an error stream string being constructed will be
|
|
/// consumed.
|
|
enum class ErrorStreamType {
|
|
// Inside a string that's streamed into an InflightDiagnostic.
|
|
InString,
|
|
// Inside a string inside an OpError.
|
|
InsideOpError,
|
|
};
|
|
|
|
/// This class deduplicates shared operation verification code by emitting
|
|
/// static functions alongside the op definitions. These methods are local to
|
|
/// the definition file, and are invoked within the operation verify methods.
|
|
/// An example is shown below:
|
|
///
|
|
/// static LogicalResult localVerify(...)
|
|
///
|
|
/// LogicalResult OpA::verify(...) {
|
|
/// if (failed(localVerify(...)))
|
|
/// return failure();
|
|
/// ...
|
|
/// }
|
|
///
|
|
/// LogicalResult OpB::verify(...) {
|
|
/// if (failed(localVerify(...)))
|
|
/// return failure();
|
|
/// ...
|
|
/// }
|
|
///
|
|
class StaticVerifierFunctionEmitter {
|
|
public:
|
|
/// Create a constraint uniquer with a unique prefix derived from the record
|
|
/// keeper with an optional tag.
|
|
StaticVerifierFunctionEmitter(raw_ostream &os,
|
|
const llvm::RecordKeeper &records,
|
|
StringRef tag = "");
|
|
|
|
/// Collect and unique all the constraints used by operations.
|
|
void collectOpConstraints(ArrayRef<const llvm::Record *> opDefs);
|
|
|
|
/// Collect and unique all compatible type, attribute, successor, and region
|
|
/// constraints from the operations in the file and emit them at the top of
|
|
/// the generated file.
|
|
///
|
|
/// Constraints that do not meet the restriction that they can only reference
|
|
/// `$_self` and `$_op` are not uniqued.
|
|
void emitOpConstraints();
|
|
|
|
/// Unique all compatible type and attribute constraints from a pattern file
|
|
/// and emit them at the top of the generated file.
|
|
///
|
|
/// Constraints that do not meet the restriction that they can only reference
|
|
/// `$_self`, `$_op`, and `$_builder` are not uniqued.
|
|
void emitPatternConstraints(const ArrayRef<DagLeaf> constraints);
|
|
|
|
/// Get the name of the static function used for the given type constraint.
|
|
/// These functions are used for operand and result constraints and have the
|
|
/// form:
|
|
///
|
|
/// LogicalResult(Operation *op, Type type, StringRef valueKind,
|
|
/// unsigned valueIndex);
|
|
///
|
|
/// Pattern constraints have the form:
|
|
///
|
|
/// LogicalResult(PatternRewriter &rewriter, Operation *op, Type type,
|
|
/// StringRef failureStr);
|
|
///
|
|
StringRef getTypeConstraintFn(const Constraint &constraint) const;
|
|
|
|
/// Get the name of the static function used for the given attribute
|
|
/// constraint. These functions are in the form:
|
|
///
|
|
/// LogicalResult(Operation *op, Attribute attr, StringRef attrName);
|
|
///
|
|
/// If a uniqued constraint was not found, this function returns std::nullopt.
|
|
/// The uniqued constraints cannot be used in the context of an OpAdaptor.
|
|
///
|
|
/// Pattern constraints have the form:
|
|
///
|
|
/// LogicalResult(PatternRewriter &rewriter, Operation *op, Attribute attr,
|
|
/// StringRef failureStr);
|
|
///
|
|
std::optional<StringRef>
|
|
getAttrConstraintFn(const Constraint &constraint) const;
|
|
|
|
/// Get the name of the static function used for the given property
|
|
/// constraint. These functions are in the form:
|
|
///
|
|
/// LogicalResult(Operation *op, T property, StringRef propName);
|
|
///
|
|
/// where T is the interface type specified in the constraint.
|
|
/// If a uniqued constraint was not found, this function returns std::nullopt.
|
|
/// The uniqued constraints cannot be used in the context of an OpAdaptor.
|
|
///
|
|
/// Pattern constraints have the form:
|
|
///
|
|
/// LogicalResult(PatternRewriter &rewriter, Operation *op, T property,
|
|
/// StringRef failureStr);
|
|
///
|
|
std::optional<StringRef>
|
|
getPropConstraintFn(const Constraint &constraint) const;
|
|
|
|
/// Get the name of the static function used for the given successor
|
|
/// constraint. These functions are in the form:
|
|
///
|
|
/// LogicalResult(Operation *op, Block *successor, StringRef successorName,
|
|
/// unsigned successorIndex);
|
|
///
|
|
StringRef getSuccessorConstraintFn(const Constraint &constraint) const;
|
|
|
|
/// Get the name of the static function used for the given region constraint.
|
|
/// These functions are in the form:
|
|
///
|
|
/// LogicalResult(Operation *op, Region ®ion, StringRef regionName,
|
|
/// unsigned regionIndex);
|
|
///
|
|
/// The region name may be empty.
|
|
StringRef getRegionConstraintFn(const Constraint &constraint) const;
|
|
|
|
private:
|
|
/// Emit static type constraint functions.
|
|
void emitTypeConstraints();
|
|
/// Emit static attribute constraint functions.
|
|
void emitAttrConstraints();
|
|
/// Emit static property constraint functions.
|
|
void emitPropConstraints();
|
|
/// Emit static successor constraint functions.
|
|
void emitSuccessorConstraints();
|
|
/// Emit static region constraint functions.
|
|
void emitRegionConstraints();
|
|
|
|
/// Emit pattern constraints.
|
|
void emitPatternConstraints();
|
|
|
|
/// Collect and unique all pattern constraints.
|
|
void collectPatternConstraints(ArrayRef<DagLeaf> constraints);
|
|
|
|
/// The output stream.
|
|
raw_ostream &os;
|
|
|
|
/// A unique label for the file currently being generated. This is used to
|
|
/// ensure that the static functions have a unique name.
|
|
std::string uniqueOutputLabel;
|
|
|
|
/// Use a MapVector to ensure that functions are generated deterministically.
|
|
using ConstraintMap = llvm::MapVector<Constraint, std::string,
|
|
llvm::DenseMap<Constraint, unsigned>>;
|
|
|
|
/// A generic function to emit constraints
|
|
void emitConstraints(const ConstraintMap &constraints, StringRef selfName,
|
|
const char *codeTemplate,
|
|
ErrorStreamType errorStreamType);
|
|
|
|
/// Assign a unique name to a unique constraint.
|
|
std::string getUniqueName(StringRef kind, unsigned index);
|
|
/// Unique a constraint in the map.
|
|
void collectConstraint(ConstraintMap &map, StringRef kind,
|
|
Constraint constraint);
|
|
|
|
/// The set of type constraints used for operand and result verification in
|
|
/// the current file.
|
|
ConstraintMap typeConstraints;
|
|
/// The set of attribute constraints used in the current file.
|
|
ConstraintMap attrConstraints;
|
|
/// The set of property constraints used in the current file.
|
|
ConstraintMap propConstraints;
|
|
/// The set of successor constraints used in the current file.
|
|
ConstraintMap successorConstraints;
|
|
/// The set of region constraints used in the current file.
|
|
ConstraintMap regionConstraints;
|
|
};
|
|
|
|
/// Escape a string using C++ encoding. E.g. foo"bar -> foo\x22bar.
|
|
std::string escapeString(StringRef value);
|
|
|
|
namespace detail {
|
|
template <typename>
|
|
struct stringifier {
|
|
template <typename T>
|
|
static std::string apply(T &&t) {
|
|
return std::string(std::forward<T>(t));
|
|
}
|
|
};
|
|
template <>
|
|
struct stringifier<Twine> {
|
|
static std::string apply(const Twine &twine) { return twine.str(); }
|
|
};
|
|
template <typename OptionalT>
|
|
struct stringifier<std::optional<OptionalT>> {
|
|
static std::string apply(std::optional<OptionalT> optional) {
|
|
return optional ? stringifier<OptionalT>::apply(*optional) : std::string();
|
|
}
|
|
};
|
|
} // namespace detail
|
|
|
|
/// Generically convert a value to a std::string.
|
|
template <typename T>
|
|
std::string stringify(T &&t) {
|
|
return detail::stringifier<std::remove_reference_t<std::remove_const_t<T>>>::
|
|
apply(std::forward<T>(t));
|
|
}
|
|
|
|
/// Helper to generate a C++ streaming error message from a given message.
|
|
/// Message can contain '{{...}}' placeholders that are substituted with
|
|
/// C-expressions via tgfmt. It would effectively convert:
|
|
/// "failed to verify {{foo}}"
|
|
/// into:
|
|
/// "failed to verify " << bar
|
|
/// where bar is the result of evaluating 'tgfmt("foo", &ctx)' at compile
|
|
/// time.
|
|
std::string buildErrorStreamingString(
|
|
StringRef message, const FmtContext &ctx,
|
|
ErrorStreamType errorStreamType = ErrorStreamType::InString);
|
|
|
|
} // namespace tblgen
|
|
} // namespace mlir
|
|
|
|
#endif // MLIR_TABLEGEN_CODEGENHELPERS_H
|