mirror of https://github.com/llvm/circt.git
[RTG] Separate operation for sequence randomization and randomized sequence type (#8147)
This commit is contained in:
parent
e4d67daaf5
commit
e4eb532604
|
@ -40,6 +40,12 @@ MLIR_CAPI_EXPORTED unsigned rtgSequenceTypeGetNumElements(MlirType type);
|
|||
MLIR_CAPI_EXPORTED MlirType rtgSequenceTypeGetElement(MlirType type,
|
||||
unsigned i);
|
||||
|
||||
/// If the type is an RTG randomized sequence.
|
||||
MLIR_CAPI_EXPORTED bool rtgTypeIsARandomizedSequence(MlirType type);
|
||||
|
||||
/// Creates an RTG randomized sequence type in the context.
|
||||
MLIR_CAPI_EXPORTED MlirType rtgRandomizedSequenceTypeGet(MlirContext ctxt);
|
||||
|
||||
/// If the type is an RTG label.
|
||||
MLIR_CAPI_EXPORTED bool rtgTypeIsALabel(MlirType type);
|
||||
|
||||
|
|
|
@ -85,17 +85,42 @@ def SequenceClosureOp : RTGOp<"sequence_closure", [
|
|||
}];
|
||||
}
|
||||
|
||||
def InvokeSequenceOp : RTGOp<"invoke_sequence", []> {
|
||||
let summary = "invoke a sequence of instructions";
|
||||
def RandomizeSequenceOp : RTGOp<"randomize_sequence", []> {
|
||||
let summary = "randomize the content of a sequence";
|
||||
let description = [{
|
||||
This operation takes a sequence closure as operand and acts as a placeholder
|
||||
for that sequence instantiated with the arguments in the closure in place.
|
||||
This operation takes a fully substituted sequence and randomizes its
|
||||
content. This means, no operations the returned sequence does not contain
|
||||
any randomization constructs anymore (such as random selection from sets and
|
||||
bags, or other 'randomize_sequence' operations).
|
||||
|
||||
It is useful to have this operation separate from 'embed_sequence' such that
|
||||
the exact same sequence (i.e., with the same random choices taken) can be
|
||||
embedded at multiple places.
|
||||
It is also useful to have this separate from sequence substitution because
|
||||
this operation is sensitive to the context, but the substitution values for
|
||||
a sequence family might already be available in a parent sequence that is
|
||||
placed on a different context. Thus, not having it separated would mean that
|
||||
the substitution values must all be passed down as arguments to the child
|
||||
sequence instead of a a single fully substituted sequence value.
|
||||
}];
|
||||
|
||||
let arguments = (ins FullySubstitutedSequenceType:$sequence);
|
||||
let results = (outs RandomizedSequenceType:$randomizedSequence);
|
||||
|
||||
let assemblyFormat = "$sequence attr-dict";
|
||||
}
|
||||
|
||||
def EmbedSequenceOp : RTGOp<"embed_sequence", []> {
|
||||
let summary = "embed a sequence of instructions into another sequence";
|
||||
let description = [{
|
||||
This operation takes a fully randomized sequence and embeds it into another
|
||||
sequence or test at the position of this operation.
|
||||
In particular, this is not any kind of function call, it doesn't set up a
|
||||
stack frame, etc. It behaves as if the sequence of instructions it refers to
|
||||
were directly inlined relacing this operation.
|
||||
}];
|
||||
|
||||
let arguments = (ins FullySubstitutedSequenceType:$sequence);
|
||||
let arguments = (ins RandomizedSequenceType:$sequence);
|
||||
|
||||
let assemblyFormat = "$sequence attr-dict";
|
||||
}
|
||||
|
|
|
@ -32,6 +32,17 @@ def SequenceType : RTGTypeDef<"Sequence"> {
|
|||
let assemblyFormat = "(`<` $elementTypes^ `>`)?";
|
||||
}
|
||||
|
||||
def RandomizedSequenceType : RTGTypeDef<"RandomizedSequence"> {
|
||||
let summary = "handle to a fully randomized sequence";
|
||||
let description = [{
|
||||
Sequences can contain operations to randomize their content in various ways.
|
||||
A sequence of this type is guaranteed to not have any such operations
|
||||
anymore (transitively).
|
||||
}];
|
||||
|
||||
let mnemonic = "randomized_sequence";
|
||||
}
|
||||
|
||||
def FullySubstitutedSequenceType : DialectType<RTGDialect,
|
||||
CPred<"llvm::isa<rtg::SequenceType>($_self) && "
|
||||
"llvm::cast<rtg::SequenceType>($_self).getElementTypes().empty()">,
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
// RTG tests
|
||||
TestOp, TargetOp, YieldOp,
|
||||
// Sequences
|
||||
SequenceOp, SequenceClosureOp, InvokeSequenceOp,
|
||||
SequenceOp, SequenceClosureOp, RandomizeSequenceOp, EmbedSequenceOp,
|
||||
// Sets
|
||||
SetCreateOp, SetSelectRandomOp, SetDifferenceOp, SetUnionOp,
|
||||
SetSizeOp>([&](auto expr) -> ResultType {
|
||||
|
@ -88,7 +88,8 @@ public:
|
|||
|
||||
HANDLE(SequenceOp, Unhandled);
|
||||
HANDLE(SequenceClosureOp, Unhandled);
|
||||
HANDLE(InvokeSequenceOp, Unhandled);
|
||||
HANDLE(RandomizeSequenceOp, Unhandled);
|
||||
HANDLE(EmbedSequenceOp, Unhandled);
|
||||
HANDLE(SetCreateOp, Unhandled);
|
||||
HANDLE(SetSelectRandomOp, Unhandled);
|
||||
HANDLE(SetDifferenceOp, Unhandled);
|
||||
|
|
|
@ -89,14 +89,18 @@ with Context() as ctx, Location.unknown():
|
|||
setTy = rtg.SetType.get(indexTy)
|
||||
bagTy = rtg.BagType.get(indexTy)
|
||||
ireg = rtgtest.IntegerRegisterType.get()
|
||||
randomizedSequenceTy = rtg.RandomizedSequenceType.get()
|
||||
seq = rtg.SequenceOp(
|
||||
'seq',
|
||||
TypeAttr.get(
|
||||
rtg.SequenceType.get([sequenceTy, labelTy, setTy, bagTy, ireg])))
|
||||
Block.create_at_start(seq.bodyRegion,
|
||||
[sequenceTy, labelTy, setTy, bagTy, ireg])
|
||||
rtg.SequenceType.get(
|
||||
[sequenceTy, labelTy, setTy, bagTy, ireg,
|
||||
randomizedSequenceTy])))
|
||||
Block.create_at_start(
|
||||
seq.bodyRegion,
|
||||
[sequenceTy, labelTy, setTy, bagTy, ireg, randomizedSequenceTy])
|
||||
|
||||
# CHECK: rtg.sequence @seq(%{{.*}}: !rtg.sequence, %{{.*}}: !rtg.label, %{{.*}}: !rtg.set<index>, %{{.*}}: !rtg.bag<index>, %{{.*}}: !rtgtest.ireg)
|
||||
# CHECK: rtg.sequence @seq(%{{.*}}: !rtg.sequence, %{{.*}}: !rtg.label, %{{.*}}: !rtg.set<index>, %{{.*}}: !rtg.bag<index>, %{{.*}}: !rtgtest.ireg, %{{.*}}: !rtg.randomized_sequence)
|
||||
print(m)
|
||||
|
||||
with Context() as ctx, Location.unknown():
|
||||
|
|
|
@ -40,6 +40,14 @@ void circt::python::populateDialectRTGSubmodule(nb::module_ &m) {
|
|||
return rtgSequenceTypeGetElement(self, i);
|
||||
});
|
||||
|
||||
mlir_type_subclass(m, "RandomizedSequenceType", rtgTypeIsARandomizedSequence)
|
||||
.def_classmethod(
|
||||
"get",
|
||||
[](nb::object cls, MlirContext ctxt) {
|
||||
return cls(rtgRandomizedSequenceTypeGet(ctxt));
|
||||
},
|
||||
nb::arg("self"), nb::arg("ctxt") = nullptr);
|
||||
|
||||
mlir_type_subclass(m, "LabelType", rtgTypeIsALabel)
|
||||
.def_classmethod(
|
||||
"get",
|
||||
|
|
|
@ -48,6 +48,17 @@ MlirType rtgSequenceTypeGetElement(MlirType type, unsigned i) {
|
|||
return wrap(cast<SequenceType>(unwrap(type)).getElementTypes()[i]);
|
||||
}
|
||||
|
||||
// RandomizedSequenceType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool rtgTypeIsARandomizedSequence(MlirType type) {
|
||||
return isa<RandomizedSequenceType>(unwrap(type));
|
||||
}
|
||||
|
||||
MlirType rtgRandomizedSequenceTypeGet(MlirContext ctxt) {
|
||||
return wrap(RandomizedSequenceType::get(unwrap(ctxt)));
|
||||
}
|
||||
|
||||
// LabelType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ static uint32_t getUniformlyInRange(std::mt19937 &rng, uint32_t a, uint32_t b) {
|
|||
namespace {
|
||||
struct BagStorage;
|
||||
struct SequenceStorage;
|
||||
struct RandomizedSequenceStorage;
|
||||
struct SetStorage;
|
||||
|
||||
/// Represents a unique virtual register.
|
||||
|
@ -126,7 +127,8 @@ struct LabelValue {
|
|||
/// The abstract base class for elaborated values.
|
||||
using ElaboratorValue =
|
||||
std::variant<TypedAttr, BagStorage *, bool, size_t, SequenceStorage *,
|
||||
SetStorage *, VirtualRegister, LabelValue>;
|
||||
RandomizedSequenceStorage *, SetStorage *, VirtualRegister,
|
||||
LabelValue>;
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
llvm::hash_code hash_value(const VirtualRegister &val) {
|
||||
|
@ -299,16 +301,34 @@ struct BagStorage {
|
|||
|
||||
/// Storage object for an '!rtg.sequence'.
|
||||
struct SequenceStorage {
|
||||
SequenceStorage(StringRef name, StringAttr familyName,
|
||||
SmallVector<ElaboratorValue> &&args)
|
||||
SequenceStorage(StringAttr familyName, SmallVector<ElaboratorValue> &&args)
|
||||
: hashcode(llvm::hash_combine(
|
||||
name, familyName,
|
||||
llvm::hash_combine_range(args.begin(), args.end()))),
|
||||
name(name), familyName(familyName), args(std::move(args)) {}
|
||||
familyName, llvm::hash_combine_range(args.begin(), args.end()))),
|
||||
familyName(familyName), args(std::move(args)) {}
|
||||
|
||||
bool isEqual(const SequenceStorage *other) const {
|
||||
return hashcode == other->hashcode && name == other->name &&
|
||||
familyName == other->familyName && args == other->args;
|
||||
return hashcode == other->hashcode && familyName == other->familyName &&
|
||||
args == other->args;
|
||||
}
|
||||
|
||||
// The cached hashcode to avoid repeated computations.
|
||||
const unsigned hashcode;
|
||||
|
||||
// The name of the sequence family this sequence is derived from.
|
||||
const StringAttr familyName;
|
||||
|
||||
// The elaborator values used during substitution of the sequence family.
|
||||
const SmallVector<ElaboratorValue> args;
|
||||
};
|
||||
|
||||
/// Storage object for an '!rtg.randomized_sequence'.
|
||||
struct RandomizedSequenceStorage {
|
||||
RandomizedSequenceStorage(StringRef name, SequenceStorage *sequence)
|
||||
: hashcode(llvm::hash_combine(name, sequence)), name(name),
|
||||
sequence(sequence) {}
|
||||
|
||||
bool isEqual(const RandomizedSequenceStorage *other) const {
|
||||
return hashcode == other->hashcode && sequence == other->sequence;
|
||||
}
|
||||
|
||||
// The cached hashcode to avoid repeated computations.
|
||||
|
@ -317,11 +337,7 @@ struct SequenceStorage {
|
|||
// The name of this fully substituted and elaborated sequence.
|
||||
const StringRef name;
|
||||
|
||||
// The name of the sequence family this sequence is derived from.
|
||||
const StringAttr familyName;
|
||||
|
||||
// The elaborator values used during substitution of the sequence family.
|
||||
const SmallVector<ElaboratorValue> args;
|
||||
const SequenceStorage *sequence;
|
||||
};
|
||||
|
||||
/// An 'Internalizer' object internalizes storages and takes ownership of them.
|
||||
|
@ -358,6 +374,8 @@ private:
|
|||
return internedBags;
|
||||
else if constexpr (std::is_same_v<StorageTy, SequenceStorage>)
|
||||
return internedSequences;
|
||||
else if constexpr (std::is_same_v<StorageTy, RandomizedSequenceStorage>)
|
||||
return internedRandomizedSequences;
|
||||
else
|
||||
static_assert(!sizeof(StorageTy),
|
||||
"no intern set available for this storage type.");
|
||||
|
@ -374,6 +392,9 @@ private:
|
|||
DenseSet<HashedStorage<BagStorage>, StorageKeyInfo<BagStorage>> internedBags;
|
||||
DenseSet<HashedStorage<SequenceStorage>, StorageKeyInfo<SequenceStorage>>
|
||||
internedSequences;
|
||||
DenseSet<HashedStorage<RandomizedSequenceStorage>,
|
||||
StorageKeyInfo<RandomizedSequenceStorage>>
|
||||
internedRandomizedSequences;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -405,13 +426,20 @@ static void print(size_t val, llvm::raw_ostream &os) {
|
|||
}
|
||||
|
||||
static void print(SequenceStorage *val, llvm::raw_ostream &os) {
|
||||
os << "<sequence @" << val->name << " derived from @"
|
||||
<< val->familyName.getValue() << "(";
|
||||
os << "<sequence @" << val->familyName.getValue() << "(";
|
||||
llvm::interleaveComma(val->args, os,
|
||||
[&](const ElaboratorValue &val) { os << val; });
|
||||
os << ") at " << val << ">";
|
||||
}
|
||||
|
||||
static void print(RandomizedSequenceStorage *val, llvm::raw_ostream &os) {
|
||||
os << "<randomized-sequence @" << val->name << " derived from @"
|
||||
<< val->sequence->familyName.getValue() << "(";
|
||||
llvm::interleaveComma(val->sequence->args, os,
|
||||
[&](const ElaboratorValue &val) { os << val; });
|
||||
os << ") at " << val << ">";
|
||||
}
|
||||
|
||||
static void print(SetStorage *val, llvm::raw_ostream &os) {
|
||||
os << "<set {";
|
||||
llvm::interleaveComma(val->set, os,
|
||||
|
@ -450,7 +478,7 @@ public:
|
|||
/// Materialize IR representing the provided `ElaboratorValue` and return the
|
||||
/// `Value` or a null value on failure.
|
||||
Value materialize(ElaboratorValue val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
auto iter = materializedValues.find(val);
|
||||
if (iter != materializedValues.end())
|
||||
|
@ -469,9 +497,9 @@ public:
|
|||
/// Otherwise, all operations after the materializer's insertion point are
|
||||
/// deleted until `op` is reached. An error is returned if the operation is
|
||||
/// before the insertion point.
|
||||
LogicalResult materialize(Operation *op,
|
||||
DenseMap<Value, ElaboratorValue> &state,
|
||||
std::queue<SequenceStorage *> &elabRequests) {
|
||||
LogicalResult
|
||||
materialize(Operation *op, DenseMap<Value, ElaboratorValue> &state,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests) {
|
||||
if (op->getNumRegions() > 0)
|
||||
return op->emitOpError("ops with nested regions must be elaborated away");
|
||||
|
||||
|
@ -545,7 +573,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(TypedAttr val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
// For index attributes (and arithmetic operations on them) we use the
|
||||
// index dialect.
|
||||
|
@ -574,7 +602,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(size_t val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
Value res = builder.create<index::ConstantOp>(loc, val);
|
||||
materializedValues[val] = res;
|
||||
|
@ -582,7 +610,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(bool val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
Value res = builder.create<index::BoolConstantOp>(loc, val);
|
||||
materializedValues[val] = res;
|
||||
|
@ -590,7 +618,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(SetStorage *val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
SmallVector<Value> elements;
|
||||
elements.reserve(val->set.size());
|
||||
|
@ -608,7 +636,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(BagStorage *val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
SmallVector<Value> values, weights;
|
||||
values.reserve(val->bag.size());
|
||||
|
@ -630,14 +658,24 @@ private:
|
|||
}
|
||||
|
||||
Value visit(SequenceStorage *val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
emitError() << "materializing a non-randomized sequence not supported yet";
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value visit(RandomizedSequenceStorage *val, Location loc,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
elabRequests.push(val);
|
||||
return builder.create<SequenceClosureOp>(loc, val->name, ValueRange());
|
||||
Value seq = builder.create<SequenceClosureOp>(
|
||||
loc, SequenceType::get(builder.getContext(), {}), val->name,
|
||||
ValueRange{});
|
||||
return builder.create<RandomizeSequenceOp>(loc, seq);
|
||||
}
|
||||
|
||||
Value visit(const VirtualRegister &val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
auto res = builder.create<VirtualRegisterOp>(loc, val.allowedRegs);
|
||||
materializedValues[val] = res;
|
||||
|
@ -645,7 +683,7 @@ private:
|
|||
}
|
||||
|
||||
Value visit(const LabelValue &val, Location loc,
|
||||
std::queue<SequenceStorage *> &elabRequests,
|
||||
std::queue<RandomizedSequenceStorage *> &elabRequests,
|
||||
function_ref<InFlightDiagnostic()> emitError) {
|
||||
if (val.id == 0) {
|
||||
auto res = builder.create<LabelDeclOp>(loc, val.name, ValueRange());
|
||||
|
@ -694,7 +732,7 @@ struct ElaboratorSharedState {
|
|||
|
||||
/// The worklist used to keep track of the test and sequence operations to
|
||||
/// make sure they are processed top-down (BFS traversal).
|
||||
std::queue<SequenceStorage *> worklist;
|
||||
std::queue<RandomizedSequenceStorage *> worklist;
|
||||
|
||||
uint64_t virtualRegisterID = 0;
|
||||
uint64_t uniqueLabelID = 1;
|
||||
|
@ -758,19 +796,27 @@ public:
|
|||
}
|
||||
|
||||
FailureOr<DeletionKind> visitOp(SequenceClosureOp op) {
|
||||
SmallVector<ElaboratorValue> args;
|
||||
for (auto arg : op.getArgs())
|
||||
args.push_back(state.at(arg));
|
||||
SmallVector<ElaboratorValue> replacements;
|
||||
for (auto replacement : op.getArgs())
|
||||
replacements.push_back(state.at(replacement));
|
||||
|
||||
auto familyName = op.getSequenceAttr();
|
||||
auto name = sharedState.names.newName(familyName.getValue());
|
||||
state[op.getResult()] =
|
||||
sharedState.internalizer.internalize<SequenceStorage>(name, familyName,
|
||||
std::move(args));
|
||||
sharedState.internalizer.internalize<SequenceStorage>(
|
||||
op.getSequenceAttr(), std::move(replacements));
|
||||
return DeletionKind::Delete;
|
||||
}
|
||||
|
||||
FailureOr<DeletionKind> visitOp(InvokeSequenceOp op) {
|
||||
FailureOr<DeletionKind> visitOp(RandomizeSequenceOp op) {
|
||||
auto *seq = get<SequenceStorage *>(op.getSequence());
|
||||
|
||||
auto name = sharedState.names.newName(seq->familyName.getValue());
|
||||
state[op.getResult()] =
|
||||
sharedState.internalizer.internalize<RandomizedSequenceStorage>(name,
|
||||
seq);
|
||||
return DeletionKind::Delete;
|
||||
}
|
||||
|
||||
FailureOr<DeletionKind> visitOp(EmbedSequenceOp op) {
|
||||
return DeletionKind::Keep;
|
||||
}
|
||||
|
||||
|
@ -1227,7 +1273,7 @@ LogicalResult ElaborationPass::elaborateModule(ModuleOp moduleOp,
|
|||
if (table.lookup<SequenceOp>(curr->name))
|
||||
continue;
|
||||
|
||||
auto familyOp = table.lookup<SequenceOp>(curr->familyName);
|
||||
auto familyOp = table.lookup<SequenceOp>(curr->sequence->familyName);
|
||||
// TODO: don't clone if this is the only remaining reference to this
|
||||
// sequence
|
||||
OpBuilder builder(familyOp);
|
||||
|
@ -1243,7 +1289,8 @@ LogicalResult ElaborationPass::elaborateModule(ModuleOp moduleOp,
|
|||
|
||||
Materializer materializer(OpBuilder::atBlockBegin(seqOp.getBody()));
|
||||
Elaborator elaborator(state, materializer);
|
||||
if (failed(elaborator.elaborate(familyOp.getBodyRegion(), curr->args)))
|
||||
if (failed(elaborator.elaborate(familyOp.getBodyRegion(),
|
||||
curr->sequence->args)))
|
||||
return failure();
|
||||
|
||||
materializer.finalize();
|
||||
|
@ -1277,29 +1324,35 @@ LogicalResult ElaborationPass::inlineSequences(TestOp testOp,
|
|||
OpBuilder builder(testOp);
|
||||
for (auto iter = testOp.getBody()->begin();
|
||||
iter != testOp.getBody()->end();) {
|
||||
auto invokeOp = dyn_cast<InvokeSequenceOp>(&*iter);
|
||||
if (!invokeOp) {
|
||||
auto embedOp = dyn_cast<EmbedSequenceOp>(&*iter);
|
||||
if (!embedOp) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto seqClosureOp =
|
||||
invokeOp.getSequence().getDefiningOp<SequenceClosureOp>();
|
||||
if (!seqClosureOp)
|
||||
return invokeOp->emitError(
|
||||
"sequence operand not directly defined by sequence_closure op");
|
||||
auto randSeqOp = embedOp.getSequence().getDefiningOp<RandomizeSequenceOp>();
|
||||
if (!randSeqOp)
|
||||
return embedOp->emitError("sequence operand not directly defined by "
|
||||
"'rtg.randomize_sequence' op");
|
||||
auto getSeqOp = randSeqOp.getSequence().getDefiningOp<SequenceClosureOp>();
|
||||
if (!getSeqOp)
|
||||
return randSeqOp->emitError(
|
||||
"sequence operand not directly defined by 'rtg.sequence_closure' op");
|
||||
|
||||
auto seqOp = table.lookup<SequenceOp>(seqClosureOp.getSequenceAttr());
|
||||
auto seqOp = table.lookup<SequenceOp>(getSeqOp.getSequenceAttr());
|
||||
|
||||
builder.setInsertionPointAfter(invokeOp);
|
||||
builder.setInsertionPointAfter(embedOp);
|
||||
IRMapping mapping;
|
||||
for (auto &op : *seqOp.getBody())
|
||||
builder.clone(op, mapping);
|
||||
|
||||
(iter++)->erase();
|
||||
|
||||
if (seqClosureOp->use_empty())
|
||||
seqClosureOp->erase();
|
||||
if (randSeqOp->use_empty())
|
||||
randSeqOp->erase();
|
||||
|
||||
if (getSeqOp->use_empty())
|
||||
getSeqOp->erase();
|
||||
}
|
||||
|
||||
return success();
|
||||
|
|
|
@ -35,6 +35,17 @@ static void testSequenceType(MlirContext ctx) {
|
|||
mlirTypeDump(sequenceWithArgsTy);
|
||||
}
|
||||
|
||||
static void testRandomizedSequenceType(MlirContext ctx) {
|
||||
MlirType sequenceTy = rtgRandomizedSequenceTypeGet(ctx);
|
||||
|
||||
// CHECK: is_randomized_sequence
|
||||
fprintf(stderr, rtgTypeIsARandomizedSequence(sequenceTy)
|
||||
? "is_randomized_sequence\n"
|
||||
: "isnot_randomized_sequence\n");
|
||||
// CHECK: !rtg.randomized_sequence
|
||||
mlirTypeDump(sequenceTy);
|
||||
}
|
||||
|
||||
static void testLabelType(MlirContext ctx) {
|
||||
MlirType labelTy = rtgLabelTypeGet(ctx);
|
||||
|
||||
|
@ -114,6 +125,7 @@ int main(int argc, char **argv) {
|
|||
mlirDialectHandleLoadDialect(mlirGetDialectHandle__rtg__(), ctx);
|
||||
|
||||
testSequenceType(ctx);
|
||||
testRandomizedSequenceType(ctx);
|
||||
testLabelType(ctx);
|
||||
testSetType(ctx);
|
||||
testBagType(ctx);
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// RUN: circt-opt %s --verify-roundtrip | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: rtg.sequence @ranomizedSequenceType
|
||||
// CHECK-SAME: (%{{.*}}: !rtg.randomized_sequence)
|
||||
rtg.sequence @ranomizedSequenceType(%seq: !rtg.randomized_sequence) {}
|
||||
|
||||
// CHECK-LABEL: rtg.sequence @seq
|
||||
rtg.sequence @seq0() {
|
||||
%arg = arith.constant 1 : index
|
||||
|
@ -23,18 +27,22 @@ rtg.sequence @seqAttrsAndTypeElements(%arg0: !rtg.sequence<!rtg.sequence<!rtg.la
|
|||
// CHECK-SAME: (%arg0: i32, %arg1: !rtg.sequence)
|
||||
rtg.sequence @seq1(%arg0: i32, %arg1: !rtg.sequence) { }
|
||||
|
||||
// CHECK-LABEL: rtg.sequence @invocations
|
||||
rtg.sequence @invocations() {
|
||||
// CHECK-LABEL: rtg.sequence @seqRandomizationAndEmbedding
|
||||
rtg.sequence @seqRandomizationAndEmbedding() {
|
||||
// CHECK: [[V0:%.+]] = rtg.sequence_closure @seq0
|
||||
// CHECK: [[C0:%.+]] = arith.constant 0 : i32
|
||||
// CHECK: [[V1:%.+]] = rtg.sequence_closure @seq1([[C0]], [[V0]] : i32, !rtg.sequence)
|
||||
// CHECK: rtg.invoke_sequence [[V0]]
|
||||
// CHECK: rtg.invoke_sequence [[V1]]
|
||||
// CHECK: [[V2:%.+]] = rtg.randomize_sequence [[V0]]
|
||||
// CHECK: [[V3:%.+]] = rtg.randomize_sequence [[V1]]
|
||||
// CHECK: rtg.embed_sequence [[V2]]
|
||||
// CHECK: rtg.embed_sequence [[V3]]
|
||||
%0 = rtg.sequence_closure @seq0
|
||||
%c0_i32 = arith.constant 0 : i32
|
||||
%1 = rtg.sequence_closure @seq1(%c0_i32, %0 : i32, !rtg.sequence)
|
||||
rtg.invoke_sequence %0
|
||||
rtg.invoke_sequence %1
|
||||
%2 = rtg.randomize_sequence %0
|
||||
%3 = rtg.randomize_sequence %1
|
||||
rtg.embed_sequence %2
|
||||
rtg.embed_sequence %3
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sets
|
||||
|
|
|
@ -23,9 +23,9 @@ rtg.sequence_closure @seq0
|
|||
// -----
|
||||
|
||||
// expected-note @below {{prior use here}}
|
||||
rtg.sequence @seq0(%arg0: !rtg.sequence<i32>) {
|
||||
// expected-error @below {{use of value '%arg0' expects different type than prior uses: '!rtg.sequence' vs '!rtg.sequence<i32>'}}
|
||||
rtg.invoke_sequence %arg0
|
||||
rtg.sequence @seq0(%arg0: !rtg.sequence) {
|
||||
// expected-error @below {{use of value '%arg0' expects different type than prior uses: '!rtg.randomized_sequence' vs '!rtg.sequence'}}
|
||||
rtg.embed_sequence %arg0
|
||||
}
|
||||
|
||||
// -----
|
||||
|
|
|
@ -116,8 +116,9 @@ rtg.sequence @seq0(%arg0: index) {
|
|||
|
||||
rtg.sequence @seq1(%arg0: index) {
|
||||
%0 = rtg.sequence_closure @seq0(%arg0 : index)
|
||||
%1 = rtg.randomize_sequence %0
|
||||
func.call @dummy2(%arg0) : (index) -> ()
|
||||
rtg.invoke_sequence %0
|
||||
rtg.embed_sequence %1
|
||||
func.call @dummy2(%arg0) : (index) -> ()
|
||||
}
|
||||
|
||||
|
@ -129,7 +130,8 @@ rtg.test @nestedSequences : !rtg.dict<> {
|
|||
// CHECK: func.call @dummy2
|
||||
%0 = index.constant 0
|
||||
%1 = rtg.sequence_closure @seq1(%0 : index)
|
||||
rtg.invoke_sequence %1
|
||||
%2 = rtg.randomize_sequence %1
|
||||
rtg.embed_sequence %2
|
||||
}
|
||||
|
||||
rtg.sequence @seq2(%arg0: index) {
|
||||
|
@ -145,9 +147,11 @@ rtg.test @sameSequenceDifferentArgs : !rtg.dict<> {
|
|||
%0 = index.constant 0
|
||||
%1 = index.constant 1
|
||||
%2 = rtg.sequence_closure @seq2(%0 : index)
|
||||
%3 = rtg.sequence_closure @seq2(%1 : index)
|
||||
rtg.invoke_sequence %2
|
||||
rtg.invoke_sequence %3
|
||||
%3 = rtg.randomize_sequence %2
|
||||
%4 = rtg.sequence_closure @seq2(%1 : index)
|
||||
%5 = rtg.randomize_sequence %4
|
||||
rtg.embed_sequence %3
|
||||
rtg.embed_sequence %5
|
||||
}
|
||||
|
||||
rtg.sequence @seq3(%arg0: !rtg.set<index>) {
|
||||
|
@ -166,10 +170,12 @@ rtg.test @sequenceClosureFixesRandomization : !rtg.dict<> {
|
|||
%1 = index.constant 1
|
||||
%2 = rtg.set_create %0, %1 : index
|
||||
%3 = rtg.sequence_closure @seq3(%2 : !rtg.set<index>)
|
||||
%4 = rtg.sequence_closure @seq3(%2 : !rtg.set<index>)
|
||||
rtg.invoke_sequence %3
|
||||
rtg.invoke_sequence %4
|
||||
rtg.invoke_sequence %3
|
||||
%4 = rtg.randomize_sequence %3
|
||||
%5 = rtg.sequence_closure @seq3(%2 : !rtg.set<index>)
|
||||
%6 = rtg.randomize_sequence %5
|
||||
rtg.embed_sequence %4
|
||||
rtg.embed_sequence %6
|
||||
rtg.embed_sequence %4
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @indexOps
|
||||
|
|
Loading…
Reference in New Issue