Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
633 changes: 500 additions & 133 deletions mlir/docs/Tutorials/DataFlowAnalysis.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions mlir/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(dataflow)
add_subdirectory(toy)
add_subdirectory(transform)
add_subdirectory(transform-opt)
Expand Down
9 changes: 9 additions & 0 deletions mlir/examples/dataflow/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_custom_target(DataFlowExample)
set_target_properties(DataFlowExample PROPERTIES FOLDER "MLIR/Examples")

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)

add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(dataflow-opt)
13 changes: 13 additions & 0 deletions mlir/examples/dataflow/dataflow-opt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_dependencies(DataFlowExample dataflow-opt)
add_llvm_example(dataflow-opt
dataflow-opt.cpp
)

target_link_libraries(dataflow-opt
PRIVATE
MLIRIR
MLIRMlirOptMain
MLIRStringDialect
MLIRTestStringConstantPropagation
MLIRTestMetadataAnalysisPass
)
44 changes: 44 additions & 0 deletions mlir/examples/dataflow/dataflow-opt/dataflow-opt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===-- dataflow-opt.cpp - dataflow tutorial entry point ------------------===//
//
// 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 is the top-level file for the dataflow tutorial.
//
//===----------------------------------------------------------------------===//

#include "StringDialect.h"
#include "mlir/IR/DialectRegistry.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/InitAllDialects.h"
#include "mlir/InitAllExtensions.h"
#include "mlir/Tools/mlir-opt/MlirOptMain.h"
#include "mlir/Transforms/Passes.h"

namespace mlir {
namespace test {
void registerTestMetadataAnalysisPass();
void registerTestStringConstantPropagation();
}; // namespace test
} // namespace mlir

int main(int argc, char *argv[]) {
// Register all MLIR core dialects.
mlir::DialectRegistry registry;
registerAllDialects(registry);
registerAllExtensions(registry);

// Register String dialect.
registry.insert<mlir::string::StringDialect>();

// Register test-string-constant-propagation pass.
mlir::test::registerTestStringConstantPropagation();

// Register test-metadata-analysis pass.
mlir::test::registerTestMetadataAnalysisPass();
return mlir::failed(
mlir::MlirOptMain(argc, argv, "dataflow-opt optimizer driver", registry));
}
2 changes: 2 additions & 0 deletions mlir/examples/dataflow/include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_mlir_dialect(StringOps string)
add_mlir_doc(StringOps StringDialect Dialects/ -gen-dialect-doc)
79 changes: 79 additions & 0 deletions mlir/examples/dataflow/include/MetadataAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===-- MetadataAnalysis.h - dataflow tutorial ------------------*- 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 is contains the dataflow tutorial's classes related to metadata.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_TUTORIAL_METADATA_ANALYSIS_H_
#define MLIR_TUTORIAL_METADATA_ANALYSIS_H_

#include "mlir/Analysis/DataFlow/SparseAnalysis.h"
#include "llvm/Support/raw_ostream.h"

using namespace mlir;
using namespace llvm;

namespace mlir {
/// The value of our lattice represents the inner structure of a DictionaryAttr,
/// for the `metadata`.
struct MetadataLatticeValue {
MetadataLatticeValue() = default;
/// Compute a lattice value from the provided dictionary.
MetadataLatticeValue(DictionaryAttr attr) {
for (NamedAttribute pair : attr) {
metadata.insert(
std::pair<StringAttr, Attribute>(pair.getName(), pair.getValue()));
}
}

/// This method conservatively joins the information held by `lhs` and `rhs`
/// into a new value. This method is required to be monotonic. `monotonicity`
/// is implied by the satisfaction of the following axioms:
/// * idempotence: join(x,x) == x
/// * commutativity: join(x,y) == join(y,x)
/// * associativity: join(x,join(y,z)) == join(join(x,y),z)
///
/// When the above axioms are satisfied, we achieve `monotonicity`:
/// * monotonicity: join(x, join(x,y)) == join(x,y)
static MetadataLatticeValue join(const MetadataLatticeValue &lhs,
const MetadataLatticeValue &rhs);

/// A simple comparator that checks to see if this value is equal to the one
/// provided.
bool operator==(const MetadataLatticeValue &rhs) const;

/// Print data in metadata.
void print(llvm::raw_ostream &os) const;

/// Our value represents the combined metadata, which is originally a
/// DictionaryAttr, so we use a map.
DenseMap<StringAttr, Attribute> metadata;
};

namespace dataflow {
class MetadataLatticeValueLattice : public Lattice<MetadataLatticeValue> {
public:
using Lattice::Lattice;
};

class MetadataAnalysis
: public SparseForwardDataFlowAnalysis<MetadataLatticeValueLattice> {
public:
using SparseForwardDataFlowAnalysis::SparseForwardDataFlowAnalysis;
LogicalResult
visitOperation(Operation *op,
ArrayRef<const MetadataLatticeValueLattice *> operands,
ArrayRef<MetadataLatticeValueLattice *> results) override;
void setToEntryState(MetadataLatticeValueLattice *lattice) override;
};

} // namespace dataflow
} // namespace mlir

#endif // MLIR_TUTORIAL_METADATA_ANALYSIS_H_
95 changes: 95 additions & 0 deletions mlir/examples/dataflow/include/StringConstantPropagation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===-- StringConstantPropagation.h - dataflow tutorial ---------*- 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 is contains the dataflow tutorial's classes related to string
// constant propagation.
//===----------------------------------------------------------------------===//

#ifndef MLIR_TUTORIAL_STRING_CONSTANT_PROPAGATION_H_
#define MLIR_TUTORIAL_STRING_CONSTANT_PROPAGATION_H_

#include "mlir/Analysis/DataFlowFramework.h"

namespace mlir {
namespace dataflow {

class StringConstant : public AnalysisState {
/// This is the known string constant value of an SSA value at compile time
/// as determined by a dataflow analysis. To implement the concept of being
/// "uninitialized", the potential string value is wrapped in an `Optional`
/// and set to `None` by default to indicate that no value has been provided.
std::optional<std::string> stringValue = std::nullopt;

public:
using AnalysisState::AnalysisState;

/// Return true if no value has been provided for the string constant value.
bool isUninitialized() const { return !stringValue.has_value(); }

/// Default initialized the state to an empty string. Return whether the value
/// of the state has changed.
ChangeResult defaultInitialize() {
// If the state already has a value, do nothing.
if (!isUninitialized())
return ChangeResult::NoChange;
// Initialize the state and indicate that its value changed.
stringValue = "";
return ChangeResult::Change;
}

/// Get the currently known string value.
StringRef getStringValue() const {
assert(!isUninitialized() && "getting the value of an uninitialized state");
return stringValue.value();
}

/// "Join" the value of the state with another constant.
ChangeResult join(const Twine &value) {
// If the current state is uninitialized, just take the value.
if (isUninitialized()) {
stringValue = value.str();
return ChangeResult::Change;
}
// If the current state is "overdefined", no new information can be taken.
if (stringValue->empty())
return ChangeResult::NoChange;
// If the current state has a different value, it now has two conflicting
// values and should go to overdefined.
if (stringValue != value.str()) {
stringValue = "";
return ChangeResult::Change;
}
return ChangeResult::NoChange;
}

/// Print the constant value.
void print(raw_ostream &os) const override {
os << stringValue.value_or("") << "\n";
}
};

class StringConstantPropagation : public DataFlowAnalysis {
public:
using DataFlowAnalysis::DataFlowAnalysis;

/// Implement the transfer function for string operations. When visiting a
/// string operation, this analysis will try to determine compile time values
/// of the operation's results and set them in `StringConstant` states. This
/// function is invoked on an operation whenever the states of its operands
/// are changed.
LogicalResult visit(ProgramPoint *point) override;

/// Initialize the analysis by visiting every operation with potential
/// control-flow semantics.
LogicalResult initialize(Operation *top) override;
};

} // namespace dataflow
} // namespace mlir

#endif // MLIR_TUTORIAL_STRING_CONSTANT_PROPAGATION_H_
30 changes: 30 additions & 0 deletions mlir/examples/dataflow/include/StringDialect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===- StringDialect.h - Dialect definition for the String IR -------------===//
//
// 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 implements the String Dialect for the StringConstantPropagation.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_TUTORIAL_STRING_DIALECT_H_
#define MLIR_TUTORIAL_STRING_DIALECT_H_

#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#define GET_TYPEDEF_CLASSES
#include "StringOpsTypes.h.inc"

#include "StringOpsDialect.h.inc"
#define GET_OP_CLASSES
#include "StringOps.h.inc"

#endif // MLIR_TUTORIAL_STRING_DIALECT_H_
75 changes: 75 additions & 0 deletions mlir/examples/dataflow/include/StringOps.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===-- StringOps.td - String dialect operation definitions *- tablegen -*-===//
//
// 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 the basic operations for the String dialect.
//
//===----------------------------------------------------------------------===//

#ifndef STRING_OPS
#define STRING_OPS

include "mlir/IR/OpBase.td"
include "mlir/IR/AttrTypeBase.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

def String_Dialect : Dialect {
let name = "string";
let cppNamespace = "mlir::string";
let description = [{
The `String` dialect provides string-related operations,
which are used for string constant propagation.
}];
let useDefaultTypePrinterParser = 1;
}

//===----------------------------------------------------------------------===//
// String Type Definitions
//===----------------------------------------------------------------------===//

def StringType : TypeDef<String_Dialect, "StringType", []> {
let mnemonic = "str";
let summary = "string literal";
let description = [{
`string.str` is a type returned by ops of string dialect.
}];
}

//===----------------------------------------------------------------------===//
// String Op Definitions
//===----------------------------------------------------------------------===//

class String_Op<string mnemonic, list<Trait> traits = [Pure]> :
Op<String_Dialect, mnemonic, traits> {}

def ConstantOp : String_Op<"constant"> {
let arguments = (ins StrAttr:$value);
let results = (outs StringType:$res);
let description = [{
The `string.constant` op is used to create string constants.
```mlir
%bar = string.constant "bar"
```
}];
let assemblyFormat = "$value attr-dict";
}

def ConcatOp : String_Op<"concat"> {
let arguments = (ins StringType:$lhs, StringType:$rhs);
let results = (outs StringType:$res);
let description = [{
The `string.concat` op is used to concatenate strings.
```mlir
%bar = string.constant "bar"
%foo = string.constant "foo"
%concat = string.concat %bar, %foo
```
}];
let assemblyFormat = "$lhs `,` $rhs attr-dict";
}

#endif // STRING_OPS
2 changes: 2 additions & 0 deletions mlir/examples/dataflow/lib/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_subdirectory(StringConstantPropagation)
add_subdirectory(MetadataAnalysis)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_mlir_example_library(MLIRMetadataAnalysis
MetadataAnalysis.cpp

LINK_LIBS PUBLIC
MLIRAnalysis
)
Loading