//===-- Generate random but valid function descriptors  ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_BENCHMARKS_AUTOMEMCPY_RANDOM_FUNCTION_GENERATOR_H
#define LLVM_LIBC_BENCHMARKS_AUTOMEMCPY_RANDOM_FUNCTION_GENERATOR_H

#include "automemcpy/FunctionDescriptor.h"
#include <cstddef>
#include <cstdint>
#include <llvm/ADT/ArrayRef.h>
#include <llvm/ADT/StringRef.h>
#include <optional>
#include <vector>
#include <z3++.h>

namespace llvm {
namespace automemcpy {

// Holds the state for the constraint solver.
// It implements a single method that returns the next valid description.
struct RandomFunctionGenerator {
  RandomFunctionGenerator();

  // Get the next valid FunctionDescriptor or std::nullopt.
  std::optional<FunctionDescriptor> next();

private:
  // Returns an expression where `Variable` is forced to be one of the `Values`.
  z3::expr inSetConstraint(z3::expr &Variable, ArrayRef<int> Values) const;
  // Add constaints to `Begin` and `End` so that they are:
  // - between 0 and kMaxSize (inclusive)
  // - ordered (begin<=End)
  // - amongst a set of predefined values.
  void addBoundsAndAnchors(z3::expr &Begin, z3::expr &End);
  // Add constraints to make sure that the loop block size is amongst a set of
  // predefined values. Also makes sure that the loop that the loop is iterated
  // at least `LoopMinIter` times.
  void addLoopConstraints(const z3::expr &LoopBegin, const z3::expr &LoopEnd,
                          z3::expr &LoopBlockSize, int LoopMinIter);

  z3::context Context;
  z3::solver Solver;

  z3::expr Type;
  z3::expr ContiguousBegin, ContiguousEnd;
  z3::expr OverlapBegin, OverlapEnd;
  z3::expr LoopBegin, LoopEnd, LoopBlockSize;
  z3::expr AlignedLoopBegin, AlignedLoopEnd, AlignedLoopBlockSize,
      AlignedAlignment, AlignedArg;
  z3::expr AcceleratorBegin, AcceleratorEnd;
  z3::expr ElementClass;
};

} // namespace automemcpy
} // namespace llvm

#endif /* LLVM_LIBC_BENCHMARKS_AUTOMEMCPY_RANDOM_FUNCTION_GENERATOR_H */
