Skip to content

[mlir][sparse][CRunnerUtils] Add shuffle in CRunnerUtils #77124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,16 @@ extern "C" MLIR_CRUNNERUTILS_EXPORT double rtclock();
//===----------------------------------------------------------------------===//
// Uses a seed to initialize a random generator and returns the generator.
extern "C" MLIR_CRUNNERUTILS_EXPORT void *rtsrand(uint64_t s);
// Returns a random number in the range of [0, m).
extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *, uint64_t m);
// Uses a random number generator g and returns a random number
// in the range of [0, m).
extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *g, uint64_t m);
// Deletes the random number generator.
extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *);
extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *g);
// Uses a random number generator g and std::shuffle to modify mref
// in place. Memref mref will be a permutation of all numbers
// in the range of [0, size of mref).
extern "C" MLIR_CRUNNERUTILS_EXPORT void
_mlir_ciface_shuffle(StridedMemRefType<uint64_t, 1> *mref, void *g);

//===----------------------------------------------------------------------===//
// Runtime support library to allow the use of std::sort in MLIR program.
Expand Down
12 changes: 12 additions & 0 deletions mlir/lib/ExecutionEngine/CRunnerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <cinttypes>
#include <cstdio>
#include <cstdlib>
#include <numeric>
#include <random>
#include <string.h>

Expand Down Expand Up @@ -176,6 +177,17 @@ extern "C" void rtdrand(void *g) {
delete generator;
}

extern "C" void _mlir_ciface_shuffle(StridedMemRefType<uint64_t, 1> *mref,
void *g) {
assert(mref);
assert(mref->strides[0] == 1); // consecutive
std::mt19937 *generator = static_cast<std::mt19937 *>(g);
uint64_t s = mref->sizes[0];
uint64_t *data = mref->data + mref->offset;
std::iota(data, data + s, 0);
std::shuffle(data, data + s, *generator);
}

#define IMPL_STDSORT(VNAME, V) \
extern "C" void _mlir_ciface_stdSort##VNAME(uint64_t n, \
StridedMemRefType<V, 1> *vref) { \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//--------------------------------------------------------------------------------------------------
// WHEN CREATING A NEW TEST, PLEASE JUST COPY & PASTE WITHOUT EDITS.
//
// Set-up that's shared across all tests in this directory. In principle, this
// config could be moved to lit.local.cfg. However, there are downstream users that
// do not use these LIT config files. Hence why this is kept inline.
//
// DEFINE: %{sparsifier_opts} = enable-runtime-library=true
// DEFINE: %{sparsifier_opts_sve} = enable-arm-sve=true %{sparsifier_opts}
// DEFINE: %{compile} = mlir-opt %s --sparsifier="%{sparsifier_opts}"
// DEFINE: %{compile_sve} = mlir-opt %s --sparsifier="%{sparsifier_opts_sve}"
// DEFINE: %{run_libs} = -shared-libs=%mlir_c_runner_utils,%mlir_runner_utils
// DEFINE: %{run_opts} = -e entry -entry-point-result=void
// DEFINE: %{run} = mlir-cpu-runner %{run_opts} %{run_libs}
// DEFINE: %{run_sve} = %mcr_aarch64_cmd --march=aarch64 --mattr="+sve" %{run_opts} %{run_libs}
//
// DEFINE: %{env} =
//--------------------------------------------------------------------------------------------------

// RUN: %{compile} | %{run} | FileCheck %s

//
// Integration test that generates a tensor with specified sparsity level.
//

!Generator = !llvm.ptr
!Array = !llvm.ptr

#SparseVector = #sparse_tensor.encoding<{
map = (d0) -> (d0 : compressed)
}>

module {
func.func private @rtsrand(index) -> (!Generator)
func.func private @rtrand(!Generator, index) -> (index)
func.func private @rtdrand(!Generator) -> ()
func.func private @shuffle(memref<?xi64>, !Generator) -> () attributes { llvm.emit_c_interface }

//
// Main driver.
//
func.func @entry() {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%f0 = arith.constant 0.0 : f64
%c99 = arith.constant 99 : index
%c100 = arith.constant 100 : index

// Set up input size and sparsity level.
%size = arith.constant 50 : index
%sparsity = arith.constant 90 : index
%zeros = arith.muli %size, %sparsity : index
%nz = arith.floordivsi %zeros, %c100 : index
%nse = arith.subi %size, %nz : index

// Set up an empty vector.
%empty = tensor.empty(%size) : tensor<?xf64>
%zero_vec = linalg.fill ins(%f0 : f64) outs(%empty : tensor<?xf64>) -> tensor<?xf64>

// Generate shuffled indices in the range of [0, %size).
%array = memref.alloc (%size) : memref<?xi64>
%g = func.call @rtsrand(%c0) : (index) ->(!Generator)
func.call @shuffle(%array, %g) : (memref<?xi64>, !Generator) -> ()

// Iterate through the number of nse indices to insert values.
%output = scf.for %iv = %c0 to %nse step %c1 iter_args(%iter = %zero_vec) -> tensor<?xf64> {
// Fetch the index to insert value from shuffled index array.
%val = memref.load %array[%iv] : memref<?xi64>
%idx = arith.index_cast %val : i64 to index
// Generate a random number from 1 to 100.
%ri0 = func.call @rtrand(%g, %c99) : (!Generator, index) -> (index)
%ri1 = arith.addi %ri0, %c1 : index
%r0 = arith.index_cast %ri1 : index to i64
%fr = arith.uitofp %r0 : i64 to f64
// Insert the random number to current index.
%out = tensor.insert %fr into %iter[%idx] : tensor<?xf64>
scf.yield %out : tensor<?xf64>
}

%sv = sparse_tensor.convert %output : tensor<?xf64> to tensor<?xf64, #SparseVector>
%n0 = sparse_tensor.number_of_entries %sv : tensor<?xf64, #SparseVector>

// Print the number of non-zeros for verification.
//
// CHECK: 5
vector.print %n0 : index

// Release the resources.
bufferization.dealloc_tensor %sv : tensor<?xf64, #SparseVector>
memref.dealloc %array : memref<?xi64>
func.call @rtdrand(%g) : (!Generator) -> ()

return
}
}