From 964c246f438ed5b5496761b574a908b3b9a9a72d Mon Sep 17 00:00:00 2001 From: Martin Erhart Date: Fri, 29 May 2026 11:29:45 +0100 Subject: [PATCH] [RTG] Randomizer operations are not pure --- include/circt/Dialect/RTG/IR/RTGOps.h | 15 +++++++ include/circt/Dialect/RTG/IR/RTGOps.td | 16 ++++++-- test/Dialect/RTG/IR/cse.mlir | 54 +++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/include/circt/Dialect/RTG/IR/RTGOps.h b/include/circt/Dialect/RTG/IR/RTGOps.h index 04f15336d9bf..2838f01a4f34 100644 --- a/include/circt/Dialect/RTG/IR/RTGOps.h +++ b/include/circt/Dialect/RTG/IR/RTGOps.h @@ -30,6 +30,21 @@ #include "mlir/Interfaces/InferTypeOpInterface.h" #include "mlir/Interfaces/SideEffectInterfaces.h" +namespace circt { +namespace rtg { + +/// A custom resource representing the RNG state. Operations that read from or +/// write to the RNG state should declare effects on this resource to prevent +/// CSE and DCE. +struct RNGStateResource + : public mlir::SideEffects::Resource::Base { + StringRef getName() const final { return "RTGRNGStateResource"; } + bool isAddressable() const override { return false; } +}; + +} // namespace rtg +} // namespace circt + #define GET_OP_CLASSES #include "circt/Dialect/RTG/IR/RTG.h.inc" diff --git a/include/circt/Dialect/RTG/IR/RTGOps.td b/include/circt/Dialect/RTG/IR/RTGOps.td index 98c3b2a9b0e8..0c92b477561d 100644 --- a/include/circt/Dialect/RTG/IR/RTGOps.td +++ b/include/circt/Dialect/RTG/IR/RTGOps.td @@ -25,6 +25,10 @@ include "circt/Dialect/RTG/IR/RTGInterfaces.td" include "circt/Dialect/RTG/IR/RTGISAAssemblyInterfaces.td" include "circt/Dialect/Emit/EmitOpInterfaces.td" +// Resource representing the RNG state. Operations that read from or write to +// the RNG state should declare effects on this resource to prevent CSE and DCE. +def RNGStateResource : Resource<"RNGStateResource">; + // Base class for the operation in this dialect. class RTGOp traits = []> : Op; @@ -363,8 +367,8 @@ def SetCreateOp : RTGOp<"set_create", [Pure, SameTypeOperands]> { } def SetSelectRandomOp : RTGOp<"set_select_random", [ - Pure, - TypesMatchWith<"output must be of the element type of input set", + MemoryEffects<[MemRead, MemWrite]>, + TypesMatchWith<"output must be of the element type of input set", "set", "output", "llvm::cast($_self).getElementType()"> ]> { @@ -496,7 +500,7 @@ def BagCreateOp : RTGOp<"bag_create", [Pure, SameVariadicOperandSize]> { } def BagSelectRandomOp : RTGOp<"bag_select_random", [ - Pure, + MemoryEffects<[MemRead, MemWrite]>, TypesMatchWith<"output must be element type of input bag", "bag", "output", "llvm::cast($_self).getElementType()"> ]> { @@ -712,7 +716,9 @@ def TupleExtractOp : RTGOp<"tuple_extract", [ //===- Integer Operations -------------------------------------------------===// -def RandomNumberInRangeOp : RTGOp<"random_number_in_range", []> { +def RandomNumberInRangeOp : RTGOp<"random_number_in_range", [ + MemoryEffects<[MemRead, MemWrite]> +]> { let summary = "returns a number uniformly at random within the given range"; let description = [{ This operation computes a random number based on a uniform distribution @@ -760,6 +766,8 @@ def ConstraintOp : RTGOp<"constraint", []> { def RandomScopeOp : RTGOp<"random_scope", [ NoRegionArguments, + MemoryEffects<[MemRead, MemWrite]>, + RecursiveMemoryEffects, SingleBlockImplicitTerminator<"rtg::YieldOp">, ]> { let summary = "introduce a new scope for randomization"; diff --git a/test/Dialect/RTG/IR/cse.mlir b/test/Dialect/RTG/IR/cse.mlir index d4081e944dd7..ca0c429caa22 100644 --- a/test/Dialect/RTG/IR/cse.mlir +++ b/test/Dialect/RTG/IR/cse.mlir @@ -7,7 +7,7 @@ rtg.sequence @seq0() attributes {rtg.some_attr} { %str = rtg.constant "label_string" : !rtg.string // CHECK-NEXT: rtg.label_unique_decl [[STR]] // CHECK-NEXT: rtg.label_unique_decl [[STR]] - // They are DCE'd but not CSE'd + // They are DCE'd but not CSE'd %2 = rtg.label_unique_decl %str %3 = rtg.label_unique_decl %str %4 = rtg.label_unique_decl %str @@ -15,3 +15,55 @@ rtg.sequence @seq0() attributes {rtg.some_attr} { rtg.label global %2 rtg.label global %3 } + +// CHECK-LABEL: rtg.sequence @setSelectRandom +rtg.sequence @setSelectRandom(%arg0: i32, %arg1: i32) { + // CHECK: [[SET:%.+]] = rtg.set_create %arg0, %arg1 : i32 + %set = rtg.set_create %arg0, %arg1 : i32 + // CHECK-NEXT: rtg.set_select_random [[SET]] : !rtg.set + // CHECK-NEXT: rtg.set_select_random [[SET]] : !rtg.set + // CHECK-NEXT: rtg.set_select_random [[SET]] : !rtg.set + // They are not CSE'd and not DCE'd + %0 = rtg.set_select_random %set : !rtg.set + %1 = rtg.set_select_random %set : !rtg.set + %2 = rtg.set_select_random %set : !rtg.set +} + +// CHECK-LABEL: rtg.sequence @bagSelectRandom +rtg.sequence @bagSelectRandom(%arg0: i32, %arg1: i32, %arg2: index) { + // CHECK: [[BAG:%.+]] = rtg.bag_create (%arg2 x %arg0, %arg2 x %arg1) : i32 + %bag = rtg.bag_create (%arg2 x %arg0, %arg2 x %arg1) : i32 + // CHECK-NEXT: rtg.bag_select_random [[BAG]] : !rtg.bag + // CHECK-NEXT: rtg.bag_select_random [[BAG]] : !rtg.bag + // CHECK-NEXT: rtg.bag_select_random [[BAG]] : !rtg.bag + // They are not CSE'd and not DCE'd + %0 = rtg.bag_select_random %bag : !rtg.bag + %1 = rtg.bag_select_random %bag : !rtg.bag + %2 = rtg.bag_select_random %bag : !rtg.bag +} + +// CHECK-LABEL: rtg.sequence @randomScope +rtg.sequence @randomScope() { + // CHECK: rtg.random_scope attributes {a} + // CHECK: rtg.random_scope attributes {b} + // CHECK: rtg.random_scope attributes {c} + // They are not CSE'd and not DCE'd + rtg.random_scope attributes {a} {} + rtg.random_scope attributes {b} {} + rtg.random_scope attributes {c} {} +} + +// CHECK-LABEL: rtg.sequence @randomNumberInRange +rtg.sequence @randomNumberInRange() { + // CHECK: [[LOW:%.+]] = index.constant 0 + // CHECK-NEXT: [[HIGH:%.+]] = index.constant 100 + // CHECK-NEXT: rtg.random_number_in_range {{\[}}[[LOW]], [[HIGH]]{{\]}} + // CHECK-NEXT: rtg.random_number_in_range {{\[}}[[LOW]], [[HIGH]]{{\]}} + // CHECK-NEXT: rtg.random_number_in_range {{\[}}[[LOW]], [[HIGH]]{{\]}} + %low = index.constant 0 + %high = index.constant 100 + // They are not CSE'd and not DCE'd + %0 = rtg.random_number_in_range [%low, %high] + %1 = rtg.random_number_in_range [%low, %high] + %2 = rtg.random_number_in_range [%low, %high] +}