functions.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s
  2. // __decltype is the GCC way of saying 'decltype', but doesn't require C++11
  3. // _Static_assert is the C11 way of saying 'static_assert', but doesn't require C++11
  4. #ifdef VERIFY_FXC
  5. #define _Static_assert(a,b,c) ;
  6. #endif
  7. // All parameters that come after a parameter with a default initializer must specify a default initializer.
  8. void fn_params_complete(int a = 0, int b = 0);
  9. void fn_params_last(int a, int b = 0);
  10. void fn_params_wrong(int a = 0, int b); // expected-error {{missing default argument on parameter 'b'}} fxc-error {{X3044: 'fn_params_wrong': missing default value for parameter 'b'}}
  11. void fn_params_fn_declaration(int fn(), int b); /* expected-error {{function declaration is not allowed in function parameters}} fxc-error {{X3000: syntax error: unexpected token '('}} fxc-error {{X3000: syntax error: unexpected token ','}} */
  12. void fn_params_fn_declaration(fn()); /* expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{function declaration is not allowed in function parameters}} fxc-error {{X3000: unrecognized identifier 'fn'}} */
  13. void fn_params_fn_pointer(int (*fn)(), int b); /* expected-error {{pointers are unsupported in HLSL}} fxc-error {{X3000: syntax error: unexpected token '('}} */
  14. // Look at the 'mul' issues.
  15. void fn_mul_test() {
  16. //
  17. // mul is a particularly interesting intrinsic, because it's
  18. // overloaded on the input types and the result type varies
  19. // significantly depending on the shape of inputs.
  20. //
  21. float f = 0;
  22. float2 f2 = { 1, 2 };
  23. float4 f4 = { 1, 2, 3, 4 };
  24. float3x4 f34 = { f4, f4, f4 }; // 3 rows, 4 columns
  25. float4x2 f42 = { f4, f4 }; // 4 rows, 2 columns
  26. float4x4 f44 = { f4, f4, f4, f4 };
  27. _Static_assert(std::is_same<float, __decltype(mul(f, f))>::value, ""); // scalar, scalar -> scalar
  28. _Static_assert(std::is_same<float4, __decltype(mul(f, f4))>::value, ""); // scalar, vector -> vector
  29. _Static_assert(std::is_same<float4x4, __decltype(mul(f, f44))>::value, ""); // scalar, matrix -> matrix
  30. _Static_assert(std::is_same<float4, __decltype(mul(f4, f))>::value, ""); // vector, scalar -> vector
  31. _Static_assert(std::is_same<float4, __decltype(mul(f4, f))>::value, ""); // vector, scalar -> vector
  32. _Static_assert(std::is_same<float, __decltype(mul(f4, f4))>::value, ""); // vector, vector -> scalar
  33. _Static_assert(std::is_same<float4, __decltype(mul(f4, f44))>::value, ""); // vector, matrix (row=vector size,col=any)-> vector(of col size)
  34. _Static_assert(std::is_same<float2, __decltype(mul(f4, f42))>::value, ""); // vector, matrix (row=vector size,col=any)-> vector(of col size) - more interesting example
  35. _Static_assert(std::is_same<float4x4, __decltype(mul(f44, f))>::value, ""); // matrix, scalar -> matrix
  36. _Static_assert(std::is_same<float4, __decltype(mul(f42, f2))>::value, ""); // matrix, vector (size=col) -> vector(of row size)
  37. _Static_assert(std::is_same<float3x2, __decltype(mul(f34, f42))>::value, ""); // matrix-x, matrix-y (row=col-x) -> matrix(of row=row-x, col=col-y)
  38. }
  39. float fn_float_arr(float arr[2]) { // expected-note {{candidate function not viable: no known conversion from 'float2' to 'float [2]' for 1st argument}} fxc-pass {{}}
  40. arr[0] = 123;
  41. return arr[0];
  42. }
  43. float fn_float_arr_out(out float arr[2]) {
  44. arr[0] = 1;
  45. arr[1] = 2;
  46. return 1;
  47. }
  48. typedef float float_arr_2[2];
  49. #if FIXED_ARRAYS_ON_RETURN
  50. float_arr_2 arr_return() {
  51. float_arr_2 arr;
  52. arr[0] = 0; arr[1] = 1;
  53. return arr;
  54. }
  55. #endif
  56. bool fn_bool() {
  57. float a [ 2 ] ;
  58. a [ 0 ] = 1 - 2 ;
  59. a [ 1 ] = 2 + 3 ;
  60. float b1 , b2 ;
  61. b1 = min(a[0], a[1]);
  62. b2 = max(a[0], a[1]);
  63. return ( a [ 1 ] < b1 || b2 < a [ 0 ] ) ;
  64. }
  65. struct Texture2DArrayFloat {
  66. Texture2DArray<float> tex;
  67. SamplerState smp;
  68. float SampleLevel(float2 coord, float arrayIndex, float level)
  69. {
  70. return tex.SampleLevel(smp, float3 (coord, arrayIndex), level);
  71. }
  72. float4 Gather(float2 coord, float arrayIndex)
  73. {
  74. return tex.Gather(smp, float3 (coord, arrayIndex));
  75. }
  76. };
  77. float SampleLevelFromConst(const Texture2DArray < float > tex, SamplerState smp, float2 coord, float arrayIndex, float level) {
  78. return tex.SampleLevel(smp, float3 (coord, arrayIndex), level);
  79. }
  80. int g_arr[3];
  81. bool fn_unroll_early() {
  82. [unroll] // expected-warning {{attribute 'unroll' can only be applied to 'for', 'while' and 'do' loop statements}} fxc-pass {{}}
  83. int aj;
  84. for (aj = 0; aj < 3; aj++) {
  85. if (g_arr[aj]) return true;
  86. }
  87. return false;
  88. }
  89. float4 component_fun(uint input) {
  90. // The interesting case here is the second statement, where a float3 (by swizzle) and a scalar
  91. // yield a bool3, go through a ternary operator, and yield a float3.
  92. float4 output = float4 (((input >> 0) & 0xFF) / 255.f, ((input >> 8) & 0xFF) / 255.f, ((input >> 16) & 0xFF) / 255.f, ((input >> 24) & 0xFF) / 255.f);
  93. // TODO: Fix ternary operator (currently conditional is scalar bool)
  94. output.rgb = (output.rgb <= 0.04045f) ? output.rgb / 12.92f : pow((output.rgb + 0.055f) / 1.055f, 2.4f);
  95. /*verify-ast
  96. BinaryOperator <col:3, col:105> 'vector<float, 3>':'vector<float, 3>' '='
  97. |-HLSLVectorElementExpr <col:3, col:10> 'vector<float, 3>':'vector<float, 3>' lvalue vectorcomponent rgb
  98. | `-DeclRefExpr <col:3> 'float4':'vector<float, 4>' lvalue Var 'output' 'float4':'vector<float, 4>'
  99. `-ConditionalOperator <col:16, col:105> 'vector<float, 3>'
  100. |-ParenExpr <col:16, col:39> 'const bool'
  101. | `-BinaryOperator <col:17, col:31> 'const bool' '<='
  102. | |-ImplicitCastExpr <col:17, col:24> 'vector<float, 3>':'vector<float, 3>' <LValueToRValue>
  103. | | `-HLSLVectorElementExpr <col:17, col:24> 'vector<float, 3>':'vector<float, 3>' lvalue vectorcomponent rgb
  104. | | `-DeclRefExpr <col:17> 'float4':'vector<float, 4>' lvalue Var 'output' 'float4':'vector<float, 4>'
  105. | `-ImplicitCastExpr <col:31> 'vector<float, 3>':'vector<float, 3>' <HLSLVectorSplat>
  106. | `-FloatingLiteral <col:31> 'float' 4.045000e-02
  107. |-BinaryOperator <col:43, col:56> 'vector<float, 3>' '/'
  108. | |-ImplicitCastExpr <col:43, col:50> 'vector<float, 3>':'vector<float, 3>' <LValueToRValue>
  109. | | `-HLSLVectorElementExpr <col:43, col:50> 'vector<float, 3>':'vector<float, 3>' lvalue vectorcomponent rgb
  110. | | `-DeclRefExpr <col:43> 'float4':'vector<float, 4>' lvalue Var 'output' 'float4':'vector<float, 4>'
  111. | `-ImplicitCastExpr <col:56> 'vector<float, 3>':'vector<float, 3>' <HLSLVectorSplat>
  112. | `-FloatingLiteral <col:56> 'float' 1.292000e+01
  113. `-CallExpr <col:65, col:105> 'vector<float, 3>':'vector<float, 3>'
  114. |-ImplicitCastExpr <col:65> 'vector<float, 3> (*)(vector<float, 3>, vector<float, 3>)' <FunctionToPointerDecay>
  115. | `-DeclRefExpr <col:65> 'vector<float, 3> (vector<float, 3>, vector<float, 3>)' lvalue Function 'pow' 'vector<float, 3> (vector<float, 3>, vector<float, 3>)'
  116. |-BinaryOperator <col:69, col:93> 'vector<float, 3>' '/'
  117. | |-ParenExpr <col:69, col:89> 'vector<float, 3>'
  118. | | `-BinaryOperator <col:70, col:83> 'vector<float, 3>' '+'
  119. | | |-ImplicitCastExpr <col:70, col:77> 'vector<float, 3>':'vector<float, 3>' <LValueToRValue>
  120. | | | `-HLSLVectorElementExpr <col:70, col:77> 'vector<float, 3>':'vector<float, 3>' lvalue vectorcomponent rgb
  121. | | | `-DeclRefExpr <col:70> 'float4':'vector<float, 4>' lvalue Var 'output' 'float4':'vector<float, 4>'
  122. | | `-ImplicitCastExpr <col:83> 'vector<float, 3>':'vector<float, 3>' <HLSLVectorSplat>
  123. | | `-FloatingLiteral <col:83> 'float' 5.500000e-02
  124. | `-ImplicitCastExpr <col:93> 'vector<float, 3>':'vector<float, 3>' <HLSLVectorSplat>
  125. | `-FloatingLiteral <col:93> 'float' 1.055000e+00
  126. `-ImplicitCastExpr <col:101> 'vector<float, 3>':'vector<float, 3>' <HLSLVectorSplat>
  127. `-FloatingLiteral <col:101> 'float' 2.400000e+00
  128. */
  129. return output;
  130. }
  131. float4 fn_cf2u(const float4 p1, uint p2) {
  132. return float4(1, 2, 3, 4);
  133. }
  134. float3 fn_cf3u(const float3 p1, uint p2) {
  135. return fn_cf2u(float4 (p1, 0.f), p2).xyz;
  136. }
  137. int call_int_oload(int i) { return i + 5; } // expected-note {{candidate function}} fxc-pass {{}}
  138. int call_int_oload(int2 i) { return i.y + 5; } // expected-note {{candidate function}} fxc-pass {{}}
  139. inline float minimum(float a, float b) { if (a > b) return b; return a; }
  140. inline float2 minimum(const float2 a, const float2 b) {
  141. float2 result;
  142. for (int i = 0; i < 2; ++i) {
  143. result[i] = a[i];
  144. if (result[i] > b[i])
  145. result[i] = b[i];
  146. }
  147. return result;
  148. }
  149. inline uint3 minimum(const uint3 a, const uint3 b) {
  150. uint3 result;
  151. for (int i = 0; i < 3; ++i) {
  152. result[i] = a[i];
  153. if (result[i] > b[i])
  154. result[i] = b[i];
  155. }
  156. return result;
  157. }
  158. void tryMinimums() {
  159. float3 tMin = { 1, 2, 3 };
  160. float3 tMax = { 3, 2, 1 };
  161. tMin = minimum(tMin, tMax);
  162. }
  163. void tryMinimumsWithOut(out float3 tMin, out float3 tMax) {
  164. tMin = minimum(tMin, tMax);
  165. }
  166. void fn_indexer_write(RWTexture2D < float4 > rw) {
  167. uint2 coord = { 1, 2 };
  168. rw[coord] = float4(1, 2, 3, 4);
  169. }
  170. // K&R-style functions and implicit int usage; none of this is accepted.
  171. fn_knr(a) // expected-error {{expected ';' after top level declarator}} expected-error {{unknown type name 'fn_knr'}} expected-note {{previous definition is here}} fxc-error {{X3000: unrecognized identifier 'fn_knr'}} //
  172. uint a; // expected-error {{redefinition of 'a'}} fxc-pass {{}}
  173. { // expected-error {{expected unqualified-id}} fxc-error {{X3000: syntax error: unexpected token '{'}}
  174. }
  175. void call_knr() {
  176. extern_fn(); // expected-error {{use of undeclared identifier 'extern_fn'}} fxc-error {{X3004: undeclared identifier 'extern_fn'}}
  177. }
  178. // in/inout/out modifiers
  179. void fn_inout_separate(in out float2 f2) {}
  180. void fn_inout_separate_2(out out float2 f2) {} // expected-error {{duplicate HLSL parameter usages 'out'}} fxc-error {{X3048: duplicate usages specified}}
  181. void fn_inout_separate_2(in out inout float2 f2) {} // expected-error {{duplicate HLSL parameter usages 'in'}} expected-error {{duplicate HLSL parameter usages 'out'}} fxc-error {{X3048: duplicate usages specified}}
  182. void fn_uint(in uint u) {}
  183. void fn_uintio(inout uint u) {} // expected-note {{candidate function}} fxc-pass {{}}
  184. void fn_uinto(out uint u) {} // expected-note {{candidate function}} fxc-pass {{}}
  185. void fn_uint_oload(uint u) { } // expected-note {{candidate function}} fxc-pass {{}}
  186. void fn_uint_oload(out uint u) { } // expected-note {{candidate function}} fxc-pass {{}}
  187. void fn_uint_oload2(inout uint u) { }
  188. void fn_uint_oload2(out uint u) { }
  189. void fn_uint_oload3(uint u) { }
  190. void fn_uint_oload3(inout uint u) { }
  191. void fn_uint_oload3(out uint u) { }
  192. // function redefinitions
  193. void fn_redef(min10float x) {} /* expected-note {{previous definition is here}} expected-warning {{min10float is promoted to min16float}} */
  194. void fn_redef(min16float x) {} /* expected-error {{redefinition of 'fn_redef'}} */
  195. void fn_redef2(min12int x) {} /* expected-note {{previous definition is here}} expected-warning {{min12int is promoted to min16int}} */
  196. void fn_redef2(min16int x) {} /* expected-error {{redefinition of 'fn_redef2'}} */
  197. void fn_redef3(half x) {} /* expected-note {{previous definition is here}} */
  198. void fn_redef3(float x) {} /* expected-error {{redefinition of 'fn_redef3'}} */
  199. typedef min16int My16Int;
  200. void fn_redef4(min16int x) {} /* expected-note {{previous definition is here}} */
  201. void fn_redef4(My16Int x) {} /* expected-error {{redefinition of 'fn_redef4'}} */
  202. void inout_calls() {
  203. uint u = 1;
  204. // Variables are fine.
  205. fn_uint(u);
  206. fn_uintio(u);
  207. fn_uinto(u);
  208. // TODO: globals
  209. // Literals won't work with inout or out.
  210. fn_uint(1);
  211. fn_uintio(1); // expected-error {{no matching function for call to 'fn_uintio'}} fxc-error {{X3025: l-value specifies const object}}
  212. fn_uinto(1); // expected-error {{no matching function for call to 'fn_uinto'}} fxc-error {{X3025: l-value specifies const object}}
  213. // Conversions in calls, these all work.
  214. float2 f2 = { 1, 2 };
  215. fn_uint(f2.x);
  216. fn_uintio(f2.x);
  217. fn_uinto(f2.x);
  218. // Overload on only in/inout/out is ambiguous.
  219. fn_uint_oload(u); // expected-error {{ambiguous}} fxc-error {{X3067: 'fn_uint_oload': ambiguous function call}}
  220. // Overload on in/inout/out is affected by conversions (and is not ambiguous).
  221. fn_uint_oload(f2.x); // this selects the in version over inout
  222. fn_uint_oload2(f2.x); // this selects the out version over inout (one conversion less)
  223. fn_uint_oload3(f2.x); // this selects the in version over inout or out
  224. }
  225. void cs_main() {
  226. float2 f2 = float2(1, 2);
  227. float arr2[2] = { 1, 2 };
  228. fn_float_arr(f2); // expected-error {{no matching function for call to 'fn_float_arr'}} fxc-error {{X3017: 'fn_float_arr': cannot convert from 'float2' to 'float[2]'}}
  229. fn_float_arr(arr2);
  230. fn_inout_separate(f2);
  231. f2 = arr2[0];
  232. f2 = arr2[arr2[0]];
  233. f2 = 0[arr2]; // expected-error {{HLSL does not support having the base of a subscript operator in brackets}} fxc-error {{X3121: array, matrix, vector, or indexable object type expected in index expression}}
  234. float3 result = { 0, 0, 0 };
  235. result.x += call_int_oload(int2(1, 2));
  236. result.x += call_int_oload(30);
  237. result.x += call_int_oload(int3(100, 200, 300)); // expected-error {{call to 'call_int_oload' is ambiguous}} fxc-error {{X3067: 'call_int_oload': ambiguous function call}}
  238. float3 tMin, tMax;
  239. tryMinimums();
  240. tryMinimumsWithOut(tMin, tMax);
  241. fn_float_arr_out(arr2);
  242. // arr2 = arr_return();
  243. }