1 #ifndef SIMD_OP_CHECK_H 2 #define SIMD_OP_CHECK_H 28 static constexpr
int max_i32 = 0x7fffffff;
53 const std::vector<ImageParam>
image_params{
in_f32,
in_f64,
in_f16,
in_bf16,
in_i8,
in_u8,
in_i16,
in_u16,
in_i32,
in_u32,
in_i64,
in_u64};
54 const std::vector<Argument>
arg_types{
in_f32,
in_f64,
in_f16,
in_bf16,
in_i8,
in_u8,
in_i16,
in_u16,
in_i32,
in_u32,
in_i64,
in_u64};
79 bool can_run_the_code =
109 can_run_the_code =
false;
112 return can_run_the_code;
115 virtual void compile_and_check(
Func error,
const std::string &op,
const std::string &name,
int vector_width, std::ostringstream &error_msg) {
116 std::string fn_name =
"test_" + name;
120 std::map<OutputFileType, std::string> outputs = {
127 std::ifstream asm_file;
128 asm_file.open(file_name +
".s");
130 bool found_it =
false;
132 std::ostringstream msg;
133 msg << op <<
" did not generate for target=" <<
get_run_target().
to_string() <<
" vector_width=" << vector_width <<
". Instead we got:\n";
136 while (getline(asm_file, line)) {
144 error_msg <<
"Failed: " << msg.str() <<
"\n";
153 while (*p && *str && *p == *str && *p !=
'*') {
160 }
else if (*p ==
'*') {
167 }
else if (*p ==
' ') {
172 }
else if (*str ==
' ') {
198 std::ostringstream error_msg;
206 inline_reduction = f;
210 IRVisitor::visit(op);
216 } has_inline_reduction;
217 e.
accept(&has_inline_reduction);
229 if (has_inline_reduction.result) {
234 Func g{has_inline_reduction.inline_reduction};
241 .split(x, xo, xi, vector_width)
243 .vectorize(g.rvars()[0])
250 error() = Halide::cast<double>(
maximum(
absd(f(r_check.
x, r_check.
y), f_scalar(r_check.
x, r_check.
y))));
256 if (can_run_the_code) {
263 if (!buf.defined())
continue;
269 if (t ==
Float(32)) {
270 buf.as<
float>().for_each_value([&](
float &f) { f = (
rng() & 0xfff) / 8.0f - 0xff; });
271 }
else if (t ==
Float(64)) {
272 buf.as<
double>().for_each_value([&](
double &f) { f = (
rng() & 0xfff) / 8.0 - 0xff; });
273 }
else if (t ==
Float(16)) {
278 ptr != (
uint32_t *)buf.data() + buf.size_in_bytes() / 4;
293 error_msg <<
"The vector and scalar versions of " << name <<
" disagree. Maximum error: " << e <<
"\n";
298 std::ifstream error_file;
299 error_file.open(error_filename);
301 error_msg <<
"Error assembly: \n";
303 while (getline(error_file, line)) {
304 error_msg << line <<
"\n";
311 return {op, error_msg.str()};
316 std::string name =
"op_" + op;
317 for (
size_t i = 0; i < name.size(); i++) {
318 if (!isalnum(name[i])) name[i] =
'_';
321 name +=
"_" + std::to_string(
tasks.size());
328 tasks.emplace_back(
Task{op, name, vector_width, e});
335 const int alignment_bytes = 16;
336 p.set_host_alignment(alignment_bytes);
337 const int alignment = alignment_bytes / p.type().bytes();
338 p.dim(0).set_min((p.dim(0).min() / alignment) * alignment);
347 const std::string run_target_str = run_target.
to_string();
351 for (
size_t t = 0; t <
tasks.size(); t++) {
353 const auto &task =
tasks.at(t);
354 auto result =
check_one(task.op, task.name, task.vector_width, task.expr);
355 constexpr
int tabstop = 32;
356 const int spaces =
std::max(1, tabstop - (
int)result.op.size());
357 std::cout << result.op << std::string(spaces,
' ') <<
"(" << run_target_str <<
")\n";
358 if (!result.error_msg.empty()) {
359 std::cerr << result.error_msg;
367 template<
typename SIMDOpCheckT>
368 static int main(
int argc,
char **argv,
const std::vector<Target> &targets_to_test) {
370 std::cout <<
"host is: " << host <<
"\n";
372 const int seed = argc > 2 ?
atoi(argv[2]) : time(
nullptr);
373 std::cout <<
"simd_op_check test seed: " << seed <<
"\n";
375 for (
const auto &t : targets_to_test) {
376 if (!t.supported()) {
377 std::cout <<
"[SKIP] Unsupported target: " << t <<
"\n";
380 SIMDOpCheckT test(t);
382 if (!t.supported()) {
383 std::cout <<
"Halide was compiled without support for " << t.to_string() <<
". Skipping.\n";
388 test.filter = argv[1];
391 if (
getenv(
"HL_SIMD_OP_CHECK_FILTER")) {
392 test.filter =
getenv(
"HL_SIMD_OP_CHECK_FILTER");
404 test.output_directory = argv[2];
407 bool success = test.test_all();
417 std::cout <<
"Success!\n";
427 #endif // SIMD_OP_CHECK_H
Expr max(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Expr maximum(Expr, const std::string &s="maximum")
An inline reduction.
A base class for algorithms that need to recursively walk over the IR.
A fragment of Halide syntax.
Func clone_in(const Func &f)
Similar to Func::in; however, instead of replacing the call to this Func with an identity Func that r...
enum Halide::Target::Arch arch
static constexpr int max_i16
A Realization is a vector of references to existing Buffer objects.
const std::vector< ImageParam > image_params
virtual void setup_images()
bool has_feature(Feature f) const
virtual void compile_and_check(Func error, const std::string &op, const std::string &name, int vector_width, std::ostringstream &error_msg)
Func & compute_root()
Compute all of this function once ahead of time.
virtual ~SimdOpCheckTest()=default
std::string output_directory
A struct representing a target machine and os to generate code for.
bool wildcard_match(const std::string &p, const std::string &str) const
bool wildcard_match(const char *p, const char *str) const
Func & bound(const Var &var, Expr min, Expr extent)
Statically declare that the range over which a function should be evaluated is given by the second an...
std::string get_test_tmp_dir()
Return the path to a directory that can be safely written to when running tests; the contents directo...
A Halide variable, to be used when defining functions.
int bits
The bit-width of the target machine.
Expr max() const
Return an expression which is the maximum value of this type.
This file defines the class FunctionDAG, which is our representation of a Halide pipeline, and contains methods to using Halide's bounds tools to query properties of it.
Expr absd(Expr a, Expr b)
Return the absolute difference between two values.
static int main(int argc, char **argv, const std::vector< Target > &targets_to_test)
virtual bool can_run_code() const
RVar y
Direct access to the first four dimensions of the reduction domain.
const std::vector< Argument > arg_types
void compile_to(const std::map< OutputFileType, std::string > &output_files, const std::vector< Argument > &args, const std::string &fn_name, const Target &target=get_target_from_environment())
Compile and generate multiple target files with single call.
Class that provides a type that implements half precision floating point (IEEE754 2008 binary16) in s...
SimdOpCheckTest(const Target t, int w, int h)
bool has_update_definition() const
Does this function have an update definition?
void accept(IRVisitor *v) const
Dispatch to the correct visitor method for this node.
static constexpr int max_i8
void check(std::string op, int vector_width, Expr e)
Type BFloat(int bits, int lanes=1)
Construct a floating-point type in the bfloat format.
unsigned __INT32_TYPE__ uint32_t
TestResult check_one(const std::string &op, const std::string &name, int vector_width, Expr e)
void compile_standalone_runtime(const std::string &object_filename, const Target &t)
Create an object file containing the Halide runtime for a given target.
Target with_feature(Feature f) const
Return a copy of the target with the given feature set.
Func & compute_at(const Func &f, const Var &var)
Compute this function as needed for each unique value of the given var for the given calling function...
Type UInt(int bits, int lanes=1)
Constructing an unsigned integer type.
A reference-counted handle to Halide's internal representation of a function.
Feature
Optional features a target can have.
An Image parameter to a halide pipeline.
Types in the halide type system.
void infer_input_bounds(const std::vector< int32_t > &sizes, const Target &target=get_jit_target_from_environment())
For a given size of output, or a given output buffer, determine the bounds required of all unbound Im...
bool should_run(size_t task_index) const
Func & vectorize(const VarOrRVar &var)
Mark a dimension to be computed all-at-once as a single vector.
bool wildcard_search(const std::string &p, const std::string &str) const
std::map< OutputFileType, const OutputInfo > get_output_info(const Target &target)
A reduction variable represents a single dimension of a reduction domain (RDom).
A multi-dimensional domain over which to iterate.
static constexpr int max_i32
static bool can_jit_target(const Target &target)
If the given target can be executed via the wasm executor, return true.
enum Halide::Target::OS os
static constexpr int max_u8
RVar x
Direct access to the first four dimensions of the reduction domain.
static constexpr int max_u16
virtual void add_tests()=0
std::string to_string() const
Convert the Target into a string form that can be reconstituted by merge_string(), which will always be of the form.
char * getenv(const char *)
std::vector< Task > tasks
Target get_host_target()
Return the target corresponding to the host machine.
Stage update(int idx=0)
Get a handle on an update step for the purposes of scheduling it.
void compile_to_assembly(const std::string &filename, const std::vector< Argument > &, const std::string &fn_name, const Target &target=get_target_from_environment())
Statically compile this function to text assembly equivalent to the object file generated by compile_...
Target get_run_target() const
Type Int(int bits, int lanes=1)
Constructing a signed integer type.
Realization realize(std::vector< int32_t > sizes={}, const Target &target=Target())
Evaluate this function over some rectangular domain and return the resulting buffer or buffers...
Target without_feature(Feature f) const
Return a copy of the target with the given feature cleared.
Type Float(int bits, int lanes=1)
Construct a floating-point type.
virtual void visit(const IntImm *)