Random Test Generation (RTG) Rationale
This dialect provides types, operations, and interfaces modeling randomization constructs for random test generation. Furthermore, it contains passes to perform and analyze the represented randomization.
Rationale ¶
This dialect aims to provide a unified representation for randomized tests, more precisely the parts of the tests that encode the randomization constructs (e.g., picking a random resource from a set of resources). This means, this dialect is only useful in combination with at least one other dialect that represents the actual test constructs, i.e., the parts that get randomized. After all the randomization constructs are fully elaborated, the resulting test will only consist of those dialects.
Examples for tests that can be randomized, and thus candidates for companion dialects, are instruction sequences of any ISA (Instruction Set Architecture), transaction sequences over a latency insensitive (ready-valid) channel, input sequences to an FSM (Finite State Machine), transaction sequences for potentially any other protocol. Albeit, the initial motivation is ISA tests and will thus be the best supported, at least initially.
While it should be valid to add constructs to this dialect that are special to any of the above mentioned use-cases, the dialect should generally be designed such that all of them can be supported.
Interfacing with the RTG dialect ¶
The RTG dialect is only useful in combination with at least one other dialect representing the test. Such a dialect has to be aware of the RTG dialect and has to implement various interfaces (depending on which parts of the RTG infrastructure it intends to use).
A test can be declared with the rtg.test operation which takes an
!rtg.target type attribute to specify requirements for the test to be able to
be generated and executed. In addition to the target having to provide an
!rtg.target typed value that is a refinement of the required target type, the
test can specify additional requirements using the rtg.require operation.
Targets can be defined using the rtg.target operation. Certain operations
are only allowed inside the target operation but not the test operation to
guarantee that certain resources (specifically contexts) cannot be generated
on-the-fly.
The RTG framework will match all tests with all targets that fulfill their requirements. The user can specify which targets and tests should be included in the test generation process and how many tests should be generated per target or in total.
Currently, there are three concepts in the RTG dialect the companion dialects can map their constructs to:
- Instructions: instructions/operations intended to be performed in series by the test, such as ISA instructions, or protocol transactions
- Resources: resources the instructions operate on, such as registers or memories in ISA tests, or channels in hardware transaction tests
- Contexts: the context or environment the instuctions are performed in, e.g., on which CPU and in which mode for ISA test.
To express their mapping, the companion dialects must implement the the interfaces as follows.
Instructions
They implement InstructionOpInterface on all operations that represent an
instruction, transaction, or similar. Those operations are intended to be
statements and not define SSA values.
Resources
Operations that create, declare, define, or produce a handle to a resource
instance must implement the ResourceOpInterface interface and define at least
one SSA value of a type that implements the ResourceTypeInterface interface.
(TODO: maybe we don’t actually need the ResourceTypeInterface?)
The RegisterOpInterface can be implemented in addition to the
ResourceOpInterface if the resource is a register to become supported by the
register allocation and assembly emission pass.
Contexts
The ContextResourceType is used to represent contexts. Instructions can be
placed in specific context using the rtg.on_context operation (Note: we might
promote this to a type interface in the future).
Operations that define contexts (i.e., create new contexts) must implement the
ContextResourceOpInterface interface.
Operations implementing the ContextResourceOpInterface interface are only
allowed inside the rtg.target operation.
Randomization ¶
This dialect aims to provide utilities that allow users to generate tests anywhere on the spectrum from directed tests to (almost) fully random tests (refer to fuzzing).
- Constraints: allow the user to specify constraints to avoid generating
illegal or useless tests, e.g., by
- allowing to specify a sequence of instructions that always have to be picked
in exactly that order and form (see
rtg.sequenceoperation) - dependencies between resources or resource usages
- etc.
- allowing to specify a sequence of instructions that always have to be picked
in exactly that order and form (see
- Probabilities and Biases: allow certain tests (or parts of a test) to be
picked more likely than others (can be seen as ‘soft-constraints’) (see
!rtg.bagtype and associated operations) - Enumerations: allow to enumerate all tests that can be produced by the current randomness constraints, possibly in a way that places the more likely tests to occur earlier in the enumeration
(TODO: expand here once these things are built out)
Main IR constructs to introduce randomness:
- Sets: a set of elements of the same type; the usual set operations apply as well as uniformly at random picking one element of the set
- Bags/Biased Sets: a generalization of sets that allows one element to occur multiple times and thus make it more likely to be picked (i.e., models non-uniform distributions)
Example ¶
This section provides an (almost) E2E walkthrough of a simple example starting
at a Python implmentation using the library wrapping around the python bindings,
showing the generated RTG IR, and the fully elaborated IR. This compilation
process can be performed in one go using the rtgtool.py driver script.
# Define a test target (essentially a design/machine with 4 CPUs)
@rtg.target([('cpus', rtg.set_of(rtg.context_resource()))])
def example_target():
# return a set containing 4 CPUs which the test can schedule instruction
# sequences on
return [rtg.Set.create([rv64.core(0), rv64.core(1), rv64.core(2), rv64.core(3)])]
# Define a sequence (for simplicity it only contains one instruction)
# Note: not adding the sequence decorator is also valid in this example but
# means the function is fully inlined at python execution time. It is not valid,
# however, if the sequence is added to a set or bag to be selected at random.
@rtg.sequence
def seq(register):
# ADD Immediate instruction adding 4 to to the given register
rtgtest.addi(register, rtgtest.imm(4, 12))
# Define a test that requires a target with CPUs to schedule instruction
# sequences on
@rtg.test([('cpus', rtg.set_of(rtg.context_resource()))])
def example(cpus):
# Pick a random CPU and schedule the ADD operation on it
with rtg.context(cpus.get_random_and_exclude()):
rtg.label('label0')
seq(rtgtest.sp())
# Pick a random CPU that was not already picked above and zero out the stack
# pointer register on it
with rtg.context(cpus.get_random()):
ra = rtgtest.sp()
rtgtest.xor(ra, ra)
The driver script will elaborate this python file and produce the following RTG IR as an intermediate step:
rtg.target @example_target : !rtg.target<cpus: !rtg.set<!rtg.context_resource>> {
%0 = rtgtest.coreid 0
%1 = rtgtest.coreid 1
%2 = rtgtest.coreid 2
%3 = rtgtest.coreid 3
%4 = rtg.set_create %0, %1, %2, %3 : !rtg.context_resource
rtg.yield %4 : !rtg.set<!rtg.context_resource>
}
rtg.sequence @seq {
^bb0(%reg: !rtgtest.reg):
%c4_i12 = arith.constant 4 : i12
rtgtest.addi %reg, %c4_i12
}
rtg.sequence @context0 {
// Labels are declared before being placed in the instruction stream such that
// we can insert jump instructions before the jump target.
%0 = rtg.label.decl "label0" -> index
rtg.label %0 : index
%sp = rtgtest.sp
// Construct a closure such that it can be easily passed around, e.g.,
// inserted into a set with other sequence closures to be selected at random.
%1 = rtg.sequence_closure @seq(%sp) : !rtgtest.reg
// Place the sequence here (i.e., inline it here with the arguments passed to
// the closure).
// This is essentially the same as an `rtg.on_context` with the context
// operand matching the one of the parent `on_context`.
rtg.sequence_invoke %1
}
rtg.sequence @context1 {
%0 = rtgtest.sp
rtgtest.xor %sp, %sp
}
rtg.test @example : !rtg.target<cpus: !rtg.set<!rtg.context_resource>> {
^bb0(%arg0: !rtg.set<!rtg.context_resource>):
// Select an element from the set uniformly at random
%0 = rtg.set_select_random %arg0 : !rtg.set<!rtg.context_resource>
%3 = rtg.sequence_closure @context0
// Place the sequence closure on the given context. In this example, there
// will be guards inserted that make sure the inlined sequence is only
// executed by the CPU specified by the selected coreid.
rtg.on_context %0, %3 : !rtg.context_resource
// Construct a new set that doesn't contain the selected element (RTG sets are
// immutable) and select another element randomly from this new set.
%1 = rtg.set_create %0 : !rtg.context_resource
%2 = rtg.set_difference %arg0, %1 : !rtg.set<!rtg.context_resource>
%7 = rtg.set_select_random %2 : !rtg.set<!rtg.context_resource>
%8 = rtg.sequence_closure @context1
rtg.on_context %7, %8 : !rtg.context_resource
}
Once all the RTG randomization passes were performed, the example looks like this:
// Two regions, the first one to be executed on CPU with coreid 0 and the second
// one on CPU with coreid 2
rtg.rendered_context [0,2] {
%0 = rtg.label.decl "label0" -> index
rtg.label %0 : index
%reg = rtgtest.sp
%c4 = arith.constant 4 : i12
rtgtest.addi %sp, %c4
// Is emitted to assembly looking something like:
// label0:
// addi sp, 4
}, {
%sp = rtgtest.sp
rtgtest.xor %sp, %sp
}
The last step to run this test is to print it in assembly format and invoke the assembler. This also includes the insertion of a considerable amount of boilerplate setup code to run the above instructions on the right CPUs which is omitted in this example for clarity.
Use-case-specific constructs ¶
This section provides an overview of operations/types/interfaces added with the intend to be only used for one (or a few) specific use-cases/test-targets.
ISA Tests ¶
- Labels: Handling of labels is added to the RTG dialect because they are common across ISAs. Leaving them to the ISA specific companion dialects would likely lead to frequent code duplication (once for each ISA).
- Register Allocation Pass
- Assembly Emission Pass
Frontends ¶
Any dialect or entry point is allowed to generate valid RTG IR with a companion dialect. The dialect already comes with an extensive CAPI, Python Bindings, and a small Python library that simplify usage over the pure Python Bindings.
Backends ¶
The RTG dialect does not have a backend itself. It is fully lowered by its dialect transformation passes that perform the randomization. The result will be IR consisting purely of the companion dialect and thus it is up to this companion dialect to define any backends.
Operations ¶
rtg.array_append (::circt::rtg::ArrayAppendOp) ¶
Append an element to an array
Syntax:
operation ::= `rtg.array_append` $array `,` $element `:` qualified(type($array)) attr-dict
This operation produces a new array of the same type as the input array with the given element appended at the end. All other values remain the same.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
array | an array type with dynamic size |
element | any type |
Results: ¶
| Result | Description |
|---|---|
result | an array type with dynamic size |
rtg.array_create (::circt::rtg::ArrayCreateOp) ¶
Create an array with an initial list of elements
This operation creates an array from a list of values. The element on the left-most position in the MLIR assembly format ends up at index 0.
Traits: AlwaysSpeculatableImplTrait, SameTypeOperands
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
elements | variadic of any type |
Results: ¶
| Result | Description |
|---|---|
result | an array type with dynamic size |
rtg.array_extract (::circt::rtg::ArrayExtractOp) ¶
Get an element from an array
Syntax:
operation ::= `rtg.array_extract` $array `[` $index `]` `:` qualified(type($array)) attr-dict
This operation returns the element at the given index of the array. Accessing out-of-bounds indices is (immediate) UB.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
array | an array type with dynamic size |
index | index |
Results: ¶
| Result | Description |
|---|---|
result | any type |
rtg.array_inject (::circt::rtg::ArrayInjectOp) ¶
Set an element in an array
Syntax:
operation ::= `rtg.array_inject` $array `[` $index `]` `,` $value `:` qualified(type($array)) attr-dict
This operation produces a new array of the same type as the input array and sets the element at the given index to the given value. All other values remain the same. An OOB access is (immediate) undefined behavior.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
array | an array type with dynamic size |
index | index |
value | any type |
Results: ¶
| Result | Description |
|---|---|
result | an array type with dynamic size |
rtg.array_size (::circt::rtg::ArraySizeOp) ¶
Return the size of an array
Syntax:
operation ::= `rtg.array_size` $array `:` qualified(type($array)) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
array | an array type with dynamic size |
Results: ¶
| Result | Description |
|---|---|
result | index |
rtg.bag_convert_to_set (::circt::rtg::BagConvertToSetOp) ¶
Convert a bag to a set
Syntax:
operation ::= `rtg.bag_convert_to_set` $input `:` qualified(type($input)) attr-dict
This operation converts a bag to a set by dropping all duplicate elements.
For example, the bag {a, a, b} is converted to {a, b}.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
input | a bag of values |
Results: ¶
| Result | Description |
|---|---|
result | a set of values |
rtg.bag_create (::circt::rtg::BagCreateOp) ¶
Constructs a bag
This operation constructs a bag with the provided values and associated
multiples. This means the bag constructed in the following example contains
two of each %arg0 and %arg0 ({%arg0, %arg0, %arg1, %arg1}).
%0 = arith.constant 2 : index
%1 = rtg.bag_create (%0 x %arg0, %0 x %arg1) : i32
Traits: AlwaysSpeculatableImplTrait, SameVariadicOperandSize
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
elements | variadic of any type |
multiples | variadic of index |
Results: ¶
| Result | Description |
|---|---|
bag | a bag of values |
rtg.bag_difference (::circt::rtg::BagDifferenceOp) ¶
Computes the difference of two bags
Syntax:
operation ::= `rtg.bag_difference` $original `,` $diff (`inf` $inf^)? `:` qualified(type($output)) attr-dict
For each element the resulting bag will have as many fewer than the ‘original’ bag as there are in the ‘diff’ bag. However, if the ‘inf’ attribute is attached, all elements of that kind will be removed (i.e., it is assumed the ‘diff’ bag has infinitely many copies of each element).
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
inf | ::mlir::UnitAttr | unit attribute |
Operands: ¶
| Operand | Description |
|---|---|
original | a bag of values |
diff | a bag of values |
Results: ¶
| Result | Description |
|---|---|
output | a bag of values |
rtg.bag_select_random (::circt::rtg::BagSelectRandomOp) ¶
Select a random element from the bag
Syntax:
operation ::= `rtg.bag_select_random` $bag `:` qualified(type($bag)) attr-dict
This operation returns an element from the bag selected uniformely at random. Therefore, the number of duplicates of each element can be used to bias the distribution. If the bag does not contain any elements, the behavior of this operation is undefined.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
bag | a bag of values |
Results: ¶
| Result | Description |
|---|---|
output | any type |
rtg.bag_union (::circt::rtg::BagUnionOp) ¶
Computes the union of bags
Syntax:
operation ::= `rtg.bag_union` $bags `:` qualified(type($result)) attr-dict
Computes the union of the given bags. The list of sets must contain at least one element.
Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
bags | variadic of a bag of values |
Results: ¶
| Result | Description |
|---|---|
result | a bag of values |
rtg.bag_unique_size (::circt::rtg::BagUniqueSizeOp) ¶
Returns the number of unique elements in the bag
Syntax:
operation ::= `rtg.bag_unique_size` $bag `:` qualified(type($bag)) attr-dict
This operation returns the number of unique elements in the bag, i.e., for
the bag {a, a, b, c, c} it returns 3.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
bag | a bag of values |
Results: ¶
| Result | Description |
|---|---|
result | index |
rtg.comment (::circt::rtg::CommentOp) ¶
Emit a comment in instruction stream
Syntax:
operation ::= `rtg.comment` $comment attr-dict
Operands: ¶
| Operand | Description |
|---|---|
comment | a string type |
rtg.constant (::circt::rtg::ConstantOp) ¶
Create an SSA value from an attribute
Syntax:
operation ::= `rtg.constant` $value attr-dict
Traits: AlwaysSpeculatableImplTrait, ConstantLike
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), OpAsmOpInterface
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
value | ::mlir::TypedAttr | TypedAttr instance |
Results: ¶
| Result | Description |
|---|---|
result | any type |
rtg.constraint (::circt::rtg::ConstraintOp) ¶
Enforce a constraint
Syntax:
operation ::= `rtg.constraint` $condition attr-dict
This operation enforces a constraint. This allows to specify additional constraints on values after their construction. It should be avoided when possible as these backward constraints are computationally more expensive.
Constraints should be tried to be solved such that all of them evaluate to ’true’. If the constraint system turns out to be unsolvable, the compiler should error out gracefully as early as possible (it might also error out when the system is too expensive to solve).
Operands: ¶
| Operand | Description |
|---|---|
condition | 1-bit signless integer |
rtg.context_switch (::circt::rtg::ContextSwitchOp) ¶
A specification of how to switch contexts
Syntax:
operation ::= `rtg.context_switch` $from `->` $to `,` $sequence `:` qualified(type($sequence)) attr-dict
This operation allows the user to specify a sequence of instructions to switch from context ‘from’ to context ’to’, randomize and embed a provided sequence, and switch back from context ’to’ to context ‘from’. This sequence of instructions should be provided as the ‘sequence’ operand which is a sequence of the type ‘!rtg.sequence<context-type-interface, context-type-interface, !rtg.sequence>’. The first parameter is the ‘from’ context, the second one the ’to’ context, and the third is the sequence to randomize and embed under the ’to’ context.
Traits: HasParent<rtg::TargetOp>
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
from | ::circt::rtg::ContextResourceAttrInterface | ContextResourceAttrInterface instance |
to | ::circt::rtg::ContextResourceAttrInterface | ContextResourceAttrInterface instance |
Operands: ¶
| Operand | Description |
|---|---|
sequence | handle to a sequence or sequence family |
rtg.embed_sequence (::circt::rtg::EmbedSequenceOp) ¶
Embed a sequence of instructions into another sequence
Syntax:
operation ::= `rtg.embed_sequence` $sequence attr-dict
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.
Operands: ¶
| Operand | Description |
|---|---|
sequence | handle to a fully randomized sequence |
rtg.get_sequence (::circt::rtg::GetSequenceOp) ¶
Create a sequence value
Syntax:
operation ::= `rtg.get_sequence` $sequence `:` qualified(type($ref)) attr-dict
This operation creates a sequence value referring to the provided sequence by symbol. It allows sequences to be passed around as an SSA value. For example, it can be inserted into a set and selected at random which is one of the main ways to do randomization.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), SymbolUserOpInterface
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
sequence | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
Results: ¶
| Result | Description |
|---|---|
ref | handle to a sequence or sequence family |
rtg.immediate_format (::circt::rtg::ImmediateFormatOp) ¶
Convert an immediate to a string
Syntax:
operation ::= `rtg.immediate_format` $value `:` qualified(type($value)) attr-dict
This operation converts an immediate value to its string representation. The immediate is formatted as a decimal number.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
value | an ISA immediate |
Results: ¶
| Result | Description |
|---|---|
result | a string type |
rtg.int_format (::circt::rtg::IntFormatOp) ¶
Format an integer as a string
Syntax:
operation ::= `rtg.int_format` $value attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
value | index |
Results: ¶
| Result | Description |
|---|---|
result | a string type |
rtg.interleave_sequences (::circt::rtg::InterleaveSequencesOp) ¶
Interleave a list of sequences
Syntax:
operation ::= `rtg.interleave_sequences` $sequences (`batch` $batchSize^)? attr-dict
This operation takes a list of (at least one) fully randomized sequences and
interleaves them by taking the next batchSize number of operations
implementing the InstructionOpInterface of each sequence round-robin.
Therefore, if only one sequence is in the list, this operation returns that sequence unchanged.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
batchSize | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Operands: ¶
| Operand | Description |
|---|---|
sequences | variadic of handle to a fully randomized sequence |
Results: ¶
| Result | Description |
|---|---|
interleavedSequence | handle to a fully randomized sequence |
rtg.isa.concat_immediate (::circt::rtg::ConcatImmediateOp) ¶
Concatenate immediates
Syntax:
operation ::= `rtg.isa.concat_immediate` $operands `:` qualified(type($operands)) attr-dict
This operation concatenates a variadic number of immediates into a single immediate. The operands are concatenated in order, with the first operand becoming the most significant bits of the result.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
operands | variadic of an ISA immediate |
Results: ¶
| Result | Description |
|---|---|
result | an ISA immediate |
rtg.isa.index_to_register (::circt::rtg::IndexToRegisterOp) ¶
Convert an index to a register
Syntax:
operation ::= `rtg.isa.index_to_register` $index `:` type($reg) attr-dict
This operation converts an index to the register with matching class index. The index must refer to a valid register index. Invalid indices are (immediate) UB.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
index | index |
Results: ¶
| Result | Description |
|---|---|
reg | RegisterTypeInterface instance |
rtg.isa.int_to_immediate (::circt::rtg::IntToImmediateOp) ¶
Construct an immediate from an integer
Syntax:
operation ::= `rtg.isa.int_to_immediate` $input `:` qualified(type($result)) attr-dict
Create an immediate of static bit-width from the provided integer. If the integer does not fit in the specified bit-width, an error shall be emitted when executing this operation.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
input | index |
Results: ¶
| Result | Description |
|---|---|
result | an ISA immediate |
rtg.isa.memory_alloc (::circt::rtg::MemoryAllocOp) ¶
Allocate a memory with the provided properties
Syntax:
operation ::= `rtg.isa.memory_alloc` $memoryBlock `,` $size `,` $alignment
`:` qualified(type($memoryBlock)) attr-dict
This operation declares a memory to be allocated with the provided
properties. It is only allowed to declare new memories in the rtg.target
operations and must be passed as argument to the rtg.test.
Interfaces: InferTypeOpInterface
Operands: ¶
| Operand | Description |
|---|---|
memoryBlock | handle to a memory block |
size | index |
alignment | index |
Results: ¶
| Result | Description |
|---|---|
result | handle to a memory |
rtg.isa.memory_base_address (::circt::rtg::MemoryBaseAddressOp) ¶
Get the memory base address as an immediate
Syntax:
operation ::= `rtg.isa.memory_base_address` $memory `:` qualified(type($memory)) attr-dict
This operation returns the base address of the given memory. The bit-width of the returned immediate must match the address width of the given memory.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
memory | handle to a memory |
Results: ¶
| Result | Description |
|---|---|
result | an ISA immediate |
rtg.isa.memory_block_declare (::circt::rtg::MemoryBlockDeclareOp) ¶
Declare a memory block with the provided properties
This operation declares a memory block to be allocated with the provided
properties. It is only allowed to declare new memory blocks in the
rtg.target operations and must be passed as argument to the rtg.test.
This is because the available memory blocks are specified by the hardware
design. This specification is fixed from the start and thus a test should
not be able to declare new memory blocks on-the-fly. However, tests are
allowed to allocate memory regions from these memory blocks.
The ‘baseAddress’ attribute specifies the first memory address (lowest address representing a valid access to the memory) and the ’endAddress’ represents the last address (highest address that is valid to access the memory).
Traits: HasParent<rtg::TargetOp>
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
baseAddress | ::mlir::IntegerAttr | arbitrary integer attribute |
endAddress | ::mlir::IntegerAttr | arbitrary integer attribute |
Results: ¶
| Result | Description |
|---|---|
result | handle to a memory block |
rtg.isa.memory_size (::circt::rtg::MemorySizeOp) ¶
Get the size of the memory in bytes
Syntax:
operation ::= `rtg.isa.memory_size` $memory `:` qualified(type($memory)) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
memory | handle to a memory |
Results: ¶
| Result | Description |
|---|---|
result | index |
rtg.isa.register_to_index (::circt::rtg::RegisterToIndexOp) ¶
Convert a register to its class index
Syntax:
operation ::= `rtg.isa.register_to_index` $reg `:` type($reg) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
reg | RegisterTypeInterface instance |
Results: ¶
| Result | Description |
|---|---|
index | index |
rtg.isa.segment (::circt::rtg::SegmentOp) ¶
Defines a new segment
Syntax:
operation ::= `rtg.isa.segment` $kind attr-dict-with-keyword $bodyRegion
Traits: NoRegionArguments, NoTerminator, SingleBlock
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
kind | ::circt::rtg::SegmentKindAttr | kind of segment |
rtg.isa.slice_immediate (::circt::rtg::SliceImmediateOp) ¶
Extract a slice from an immediate
Syntax:
operation ::= `rtg.isa.slice_immediate` $input `from` $lowBit `:`
qualified(type($input)) `->` qualified(type($result)) attr-dict
This operation extracts a contiguous slice of bits from an immediate value. The slice is specified by a low bit index (inclusive) and the width of the slice is determined by the result type. The slice must fit within the input immediate’s width.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
lowBit | ::mlir::IntegerAttr | 32-bit signless integer attribute |
Operands: ¶
| Operand | Description |
|---|---|
input | an ISA immediate |
Results: ¶
| Result | Description |
|---|---|
result | an ISA immediate |
rtg.isa.space (::circt::rtg::SpaceOp) ¶
Reserve the given number of bytes
Syntax:
operation ::= `rtg.isa.space` $size attr-dict
Operands: ¶
| Operand | Description |
|---|---|
size | index |
rtg.isa.string_data (::circt::rtg::StringDataOp) ¶
Reserve a string
Syntax:
operation ::= `rtg.isa.string_data` $data attr-dict
Always appends a zero character (\00).
Operands: ¶
| Operand | Description |
|---|---|
data | a string type |
rtg.label (::circt::rtg::LabelOp) ¶
Places a label in an instruction sequence
Syntax:
operation ::= `rtg.label` $visibility $label attr-dict
Any declared label must only be placed at most once in any fully elaborated instruction sequence.
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
visibility | ::circt::rtg::LabelVisibilityAttr | visibility specifiers for labels |
Operands: ¶
| Operand | Description |
|---|---|
label | a reference to a label |
rtg.label_unique_decl (::circt::rtg::LabelUniqueDeclOp) ¶
Declares a unique label for an instruction sequence
Syntax:
operation ::= `rtg.label_unique_decl` $namePrefix attr-dict
Declares a label that can then be placed by an rtg.label operation in an
instruction sequence, passed on to sequences via their arguments, and used
by instructions (e.g., as jump targets) by allowing ISA dialects to use them
directly as an operand of an instruction or by casting it to a value
representing an immediate.
The provided ’name’ value is used as a prefix for the unique label name.
Interfaces: InferTypeOpInterface
Operands: ¶
| Operand | Description |
|---|---|
namePrefix | a string type |
Results: ¶
| Result | Description |
|---|---|
label | a reference to a label |
rtg.on_context (::circt::rtg::OnContextOp) ¶
Places a sequence on a context
Syntax:
operation ::= `rtg.on_context` $context `,` $sequence `:` qualified(type($context)) attr-dict
This operation takes a context and a fully substituted, but not yet randomized sequence and inserts the necessary instructions to switch from the current context to the provided context, randomizes and embeds the given sequence under the given context, and inserts instructions to switch back to the original context.
These instructions are provided by the ‘rtg.context_switch’ operation. If no ‘rtg.context_switch’ for this transition is provided, the compiler will error out. If multiple such context switches apply, the most recently registered one takes precedence.
Operands: ¶
| Operand | Description |
|---|---|
context | ContextResourceTypeInterface instance |
sequence | fully substituted sequence type |
rtg.random_number_in_range (::circt::rtg::RandomNumberInRangeOp) ¶
Returns a number uniformly at random within the given range
Syntax:
operation ::= `rtg.random_number_in_range` ` ` `[` $lowerBound `,` $upperBound `]` attr-dict
This operation computes a random number based on a uniform distribution within the given range. Both the lower and upper bounds are inclusive. If the range is empty, compilation will fail. This is (obviously) more performant than inserting all legal numbers into a set and using ‘set_select_random’, but yields the same behavior.
Interfaces: InferTypeOpInterface
Operands: ¶
| Operand | Description |
|---|---|
lowerBound | index |
upperBound | index |
Results: ¶
| Result | Description |
|---|---|
result | index |
rtg.random_scope (::circt::rtg::RandomScopeOp) ¶
Introduce a new scope for randomization
Syntax:
operation ::= `rtg.random_scope` (`seed` $seed^)? attr-dict-with-keyword (`:` type($results)^)? $bodyRegion
This operation introduces a new scope for randomization. This is useful to isolate randomization such that the same sequence of operations in the parent scope yields the same RNG results despite operations being added in this scope.
The optional seed attribute can be used to fix the RNG seed of this scope such that changes in the parent region do not affect the RNG results in this scope. This attribute is intended for internal uses (e.g., regression tests) and not exposed to the frontend user.
Traits: NoRegionArguments, SingleBlockImplicitTerminator<rtg::YieldOp>, SingleBlock
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
seed | ::mlir::IntegerAttr | index attribute |
Results: ¶
| Result | Description |
|---|---|
results | variadic of any type |
rtg.randomize_sequence (::circt::rtg::RandomizeSequenceOp) ¶
Randomize the content of a sequence
Syntax:
operation ::= `rtg.randomize_sequence` $sequence attr-dict
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.
Interfaces: InferTypeOpInterface
Operands: ¶
| Operand | Description |
|---|---|
sequence | fully substituted sequence type |
Results: ¶
| Result | Description |
|---|---|
randomizedSequence | handle to a fully randomized sequence |
rtg.register_format (::circt::rtg::RegisterFormatOp) ¶
Convert a register to its name as a string
Syntax:
operation ::= `rtg.register_format` $value `:` qualified(type($value)) attr-dict
This operation converts a register to its assembly name as a string. The string representation is obtained from the register’s assembly format.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
value | RegisterTypeInterface instance |
Results: ¶
| Result | Description |
|---|---|
result | a string type |
rtg.sequence (::circt::rtg::SequenceOp) ¶
A sequence of instructions
This operation collects a sequence of instructions such that they can be placed as one unit. This is effectively the way to impose a constraint on the order and presence of some instructions.
It is allowed to contain randomization constructs and invokations on any contexts. It is not allowed to create new context resources inside a sequence, however.
This operation can be invoked by the invoke and on_context operations.
It is referred to by symbol and isolated from above to ease multi-threading
and it allows the rtg.test operation to be isolated-from-above to provide
stronger top-level isolation guarantees.
Traits: HasParent<mlir::ModuleOp>, IsolatedFromAbove, NoTerminator, SingleBlock
Interfaces: SymbolOpInterface
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
sequenceType | ::mlir::TypeAttr | type attribute of handle to a sequence or sequence family |
rtg.set_cartesian_product (::circt::rtg::SetCartesianProductOp) ¶
Computes the n-ary cartesian product of sets
Syntax:
operation ::= `rtg.set_cartesian_product` $inputs `:` qualified(type($inputs)) attr-dict
This operation computes a set of tuples from a list of input sets such that
each combination of elements from the input sets is present in the result
set. More formally, for n input sets it computes
X_1 x ... x X_n = {(x_1, ..., x_n) | x_i \in X_i for i \in {1, ..., n}}.
At least one input set has to be provided (i.e., n > 0).
For example, given two sets A and B with elements
A = {a0, a1}, B = {b0, b1} the result set R will be
R = {(a0, b0), (a0, b1), (a1, b0), (a1, b1)}.
Note that an RTG set does not provide any guarantees about the order of elements an can thus not be iterated over or indexed into, however, a random element can be selected and subtracted from the set until it is empty. This procedure is determinstic and will yield the same sequence of elements for a fixed seed and RTG version. If more guarantees about the order of elements is necessary, use arrays instead (and compute the cartesian product manually using nested loops).
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
inputs | variadic of a set of values |
Results: ¶
| Result | Description |
|---|---|
result | a set of values |
rtg.set_convert_to_bag (::circt::rtg::SetConvertToBagOp) ¶
Convert a set to a bag
Syntax:
operation ::= `rtg.set_convert_to_bag` $input `:` qualified(type($input)) attr-dict
This operation converts a set to a bag. Each element in the set occurs exactly once in the resulting bag.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
input | a set of values |
Results: ¶
| Result | Description |
|---|---|
result | a bag of values |
rtg.set_create (::circt::rtg::SetCreateOp) ¶
Constructs a set of the given values
Traits: AlwaysSpeculatableImplTrait, SameTypeOperands
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
elements | variadic of any type |
Results: ¶
| Result | Description |
|---|---|
set | a set of values |
rtg.set_difference (::circt::rtg::SetDifferenceOp) ¶
Computes the difference of two sets
Syntax:
operation ::= `rtg.set_difference` $original `,` $diff `:` qualified(type($output)) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
original | a set of values |
diff | a set of values |
Results: ¶
| Result | Description |
|---|---|
output | a set of values |
rtg.set_select_random (::circt::rtg::SetSelectRandomOp) ¶
Selects an element uniformly at random from a set
Syntax:
operation ::= `rtg.set_select_random` $set `:` qualified(type($set)) attr-dict
This operation returns an element from the given set uniformly at random. Applying this operation to an empty set is undefined behavior.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
set | a set of values |
Results: ¶
| Result | Description |
|---|---|
output | any type |
rtg.set_size (::circt::rtg::SetSizeOp) ¶
Returns the number of elements in the set
Syntax:
operation ::= `rtg.set_size` $set `:` qualified(type($set)) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
set | a set of values |
Results: ¶
| Result | Description |
|---|---|
result | index |
rtg.set_union (::circt::rtg::SetUnionOp) ¶
Computes the union of sets
Syntax:
operation ::= `rtg.set_union` $sets `:` qualified(type($result)) attr-dict
Computes the union of the given sets. The list of sets must contain at least one element.
Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
sets | variadic of a set of values |
Results: ¶
| Result | Description |
|---|---|
result | a set of values |
rtg.string_concat (::circt::rtg::StringConcatOp) ¶
Concatenate strings
Syntax:
operation ::= `rtg.string_concat` $strings attr-dict
This operation concatenates a variadic number of strings into a single string. The operands are concatenated in order, with the first operand becoming the most significant bits of the result.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
strings | variadic of a string type |
Results: ¶
| Result | Description |
|---|---|
result | a string type |
rtg.string_to_label (::circt::rtg::StringToLabelOp) ¶
Converts a string to a label
Syntax:
operation ::= `rtg.string_to_label` $string attr-dict
This operation converts a string to a label. The label name is not uniqued and it is the user’s responsibility to ensure that the label name is valid in the target assembly.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
string | a string type |
Results: ¶
| Result | Description |
|---|---|
label | a reference to a label |
rtg.substitute_sequence (::circt::rtg::SubstituteSequenceOp) ¶
Partially substitute arguments of a sequence family
This operation substitutes the first N of the M >= N arguments of the given sequence family, where N is the size of provided argument substitution list. A new sequence (if N == M) or sequence family with M-N will be returned.
Not having to deal with sequence arguments after randomly selecting a sequence simplifies the problem of coming up with values to pass as arguments, but also provides a way for the user to constrain the arguments at the location where they are added to a set or bag.
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
sequence | handle to a sequence or sequence family |
replacements | variadic of any type |
Results: ¶
| Result | Description |
|---|---|
result | handle to a sequence or sequence family |
rtg.target (::circt::rtg::TargetOp) ¶
Defines a test target
Syntax:
operation ::= `rtg.target` $sym_name `:` $target attr-dict-with-keyword $bodyRegion
This operation specifies capabilities of a specific test target and can
provide additional information about it. These are added as operands to the
yield terminator and implicitly packed up into an !rtg.dict type which
is passed to tests that are matched with this target.
These capabilities can, for example, consist of the number of CPUs, supported priviledge modes, available memories, etc.
Traits: HasParent<mlir::ModuleOp>, IsolatedFromAbove, NoRegionArguments, SingleBlockImplicitTerminator<rtg::YieldOp>, SingleBlock
Interfaces: Symbol
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
target | ::mlir::TypeAttr | type attribute of a dictionary |
rtg.test (::circt::rtg::TestOp) ¶
The root of a test
This operation declares the root of a randomized or directed test.
The target attribute specifies requirements of this test. These can be
refined by rtg.require operations inside this operation’s body. A test
can only be matched with a target if the target fulfills all the test’s
requirements. However, the target may provide more than the test requires.
For example, if the target allows execution in a user and privileged mode,
but the test only requires and runs in user mode, it can still be matched
with that target.
By default each test can be matched with all targets that fulfill its requirements, but the user can also directly provide a target via the ’target’ attribute. In that case, the test will only be randomized against that target.
The ’templateName’ attribute specifies the name of the original test template (mostly for result reporting purposes). This is because a test (template) can be matched against many targets and during this process one test per match is created, but all of them preserve the same test template name.
The body of this operation shall be processed the same way as an
rtg.sequence’s body with the exception of the block arguments.
The arguments must match the fields of the dict type in the target attribute
exactly. The test must not have any additional arguments and cannot be
referenced by an rtg.get_sequence operation.
If the end of the test is reached without executing an rtg.test.success
or rtg.test.failure it is as if an rtg.test.success is executed at the
very end.
Traits: HasParent<mlir::ModuleOp>, IsolatedFromAbove, NoTerminator, SingleBlock
Interfaces: Emittable, OpAsmOpInterface, SymbolUserOpInterface, Symbol
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
templateName | ::mlir::StringAttr | string attribute |
targetType | ::mlir::TypeAttr | type attribute of a dictionary |
target | ::mlir::StringAttr | string attribute |
rtg.test.failure (::circt::rtg::TestFailureOp) ¶
Exit the test and report failure
Syntax:
operation ::= `rtg.test.failure` $errorMessage attr-dict
Operands: ¶
| Operand | Description |
|---|---|
errorMessage | a string type |
rtg.test.success (::circt::rtg::TestSuccessOp) ¶
Exit the test and report success
Syntax:
operation ::= `rtg.test.success` attr-dict
rtg.tuple_create (::circt::rtg::TupleCreateOp) ¶
Create a tuple
Syntax:
operation ::= `rtg.tuple_create` ($elements^ `:` qualified(type($elements)))? attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
elements | variadic of any type |
Results: ¶
| Result | Description |
|---|---|
result | a tuple of zero or more fields |
rtg.tuple_extract (::circt::rtg::TupleExtractOp) ¶
Get an element from a tuple
Syntax:
operation ::= `rtg.tuple_extract` $tuple `at` $index `:` qualified(type($tuple)) attr-dict
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
index | ::mlir::IntegerAttr | index attribute |
Operands: ¶
| Operand | Description |
|---|---|
tuple | a tuple of zero or more fields |
Results: ¶
| Result | Description |
|---|---|
result | any type |
rtg.validate (::circt::rtg::ValidateOp) ¶
Validate the value in the given resource
Syntax:
operation ::= `rtg.validate` $ref `,` $defaultValue (`,` $id^)?
(` ``(` $defaultUsedValues^ `else` $elseValues `:`
qualified(type($defaultUsedValues)) `)`)? `:`
qualified(type($ref)) `->` qualified(type($defaultValue)) attr-dict
Validates the content of a reference-style value from the payload dialect at the position of this operation. This validation may happen in a single lowering step, e.g., a compiler pass that interprets the IR and inlines the interpreted value directly, or a program that can be run to generate the desired values may be generated first and in a second compilation run those values (possibly stored in a file by the first run) may be inlined at the position of these operations. For the latter, the ID attribute may be used to match the values to the right operations and the ‘defaultValue’ is used by the first run instead of the simulated value.
If the control-flow of the payload program visits this operation multiple times, a possibly different value may be logged each time. In such situations, the lowering should fail as no single value can be determined that can be hardcoded/inlined in its place.
The value returned by this operation is not known during elaboration and is thus treated like a value with identity (even though it might just be a simple integer). Therefore, it is strongly recommended to not use the result value of this operation in situations that expect structural equivalence checks such as adding it to sets or bags.
The ‘defaultUsedValues’ are forwarded to the ‘values’ results without any modification whenever the ‘defaultValue’ is used as replacement for ‘value’. Otherwise, the ’elseValues’ are forwarded. This can be used to conditionally execute code based on whether the default value was used or a proper value was used as replacement. Note that this is not the most light-weight implementation as, in principle, a single ‘i1’ result could achieve the same in combination with an ‘scf.if’ or ‘select’ operation. However, these operations are fully resolved during elaboration while the ‘validate’ operation remains until later in the pipeline because the repeated compilation runs to resolve the validate operations should use the same elaboration result which is difficult to achieve with multiple elaboration runs even with the same seed as a different elaboration of the validate op for the different compilation runs can lead to subtle differences in the RNG querrying behavior.
Another alternative could be a region that is conditionally inlined or deleted. However, this is even more heavy-weight and implies a strategy that involves some instructions to be present in one run but not the other which can lead to different label addresses, etc. and thus more likely to problems with AOT co-simulation.
Traits: AttrSizedOperandSegments
Interfaces: RegisterAllocationOpInterface
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
id | ::mlir::StringAttr | string attribute |
Operands: ¶
| Operand | Description |
|---|---|
ref | ValidationTypeInterface instance |
defaultValue | any type |
defaultUsedValues | variadic of any type |
elseValues | variadic of any type |
Results: ¶
| Result | Description |
|---|---|
value | any type |
values | variadic of any type |
rtg.virtual_reg (::circt::rtg::VirtualRegisterOp) ¶
Returns a value representing a virtual register
Syntax:
operation ::= `rtg.virtual_reg` $allowedRegs attr-dict
This operation creates a value representing a virtual register. The ‘allowedRegisters’ attribute specifies the concrete registers that may be chosen during register allocation.
Interfaces: InferTypeOpInterface
Attributes: ¶
| Attribute | MLIR Type | Description |
|---|---|---|
allowedRegs | ::circt::rtg::VirtualRegisterConfigAttr | an allowed register configuration for a virtual register |
Results: ¶
| Result | Description |
|---|---|
result | RegisterTypeInterface instance |
rtg.yield (::circt::rtg::YieldOp) ¶
Terminates RTG operation regions
Syntax:
operation ::= `rtg.yield` ($operands^ `:` type($operands))? attr-dict
Traits: AlwaysSpeculatableImplTrait, Terminator
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
operands | variadic of any type |
Types ¶
ArrayType ¶
An array type with dynamic size
Syntax:
!rtg.array<
::mlir::Type # elementType
>
Represents an array type with dynamic size. The array contains elements of the specified type only.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| elementType | ::mlir::Type |
BagType ¶
A bag of values
Syntax:
!rtg.bag<
::mlir::Type # elementType
>
This type represents a standard bag/multiset datastructure. It does not make any assumptions about the underlying implementation.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| elementType | ::mlir::Type |
DictType ¶
A dictionary
This type is a dictionary with a static set of entries. This datatype does not make any assumptions about how the values are stored (could be a struct, a map, etc.). Furthermore, two values of this type should be considered equivalent if they have the same set of entry names and types and the values match for each entry, independent of the order.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| entries | ::llvm::ArrayRef<::circt::rtg::DictEntry> | dict entries |
ImmediateType ¶
An ISA immediate
Syntax:
!rtg.isa.immediate<
uint32_t # width
>
This type represents immediates of arbitrary but fixed bit-width. The RTG dialect provides this type to avoid duplication in ISA payload dialects.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| width | uint32_t |
LabelType ¶
A reference to a label
Syntax: !rtg.isa.label
This type represents a label. Payload dialects can add operations to cast from this type to an immediate type they can use as an operand to an instruction or allow an operand of this type directly.
MapType ¶
A map from keys to values
Syntax:
!rtg.map<
::mlir::Type, # keyType
::mlir::Type # valueType
>
This type represents a standard map/dictionary datastructure. It does not make any assumptions about the underlying implementation. Thus a hash map, tree map, etc. can be used in a backend. It does not guarentee deterministic iteration.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| keyType | ::mlir::Type | |
| valueType | ::mlir::Type |
MemoryBlockType ¶
Handle to a memory block
Syntax:
!rtg.isa.memory_block<
uint32_t # addressWidth
>
A memory block is representing a continuous region in a memory map with a fixed size and base address. It can refer to actual memory or a memory mapped device.
It is assumed that there is only a single address space.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| addressWidth | uint32_t |
MemoryType ¶
Handle to a memory
Syntax:
!rtg.isa.memory<
uint32_t # addressWidth
>
This type is used to represent memory resources that are allocated from memory blocks and can be accessed and manipulated by payload dialect operations.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| addressWidth | uint32_t |
RandomizedSequenceType ¶
Handle to a fully randomized sequence
Syntax: !rtg.randomized_sequence
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).
SequenceType ¶
Handle to a sequence or sequence family
Syntax:
!rtg.sequence<
::llvm::ArrayRef<mlir::Type> # elementTypes
>
An SSA value of this type refers to a sequence if the list of element types is empty or a sequence family if there are elements left to be substituted.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| elementTypes | ::llvm::ArrayRef<mlir::Type> | element types |
SetType ¶
A set of values
Syntax:
!rtg.set<
::mlir::Type # elementType
>
This type represents a standard set datastructure. It does not make any assumptions about the underlying implementation. Thus a hash set, tree set, etc. can be used in a backend.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| elementType | ::mlir::Type |
StringType ¶
A string type
Syntax: !rtg.string
TupleType ¶
A tuple of zero or more fields
Syntax:
!rtg.tuple<
::llvm::ArrayRef<::mlir::Type> # fieldTypes
>
This type represents a tuple of zero or more fields. The fields can be of any type. The builtin tuple type is not used because it does not allow zero fields.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| fieldTypes | ::llvm::ArrayRef<::mlir::Type> | tuple field types |
Passes ¶
-rtg-elaborate ¶
Elaborate the randomization parts
This pass interprets most RTG operations to perform the represented randomization and in the process get rid of those operations. This means, after this pass the IR does not contain any random constructs within tests anymore.
Options ¶
-seed : The seed for any RNG constructs used in the pass.
-delete-unmatched-tests : Delete tests that could not be matched with a target.
-rtg-embed-validation-values ¶
Lower validate operations to the externally provided values
This pass replaces ‘rtg.validate’ operations with concrete values read from an external file. The file should contain the expected validation values with matching IDs computed, e.g., by running the program in a simulator.
Each validate operation is matched with its corresponding value using the unique identifier. If an identifier occurs multiple times in the file, the pass fails. If an identifier for a ‘validate’ operation is missing in the file, the pass will not modify that operation. Otherwise, the values are parsed according to the implementation provided by the ‘ValidationTypeInterface’ implementation of the ‘ref’ operand type and materialized in the IR as constants to replace the ‘validate’ operation.
This pass is typically used as part of a two-phase compilation process that forks after the ‘rtg-unique-valiate’ pass is run:
- Run the ‘rtg-lower-validate-ops-to-labels’ pass and the rest of the pipeline, then simulate the output in a reference simulator to generate a file with the expected values.
- Run this pass and the rest of the pipeline to produce the final test.
Options ¶
-filename : The file with the validation values.
-rtg-emit-isa-assembly ¶
Emits the instructions in a format understood by assemblers
This pass expects all instructions to be inside ’emit.file’ operations with an appropriate filename attribute. There are two special filenames:
- “-” means that the output should be emitted to stdout.
- "" means that the output should be emitted to stderr.
In order to operate on ’emit.file’ operations in parallel, the pass requires that all ’emit.file’ operations have a unique filename (this is not checked by the pass and violations will result in race conditions).
There are two options to specify lists of instructions that are not supported by the assembler. For instructions in any of those lists, this pass will emit the equivalent binary representation.
Options ¶
-unsupported-instructions-file : An absolute path to a file with a list of instruction names not supported by the assembler.
-unsupported-instructions : A list of ISA instruction names not supported by the assembler.
-rtg-inline-sequences ¶
Inline and interleave sequences
Inline all sequences into tests and remove the ‘rtg.sequence’ operations. Also computes and materializes all interleaved sequences (‘interleave_sequences’ operation).
Options ¶
-fail-on-remaining : Fail if there are remaining 'rtg.sequence' operations after inlining.
Statistics ¶
num-sequences-inlined : Number of sequences inlined into another sequence or test.
num-sequences-interleaved : Number of sequences interleaved with another sequence.
-rtg-insert-test-to-file-mapping ¶
Insert Emit dialect ops to prepare for emission
This pass inserts emit dialect operations to group tests to output files. All tests can be put in a single output file, each test in its own file, or tests can be grouped according to some properties (e.g., machine mode vs. user mode tests) (TODO).
Options ¶
-split-output : If 'true' emits one file per 'rtg.test' in the IR. The name of the file matches the test name and is placed in 'path'. Otherwise, path is interpreted as the full file path including filename.
-path : The directory or file path in which the output files should be created. If empty is is emitted to stderr (not allowed if 'split-output' is set to 'true')
-rtg-linear-scan-register-allocation ¶
Simple linear scan register allocation for RTG
Performs a simple version of the linear scan register allocation algorithm based on the ‘rtg.virtual_reg’ operations.
This pass is expected to be run after elaboration.
Statistics ¶
num-registers-spilled : Number of registers spilled to the stack.
-rtg-lower-unique-labels ¶
Lower label_unique_decl to label_decl operations
This pass lowers label_unique_decl operations to label_decl operations by creating a unique label string based on all the existing unique and non-unique label declarations in the module.
Statistics ¶
num-labels-lowered : Number of unique labels lowered to regular label declarations.
-rtg-lower-validate-to-labels ¶
Lower validation operations to intrinsic labels
Lowers the ‘rtg.validate’ operations to special intrinsic labels understood by the target simulator to print the register contents.
-rtg-materialize-constraints ¶
Materialize implicit constraints
-rtg-memory-allocation ¶
Lower memories to immediates or labels
This pass lowers ‘memory_alloc’ and other memory handling operations to immediates or labels by computing offsets within memory blocks according to the memory allocation’s size and alignments.
Options ¶
-use-immediates : Whether the pass should lower memories to immediates instead of labels.
Statistics ¶
num-memories-allocated : Number of memories allocated from memory blocks.
-rtg-print-test-names ¶
Print the names of all tests to the given file
Prints the names of all tests in the module to the given file. A CSV format is used with the first column being the properly uniqued name of the test and the second column being the original name of the test as it appeared in the frontend. The original name of a test may occur several times because the test might have been duplicated for multiple targets or because multiple elaborations of the same test/target pair were requested.
Options ¶
-filename : The file to print the test names to.
-rtg-simple-test-inliner ¶
Inline test contents
This is a simple pass to inline test contents into ’emit.file’ operations in which they are referenced. No “glue code” is inserted between tests added to the same file. Thus this pass is not intended to be used in a production pipeline but just to bring the IR into a structure understood by the RTG ISA assembly emission pass to avoid making that pass more complex.
-rtg-unique-validate ¶
Compute unique IDs for validate operations
This pass visits all ‘rtg.validate’ operations without an ID attribute and assigns a unique ID to them.