Skip to content

MLIR Backend for Generating Constant-Bounded Benchmarks (SCF + MemRef) #48

@pronesto

Description

@pronesto

Feature Request: MLIR Backend for Generating Constant-Bounded Benchmarks (SCF + MemRef)

BenchGen already provides a flexible framework for generating random, structured programs using L-systems, including conditionals, loops, and arrays. We would like to propose a new backend that emits MLIR, targeting a very small subset of standard dialects, in order to generate constant-bounded programs suitable for compiler benchmarking.

The goal is to keep this backend as simple and maintainable as possible, while enabling new use cases related to optimization and analysis.


Scope and design goals

The proposed backend would:

  • Emit only standard MLIR dialects
  • Use structured control flow only
  • Generate programs where all loops have constant bounds
  • Explicitly model memory allocation and usage
  • Avoid function calls, recursion, or unstructured control flow

We believe this can be achieved using only:

  • scf for control flow (scf.for, scf.if)
  • memref for memory allocation and access

No custom dialects or advanced MLIR features are required.


Mapping from BenchGen constructs to MLIR

The mapping from existing BenchGen constructs would be straightforward:

  • IF–THEN–ELSE → scf.if
  • LOOP → scf.for with constant bounds
  • Array creation → memref.alloc
  • Array update → memref.store
  • Array read → memref.load

To enforce constant-boundedness, loop bounds and array sizes would be compile-time constants.


Example expected output (simple)

module {
  func.func @bench() {
    %A = memref.alloc() : memref<64xi32>
    %c0 = arith.constant 0 : i32
    %c1 = arith.constant 1 : i32

    scf.for %i = %c0 to %c1 step %c1 {
      memref.store %c0, %A[%i] : memref<64xi32>
    }

    memref.dealloc %A : memref<64xi32>
    return
  }
}

Example with control flow and multiple arrays

module {
  func.func @bench() {
    %A = memref.alloc() : memref<32xi32>
    %B = memref.alloc() : memref<16xi32>
    %c0 = arith.constant 0 : i32
    %c10 = arith.constant 10 : i32
    %c1 = arith.constant 1 : i32

    scf.for %i = %c0 to %c10 step %c1 {
      scf.if (%i) {
        memref.store %i, %A[%i] : memref<32xi32>
      } else {
        memref.store %i, %B[%c0] : memref<16xi32>
      }
    }

    memref.dealloc %A : memref<32xi32>
    memref.dealloc %B : memref<16xi32>
    return
  }
}

Motivation and use cases

This backend would allow BenchGen to generate benchmarks for:

  • Memory allocation and stack layout
  • Liveness and interference analysis
  • Compiler optimizations that benefit from bounded control flow

Because all loops are constant-bounded and control flow is structured, the generated programs are easy to analyze, unroll, and transform, making them well-suited for benchmarking compiler passes.


Summary

In short, this feature would add a minimal MLIR backend to BenchGen, based on scf and memref, enabling the generation of constant-bounded, structured benchmarks without introducing new dependencies or dialects. We believe this aligns well with BenchGen’s design goals and would open up additional applications for the tool.

We are happy to help refine the scope, provide test cases, or contribute feedback during development.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions