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

Conversation

yinying-lisa-li
Copy link
Contributor

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.

@yinying-lisa-li yinying-lisa-li marked this pull request as ready for review January 5, 2024 18:53
@llvmbot
Copy link
Member

llvmbot commented Jan 5, 2024

@llvm/pr-subscribers-mlir-sparse

Author: Yinying Li (yinying-lisa-li)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/77124.diff

3 Files Affected:

  • (modified) mlir/include/mlir/ExecutionEngine/CRunnerUtils.h (+4)
  • (modified) mlir/lib/ExecutionEngine/CRunnerUtils.cpp (+16)
  • (added) mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir (+108)
diff --git a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
index 76b04145b482e4..747e5ca40ca6f6 100644
--- a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
+++ b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
@@ -486,6 +486,10 @@ extern "C" MLIR_CRUNNERUTILS_EXPORT void *rtsrand(uint64_t s);
 extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *, uint64_t m);
 // Deletes the random number generator.
 extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *);
+// Returns a pointer to an array of random numbers in the range of [0, s).
+extern "C" MLIR_CRUNNERUTILS_EXPORT void *shuffle(uint64_t s, void *g);
+// Deletes the array of random numbers.
+extern "C" MLIR_CRUNNERUTILS_EXPORT void shuffleFree(void *a);
 
 //===----------------------------------------------------------------------===//
 // Runtime support library to allow the use of std::sort in MLIR program.
diff --git a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
index e28e75eb110303..3a3261d1ad4e03 100644
--- a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
+++ b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
@@ -160,6 +160,22 @@ extern "C" void mlirAlignedFree(void *ptr) {
 #endif
 }
 
+/// Generates an array with unique and random numbers from 0 to s-1.
+extern "C" void *shuffle(uint64_t s, void *g) {
+  std::mt19937 *generator = static_cast<std::mt19937 *>(g);
+  uint64_t *output = new uint64_t[s];
+  std::vector<uint64_t> arr(s);
+  std::iota(arr.begin(), arr.end(), 0);
+  std::shuffle(arr.begin(), arr.end(), *generator);
+  std::copy(arr.begin(), arr.end(), output);
+  return output;
+}
+
+extern "C" void shuffleFree(void *a) {
+  uint64_t *arr = static_cast<uint64_t *>(a);
+  delete[] arr;
+}
+
 extern "C" void *rtsrand(uint64_t s) {
   // Standard mersenne_twister_engine seeded with s.
   return new std::mt19937(s);
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
new file mode 100644
index 00000000000000..b2bf3eb74e8f52
--- /dev/null
+++ b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
@@ -0,0 +1,108 @@
+//--------------------------------------------------------------------------------------------------
+// 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
+//
+// Do the same run, but now with direct IR generation.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and vectorization.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false vl=2 reassociate-fp-reductions=true enable-index-optimizations=true
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and VLA vectorization.
+// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | 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(index, !Generator) -> (!Array)
+  func.func private @shuffleFree(!Array) -> ()
+
+  //
+  // 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).
+    %g = func.call @rtsrand(%c0) : (index) ->(!Generator)
+    %res = func.call @shuffle(%size, %g) : (index, !Generator) -> !Array
+
+    // 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.
+      %r = arith.index_cast %iv : index to i64
+      %arr = llvm.getelementptr %res[%r] : (!llvm.ptr, i64) -> !llvm.ptr, i64
+      %val = llvm.load %arr : !Array -> i64
+      %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>
+    func.call @shuffleFree(%res) : (!Array) -> ()
+    func.call @rtdrand(%g) : (!Generator) -> ()
+
+    return
+  }
+}

@llvmbot
Copy link
Member

llvmbot commented Jan 5, 2024

@llvm/pr-subscribers-mlir

Author: Yinying Li (yinying-lisa-li)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/77124.diff

3 Files Affected:

  • (modified) mlir/include/mlir/ExecutionEngine/CRunnerUtils.h (+4)
  • (modified) mlir/lib/ExecutionEngine/CRunnerUtils.cpp (+16)
  • (added) mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir (+108)
diff --git a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
index 76b04145b482e4..747e5ca40ca6f6 100644
--- a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
+++ b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
@@ -486,6 +486,10 @@ extern "C" MLIR_CRUNNERUTILS_EXPORT void *rtsrand(uint64_t s);
 extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *, uint64_t m);
 // Deletes the random number generator.
 extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *);
+// Returns a pointer to an array of random numbers in the range of [0, s).
+extern "C" MLIR_CRUNNERUTILS_EXPORT void *shuffle(uint64_t s, void *g);
+// Deletes the array of random numbers.
+extern "C" MLIR_CRUNNERUTILS_EXPORT void shuffleFree(void *a);
 
 //===----------------------------------------------------------------------===//
 // Runtime support library to allow the use of std::sort in MLIR program.
diff --git a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
index e28e75eb110303..3a3261d1ad4e03 100644
--- a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
+++ b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
@@ -160,6 +160,22 @@ extern "C" void mlirAlignedFree(void *ptr) {
 #endif
 }
 
+/// Generates an array with unique and random numbers from 0 to s-1.
+extern "C" void *shuffle(uint64_t s, void *g) {
+  std::mt19937 *generator = static_cast<std::mt19937 *>(g);
+  uint64_t *output = new uint64_t[s];
+  std::vector<uint64_t> arr(s);
+  std::iota(arr.begin(), arr.end(), 0);
+  std::shuffle(arr.begin(), arr.end(), *generator);
+  std::copy(arr.begin(), arr.end(), output);
+  return output;
+}
+
+extern "C" void shuffleFree(void *a) {
+  uint64_t *arr = static_cast<uint64_t *>(a);
+  delete[] arr;
+}
+
 extern "C" void *rtsrand(uint64_t s) {
   // Standard mersenne_twister_engine seeded with s.
   return new std::mt19937(s);
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
new file mode 100644
index 00000000000000..b2bf3eb74e8f52
--- /dev/null
+++ b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
@@ -0,0 +1,108 @@
+//--------------------------------------------------------------------------------------------------
+// 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
+//
+// Do the same run, but now with direct IR generation.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and vectorization.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false vl=2 reassociate-fp-reductions=true enable-index-optimizations=true
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and VLA vectorization.
+// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | 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(index, !Generator) -> (!Array)
+  func.func private @shuffleFree(!Array) -> ()
+
+  //
+  // 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).
+    %g = func.call @rtsrand(%c0) : (index) ->(!Generator)
+    %res = func.call @shuffle(%size, %g) : (index, !Generator) -> !Array
+
+    // 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.
+      %r = arith.index_cast %iv : index to i64
+      %arr = llvm.getelementptr %res[%r] : (!llvm.ptr, i64) -> !llvm.ptr, i64
+      %val = llvm.load %arr : !Array -> i64
+      %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>
+    func.call @shuffleFree(%res) : (!Array) -> ()
+    func.call @rtdrand(%g) : (!Generator) -> ()
+
+    return
+  }
+}

@llvmbot
Copy link
Member

llvmbot commented Jan 5, 2024

@llvm/pr-subscribers-mlir-execution-engine

Author: Yinying Li (yinying-lisa-li)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/77124.diff

3 Files Affected:

  • (modified) mlir/include/mlir/ExecutionEngine/CRunnerUtils.h (+4)
  • (modified) mlir/lib/ExecutionEngine/CRunnerUtils.cpp (+16)
  • (added) mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir (+108)
diff --git a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
index 76b04145b482e4..747e5ca40ca6f6 100644
--- a/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
+++ b/mlir/include/mlir/ExecutionEngine/CRunnerUtils.h
@@ -486,6 +486,10 @@ extern "C" MLIR_CRUNNERUTILS_EXPORT void *rtsrand(uint64_t s);
 extern "C" MLIR_CRUNNERUTILS_EXPORT uint64_t rtrand(void *, uint64_t m);
 // Deletes the random number generator.
 extern "C" MLIR_CRUNNERUTILS_EXPORT void rtdrand(void *);
+// Returns a pointer to an array of random numbers in the range of [0, s).
+extern "C" MLIR_CRUNNERUTILS_EXPORT void *shuffle(uint64_t s, void *g);
+// Deletes the array of random numbers.
+extern "C" MLIR_CRUNNERUTILS_EXPORT void shuffleFree(void *a);
 
 //===----------------------------------------------------------------------===//
 // Runtime support library to allow the use of std::sort in MLIR program.
diff --git a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
index e28e75eb110303..3a3261d1ad4e03 100644
--- a/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
+++ b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp
@@ -160,6 +160,22 @@ extern "C" void mlirAlignedFree(void *ptr) {
 #endif
 }
 
+/// Generates an array with unique and random numbers from 0 to s-1.
+extern "C" void *shuffle(uint64_t s, void *g) {
+  std::mt19937 *generator = static_cast<std::mt19937 *>(g);
+  uint64_t *output = new uint64_t[s];
+  std::vector<uint64_t> arr(s);
+  std::iota(arr.begin(), arr.end(), 0);
+  std::shuffle(arr.begin(), arr.end(), *generator);
+  std::copy(arr.begin(), arr.end(), output);
+  return output;
+}
+
+extern "C" void shuffleFree(void *a) {
+  uint64_t *arr = static_cast<uint64_t *>(a);
+  delete[] arr;
+}
+
 extern "C" void *rtsrand(uint64_t s) {
   // Standard mersenne_twister_engine seeded with s.
   return new std::mt19937(s);
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
new file mode 100644
index 00000000000000..b2bf3eb74e8f52
--- /dev/null
+++ b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_generate.mlir
@@ -0,0 +1,108 @@
+//--------------------------------------------------------------------------------------------------
+// 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
+//
+// Do the same run, but now with direct IR generation.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and vectorization.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false vl=2 reassociate-fp-reductions=true enable-index-optimizations=true
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and VLA vectorization.
+// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | 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(index, !Generator) -> (!Array)
+  func.func private @shuffleFree(!Array) -> ()
+
+  //
+  // 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).
+    %g = func.call @rtsrand(%c0) : (index) ->(!Generator)
+    %res = func.call @shuffle(%size, %g) : (index, !Generator) -> !Array
+
+    // 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.
+      %r = arith.index_cast %iv : index to i64
+      %arr = llvm.getelementptr %res[%r] : (!llvm.ptr, i64) -> !llvm.ptr, i64
+      %val = llvm.load %arr : !Array -> i64
+      %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>
+    func.call @shuffleFree(%res) : (!Array) -> ()
+    func.call @rtdrand(%g) : (!Generator) -> ()
+
+    return
+  }
+}

Copy link

github-actions bot commented Jan 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@aartbik aartbik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@yinying-lisa-li yinying-lisa-li merged commit 412d784 into llvm:main Jan 10, 2024
@yinying-lisa-li yinying-lisa-li deleted the shuffle branch January 10, 2024 00:46
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants