Conversation
e836b13 to
4e4cf93
Compare
src/ExprInterpreter.cpp
Outdated
| result = apply_unary(op->type, args[0], [](auto a) { return std::log(a); }); | ||
| } else if (op->name == "sqrt") { | ||
| result = apply_unary(op->type, args[0], [](auto a) { return std::sqrt(a); }); | ||
| } else if (op->is_intrinsic(Call::strict_add)) { |
There was a problem hiding this comment.
This should just be:
if (op->is_strict_intrinsic()) {
Expr lowered = unstrictify_float(op);
lowered.accept(this);
}
Also instead of interpreting the fixed-point instrinsics (e.g. halving add), in the else case at the bottom you can call lower_intrinsic(op) and try again.
There was a problem hiding this comment.
I'll leave strict_fma and redirect it to std::fma().
There was a problem hiding this comment.
There is no helper function to tell if an intrinsic is a fixed-point intrinsic.
There was a problem hiding this comment.
Added a helper: is_integer_intrinsic()
First step in addressing #9044 Co-authored-by: Gemini 3.1 Pro <gemini@aistudio.google.com>
…rinsics via lower_intrinsics and recurse.
3d3054c to
26d2483
Compare
|
I think the interpreter should be in test/fuzz, until such time as we need it more generally. is_integer_intrinsic isn't quite right as a name because you can indeed do widening_mul on floats. lower_intrinsic (the existing name) is also not great because it's too broad. Maybe we should call these "arithmetic intrinsics" and have is_arithmetic_intrinsic and lower_arithmetic_intrinsic? Open to ideas for a better name. |
|
I don't think this implements Halide math correctly. E.g. there's no overflow handling on integer math, and you don't get the same rounding behavior if you emulate a narrow float with a double. We may want to reuse existing compiler machinery (e.g. the constant folding in IRMatch.h), but that means we're not testing that logic. Let's discuss the best way to do this at the dev meeting. |
The tests don't support linking multiple .cpp files together. We could
That sounds like it would include all strict_float intrinsics too.
It's possible because
I wonder if that's strictly required for our fuzzing purpose. We want to test the simplifier, CodeGen backends, and LLVM. We can at least test it for all the normal types (f32, f64, i/u 1,8,16,32,64) if we don't trigger overflows with our test numbers. Having this rudimentary ExprInterpreter sit in the test/fuzz/ folder seems like it's clear enough that it's for testing purposes.
|
It's not that bad... add it to the # Existing code:
add_library(Halide_fuzz OBJECT) # INTERFACE ~> OBJECT
add_library(Halide::fuzz ALIAS Halide_fuzz)
target_sources(Halide_fuzz PRIVATE ExprInterpreter.cpp) # NEW
if (NOT HAVE_LIBFUZZER_FLAGS)
# ...
target_sources(Halide_fuzz PRIVATE halide_fuzz_main.cpp halide_fuzz_main.h) # INTERFACE ~> PRIVATE
# ...Adjusts two lines, adds a third.
We do promise defined overflow on signed ints narrower than 32. |
|
Also uints have the normal wrapping behavior. As soon as you subtract two numbers, you're going to get overflow for the uint types, so it does need to be handled. The strict_float intrinsics are different, because "lowering" them does sort of change the meaning of the Expr, in that it relaxes the guarantees. For the others, it should be exactly identical. widening_mul(f16, f16) -> f32 is very much intended. I can't think of a good alternative to arithmetic right now but I'll keep thinking. |
I did like the name. I was just thinking that strict_add and strict_mul etc are also arithmetic operations. Was wondering if they should be included in the list for
So the concern here is that C++ doesn't consider this as defined behavior, and we do. So, despite the fact that all of the code will most likely just work, it's technically still UB.
C++ already defines wraparound with module 2^N for unsigned integer types. So I think the expression interpreter should already do this automatically. The problem would only exist for signed integers (32 bits or narrower), because it's undefined in C++.
Great, I'll do that! One unfortunate side effect of this is that the call to ExprInterpreter::test() is no longer valid from within |
Rename Call::is_integer_intrinsic() to Call::is_arithmetic_intrinsic().
Second step in addressing #9044.