Skip to content

Commit 0ee3284

Browse files
authored
[RTG] Redefine RandomNumberInRangeOp upper bound to be inclusive (#8710)
When we want to be able to get all possible numbers that fit in a 64 bit register, we would need a 65 bit number as the upper bound. However, an iindex typed attribute uses an APInt with 64 bits and would thus make this complicated.
1 parent 2b1b9fe commit 0ee3284

File tree

6 files changed

+42
-15
lines changed

6 files changed

+42
-15
lines changed

frontends/PyRTG/src/pyrtg/immediates.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,19 @@ def random(width: int) -> Immediate:
2727
"""
2828

2929
# Note that the upper limit is exclusive
30-
return Immediate(width, Integer.random(0, 2**width))
30+
return Immediate(width, Integer.random(0, 2**width - 1))
31+
32+
@staticmethod
33+
def umax(width: int) -> Immediate:
34+
"""
35+
An immediate of the provided width with the maximum unsigned value it can
36+
hold.
37+
"""
38+
39+
return Immediate(width, 2**width - 1)
40+
41+
def __repr__(self) -> str:
42+
return f"Immediate<{self._width}, {self._value}>"
3143

3244
def _get_ssa_value(self) -> ir.Value:
3345
if isinstance(self._value, int):
@@ -55,5 +67,8 @@ def __init__(self, width: int):
5567
def __eq__(self, other) -> bool:
5668
return isinstance(other, ImmediateType) and self.width == other.width
5769

70+
def __repr__(self) -> str:
71+
return f"ImmediateType<{self.width}>"
72+
5873
def _codegen(self) -> ir.Type:
5974
return rtg.ImmediateType.get(self.width)

frontends/PyRTG/src/pyrtg/integers.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __init__(self, value: Union[ir.Value, int]) -> Integer:
3030
def random(lower_bound: Union[int, Integer],
3131
upper_bound: Union[int, Integer]) -> Integer:
3232
"""
33-
Get a random number in the given range (lower inclusive, upper exclusive).
33+
Get a random number in the given range (lower and upper inclusive).
3434
"""
3535

3636
if isinstance(lower_bound, int):
@@ -78,7 +78,18 @@ def get_type(self) -> Type:
7878

7979
def _get_ssa_value(self) -> ir.Value:
8080
if isinstance(self._value, int):
81-
self = index.ConstantOp(self._value)
81+
# The MLIR index type (more precisely the attribute) does not support integers with more than 64 bits.
82+
if self._value >= 2**64:
83+
raise ValueError("Integer value out of range")
84+
85+
# The Python Bindings use an 'int64_t' and the bounds of this type are
86+
# checked and enforced. However, that integer ends up in a signless APInt
87+
# anyway, so we can compute the signed integer that matches the bitvector
88+
# of the unsigned integer and use that.
89+
if self._value >= 2**63:
90+
self = index.ConstantOp(self._value - 2**64)
91+
else:
92+
self = index.ConstantOp(self._value)
8293

8394
return self._value
8495

include/circt/Dialect/RTG/IR/RTGOps.td

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,16 +629,16 @@ def RandomNumberInRangeOp : RTGOp<"random_number_in_range", []> {
629629
let summary = "returns a number uniformly at random within the given range";
630630
let description = [{
631631
This operation computes a random number based on a uniform distribution
632-
within the given range. The lower bound is inclusive while the upper bound
633-
is exclusive. If the range is empty, compilation will fail.
634-
This is (obviously) more performant than inserting all legal numbers into a
635-
set and using 'set_select_random', but yields the same behavior.
632+
within the given range. Both the lower and upper bounds are inclusive. If
633+
the range is empty, compilation will fail. This is (obviously) more
634+
performant than inserting all legal numbers into a set and using
635+
'set_select_random', but yields the same behavior.
636636
}];
637637

638638
let arguments = (ins Index:$lowerBound, Index:$upperBound);
639639
let results = (outs Index:$result);
640640

641-
let assemblyFormat = "` ` `[` $lowerBound `,` $upperBound `)` attr-dict";
641+
let assemblyFormat = "` ` `[` $lowerBound `,` $upperBound `]` attr-dict";
642642
}
643643

644644
//===- Misc Operations ----------------------------------------------------===//

lib/Dialect/RTG/Transforms/ElaborationPass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ class Elaborator : public RTGOpVisitor<Elaborator, FailureOr<DeletionKind>> {
15491549

15501550
FailureOr<DeletionKind> visitOp(RandomNumberInRangeOp op) {
15511551
size_t lower = get<size_t>(op.getLowerBound());
1552-
size_t upper = get<size_t>(op.getUpperBound()) - 1;
1552+
size_t upper = get<size_t>(op.getUpperBound());
15531553
if (lower > upper)
15541554
return op->emitError("cannot select a number from an empty range");
15551555

test/Dialect/RTG/IR/basic.mlir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ rtg.test @test1(num_cpus = %a: i32, num_modes = %b: i32) { }
154154

155155
// CHECK-LABEL: rtg.sequence @integerHandlingOps
156156
rtg.sequence @integerHandlingOps(%arg0: index, %arg1: index) {
157-
// CHECK: rtg.random_number_in_range [%arg0, %arg1)
158-
rtg.random_number_in_range [%arg0, %arg1)
157+
// CHECK: rtg.random_number_in_range [%arg0, %arg1]
158+
rtg.random_number_in_range [%arg0, %arg1]
159159
}
160160

161161
// CHECK-LABEL: rtg.test @interleaveSequences

test/Dialect/RTG/Transform/elaboration.mlir

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,13 @@ rtg.test @labels(singleton = %none: index) {
478478
// CHECK-LABEL: rtg.test @randomIntegers
479479
rtg.test @randomIntegers(singleton = %none: index) {
480480
%lower = index.constant 5
481-
%upper = index.constant 10
482-
%0 = rtg.random_number_in_range [%lower, %upper) {rtg.elaboration_custom_seed=0}
481+
%upper = index.constant 9
482+
%0 = rtg.random_number_in_range [%lower, %upper] {rtg.elaboration_custom_seed=0}
483483
// CHECK-NEXT: [[V0:%.+]] = index.constant 5
484484
// CHECK-NEXT: func.call @dummy2([[V0]])
485485
func.call @dummy2(%0) : (index) -> ()
486486

487-
%1 = rtg.random_number_in_range [%lower, %upper) {rtg.elaboration_custom_seed=3}
487+
%1 = rtg.random_number_in_range [%lower, %upper] {rtg.elaboration_custom_seed=3}
488488
// CHECK-NEXT: [[V1:%.+]] = index.constant 8
489489
// CHECK-NEXT: func.call @dummy2([[V1]])
490490
func.call @dummy2(%1) : (index) -> ()
@@ -799,9 +799,10 @@ rtg.target @singletonTarget : !rtg.dict<singleton: index> {
799799
func.func @dummy2(%arg0: index) -> () {return}
800800

801801
rtg.test @randomIntegers(singleton = %none: index) {
802+
%c4 = index.constant 4
802803
%c5 = index.constant 5
803804
// expected-error @below {{cannot select a number from an empty range}}
804-
%0 = rtg.random_number_in_range [%c5, %c5)
805+
%0 = rtg.random_number_in_range [%c5, %c4]
805806
func.call @dummy2(%0) : (index) -> ()
806807
}
807808

0 commit comments

Comments
 (0)