//TEST:SIMPLE(filecheck=METAL): -stage compute -entry computeMain -target metal //TEST:SIMPLE(filecheck=GLSL): -stage compute -entry computeMain -target glsl //TEST:SIMPLE(filecheck=GLSL_SPIRV): -stage compute -entry computeMain -target spirv -emit-spirv-via-glsl //TEST:SIMPLE(filecheck=SPIR): -stage compute -entry computeMain -target spirv -emit-spirv-directly //TEST:SIMPLE(filecheck=HLSL): -stage compute -entry computeMain -target hlsl //TEST:SIMPLE(filecheck=CUDA): -stage compute -entry computeMain -target cuda //TEST:SIMPLE(filecheck=CPP): -stage compute -entry computeMain -target cpp //TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -output-using-type -emit-spirv-via-glsl //TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -output-using-type -emit-spirv-directly //TEST:SIMPLE(filecheck=METALLIB): -target metallib //TEST(compute, metal):COMPARE_COMPUTE(filecheck-buffer=BUF):-metal -compute -output-using-type -xslang -DMETAL_COMPUTE //TEST_INPUT:ubuffer(data=[0 1 -1], stride=4):name=inputBuffer RWStructuredBuffer inputBuffer; //TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer RWStructuredBuffer outputBuffer; // METALLIB: define void @computeMain // It is unclear why "nextafter" is not working for Metal. #define TEST_WHEN_nextafter_WORKS 0 // NOTE: This test is mainly equality comparisons of math functions results // against a precise expected value, but the Metal spec defines a minimum // accuracy for many of these math functions such that a range of results may // be allowed, presumably corresponding to different generations of hardware. // Exact comparisons are preferred here for simplicity's sake, but in cases // where, e.g., an M1 may yield a different result from an M4, this test checks // that the value falls within the documented range instead. __generic bool fuzzyCompare(const T value, const T expected, const T epsilon) { return value <= (expected + epsilon) && value >= (expected - epsilon); } __generic bool fuzzyCompare(const vector value, const vector expected, const vector epsilon) { return all( value <= (expected + epsilon) && value >= (expected - epsilon) ); } __generic bool Test_Scalar() { // METAL-LABEL: Test_Scalar const T zero = T(inputBuffer[0]); const T one = T(inputBuffer[1]); const int zeroInt = int(inputBuffer[0]); const T EPS_E2N13 = T(0.0001220703125); // 2^-13 T outFloat1, outFloat2; int outInt; bool voidResult = true; // METAL: sincos( // METAL-NOT: sincos( sincos(zero, outFloat1, outFloat2); voidResult = voidResult && zero == outFloat1 && one == outFloat2; return voidResult // METAL: acos( // METALLIB: acos.f32 && zero == acos(one) // METAL: acosh( // METALLIB: acosh.f32 && zero == acosh(one) // METAL: asin( // METALLIB: asin.f32 && zero == asin(zero) // METAL: asinh( // METALLIB: asinh.f32 && zero == asinh(zero) // METAL: atan( // METALLIB: atan.f32 && zero == atan(zero) // METAL: atan2( // METALLIB: atan2.f32 && zero == atan2(zero, one) // METAL: atanh( // METALLIB: atanh.f32 && zero == atanh(zero) // METAL: ceil( // METALLIB: ceil.f32 && zero == ceil(zero) // METAL: copysign( // METALLIB: bitcast float && zero == copysign(zero, zero) // METAL: cos( // METALLIB: cos.f32 && one == cos(zero) // METAL: cosh( // METALLIB: cosh.f32 && one == cosh(zero) // METAL: cospi( // METALLIB: cospi.f32 && fuzzyCompare(cospi(zero), one, EPS_E2N13) // METAL: divide( // METALLIB: fdiv && zero == divide(zero, one) // METAL: exp( // METALLIB: exp.f32 && one == exp(zero) // METAL: exp2( // METALLIB: exp2.f32 && one == exp2(zero) // METAL: exp10( // METALLIB: exp10.f32 && one == exp10(zero) // METAL: fabs( // METALLIB: fabs.f32 && zero == fabs(zero) // METAL: abs( && zero == abs(zero) // METAL: fdim( && zero == fdim(zero, zero) // METAL: floor( // METALLIB: floor.f32 && zero == floor(zero) // METAL: fma( // METALLIB: fma.f32 && zero == fma(zero, zero, zero) // METAL: fmax( // METALLIB: fmax.f32 && zero == fmax(zero, zero) // METAL: max( && zero == max(zero, zero) // METAL: fmax3( // METALLIB: fmax3.f32 && zero == fmax3(zero, zero, zero) // METAL: max3( && zero == max3(zero, zero, zero) // METAL: fmedian3( // METALLIB: fmedian3.f32 && zero == fmedian3(zero, zero, zero) // METAL: median3( && zero == median3(zero, zero, zero) // METAL: fmin( // METALLIB: fmin.f32 && zero == fmin(zero, zero) // METAL: min( && zero == min(zero, zero) // METAL: fmin3( // METALLIB: fmin3.f32 && zero == fmin3(zero, zero, zero) // METAL: min3( && zero == min3(zero, zero, zero) // METAL-COUNT-2: fmod( // METALLIB-COUNT-2: fmod.f32 && zero == fmod(zero, one) // METAL: fract( // METALLIB: fract.f32 && zero == fract(zero) // METAL: frexp( // METALLIB: frexp_float && zero == frexp(zero, outInt) && zeroInt == outInt // METAL: ldexp( // METALLIB: ldexp.f32 && zero == ldexp(zero, zeroInt) // METAL: log( // METALLIB: log.f32 && zero == log(one) // METAL: log2( // METALLIB: log2.f32 && zero == log2(one) // METAL: log10( // METALLIB: log10.f32 && zero == log10(one) // METAL: modf( && zero == modf(zero, outFloat1) #if TEST_WHEN_nextafter_WORKS // M-ETAL: nextafter( && zero == nextafter(zero, zero) #endif // METAL: pow( // METALLIB: pow.f32 && zero == pow(zero, one) // METAL: powr( // METALLIB: powr.f32 && zero == powr(zero, one) // METAL: rint( // METALLIB: rint.f32 && zero == rint(zero) // METAL: round( // METALLIB: round.f32 && zero == round(zero) // METAL: rsqrt( // METALLIB: rsqrt.f32 && one == rsqrt(one) // METAL: sin( // METALLIB: sin.f32 && zero == sin(zero) // METAL: sinh( // METALLIB: sinh.f32 && zero == sinh(zero) // METAL: sinpi( // METALLIB: sinpi.f32 && zero == sinpi(zero) // METAL: sqrt( // METALLIB: sqrt.f32 && zero == sqrt(zero) // METAL: tan( // METALLIB: tan.f32 && zero == tan(zero) // METAL: tanh( // METALLIB: tanh.f32 && zero == tanh(zero) // METAL: tanpi( // METALLIB: tanpi.f32 && zero == tanpi(zero) // METAL: trunc( && zero == trunc(zero) ; // METALLIB: ret } __generic bool Test_Vector() { // METAL-LABEL: Test_Vector_0 const vector zero = T(inputBuffer[0]); const vector one = T(inputBuffer[1]); const vector zeroInt = int(inputBuffer[0]); const vector EPS_E2N13 = T(0.0001220703125); // 2^-13 vector outFloat1, outFloat2; vector outInt; bool voidResult = true; // METAL: sincos( // METAL-NOT: sincos( sincos(zero, outFloat1, outFloat2); voidResult = voidResult && zero == outFloat1 && one == outFloat2; return voidResult // METAL: acos( // METAL-NOT: acos( && zero == acos(one) // METAL: acosh( // METAL-NOT: acosh( && zero == acosh(one) // METAL: asin( // METAL-NOT: asin( && zero == asin(zero) // METAL: asinh( // METAL-NOT: asinh( && zero == asinh(zero) // METAL: atan( // METAL-NOT: atan( && zero == atan(zero) // METAL: atan2( // METAL-NOT: atan2( && zero == atan2(zero, one) // METAL: atanh( // METAL-NOT: atanh( && zero == atanh(zero) // METAL: ceil( // METAL-NOT: ceil( && zero == ceil(zero) // METAL: copysign( // METAL-NOT: copysign( && zero == copysign(zero, zero) // METAL: cos( // METAL-NOT: cos( && one == cos(zero) // METAL: cosh( // METAL-NOT: cosh( && one == cosh(zero) // METAL: cospi( // METAL-NOT: cospi( && fuzzyCompare(cospi(zero), one, EPS_E2N13) // METAL: divide( // METAL-NOT: divide( && zero == divide(zero, one) // METAL: exp( // METAL-NOT: exp( && one == exp(zero) // METAL: exp2( // METAL-NOT: exp2( && one == exp2(zero) // METAL: exp10( // METAL-NOT: exp10( && one == exp10(zero) // METAL: fabs( // METAL-NOT: fabs( && zero == fabs(zero) // METAL: abs( // METAL-NOT: abs( && zero == abs(zero) // METAL: fdim( // METAL-NOT: fdim( && zero == fdim(zero, zero) // METAL: floor( // METAL-NOT: floor( && zero == floor(zero) // METAL: fma( // METAL-NOT: fma( && zero == fma(zero, zero, zero) // METAL: fmax( // METAL-NOT: fmax( && zero == fmax(zero, zero) // METAL: max( // METAL-NOT: max( && zero == max(zero, zero) // METAL: fmax3( // METAL-NOT: fmax3( && zero == fmax3(zero, zero, zero) // METAL: max3( // METAL-NOT: max3( && zero == max3(zero, zero, zero) // METAL: fmedian3( // METAL-NOT: fmedian3( && zero == fmedian3(zero, zero, zero) // METAL: median3( // METAL-NOT: median3( && zero == median3(zero, zero, zero) // METAL: fmin( // METAL-NOT: fmin( && zero == fmin(zero, zero) // METAL: min( // METAL-NOT: min( && zero == min(zero, zero) // METAL: fmin3( // METAL-NOT: fmin3( && zero == fmin3(zero, zero, zero) // METAL: min3( // METAL-NOT: min3( && zero == min3(zero, zero, zero) // METAL-COUNT-2: fmod( // METAL-NOT: fmod( && zero == fmod(zero, one) // METAL: fract( // METAL-NOT: fract( && zero == fract(zero) // METAL: frexp( // METAL-NOT: frexp( && zero == frexp(zero, outInt) && all(zeroInt == outInt) // METAL: ldexp( // METAL-NOT: ldexp( && zero == ldexp(zero, zeroInt) // METAL: log( // METAL-NOT: log( && zero == log(one) // METAL: log2( // METAL-NOT: log2( && zero == log2(one) // METAL: log10( // METAL-NOT: log10( && zero == log10(one) // METAL: modf( // METAL-NOT: modf( && zero == modf(zero, outFloat1) #if TEST_WHEN_nextafter_WORKS // M-ETAL: nextafter( // METAL-NOT: nextafter( && zero == nextafter(zero, zero) #endif // METAL: pow( // METAL-NOT: pow( && zero == pow(zero, one) // METAL: powr( // METAL-NOT: powr( && zero == powr(zero, one) // METAL: rint( // METAL-NOT: rint( && zero == rint(zero) // METAL: round( // METAL-NOT: round( && zero == round(zero) // METAL: rsqrt( // METAL-NOT: rsqrt( && one == rsqrt(one) // METAL: sin( // METAL-NOT: sin( && zero == sin(zero) // METAL: sinh( // METAL-NOT: sinh( && zero == sinh(zero) // METAL: sinpi( // METAL-NOT: sinpi( && zero == sinpi(zero) // METAL: sqrt( // METAL-NOT: sqrt( && zero == sqrt(zero) // METAL: tan( // METAL-NOT: tan( && zero == tan(zero) // METAL: tanh( // METAL-NOT: tanh( && zero == tanh(zero) // METAL: tanpi( // METAL-NOT: tanpi( && zero == tanpi(zero) // METAL: trunc( // METAL-NOT: trunc( && zero == trunc(zero) ; // METAL-LABEL: Test_Vector_1 } [numthreads(1,1,1)] void computeMain() { // GLSL: void main( // GLSL_SPIRV: OpEntryPoint // SPIR: OpEntryPoint // HLSL: void computeMain( // CUDA: void computeMain( // CPP: void _computeMain( bool result = true && Test_Scalar() && Test_Vector() && Test_Vector() && Test_Vector() && Test_Scalar() && Test_Vector() && Test_Vector() && Test_Vector() ; // BUF: 1 outputBuffer[0] = int(result); }