circt/lib/Conversion/LTLToCore/LTLToCore.cpp

169 lines
6.3 KiB
C++

//===- LTLToCore.cpp -----------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Converts LTL and Verif operations to Core operations
//
//===----------------------------------------------------------------------===//
#include "circt/Conversion/LTLToCore.h"
#include "circt/Conversion/HWToSV.h"
#include "circt/Dialect/Comb/CombOps.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/LTL/LTLDialect.h"
#include "circt/Dialect/LTL/LTLOps.h"
#include "circt/Dialect/SV/SVDialect.h"
#include "circt/Dialect/SV/SVOps.h"
#include "circt/Dialect/Seq/SeqOps.h"
#include "circt/Dialect/Verif/VerifOps.h"
#include "circt/Support/BackedgeBuilder.h"
#include "circt/Support/Namespace.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/DialectConversion.h"
#include "llvm/Support/MathExtras.h"
namespace circt {
#define GEN_PASS_DEF_LOWERLTLTOCORE
#include "circt/Conversion/Passes.h.inc"
} // namespace circt
using namespace mlir;
using namespace circt;
using namespace hw;
//===----------------------------------------------------------------------===//
// Conversion patterns
//===----------------------------------------------------------------------===//
namespace {
struct HasBeenResetOpConversion : OpConversionPattern<verif::HasBeenResetOp> {
using OpConversionPattern<verif::HasBeenResetOp>::OpConversionPattern;
// HasBeenReset generates a 1 bit register that is set to one once the reset
// has been raised and lowered at at least once.
LogicalResult
matchAndRewrite(verif::HasBeenResetOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
auto i1 = rewriter.getI1Type();
// Generate the constant used to set the register value
Value constZero = seq::createConstantInitialValue(
rewriter, op->getLoc(), rewriter.getIntegerAttr(i1, 0));
// Generate the constant used to negate the reset value
Value constOne = hw::ConstantOp::create(rewriter, op.getLoc(), i1, 1);
// Create a backedge for the register to be used in the OrOp
circt::BackedgeBuilder bb(rewriter, op.getLoc());
circt::Backedge reg = bb.get(rewriter.getI1Type());
// Generate an or between the reset and the register's value to store
// whether or not the reset has been active at least once
Value orReset =
comb::OrOp::create(rewriter, op.getLoc(), adaptor.getReset(), reg);
// This register should not be reset, so we give it dummy reset and resetval
// operands to fit the build signature
Value reset, resetval;
// Finally generate the register to set the backedge
reg.setValue(seq::CompRegOp::create(
rewriter, op.getLoc(), orReset,
rewriter.createOrFold<seq::ToClockOp>(op.getLoc(), adaptor.getClock()),
rewriter.getStringAttr("hbr"), reset, resetval, constZero,
InnerSymAttr{} // inner_sym
));
// We also need to consider the case where we are currently in a reset cycle
// in which case our hbr register should be down-
// Practically this means converting it to (and hbr (not reset))
Value notReset = comb::XorOp::create(rewriter, op.getLoc(),
adaptor.getReset(), constOne);
rewriter.replaceOpWithNewOp<comb::AndOp>(op, reg, notReset);
return success();
}
};
} // namespace
//===----------------------------------------------------------------------===//
// Lower LTL To Core pass
//===----------------------------------------------------------------------===//
namespace {
struct LowerLTLToCorePass
: public circt::impl::LowerLTLToCoreBase<LowerLTLToCorePass> {
LowerLTLToCorePass() = default;
void runOnOperation() override;
};
} // namespace
// Simply applies the conversion patterns defined above
void LowerLTLToCorePass::runOnOperation() {
// Set target dialects: We don't want to see any ltl or verif that might
// come from an AssertProperty left in the result
ConversionTarget target(getContext());
target.addLegalDialect<hw::HWDialect>();
target.addLegalDialect<comb::CombDialect>();
target.addLegalDialect<sv::SVDialect>();
target.addLegalDialect<seq::SeqDialect>();
target.addLegalDialect<ltl::LTLDialect>();
target.addLegalDialect<verif::VerifDialect>();
target.addIllegalOp<verif::HasBeenResetOp>();
// Create type converters, mostly just to convert an ltl property to a bool
mlir::TypeConverter converter;
// Convert the ltl property type to a built-in type
converter.addConversion([](IntegerType type) { return type; });
converter.addConversion([](ltl::PropertyType type) {
return IntegerType::get(type.getContext(), 1);
});
converter.addConversion([](ltl::SequenceType type) {
return IntegerType::get(type.getContext(), 1);
});
// Basic materializations
converter.addTargetMaterialization(
[&](mlir::OpBuilder &builder, mlir::Type resultType,
mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
if (inputs.size() != 1)
return Value();
return UnrealizedConversionCastOp::create(builder, loc, resultType,
inputs[0])
->getResult(0);
});
converter.addSourceMaterialization(
[&](mlir::OpBuilder &builder, mlir::Type resultType,
mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
if (inputs.size() != 1)
return Value();
return UnrealizedConversionCastOp::create(builder, loc, resultType,
inputs[0])
->getResult(0);
});
// Create the operation rewrite patters
RewritePatternSet patterns(&getContext());
patterns.add<HasBeenResetOpConversion>(converter, patterns.getContext());
// Apply the conversions
if (failed(
applyPartialConversion(getOperation(), target, std::move(patterns))))
return signalPassFailure();
}
// Basic default constructor
std::unique_ptr<mlir::Pass> circt::createLowerLTLToCorePass() {
return std::make_unique<LowerLTLToCorePass>();
}