[RTG] Separate operation for sequence randomization and randomized sequence type (#8147)

This commit is contained in:
Martin Erhart 2025-02-04 16:35:48 +00:00 committed by GitHub
parent e4d67daaf5
commit e4eb532604
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 224 additions and 79 deletions

View File

@ -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);

View File

@ -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";
}

View File

@ -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()">,

View File

@ -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);

View File

@ -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():

View File

@ -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",

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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
}
// -----

View File

@ -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