halide / Halide

a language for fast, portable data-parallel computation
https://halide-lang.org
Other
5.86k stars 1.07k forks source link

Runtime error (ambiguous function call) for float16 on Metal backend #8245

Closed yyuting closed 4 months ago

yyuting commented 4 months ago

When using float16 and a metal backend, I'm getting runtime errors that complains calls to min/max/select are ambiguous because METAL_FUNC with both half and float signatures exist.

This error is triggered if the computation involves both half and float, even when explicit cast is used before calling the functions min/max/select.

Here is a minimum example that exposed this error for min and select. I'm using Mac M2 with target=host-metal, and I'm building Halide from top of tree.

// f16_bug_generator.cpp
#include "Halide.h"
#include <stdio.h>

using namespace Halide;

class F16BugGenerator : public Halide::Generator<F16BugGenerator> {
public:
  Input<Buffer<>> input{"input", 2};
  Output<Buffer<>> output{"output", 2};

  Var x, y;

  void generate() {
    Expr val = cast(output.type(), input(x, y) + 1.f);
    Expr clamp_val = clamp(val, cast(output.type(), 0), cast(output.type(), 1));

    output(x, y) = cast(output.type(), select(clamp_val > 1, cast<float>(abs(clamp_val)), cast<float>(fast_pow(clamp_val, 1.f / 2.2f))));

    if (get_target().has_gpu_feature()) {
      printf("GPU schedule\n");
      Var xi, xo, yi, yo;
      output.compute_root()
          .gpu_tile(x, y, xo, yo, xi, yi, 8, 32);
    }
  }
};

HALIDE_REGISTER_GENERATOR(F16BugGenerator, f16_bug_generator)
// f16_bug_test.cpp
#include "HalideBuffer.h"
#include "f16_bug_generator.h"

#include <stdio.h>
#include <stdlib.h>

using half = _Float16;

int main(int argc, char **argv) {

  Halide::Runtime::Buffer<half> input(32, 32);
  Halide::Runtime::Buffer<half> output(32, 32);

  f16_bug_generator(input, output);

  printf("success\n");

  return 0;

}
// f16_bug.sh
export DYLD_LIBRARY_PATH=/usr/lib:/Users/yutingyang/Documents/halide_build/distrib/lib
g++ f16_bug_generator.cpp ~/Documents/halide_build/distrib/tools/GenGen.cpp -g -std=c++17 -fno-rtti -I ~/Documents/halide_build/distrib/include -L ~/Documents/halide_build/distrib/lib -lHalide -o f16_bug_generator
./f16_bug_generator -g f16_bug_generator -o . target=host-metal input.type=float16 output.type=float16
g++ -std=c++17 -I ~/Documents/halide_build/distrib/include -L ~/Documents/halide_build/distrib/lib -ldl -lpthread -lz -framework Metal -framework Foundation f16_bug_test.cpp f16_bug_generator.a -o f16_bug_test
./f16_bug_test

Error message:

2024-05-29 14:14:11.017 f16_bug_test[57266:14995657] Error Domain=MTLLibraryErrorDomain Code=3 "program_source:121:14: error: call to 'min' is ambiguous
  half _16 = min(_15, _13);
             ^~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:3205:17: note: candidate function
METAL_FUNC half min(half x, half y)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:4709:18: note: candidate function
METAL_FUNC float min(float x, float y)
                 ^
program_source:194:22: error: call to 'select' is ambiguous
  float _86 = (float)select(_84, _17, _85);
                     ^~~~~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1096:17: note: candidate function
METAL_FUNC half select(half x, half y, bool c)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1124:18: note: candidate function
METAL_FUNC float select(float x, float y, bool c)
                 ^
program_source:215:15: error: call to 'min' is ambiguous
  half _103 = min(_102, _100);
              ^~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:3205:17: note: candidate function
METAL_FUNC half min(half x, half y)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:4709:18: note: candidate function
METAL_FUNC float min(float x, float y)
                 ^
program_source:288:23: error: call to 'select' is ambiguous
  float _173 = (float)select(_171, _104, _172);
                      ^~~~~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1096:17: note: candidate function
METAL_FUNC half select(half x, half y, bool c)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1124:18: note: candidate function
METAL_FUNC float select(float x, float y, bool c)
                 ^
" UserInfo={NSLocalizedDescription=program_source:121:14: error: call to 'min' is ambiguous
  half _16 = min(_15, _13);
             ^~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:3205:17: note: candidate function
METAL_FUNC half min(half x, half y)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:4709:18: note: candidate function
METAL_FUNC float min(float x, float y)
                 ^
program_source:194:22: error: call to 'select' is ambiguous
  float _86 = (float)select(_84, _17, _85);
                     ^~~~~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1096:17: note: candidate function
METAL_FUNC half select(half x, half y, bool c)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1124:18: note: candidate function
METAL_FUNC float select(float x, float y, bool c)
                 ^
program_source:215:15: error: call to 'min' is ambiguous
  half _103 = min(_102, _100);
              ^~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:3205:17: note: candidate function
METAL_FUNC half min(half x, half y)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_math:4709:18: note: candidate function
METAL_FUNC float min(float x, float y)
                 ^
program_source:288:23: error: call to 'select' is ambiguous
  float _173 = (float)select(_171, _104, _172);
                      ^~~~~~
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1096:17: note: candidate function
METAL_FUNC half select(half x, half y, bool c)
                ^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/lib/clang/32023.34/include/metal/metal_relational:1124:18: note: candidate function
METAL_FUNC float select(float x, float y, bool c)
                 ^
}
Error: halide_metal_initialize_kernels: setup failed.