Skip to content

Commit 412d784

Browse files
[mlir][sparse][CRunnerUtils] Add shuffle in CRunnerUtils (llvm#77124)
Shuffle can generate an array of unique and random numbers from 0 to size-1. It can be used to generate tensors with specified sparsity level.
1 parent ab82b06 commit 412d784

File tree

3 files changed

+116
-3
lines changed

3 files changed

+116
-3
lines changed

mlir/include/mlir/ExecutionEngine/CRunnerUtils.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,16 @@ extern "C" MLIR_CRUNNERUTILS_EXPORT double rtclock();
482482
//===----------------------------------------------------------------------===//
483483
// Uses a seed to initialize a random generator and returns the generator.
484484
extern "C" MLIR_CRUNNERUTILS_EXPORT void *rtsrand(uint64_t s);
485-
// Returns a random number in the range of [0, m).
486-
extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *, uint64_t m);
485+
// Uses a random number generator g and returns a random number
486+
// in the range of [0, m).
487+
extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *g, uint64_t m);
487488
// Deletes the random number generator.
488-
extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *);
489+
extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *g);
490+
// Uses a random number generator g and std::shuffle to modify mref
491+
// in place. Memref mref will be a permutation of all numbers
492+
// in the range of [0, size of mref).
493+
extern "C" MLIR_CRUNNERUTILS_EXPORT void
494+
_mlir_ciface_shuffle(StridedMemRefType<uint64_t, 1> *mref, void *g);
489495

490496
//===----------------------------------------------------------------------===//
491497
// Runtime support library to allow the use of std::sort in MLIR program.

mlir/lib/ExecutionEngine/CRunnerUtils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <cinttypes>
3232
#include <cstdio>
3333
#include <cstdlib>
34+
#include <numeric>
3435
#include <random>
3536
#include <string.h>
3637

@@ -176,6 +177,17 @@ extern "C" void rtdrand(void *g) {
176177
delete generator;
177178
}
178179

180+
extern "C" void _mlir_ciface_shuffle(StridedMemRefType<uint64_t, 1> *mref,
181+
void *g) {
182+
assert(mref);
183+
assert(mref->strides[0] == 1); // consecutive
184+
std::mt19937 *generator = static_cast<std::mt19937 *>(g);
185+
uint64_t s = mref->sizes[0];
186+
uint64_t *data = mref->data + mref->offset;
187+
std::iota(data, data + s, 0);
188+
std::shuffle(data, data + s, *generator);
189+
}
190+
179191
#define IMPL_STDSORT(VNAME, V) \
180192
extern "C" void _mlir_ciface_stdSort##VNAME(uint64_t n, \
181193
StridedMemRefType<V, 1> *vref) { \
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//--------------------------------------------------------------------------------------------------
2+
// WHEN CREATING A NEW TEST, PLEASE JUST COPY & PASTE WITHOUT EDITS.
3+
//
4+
// Set-up that's shared across all tests in this directory. In principle, this
5+
// config could be moved to lit.local.cfg. However, there are downstream users that
6+
// do not use these LIT config files. Hence why this is kept inline.
7+
//
8+
// DEFINE: %{sparsifier_opts} = enable-runtime-library=true
9+
// DEFINE: %{sparsifier_opts_sve} = enable-arm-sve=true %{sparsifier_opts}
10+
// DEFINE: %{compile} = mlir-opt %s --sparsifier="%{sparsifier_opts}"
11+
// DEFINE: %{compile_sve} = mlir-opt %s --sparsifier="%{sparsifier_opts_sve}"
12+
// DEFINE: %{run_libs} = -shared-libs=%mlir_c_runner_utils,%mlir_runner_utils
13+
// DEFINE: %{run_opts} = -e entry -entry-point-result=void
14+
// DEFINE: %{run} = mlir-cpu-runner %{run_opts} %{run_libs}
15+
// DEFINE: %{run_sve} = %mcr_aarch64_cmd --march=aarch64 --mattr="+sve" %{run_opts} %{run_libs}
16+
//
17+
// DEFINE: %{env} =
18+
//--------------------------------------------------------------------------------------------------
19+
20+
// RUN: %{compile} | %{run} | FileCheck %s
21+
22+
//
23+
// Integration test that generates a tensor with specified sparsity level.
24+
//
25+
26+
!Generator = !llvm.ptr
27+
!Array = !llvm.ptr
28+
29+
#SparseVector = #sparse_tensor.encoding<{
30+
map = (d0) -> (d0 : compressed)
31+
}>
32+
33+
module {
34+
func.func private @rtsrand(index) -> (!Generator)
35+
func.func private @rtrand(!Generator, index) -> (index)
36+
func.func private @rtdrand(!Generator) -> ()
37+
func.func private @shuffle(memref<?xi64>, !Generator) -> () attributes { llvm.emit_c_interface }
38+
39+
//
40+
// Main driver.
41+
//
42+
func.func @entry() {
43+
%c0 = arith.constant 0 : index
44+
%c1 = arith.constant 1 : index
45+
%f0 = arith.constant 0.0 : f64
46+
%c99 = arith.constant 99 : index
47+
%c100 = arith.constant 100 : index
48+
49+
// Set up input size and sparsity level.
50+
%size = arith.constant 50 : index
51+
%sparsity = arith.constant 90 : index
52+
%zeros = arith.muli %size, %sparsity : index
53+
%nz = arith.floordivsi %zeros, %c100 : index
54+
%nse = arith.subi %size, %nz : index
55+
56+
// Set up an empty vector.
57+
%empty = tensor.empty(%size) : tensor<?xf64>
58+
%zero_vec = linalg.fill ins(%f0 : f64) outs(%empty : tensor<?xf64>) -> tensor<?xf64>
59+
60+
// Generate shuffled indices in the range of [0, %size).
61+
%array = memref.alloc (%size) : memref<?xi64>
62+
%g = func.call @rtsrand(%c0) : (index) ->(!Generator)
63+
func.call @shuffle(%array, %g) : (memref<?xi64>, !Generator) -> ()
64+
65+
// Iterate through the number of nse indices to insert values.
66+
%output = scf.for %iv = %c0 to %nse step %c1 iter_args(%iter = %zero_vec) -> tensor<?xf64> {
67+
// Fetch the index to insert value from shuffled index array.
68+
%val = memref.load %array[%iv] : memref<?xi64>
69+
%idx = arith.index_cast %val : i64 to index
70+
// Generate a random number from 1 to 100.
71+
%ri0 = func.call @rtrand(%g, %c99) : (!Generator, index) -> (index)
72+
%ri1 = arith.addi %ri0, %c1 : index
73+
%r0 = arith.index_cast %ri1 : index to i64
74+
%fr = arith.uitofp %r0 : i64 to f64
75+
// Insert the random number to current index.
76+
%out = tensor.insert %fr into %iter[%idx] : tensor<?xf64>
77+
scf.yield %out : tensor<?xf64>
78+
}
79+
80+
%sv = sparse_tensor.convert %output : tensor<?xf64> to tensor<?xf64, #SparseVector>
81+
%n0 = sparse_tensor.number_of_entries %sv : tensor<?xf64, #SparseVector>
82+
83+
// Print the number of non-zeros for verification.
84+
//
85+
// CHECK: 5
86+
vector.print %n0 : index
87+
88+
// Release the resources.
89+
bufferization.dealloc_tensor %sv : tensor<?xf64, #SparseVector>
90+
memref.dealloc %array : memref<?xi64>
91+
func.call @rtdrand(%g) : (!Generator) -> ()
92+
93+
return
94+
}
95+
}

0 commit comments

Comments
 (0)