mirror of https://github.com/llvm/circt.git
[Handshake] Add StaticLogic Dialect and Pipeline Operation (#62)
* add pipeline operation * add staticlogic dialect lib * add standard-to-staticlogic pass * update standard-to-staticlogic pass * update conversion pass * complete initial design of -create-pipeline pass * format fixed; add testcase for -create-pipeline pass * update references * update pipeline operation defination; update standard-to-pipeline pass; update testcase * add endline * update pipeline operation and lowering pass: isolate from above, but not single-producer single-consumer; update test case.
This commit is contained in:
parent
d284b0dddc
commit
9ab7d667f9
|
@ -0,0 +1,19 @@
|
|||
//===- StandardToStaticLogic.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Copyright 2020 The CIRCT Authors.
|
||||
//
|
||||
// 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CIRCT_CONVERSION_STANDARDTOSTATICLOGIC_H_
|
||||
#define CIRCT_CONVERSION_STANDARDTOSTATICLOGIC_H_
|
||||
|
||||
namespace circt {
|
||||
namespace staticlogic {
|
||||
void registerStandardToStaticLogicPasses();
|
||||
} // namespace staticlogic
|
||||
} // namespace circt
|
||||
|
||||
#endif // CIRCT_CONVERSION_STANDARDTOSTATICLOGIC_H_
|
|
@ -2,3 +2,4 @@ add_subdirectory(FIRRTL)
|
|||
add_subdirectory(Handshake)
|
||||
add_subdirectory(LLHD)
|
||||
add_subdirectory(RTL)
|
||||
add_subdirectory(StaticLogic)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
add_mlir_dialect(StaticLogic staticlogic)
|
||||
|
||||
set(LLVM_TARGET_DEFINITIONS StaticLogic.td)
|
|
@ -0,0 +1,44 @@
|
|||
//===- StaticLogic.h - StaticLogic Definitions ------------------*- C++ -*-===//
|
||||
//
|
||||
// Copyright 2020 The CIRCT Authors.
|
||||
//
|
||||
// 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CIRCT_STATICLOGIC_OPS_H_
|
||||
#define CIRCT_STATICLOGIC_OPS_H_
|
||||
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/RegionKindInterface.h"
|
||||
#include "mlir/IR/StandardTypes.h"
|
||||
#include "mlir/IR/TypeSupport.h"
|
||||
#include "mlir/IR/Types.h"
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
#include "mlir/Pass/Pass.h"
|
||||
|
||||
namespace circt {
|
||||
namespace staticlogic {
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
class StaticLogicDialect : public Dialect {
|
||||
public:
|
||||
StaticLogicDialect(MLIRContext *context);
|
||||
static StringRef getDialectNamespace() { return "staticlogic"; }
|
||||
};
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.h.inc"
|
||||
|
||||
} // namespace staticlogic
|
||||
} // namespace circt
|
||||
|
||||
#endif // CIRCT_STATICLOGIC_OPS_H_
|
|
@ -0,0 +1,73 @@
|
|||
//===- StaticLogic.td - StaticLogic Definitions ------------*- tablegen -*-===//
|
||||
//
|
||||
// Copyright 2020 The CIRCT Authors.
|
||||
//
|
||||
// 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef STATICLOGIC_OPS
|
||||
#else
|
||||
#define STATICLOGIC_OPS
|
||||
|
||||
#ifdef OP_BASE
|
||||
#else
|
||||
include "mlir/IR/OpBase.td"
|
||||
#endif // OP_BASE
|
||||
|
||||
include "mlir/IR/SymbolInterfaces.td"
|
||||
include "mlir/IR/RegionKindInterface.td"
|
||||
include "mlir/Interfaces/CallInterfaces.td"
|
||||
include "mlir/Interfaces/SideEffectInterfaces.td"
|
||||
|
||||
def StaticLogic_Dialect : Dialect {
|
||||
let name = "staticlogic";
|
||||
let cppNamespace = "";
|
||||
}
|
||||
|
||||
def PipelineOp : Op<StaticLogic_Dialect, "pipeline", [NoSideEffect]> {
|
||||
let summary = "pipeline operation";
|
||||
let description = [{
|
||||
The "staticlogic.pipeline" operation represents a statically scheduled
|
||||
pipeline stucture which contains several MLIR blocks. Each MLIR block is
|
||||
corresponding to a pipeline stage.
|
||||
}];
|
||||
|
||||
let arguments = (ins Variadic<AnyType>);
|
||||
let results = (outs Variadic<AnyType>);
|
||||
let regions = (region AnyRegion: $body);
|
||||
|
||||
let skipDefaultBuilders = 1;
|
||||
|
||||
let builders = [OpBuilder<"OpBuilder &odsBuilder, OperationState &odsState, "
|
||||
"ValueRange operands, ValueRange results", [{
|
||||
SmallVector<Type, 4> argTypes;
|
||||
for (auto value : operands)
|
||||
argTypes.push_back(value.getType());
|
||||
|
||||
SmallVector<Type, 4> resultTypes;
|
||||
for (auto value : results)
|
||||
resultTypes.push_back(value.getType());
|
||||
|
||||
Region *bodyRegion = odsState.addRegion();
|
||||
Block *body = new Block();
|
||||
bodyRegion->push_back(body);
|
||||
body->addArguments(argTypes);
|
||||
|
||||
odsState.addOperands(operands);
|
||||
odsState.addTypes(resultTypes);
|
||||
}]>];
|
||||
}
|
||||
|
||||
def ReturnOp : Op<StaticLogic_Dialect, "return", [Terminator]> {
|
||||
let summary = "StaticLogic dialect return.";
|
||||
let description = [{
|
||||
The "staticlogic.return" operation represents a terminator of a statically
|
||||
scheduled module, which is similar to a standard return operation.
|
||||
}];
|
||||
|
||||
let arguments = (ins Variadic<AnyType>: $operands);
|
||||
}
|
||||
|
||||
#endif // STATICLOGIC_OPS
|
|
@ -1,3 +1,4 @@
|
|||
add_subdirectory(StandardToHandshake)
|
||||
add_subdirectory(HandshakeToFIRRTL)
|
||||
add_subdirectory(LLHDToLLVM)
|
||||
add_subdirectory(StandardToStaticLogic)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// =============================================================================
|
||||
|
||||
#include "circt/Conversion/StandardToHandshake/StandardToHandshake.h"
|
||||
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.h"
|
||||
#include "circt/Dialect/Handshake/HandshakeOps.h"
|
||||
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
add_mlir_library(MLIRStandardToStaticLogic
|
||||
StandardToStaticLogic.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/StandardToStaticLogic
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
MLIRIR
|
||||
MLIRPass
|
||||
MLIRStandardOps
|
||||
MLIRSupport
|
||||
MLIRTransforms
|
||||
MLIRStaticLogicOps
|
||||
)
|
|
@ -0,0 +1,122 @@
|
|||
//===- Ops.h - StaticLogic MLIR Operations ----------------------*- C++ -*-===//
|
||||
//
|
||||
// Copyright 2020 The CIRCT Authors.
|
||||
//
|
||||
// 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 "circt/Conversion/StandardToStaticLogic/StandardToStaticLogic.h"
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.h"
|
||||
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace circt;
|
||||
using namespace staticlogic;
|
||||
using namespace std;
|
||||
|
||||
using valueVector = SmallVector<Value, 4>;
|
||||
|
||||
valueVector getPipelineArgs(Block &block) {
|
||||
valueVector arguments;
|
||||
for (auto &op : block) {
|
||||
if (op.isKnownNonTerminator()) {
|
||||
for (auto operand : op.getOperands()) {
|
||||
if (operand.getKind() == Value::Kind::BlockArgument) {
|
||||
// Add only unique uses
|
||||
if (std::find(arguments.begin(), arguments.end(), operand) ==
|
||||
arguments.end())
|
||||
arguments.push_back(operand);
|
||||
} else if (operand.getDefiningOp()->getBlock() != &block) {
|
||||
// Add only unique uses
|
||||
if (std::find(arguments.begin(), arguments.end(), operand) ==
|
||||
arguments.end())
|
||||
arguments.push_back(operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
valueVector getPipelineResults(Block &block) {
|
||||
SmallVector<Value, 4> results;
|
||||
for (auto &op : block) {
|
||||
for (auto result : op.getResults()) {
|
||||
bool isResult = false;
|
||||
for (auto user : result.getUsers()) {
|
||||
if (user->getBlock() != &block || user->isKnownTerminator()) {
|
||||
isResult = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isResult)
|
||||
results.push_back(result);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static void createPipeline(mlir::FuncOp f, OpBuilder &builder) {
|
||||
for (Block &block : f) {
|
||||
if (block.front().isKnownNonTerminator()) {
|
||||
|
||||
auto arguments = getPipelineArgs(block);
|
||||
auto results = getPipelineResults(block);
|
||||
builder.setInsertionPoint(&block.back());
|
||||
builder.create<staticlogic::ReturnOp>(f.getLoc(), ValueRange(results));
|
||||
|
||||
// Create pipeline operation, and move all operations except terminator
|
||||
// into the pipeline.
|
||||
builder.setInsertionPoint(&block.front());
|
||||
auto pipeline = builder.create<staticlogic::PipelineOp>(
|
||||
f.getLoc(), ValueRange(arguments), ValueRange(results));
|
||||
|
||||
auto &body = pipeline.getRegion().front();
|
||||
body.getOperations().splice(body.getOperations().begin(),
|
||||
block.getOperations(), ++block.begin(),
|
||||
--block.end());
|
||||
|
||||
// Reconnect arguments of the pipeline operation.
|
||||
unsigned argIdx = 0;
|
||||
for (auto value : arguments) {
|
||||
value.replaceUsesWithIf(
|
||||
body.getArgument(argIdx),
|
||||
function_ref<bool(OpOperand &)>([&body](OpOperand &use) -> bool {
|
||||
return use.getOwner()->getBlock() == &body;
|
||||
}));
|
||||
argIdx += 1;
|
||||
}
|
||||
|
||||
// Reconnect results of the pipeline operation.
|
||||
unsigned resultIdx = 0;
|
||||
for (auto value : results) {
|
||||
value.replaceUsesWithIf(
|
||||
pipeline.getResult(resultIdx),
|
||||
function_ref<bool(OpOperand &)>([&body](OpOperand &use) -> bool {
|
||||
return use.getOwner()->getBlock() != &body;
|
||||
}));
|
||||
resultIdx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct CreatePipelinePass
|
||||
: public PassWrapper<CreatePipelinePass, OperationPass<mlir::FuncOp>> {
|
||||
void runOnOperation() override {
|
||||
mlir::FuncOp f = getOperation();
|
||||
auto builder = OpBuilder(f.getContext());
|
||||
createPipeline(f, builder);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void staticlogic::registerStandardToStaticLogicPasses() {
|
||||
PassRegistration<CreatePipelinePass>(
|
||||
"create-pipeline", "Create StaticLogic pipeline operations.");
|
||||
}
|
|
@ -2,3 +2,4 @@ add_subdirectory(FIRRTL)
|
|||
add_subdirectory(Handshake)
|
||||
add_subdirectory(LLHD)
|
||||
add_subdirectory(RTL)
|
||||
add_subdirectory(StaticLogic)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
set(LLVM_OPTIONAL_SOURCES
|
||||
DialectRegistration.cpp
|
||||
mlir_std_runner.cpp
|
||||
Ops.cpp
|
||||
)
|
||||
|
||||
add_mlir_dialect_library(MLIRStaticLogicOps
|
||||
Ops.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
MLIRStandardOps
|
||||
MLIRIR
|
||||
|
||||
DEPENDS
|
||||
MLIRStaticLogicIncGen
|
||||
)
|
|
@ -0,0 +1,30 @@
|
|||
//===- Ops.h - StaticLogic MLIR Operations ----------------------*- C++ -*-===//
|
||||
//
|
||||
// Copyright 2020 The CIRCT Authors.
|
||||
//
|
||||
// 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 "circt/Dialect/StaticLogic/StaticLogic.h"
|
||||
#include "mlir/IR/FunctionImplementation.h"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace circt;
|
||||
using namespace circt::staticlogic;
|
||||
|
||||
namespace circt {
|
||||
namespace staticlogic {
|
||||
#define GET_OP_CLASSES
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.cpp.inc"
|
||||
} // namespace staticlogic
|
||||
} // namespace circt
|
||||
|
||||
StaticLogicDialect::StaticLogicDialect(MLIRContext *context)
|
||||
: Dialect(getDialectNamespace(), context) {
|
||||
addOperations<
|
||||
#define GET_OP_LIST
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.cpp.inc"
|
||||
>();
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// RUN: circt-opt -create-pipeline %s | FileCheck %s
|
||||
|
||||
// CHECK: module {
|
||||
// CHECK-LABEL: func @simple_loop() {
|
||||
// CHECK: br ^bb1
|
||||
// CHECK: ^bb1: // pred: ^bb0
|
||||
// CHECK: %[[VAL_0:.*]]:2 = "staticlogic.pipeline"() ( {
|
||||
// CHECK: %c1 = constant 1 : index
|
||||
// CHECK: %c42 = constant 42 : index
|
||||
// CHECK: "staticlogic.return"(%c1, %c42) : (index, index) -> ()
|
||||
// CHECK: }) : () -> (index, index)
|
||||
// CHECK: br ^bb2(%[[VAL_0:.*]]#0 : index)
|
||||
// CHECK: ^bb2(%[[VAL_1:.*]]: index): // 2 preds: ^bb1, ^bb3
|
||||
// CHECK: %[[VAL_2:.*]] = "staticlogic.pipeline"(%[[VAL_1:.*]], %[[VAL_0:.*]]#1) ( {
|
||||
// CHECK: ^bb0(%[[ARG_0:.*]]: index, %[[ARG_1:.*]]: index): // no predecessors
|
||||
// CHECK: %[[TMP_0:.*]] = cmpi "slt", %[[ARG_0:.*]], %[[ARG_1:.*]] : index
|
||||
// CHECK: "staticlogic.return"(%[[TMP_0:.*]]) : (i1) -> ()
|
||||
// CHECK: }) : (index, index) -> i1
|
||||
// CHECK: cond_br %[[VAL_2:.*]], ^bb3, ^bb4
|
||||
// CHECK: ^bb3: // pred: ^bb2
|
||||
// CHECK: %[[VAL_3:.*]] = "staticlogic.pipeline"(%[[VAL_1:.*]]) ( {
|
||||
// CHECK: ^bb0(%[[ARG_0:.*]]: index): // no predecessors
|
||||
// CHECK: %c1 = constant 1 : index
|
||||
// CHECK: %[[TMP_1:.*]] = addi %[[ARG_0:.*]], %c1 : index
|
||||
// CHECK: "staticlogic.return"(%[[TMP_1:.*]]) : (index) -> ()
|
||||
// CHECK: }) : (index) -> index
|
||||
// CHECK: br ^bb2(%[[VAL_3:.*]] : index)
|
||||
// CHECK: ^bb4: // pred: ^bb2
|
||||
// CHECK: return
|
||||
// CHECK: }
|
||||
// CHECK: }
|
||||
|
||||
func @simple_loop() {
|
||||
^bb0:
|
||||
br ^bb1
|
||||
^bb1: // pred: ^bb0
|
||||
%c1 = constant 1 : index
|
||||
%c42 = constant 42 : index
|
||||
br ^bb2(%c1 : index)
|
||||
^bb2(%0: index): // 2 preds: ^bb1, ^bb3
|
||||
%1 = cmpi "slt", %0, %c42 : index
|
||||
cond_br %1, ^bb3, ^bb4
|
||||
^bb3: // pred: ^bb2
|
||||
%c1_0 = constant 1 : index
|
||||
%2 = addi %0, %c1_0 : index
|
||||
br ^bb2(%2 : index)
|
||||
^bb4: // pred: ^bb2
|
||||
return
|
||||
}
|
|
@ -9,9 +9,11 @@ llvm_update_compile_flags(circt-opt)
|
|||
target_link_libraries(circt-opt
|
||||
PRIVATE
|
||||
MLIRFIRRTL
|
||||
MLIRStaticLogicOps
|
||||
MLIRHandshakeOps
|
||||
MLIRRTL
|
||||
MLIRStandardToHandshake
|
||||
MLIRStandardToStaticLogic
|
||||
MLIRHandshakeToFIRRTL
|
||||
MLIRLLHD
|
||||
MLIRLLHDTransforms
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "circt/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.h"
|
||||
#include "circt/Conversion/LLHDToLLVM/LLHDToLLVM.h"
|
||||
#include "circt/Conversion/StandardToHandshake/StandardToHandshake.h"
|
||||
#include "circt/Conversion/StandardToStaticLogic/StandardToStaticLogic.h"
|
||||
#include "circt/Dialect/FIRRTL/Dialect.h"
|
||||
#include "circt/Dialect/Handshake/HandshakeOps.h"
|
||||
#include "circt/Dialect/StaticLogic/StaticLogic.h"
|
||||
#include "circt/Dialect/LLHD/IR/LLHDDialect.h"
|
||||
#include "circt/Dialect/LLHD/Transforms/Passes.h"
|
||||
#include "circt/Dialect/RTL/Dialect.h"
|
||||
|
@ -88,6 +90,8 @@ int main(int argc, char **argv) {
|
|||
firrtl::registerFIRRTLPasses();
|
||||
|
||||
registerDialect<handshake::HandshakeOpsDialect>();
|
||||
registerDialect<staticlogic::StaticLogicDialect>();
|
||||
staticlogic::registerStandardToStaticLogicPasses();
|
||||
handshake::registerStandardToHandshakePasses();
|
||||
handshake::registerHandshakeToFIRRTLPasses();
|
||||
|
||||
|
|
Loading…
Reference in New Issue