duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

effect_symbol_table_intrinsics.inl (159812B)


      1 /*
      2  * Copyright (C) 2014 Patrick Mours
      3  * SPDX-License-Identifier: BSD-3-Clause
      4  */
      5 
      6 #if defined(__INTELLISENSE__) || !defined(DEFINE_INTRINSIC)
      7 #define DEFINE_INTRINSIC(name, i, ret_type, ...)
      8 #endif
      9 #if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_GLSL)
     10 #define IMPLEMENT_INTRINSIC_GLSL(name, i, code)
     11 #endif
     12 #if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_HLSL)
     13 #define IMPLEMENT_INTRINSIC_HLSL(name, i, code)
     14 #endif
     15 #if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_SPIRV)
     16 #define IMPLEMENT_INTRINSIC_SPIRV(name, i, code)
     17 #endif
     18 
     19 // ret abs(x)
     20 DEFINE_INTRINSIC(abs, 0, int, int)
     21 DEFINE_INTRINSIC(abs, 0, int2, int2)
     22 DEFINE_INTRINSIC(abs, 0, int3, int3)
     23 DEFINE_INTRINSIC(abs, 0, int4, int4)
     24 DEFINE_INTRINSIC(abs, 1, float, float)
     25 DEFINE_INTRINSIC(abs, 1, float2, float2)
     26 DEFINE_INTRINSIC(abs, 1, float3, float3)
     27 DEFINE_INTRINSIC(abs, 1, float4, float4)
     28 IMPLEMENT_INTRINSIC_GLSL(abs, 0, {
     29 	code += "abs(" + id_to_name(args[0].base) + ')';
     30 	})
     31 IMPLEMENT_INTRINSIC_GLSL(abs, 1, {
     32 	code += "abs(" + id_to_name(args[0].base) + ')';
     33 	})
     34 IMPLEMENT_INTRINSIC_HLSL(abs, 0, {
     35 	code += "abs(" + id_to_name(args[0].base) + ')';
     36 	})
     37 IMPLEMENT_INTRINSIC_HLSL(abs, 1, {
     38 	code += "abs(" + id_to_name(args[0].base) + ')';
     39 	})
     40 IMPLEMENT_INTRINSIC_SPIRV(abs, 0, {
     41 	return
     42 	add_instruction(spv::OpExtInst, convert_type(res_type))
     43 		.add(_glsl_ext)
     44 		.add(spv::GLSLstd450SAbs)
     45 		.add(args[0].base)
     46 		.result;
     47 	})
     48 IMPLEMENT_INTRINSIC_SPIRV(abs, 1, {
     49 	return
     50 	add_instruction(spv::OpExtInst, convert_type(res_type))
     51 		.add(_glsl_ext)
     52 		.add(spv::GLSLstd450FAbs)
     53 		.add(args[0].base)
     54 		.result;
     55 	})
     56 
     57 // ret all(x)
     58 DEFINE_INTRINSIC(all, 0, bool, bool)
     59 DEFINE_INTRINSIC(all, 1, bool, bool2)
     60 DEFINE_INTRINSIC(all, 1, bool, bool3)
     61 DEFINE_INTRINSIC(all, 1, bool, bool4)
     62 IMPLEMENT_INTRINSIC_GLSL(all, 0, {
     63 	code += id_to_name(args[0].base);
     64 	})
     65 IMPLEMENT_INTRINSIC_GLSL(all, 1, {
     66 	code += "all(" + id_to_name(args[0].base) + ')';
     67 	})
     68 IMPLEMENT_INTRINSIC_HLSL(all, 0, {
     69 	code += id_to_name(args[0].base);
     70 	})
     71 IMPLEMENT_INTRINSIC_HLSL(all, 1, {
     72 	code += "all(" + id_to_name(args[0].base) + ')';
     73 	})
     74 IMPLEMENT_INTRINSIC_SPIRV(all, 0, {
     75 	return args[0].base;
     76 	})
     77 IMPLEMENT_INTRINSIC_SPIRV(all, 1, {
     78 	return
     79 	add_instruction(spv::OpAll, convert_type(res_type))
     80 		.add(args[0].base)
     81 		.result;
     82 	})
     83 
     84 // ret any(x)
     85 DEFINE_INTRINSIC(any, 0, bool, bool)
     86 DEFINE_INTRINSIC(any, 1, bool, bool2)
     87 DEFINE_INTRINSIC(any, 1, bool, bool3)
     88 DEFINE_INTRINSIC(any, 1, bool, bool4)
     89 IMPLEMENT_INTRINSIC_GLSL(any, 0, {
     90 	code += id_to_name(args[0].base);
     91 	})
     92 IMPLEMENT_INTRINSIC_GLSL(any, 1, {
     93 	code += "any(" + id_to_name(args[0].base) + ')';
     94 	})
     95 IMPLEMENT_INTRINSIC_HLSL(any, 0, {
     96 	code += id_to_name(args[0].base);
     97 	})
     98 IMPLEMENT_INTRINSIC_HLSL(any, 1, {
     99 	code += "any(" + id_to_name(args[0].base) + ')';
    100 	})
    101 IMPLEMENT_INTRINSIC_SPIRV(any, 0, {
    102 	return args[0].base;
    103 	})
    104 IMPLEMENT_INTRINSIC_SPIRV(any, 1, {
    105 	return
    106 	add_instruction(spv::OpAny, convert_type(res_type))
    107 		.add(args[0].base)
    108 		.result;
    109 	})
    110 
    111 // ret asin(x)
    112 DEFINE_INTRINSIC(asin, 0, float, float)
    113 DEFINE_INTRINSIC(asin, 0, float2, float2)
    114 DEFINE_INTRINSIC(asin, 0, float3, float3)
    115 DEFINE_INTRINSIC(asin, 0, float4, float4)
    116 IMPLEMENT_INTRINSIC_GLSL(asin, 0, {
    117 	code += "asin(" + id_to_name(args[0].base) + ')';
    118 	})
    119 IMPLEMENT_INTRINSIC_HLSL(asin, 0, {
    120 	code += "asin(" + id_to_name(args[0].base) + ')';
    121 	})
    122 IMPLEMENT_INTRINSIC_SPIRV(asin, 0, {
    123 	return
    124 	add_instruction(spv::OpExtInst, convert_type(res_type))
    125 		.add(_glsl_ext)
    126 		.add(spv::GLSLstd450Asin)
    127 		.add(args[0].base)
    128 		.result;
    129 	})
    130 
    131 // ret acos(x)
    132 DEFINE_INTRINSIC(acos, 0, float, float)
    133 DEFINE_INTRINSIC(acos, 0, float2, float2)
    134 DEFINE_INTRINSIC(acos, 0, float3, float3)
    135 DEFINE_INTRINSIC(acos, 0, float4, float4)
    136 IMPLEMENT_INTRINSIC_GLSL(acos, 0, {
    137 	code += "acos(" + id_to_name(args[0].base) + ')';
    138 	})
    139 IMPLEMENT_INTRINSIC_HLSL(acos, 0, {
    140 	code += "acos(" + id_to_name(args[0].base) + ')';
    141 	})
    142 IMPLEMENT_INTRINSIC_SPIRV(acos, 0, {
    143 	return
    144 	add_instruction(spv::OpExtInst, convert_type(res_type))
    145 		.add(_glsl_ext)
    146 		.add(spv::GLSLstd450Acos)
    147 		.add(args[0].base)
    148 		.result;
    149 	})
    150 
    151 // ret atan(x)
    152 DEFINE_INTRINSIC(atan, 0, float, float)
    153 DEFINE_INTRINSIC(atan, 0, float2, float2)
    154 DEFINE_INTRINSIC(atan, 0, float3, float3)
    155 DEFINE_INTRINSIC(atan, 0, float4, float4)
    156 IMPLEMENT_INTRINSIC_GLSL(atan, 0, {
    157 	code += "atan(" + id_to_name(args[0].base) + ')';
    158 	})
    159 IMPLEMENT_INTRINSIC_HLSL(atan, 0, {
    160 	code += "atan(" + id_to_name(args[0].base) + ')';
    161 	})
    162 IMPLEMENT_INTRINSIC_SPIRV(atan, 0, {
    163 	return
    164 	add_instruction(spv::OpExtInst, convert_type(res_type))
    165 		.add(_glsl_ext)
    166 		.add(spv::GLSLstd450Atan)
    167 		.add(args[0].base)
    168 		.result;
    169 	})
    170 
    171 // ret atan2(x, y)
    172 DEFINE_INTRINSIC(atan2, 0, float, float, float)
    173 DEFINE_INTRINSIC(atan2, 0, float2, float2, float2)
    174 DEFINE_INTRINSIC(atan2, 0, float3, float3, float3)
    175 DEFINE_INTRINSIC(atan2, 0, float4, float4, float4)
    176 IMPLEMENT_INTRINSIC_GLSL(atan2, 0, {
    177 	code += "atan(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    178 	})
    179 IMPLEMENT_INTRINSIC_HLSL(atan2, 0, {
    180 	code += "atan2(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    181 	})
    182 IMPLEMENT_INTRINSIC_SPIRV(atan2, 0, {
    183 	return
    184 	add_instruction(spv::OpExtInst, convert_type(res_type))
    185 		.add(_glsl_ext)
    186 		.add(spv::GLSLstd450Atan2)
    187 		.add(args[0].base)
    188 		.add(args[1].base)
    189 		.result;
    190 	})
    191 
    192 // ret sin(x)
    193 DEFINE_INTRINSIC(sin, 0, float, float)
    194 DEFINE_INTRINSIC(sin, 0, float2, float2)
    195 DEFINE_INTRINSIC(sin, 0, float3, float3)
    196 DEFINE_INTRINSIC(sin, 0, float4, float4)
    197 IMPLEMENT_INTRINSIC_GLSL(sin, 0, {
    198 	code += "sin(" + id_to_name(args[0].base) + ')';
    199 	})
    200 IMPLEMENT_INTRINSIC_HLSL(sin, 0, {
    201 	code += "sin(" + id_to_name(args[0].base) + ')';
    202 	})
    203 IMPLEMENT_INTRINSIC_SPIRV(sin, 0, {
    204 	return
    205 	add_instruction(spv::OpExtInst, convert_type(res_type))
    206 		.add(_glsl_ext)
    207 		.add(spv::GLSLstd450Sin)
    208 		.add(args[0].base)
    209 		.result;
    210 	})
    211 
    212 // ret sinh(x)
    213 DEFINE_INTRINSIC(sinh, 0, float, float)
    214 DEFINE_INTRINSIC(sinh, 0, float2, float2)
    215 DEFINE_INTRINSIC(sinh, 0, float3, float3)
    216 DEFINE_INTRINSIC(sinh, 0, float4, float4)
    217 IMPLEMENT_INTRINSIC_GLSL(sinh, 0, {
    218 	code += "sinh(" + id_to_name(args[0].base) + ')';
    219 	})
    220 IMPLEMENT_INTRINSIC_HLSL(sinh, 0, {
    221 	code += "sinh(" + id_to_name(args[0].base) + ')';
    222 	})
    223 IMPLEMENT_INTRINSIC_SPIRV(sinh, 0, {
    224 	return
    225 	add_instruction(spv::OpExtInst, convert_type(res_type))
    226 		.add(_glsl_ext)
    227 		.add(spv::GLSLstd450Sinh)
    228 		.add(args[0].base)
    229 		.result;
    230 	})
    231 
    232 // ret cos(x)
    233 DEFINE_INTRINSIC(cos, 0, float, float)
    234 DEFINE_INTRINSIC(cos, 0, float2, float2)
    235 DEFINE_INTRINSIC(cos, 0, float3, float3)
    236 DEFINE_INTRINSIC(cos, 0, float4, float4)
    237 IMPLEMENT_INTRINSIC_GLSL(cos, 0, {
    238 	code += "cos(" + id_to_name(args[0].base) + ')';
    239 	})
    240 IMPLEMENT_INTRINSIC_HLSL(cos, 0, {
    241 	code += "cos(" + id_to_name(args[0].base) + ')';
    242 	})
    243 IMPLEMENT_INTRINSIC_SPIRV(cos, 0, {
    244 	return
    245 	add_instruction(spv::OpExtInst, convert_type(res_type))
    246 		.add(_glsl_ext)
    247 		.add(spv::GLSLstd450Cos)
    248 		.add(args[0].base)
    249 		.result;
    250 	})
    251 
    252 // ret cosh(x)
    253 DEFINE_INTRINSIC(cosh, 0, float, float)
    254 DEFINE_INTRINSIC(cosh, 0, float2, float2)
    255 DEFINE_INTRINSIC(cosh, 0, float3, float3)
    256 DEFINE_INTRINSIC(cosh, 0, float4, float4)
    257 IMPLEMENT_INTRINSIC_GLSL(cosh, 0, {
    258 	code += "cosh(" + id_to_name(args[0].base) + ')';
    259 	})
    260 IMPLEMENT_INTRINSIC_HLSL(cosh, 0, {
    261 	code += "cosh(" + id_to_name(args[0].base) + ')';
    262 	})
    263 IMPLEMENT_INTRINSIC_SPIRV(cosh, 0, {
    264 	return
    265 	add_instruction(spv::OpExtInst, convert_type(res_type))
    266 		.add(_glsl_ext)
    267 		.add(spv::GLSLstd450Cosh)
    268 		.add(args[0].base)
    269 		.result;
    270 	})
    271 
    272 // ret tan(x)
    273 DEFINE_INTRINSIC(tan, 0, float, float)
    274 DEFINE_INTRINSIC(tan, 0, float2, float2)
    275 DEFINE_INTRINSIC(tan, 0, float3, float3)
    276 DEFINE_INTRINSIC(tan, 0, float4, float4)
    277 IMPLEMENT_INTRINSIC_GLSL(tan, 0, {
    278 	code += "tan(" + id_to_name(args[0].base) + ')';
    279 	})
    280 IMPLEMENT_INTRINSIC_HLSL(tan, 0, {
    281 	code += "tan(" + id_to_name(args[0].base) + ')';
    282 	})
    283 IMPLEMENT_INTRINSIC_SPIRV(tan, 0, {
    284 	return
    285 	add_instruction(spv::OpExtInst, convert_type(res_type))
    286 		.add(_glsl_ext)
    287 		.add(spv::GLSLstd450Tan)
    288 		.add(args[0].base)
    289 		.result;
    290 	})
    291 
    292 // ret tanh(x)
    293 DEFINE_INTRINSIC(tanh, 0, float, float)
    294 DEFINE_INTRINSIC(tanh, 0, float2, float2)
    295 DEFINE_INTRINSIC(tanh, 0, float3, float3)
    296 DEFINE_INTRINSIC(tanh, 0, float4, float4)
    297 IMPLEMENT_INTRINSIC_GLSL(tanh, 0, {
    298 	code += "tanh(" + id_to_name(args[0].base) + ')';
    299 	})
    300 IMPLEMENT_INTRINSIC_HLSL(tanh, 0, {
    301 	code += "tanh(" + id_to_name(args[0].base) + ')';
    302 	})
    303 IMPLEMENT_INTRINSIC_SPIRV(tanh, 0, {
    304 	return
    305 	add_instruction(spv::OpExtInst, convert_type(res_type))
    306 		.add(_glsl_ext)
    307 		.add(spv::GLSLstd450Tanh)
    308 		.add(args[0].base)
    309 		.result;
    310 	})
    311 
    312 // sincos(x, out s, out c)
    313 DEFINE_INTRINSIC(sincos, 0, void, float, out_float, out_float)
    314 DEFINE_INTRINSIC(sincos, 0, void, float2, out_float2, out_float2)
    315 DEFINE_INTRINSIC(sincos, 0, void, float3, out_float3, out_float3)
    316 DEFINE_INTRINSIC(sincos, 0, void, float4, out_float4, out_float4)
    317 IMPLEMENT_INTRINSIC_GLSL(sincos, 0, {
    318 	code += id_to_name(args[1].base) + " = sin(" + id_to_name(args[0].base) + "), " + id_to_name(args[2].base) + " = cos(" + id_to_name(args[0].base) + ')';
    319 	})
    320 IMPLEMENT_INTRINSIC_HLSL(sincos, 0, {
    321 	code += "sincos(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    322 	})
    323 IMPLEMENT_INTRINSIC_SPIRV(sincos, 0, {
    324 	const spv::Id sin_result = add_instruction(spv::OpExtInst, convert_type(args[0].type))
    325 		.add(_glsl_ext)
    326 		.add(spv::GLSLstd450Sin)
    327 		.add(args[0].base)
    328 		.result;
    329 	const spv::Id cos_result = add_instruction(spv::OpExtInst, convert_type(args[0].type))
    330 		.add(_glsl_ext)
    331 		.add(spv::GLSLstd450Cos)
    332 		.add(args[0].base)
    333 		.result;
    334 
    335 	add_instruction_without_result(spv::OpStore)
    336 		.add(args[1].base)
    337 		.add(sin_result);
    338 	add_instruction_without_result(spv::OpStore)
    339 		.add(args[2].base)
    340 		.add(cos_result);
    341 
    342 	return 0;
    343 	})
    344 
    345 // ret asint(x)
    346 DEFINE_INTRINSIC(asint, 0, int, float)
    347 DEFINE_INTRINSIC(asint, 0, int2, float2)
    348 DEFINE_INTRINSIC(asint, 0, int3, float3)
    349 DEFINE_INTRINSIC(asint, 0, int4, float4)
    350 IMPLEMENT_INTRINSIC_GLSL(asint, 0, {
    351 	code += "floatBitsToInt(" + id_to_name(args[0].base) + ')';
    352 	})
    353 IMPLEMENT_INTRINSIC_HLSL(asint, 0, {
    354 	_uses_bitwise_cast = true;
    355 	if (_shader_model < 40)
    356 		code += "__";
    357 	code += "asint(" + id_to_name(args[0].base) + ')';
    358 	})
    359 IMPLEMENT_INTRINSIC_SPIRV(asint, 0, {
    360 	return
    361 	add_instruction(spv::OpBitcast, convert_type(res_type))
    362 		.add(args[0].base)
    363 		.result;
    364 	})
    365 
    366 // ret asuint(x)
    367 DEFINE_INTRINSIC(asuint, 0, uint, float)
    368 DEFINE_INTRINSIC(asuint, 0, uint2, float2)
    369 DEFINE_INTRINSIC(asuint, 0, uint3, float3)
    370 DEFINE_INTRINSIC(asuint, 0, uint4, float4)
    371 IMPLEMENT_INTRINSIC_GLSL(asuint, 0, {
    372 	code += "floatBitsToUint(" + id_to_name(args[0].base) + ')';
    373 	})
    374 IMPLEMENT_INTRINSIC_HLSL(asuint, 0, {
    375 	_uses_bitwise_cast = true;
    376 	if (_shader_model < 40)
    377 		code += "__";
    378 	code += "asuint(" + id_to_name(args[0].base) + ')';
    379 	})
    380 IMPLEMENT_INTRINSIC_SPIRV(asuint, 0, {
    381 	return
    382 	add_instruction(spv::OpBitcast, convert_type(res_type))
    383 		.add(args[0].base)
    384 		.result;
    385 	})
    386 
    387 // ret asfloat(x)
    388 DEFINE_INTRINSIC(asfloat, 0, float, int)
    389 DEFINE_INTRINSIC(asfloat, 0, float2, int2)
    390 DEFINE_INTRINSIC(asfloat, 0, float3, int3)
    391 DEFINE_INTRINSIC(asfloat, 0, float4, int4)
    392 DEFINE_INTRINSIC(asfloat, 1, float, uint)
    393 DEFINE_INTRINSIC(asfloat, 1, float2, uint2)
    394 DEFINE_INTRINSIC(asfloat, 1, float3, uint3)
    395 DEFINE_INTRINSIC(asfloat, 1, float4, uint4)
    396 IMPLEMENT_INTRINSIC_GLSL(asfloat, 0, {
    397 	code += "intBitsToFloat(" + id_to_name(args[0].base) + ')';
    398 	})
    399 IMPLEMENT_INTRINSIC_GLSL(asfloat, 1, {
    400 	code += "uintBitsToFloat(" + id_to_name(args[0].base) + ')';
    401 	})
    402 IMPLEMENT_INTRINSIC_HLSL(asfloat, 0, {
    403 	_uses_bitwise_cast = true;
    404 	if (_shader_model < 40)
    405 		code += "__";
    406 	code += "asfloat(" + id_to_name(args[0].base) + ')';
    407 	})
    408 IMPLEMENT_INTRINSIC_HLSL(asfloat, 1, {
    409 	_uses_bitwise_cast = true;
    410 	if (_shader_model < 40)
    411 		code += "__";
    412 	code += "asfloat(" + id_to_name(args[0].base) + ')';
    413 	})
    414 IMPLEMENT_INTRINSIC_SPIRV(asfloat, 0, {
    415 	return
    416 	add_instruction(spv::OpBitcast, convert_type(res_type))
    417 		.add(args[0].base)
    418 		.result;
    419 	})
    420 IMPLEMENT_INTRINSIC_SPIRV(asfloat, 1, {
    421 	return
    422 	add_instruction(spv::OpBitcast, convert_type(res_type))
    423 		.add(args[0].base)
    424 		.result;
    425 	})
    426 
    427 // ret firstbitlow
    428 DEFINE_INTRINSIC(firstbitlow, 0, uint, uint)
    429 DEFINE_INTRINSIC(firstbitlow, 0, uint2, uint2)
    430 DEFINE_INTRINSIC(firstbitlow, 0, uint3, uint3)
    431 DEFINE_INTRINSIC(firstbitlow, 0, uint4, uint4)
    432 IMPLEMENT_INTRINSIC_GLSL(firstbitlow, 0, {
    433 	code += "findLSB(" + id_to_name(args[0].base) + ')';
    434 	})
    435 IMPLEMENT_INTRINSIC_HLSL(firstbitlow, 0, {
    436 	if (_shader_model < 50)
    437 		code += "__";
    438 	code += "firstbitlow(" + id_to_name(args[0].base) + ')';
    439 	})
    440 IMPLEMENT_INTRINSIC_SPIRV(firstbitlow, 0, {
    441 	return
    442 	add_instruction(spv::OpExtInst, convert_type(res_type))
    443 		.add(_glsl_ext)
    444 		.add(spv::GLSLstd450FindILsb)
    445 		.add(args[0].base)
    446 		.result;
    447 	})
    448 
    449 // ret firstbithigh
    450 DEFINE_INTRINSIC(firstbithigh, 0, int, int)
    451 DEFINE_INTRINSIC(firstbithigh, 0, int2, int2)
    452 DEFINE_INTRINSIC(firstbithigh, 0, int3, int3)
    453 DEFINE_INTRINSIC(firstbithigh, 0, int4, int4)
    454 DEFINE_INTRINSIC(firstbithigh, 1, uint, uint)
    455 DEFINE_INTRINSIC(firstbithigh, 1, uint2, uint2)
    456 DEFINE_INTRINSIC(firstbithigh, 1, uint3, uint3)
    457 DEFINE_INTRINSIC(firstbithigh, 1, uint4, uint4)
    458 IMPLEMENT_INTRINSIC_GLSL(firstbithigh, 0, {
    459 	code += "findMSB(" + id_to_name(args[0].base) + ')';
    460 	})
    461 IMPLEMENT_INTRINSIC_GLSL(firstbithigh, 1, {
    462 	code += "findMSB(" + id_to_name(args[0].base) + ')';
    463 	})
    464 IMPLEMENT_INTRINSIC_HLSL(firstbithigh, 0, {
    465 	if (_shader_model < 50)
    466 		code += "__";
    467 	code += "firstbithigh(" + id_to_name(args[0].base) + ')';
    468 	})
    469 IMPLEMENT_INTRINSIC_HLSL(firstbithigh, 1, {
    470 	if (_shader_model < 50)
    471 		code += "__";
    472 	code += "firstbithigh(" + id_to_name(args[0].base) + ')';
    473 	})
    474 IMPLEMENT_INTRINSIC_SPIRV(firstbithigh, 0, {
    475 	return
    476 	add_instruction(spv::OpExtInst, convert_type(res_type))
    477 		.add(_glsl_ext)
    478 		.add(spv::GLSLstd450FindSMsb)
    479 		.add(args[0].base)
    480 		.result;
    481 	})
    482 IMPLEMENT_INTRINSIC_SPIRV(firstbithigh, 1, {
    483 	return
    484 	add_instruction(spv::OpExtInst, convert_type(res_type))
    485 		.add(_glsl_ext)
    486 		.add(spv::GLSLstd450FindUMsb)
    487 		.add(args[0].base)
    488 		.result;
    489 	})
    490 
    491 // ret countbits
    492 DEFINE_INTRINSIC(countbits, 0, uint, uint)
    493 DEFINE_INTRINSIC(countbits, 0, uint2, uint2)
    494 DEFINE_INTRINSIC(countbits, 0, uint3, uint3)
    495 DEFINE_INTRINSIC(countbits, 0, uint4, uint4)
    496 IMPLEMENT_INTRINSIC_GLSL(countbits, 0, {
    497 	code += "bitCount(" + id_to_name(args[0].base) + ')';
    498 	})
    499 IMPLEMENT_INTRINSIC_HLSL(countbits, 0, {
    500 	if (_shader_model < 50)
    501 		code += "__";
    502 	code += "countbits(" + id_to_name(args[0].base) + ')';
    503 	})
    504 IMPLEMENT_INTRINSIC_SPIRV(countbits, 0, {
    505 	return
    506 	add_instruction(spv::OpBitCount, convert_type(res_type))
    507 		.add(args[0].base)
    508 		.result;
    509 	})
    510 
    511 // ret reversebits
    512 DEFINE_INTRINSIC(reversebits, 0, uint, uint)
    513 DEFINE_INTRINSIC(reversebits, 0, uint2, uint2)
    514 DEFINE_INTRINSIC(reversebits, 0, uint3, uint3)
    515 DEFINE_INTRINSIC(reversebits, 0, uint4, uint4)
    516 IMPLEMENT_INTRINSIC_GLSL(reversebits, 0, {
    517 	code += "bitfieldReverse(" + id_to_name(args[0].base) + ')';
    518 	})
    519 IMPLEMENT_INTRINSIC_HLSL(reversebits, 0, {
    520 	if (_shader_model < 50)
    521 		code += "__";
    522 	code += "reversebits(" + id_to_name(args[0].base) + ')';
    523 	})
    524 IMPLEMENT_INTRINSIC_SPIRV(reversebits, 0, {
    525 	return
    526 	add_instruction(spv::OpBitReverse, convert_type(res_type))
    527 		.add(args[0].base)
    528 		.result;
    529 	})
    530 
    531 // ret ceil(x)
    532 DEFINE_INTRINSIC(ceil, 0, float, float)
    533 DEFINE_INTRINSIC(ceil, 0, float2, float2)
    534 DEFINE_INTRINSIC(ceil, 0, float3, float3)
    535 DEFINE_INTRINSIC(ceil, 0, float4, float4)
    536 IMPLEMENT_INTRINSIC_GLSL(ceil, 0, {
    537 	code += "ceil(" + id_to_name(args[0].base) + ')';
    538 	})
    539 IMPLEMENT_INTRINSIC_HLSL(ceil, 0, {
    540 	code += "ceil(" + id_to_name(args[0].base) + ')';
    541 	})
    542 IMPLEMENT_INTRINSIC_SPIRV(ceil, 0, {
    543 	return
    544 	add_instruction(spv::OpExtInst, convert_type(res_type))
    545 		.add(_glsl_ext)
    546 		.add(spv::GLSLstd450Ceil)
    547 		.add(args[0].base)
    548 		.result;
    549 	})
    550 
    551 // ret floor(x)
    552 DEFINE_INTRINSIC(floor, 0, float, float)
    553 DEFINE_INTRINSIC(floor, 0, float2, float2)
    554 DEFINE_INTRINSIC(floor, 0, float3, float3)
    555 DEFINE_INTRINSIC(floor, 0, float4, float4)
    556 IMPLEMENT_INTRINSIC_GLSL(floor, 0, {
    557 	code += "floor(" + id_to_name(args[0].base) + ')';
    558 	})
    559 IMPLEMENT_INTRINSIC_HLSL(floor, 0, {
    560 	if (_shader_model >= 40)
    561 		code += "floor(" + id_to_name(args[0].base) + ')';
    562 	else // Using the floor intrinsic sometimes causes the SM3 D3DCompiler to generate wrong code, so replace it with a custom implementation
    563 		code += id_to_name(args[0].base) + " - frac(" + id_to_name(args[0].base) + ')';
    564 	})
    565 IMPLEMENT_INTRINSIC_SPIRV(floor, 0, {
    566 	return
    567 	add_instruction(spv::OpExtInst, convert_type(res_type))
    568 		.add(_glsl_ext)
    569 		.add(spv::GLSLstd450Floor)
    570 		.add(args[0].base)
    571 		.result;
    572 	})
    573 
    574 // ret clamp(x, min, max)
    575 DEFINE_INTRINSIC(clamp, 0, int, int, int, int)
    576 DEFINE_INTRINSIC(clamp, 0, int2, int2, int2, int2)
    577 DEFINE_INTRINSIC(clamp, 0, int3, int3, int3, int3)
    578 DEFINE_INTRINSIC(clamp, 0, int4, int4, int4, int4)
    579 DEFINE_INTRINSIC(clamp, 1, uint, uint, uint, uint)
    580 DEFINE_INTRINSIC(clamp, 1, uint2, uint2, uint2, uint2)
    581 DEFINE_INTRINSIC(clamp, 1, uint3, uint3, uint3, uint3)
    582 DEFINE_INTRINSIC(clamp, 1, uint4, uint4, uint4, uint4)
    583 DEFINE_INTRINSIC(clamp, 2, float, float, float, float)
    584 DEFINE_INTRINSIC(clamp, 2, float2, float2, float2, float2)
    585 DEFINE_INTRINSIC(clamp, 2, float3, float3, float3, float3)
    586 DEFINE_INTRINSIC(clamp, 2, float4, float4, float4, float4)
    587 IMPLEMENT_INTRINSIC_GLSL(clamp, 0, {
    588 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    589 	})
    590 IMPLEMENT_INTRINSIC_GLSL(clamp, 1, {
    591 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    592 	})
    593 IMPLEMENT_INTRINSIC_GLSL(clamp, 2, {
    594 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    595 	})
    596 IMPLEMENT_INTRINSIC_HLSL(clamp, 0, {
    597 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    598 	})
    599 IMPLEMENT_INTRINSIC_HLSL(clamp, 1, {
    600 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    601 	})
    602 IMPLEMENT_INTRINSIC_HLSL(clamp, 2, {
    603 	code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    604 	})
    605 IMPLEMENT_INTRINSIC_SPIRV(clamp, 0, {
    606 	return
    607 	add_instruction(spv::OpExtInst, convert_type(res_type))
    608 		.add(_glsl_ext)
    609 		.add(spv::GLSLstd450SClamp)
    610 		.add(args[0].base)
    611 		.add(args[1].base)
    612 		.add(args[2].base)
    613 		.result;
    614 	})
    615 IMPLEMENT_INTRINSIC_SPIRV(clamp, 1, {
    616 	return
    617 	add_instruction(spv::OpExtInst, convert_type(res_type))
    618 		.add(_glsl_ext)
    619 		.add(spv::GLSLstd450UClamp)
    620 		.add(args[0].base)
    621 		.add(args[1].base)
    622 		.add(args[2].base)
    623 		.result;
    624 	})
    625 IMPLEMENT_INTRINSIC_SPIRV(clamp, 2, {
    626 	return
    627 	add_instruction(spv::OpExtInst, convert_type(res_type))
    628 		.add(_glsl_ext)
    629 		.add(spv::GLSLstd450FClamp)
    630 		.add(args[0].base)
    631 		.add(args[1].base)
    632 		.add(args[2].base)
    633 		.result;
    634 	})
    635 
    636 // ret saturate(x)
    637 DEFINE_INTRINSIC(saturate, 0, float, float)
    638 DEFINE_INTRINSIC(saturate, 0, float2, float2)
    639 DEFINE_INTRINSIC(saturate, 0, float3, float3)
    640 DEFINE_INTRINSIC(saturate, 0, float4, float4)
    641 IMPLEMENT_INTRINSIC_GLSL(saturate, 0, {
    642 	code += "clamp(" + id_to_name(args[0].base) + ", 0.0, 1.0)";
    643 	})
    644 IMPLEMENT_INTRINSIC_HLSL(saturate, 0, {
    645 	code += "saturate(" + id_to_name(args[0].base) + ')';
    646 	})
    647 IMPLEMENT_INTRINSIC_SPIRV(saturate, 0, {
    648 	const spv::Id constant_one = emit_constant(args[0].type, 1u);
    649 	const spv::Id constant_zero = emit_constant(args[0].type, 0u);
    650 
    651 	return
    652 	add_instruction(spv::OpExtInst, convert_type(res_type))
    653 		.add(_glsl_ext)
    654 		.add(spv::GLSLstd450FClamp)
    655 		.add(args[0].base)
    656 		.add(constant_zero)
    657 		.add(constant_one)
    658 		.result;
    659 	})
    660 
    661 // ret mad(mvalue, avalue, bvalue)
    662 DEFINE_INTRINSIC(mad, 0, float, float, float, float)
    663 DEFINE_INTRINSIC(mad, 0, float2, float2, float2, float2)
    664 DEFINE_INTRINSIC(mad, 0, float3, float3, float3, float3)
    665 DEFINE_INTRINSIC(mad, 0, float4, float4, float4, float4)
    666 IMPLEMENT_INTRINSIC_GLSL(mad, 0, {
    667 	code += "fma(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    668 	})
    669 IMPLEMENT_INTRINSIC_HLSL(mad, 0, {
    670 	if (_shader_model >= 50)
    671 		code += "mad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    672 	else
    673 		code += id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base);
    674 	})
    675 IMPLEMENT_INTRINSIC_SPIRV(mad, 0, {
    676 	return
    677 	add_instruction(spv::OpExtInst, convert_type(res_type))
    678 		.add(_glsl_ext)
    679 		.add(spv::GLSLstd450Fma)
    680 		.add(args[0].base)
    681 		.add(args[1].base)
    682 		.add(args[2].base)
    683 		.result;
    684 	})
    685 
    686 // ret rcp(x)
    687 DEFINE_INTRINSIC(rcp, 0, float, float)
    688 DEFINE_INTRINSIC(rcp, 0, float2, float2)
    689 DEFINE_INTRINSIC(rcp, 0, float3, float3)
    690 DEFINE_INTRINSIC(rcp, 0, float4, float4)
    691 IMPLEMENT_INTRINSIC_GLSL(rcp, 0, {
    692 	code += "1.0 / " + id_to_name(args[0].base);
    693 	})
    694 IMPLEMENT_INTRINSIC_HLSL(rcp, 0, {
    695 	if (_shader_model >= 50)
    696 		code += "rcp(" + id_to_name(args[0].base) + ')';
    697 	else
    698 		code += "1.0 / " + id_to_name(args[0].base);
    699 	})
    700 IMPLEMENT_INTRINSIC_SPIRV(rcp, 0, {
    701 	const spv::Id constant_one = emit_constant(args[0].type, 1u);
    702 
    703 	return
    704 	add_instruction(spv::OpFDiv, convert_type(res_type))
    705 		.add(constant_one)
    706 		.add(args[0].base)
    707 		.result;
    708 	})
    709 
    710 // ret pow(x, y)
    711 DEFINE_INTRINSIC(pow, 0, float, float, float)
    712 DEFINE_INTRINSIC(pow, 0, float2, float2, float2)
    713 DEFINE_INTRINSIC(pow, 0, float3, float3, float3)
    714 DEFINE_INTRINSIC(pow, 0, float4, float4, float4)
    715 IMPLEMENT_INTRINSIC_GLSL(pow, 0, {
    716 	code += "pow(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    717 	})
    718 IMPLEMENT_INTRINSIC_HLSL(pow, 0, {
    719 	code += "pow(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    720 	})
    721 IMPLEMENT_INTRINSIC_SPIRV(pow, 0, {
    722 	return
    723 	add_instruction(spv::OpExtInst, convert_type(res_type))
    724 		.add(_glsl_ext)
    725 		.add(spv::GLSLstd450Pow)
    726 		.add(args[0].base)
    727 		.add(args[1].base)
    728 		.result;
    729 	})
    730 
    731 // ret exp(x)
    732 DEFINE_INTRINSIC(exp, 0, float, float)
    733 DEFINE_INTRINSIC(exp, 0, float2, float2)
    734 DEFINE_INTRINSIC(exp, 0, float3, float3)
    735 DEFINE_INTRINSIC(exp, 0, float4, float4)
    736 IMPLEMENT_INTRINSIC_GLSL(exp, 0, {
    737 	code += "exp(" + id_to_name(args[0].base) + ')';
    738 	})
    739 IMPLEMENT_INTRINSIC_HLSL(exp, 0, {
    740 	code += "exp(" + id_to_name(args[0].base) + ')';
    741 	})
    742 IMPLEMENT_INTRINSIC_SPIRV(exp, 0, {
    743 	return
    744 	add_instruction(spv::OpExtInst, convert_type(res_type))
    745 		.add(_glsl_ext)
    746 		.add(spv::GLSLstd450Exp)
    747 		.add(args[0].base)
    748 		.result;
    749 	})
    750 
    751 // ret exp2(x)
    752 DEFINE_INTRINSIC(exp2, 0, float, float)
    753 DEFINE_INTRINSIC(exp2, 0, float2, float2)
    754 DEFINE_INTRINSIC(exp2, 0, float3, float3)
    755 DEFINE_INTRINSIC(exp2, 0, float4, float4)
    756 IMPLEMENT_INTRINSIC_GLSL(exp2, 0, {
    757 	code += "exp2(" + id_to_name(args[0].base) + ')';
    758 	})
    759 IMPLEMENT_INTRINSIC_HLSL(exp2, 0, {
    760 	code += "exp2(" + id_to_name(args[0].base) + ')';
    761 	})
    762 IMPLEMENT_INTRINSIC_SPIRV(exp2, 0, {
    763 	return
    764 	add_instruction(spv::OpExtInst, convert_type(res_type))
    765 		.add(_glsl_ext)
    766 		.add(spv::GLSLstd450Exp2)
    767 		.add(args[0].base)
    768 		.result;
    769 	})
    770 
    771 // ret log(x)
    772 DEFINE_INTRINSIC(log, 0, float, float)
    773 DEFINE_INTRINSIC(log, 0, float2, float2)
    774 DEFINE_INTRINSIC(log, 0, float3, float3)
    775 DEFINE_INTRINSIC(log, 0, float4, float4)
    776 IMPLEMENT_INTRINSIC_GLSL(log, 0, {
    777 	code += "log(" + id_to_name(args[0].base) + ')';
    778 	})
    779 IMPLEMENT_INTRINSIC_HLSL(log, 0, {
    780 	code += "log(" + id_to_name(args[0].base) + ')';
    781 	})
    782 IMPLEMENT_INTRINSIC_SPIRV(log, 0, {
    783 	return
    784 	add_instruction(spv::OpExtInst, convert_type(res_type))
    785 		.add(_glsl_ext)
    786 		.add(spv::GLSLstd450Log)
    787 		.add(args[0].base)
    788 		.result;
    789 	})
    790 
    791 // ret log2(x)
    792 DEFINE_INTRINSIC(log2, 0, float, float)
    793 DEFINE_INTRINSIC(log2, 0, float2, float2)
    794 DEFINE_INTRINSIC(log2, 0, float3, float3)
    795 DEFINE_INTRINSIC(log2, 0, float4, float4)
    796 IMPLEMENT_INTRINSIC_GLSL(log2, 0, {
    797 	code += "log2(" + id_to_name(args[0].base) + ')';
    798 	})
    799 IMPLEMENT_INTRINSIC_HLSL(log2, 0, {
    800 	code += "log2(" + id_to_name(args[0].base) + ')';
    801 	})
    802 IMPLEMENT_INTRINSIC_SPIRV(log2, 0, {
    803 	return
    804 	add_instruction(spv::OpExtInst, convert_type(res_type))
    805 		.add(_glsl_ext)
    806 		.add(spv::GLSLstd450Log2)
    807 		.add(args[0].base)
    808 		.result;
    809 	})
    810 
    811 // ret log10(x)
    812 DEFINE_INTRINSIC(log10, 0, float, float)
    813 DEFINE_INTRINSIC(log10, 0, float2, float2)
    814 DEFINE_INTRINSIC(log10, 0, float3, float3)
    815 DEFINE_INTRINSIC(log10, 0, float4, float4)
    816 IMPLEMENT_INTRINSIC_GLSL(log10, 0, {
    817 	code += "(log2(" + id_to_name(args[0].base) + ") / log2(10.0))";
    818 	})
    819 IMPLEMENT_INTRINSIC_HLSL(log10, 0, {
    820 	code += "(log2(" + id_to_name(args[0].base) + ") / log2(10.0))";
    821 	})
    822 IMPLEMENT_INTRINSIC_SPIRV(log10, 0, {
    823 	const spv::Id log2 = add_instruction(spv::OpExtInst, convert_type(res_type))
    824 		.add(_glsl_ext)
    825 		.add(spv::GLSLstd450Log2)
    826 		.add(args[0].base)
    827 		.result;
    828 
    829 	const spv::Id log10 = emit_constant(args[0].type, /* log2(10) */
    830 		constant { { 3.321928f, 3.321928f, 3.321928f, 3.321928f } });
    831 
    832 	return
    833 	add_instruction(spv::OpFDiv, convert_type(res_type))
    834 		.add(log2)
    835 		.add(log10)
    836 		.result; })
    837 
    838 // ret sign(x)
    839 DEFINE_INTRINSIC(sign, 0, int, int)
    840 DEFINE_INTRINSIC(sign, 0, int2, int2)
    841 DEFINE_INTRINSIC(sign, 0, int3, int3)
    842 DEFINE_INTRINSIC(sign, 0, int4, int4)
    843 DEFINE_INTRINSIC(sign, 1, float, float)
    844 DEFINE_INTRINSIC(sign, 1, float2, float2)
    845 DEFINE_INTRINSIC(sign, 1, float3, float3)
    846 DEFINE_INTRINSIC(sign, 1, float4, float4)
    847 IMPLEMENT_INTRINSIC_GLSL(sign, 0, {
    848 	code += "sign(" + id_to_name(args[0].base) + ')';
    849 	})
    850 IMPLEMENT_INTRINSIC_GLSL(sign, 1, {
    851 	code += "sign(" + id_to_name(args[0].base) + ')';
    852 	})
    853 IMPLEMENT_INTRINSIC_HLSL(sign, 0, {
    854 	code += "sign(" + id_to_name(args[0].base) + ')';
    855 	})
    856 IMPLEMENT_INTRINSIC_HLSL(sign, 1, {
    857 	code += "sign(" + id_to_name(args[0].base) + ')';
    858 	})
    859 IMPLEMENT_INTRINSIC_SPIRV(sign, 0, {
    860 	return
    861 	add_instruction(spv::OpExtInst, convert_type(res_type))
    862 		.add(_glsl_ext)
    863 		.add(spv::GLSLstd450SSign)
    864 		.add(args[0].base)
    865 		.result;
    866 	})
    867 IMPLEMENT_INTRINSIC_SPIRV(sign, 1, {
    868 	return
    869 	add_instruction(spv::OpExtInst, convert_type(res_type))
    870 		.add(_glsl_ext)
    871 		.add(spv::GLSLstd450FSign)
    872 		.add(args[0].base)
    873 		.result;
    874 	})
    875 
    876 // ret sqrt(x)
    877 DEFINE_INTRINSIC(sqrt, 0, float, float)
    878 DEFINE_INTRINSIC(sqrt, 0, float2, float2)
    879 DEFINE_INTRINSIC(sqrt, 0, float3, float3)
    880 DEFINE_INTRINSIC(sqrt, 0, float4, float4)
    881 IMPLEMENT_INTRINSIC_GLSL(sqrt, 0, {
    882 	code += "sqrt(" + id_to_name(args[0].base) + ')';
    883 	})
    884 IMPLEMENT_INTRINSIC_HLSL(sqrt, 0, {
    885 	code += "sqrt(" + id_to_name(args[0].base) + ')';
    886 	})
    887 IMPLEMENT_INTRINSIC_SPIRV(sqrt, 0, {
    888 	return
    889 	add_instruction(spv::OpExtInst, convert_type(res_type))
    890 		.add(_glsl_ext)
    891 		.add(spv::GLSLstd450Sqrt)
    892 		.add(args[0].base)
    893 		.result;
    894 	})
    895 
    896 // ret rsqrt(x)
    897 DEFINE_INTRINSIC(rsqrt, 0, float, float)
    898 DEFINE_INTRINSIC(rsqrt, 0, float2, float2)
    899 DEFINE_INTRINSIC(rsqrt, 0, float3, float3)
    900 DEFINE_INTRINSIC(rsqrt, 0, float4, float4)
    901 IMPLEMENT_INTRINSIC_GLSL(rsqrt, 0, {
    902 	code += "inversesqrt(" + id_to_name(args[0].base) + ')';
    903 	})
    904 IMPLEMENT_INTRINSIC_HLSL(rsqrt, 0, {
    905 	code += "rsqrt(" + id_to_name(args[0].base) + ')';
    906 	})
    907 IMPLEMENT_INTRINSIC_SPIRV(rsqrt, 0, {
    908 	return
    909 	add_instruction(spv::OpExtInst, convert_type(res_type))
    910 		.add(_glsl_ext)
    911 		.add(spv::GLSLstd450InverseSqrt)
    912 		.add(args[0].base)
    913 		.result;
    914 	})
    915 
    916 // ret lerp(x, y, s)
    917 DEFINE_INTRINSIC(lerp, 0, float, float, float, float)
    918 DEFINE_INTRINSIC(lerp, 0, float2, float2, float2, float2)
    919 DEFINE_INTRINSIC(lerp, 0, float3, float3, float3, float3)
    920 DEFINE_INTRINSIC(lerp, 0, float4, float4, float4, float4)
    921 IMPLEMENT_INTRINSIC_GLSL(lerp, 0, {
    922 	code += "mix(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    923 	})
    924 IMPLEMENT_INTRINSIC_HLSL(lerp, 0, {
    925 	code += "lerp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    926 	})
    927 IMPLEMENT_INTRINSIC_SPIRV(lerp, 0, {
    928 	return
    929 	add_instruction(spv::OpExtInst, convert_type(res_type))
    930 		.add(_glsl_ext)
    931 		.add(spv::GLSLstd450FMix)
    932 		.add(args[0].base)
    933 		.add(args[1].base)
    934 		.add(args[2].base)
    935 		.result;
    936 	})
    937 
    938 // ret step(y, x)
    939 DEFINE_INTRINSIC(step, 0, float, float, float)
    940 DEFINE_INTRINSIC(step, 0, float2, float2, float2)
    941 DEFINE_INTRINSIC(step, 0, float3, float3, float3)
    942 DEFINE_INTRINSIC(step, 0, float4, float4, float4)
    943 IMPLEMENT_INTRINSIC_GLSL(step, 0, {
    944 	code += "step(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    945 	})
    946 IMPLEMENT_INTRINSIC_HLSL(step, 0, {
    947 	code += "step(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
    948 	})
    949 IMPLEMENT_INTRINSIC_SPIRV(step, 0, {
    950 	return
    951 	add_instruction(spv::OpExtInst, convert_type(res_type))
    952 		.add(_glsl_ext)
    953 		.add(spv::GLSLstd450Step)
    954 		.add(args[0].base)
    955 		.add(args[1].base)
    956 		.result;
    957 	})
    958 
    959 // ret smoothstep(min, max, x)
    960 DEFINE_INTRINSIC(smoothstep, 0, float, float, float, float)
    961 DEFINE_INTRINSIC(smoothstep, 0, float2, float2, float2, float2)
    962 DEFINE_INTRINSIC(smoothstep, 0, float3, float3, float3, float3)
    963 DEFINE_INTRINSIC(smoothstep, 0, float4, float4, float4, float4)
    964 IMPLEMENT_INTRINSIC_GLSL(smoothstep, 0, {
    965 	code += "smoothstep(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    966 	})
    967 IMPLEMENT_INTRINSIC_HLSL(smoothstep, 0, {
    968 	code += "smoothstep(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
    969 	})
    970 IMPLEMENT_INTRINSIC_SPIRV(smoothstep, 0, {
    971 	return
    972 	add_instruction(spv::OpExtInst, convert_type(args[2].type))
    973 		.add(_glsl_ext)
    974 		.add(spv::GLSLstd450SmoothStep)
    975 		.add(args[0].base)
    976 		.add(args[1].base)
    977 		.add(args[2].base)
    978 		.result;
    979 	})
    980 
    981 // ret frac(x)
    982 DEFINE_INTRINSIC(frac, 0, float, float)
    983 DEFINE_INTRINSIC(frac, 0, float2, float2)
    984 DEFINE_INTRINSIC(frac, 0, float3, float3)
    985 DEFINE_INTRINSIC(frac, 0, float4, float4)
    986 IMPLEMENT_INTRINSIC_GLSL(frac, 0, {
    987 	code += "fract(" + id_to_name(args[0].base) + ')';
    988 	})
    989 IMPLEMENT_INTRINSIC_HLSL(frac, 0, {
    990 	code += "frac(" + id_to_name(args[0].base) + ')';
    991 	})
    992 IMPLEMENT_INTRINSIC_SPIRV(frac, 0, {
    993 	return
    994 	add_instruction(spv::OpExtInst, convert_type(res_type))
    995 		.add(_glsl_ext)
    996 		.add(spv::GLSLstd450Fract)
    997 		.add(args[0].base)
    998 		.result;
    999 	})
   1000 
   1001 // ret ldexp(x, exp)
   1002 DEFINE_INTRINSIC(ldexp, 0, float, float, int)
   1003 DEFINE_INTRINSIC(ldexp, 0, float2, float2, int2)
   1004 DEFINE_INTRINSIC(ldexp, 0, float3, float3, int3)
   1005 DEFINE_INTRINSIC(ldexp, 0, float4, float4, int4)
   1006 IMPLEMENT_INTRINSIC_GLSL(ldexp, 0, {
   1007 	code += "ldexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1008 	})
   1009 IMPLEMENT_INTRINSIC_HLSL(ldexp, 0, {
   1010 	code += "ldexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1011 	})
   1012 IMPLEMENT_INTRINSIC_SPIRV(ldexp, 0, {
   1013 	return
   1014 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1015 		.add(_glsl_ext)
   1016 		.add(spv::GLSLstd450Ldexp)
   1017 		.add(args[0].base)
   1018 		.add(args[1].base)
   1019 		.result;
   1020 	})
   1021 
   1022 // ret modf(x, out ip)
   1023 DEFINE_INTRINSIC(modf, 0, float, float, out_float)
   1024 DEFINE_INTRINSIC(modf, 0, float2, float2, out_float2)
   1025 DEFINE_INTRINSIC(modf, 0, float3, float3, out_float3)
   1026 DEFINE_INTRINSIC(modf, 0, float4, float4, out_float4)
   1027 IMPLEMENT_INTRINSIC_GLSL(modf, 0, {
   1028 	code += "modf(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1029 	})
   1030 IMPLEMENT_INTRINSIC_HLSL(modf, 0, {
   1031 	code += "modf(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1032 	})
   1033 IMPLEMENT_INTRINSIC_SPIRV(modf, 0, {
   1034 	return
   1035 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1036 		.add(_glsl_ext)
   1037 		.add(spv::GLSLstd450Modf)
   1038 		.add(args[0].base)
   1039 		.add(args[1].base)
   1040 		.result;
   1041 	})
   1042 
   1043 // ret frexp(x, out exp)
   1044 DEFINE_INTRINSIC(frexp, 0, float, float, out_int)
   1045 DEFINE_INTRINSIC(frexp, 0, float2, float2, out_int2)
   1046 DEFINE_INTRINSIC(frexp, 0, float3, float3, out_int3)
   1047 DEFINE_INTRINSIC(frexp, 0, float4, float4, out_int4)
   1048 IMPLEMENT_INTRINSIC_GLSL(frexp, 0, {
   1049 	code += "frexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1050 	})
   1051 IMPLEMENT_INTRINSIC_HLSL(frexp, 0, {
   1052 	code += "frexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1053 	})
   1054 IMPLEMENT_INTRINSIC_SPIRV(frexp, 0, {
   1055 	return
   1056 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1057 		.add(_glsl_ext)
   1058 		.add(spv::GLSLstd450Frexp)
   1059 		.add(args[0].base)
   1060 		.add(args[1].base)
   1061 		.result;
   1062 	})
   1063 
   1064 // ret trunc(x)
   1065 DEFINE_INTRINSIC(trunc, 0, float, float)
   1066 DEFINE_INTRINSIC(trunc, 0, float2, float2)
   1067 DEFINE_INTRINSIC(trunc, 0, float3, float3)
   1068 DEFINE_INTRINSIC(trunc, 0, float4, float4)
   1069 IMPLEMENT_INTRINSIC_GLSL(trunc, 0, {
   1070 	code += "trunc(" + id_to_name(args[0].base) + ')';
   1071 	})
   1072 IMPLEMENT_INTRINSIC_HLSL(trunc, 0, {
   1073 	code += "trunc(" + id_to_name(args[0].base) + ')';
   1074 	})
   1075 IMPLEMENT_INTRINSIC_SPIRV(trunc, 0, {
   1076 	return
   1077 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1078 		.add(_glsl_ext)
   1079 		.add(spv::GLSLstd450Trunc)
   1080 		.add(args[0].base)
   1081 		.result;
   1082 	})
   1083 
   1084 // ret round(x)
   1085 DEFINE_INTRINSIC(round, 0, float, float)
   1086 DEFINE_INTRINSIC(round, 0, float2, float2)
   1087 DEFINE_INTRINSIC(round, 0, float3, float3)
   1088 DEFINE_INTRINSIC(round, 0, float4, float4)
   1089 IMPLEMENT_INTRINSIC_GLSL(round, 0, {
   1090 	code += "round(" + id_to_name(args[0].base) + ')';
   1091 	})
   1092 IMPLEMENT_INTRINSIC_HLSL(round, 0, {
   1093 	code += "round(" + id_to_name(args[0].base) + ')';
   1094 	})
   1095 IMPLEMENT_INTRINSIC_SPIRV(round, 0, {
   1096 	return
   1097 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1098 		.add(_glsl_ext)
   1099 		.add(spv::GLSLstd450Round)
   1100 		.add(args[0].base)
   1101 		.result;
   1102 	})
   1103 
   1104 // ret min(x, y)
   1105 DEFINE_INTRINSIC(min, 0, int, int, int)
   1106 DEFINE_INTRINSIC(min, 0, int2, int2, int2)
   1107 DEFINE_INTRINSIC(min, 0, int3, int3, int3)
   1108 DEFINE_INTRINSIC(min, 0, int4, int4, int4)
   1109 DEFINE_INTRINSIC(min, 1, float, float, float)
   1110 DEFINE_INTRINSIC(min, 1, float2, float2, float2)
   1111 DEFINE_INTRINSIC(min, 1, float3, float3, float3)
   1112 DEFINE_INTRINSIC(min, 1, float4, float4, float4)
   1113 IMPLEMENT_INTRINSIC_GLSL(min, 0, {
   1114 	code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1115 	})
   1116 IMPLEMENT_INTRINSIC_GLSL(min, 1, {
   1117 	code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1118 	})
   1119 IMPLEMENT_INTRINSIC_HLSL(min, 0, {
   1120 	code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1121 	})
   1122 IMPLEMENT_INTRINSIC_HLSL(min, 1, {
   1123 	code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1124 	})
   1125 IMPLEMENT_INTRINSIC_SPIRV(min, 0, {
   1126 	return
   1127 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1128 		.add(_glsl_ext)
   1129 		.add(spv::GLSLstd450SMin)
   1130 		.add(args[0].base)
   1131 		.add(args[1].base)
   1132 		.result;
   1133 	})
   1134 IMPLEMENT_INTRINSIC_SPIRV(min, 1, {
   1135 	return
   1136 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1137 		.add(_glsl_ext)
   1138 		.add(spv::GLSLstd450FMin)
   1139 		.add(args[0].base)
   1140 		.add(args[1].base)
   1141 		.result;
   1142 	})
   1143 
   1144 // ret max(x, y)
   1145 DEFINE_INTRINSIC(max, 0, int, int, int)
   1146 DEFINE_INTRINSIC(max, 0, int2, int2, int2)
   1147 DEFINE_INTRINSIC(max, 0, int3, int3, int3)
   1148 DEFINE_INTRINSIC(max, 0, int4, int4, int4)
   1149 DEFINE_INTRINSIC(max, 1, float, float, float)
   1150 DEFINE_INTRINSIC(max, 1, float2, float2, float2)
   1151 DEFINE_INTRINSIC(max, 1, float3, float3, float3)
   1152 DEFINE_INTRINSIC(max, 1, float4, float4, float4)
   1153 IMPLEMENT_INTRINSIC_GLSL(max, 0, {
   1154 	code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1155 	})
   1156 IMPLEMENT_INTRINSIC_GLSL(max, 1, {
   1157 	code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1158 	})
   1159 IMPLEMENT_INTRINSIC_HLSL(max, 0, {
   1160 	code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1161 	})
   1162 IMPLEMENT_INTRINSIC_HLSL(max, 1, {
   1163 	code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1164 	})
   1165 IMPLEMENT_INTRINSIC_SPIRV(max, 0, {
   1166 	return
   1167 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1168 		.add(_glsl_ext)
   1169 		.add(spv::GLSLstd450SMax)
   1170 		.add(args[0].base)
   1171 		.add(args[1].base)
   1172 		.result;
   1173 	})
   1174 IMPLEMENT_INTRINSIC_SPIRV(max, 1, {
   1175 	return
   1176 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1177 		.add(_glsl_ext)
   1178 		.add(spv::GLSLstd450FMax)
   1179 		.add(args[0].base)
   1180 		.add(args[1].base)
   1181 		.result;
   1182 	})
   1183 
   1184 // ret degree(x)
   1185 DEFINE_INTRINSIC(degrees, 0, float, float)
   1186 DEFINE_INTRINSIC(degrees, 0, float2, float2)
   1187 DEFINE_INTRINSIC(degrees, 0, float3, float3)
   1188 DEFINE_INTRINSIC(degrees, 0, float4, float4)
   1189 IMPLEMENT_INTRINSIC_GLSL(degrees, 0, {
   1190 	code += "degrees(" + id_to_name(args[0].base) + ')';
   1191 	})
   1192 IMPLEMENT_INTRINSIC_HLSL(degrees, 0, {
   1193 	code += "degrees(" + id_to_name(args[0].base) + ')';
   1194 	})
   1195 IMPLEMENT_INTRINSIC_SPIRV(degrees, 0, {
   1196 	return
   1197 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1198 		.add(_glsl_ext)
   1199 		.add(spv::GLSLstd450Degrees)
   1200 		.add(args[0].base)
   1201 		.result;
   1202 	})
   1203 
   1204 // ret radians(x)
   1205 DEFINE_INTRINSIC(radians, 0, float, float)
   1206 DEFINE_INTRINSIC(radians, 0, float2, float2)
   1207 DEFINE_INTRINSIC(radians, 0, float3, float3)
   1208 DEFINE_INTRINSIC(radians, 0, float4, float4)
   1209 IMPLEMENT_INTRINSIC_GLSL(radians, 0, {
   1210 	code += "radians(" + id_to_name(args[0].base) + ')';
   1211 	})
   1212 IMPLEMENT_INTRINSIC_HLSL(radians, 0, {
   1213 	code += "radians(" + id_to_name(args[0].base) + ')';
   1214 	})
   1215 IMPLEMENT_INTRINSIC_SPIRV(radians, 0, {
   1216 	return
   1217 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1218 		.add(_glsl_ext)
   1219 		.add(spv::GLSLstd450Radians)
   1220 		.add(args[0].base)
   1221 		.result;
   1222 	})
   1223 
   1224 // ret ddx(x)
   1225 DEFINE_INTRINSIC(ddx, 0, float, float)
   1226 DEFINE_INTRINSIC(ddx, 0, float2, float2)
   1227 DEFINE_INTRINSIC(ddx, 0, float3, float3)
   1228 DEFINE_INTRINSIC(ddx, 0, float4, float4)
   1229 IMPLEMENT_INTRINSIC_GLSL(ddx, 0, {
   1230 	code += "dFdx(" + id_to_name(args[0].base) + ')';
   1231 	})
   1232 IMPLEMENT_INTRINSIC_HLSL(ddx, 0, {
   1233 	code += "ddx(" + id_to_name(args[0].base) + ')';
   1234 	})
   1235 IMPLEMENT_INTRINSIC_SPIRV(ddx, 0, {
   1236 	return
   1237 	add_instruction(spv::OpDPdx, convert_type(res_type))
   1238 		.add(args[0].base)
   1239 		.result;
   1240 	})
   1241 
   1242 // ret ddy(x)
   1243 DEFINE_INTRINSIC(ddy, 0, float, float)
   1244 DEFINE_INTRINSIC(ddy, 0, float2, float2)
   1245 DEFINE_INTRINSIC(ddy, 0, float3, float3)
   1246 DEFINE_INTRINSIC(ddy, 0, float4, float4)
   1247 IMPLEMENT_INTRINSIC_GLSL(ddy, 0, {
   1248 	code += "dFdy(" + id_to_name(args[0].base) + ')';
   1249 	})
   1250 IMPLEMENT_INTRINSIC_HLSL(ddy, 0, {
   1251 	code += "ddy(" + id_to_name(args[0].base) + ')';
   1252 	})
   1253 IMPLEMENT_INTRINSIC_SPIRV(ddy, 0, {
   1254 	return
   1255 	add_instruction(spv::OpDPdy, convert_type(res_type))
   1256 		.add(args[0].base)
   1257 		.result;
   1258 	})
   1259 
   1260 // ret fwidth(x)
   1261 DEFINE_INTRINSIC(fwidth, 0, float, float)
   1262 DEFINE_INTRINSIC(fwidth, 0, float2, float2)
   1263 DEFINE_INTRINSIC(fwidth, 0, float3, float3)
   1264 DEFINE_INTRINSIC(fwidth, 0, float4, float4)
   1265 IMPLEMENT_INTRINSIC_GLSL(fwidth, 0, {
   1266 	code += "fwidth(" + id_to_name(args[0].base) + ')';
   1267 	})
   1268 IMPLEMENT_INTRINSIC_HLSL(fwidth, 0, {
   1269 	code += "fwidth(" + id_to_name(args[0].base) + ')';
   1270 	})
   1271 IMPLEMENT_INTRINSIC_SPIRV(fwidth, 0, {
   1272 	return
   1273 	add_instruction(spv::OpFwidth, convert_type(res_type))
   1274 		.add(args[0].base)
   1275 		.result;
   1276 	})
   1277 
   1278 // ret dot(x, y)
   1279 DEFINE_INTRINSIC(dot, 0, float, float, float)
   1280 DEFINE_INTRINSIC(dot, 1, float, float2, float2)
   1281 DEFINE_INTRINSIC(dot, 1, float, float3, float3)
   1282 DEFINE_INTRINSIC(dot, 1, float, float4, float4)
   1283 IMPLEMENT_INTRINSIC_GLSL(dot, 0, {
   1284 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1285 	})
   1286 IMPLEMENT_INTRINSIC_GLSL(dot, 1, {
   1287 	code += "dot(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1288 	})
   1289 IMPLEMENT_INTRINSIC_HLSL(dot, 0, {
   1290 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1291 	})
   1292 IMPLEMENT_INTRINSIC_HLSL(dot, 1, {
   1293 	code += "dot(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1294 	})
   1295 IMPLEMENT_INTRINSIC_SPIRV(dot, 0, {
   1296 	return
   1297 	add_instruction(spv::OpFMul, convert_type(res_type))
   1298 		.add(args[0].base)
   1299 		.add(args[1].base)
   1300 		.result;
   1301 	})
   1302 IMPLEMENT_INTRINSIC_SPIRV(dot, 1, {
   1303 	return
   1304 	add_instruction(spv::OpDot, convert_type(res_type))
   1305 		.add(args[0].base)
   1306 		.add(args[1].base)
   1307 		.result;
   1308 	})
   1309 
   1310 // ret cross(x, y)
   1311 DEFINE_INTRINSIC(cross, 0, float3, float3, float3)
   1312 IMPLEMENT_INTRINSIC_GLSL(cross, 0, {
   1313 	code += "cross(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1314 	})
   1315 IMPLEMENT_INTRINSIC_HLSL(cross, 0, {
   1316 	code += "cross(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1317 	})
   1318 IMPLEMENT_INTRINSIC_SPIRV(cross, 0, {
   1319 	return
   1320 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1321 		.add(_glsl_ext)
   1322 		.add(spv::GLSLstd450Cross)
   1323 		.add(args[0].base)
   1324 		.add(args[1].base)
   1325 		.result;
   1326 	})
   1327 
   1328 // ret length(x)
   1329 DEFINE_INTRINSIC(length, 0, float, float)
   1330 DEFINE_INTRINSIC(length, 0, float, float2)
   1331 DEFINE_INTRINSIC(length, 0, float, float3)
   1332 DEFINE_INTRINSIC(length, 0, float, float4)
   1333 IMPLEMENT_INTRINSIC_GLSL(length, 0, {
   1334 	code += "length(" + id_to_name(args[0].base) + ')';
   1335 	})
   1336 IMPLEMENT_INTRINSIC_HLSL(length, 0, {
   1337 	code += "length(" + id_to_name(args[0].base) + ')';
   1338 	})
   1339 IMPLEMENT_INTRINSIC_SPIRV(length, 0, {
   1340 	return
   1341 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1342 		.add(_glsl_ext)
   1343 		.add(spv::GLSLstd450Length)
   1344 		.add(args[0].base)
   1345 		.result;
   1346 	})
   1347 
   1348 // ret distance(x, y)
   1349 DEFINE_INTRINSIC(distance, 0, float, float, float)
   1350 DEFINE_INTRINSIC(distance, 0, float, float2, float2)
   1351 DEFINE_INTRINSIC(distance, 0, float, float3, float3)
   1352 DEFINE_INTRINSIC(distance, 0, float, float4, float4)
   1353 IMPLEMENT_INTRINSIC_GLSL(distance, 0, {
   1354 	code += "distance(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1355 	})
   1356 IMPLEMENT_INTRINSIC_HLSL(distance, 0, {
   1357 	code += "distance(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1358 	})
   1359 IMPLEMENT_INTRINSIC_SPIRV(distance, 0, {
   1360 	return
   1361 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1362 		.add(_glsl_ext)
   1363 		.add(spv::GLSLstd450Distance)
   1364 		.add(args[0].base)
   1365 		.add(args[1].base)
   1366 		.result;
   1367 	})
   1368 
   1369 // ret normalize(x)
   1370 DEFINE_INTRINSIC(normalize, 0, float2, float2)
   1371 DEFINE_INTRINSIC(normalize, 0, float3, float3)
   1372 DEFINE_INTRINSIC(normalize, 0, float4, float4)
   1373 IMPLEMENT_INTRINSIC_GLSL(normalize, 0, {
   1374 	code += "normalize(" + id_to_name(args[0].base) + ')';
   1375 	})
   1376 IMPLEMENT_INTRINSIC_HLSL(normalize, 0, {
   1377 	code += "normalize(" + id_to_name(args[0].base) + ')';
   1378 	})
   1379 IMPLEMENT_INTRINSIC_SPIRV(normalize, 0, {
   1380 	return
   1381 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1382 		.add(_glsl_ext)
   1383 		.add(spv::GLSLstd450Normalize)
   1384 		.add(args[0].base)
   1385 		.result;
   1386 	})
   1387 
   1388 // ret transpose(x)
   1389 DEFINE_INTRINSIC(transpose, 0, float2x2, float2x2)
   1390 DEFINE_INTRINSIC(transpose, 0, float2x3, float3x2)
   1391 DEFINE_INTRINSIC(transpose, 0, float2x4, float4x2)
   1392 DEFINE_INTRINSIC(transpose, 0, float3x2, float2x3)
   1393 DEFINE_INTRINSIC(transpose, 0, float3x3, float3x3)
   1394 DEFINE_INTRINSIC(transpose, 0, float3x4, float4x3)
   1395 DEFINE_INTRINSIC(transpose, 0, float4x2, float2x4)
   1396 DEFINE_INTRINSIC(transpose, 0, float4x3, float3x4)
   1397 DEFINE_INTRINSIC(transpose, 0, float4x4, float4x4)
   1398 IMPLEMENT_INTRINSIC_GLSL(transpose, 0, {
   1399 	code += "transpose(" + id_to_name(args[0].base) + ')';
   1400 	})
   1401 IMPLEMENT_INTRINSIC_HLSL(transpose, 0, {
   1402 	code += "transpose(" + id_to_name(args[0].base) + ')';
   1403 	})
   1404 IMPLEMENT_INTRINSIC_SPIRV(transpose, 0, {
   1405 	return
   1406 	add_instruction(spv::OpTranspose, convert_type(res_type))
   1407 		.add(args[0].base)
   1408 		.result;
   1409 	})
   1410 
   1411 // ret determinant(m)
   1412 DEFINE_INTRINSIC(determinant, 0, float, float2x2)
   1413 DEFINE_INTRINSIC(determinant, 0, float, float3x3)
   1414 DEFINE_INTRINSIC(determinant, 0, float, float4x4)
   1415 IMPLEMENT_INTRINSIC_GLSL(determinant, 0, {
   1416 	code += "determinant(" + id_to_name(args[0].base) + ')';
   1417 	})
   1418 IMPLEMENT_INTRINSIC_HLSL(determinant, 0, {
   1419 	code += "determinant(" + id_to_name(args[0].base) + ')';
   1420 	})
   1421 IMPLEMENT_INTRINSIC_SPIRV(determinant, 0, {
   1422 	return
   1423 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1424 		.add(_glsl_ext)
   1425 		.add(spv::GLSLstd450Determinant)
   1426 		.add(args[0].base)
   1427 		.result;
   1428 	})
   1429 
   1430 // ret reflect(i, n)
   1431 DEFINE_INTRINSIC(reflect, 0, float2, float2, float2)
   1432 DEFINE_INTRINSIC(reflect, 0, float3, float3, float3)
   1433 DEFINE_INTRINSIC(reflect, 0, float4, float4, float4)
   1434 IMPLEMENT_INTRINSIC_GLSL(reflect, 0, {
   1435 	code += "reflect(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1436 	})
   1437 IMPLEMENT_INTRINSIC_HLSL(reflect, 0, {
   1438 	code += "reflect(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1439 	})
   1440 IMPLEMENT_INTRINSIC_SPIRV(reflect, 0, {
   1441 	return
   1442 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1443 		.add(_glsl_ext)
   1444 		.add(spv::GLSLstd450Reflect)
   1445 		.add(args[0].base)
   1446 		.add(args[1].base)
   1447 		.result;
   1448 	})
   1449 
   1450 // ret refract(i, n, eta)
   1451 DEFINE_INTRINSIC(refract, 0, float2, float2, float2, float)
   1452 DEFINE_INTRINSIC(refract, 0, float3, float3, float3, float)
   1453 DEFINE_INTRINSIC(refract, 0, float4, float4, float4, float)
   1454 IMPLEMENT_INTRINSIC_GLSL(refract, 0, {
   1455 	code += "refract(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
   1456 	})
   1457 IMPLEMENT_INTRINSIC_HLSL(refract, 0, {
   1458 	code += "refract(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
   1459 	})
   1460 IMPLEMENT_INTRINSIC_SPIRV(refract, 0, {
   1461 	return
   1462 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1463 		.add(_glsl_ext)
   1464 		.add(spv::GLSLstd450Refract)
   1465 		.add(args[0].base)
   1466 		.add(args[1].base)
   1467 		.add(args[2].base)
   1468 		.result;
   1469 	})
   1470 
   1471 // ret faceforward(n, i, ng)
   1472 DEFINE_INTRINSIC(faceforward, 0, float, float, float, float)
   1473 DEFINE_INTRINSIC(faceforward, 0, float2, float2, float2, float2)
   1474 DEFINE_INTRINSIC(faceforward, 0, float3, float3, float3, float3)
   1475 DEFINE_INTRINSIC(faceforward, 0, float4, float4, float4, float4)
   1476 IMPLEMENT_INTRINSIC_GLSL(faceforward, 0, {
   1477 	code += "faceforward(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
   1478 	})
   1479 IMPLEMENT_INTRINSIC_HLSL(faceforward, 0, {
   1480 	code += "faceforward(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
   1481 	})
   1482 IMPLEMENT_INTRINSIC_SPIRV(faceforward, 0, {
   1483 	return
   1484 	add_instruction(spv::OpExtInst, convert_type(res_type))
   1485 		.add(_glsl_ext)
   1486 		.add(spv::GLSLstd450FaceForward)
   1487 		.add(args[0].base)
   1488 		.add(args[1].base)
   1489 		.add(args[2].base)
   1490 		.result;
   1491 	})
   1492 
   1493 // ret mul(x, y)
   1494 DEFINE_INTRINSIC(mul, 0, int2, int, int2)
   1495 DEFINE_INTRINSIC(mul, 0, int3, int, int3)
   1496 DEFINE_INTRINSIC(mul, 0, int4, int, int4)
   1497 DEFINE_INTRINSIC(mul, 0, float2, float, float2)
   1498 DEFINE_INTRINSIC(mul, 0, float3, float, float3)
   1499 DEFINE_INTRINSIC(mul, 0, float4, float, float4)
   1500 IMPLEMENT_INTRINSIC_GLSL(mul, 0, {
   1501 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1502 	})
   1503 IMPLEMENT_INTRINSIC_HLSL(mul, 0, {
   1504 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1505 	})
   1506 IMPLEMENT_INTRINSIC_SPIRV(mul, 0, {
   1507 	return
   1508 	add_instruction(spv::OpVectorTimesScalar, convert_type(res_type))
   1509 		.add(args[1].base)
   1510 		.add(args[0].base)
   1511 		.result;
   1512 	})
   1513 DEFINE_INTRINSIC(mul, 1, int2, int2, int)
   1514 DEFINE_INTRINSIC(mul, 1, int3, int3, int)
   1515 DEFINE_INTRINSIC(mul, 1, int4, int4, int)
   1516 DEFINE_INTRINSIC(mul, 1, float2, float2, float)
   1517 DEFINE_INTRINSIC(mul, 1, float3, float3, float)
   1518 DEFINE_INTRINSIC(mul, 1, float4, float4, float)
   1519 IMPLEMENT_INTRINSIC_GLSL(mul, 1, {
   1520 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1521 	})
   1522 IMPLEMENT_INTRINSIC_HLSL(mul, 1, {
   1523 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1524 	})
   1525 IMPLEMENT_INTRINSIC_SPIRV(mul, 1, {
   1526 	return
   1527 	add_instruction(spv::OpVectorTimesScalar, convert_type(res_type))
   1528 		.add(args[0].base)
   1529 		.add(args[1].base)
   1530 		.result;
   1531 	})
   1532 
   1533 DEFINE_INTRINSIC(mul, 2, int2x2, int, int2x2)
   1534 DEFINE_INTRINSIC(mul, 2, int2x3, int, int2x3)
   1535 DEFINE_INTRINSIC(mul, 2, int2x4, int, int2x4)
   1536 DEFINE_INTRINSIC(mul, 2, int3x2, int, int3x2)
   1537 DEFINE_INTRINSIC(mul, 2, int3x3, int, int3x3)
   1538 DEFINE_INTRINSIC(mul, 2, int3x4, int, int3x4)
   1539 DEFINE_INTRINSIC(mul, 2, int4x2, int, int4x2)
   1540 DEFINE_INTRINSIC(mul, 2, int4x3, int, int4x3)
   1541 DEFINE_INTRINSIC(mul, 2, int4x4, int, int4x4)
   1542 DEFINE_INTRINSIC(mul, 2, float2x2, float, float2x2)
   1543 DEFINE_INTRINSIC(mul, 2, float2x3, float, float2x3)
   1544 DEFINE_INTRINSIC(mul, 2, float2x4, float, float2x4)
   1545 DEFINE_INTRINSIC(mul, 2, float3x2, float, float3x2)
   1546 DEFINE_INTRINSIC(mul, 2, float3x3, float, float3x3)
   1547 DEFINE_INTRINSIC(mul, 2, float3x4, float, float3x4)
   1548 DEFINE_INTRINSIC(mul, 2, float4x2, float, float4x2)
   1549 DEFINE_INTRINSIC(mul, 2, float4x3, float, float4x3)
   1550 DEFINE_INTRINSIC(mul, 2, float4x4, float, float4x4)
   1551 IMPLEMENT_INTRINSIC_GLSL(mul, 2, {
   1552 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1553 	})
   1554 IMPLEMENT_INTRINSIC_HLSL(mul, 2, {
   1555 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1556 	})
   1557 IMPLEMENT_INTRINSIC_SPIRV(mul, 2, {
   1558 	return
   1559 	add_instruction(spv::OpMatrixTimesScalar, convert_type(res_type))
   1560 		.add(args[1].base)
   1561 		.add(args[0].base)
   1562 		.result;
   1563 	})
   1564 DEFINE_INTRINSIC(mul, 3, int2x2, int2x2, int)
   1565 DEFINE_INTRINSIC(mul, 3, int2x3, int2x3, int)
   1566 DEFINE_INTRINSIC(mul, 3, int2x4, int2x4, int)
   1567 DEFINE_INTRINSIC(mul, 3, int3x2, int3x2, int)
   1568 DEFINE_INTRINSIC(mul, 3, int3x3, int3x3, int)
   1569 DEFINE_INTRINSIC(mul, 3, int3x4, int3x4, int)
   1570 DEFINE_INTRINSIC(mul, 3, int4x2, int4x2, int)
   1571 DEFINE_INTRINSIC(mul, 3, int4x3, int4x3, int)
   1572 DEFINE_INTRINSIC(mul, 3, int4x4, int4x4, int)
   1573 DEFINE_INTRINSIC(mul, 3, float2x2, float2x2, float)
   1574 DEFINE_INTRINSIC(mul, 3, float2x3, float2x3, float)
   1575 DEFINE_INTRINSIC(mul, 3, float2x4, float2x4, float)
   1576 DEFINE_INTRINSIC(mul, 3, float3x2, float3x2, float)
   1577 DEFINE_INTRINSIC(mul, 3, float3x3, float3x3, float)
   1578 DEFINE_INTRINSIC(mul, 3, float3x4, float3x4, float)
   1579 DEFINE_INTRINSIC(mul, 3, float4x2, float4x2, float)
   1580 DEFINE_INTRINSIC(mul, 3, float4x3, float4x3, float)
   1581 DEFINE_INTRINSIC(mul, 3, float4x4, float4x4, float)
   1582 IMPLEMENT_INTRINSIC_GLSL(mul, 3, {
   1583 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1584 	})
   1585 IMPLEMENT_INTRINSIC_HLSL(mul, 3, {
   1586 	code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
   1587 	})
   1588 IMPLEMENT_INTRINSIC_SPIRV(mul, 3, {
   1589 	return
   1590 	add_instruction(spv::OpMatrixTimesScalar, convert_type(res_type))
   1591 		.add(args[0].base)
   1592 		.add(args[1].base)
   1593 		.result;
   1594 	})
   1595 
   1596 DEFINE_INTRINSIC(mul, 4, int2, int2, int2x2)
   1597 DEFINE_INTRINSIC(mul, 4, int3, int2, int2x3)
   1598 DEFINE_INTRINSIC(mul, 4, int4, int2, int2x4)
   1599 DEFINE_INTRINSIC(mul, 4, int2, int3, int3x2)
   1600 DEFINE_INTRINSIC(mul, 4, int3, int3, int3x3)
   1601 DEFINE_INTRINSIC(mul, 4, int4, int3, int3x4)
   1602 DEFINE_INTRINSIC(mul, 4, int2, int4, int4x2)
   1603 DEFINE_INTRINSIC(mul, 4, int3, int4, int4x3)
   1604 DEFINE_INTRINSIC(mul, 4, int4, int4, int4x4)
   1605 DEFINE_INTRINSIC(mul, 4, float2, float2, float2x2)
   1606 DEFINE_INTRINSIC(mul, 4, float3, float2, float2x3)
   1607 DEFINE_INTRINSIC(mul, 4, float4, float2, float2x4)
   1608 DEFINE_INTRINSIC(mul, 4, float2, float3, float3x2)
   1609 DEFINE_INTRINSIC(mul, 4, float3, float3, float3x3)
   1610 DEFINE_INTRINSIC(mul, 4, float4, float3, float3x4)
   1611 DEFINE_INTRINSIC(mul, 4, float2, float4, float4x2)
   1612 DEFINE_INTRINSIC(mul, 4, float3, float4, float4x3)
   1613 DEFINE_INTRINSIC(mul, 4, float4, float4, float4x4)
   1614 IMPLEMENT_INTRINSIC_GLSL(mul, 4, {
   1615 	// Flip inputs because matrices are column-wise
   1616 	code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
   1617 	})
   1618 IMPLEMENT_INTRINSIC_HLSL(mul, 4, {
   1619 	code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1620 	})
   1621 IMPLEMENT_INTRINSIC_SPIRV(mul, 4, {
   1622 	return
   1623 	add_instruction(spv::OpMatrixTimesVector, convert_type(res_type))
   1624 		.add(args[1].base) // Flip inputs because matrices are column-wise
   1625 		.add(args[0].base)
   1626 		.result;
   1627 	})
   1628 DEFINE_INTRINSIC(mul, 5, int2, int2x2, int2)
   1629 DEFINE_INTRINSIC(mul, 5, int2, int2x3, int3)
   1630 DEFINE_INTRINSIC(mul, 5, int2, int2x4, int4)
   1631 DEFINE_INTRINSIC(mul, 5, int3, int3x2, int2)
   1632 DEFINE_INTRINSIC(mul, 5, int3, int3x3, int3)
   1633 DEFINE_INTRINSIC(mul, 5, int3, int3x4, int4)
   1634 DEFINE_INTRINSIC(mul, 5, int4, int4x2, int2)
   1635 DEFINE_INTRINSIC(mul, 5, int4, int4x3, int3)
   1636 DEFINE_INTRINSIC(mul, 5, int4, int4x4, int4)
   1637 DEFINE_INTRINSIC(mul, 5, float2, float2x2, float2)
   1638 DEFINE_INTRINSIC(mul, 5, float2, float2x3, float3)
   1639 DEFINE_INTRINSIC(mul, 5, float2, float2x4, float4)
   1640 DEFINE_INTRINSIC(mul, 5, float3, float3x2, float2)
   1641 DEFINE_INTRINSIC(mul, 5, float3, float3x3, float3)
   1642 DEFINE_INTRINSIC(mul, 5, float3, float3x4, float4)
   1643 DEFINE_INTRINSIC(mul, 5, float4, float4x2, float2)
   1644 DEFINE_INTRINSIC(mul, 5, float4, float4x3, float3)
   1645 DEFINE_INTRINSIC(mul, 5, float4, float4x4, float4)
   1646 IMPLEMENT_INTRINSIC_GLSL(mul, 5, {
   1647 	// Flip inputs because matrices are column-wise
   1648 	code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
   1649 	})
   1650 IMPLEMENT_INTRINSIC_HLSL(mul, 5, {
   1651 	code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1652 	})
   1653 IMPLEMENT_INTRINSIC_SPIRV(mul, 5, {
   1654 	return
   1655 	add_instruction(spv::OpVectorTimesMatrix, convert_type(res_type))
   1656 		.add(args[1].base) // Flip inputs because matrices are column-wise
   1657 		.add(args[0].base)
   1658 		.result;
   1659 	})
   1660 
   1661 DEFINE_INTRINSIC(mul, 6, int2x2, int2x2, int2x2)
   1662 DEFINE_INTRINSIC(mul, 6, int2x3, int2x2, int2x3)
   1663 DEFINE_INTRINSIC(mul, 6, int2x4, int2x2, int2x4)
   1664 DEFINE_INTRINSIC(mul, 6, int2x2, int2x3, int3x2)
   1665 DEFINE_INTRINSIC(mul, 6, int2x3, int2x3, int3x3)
   1666 DEFINE_INTRINSIC(mul, 6, int2x4, int2x3, int3x4)
   1667 DEFINE_INTRINSIC(mul, 6, int2x2, int2x4, int4x2)
   1668 DEFINE_INTRINSIC(mul, 6, int2x3, int2x4, int4x3)
   1669 DEFINE_INTRINSIC(mul, 6, int2x4, int2x4, int4x4)
   1670 DEFINE_INTRINSIC(mul, 6, int3x2, int3x2, int2x2)
   1671 DEFINE_INTRINSIC(mul, 6, int3x3, int3x2, int2x3)
   1672 DEFINE_INTRINSIC(mul, 6, int3x4, int3x2, int2x4)
   1673 DEFINE_INTRINSIC(mul, 6, int3x2, int3x3, int3x2)
   1674 DEFINE_INTRINSIC(mul, 6, int3x3, int3x3, int3x3)
   1675 DEFINE_INTRINSIC(mul, 6, int3x4, int3x3, int3x4)
   1676 DEFINE_INTRINSIC(mul, 6, int3x2, int3x4, int4x2)
   1677 DEFINE_INTRINSIC(mul, 6, int3x3, int3x4, int4x3)
   1678 DEFINE_INTRINSIC(mul, 6, int3x4, int3x4, int4x4)
   1679 DEFINE_INTRINSIC(mul, 6, int4x2, int4x2, int2x2)
   1680 DEFINE_INTRINSIC(mul, 6, int4x3, int4x2, int2x3)
   1681 DEFINE_INTRINSIC(mul, 6, int4x4, int4x2, int2x4)
   1682 DEFINE_INTRINSIC(mul, 6, int4x2, int4x3, int3x2)
   1683 DEFINE_INTRINSIC(mul, 6, int4x3, int4x3, int3x3)
   1684 DEFINE_INTRINSIC(mul, 6, int4x4, int4x3, int3x4)
   1685 DEFINE_INTRINSIC(mul, 6, int4x2, int4x4, int4x2)
   1686 DEFINE_INTRINSIC(mul, 6, int4x3, int4x4, int4x3)
   1687 DEFINE_INTRINSIC(mul, 6, int4x4, int4x4, int4x4)
   1688 DEFINE_INTRINSIC(mul, 6, float2x2, float2x2, float2x2)
   1689 DEFINE_INTRINSIC(mul, 6, float2x3, float2x2, float2x3)
   1690 DEFINE_INTRINSIC(mul, 6, float2x4, float2x2, float2x4)
   1691 DEFINE_INTRINSIC(mul, 6, float2x2, float2x3, float3x2)
   1692 DEFINE_INTRINSIC(mul, 6, float2x3, float2x3, float3x3)
   1693 DEFINE_INTRINSIC(mul, 6, float2x4, float2x3, float3x4)
   1694 DEFINE_INTRINSIC(mul, 6, float2x2, float2x4, float4x2)
   1695 DEFINE_INTRINSIC(mul, 6, float2x3, float2x4, float4x3)
   1696 DEFINE_INTRINSIC(mul, 6, float2x4, float2x4, float4x4)
   1697 DEFINE_INTRINSIC(mul, 6, float3x2, float3x2, float2x2)
   1698 DEFINE_INTRINSIC(mul, 6, float3x3, float3x2, float2x3)
   1699 DEFINE_INTRINSIC(mul, 6, float3x4, float3x2, float2x4)
   1700 DEFINE_INTRINSIC(mul, 6, float3x2, float3x3, float3x2)
   1701 DEFINE_INTRINSIC(mul, 6, float3x3, float3x3, float3x3)
   1702 DEFINE_INTRINSIC(mul, 6, float3x4, float3x3, float3x4)
   1703 DEFINE_INTRINSIC(mul, 6, float3x2, float3x4, float4x2)
   1704 DEFINE_INTRINSIC(mul, 6, float3x3, float3x4, float4x3)
   1705 DEFINE_INTRINSIC(mul, 6, float3x4, float3x4, float4x4)
   1706 DEFINE_INTRINSIC(mul, 6, float4x2, float4x2, float2x2)
   1707 DEFINE_INTRINSIC(mul, 6, float4x3, float4x2, float2x3)
   1708 DEFINE_INTRINSIC(mul, 6, float4x4, float4x2, float2x4)
   1709 DEFINE_INTRINSIC(mul, 6, float4x2, float4x3, float3x2)
   1710 DEFINE_INTRINSIC(mul, 6, float4x3, float4x3, float3x3)
   1711 DEFINE_INTRINSIC(mul, 6, float4x4, float4x3, float3x4)
   1712 DEFINE_INTRINSIC(mul, 6, float4x2, float4x4, float4x2)
   1713 DEFINE_INTRINSIC(mul, 6, float4x3, float4x4, float4x3)
   1714 DEFINE_INTRINSIC(mul, 6, float4x4, float4x4, float4x4)
   1715 IMPLEMENT_INTRINSIC_GLSL(mul, 6, {
   1716 	// Flip inputs because matrices are column-wise
   1717 	code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
   1718 	})
   1719 IMPLEMENT_INTRINSIC_HLSL(mul, 6, {
   1720 	code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1721 	})
   1722 IMPLEMENT_INTRINSIC_SPIRV(mul, 6, {
   1723 	return
   1724 	add_instruction(spv::OpMatrixTimesMatrix, convert_type(res_type))
   1725 		.add(args[1].base) // Flip inputs because matrices are column-wise
   1726 		.add(args[0].base)
   1727 		.result;
   1728 	})
   1729 
   1730 // ret isinf(x)
   1731 DEFINE_INTRINSIC(isinf, 0, bool, float)
   1732 DEFINE_INTRINSIC(isinf, 0, bool2, float2)
   1733 DEFINE_INTRINSIC(isinf, 0, bool3, float3)
   1734 DEFINE_INTRINSIC(isinf, 0, bool4, float4)
   1735 IMPLEMENT_INTRINSIC_GLSL(isinf, 0, {
   1736 	code += "isinf(" + id_to_name(args[0].base) + ')';
   1737 	})
   1738 IMPLEMENT_INTRINSIC_HLSL(isinf, 0, {
   1739 	code += "isinf(" + id_to_name(args[0].base) + ')';
   1740 	})
   1741 IMPLEMENT_INTRINSIC_SPIRV(isinf, 0, {
   1742 	return
   1743 	add_instruction(spv::OpIsInf, convert_type(res_type))
   1744 		.add(args[0].base)
   1745 		.result;
   1746 	})
   1747 
   1748 // ret isnan(x)
   1749 DEFINE_INTRINSIC(isnan, 0, bool, float)
   1750 DEFINE_INTRINSIC(isnan, 0, bool2, float2)
   1751 DEFINE_INTRINSIC(isnan, 0, bool3, float3)
   1752 DEFINE_INTRINSIC(isnan, 0, bool4, float4)
   1753 IMPLEMENT_INTRINSIC_GLSL(isnan, 0, {
   1754 	code += "isnan(" + id_to_name(args[0].base) + ')';
   1755 	})
   1756 IMPLEMENT_INTRINSIC_HLSL(isnan, 0, {
   1757 	code += "isnan(" + id_to_name(args[0].base) + ')';
   1758 	})
   1759 IMPLEMENT_INTRINSIC_SPIRV(isnan, 0, {
   1760 	return
   1761 	add_instruction(spv::OpIsNan, convert_type(res_type))
   1762 		.add(args[0].base)
   1763 		.result;
   1764 	})
   1765 
   1766 // ret tex1D(s, coords)
   1767 // ret tex1D(s, coords, offset)
   1768 DEFINE_INTRINSIC(tex1D, 0, int, sampler1d_int, float)
   1769 DEFINE_INTRINSIC(tex1D, 0, uint, sampler1d_uint, float)
   1770 DEFINE_INTRINSIC(tex1D, 0, float, sampler1d_float, float)
   1771 DEFINE_INTRINSIC(tex1D, 0, float4, sampler1d_float4, float)
   1772 DEFINE_INTRINSIC(tex1D, 1, int, sampler1d_int, float, int)
   1773 DEFINE_INTRINSIC(tex1D, 1, uint, sampler1d_uint, float, int)
   1774 DEFINE_INTRINSIC(tex1D, 1, float, sampler1d_float, float, int)
   1775 DEFINE_INTRINSIC(tex1D, 1, float4, sampler1d_float4, float, int)
   1776 IMPLEMENT_INTRINSIC_GLSL(tex1D, 0, {
   1777 	code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1778 	if (res_type.rows == 1)
   1779 		code += ".x"; // Collapse last argument from a 4-component vector
   1780 	})
   1781 IMPLEMENT_INTRINSIC_GLSL(tex1D, 1, {
   1782 	code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1783 	if (res_type.rows == 1)
   1784 		code += ".x";
   1785 	})
   1786 IMPLEMENT_INTRINSIC_HLSL(tex1D, 0, {
   1787 	if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
   1788 		if (res_type.is_floating_point() || _shader_model >= 67)
   1789 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1790 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   1791 			code += "uint temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + "); " +
   1792 			id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0))";
   1793 	}
   1794 	else {
   1795 		code += "tex1D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1796 		if (res_type.rows == 1)
   1797 			code += ".x";
   1798 	}
   1799 	})
   1800 IMPLEMENT_INTRINSIC_HLSL(tex1D, 1, {
   1801 	if (_shader_model >= 40) {
   1802 		if (res_type.is_floating_point() || _shader_model >= 67)
   1803 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1804 		else
   1805 			code += "uint temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + "); " +
   1806 			id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0), " + id_to_name(args[2].base) + ')';
   1807 	}
   1808 	else {
   1809 		code += "tex1D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
   1810 		if (res_type.rows == 1)
   1811 			code += ".x";
   1812 	}
   1813 	})
   1814 IMPLEMENT_INTRINSIC_SPIRV(tex1D, 0, {
   1815 	type res_vector_type = res_type;
   1816 	res_vector_type.rows = 4;
   1817 
   1818 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   1819 		.add(args[0].base)
   1820 		.add(args[1].base)
   1821 		.add(spv::ImageOperandsMaskNone)
   1822 		.result;
   1823 	if (res_type.rows == 1)
   1824 		// Collapse last argument from a 4-component vector
   1825 		return
   1826 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   1827 			.add(res)
   1828 			.add(0u)
   1829 			.result;
   1830 	else
   1831 		return res;
   1832 	})
   1833 IMPLEMENT_INTRINSIC_SPIRV(tex1D, 1, {
   1834 	// Non-constant offset operand needs extended capability
   1835 	if (!args[2].is_constant)
   1836 		add_capability(spv::CapabilityImageGatherExtended);
   1837 
   1838 	type res_vector_type = res_type;
   1839 	res_vector_type.rows = 4;
   1840 
   1841 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   1842 		.add(args[0].base)
   1843 		.add(args[1].base)
   1844 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   1845 		.add(args[2].base)
   1846 		.result;
   1847 	if (res_type.rows == 1)
   1848 		return
   1849 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   1850 			.add(res)
   1851 			.add(0u)
   1852 			.result;
   1853 	else
   1854 		return res;
   1855 	})
   1856 
   1857 // ret tex2D(s, coords)
   1858 // ret tex2D(s, coords, offset)
   1859 DEFINE_INTRINSIC(tex2D, 0, int, sampler2d_int, float2)
   1860 DEFINE_INTRINSIC(tex2D, 0, uint, sampler2d_uint, float2)
   1861 DEFINE_INTRINSIC(tex2D, 0, float, sampler2d_float, float2)
   1862 DEFINE_INTRINSIC(tex2D, 0, float4, sampler2d_float4, float2)
   1863 DEFINE_INTRINSIC(tex2D, 1, int, sampler2d_int, float2, int2)
   1864 DEFINE_INTRINSIC(tex2D, 1, uint, sampler2d_uint, float2, int2)
   1865 DEFINE_INTRINSIC(tex2D, 1, float, sampler2d_float, float2, int2)
   1866 DEFINE_INTRINSIC(tex2D, 1, float4, sampler2d_float4, float2, int2)
   1867 IMPLEMENT_INTRINSIC_GLSL(tex2D, 0, {
   1868 	code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1869 	if (res_type.rows == 1)
   1870 		code += ".x"; // Collapse last argument from a 4-component vector
   1871 	})
   1872 IMPLEMENT_INTRINSIC_GLSL(tex2D, 1, {
   1873 	code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1874 	if (res_type.rows == 1)
   1875 		code += ".x";
   1876 	})
   1877 IMPLEMENT_INTRINSIC_HLSL(tex2D, 0, {
   1878 	if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
   1879 		if (res_type.is_floating_point() || _shader_model >= 67)
   1880 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1881 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   1882 			code += "uint2 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y); " +
   1883 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0))";
   1884 	}
   1885 	else {
   1886 		code += "tex2D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1887 		if (res_type.rows == 1)
   1888 			code += ".x";
   1889 	}
   1890 	})
   1891 IMPLEMENT_INTRINSIC_HLSL(tex2D, 1, {
   1892 	if (_shader_model >= 40) {
   1893 		if (res_type.is_floating_point() || _shader_model >= 67)
   1894 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1895 		else
   1896 			code += "uint2 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y); " +
   1897 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0), " + id_to_name(args[2].base) + ')';
   1898 	}
   1899 	else {
   1900 		code += "tex2D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
   1901 		if (res_type.rows == 1)
   1902 			code += ".x";
   1903 	}
   1904 	})
   1905 IMPLEMENT_INTRINSIC_SPIRV(tex2D, 0, {
   1906 	type res_vector_type = res_type;
   1907 	res_vector_type.rows = 4;
   1908 
   1909 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   1910 		.add(args[0].base)
   1911 		.add(args[1].base)
   1912 		.add(spv::ImageOperandsMaskNone)
   1913 		.result;
   1914 	if (res_type.rows == 1)
   1915 		// Collapse last argument from a 4-component vector
   1916 		return
   1917 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   1918 			.add(res)
   1919 			.add(0u)
   1920 			.result;
   1921 	else
   1922 		return res;
   1923 	})
   1924 IMPLEMENT_INTRINSIC_SPIRV(tex2D, 1, {
   1925 	// Non-constant offset operand needs extended capability
   1926 	if (!args[2].is_constant)
   1927 		add_capability(spv::CapabilityImageGatherExtended);
   1928 
   1929 	type res_vector_type = res_type;
   1930 	res_vector_type.rows = 4;
   1931 
   1932 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   1933 		.add(args[0].base)
   1934 		.add(args[1].base)
   1935 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   1936 		.add(args[2].base)
   1937 		.result;
   1938 	if (res_type.rows == 1)
   1939 		return
   1940 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   1941 			.add(res)
   1942 			.add(0u)
   1943 			.result;
   1944 	else
   1945 		return res;
   1946 	})
   1947 
   1948 // ret tex3D(s, coords)
   1949 // ret tex3D(s, coords, offset)
   1950 DEFINE_INTRINSIC(tex3D, 0, int, sampler3d_int, float3)
   1951 DEFINE_INTRINSIC(tex3D, 0, uint, sampler3d_uint, float3)
   1952 DEFINE_INTRINSIC(tex3D, 0, float, sampler3d_float, float3)
   1953 DEFINE_INTRINSIC(tex3D, 0, float4, sampler3d_float4, float3)
   1954 DEFINE_INTRINSIC(tex3D, 1, int, sampler3d_int, float3, int3)
   1955 DEFINE_INTRINSIC(tex3D, 1, uint, sampler3d_uint, float3, int3)
   1956 DEFINE_INTRINSIC(tex3D, 1, float, sampler3d_float, float3, int3)
   1957 DEFINE_INTRINSIC(tex3D, 1, float4, sampler3d_float4, float3, int3)
   1958 IMPLEMENT_INTRINSIC_GLSL(tex3D, 0, {
   1959 	code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   1960 	if (res_type.rows == 1)
   1961 		code += ".x"; // Collapse last argument from a 4-component vector
   1962 	})
   1963 IMPLEMENT_INTRINSIC_GLSL(tex3D, 1, {
   1964 	code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1965 	if (res_type.rows == 1)
   1966 		code += ".x";
   1967 	})
   1968 IMPLEMENT_INTRINSIC_HLSL(tex3D, 0, {
   1969 	if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
   1970 		if (res_type.is_floating_point() || _shader_model >= 67)
   1971 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1972 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   1973 			code += "uint3 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z); " +
   1974 			id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0))";
   1975 	}
   1976 	else {
   1977 		code += "tex3D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   1978 		if (res_type.rows == 1)
   1979 			code += ".x";
   1980 	}
   1981 	})
   1982 IMPLEMENT_INTRINSIC_HLSL(tex3D, 1, {
   1983 	if (_shader_model >= 40) {
   1984 		if (res_type.is_floating_point() || _shader_model >= 67)
   1985 			code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   1986 		else
   1987 			code += "uint3 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions(temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z); " +
   1988 			id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + " * temp" + std::to_string(res) + ", 0), " + id_to_name(args[2].base) + ')';
   1989 	}
   1990 	else {
   1991 		code += "tex3D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
   1992 		if (res_type.rows == 1)
   1993 			code += ".x";
   1994 	}
   1995 	})
   1996 IMPLEMENT_INTRINSIC_SPIRV(tex3D, 0, {
   1997 	type res_vector_type = res_type;
   1998 	res_vector_type.rows = 4;
   1999 
   2000 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   2001 		.add(args[0].base)
   2002 		.add(args[1].base)
   2003 		.add(spv::ImageOperandsMaskNone)
   2004 		.result;
   2005 	if (res_type.rows == 1)
   2006 		// Collapse last argument from a 4-component vector
   2007 		return
   2008 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2009 			.add(res)
   2010 			.add(0u)
   2011 			.result;
   2012 	else
   2013 		return res;
   2014 	})
   2015 IMPLEMENT_INTRINSIC_SPIRV(tex3D, 1, {
   2016 	// Non-constant offset operand needs extended capability
   2017 	if (!args[2].is_constant)
   2018 		add_capability(spv::CapabilityImageGatherExtended);
   2019 
   2020 	type res_vector_type = res_type;
   2021 	res_vector_type.rows = 4;
   2022 
   2023 	const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
   2024 		.add(args[0].base)
   2025 		.add(args[1].base)
   2026 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   2027 		.add(args[2].base)
   2028 		.result;
   2029 	if (res_type.rows == 1)
   2030 		return
   2031 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2032 			.add(res)
   2033 			.add(0u)
   2034 			.result;
   2035 	else
   2036 		return res;
   2037 	})
   2038 
   2039 // ret tex1Dlod(s, coords)
   2040 // ret tex1Dlod(s, coords, offset)
   2041 DEFINE_INTRINSIC(tex1Dlod, 0, int, sampler1d_int, float4)
   2042 DEFINE_INTRINSIC(tex1Dlod, 0, uint, sampler1d_uint, float4)
   2043 DEFINE_INTRINSIC(tex1Dlod, 0, float, sampler1d_float, float4)
   2044 DEFINE_INTRINSIC(tex1Dlod, 0, float4, sampler1d_float4, float4)
   2045 DEFINE_INTRINSIC(tex1Dlod, 1, int, sampler1d_int, float4, int)
   2046 DEFINE_INTRINSIC(tex1Dlod, 1, uint, sampler1d_uint, float4, int)
   2047 DEFINE_INTRINSIC(tex1Dlod, 1, float, sampler1d_float, float4, int)
   2048 DEFINE_INTRINSIC(tex1Dlod, 1, float4, sampler1d_float4, float4, int)
   2049 IMPLEMENT_INTRINSIC_GLSL(tex1Dlod, 0, {
   2050 	code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w)";
   2051 	if (res_type.rows == 1)
   2052 		code += ".x"; // Collapse last argument from a 4-component vector
   2053 	})
   2054 IMPLEMENT_INTRINSIC_GLSL(tex1Dlod, 1, {
   2055 	code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2056 	if (res_type.rows == 1)
   2057 		code += ".x";
   2058 	})
   2059 IMPLEMENT_INTRINSIC_HLSL(tex1Dlod, 0, {
   2060 	if (_shader_model >= 40) {
   2061 		if (res_type.is_floating_point() || _shader_model >= 67)
   2062 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w)";
   2063 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   2064 			code += "uint2 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y); " +
   2065 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ".x * temp" + std::to_string(res) + ".x, (int)" + id_to_name(args[1].base) + ".w))";
   2066 	}
   2067 	else {
   2068 		code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   2069 		if (res_type.rows == 1)
   2070 			code += ".x";
   2071 	}
   2072 	})
   2073 IMPLEMENT_INTRINSIC_HLSL(tex1Dlod, 1, {
   2074 	if (_shader_model >= 40) {
   2075 		if (res_type.is_floating_point() || _shader_model >= 67)
   2076 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2077 		else
   2078 			code += "uint2 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y); " +
   2079 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ".x * temp" + std::to_string(res) + ".x, (int)" + id_to_name(args[1].base) + ".w))" + id_to_name(args[2].base) + ')';
   2080 	}
   2081 	else {
   2082 		code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0, 0, 0))";
   2083 		if (res_type.rows == 1)
   2084 			code += ".x";
   2085 	}
   2086 	})
   2087 IMPLEMENT_INTRINSIC_SPIRV(tex1Dlod, 0, {
   2088 	const spv::Id x = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2089 		.add(args[1].base)
   2090 		.add(0) // .x
   2091 		.result;
   2092 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2093 		.add(args[1].base)
   2094 		.add(3) // .w
   2095 		.result;
   2096 
   2097 	type res_vector_type = res_type;
   2098 	res_vector_type.rows = 4;
   2099 
   2100 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2101 		.add(args[0].base)
   2102 		.add(x)
   2103 		.add(spv::ImageOperandsLodMask)
   2104 		.add(lod)
   2105 		.result;
   2106 	if (res_type.rows == 1)
   2107 		// Collapse last argument from a 4-component vector
   2108 		return
   2109 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2110 			.add(res)
   2111 			.add(0u)
   2112 			.result;
   2113 	else
   2114 		return res;
   2115 	})
   2116 IMPLEMENT_INTRINSIC_SPIRV(tex1Dlod, 1, {
   2117 	if (!args[2].is_constant)
   2118 		add_capability(spv::CapabilityImageGatherExtended);
   2119 
   2120 	const spv::Id x = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2121 		.add(args[1].base)
   2122 		.add(0) // .x
   2123 		.result;
   2124 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2125 		.add(args[1].base)
   2126 		.add(3) // .w
   2127 		.result;
   2128 
   2129 	type res_vector_type = res_type;
   2130 	res_vector_type.rows = 4;
   2131 
   2132 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2133 		.add(args[0].base)
   2134 		.add(x)
   2135 		.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
   2136 		.add(lod)
   2137 		.add(args[2].base)
   2138 		.result;
   2139 	if (res_type.rows == 1)
   2140 		return
   2141 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2142 			.add(res)
   2143 			.add(0u)
   2144 			.result;
   2145 	else
   2146 		return res;
   2147 	})
   2148 
   2149 // ret tex2Dlod(s, coords)
   2150 // ret tex2Dlod(s, coords, offset)
   2151 DEFINE_INTRINSIC(tex2Dlod, 0, int, sampler2d_int, float4)
   2152 DEFINE_INTRINSIC(tex2Dlod, 0, uint, sampler2d_uint, float4)
   2153 DEFINE_INTRINSIC(tex2Dlod, 0, float, sampler2d_float, float4)
   2154 DEFINE_INTRINSIC(tex2Dlod, 0, float4, sampler2d_float4, float4)
   2155 DEFINE_INTRINSIC(tex2Dlod, 1, int, sampler2d_int, float4, int2)
   2156 DEFINE_INTRINSIC(tex2Dlod, 1, uint, sampler2d_uint, float4, int2)
   2157 DEFINE_INTRINSIC(tex2Dlod, 1, float, sampler2d_float, float4, int2)
   2158 DEFINE_INTRINSIC(tex2Dlod, 1, float4, sampler2d_float4, float4, int2)
   2159 IMPLEMENT_INTRINSIC_GLSL(tex2Dlod, 0, {
   2160 	code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w)";
   2161 	if (res_type.rows == 1)
   2162 		code += ".x"; // Collapse last argument from a 4-component vector
   2163 	})
   2164 IMPLEMENT_INTRINSIC_GLSL(tex2Dlod, 1, {
   2165 	code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2166 	if (res_type.rows == 1)
   2167 		code += ".x";
   2168 	})
   2169 IMPLEMENT_INTRINSIC_HLSL(tex2Dlod, 0, {
   2170 	if (_shader_model >= 40) {
   2171 		if (res_type.is_floating_point() || _shader_model >= 67)
   2172 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w)";
   2173 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   2174 			code += "uint3 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z); " +
   2175 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ".xy * temp" + std::to_string(res) + ".xy, (int)" + id_to_name(args[1].base) + ".w))";
   2176 	}
   2177 	else {
   2178 		code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   2179 		if (res_type.rows == 1)
   2180 			code += ".x";
   2181 	}
   2182 	})
   2183 IMPLEMENT_INTRINSIC_HLSL(tex2Dlod, 1, {
   2184 	if (_shader_model >= 40) {
   2185 		if (res_type.is_floating_point() || _shader_model >= 67)
   2186 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2187 		else
   2188 			code += "uint3 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z); " +
   2189 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ".xy * temp" + std::to_string(res) + ".xy, (int)" + id_to_name(args[1].base) + ".w))" + id_to_name(args[2].base) + ')';
   2190 	}
   2191 	else {
   2192 		code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0, 0))";
   2193 		if (res_type.rows == 1)
   2194 			code += ".x";
   2195 	}
   2196 	})
   2197 IMPLEMENT_INTRINSIC_SPIRV(tex2Dlod, 0, {
   2198 	const spv::Id xy = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 2, 1 }))
   2199 		.add(args[1].base)
   2200 		.add(args[1].base)
   2201 		.add(0) // .x
   2202 		.add(1) // .y
   2203 		.result;
   2204 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2205 		.add(args[1].base)
   2206 		.add(3) // .w
   2207 		.result;
   2208 
   2209 	type res_vector_type = res_type;
   2210 	res_vector_type.rows = 4;
   2211 
   2212 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2213 		.add(args[0].base)
   2214 		.add(xy)
   2215 		.add(spv::ImageOperandsLodMask)
   2216 		.add(lod)
   2217 		.result;
   2218 	if (res_type.rows == 1)
   2219 		// Collapse last argument from a 4-component vector
   2220 		return
   2221 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2222 			.add(res)
   2223 			.add(0u)
   2224 			.result;
   2225 	else
   2226 		return res;
   2227 	})
   2228 IMPLEMENT_INTRINSIC_SPIRV(tex2Dlod, 1, {
   2229 	if (!args[2].is_constant)
   2230 		add_capability(spv::CapabilityImageGatherExtended);
   2231 
   2232 	const spv::Id xy = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 2, 1 }))
   2233 		.add(args[1].base)
   2234 		.add(args[1].base)
   2235 		.add(0) // .x
   2236 		.add(1) // .y
   2237 		.result;
   2238 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2239 		.add(args[1].base)
   2240 		.add(3) // .w
   2241 		.result;
   2242 
   2243 	type res_vector_type = res_type;
   2244 	res_vector_type.rows = 4;
   2245 
   2246 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2247 		.add(args[0].base)
   2248 		.add(xy)
   2249 		.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
   2250 		.add(lod)
   2251 		.add(args[2].base)
   2252 		.result;
   2253 	if (res_type.rows == 1)
   2254 		return
   2255 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2256 			.add(res)
   2257 			.add(0u)
   2258 			.result;
   2259 	else
   2260 		return res;
   2261 	})
   2262 
   2263 // ret tex3Dlod(s, coords)
   2264 // ret tex3Dlod(s, coords, offset)
   2265 DEFINE_INTRINSIC(tex3Dlod, 0, int, sampler3d_int, float4)
   2266 DEFINE_INTRINSIC(tex3Dlod, 0, uint, sampler3d_uint, float4)
   2267 DEFINE_INTRINSIC(tex3Dlod, 0, float, sampler3d_float, float4)
   2268 DEFINE_INTRINSIC(tex3Dlod, 0, float4, sampler3d_float4, float4)
   2269 DEFINE_INTRINSIC(tex3Dlod, 1, int, sampler3d_int, float4, int2)
   2270 DEFINE_INTRINSIC(tex3Dlod, 1, uint, sampler3d_uint, float4, int2)
   2271 DEFINE_INTRINSIC(tex3Dlod, 1, float, sampler3d_float, float4, int2)
   2272 DEFINE_INTRINSIC(tex3Dlod, 1, float4, sampler3d_float4, float4, int2)
   2273 IMPLEMENT_INTRINSIC_GLSL(tex3Dlod, 0, {
   2274 	code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w)";
   2275 	if (res_type.rows == 1)
   2276 		code += ".x"; // Collapse last argument from a 4-component vector
   2277 	})
   2278 IMPLEMENT_INTRINSIC_GLSL(tex3Dlod, 1, {
   2279 	code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2280 	if (res_type.rows == 1)
   2281 		code += ".x";
   2282 	})
   2283 IMPLEMENT_INTRINSIC_HLSL(tex3Dlod, 0, {
   2284 	if (_shader_model >= 40) {
   2285 		if (res_type.is_floating_point() || _shader_model >= 67)
   2286 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w)";
   2287 		else // Integer sampling is not supported until SM6.7, so emulate with a texture fetch
   2288 			code += "uint4 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z, temp" + std::to_string(res) + ".w); " +
   2289 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ".xyz * temp" + std::to_string(res) + ".xyz, (int)" + id_to_name(args[1].base) + ".w))";
   2290 	}
   2291 	else {
   2292 		code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   2293 		if (res_type.rows == 1)
   2294 			code += ".x";
   2295 	}
   2296 	})
   2297 IMPLEMENT_INTRINSIC_HLSL(tex3Dlod, 1, {
   2298 	if (_shader_model >= 40) {
   2299 		if (res_type.is_floating_point() || _shader_model >= 67)
   2300 			code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
   2301 		else
   2302 			code += "uint4 temp" + std::to_string(res) + "; " + id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, temp" + std::to_string(res) + ".x, temp" + std::to_string(res) + ".y, temp" + std::to_string(res) + ".z, temp" + std::to_string(res) + ".w); " +
   2303 				id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ".xyz * temp" + std::to_string(res) + ".xyz, (int)" + id_to_name(args[1].base) + ".w))" + id_to_name(args[2].base) + ')';
   2304 	}
   2305 	else {
   2306 		code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0))";
   2307 		if (res_type.rows == 1)
   2308 			code += ".x";
   2309 	}
   2310 	})
   2311 IMPLEMENT_INTRINSIC_SPIRV(tex3Dlod, 0, {
   2312 	const spv::Id xyz = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 3, 1 }))
   2313 		.add(args[1].base)
   2314 		.add(args[1].base)
   2315 		.add(0) // .x
   2316 		.add(1) // .y
   2317 		.add(2) // .z
   2318 		.result;
   2319 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2320 		.add(args[1].base)
   2321 		.add(3) // .w
   2322 		.result;
   2323 
   2324 	type res_vector_type = res_type;
   2325 	res_vector_type.rows = 4;
   2326 
   2327 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2328 		.add(args[0].base)
   2329 		.add(xyz)
   2330 		.add(spv::ImageOperandsLodMask)
   2331 		.add(lod)
   2332 		.result;
   2333 	if (res_type.rows == 1)
   2334 		// Collapse last argument from a 4-component vector
   2335 		return
   2336 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2337 			.add(res)
   2338 			.add(0u)
   2339 			.result;
   2340 	else
   2341 		return res;
   2342 	})
   2343 IMPLEMENT_INTRINSIC_SPIRV(tex3Dlod, 1, {
   2344 	if (!args[2].is_constant)
   2345 		add_capability(spv::CapabilityImageGatherExtended);
   2346 
   2347 	const spv::Id xyz = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 3, 1 }))
   2348 		.add(args[1].base)
   2349 		.add(args[1].base)
   2350 		.add(0) // .x
   2351 		.add(1) // .y
   2352 		.add(2) // .z
   2353 		.result;
   2354 	const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
   2355 		.add(args[1].base)
   2356 		.add(3) // .w
   2357 		.result;
   2358 
   2359 	type res_vector_type = res_type;
   2360 	res_vector_type.rows = 4;
   2361 
   2362 	const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
   2363 		.add(args[0].base)
   2364 		.add(xyz)
   2365 		.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
   2366 		.add(lod)
   2367 		.add(args[2].base)
   2368 		.result;
   2369 	if (res_type.rows == 1)
   2370 		return
   2371 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2372 			.add(res)
   2373 			.add(0u)
   2374 			.result;
   2375 	else
   2376 		return res;
   2377 	})
   2378 
   2379 // ret tex1Dfetch(s, coords)
   2380 // ret tex1Dfetch(s, coords, lod)
   2381 DEFINE_INTRINSIC(tex1Dfetch, 0, int, sampler1d_int, int)
   2382 DEFINE_INTRINSIC(tex1Dfetch, 0, uint, sampler1d_uint, int)
   2383 DEFINE_INTRINSIC(tex1Dfetch, 0, float, sampler1d_float, int)
   2384 DEFINE_INTRINSIC(tex1Dfetch, 0, float4, sampler1d_float4, int)
   2385 DEFINE_INTRINSIC(tex1Dfetch, 1, int, sampler1d_int, int, int)
   2386 DEFINE_INTRINSIC(tex1Dfetch, 1, uint, sampler1d_uint, int, int)
   2387 DEFINE_INTRINSIC(tex1Dfetch, 1, float, sampler1d_float, int, int)
   2388 DEFINE_INTRINSIC(tex1Dfetch, 1, float4, sampler1d_float4, int, int)
   2389 DEFINE_INTRINSIC(tex1Dfetch, 2, int, storage1d_int, int)
   2390 DEFINE_INTRINSIC(tex1Dfetch, 2, uint, storage1d_uint, int)
   2391 DEFINE_INTRINSIC(tex1Dfetch, 2, float, storage1d_float, int)
   2392 DEFINE_INTRINSIC(tex1Dfetch, 2, float4, storage1d_float4, int)
   2393 IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 0, {
   2394 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
   2395 	if (res_type.rows == 1)
   2396 		code += ".x"; // Collapse last argument from a 4-component vector
   2397 	})
   2398 IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 1, {
   2399 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   2400 	if (res_type.rows == 1)
   2401 		code += ".x";
   2402 	})
   2403 IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 2, {
   2404 	code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ")";
   2405 	if (res_type.rows == 1)
   2406 		code += ".x";
   2407 	})
   2408 IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 0, {
   2409 	if (_shader_model >= 40)
   2410 		code += id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ", 0))";
   2411 	else {
   2412 		// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
   2413 		// Also add a half-pixel offset to align texels with pixels
   2414 		//   (coords + 0.5) / size
   2415 		code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2416 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0, 0, 0))";
   2417 		if (res_type.rows == 1)
   2418 			code += ".x";
   2419 	}
   2420 	})
   2421 IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 1, {
   2422 	if (_shader_model >= 40)
   2423 		code += id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
   2424 	else {
   2425 		code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2426 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), 0, 0, " +
   2427 			id_to_name(args[2].base) + "))";
   2428 		if (res_type.rows == 1)
   2429 			code += ".x";
   2430 	}
   2431 	})
   2432 IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 2, {
   2433 	code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
   2434 	})
   2435 IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 0, {
   2436 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2437 		.add(args[0].base)
   2438 		.result;
   2439 
   2440 	type res_vector_type = res_type;
   2441 	res_vector_type.rows = 4;
   2442 
   2443 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2444 		.add(image)
   2445 		.add(args[1].base)
   2446 		.result;
   2447 	if (res_type.rows == 1)
   2448 		// Collapse last argument from a 4-component vector
   2449 		return
   2450 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2451 			.add(res)
   2452 			.add(0u)
   2453 			.result;
   2454 	else
   2455 		return res;
   2456 	})
   2457 IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 1, {
   2458 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2459 		.add(args[0].base)
   2460 		.result;
   2461 
   2462 	type res_vector_type = res_type;
   2463 	res_vector_type.rows = 4;
   2464 
   2465 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2466 		.add(image)
   2467 		.add(args[1].base)
   2468 		.add(spv::ImageOperandsLodMask)
   2469 		.add(args[2].base)
   2470 		.result;
   2471 	if (res_type.rows == 1)
   2472 		return
   2473 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2474 			.add(res)
   2475 			.add(0u)
   2476 			.result;
   2477 	else
   2478 		return res;
   2479 	})
   2480 IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 2, {
   2481 	type res_vector_type = res_type;
   2482 	res_vector_type.rows = 4;
   2483 
   2484 	const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
   2485 		.add(args[0].base)
   2486 		.add(args[1].base)
   2487 		.result;
   2488 	if (res_type.rows == 1)
   2489 		return
   2490 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2491 			.add(res)
   2492 			.add(0u)
   2493 			.result;
   2494 	else
   2495 		return res;
   2496 	})
   2497 
   2498 // ret tex2Dfetch(s, coords)
   2499 // ret tex2Dfetch(s, coords, lod)
   2500 DEFINE_INTRINSIC(tex2Dfetch, 0, int, sampler2d_int, int2)
   2501 DEFINE_INTRINSIC(tex2Dfetch, 0, uint, sampler2d_uint, int2)
   2502 DEFINE_INTRINSIC(tex2Dfetch, 0, float, sampler2d_float, int2)
   2503 DEFINE_INTRINSIC(tex2Dfetch, 0, float4, sampler2d_float4, int2)
   2504 DEFINE_INTRINSIC(tex2Dfetch, 1, int, sampler2d_int, int2, int)
   2505 DEFINE_INTRINSIC(tex2Dfetch, 1, uint, sampler2d_uint, int2, int)
   2506 DEFINE_INTRINSIC(tex2Dfetch, 1, float, sampler2d_float, int2, int)
   2507 DEFINE_INTRINSIC(tex2Dfetch, 1, float4, sampler2d_float4, int2, int)
   2508 DEFINE_INTRINSIC(tex2Dfetch, 2, int, storage2d_int, int2)
   2509 DEFINE_INTRINSIC(tex2Dfetch, 2, uint, storage2d_uint, int2)
   2510 DEFINE_INTRINSIC(tex2Dfetch, 2, float, storage2d_float, int2)
   2511 DEFINE_INTRINSIC(tex2Dfetch, 2, float4, storage2d_float4, int2)
   2512 IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 0, {
   2513 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
   2514 	if (res_type.rows == 1)
   2515 		code += ".x"; // Collapse last argument from a 4-component vector
   2516 	})
   2517 IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 1, {
   2518 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   2519 	if (res_type.rows == 1)
   2520 		code += ".x";
   2521 	})
   2522 IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 2, {
   2523 	code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   2524 	if (res_type.rows == 1)
   2525 		code += ".x";
   2526 	})
   2527 IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 0, {
   2528 	if (_shader_model >= 40)
   2529 		code += id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ", 0))";
   2530 	else {
   2531 		// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
   2532 		// Also add a half-pixel offset to align texels with pixels
   2533 		//   (coords + 0.5) / size
   2534 		code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2535 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0, 0))";
   2536 		if (res_type.rows == 1)
   2537 			code += ".x";
   2538 	}
   2539 	})
   2540 IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 1, {
   2541 	if (_shader_model >= 40)
   2542 		code += id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
   2543 	else {
   2544 		code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2545 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), 0, " +
   2546 			id_to_name(args[2].base) + "))";
   2547 		if (res_type.rows == 1)
   2548 			code += ".x";
   2549 	}
   2550 	})
   2551 IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 2, {
   2552 	if (_shader_model >= 50)
   2553 		code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
   2554 	else
   2555 		code += "{}";
   2556 	})
   2557 IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 0, {
   2558 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2559 		.add(args[0].base)
   2560 		.result;
   2561 
   2562 	type res_vector_type = res_type;
   2563 	res_vector_type.rows = 4;
   2564 
   2565 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2566 		.add(image)
   2567 		.add(args[1].base)
   2568 		.result;
   2569 	if (res_type.rows == 1)
   2570 		// Collapse last argument from a 4-component vector
   2571 		return
   2572 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2573 			.add(res)
   2574 			.add(0u)
   2575 			.result;
   2576 	else
   2577 		return res;
   2578 	})
   2579 IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 1, {
   2580 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2581 		.add(args[0].base)
   2582 		.result;
   2583 
   2584 	type res_vector_type = res_type;
   2585 	res_vector_type.rows = 4;
   2586 
   2587 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2588 		.add(image)
   2589 		.add(args[1].base)
   2590 		.add(spv::ImageOperandsLodMask)
   2591 		.add(args[2].base)
   2592 		.result;
   2593 	if (res_type.rows == 1)
   2594 		return
   2595 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2596 			.add(res)
   2597 			.add(0u)
   2598 			.result;
   2599 	else
   2600 		return res;
   2601 	})
   2602 IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 2, {
   2603 	type res_vector_type = res_type;
   2604 	res_vector_type.rows = 4;
   2605 
   2606 	const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
   2607 		.add(args[0].base)
   2608 		.add(args[1].base)
   2609 		.result;
   2610 	if (res_type.rows == 1)
   2611 		return
   2612 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2613 			.add(res)
   2614 			.add(0u)
   2615 			.result;
   2616 	else
   2617 		return res;
   2618 	})
   2619 
   2620 // ret tex3Dfetch(s, coords)
   2621 // ret tex3Dfetch(s, coords, lod)
   2622 DEFINE_INTRINSIC(tex3Dfetch, 0, int, sampler3d_int, int3)
   2623 DEFINE_INTRINSIC(tex3Dfetch, 0, uint, sampler3d_uint, int3)
   2624 DEFINE_INTRINSIC(tex3Dfetch, 0, float, sampler3d_float, int3)
   2625 DEFINE_INTRINSIC(tex3Dfetch, 0, float4, sampler3d_float4, int3)
   2626 DEFINE_INTRINSIC(tex3Dfetch, 1, int, sampler3d_int, int3, int)
   2627 DEFINE_INTRINSIC(tex3Dfetch, 1, uint, sampler3d_uint, int3, int)
   2628 DEFINE_INTRINSIC(tex3Dfetch, 1, float, sampler3d_float, int3, int)
   2629 DEFINE_INTRINSIC(tex3Dfetch, 1, float4, sampler3d_float4, int3, int)
   2630 DEFINE_INTRINSIC(tex3Dfetch, 2, int, storage3d_int, int3)
   2631 DEFINE_INTRINSIC(tex3Dfetch, 2, uint, storage3d_uint, int3)
   2632 DEFINE_INTRINSIC(tex3Dfetch, 2, float, storage3d_float, int3)
   2633 DEFINE_INTRINSIC(tex3Dfetch, 2, float4, storage3d_float4, int3)
   2634 IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 0, {
   2635 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
   2636 	if (res_type.rows == 1)
   2637 		code += ".x"; // Collapse last argument from a 4-component vector
   2638 	})
   2639 IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 1, {
   2640 	code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   2641 	if (res_type.rows == 1)
   2642 		code += ".x";
   2643 	})
   2644 IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 2, {
   2645 	code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ")";
   2646 	if (res_type.rows == 1)
   2647 		code += ".x";
   2648 	})
   2649 IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 0, {
   2650 	if (_shader_model >= 40)
   2651 		code += id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ", 0))";
   2652 	else {
   2653 		// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
   2654 		// Also add a half-pixel offset to align texels with pixels
   2655 		//   (coords + 0.5) / size
   2656 		code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2657 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0))";
   2658 		if (res_type.rows == 1)
   2659 			code += ".x";
   2660 	}
   2661 	})
   2662 IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 1, {
   2663 	if (_shader_model >= 40)
   2664 		code += id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
   2665 	else {
   2666 		code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, float4((" +
   2667 			id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), " +
   2668 			id_to_name(args[2].base) + "))";
   2669 		if (res_type.rows == 1)
   2670 			code += ".x";
   2671 	}
   2672 	})
   2673 IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 2, {
   2674 	code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
   2675 	})
   2676 IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 0, {
   2677 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2678 		.add(args[0].base)
   2679 		.result;
   2680 
   2681 	type res_vector_type = res_type;
   2682 	res_vector_type.rows = 4;
   2683 
   2684 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2685 		.add(image)
   2686 		.add(args[1].base)
   2687 		.result;
   2688 	if (res_type.rows == 1)
   2689 		// Collapse last argument from a 4-component vector
   2690 		return
   2691 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2692 			.add(res)
   2693 			.add(0u)
   2694 			.result;
   2695 	else
   2696 		return res;
   2697 	})
   2698 IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 1, {
   2699 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   2700 		.add(args[0].base)
   2701 		.result;
   2702 
   2703 	type res_vector_type = res_type;
   2704 	res_vector_type.rows = 4;
   2705 
   2706 	const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
   2707 		.add(image)
   2708 		.add(args[1].base)
   2709 		.add(spv::ImageOperandsLodMask)
   2710 		.add(args[2].base)
   2711 		.result;
   2712 	if (res_type.rows == 1)
   2713 		return
   2714 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2715 			.add(res)
   2716 			.add(0u)
   2717 			.result;
   2718 	else
   2719 		return res;
   2720 	})
   2721 IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 2, {
   2722 	type res_vector_type = res_type;
   2723 	res_vector_type.rows = 4;
   2724 
   2725 	const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
   2726 		.add(args[0].base)
   2727 		.add(args[1].base)
   2728 		.result;
   2729 	if (res_type.rows == 1)
   2730 		return
   2731 		add_instruction(spv::OpCompositeExtract, convert_type(res_type))
   2732 			.add(res)
   2733 			.add(0u)
   2734 			.result;
   2735 	else
   2736 		return res;
   2737 	})
   2738 
   2739 // ret tex2DgatherR(s, coords)
   2740 // ret tex2DgatherR(s, coords, offset)
   2741 // ret tex2DgatherR(s, coords, offset0, offset1, offset2, offset3)
   2742 DEFINE_INTRINSIC(tex2DgatherR, 0, float4, sampler2d_float4, float2)
   2743 DEFINE_INTRINSIC(tex2DgatherR, 1, float4, sampler2d_float4, float2, int2)
   2744 DEFINE_INTRINSIC(tex2DgatherR, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
   2745 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 0, {
   2746 	code += "textureGather(" + id_to_name(args[0].base) + ", " +
   2747 		id_to_name(args[1].base) + ", 0)";
   2748 	})
   2749 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 1, {
   2750 	code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
   2751 		id_to_name(args[1].base) + ", " +
   2752 		id_to_name(args[2].base) + ", 0)";
   2753 	})
   2754 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 2, {
   2755 	code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
   2756 		"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 0)";
   2757 	})
   2758 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 0, {
   2759 	const std::string s = id_to_name(args[0].base);
   2760 	if (_shader_model >= 50)
   2761 		code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ')';
   2762 	else if (_shader_model >= 40) // Emulate texture gather intrinsic by sampling each location separately (SM41 has 'Gather', but that only works on single component texture formats)
   2763 		code += "float4(" +
   2764 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 1))." + 'r' + ", " +
   2765 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 1))." + 'r' + ", " +
   2766 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 0))." + 'r' + ", " +
   2767 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 0))." + 'r' + ')';
   2768 	else
   2769 		code += "float4("
   2770 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2771 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2772 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2773 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0))." + 'r' + ')';
   2774 	})
   2775 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 1, {
   2776 	const std::string s = id_to_name(args[0].base);
   2777 	if (_shader_model >= 50)
   2778 		code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   2779 	else if (_shader_model >= 40)
   2780 		code += "float4(" +
   2781 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 1))." + 'r' + ", " +
   2782 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 1))." + 'r' + ", " +
   2783 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 0))." + 'r' + ", " +
   2784 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 0))." + 'r' + ')';
   2785 	else
   2786 		code += "float4("
   2787 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2788 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2789 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2790 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0))." + 'r' + ')';
   2791 	})
   2792 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 2, {
   2793 	const std::string s = id_to_name(args[0].base);
   2794 	if (_shader_model >= 50)
   2795 		code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ", " +
   2796 			id_to_name(args[2].base) + " - int2(0, 1), " +
   2797 			id_to_name(args[3].base) + " - int2(1, 1), " +
   2798 			id_to_name(args[4].base) + " - int2(1, 0), " +
   2799 			id_to_name(args[5].base) + ')';
   2800 	else if (_shader_model >= 40)
   2801 		code += "float4(" +
   2802 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + ")." + 'r' + ", " +
   2803 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[3].base) + ")." + 'r' + ", " +
   2804 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[4].base) + ")." + 'r' + ", " +
   2805 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[5].base) + ")." + 'r' + ')';
   2806 	else
   2807 		code += "float4("
   2808 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2809 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2810 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0))." + 'r' + ", "
   2811 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0))." + 'r' + ')';
   2812 	})
   2813 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 0, {
   2814 	const spv::Id comp = emit_constant(0u);
   2815 
   2816 	return
   2817 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2818 		.add(args[0].base)
   2819 		.add(args[1].base)
   2820 		.add(comp)
   2821 		.add(spv::ImageOperandsMaskNone)
   2822 		.result;
   2823 	})
   2824 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 1, {
   2825 	if (!args[2].is_constant)
   2826 		add_capability(spv::CapabilityImageGatherExtended);
   2827 
   2828 	const spv::Id comp = emit_constant(0u);
   2829 
   2830 	return
   2831 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2832 		.add(args[0].base)
   2833 		.add(args[1].base)
   2834 		.add(comp)
   2835 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   2836 		.add(args[2].base)
   2837 		.result;
   2838 	})
   2839 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 2, {
   2840 	add_capability(spv::CapabilityImageGatherExtended);
   2841 
   2842 	const spv::Id comp = emit_constant(0u);
   2843 	const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
   2844 		.add(args[2].base)
   2845 		.add(args[3].base)
   2846 		.add(args[4].base)
   2847 		.add(args[5].base)
   2848 		.result;
   2849 
   2850 	return
   2851 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2852 		.add(args[0].base)
   2853 		.add(args[1].base)
   2854 		.add(comp)
   2855 		.add(spv::ImageOperandsConstOffsetsMask)
   2856 		.add(offsets)
   2857 		.result;
   2858 	})
   2859 // ret tex2DgatherG(s, coords)
   2860 // ret tex2DgatherG(s, coords, offset)
   2861 // ret tex2DgatherG(s, coords, offset0, offset1, offset2, offset3)
   2862 DEFINE_INTRINSIC(tex2DgatherG, 0, float4, sampler2d_float4, float2)
   2863 DEFINE_INTRINSIC(tex2DgatherG, 1, float4, sampler2d_float4, float2, int2)
   2864 DEFINE_INTRINSIC(tex2DgatherG, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
   2865 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 0, {
   2866 	code += "textureGather(" + id_to_name(args[0].base) + ", " +
   2867 		id_to_name(args[1].base) + ", 1)";
   2868 	})
   2869 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 1, {
   2870 	code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
   2871 		id_to_name(args[1].base) + ", " +
   2872 		id_to_name(args[2].base) + ", 1)";
   2873 	})
   2874 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 2, {
   2875 	code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
   2876 		"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 1)";
   2877 	})
   2878 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 0, {
   2879 	const std::string s = id_to_name(args[0].base);
   2880 	if (_shader_model >= 50)
   2881 		code += s + ".t.GatherGreen(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
   2882 	else if (_shader_model >= 40)
   2883 		code += "float4(" +
   2884 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 1))." + 'g' + ", " +
   2885 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 1))." + 'g' + ", " +
   2886 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 0))." + 'g' + ", " +
   2887 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 0))." + 'g' + ')';
   2888 	else
   2889 		code += "float4("
   2890 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2891 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2892 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2893 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0))." + 'g' + ')';
   2894 	})
   2895 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 1, {
   2896 	const std::string s = id_to_name(args[0].base);
   2897 	if (_shader_model >= 50)
   2898 		code += s + ".t.GatherGreen(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   2899 	else if (_shader_model >= 40)
   2900 		code += "float4(" +
   2901 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 1))." + 'g' + ", " +
   2902 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 1))." + 'g' + ", " +
   2903 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 0))." + 'g' + ", " +
   2904 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 0))." + 'g' + ')';
   2905 	else
   2906 		code += "float4("
   2907 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2908 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2909 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2910 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0))." + 'g' + ')';
   2911 	})
   2912 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 2, {
   2913 	const std::string s = id_to_name(args[0].base);
   2914 	if (_shader_model >= 50)
   2915 		code += s + ".t.GatherGreen(" + s + ".s, " + id_to_name(args[1].base) + ", " +
   2916 			id_to_name(args[2].base) + " - int2(0, 1), " +
   2917 			id_to_name(args[3].base) + " - int2(1, 1), " +
   2918 			id_to_name(args[4].base) + " - int2(1, 0), " +
   2919 			id_to_name(args[5].base) + ')';
   2920 	else if (_shader_model >= 40)
   2921 		code += "float4(" +
   2922 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + ")." + 'g' + ", " +
   2923 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[3].base) + ")." + 'g' + ", " +
   2924 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[4].base) + ")." + 'g' + ", " +
   2925 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[5].base) + ")." + 'g' + ')';
   2926 	else
   2927 		code += "float4("
   2928 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2929 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2930 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0))." + 'g' + ", "
   2931 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0))." + 'g' + ')';
   2932 	})
   2933 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 0, {
   2934 	const spv::Id comp = emit_constant(1u);
   2935 
   2936 	return
   2937 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2938 		.add(args[0].base)
   2939 		.add(args[1].base)
   2940 		.add(comp)
   2941 		.add(spv::ImageOperandsMaskNone)
   2942 		.result;
   2943 	})
   2944 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 1, {
   2945 	if (!args[2].is_constant)
   2946 		add_capability(spv::CapabilityImageGatherExtended);
   2947 
   2948 	const spv::Id comp = emit_constant(1u);
   2949 
   2950 	return
   2951 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2952 		.add(args[0].base)
   2953 		.add(args[1].base)
   2954 		.add(comp)
   2955 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   2956 		.add(args[2].base)
   2957 		.result;
   2958 	})
   2959 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 2, {
   2960 	add_capability(spv::CapabilityImageGatherExtended);
   2961 
   2962 	const spv::Id comp = emit_constant(1u);
   2963 	const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
   2964 		.add(args[2].base)
   2965 		.add(args[3].base)
   2966 		.add(args[4].base)
   2967 		.add(args[5].base)
   2968 		.result;
   2969 
   2970 	return
   2971 	add_instruction(spv::OpImageGather, convert_type(res_type))
   2972 		.add(args[0].base)
   2973 		.add(args[1].base)
   2974 		.add(comp)
   2975 		.add(spv::ImageOperandsConstOffsetsMask)
   2976 		.add(offsets)
   2977 		.result;
   2978 	})
   2979 // ret tex2DgatherB(s, coords)
   2980 // ret tex2DgatherB(s, coords, offset)
   2981 // ret tex2DgatherB(s, coords, offset0, offset1, offset2, offset3)
   2982 DEFINE_INTRINSIC(tex2DgatherB, 0, float4, sampler2d_float4, float2)
   2983 DEFINE_INTRINSIC(tex2DgatherB, 1, float4, sampler2d_float4, float2, int2)
   2984 DEFINE_INTRINSIC(tex2DgatherB, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
   2985 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 0, {
   2986 	code += "textureGather(" + id_to_name(args[0].base) + ", " +
   2987 		id_to_name(args[1].base) + ", 2)";
   2988 	})
   2989 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 1, {
   2990 	code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
   2991 		id_to_name(args[1].base) + ", " +
   2992 		id_to_name(args[2].base) + ", 2)";
   2993 	})
   2994 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 2, {
   2995 	code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
   2996 		"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 2)";
   2997 	})
   2998 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 0, {
   2999 	const std::string s = id_to_name(args[0].base);
   3000 	if (_shader_model >= 50)
   3001 		code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ')';
   3002 	else if (_shader_model >= 40)
   3003 		code += "float4(" +
   3004 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 1))." + 'b' + ", " +
   3005 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 1))." + 'b' + ", " +
   3006 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 0))." + 'b' + ", " +
   3007 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 0))." + 'b' + ')';
   3008 	else
   3009 		code += "float4("
   3010 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3011 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3012 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3013 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0))." + 'b' + ')';
   3014 	})
   3015 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 1, {
   3016 	const std::string s = id_to_name(args[0].base);
   3017 	if (_shader_model >= 50)
   3018 		code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3019 	else if (_shader_model >= 40)
   3020 		code += "float4(" +
   3021 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 1))." + 'b' + ", " +
   3022 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 1))." + 'b' + ", " +
   3023 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 0))." + 'b' + ", " +
   3024 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 0))." + 'b' + ')';
   3025 	else
   3026 		code += "float4("
   3027 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3028 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3029 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3030 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0))." + 'b' + ')';
   3031 	})
   3032 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 2, {
   3033 	const std::string s = id_to_name(args[0].base);
   3034 	if (_shader_model >= 50)
   3035 		code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ", " +
   3036 			id_to_name(args[2].base) + " - int2(0, 1), " +
   3037 			id_to_name(args[3].base) + " - int2(1, 1), " +
   3038 			id_to_name(args[4].base) + " - int2(1, 0), " +
   3039 			id_to_name(args[5].base) + ')';
   3040 	else if (_shader_model >= 40)
   3041 		code += "float4(" +
   3042 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + ")." + 'b' + ", " +
   3043 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[3].base) + ")." + 'b' + ", " +
   3044 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[4].base) + ")." + 'b' + ", " +
   3045 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[5].base) + ")." + 'b' + ')';
   3046 	else
   3047 		code += "float4("
   3048 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3049 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3050 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0))." + 'b' + ", "
   3051 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0))." + 'b' + ')';
   3052 	})
   3053 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 0, {
   3054 	const spv::Id comp = emit_constant(2u);
   3055 
   3056 	return
   3057 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3058 		.add(args[0].base)
   3059 		.add(args[1].base)
   3060 		.add(comp)
   3061 		.add(spv::ImageOperandsMaskNone)
   3062 		.result;
   3063 	})
   3064 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 1, {
   3065 	if (!args[2].is_constant)
   3066 		add_capability(spv::CapabilityImageGatherExtended);
   3067 
   3068 	const spv::Id comp = emit_constant(2u);
   3069 
   3070 	return
   3071 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3072 		.add(args[0].base)
   3073 		.add(args[1].base)
   3074 		.add(comp)
   3075 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   3076 		.add(args[2].base)
   3077 		.result;
   3078 	})
   3079 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 2, {
   3080 	add_capability(spv::CapabilityImageGatherExtended);
   3081 
   3082 	const spv::Id comp = emit_constant(2u);
   3083 	const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
   3084 		.add(args[2].base)
   3085 		.add(args[3].base)
   3086 		.add(args[4].base)
   3087 		.add(args[5].base)
   3088 		.result;
   3089 
   3090 	return
   3091 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3092 		.add(args[0].base)
   3093 		.add(args[1].base)
   3094 		.add(comp)
   3095 		.add(spv::ImageOperandsConstOffsetsMask)
   3096 		.add(offsets)
   3097 		.result;
   3098 	})
   3099 // ret tex2DgatherA(s, coords)
   3100 // ret tex2DgatherA(s, coords, offset)
   3101 // ret tex2DgatherA(s, coords, offset0, offset1, offset2, offset3)
   3102 DEFINE_INTRINSIC(tex2DgatherA, 0, float4, sampler2d_float4, float2)
   3103 DEFINE_INTRINSIC(tex2DgatherA, 1, float4, sampler2d_float4, float2, int2)
   3104 DEFINE_INTRINSIC(tex2DgatherA, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
   3105 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 0, {
   3106 	code += "textureGather(" + id_to_name(args[0].base) + ", " +
   3107 		id_to_name(args[1].base) + ", 3)";
   3108 	})
   3109 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 1, {
   3110 	code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
   3111 		id_to_name(args[1].base) + ", " +
   3112 		id_to_name(args[2].base) + ", 3)";
   3113 	})
   3114 IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 2, {
   3115 	code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
   3116 		"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 3)";
   3117 	})
   3118 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 0, {
   3119 	const std::string s = id_to_name(args[0].base);
   3120 	if (_shader_model >= 50)
   3121 		code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ')';
   3122 	else if (_shader_model >= 40)
   3123 		code += "float4(" +
   3124 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 1))." + 'a' + ", " +
   3125 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 1))." + 'a' + ", " +
   3126 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(1, 0))." + 'a' + ", " +
   3127 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, int2(0, 0))." + 'a' + ')';
   3128 	else
   3129 		code += "float4("
   3130 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3131 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3132 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3133 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0))." + 'a' + ')';
   3134 	})
   3135 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 1, {
   3136 	const std::string s = id_to_name(args[0].base);
   3137 	if (_shader_model >= 50)
   3138 		code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3139 	else if (_shader_model >= 40)
   3140 		code += "float4(" +
   3141 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 1))." + 'a' + ", " +
   3142 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 1))." + 'a' + ", " +
   3143 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(1, 0))." + 'a' + ", " +
   3144 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + " + int2(0, 0))." + 'a' + ')';
   3145 	else
   3146 		code += "float4("
   3147 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3148 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3149 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3150 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0))." + 'a' + ')';
   3151 	})
   3152 IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 2, {
   3153 	const std::string s = id_to_name(args[0].base);
   3154 	if (_shader_model >= 50)
   3155 		code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ", " +
   3156 			id_to_name(args[2].base) + " - int2(0, 1), " +
   3157 			id_to_name(args[3].base) + " - int2(1, 1), " +
   3158 			id_to_name(args[4].base) + " - int2(1, 0), " +
   3159 			id_to_name(args[5].base) + ')';
   3160 	else if (_shader_model >= 40)
   3161 		code += "float4(" +
   3162 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[2].base) + ")." + 'a' + ", " +
   3163 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[3].base) + ")." + 'a' + ", " +
   3164 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[4].base) + ")." + 'a' + ", " +
   3165 			s + ".t.SampleLevel(" + s + ".s, " + id_to_name(args[1].base) + ", 0, " + id_to_name(args[5].base) + ")." + 'a' + ')';
   3166 	else
   3167 		code += "float4("
   3168 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3169 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3170 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0))." + 'a' + ", "
   3171 			"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0))." + 'a' + ')';
   3172 	})
   3173 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 0, {
   3174 	const spv::Id comp = emit_constant(3u);
   3175 
   3176 	return
   3177 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3178 		.add(args[0].base)
   3179 		.add(args[1].base)
   3180 		.add(comp)
   3181 		.add(spv::ImageOperandsMaskNone)
   3182 		.result;
   3183 	})
   3184 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 1, {
   3185 	if (!args[2].is_constant)
   3186 		add_capability(spv::CapabilityImageGatherExtended);
   3187 
   3188 	const spv::Id comp = emit_constant(3u);
   3189 
   3190 	return
   3191 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3192 		.add(args[0].base)
   3193 		.add(args[1].base)
   3194 		.add(comp)
   3195 		.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
   3196 		.add(args[2].base)
   3197 		.result;
   3198 	})
   3199 IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 2, {
   3200 	add_capability(spv::CapabilityImageGatherExtended);
   3201 
   3202 	const spv::Id comp = emit_constant(3u);
   3203 	const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
   3204 		.add(args[2].base)
   3205 		.add(args[3].base)
   3206 		.add(args[4].base)
   3207 		.add(args[5].base)
   3208 		.result;
   3209 
   3210 	return
   3211 	add_instruction(spv::OpImageGather, convert_type(res_type))
   3212 		.add(args[0].base)
   3213 		.add(args[1].base)
   3214 		.add(comp)
   3215 		.add(spv::ImageOperandsConstOffsetsMask)
   3216 		.add(offsets)
   3217 		.result;
   3218 	})
   3219 
   3220 // tex1Dstore(s, coords, value)
   3221 DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_int, int, int)
   3222 DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_uint, int, uint)
   3223 DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_float, int, float)
   3224 DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_float4, int, float4)
   3225 IMPLEMENT_INTRINSIC_GLSL(tex1Dstore, 0, {
   3226 	code += "imageStore(" + id_to_name(args[0].base) + ", " +
   3227 		id_to_name(args[1].base) + ", " +
   3228 		id_to_name(args[2].base);
   3229 	if (args[2].type.rows == 1)
   3230 		code += ".xxxx"; // Expand last argument to a 4-component vector
   3231 	code += ')';
   3232 	})
   3233 IMPLEMENT_INTRINSIC_HLSL(tex1Dstore, 0, {
   3234 	if (_shader_model >= 50) {
   3235 		code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
   3236 	}
   3237 	})
   3238 IMPLEMENT_INTRINSIC_SPIRV(tex1Dstore, 0, {
   3239 	spv::Id data = args[2].base;
   3240 	if (args[2].type.rows == 1)
   3241 	{
   3242 		// Expand last argument to a 4-component vector
   3243 		auto comp_type = args[2].type;
   3244 		comp_type.rows = 4;
   3245 
   3246 		data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
   3247 			.add(data)
   3248 			.add(data)
   3249 			.add(data)
   3250 			.add(data)
   3251 			.result;
   3252 	}
   3253 
   3254 	add_instruction_without_result(spv::OpImageWrite)
   3255 		.add(args[0].base)
   3256 		.add(args[1].base)
   3257 		.add(data);
   3258 	return 0;
   3259 	})
   3260 
   3261 // tex2Dstore(s, coords, value)
   3262 DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_int, int2, int)
   3263 DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_uint, int2, uint)
   3264 DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_float, int2, float)
   3265 DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_float4, int2, float4)
   3266 IMPLEMENT_INTRINSIC_GLSL(tex2Dstore, 0, {
   3267 	code += "imageStore(" + id_to_name(args[0].base) + ", " +
   3268 		id_to_name(args[1].base) + ", " +
   3269 		id_to_name(args[2].base);
   3270 	if (args[2].type.rows == 1)
   3271 		code += ".xxxx"; // Expand last argument to a 4-component vector
   3272 	code += ')';
   3273 	})
   3274 IMPLEMENT_INTRINSIC_HLSL(tex2Dstore, 0, {
   3275 	if (_shader_model >= 50)
   3276 		code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
   3277 	})
   3278 IMPLEMENT_INTRINSIC_SPIRV(tex2Dstore, 0, {
   3279 	spv::Id data = args[2].base;
   3280 	if (args[2].type.rows == 1)
   3281 	{
   3282 		// Expand last argument to a 4-component vector
   3283 		auto comp_type = args[2].type;
   3284 		comp_type.rows = 4;
   3285 
   3286 		data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
   3287 			.add(data)
   3288 			.add(data)
   3289 			.add(data)
   3290 			.add(data)
   3291 			.result;
   3292 	}
   3293 
   3294 	add_instruction_without_result(spv::OpImageWrite)
   3295 		.add(args[0].base)
   3296 		.add(args[1].base)
   3297 		.add(data);
   3298 	return 0;
   3299 	})
   3300 
   3301 // tex3Dstore(s, coords, value)
   3302 DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_int, int3, int)
   3303 DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_uint, int3, uint)
   3304 DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_float, int3, float)
   3305 DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_float4, int3, float4)
   3306 IMPLEMENT_INTRINSIC_GLSL(tex3Dstore, 0, {
   3307 	code += "imageStore(" + id_to_name(args[0].base) + ", " +
   3308 		id_to_name(args[1].base) + ", " +
   3309 		id_to_name(args[2].base);
   3310 	if (args[2].type.rows == 1)
   3311 		code += ".xxxx"; // Expand last argument to a 4-component vector
   3312 	code += ')';
   3313 	})
   3314 IMPLEMENT_INTRINSIC_HLSL(tex3Dstore, 0, {
   3315 	code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
   3316 	})
   3317 IMPLEMENT_INTRINSIC_SPIRV(tex3Dstore, 0, {
   3318 	spv::Id data = args[2].base;
   3319 	if (args[2].type.rows == 1)
   3320 	{
   3321 		// Expand last argument to a 4-component vector
   3322 		auto comp_type = args[2].type;
   3323 		comp_type.rows = 4;
   3324 
   3325 		data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
   3326 			.add(data)
   3327 			.add(data)
   3328 			.add(data)
   3329 			.add(data)
   3330 			.result;
   3331 	}
   3332 
   3333 	add_instruction_without_result(spv::OpImageWrite)
   3334 		.add(args[0].base)
   3335 		.add(args[1].base)
   3336 		.add(data);
   3337 	return 0;
   3338 	})
   3339 
   3340 // ret tex1Dsize(s)
   3341 // ret tex1Dsize(s, lod)
   3342 DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_int)
   3343 DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_uint)
   3344 DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_float)
   3345 DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_float4)
   3346 DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_int, int)
   3347 DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_uint, int)
   3348 DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_float, int)
   3349 DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_float4, int)
   3350 DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_int)
   3351 DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_uint)
   3352 DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_float)
   3353 DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_float4)
   3354 IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 0, {
   3355 	code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
   3356 	})
   3357 IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 1, {
   3358 	code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3359 	})
   3360 IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 2, {
   3361 	code += "imageSize(" + id_to_name(args[0].base) + ')';
   3362 	})
   3363 IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 0, {
   3364 	if (_shader_model >= 40)
   3365 		code += id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ')';
   3366 	else
   3367 		code += "int(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
   3368 	})
   3369 IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 1, {
   3370 	if (_shader_model >= 40)
   3371 		code += "uint temp" + std::to_string(res) + "; " + // Don't need the number of levels out value, so route that to a dummy variable
   3372 			id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ", temp" + std::to_string(res) + ')';
   3373 	else
   3374 		code += "int(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
   3375 	})
   3376 IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 2, {
   3377 	if (_shader_model >= 50)
   3378 		code += id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ')';
   3379 	else
   3380 		code += "0"; // Only supported on SM5+
   3381 	})
   3382 IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 0, {
   3383 	add_capability(spv::CapabilityImageQuery);
   3384 
   3385 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3386 		.add(args[0].base)
   3387 		.result;
   3388 	const spv::Id level = emit_constant(0u);
   3389 
   3390 	return
   3391 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3392 		.add(image)
   3393 		.add(level)
   3394 		.result;
   3395 	})
   3396 IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 1, {
   3397 	add_capability(spv::CapabilityImageQuery);
   3398 
   3399 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3400 		.add(args[0].base)
   3401 		.result;
   3402 
   3403 	return
   3404 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3405 		.add(image)
   3406 		.add(args[1].base)
   3407 		.result;
   3408 	})
   3409 IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 2, {
   3410 	add_capability(spv::CapabilityImageQuery);
   3411 
   3412 	return
   3413 	add_instruction(spv::OpImageQuerySize, convert_type(res_type))
   3414 		.add(args[0].base)
   3415 		.result;
   3416 	})
   3417 
   3418 // ret tex2Dsize(s)
   3419 // ret tex2Dsize(s, lod)
   3420 DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_int)
   3421 DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_uint)
   3422 DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_float)
   3423 DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_float4)
   3424 DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_int, int)
   3425 DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_uint, int)
   3426 DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_float, int)
   3427 DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_float4, int)
   3428 DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_int)
   3429 DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_uint)
   3430 DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_float)
   3431 DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_float4)
   3432 IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 0, {
   3433 	code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
   3434 	})
   3435 IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 1, {
   3436 	code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3437 	})
   3438 IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 2, {
   3439 	code += "imageSize(" + id_to_name(args[0].base) + ')';
   3440 	})
   3441 IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 0, {
   3442 	if (_shader_model >= 40)
   3443 		code += id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y)";
   3444 	else
   3445 		code += "int2(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
   3446 	})
   3447 IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 1, {
   3448 	if (_shader_model >= 40)
   3449 		code += "uint temp" + std::to_string(res) + "; " + // Don't need the number of levels out value, so route that to a dummy variable
   3450 			id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ".x, " + id_to_name(res) + ".y, temp" + std::to_string(res) + ')';
   3451 	else
   3452 		code += "int2(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
   3453 	})
   3454 IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 2, {
   3455 	if (_shader_model >= 50)
   3456 		code += id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y)";
   3457 	else
   3458 		code += "int2(0, 0)"; // Only supported on SM5+
   3459 	})
   3460 IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 0, {
   3461 	add_capability(spv::CapabilityImageQuery);
   3462 
   3463 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3464 		.add(args[0].base)
   3465 		.result;
   3466 	const spv::Id level = emit_constant(0u);
   3467 
   3468 	return
   3469 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3470 		.add(image)
   3471 		.add(level)
   3472 		.result;
   3473 	})
   3474 IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 1, {
   3475 	add_capability(spv::CapabilityImageQuery);
   3476 
   3477 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3478 		.add(args[0].base)
   3479 		.result;
   3480 
   3481 	return
   3482 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3483 		.add(image)
   3484 		.add(args[1].base)
   3485 		.result;
   3486 	})
   3487 IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 2, {
   3488 	add_capability(spv::CapabilityImageQuery);
   3489 
   3490 	return
   3491 	add_instruction(spv::OpImageQuerySize, convert_type(res_type))
   3492 		.add(args[0].base)
   3493 		.result;
   3494 	})
   3495 
   3496 // ret tex3Dsize(s)
   3497 // ret tex3Dsize(s, lod)
   3498 DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_int)
   3499 DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_uint)
   3500 DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_float)
   3501 DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_float4)
   3502 DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_int, int)
   3503 DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_uint, int)
   3504 DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_float, int)
   3505 DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_float4, int)
   3506 DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_int)
   3507 DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_uint)
   3508 DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_float)
   3509 DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_float4)
   3510 IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 0, {
   3511 	code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
   3512 	})
   3513 IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 1, {
   3514 	code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3515 	})
   3516 IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 2, {
   3517 	code += "imageSize(" + id_to_name(args[0].base) + ')';
   3518 	})
   3519 IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 0, {
   3520 	if (_shader_model >= 40)
   3521 		code += id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z)";
   3522 	else
   3523 		code += "int3(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
   3524 	})
   3525 IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 1, {
   3526 	if (_shader_model >= 40)
   3527 		code += "uint temp" + std::to_string(res) + "; " + // Don't need the number of levels out value, so route that to a dummy variable
   3528 			id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z, temp" + std::to_string(res) + ')';
   3529 	else
   3530 		code += "int3(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
   3531 	})
   3532 IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 2, {
   3533 	if (_shader_model >= 50)
   3534 		code += id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z)";
   3535 	else
   3536 		code += "int3(0, 0, 0)"; // Only supported on SM5+
   3537 	})
   3538 IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 0, {
   3539 	add_capability(spv::CapabilityImageQuery);
   3540 
   3541 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3542 		.add(args[0].base)
   3543 		.result;
   3544 	const spv::Id level = emit_constant(0u);
   3545 
   3546 	return
   3547 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3548 		.add(image)
   3549 		.add(level)
   3550 		.result;
   3551 	})
   3552 IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 1, {
   3553 	add_capability(spv::CapabilityImageQuery);
   3554 
   3555 	const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
   3556 		.add(args[0].base)
   3557 		.result;
   3558 
   3559 	return
   3560 	add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
   3561 		.add(image)
   3562 		.add(args[1].base)
   3563 		.result;
   3564 	})
   3565 IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 2, {
   3566 	add_capability(spv::CapabilityImageQuery);
   3567 
   3568 	return
   3569 	add_instruction(spv::OpImageQuerySize, convert_type(res_type))
   3570 		.add(args[0].base)
   3571 		.result;
   3572 	})
   3573 
   3574 // barrier()
   3575 DEFINE_INTRINSIC(barrier, 0, void)
   3576 IMPLEMENT_INTRINSIC_GLSL(barrier, 0, {
   3577 	code += "barrier()";
   3578 	})
   3579 IMPLEMENT_INTRINSIC_HLSL(barrier, 0, {
   3580 	if (_shader_model >= 50)
   3581 		code += "GroupMemoryBarrierWithGroupSync()";
   3582 	})
   3583 IMPLEMENT_INTRINSIC_SPIRV(barrier, 0, {
   3584 	const spv::Id mem_scope = emit_constant(spv::ScopeWorkgroup);
   3585 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
   3586 
   3587 	add_instruction_without_result(spv::OpControlBarrier)
   3588 		.add(mem_scope) // Execution scope
   3589 		.add(mem_scope)
   3590 		.add(mem_semantics);
   3591 	return 0;
   3592 	})
   3593 
   3594 // memoryBarrier()
   3595 DEFINE_INTRINSIC(memoryBarrier, 0, void)
   3596 IMPLEMENT_INTRINSIC_GLSL(memoryBarrier, 0, {
   3597 	code += "memoryBarrier()";
   3598 	})
   3599 IMPLEMENT_INTRINSIC_HLSL(memoryBarrier, 0, {
   3600 	if (_shader_model >= 50)
   3601 		code += "AllMemoryBarrier()";
   3602 	})
   3603 IMPLEMENT_INTRINSIC_SPIRV(memoryBarrier, 0, {
   3604 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3605 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsImageMemoryMask | spv::MemorySemanticsUniformMemoryMask | spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
   3606 
   3607 	add_instruction_without_result(spv::OpMemoryBarrier)
   3608 		.add(mem_scope)
   3609 		.add(mem_semantics);
   3610 	return 0;
   3611 	})
   3612 // groupMemoryBarrier()
   3613 DEFINE_INTRINSIC(groupMemoryBarrier, 0, void)
   3614 IMPLEMENT_INTRINSIC_GLSL(groupMemoryBarrier, 0, {
   3615 	code += "groupMemoryBarrier()";
   3616 	})
   3617 IMPLEMENT_INTRINSIC_HLSL(groupMemoryBarrier, 0, {
   3618 	if (_shader_model >= 50)
   3619 		code += "GroupMemoryBarrier()";
   3620 	})
   3621 IMPLEMENT_INTRINSIC_SPIRV(groupMemoryBarrier, 0, {
   3622 	const spv::Id mem_scope = emit_constant(spv::ScopeWorkgroup);
   3623 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
   3624 
   3625 	add_instruction_without_result(spv::OpMemoryBarrier)
   3626 		.add(mem_scope)
   3627 		.add(mem_semantics);
   3628 	return 0;
   3629 	})
   3630 
   3631 // ret atomicAdd(inout mem, data)
   3632 DEFINE_INTRINSIC(atomicAdd, 0, int, inout_int, int)
   3633 DEFINE_INTRINSIC(atomicAdd, 0, uint, inout_uint, uint)
   3634 IMPLEMENT_INTRINSIC_GLSL(atomicAdd, 0, {
   3635 	code += "atomicAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3636 	})
   3637 IMPLEMENT_INTRINSIC_HLSL(atomicAdd, 0, {
   3638 	if (_shader_model >= 50)
   3639 		code += "InterlockedAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3640 	else
   3641 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " += " + id_to_name(args[1].base);
   3642 	})
   3643 IMPLEMENT_INTRINSIC_SPIRV(atomicAdd, 0, {
   3644 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3645 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3646 
   3647 	return
   3648 	add_instruction(spv::OpAtomicIAdd, convert_type(res_type))
   3649 		.add(args[0].base)
   3650 		.add(mem_scope)
   3651 		.add(mem_semantics)
   3652 		.add(args[1].base)
   3653 		.result;
   3654 	})
   3655 // ret atomicAdd(s, coords, data)
   3656 DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage1d_int, int, int)
   3657 DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage2d_int, int2, int)
   3658 DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage3d_int, int3, int)
   3659 DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage1d_uint, int, uint)
   3660 DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage2d_uint, int2, uint)
   3661 DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage3d_uint, int3, uint)
   3662 IMPLEMENT_INTRINSIC_GLSL(atomicAdd, 1, {
   3663 	code += "imageAtomicAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3664 	})
   3665 IMPLEMENT_INTRINSIC_HLSL(atomicAdd, 1, {
   3666 	if (_shader_model >= 50)
   3667 		code += "InterlockedAdd(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3668 	})
   3669 IMPLEMENT_INTRINSIC_SPIRV(atomicAdd, 1, {
   3670 	const spv::Id ms_sample = emit_constant(0u);
   3671 
   3672 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3673 		.add(args[0].base)
   3674 		.add(args[1].base)
   3675 		.add(ms_sample)
   3676 		.result;
   3677 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3678 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3679 
   3680 	return
   3681 	add_instruction(spv::OpAtomicIAdd, convert_type(res_type))
   3682 		.add(texel)
   3683 		.add(mem_scope)
   3684 		.add(mem_semantics)
   3685 		.add(args[2].base)
   3686 		.result;
   3687 	})
   3688 
   3689 // ret atomicAnd(inout mem, data)
   3690 DEFINE_INTRINSIC(atomicAnd, 0, int, inout_int, int)
   3691 DEFINE_INTRINSIC(atomicAnd, 0, uint, inout_uint, uint)
   3692 IMPLEMENT_INTRINSIC_GLSL(atomicAnd, 0, {
   3693 	code += "atomicAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3694 	})
   3695 IMPLEMENT_INTRINSIC_HLSL(atomicAnd, 0, {
   3696 	if (_shader_model >= 50)
   3697 		code += "InterlockedAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3698 	else
   3699 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " &= " + id_to_name(args[1].base);
   3700 	})
   3701 IMPLEMENT_INTRINSIC_SPIRV(atomicAnd, 0, {
   3702 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3703 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3704 
   3705 	return
   3706 	add_instruction(spv::OpAtomicAnd, convert_type(res_type))
   3707 		.add(args[0].base)
   3708 		.add(mem_scope)
   3709 		.add(mem_semantics)
   3710 		.add(args[1].base)
   3711 		.result;
   3712 	})
   3713 // ret atomicAnd(s, coords, data)
   3714 DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage1d_int, int, int)
   3715 DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage2d_int, int2, int)
   3716 DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage3d_int, int3, int)
   3717 DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage1d_uint, int, uint)
   3718 DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage2d_uint, int2, uint)
   3719 DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage3d_uint, int3, uint)
   3720 IMPLEMENT_INTRINSIC_GLSL(atomicAnd, 1, {
   3721 	code += "imageAtomicAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3722 	})
   3723 IMPLEMENT_INTRINSIC_HLSL(atomicAnd, 1, {
   3724 	if (_shader_model >= 50)
   3725 		code += "InterlockedAnd(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3726 	})
   3727 IMPLEMENT_INTRINSIC_SPIRV(atomicAnd, 1, {
   3728 	const spv::Id ms_sample = emit_constant(0u);
   3729 
   3730 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3731 		.add(args[0].base)
   3732 		.add(args[1].base)
   3733 		.add(ms_sample)
   3734 		.result;
   3735 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3736 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3737 
   3738 	return
   3739 	add_instruction(spv::OpAtomicAnd, convert_type(res_type))
   3740 		.add(texel)
   3741 		.add(mem_scope)
   3742 		.add(mem_semantics)
   3743 		.add(args[2].base)
   3744 		.result;
   3745 	})
   3746 
   3747 // ret atomicOr(inout mem, data)
   3748 DEFINE_INTRINSIC(atomicOr, 0, int, inout_int, int)
   3749 DEFINE_INTRINSIC(atomicOr, 0, uint, inout_uint, uint)
   3750 IMPLEMENT_INTRINSIC_GLSL(atomicOr, 0, {
   3751 	code += "atomicOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3752 	})
   3753 IMPLEMENT_INTRINSIC_HLSL(atomicOr, 0, {
   3754 	if (_shader_model >= 50)
   3755 		code += "InterlockedOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3756 	else
   3757 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " |= " + id_to_name(args[1].base);
   3758 	})
   3759 IMPLEMENT_INTRINSIC_SPIRV(atomicOr, 0, {
   3760 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3761 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3762 
   3763 	return
   3764 	add_instruction(spv::OpAtomicOr, convert_type(res_type))
   3765 		.add(args[0].base)
   3766 		.add(mem_scope)
   3767 		.add(mem_semantics)
   3768 		.add(args[1].base)
   3769 		.result;
   3770 	})
   3771 // ret atomicOr(s, coords, data)
   3772 DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage1d_int, int, int)
   3773 DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage2d_int, int2, int)
   3774 DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage3d_int, int3, int)
   3775 DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage1d_uint, int, uint)
   3776 DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage2d_uint, int2, uint)
   3777 DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage3d_uint, int3, uint)
   3778 IMPLEMENT_INTRINSIC_GLSL(atomicOr, 1, {
   3779 	code += "imageAtomicOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3780 	})
   3781 IMPLEMENT_INTRINSIC_HLSL(atomicOr, 1, {
   3782 	if (_shader_model >= 50)
   3783 		code += "InterlockedOr(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3784 	})
   3785 IMPLEMENT_INTRINSIC_SPIRV(atomicOr, 1, {
   3786 	const spv::Id ms_sample = emit_constant(0u);
   3787 
   3788 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3789 		.add(args[0].base)
   3790 		.add(args[1].base)
   3791 		.add(ms_sample)
   3792 		.result;
   3793 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3794 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3795 
   3796 	return
   3797 	add_instruction(spv::OpAtomicOr, convert_type(res_type))
   3798 		.add(texel)
   3799 		.add(mem_scope)
   3800 		.add(mem_semantics)
   3801 		.add(args[2].base)
   3802 		.result;
   3803 	})
   3804 
   3805 // ret atomicXor(inout mem, data)
   3806 DEFINE_INTRINSIC(atomicXor, 0, int, inout_int, int)
   3807 DEFINE_INTRINSIC(atomicXor, 0, uint, inout_uint, uint)
   3808 IMPLEMENT_INTRINSIC_GLSL(atomicXor, 0, {
   3809 	code += "atomicXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3810 	})
   3811 IMPLEMENT_INTRINSIC_HLSL(atomicXor, 0, {
   3812 	if (_shader_model >= 50)
   3813 		code += "InterlockedXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3814 	else
   3815 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " ^= " + id_to_name(args[1].base);
   3816 	})
   3817 IMPLEMENT_INTRINSIC_SPIRV(atomicXor, 0, {
   3818 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3819 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3820 
   3821 	return
   3822 	add_instruction(spv::OpAtomicXor, convert_type(res_type))
   3823 		.add(args[0].base)
   3824 		.add(mem_scope)
   3825 		.add(mem_semantics)
   3826 		.add(args[1].base)
   3827 		.result;
   3828 	})
   3829 // ret atomicXor(s, coords, data)
   3830 DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage1d_int, int, int)
   3831 DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage2d_int, int2, int)
   3832 DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage3d_int, int3, int)
   3833 DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage1d_uint, int, uint)
   3834 DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage2d_uint, int2, uint)
   3835 DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage3d_uint, int3, uint)
   3836 IMPLEMENT_INTRINSIC_GLSL(atomicXor, 1, {
   3837 	code += "imageAtomicXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3838 	})
   3839 IMPLEMENT_INTRINSIC_HLSL(atomicXor, 1, {
   3840 	if (_shader_model >= 50)
   3841 		code += "InterlockedXor(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3842 	})
   3843 IMPLEMENT_INTRINSIC_SPIRV(atomicXor, 1, {
   3844 	const spv::Id ms_sample = emit_constant(0u);
   3845 
   3846 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3847 		.add(args[0].base)
   3848 		.add(args[1].base)
   3849 		.add(ms_sample)
   3850 		.result;
   3851 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3852 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3853 
   3854 	return
   3855 	add_instruction(spv::OpAtomicXor, convert_type(res_type))
   3856 		.add(texel)
   3857 		.add(mem_scope)
   3858 		.add(mem_semantics)
   3859 		.add(args[2].base)
   3860 		.result;
   3861 	})
   3862 
   3863 // ret atomicMin(inout mem, data)
   3864 DEFINE_INTRINSIC(atomicMin, 0, int, inout_int, int)
   3865 DEFINE_INTRINSIC(atomicMin, 1, uint, inout_uint, uint)
   3866 IMPLEMENT_INTRINSIC_GLSL(atomicMin, 0, {
   3867 	code += "atomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3868 	})
   3869 IMPLEMENT_INTRINSIC_GLSL(atomicMin, 1, {
   3870 	code += "atomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3871 	})
   3872 IMPLEMENT_INTRINSIC_HLSL(atomicMin, 0, {
   3873 	if (_shader_model >= 50)
   3874 		code += "InterlockedMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3875 	else
   3876 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3877 	})
   3878 IMPLEMENT_INTRINSIC_HLSL(atomicMin, 1, {
   3879 	if (_shader_model >= 50)
   3880 		code += "InterlockedMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3881 	else
   3882 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3883 	})
   3884 IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 0, {
   3885 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3886 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3887 
   3888 	return
   3889 	add_instruction(spv::OpAtomicSMin, convert_type(res_type))
   3890 		.add(args[0].base)
   3891 		.add(mem_scope)
   3892 		.add(mem_semantics)
   3893 		.add(args[1].base)
   3894 		.result;
   3895 	})
   3896 IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 1, {
   3897 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3898 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3899 
   3900 	return
   3901 	add_instruction(spv::OpAtomicUMin, convert_type(res_type))
   3902 		.add(args[0].base)
   3903 		.add(mem_scope)
   3904 		.add(mem_semantics)
   3905 		.add(args[1].base)
   3906 		.result;
   3907 	})
   3908 // ret atomicMin(s, coords, data)
   3909 DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage1d_int, int, int)
   3910 DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage2d_int, int2, int)
   3911 DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage3d_int, int3, int)
   3912 DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage1d_uint, int, uint)
   3913 DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage2d_uint, int2, uint)
   3914 DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage3d_uint, int3, uint)
   3915 IMPLEMENT_INTRINSIC_GLSL(atomicMin, 2, {
   3916 	code += "imageAtomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3917 	})
   3918 IMPLEMENT_INTRINSIC_GLSL(atomicMin, 3, {
   3919 	code += "imageAtomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   3920 	})
   3921 IMPLEMENT_INTRINSIC_HLSL(atomicMin, 2, {
   3922 	if (_shader_model >= 50)
   3923 		code += "InterlockedMin(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3924 	})
   3925 IMPLEMENT_INTRINSIC_HLSL(atomicMin, 3, {
   3926 	if (_shader_model >= 50)
   3927 		code += "InterlockedMin(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   3928 	})
   3929 IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 2, {
   3930 	const spv::Id ms_sample = emit_constant(0u);
   3931 
   3932 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3933 		.add(args[0].base)
   3934 		.add(args[1].base)
   3935 		.add(ms_sample)
   3936 		.result;
   3937 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3938 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3939 
   3940 	return
   3941 	add_instruction(spv::OpAtomicSMin, convert_type(res_type))
   3942 		.add(texel)
   3943 		.add(mem_scope)
   3944 		.add(mem_semantics)
   3945 		.add(args[2].base)
   3946 		.result;
   3947 	})
   3948 IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 3, {
   3949 	const spv::Id ms_sample = emit_constant(0u);
   3950 
   3951 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   3952 		.add(args[0].base)
   3953 		.add(args[1].base)
   3954 		.add(ms_sample)
   3955 		.result;
   3956 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3957 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3958 
   3959 	return
   3960 	add_instruction(spv::OpAtomicUMin, convert_type(res_type))
   3961 		.add(texel)
   3962 		.add(mem_scope)
   3963 		.add(mem_semantics)
   3964 		.add(args[2].base)
   3965 		.result;
   3966 	})
   3967 
   3968 // ret atomicMax(inout mem, data)
   3969 DEFINE_INTRINSIC(atomicMax, 0, int, inout_int, int)
   3970 DEFINE_INTRINSIC(atomicMax, 1, uint, inout_uint, uint)
   3971 IMPLEMENT_INTRINSIC_GLSL(atomicMax, 0, {
   3972 	code += "atomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3973 	})
   3974 IMPLEMENT_INTRINSIC_GLSL(atomicMax, 1, {
   3975 	code += "atomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3976 	})
   3977 IMPLEMENT_INTRINSIC_HLSL(atomicMax, 0, {
   3978 	if (_shader_model >= 50)
   3979 		code += "InterlockedMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3980 	else
   3981 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3982 	})
   3983 IMPLEMENT_INTRINSIC_HLSL(atomicMax, 1, {
   3984 	if (_shader_model >= 50)
   3985 		code += "InterlockedMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   3986 	else
   3987 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   3988 	})
   3989 IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 0, {
   3990 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   3991 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   3992 
   3993 	return
   3994 	add_instruction(spv::OpAtomicSMax, convert_type(res_type))
   3995 		.add(args[0].base)
   3996 		.add(mem_scope)
   3997 		.add(mem_semantics)
   3998 		.add(args[1].base)
   3999 		.result;
   4000 	})
   4001 IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 1, {
   4002 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4003 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4004 
   4005 	return
   4006 	add_instruction(spv::OpAtomicUMax, convert_type(res_type))
   4007 		.add(args[0].base)
   4008 		.add(mem_scope)
   4009 		.add(mem_semantics)
   4010 		.add(args[1].base)
   4011 		.result;
   4012 	})
   4013 // ret atomicMax(s, coords, data)
   4014 DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage1d_int, int, int)
   4015 DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage2d_int, int2, int)
   4016 DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage3d_int, int3, int)
   4017 DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage1d_uint, int, uint)
   4018 DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage2d_uint, int2, uint)
   4019 DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage3d_uint, int3, uint)
   4020 IMPLEMENT_INTRINSIC_GLSL(atomicMax, 2, {
   4021 	code += "imageAtomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   4022 	})
   4023 IMPLEMENT_INTRINSIC_GLSL(atomicMax, 3, {
   4024 	code += "imageAtomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   4025 	})
   4026 IMPLEMENT_INTRINSIC_HLSL(atomicMax, 2, {
   4027 	if (_shader_model >= 50)
   4028 		code += "InterlockedMax(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   4029 	})
   4030 IMPLEMENT_INTRINSIC_HLSL(atomicMax, 3, {
   4031 	if (_shader_model >= 50)
   4032 		code += "InterlockedMax(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   4033 	})
   4034 IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 2, {
   4035 	const spv::Id ms_sample = emit_constant(0u);
   4036 
   4037 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   4038 		.add(args[0].base)
   4039 		.add(args[1].base)
   4040 		.add(ms_sample)
   4041 		.result;
   4042 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4043 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4044 
   4045 	return
   4046 	add_instruction(spv::OpAtomicSMax, convert_type(res_type))
   4047 		.add(texel)
   4048 		.add(mem_scope)
   4049 		.add(mem_semantics)
   4050 		.add(args[2].base)
   4051 		.result;
   4052 	})
   4053 IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 3, {
   4054 	const spv::Id ms_sample = emit_constant(0u);
   4055 
   4056 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   4057 		.add(args[0].base)
   4058 		.add(args[1].base)
   4059 		.add(ms_sample)
   4060 		.result;
   4061 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4062 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4063 
   4064 	return
   4065 	add_instruction(spv::OpAtomicUMax, convert_type(res_type))
   4066 		.add(texel)
   4067 		.add(mem_scope)
   4068 		.add(mem_semantics)
   4069 		.add(args[2].base)
   4070 		.result;
   4071 	})
   4072 
   4073 // ret atomicExchange(inout mem, data)
   4074 DEFINE_INTRINSIC(atomicExchange, 0, int, inout_int, int)
   4075 DEFINE_INTRINSIC(atomicExchange, 0, uint, inout_uint, uint)
   4076 IMPLEMENT_INTRINSIC_GLSL(atomicExchange, 0, {
   4077 	code += "atomicExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
   4078 	})
   4079 IMPLEMENT_INTRINSIC_HLSL(atomicExchange, 0, {
   4080 	if (_shader_model >= 50)
   4081 		code += "InterlockedExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
   4082 	else
   4083 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = " + id_to_name(args[1].base);
   4084 	})
   4085 IMPLEMENT_INTRINSIC_SPIRV(atomicExchange, 0, {
   4086 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4087 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4088 
   4089 	return
   4090 	add_instruction(spv::OpAtomicExchange, convert_type(res_type))
   4091 		.add(args[0].base)
   4092 		.add(mem_scope)
   4093 		.add(mem_semantics)
   4094 		.add(args[1].base)
   4095 		.result;
   4096 	})
   4097 // ret atomicExchange(s, coords, data)
   4098 DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage1d_int, int, int)
   4099 DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage2d_int, int2, int)
   4100 DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage3d_int, int3, int)
   4101 DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage1d_uint, int, uint)
   4102 DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage2d_uint, int2, uint)
   4103 DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage3d_uint, int3, uint)
   4104 IMPLEMENT_INTRINSIC_GLSL(atomicExchange, 1, {
   4105 	code += "imageAtomicExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   4106 	})
   4107 IMPLEMENT_INTRINSIC_HLSL(atomicExchange, 1, {
   4108 	if (_shader_model >= 50)
   4109 		code += "InterlockedExchange(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   4110 	})
   4111 IMPLEMENT_INTRINSIC_SPIRV(atomicExchange, 1, {
   4112 	const spv::Id ms_sample = emit_constant(0u);
   4113 
   4114 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   4115 		.add(args[0].base)
   4116 		.add(args[1].base)
   4117 		.add(ms_sample)
   4118 		.result;
   4119 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4120 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4121 
   4122 	return
   4123 	add_instruction(spv::OpAtomicExchange, convert_type(res_type))
   4124 		.add(texel)
   4125 		.add(mem_scope)
   4126 		.add(mem_semantics)
   4127 		.add(args[2].base)
   4128 		.result;
   4129 	})
   4130 
   4131 // ret atomicCompareExchange(inout mem, compare, data)
   4132 DEFINE_INTRINSIC(atomicCompareExchange, 0, int, inout_int, int, int)
   4133 DEFINE_INTRINSIC(atomicCompareExchange, 0, uint, inout_uint, uint, uint)
   4134 IMPLEMENT_INTRINSIC_GLSL(atomicCompareExchange, 0, {
   4135 	code += "atomicCompSwap(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
   4136 	})
   4137 IMPLEMENT_INTRINSIC_HLSL(atomicCompareExchange, 0, {
   4138 	if (_shader_model >= 50)
   4139 		code += "InterlockedCompareExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
   4140 	else
   4141 		code += id_to_name(res) + " = " + id_to_name(args[0].base) + "; if (" + id_to_name(args[0].base) + " == " + id_to_name(args[1].base) + ") " + id_to_name(args[0].base) + " = " + id_to_name(args[2].base);
   4142 	})
   4143 IMPLEMENT_INTRINSIC_SPIRV(atomicCompareExchange, 0, {
   4144 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4145 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4146 
   4147 	return
   4148 	add_instruction(spv::OpAtomicCompareExchange, convert_type(res_type))
   4149 		.add(args[0].base)
   4150 		.add(mem_scope)
   4151 		.add(mem_semantics)
   4152 		.add(mem_semantics)
   4153 		.add(args[2].base)
   4154 		.add(args[1].base)
   4155 		.result;
   4156 	})
   4157 // ret atomicCompareExchange(s, coords, compare, data)
   4158 DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage1d_int, int, int, int)
   4159 DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage2d_int, int2, int, int)
   4160 DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage3d_int, int3, int, int)
   4161 DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage1d_uint, int, uint, uint)
   4162 DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage2d_uint, int2, uint, uint)
   4163 DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage3d_uint, int3, uint, uint)
   4164 IMPLEMENT_INTRINSIC_GLSL(atomicCompareExchange, 1, {
   4165 	code += "imageAtomicCompSwap(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
   4166 	})
   4167 IMPLEMENT_INTRINSIC_HLSL(atomicCompareExchange, 1, {
   4168 	if (_shader_model >= 50)
   4169 		code += "InterlockedCompareExchange(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(res) + ')';
   4170 	})
   4171 IMPLEMENT_INTRINSIC_SPIRV(atomicCompareExchange, 1, {
   4172 	const spv::Id ms_sample = emit_constant(0u);
   4173 
   4174 	const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
   4175 		.add(args[0].base)
   4176 		.add(args[1].base)
   4177 		.add(ms_sample)
   4178 		.result;
   4179 	const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
   4180 	const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
   4181 
   4182 	return
   4183 	add_instruction(spv::OpAtomicCompareExchange, convert_type(res_type))
   4184 		.add(texel)
   4185 		.add(mem_scope)
   4186 		.add(mem_semantics)
   4187 		.add(mem_semantics)
   4188 		.add(args[3].base)
   4189 		.add(args[2].base)
   4190 		.result;
   4191 	})
   4192 
   4193 #undef DEFINE_INTRINSIC
   4194 #undef IMPLEMENT_INTRINSIC_GLSL
   4195 #undef IMPLEMENT_INTRINSIC_HLSL
   4196 #undef IMPLEMENT_INTRINSIC_SPIRV