+#include <msp/core/algorithm.h>
#include <msp/core/maputils.h>
#include <msp/core/raii.h>
#include "reflect.h"
const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] =
{
- { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0 },
- { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0 },
- { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0 },
- { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0 },
- { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0 },
- { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0 },
- { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0 },
- { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0 },
- { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0 },
- { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0 },
- { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0 },
- { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0 },
- { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0 },
- { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0 },
- { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0 },
- { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0 },
- { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0 },
- { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0 },
- { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0 },
- { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0 },
- { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0 },
- { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0 },
- { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0 },
- { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0 },
- { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0 },
- { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0 },
- { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0 },
- { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0 },
- { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0 },
- { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0 },
- { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0 },
- { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0 },
- { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0 },
- { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0 },
- { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0 },
- { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0 },
- { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0 },
- { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0 },
- { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0 },
- { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0 },
- { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0 },
- { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0 },
- { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0 },
- { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0 },
- { "isnan", "f", "", OP_IS_NAN, { 1 }, 0 },
- { "isinf", "f", "", OP_IS_INF, { 1 }, 0 },
- { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0 },
- { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0 },
- { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0 },
- { "dot", "ff", "", OP_DOT, { 1, 2 }, 0 },
- { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0 },
- { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0 },
- { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0 },
- { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0 },
- { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0 },
- { "matrixCompMult", "ff", "", 0, { 0 }, &SpirVGenerator::visit_builtin_matrix_comp_mult },
- { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0 },
- { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0 },
- { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0 },
- { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0 },
- { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0 },
- { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0 },
- { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0 },
- { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0 },
- { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0 },
- { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0 },
- { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0 },
- { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0 },
- { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0 },
- { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0 },
- { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0 },
- { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0 },
- { "any", "b", "", OP_ANY, { 1 }, 0 },
- { "all", "b", "", OP_ALL, { 1 }, 0 },
- { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0 },
- { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0 },
- { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0 },
- { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0 },
- { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0 },
- { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0 },
- { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0 },
- { "textureSize", "", "", OP_IMAGE_QUERY_SIZE_LOD, { 1, 2 }, 0 },
- { "texture", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture },
- { "textureLod", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture },
- { "texelFetch", "", "", 0, { }, &SpirVGenerator::visit_builtin_texel_fetch },
- { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0 },
- { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0 },
- { "dFdx", "f", "", OP_DP_DX, { 1 }, 0 },
- { "dFdy", "f", "", OP_DP_DY, { 1 }, 0 },
- { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, 0 },
- { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, 0 },
- { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, 0 },
- { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, 0 },
- { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0 },
- { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, 0 },
- { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, 0 },
- { "interpolateAtCentroid", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
- { "interpolateAtSample", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
- { "interpolateAtOffset", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
- { "", "", "", 0, { }, 0 }
+ { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0, 0 },
+ { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0, 0 },
+ { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0, 0 },
+ { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0, 0 },
+ { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0, 0 },
+ { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0, 0 },
+ { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0, 0 },
+ { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0, 0 },
+ { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0, 0 },
+ { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0, 0 },
+ { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0, 0 },
+ { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0, 0 },
+ { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0, 0 },
+ { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0, 0 },
+ { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0, 0 },
+ { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0, 0 },
+ { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0, 0 },
+ { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0, 0 },
+ { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0, 0 },
+ { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0, 0 },
+ { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0, 0 },
+ { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0, 0 },
+ { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0, 0 },
+ { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0, 0 },
+ { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0, 0 },
+ { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0, 0 },
+ { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0, 0 },
+ { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0, 0 },
+ { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0, 0 },
+ { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0, 0 },
+ { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0, 0 },
+ { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0, 0 },
+ { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0, 0 },
+ { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0, 0 },
+ { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0, 0 },
+ { "min", "uu", "GLSL.std.450", GLSL450_U_MIN, { 1, 2 }, 0, 0 },
+ { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0, 0 },
+ { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0, 0 },
+ { "max", "uu", "GLSL.std.450", GLSL450_U_MAX, { 1, 2 }, 0, 0 },
+ { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0, 0 },
+ { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0, 0 },
+ { "clamp", "uuu", "GLSL.std.450", GLSL450_U_CLAMP, { 1, 2, 3 }, 0, 0 },
+ { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0, 0 },
+ { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
+ { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
+ { "mix", "uub", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
+ { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0, 0 },
+ { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0, 0 },
+ { "isnan", "f", "", OP_IS_NAN, { 1 }, 0, 0 },
+ { "isinf", "f", "", OP_IS_INF, { 1 }, 0, 0 },
+ { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0, 0 },
+ { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0, 0 },
+ { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0, 0 },
+ { "dot", "ff", "", OP_DOT, { 1, 2 }, 0, 0 },
+ { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0, 0 },
+ { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0, 0 },
+ { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0, 0 },
+ { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0, 0 },
+ { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0, 0 },
+ { "matrixCompMult", "ff", "", 0, { 0 }, 0, &SpirVGenerator::visit_builtin_matrix_comp_mult },
+ { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0, 0 },
+ { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0, 0 },
+ { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0, 0 },
+ { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0, 0 },
+ { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0, 0 },
+ { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0, 0 },
+ { "lessThan", "uu", "", OP_U_LESS_THAN, { 1, 2 }, 0, 0 },
+ { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "lessThanEqual", "uu", "", OP_U_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0, 0 },
+ { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0, 0 },
+ { "greaterThan", "uu", "", OP_U_GREATER_THAN, { 1, 2 }, 0, 0 },
+ { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "greaterThanEqual", "uu", "", OP_U_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
+ { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0, 0 },
+ { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
+ { "equal", "uu", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
+ { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0, 0 },
+ { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
+ { "notEqual", "uu", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
+ { "any", "b", "", OP_ANY, { 1 }, 0, 0 },
+ { "all", "b", "", OP_ALL, { 1 }, 0, 0 },
+ { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0, 0 },
+ { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0, 0 },
+ { "bitfieldExtract", "uii", "", OP_BIT_FIELD_U_EXTRACT, { 1, 2, 3 }, 0, 0 },
+ { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
+ { "bitfieldInsert", "uuii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
+ { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
+ { "bitfieldReverse", "u", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
+ { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0, 0 },
+ { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
+ { "findLSB", "u", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
+ { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0, 0 },
+ { "findMSB", "u", "GLSL.std.450", GLSL450_FIND_U_MSB, { 1 }, 0, 0 },
+ { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
+ { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
+ { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
+ { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
+ { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
+ { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texel_fetch },
+ { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 },
+ { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 },
+ { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 },
+ { "dFdy", "f", "", OP_DP_DY, { 1 }, 0, 0 },
+ { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0, 0 },
+ { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
+ { "interpolateAtCentroid", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
+ { "interpolateAtSample", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
+ { "interpolateAtOffset", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
+ { "", "", "", 0, { }, 0, 0 }
};
SpirVGenerator::SpirVGenerator():
- stage(0),
- current_function(0),
- writer(content),
- next_id(1),
- r_expression_result_id(0),
- constant_expression(false),
- spec_constant(false),
- reachable(false),
- composite_access(false),
- r_composite_base_id(0),
- r_composite_base(0),
- assignment_source_id(0),
- loop_merge_block_id(0),
- loop_continue_target_id(0)
+ writer(content)
{ }
-void SpirVGenerator::apply(Module &module)
+void SpirVGenerator::apply(Module &module, const Features &f)
{
+ features = f;
use_capability(CAP_SHADER);
- for(list<Stage>::iterator i=module.stages.begin(); i!=module.stages.end(); ++i)
+ for(Stage &s: module.stages)
{
- stage = &*i;
+ stage = &s;
interface_layouts.clear();
- i->content.visit(*this);
+ s.content.visit(*this);
}
writer.finalize(SPIRV_GENERATOR_MSP, next_id);
SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id)
{
+ auto i = declared_ids.find(&node);
+ if(i!=declared_ids.end())
+ {
+ if(i->second.type_id)
+ throw key_error(&node);
+ i->second.type_id = type_id;
+ return i->second.id;
+ }
+
Id id = next_id++;
- insert_unique(declared_ids, &node, Declaration(id, type_id));
+ declared_ids.insert(make_pair(&node, Declaration(id, type_id)));
+ return id;
+}
+
+SpirVGenerator::Id SpirVGenerator::allocate_forward_id(Node &node)
+{
+ auto i = declared_ids.find(&node);
+ if(i!=declared_ids.end())
+ return i->second.id;
+
+ Id id = next_id++;
+ declared_ids.insert(make_pair(&node, Declaration(id, 0)));
return id;
}
return ConstantKey(type_id, value.value<bool>());
else if(value.check_type<int>())
return ConstantKey(type_id, value.value<int>());
+ else if(value.check_type<unsigned>())
+ return ConstantKey(type_id, value.value<unsigned>());
else if(value.check_type<float>())
return ConstantKey(type_id, value.value<float>());
else
return const_id;
}
-SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Kind kind, unsigned size)
+SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Kind kind, unsigned size, bool sign)
{
- Id base_id = (size>1 ? get_standard_type_id(kind, 1) : 0);
- Id &type_id = standard_type_ids[TypeKey(base_id, (size>1 ? size : static_cast<unsigned>(kind)))];
+ Id base_id = (size>1 ? get_standard_type_id(kind, 1, sign) : 0);
+ Id &type_id = standard_type_ids[base_id ? TypeKey(base_id, size) : TypeKey(kind, sign)];
if(!type_id)
{
type_id = next_id++;
else if(kind==BasicTypeDeclaration::BOOL)
writer.write_op(content.globals, OP_TYPE_BOOL, type_id);
else if(kind==BasicTypeDeclaration::INT)
- writer.write_op(content.globals, OP_TYPE_INT, type_id, 32, 1);
+ writer.write_op(content.globals, OP_TYPE_INT, type_id, 32, sign);
else if(kind==BasicTypeDeclaration::FLOAT)
writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, 32);
else
bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) const
{
- map<TypeKey, Id>::const_iterator i = standard_type_ids.find(TypeKey(0, kind));
+ auto i = standard_type_ids.find(TypeKey(kind, true));
return (i!=standard_type_ids.end() && i->second==type_id);
}
-SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id)
+SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align)
{
Id base_type_id = get_id(base_type);
- Id &array_type_id = array_type_ids[TypeKey(base_type_id, size_id)];
+ Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)];
if(!array_type_id)
{
array_type_id = next_id++;
writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id);
unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride;
+ if(extended_align)
+ stride = (stride+15)&~15U;
writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride);
}
if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var.type_declaration))
if(basic->kind==BasicTypeDeclaration::ARRAY)
{
- Id size_id = 0;
- if(var.array_size)
- {
- SetFlag set_const(constant_expression);
- r_expression_result_id = 0;
- var.array_size->visit(*this);
- size_id = r_expression_result_id;
- }
- else
- size_id = get_constant_id(get_standard_type_id(BasicTypeDeclaration::INT, 1), 1);
- return get_array_type_id(*basic->base_type, size_id);
+ if(!var.array_size)
+ throw logic_error("array without size");
+
+ SetFlag set_const(constant_expression);
+ r_expression_result_id = 0;
+ var.array_size->visit(*this);
+ return get_array_type_id(*basic->base_type, r_expression_result_id, basic->extended_alignment);
}
return get_id(*var.type_declaration);
void SpirVGenerator::prune_loads(Id min_id)
{
- for(map<const VariableDeclaration *, Id>::iterator i=variable_load_ids.begin(); i!=variable_load_ids.end(); )
+ for(auto i=variable_load_ids.begin(); i!=variable_load_ids.end(); )
{
if(i->second>=min_id)
variable_load_ids.erase(i++);
writer.begin_op(content.function_body, opcode, (n_args ? 1+has_result*2+n_args : 0));
}
else if(opcode==OP_COMPOSITE_CONSTRUCT)
- writer.begin_op(content.globals, OP_SPEC_CONSTANT_COMPOSITE, (n_args ? 1+has_result*2+n_args : 0));
+ writer.begin_op(content.globals, (spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE),
+ (n_args ? 1+has_result*2+n_args : 0));
+ else if(!spec_constant)
+ throw internal_error("invalid non-specialization constant expression");
else
writer.begin_op(content.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
writer.write(type_id);
writer.write(result_id);
}
- if(constant_expression && opcode!=OP_COMPOSITE_CONSTRUCT)
+ if(spec_constant && opcode!=OP_COMPOSITE_CONSTRUCT)
writer.write(opcode);
return result_id;
void SpirVGenerator::end_expression(Opcode opcode)
{
if(constant_expression)
- opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? OP_SPEC_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP);
+ opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP);
writer.end_op(opcode);
}
void SpirVGenerator::visit(Block &block)
{
- for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
- (*i)->visit(*this);
+ for(const RefPtr<Statement> &s: block.body)
+ s->visit(*this);
}
void SpirVGenerator::visit(Literal &literal)
r_expression_result_id = write_constant(type_id, get_constant_key(type_id, literal.value).int_value, true);
else
r_expression_result_id = get_constant_id(type_id, literal.value);
+ r_constant_result = true;
}
void SpirVGenerator::visit(VariableReference &var)
throw internal_error("reference to non-constant variable in constant context");
r_expression_result_id = get_id(*var.declaration);
+ r_constant_result = true;
return;
}
else if(!current_function)
throw internal_error("non-constant context outside a function");
+ r_constant_result = false;
if(composite_access)
{
- r_composite_base = var.declaration;
r_expression_result_id = 0;
+ if(!assignment_source_id)
+ {
+ auto i = variable_load_ids.find(var.declaration);
+ if(i!=variable_load_ids.end())
+ r_expression_result_id = i->second;
+ }
+ if(!r_expression_result_id)
+ r_composite_base = var.declaration;
}
else if(assignment_source_id)
{
r_expression_result_id = get_load_id(*var.declaration);
}
-void SpirVGenerator::visit(InterfaceBlockReference &iface)
-{
- if(!composite_access || !current_function)
- throw internal_error("invalid interface block reference");
-
- r_composite_base = iface.declaration;
- r_expression_result_id = 0;
-}
-
void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type)
{
Opcode opcode;
throw internal_error("composite access through pointer in constant context");
Id int32_type_id = get_standard_type_id(BasicTypeDeclaration::INT, 1);
- for(vector<unsigned>::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
- *i = (*i<0x400000 ? get_constant_id(int32_type_id, static_cast<int>(*i)) : *i&0x3FFFFF);
+ for(unsigned &i: r_composite_chain)
+ i = (i<0x400000 ? get_constant_id(int32_type_id, static_cast<int>(i)) : i&0x3FFFFF);
/* Find the storage class of the base and obtain appropriate pointer type
for the result. */
const Declaration &base_decl = get_item(declared_ids, r_composite_base);
- map<TypeKey, Id>::const_iterator i = pointer_type_ids.begin();
+ auto i = pointer_type_ids.begin();
for(; (i!=pointer_type_ids.end() && i->second!=base_decl.type_id); ++i) ;
if(i==pointer_type_ids.end())
throw internal_error("could not find storage class");
throw internal_error("assignment to temporary composite");
else
{
- for(vector<unsigned>::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
- for(map<ConstantKey, Id>::iterator j=constant_ids.begin(); (*i>=0x400000 && j!=constant_ids.end()); ++j)
- if(j->second==(*i&0x3FFFFF))
- *i = j->first.int_value;
+ for(unsigned &i: r_composite_chain)
+ for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j)
+ if(j->second==(i&0x3FFFFF))
+ i = j->first.int_value;
opcode = OP_COMPOSITE_EXTRACT;
}
Id access_id = begin_expression(opcode, access_type_id, 1+r_composite_chain.size());
writer.write(r_composite_base_id);
- for(vector<unsigned>::const_iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
- writer.write(*i);
+ for(unsigned i: r_composite_chain)
+ writer.write(i);
end_expression(opcode);
+ r_constant_result = false;
if(r_composite_base)
{
if(assignment_source_id)
writer.write(swizzle.components[i]);
end_expression(OP_VECTOR_SHUFFLE);
}
+ r_constant_result = false;
}
void SpirVGenerator::visit(UnaryExpression &unary)
{
+ if(composite_access)
+ return visit_isolated(unary);
+
unary.expression->visit(*this);
char oper = unary.oper->token[0];
Id result_type_id = get_id(*unary.type);
Opcode opcode = OP_NOP;
+ r_constant_result = false;
if(oper=='!')
opcode = OP_LOGICAL_NOT;
else if(oper=='~')
visit_isolated(*binary.right);
return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
}
+ else if(composite_access)
+ return visit_isolated(binary);
if(assignment_source_id)
throw internal_error("invalid binary expression in assignment target");
Opcode opcode = OP_NOP;
bool swap_operands = false;
+ r_constant_result = false;
+
char oper2 = binary.oper->token[1];
if((oper=='<' || oper=='>') && oper2!=oper)
{
if(basic_left.kind==BasicTypeDeclaration::INT)
- opcode = (oper=='<' ? (oper2=='=' ? OP_S_LESS_THAN_EQUAL : OP_S_LESS_THAN) :
- (oper2=='=' ? OP_S_GREATER_THAN_EQUAL : OP_S_GREATER_THAN));
+ {
+ if(basic_left.sign)
+ opcode = (oper=='<' ? (oper2=='=' ? OP_S_LESS_THAN_EQUAL : OP_S_LESS_THAN) :
+ (oper2=='=' ? OP_S_GREATER_THAN_EQUAL : OP_S_GREATER_THAN));
+ else
+ opcode = (oper=='<' ? (oper2=='=' ? OP_U_LESS_THAN_EQUAL : OP_U_LESS_THAN) :
+ (oper2=='=' ? OP_U_GREATER_THAN_EQUAL : OP_U_GREATER_THAN));
+ }
else if(basic_left.kind==BasicTypeDeclaration::FLOAT)
opcode = (oper=='<' ? (oper2=='=' ? OP_F_ORD_LESS_THAN_EQUAL : OP_F_ORD_LESS_THAN) :
(oper2=='=' ? OP_F_ORD_GREATER_THAN_EQUAL : OP_F_ORD_GREATER_THAN));
else if(oper=='>' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
opcode = OP_SHIFT_RIGHT_ARITHMETIC;
else if(oper=='%' && elem.kind==BasicTypeDeclaration::INT)
- opcode = OP_S_MOD;
+ opcode = (elem.sign ? OP_S_MOD : OP_U_MOD);
else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
{
Opcode elem_op = OP_NOP;
if(elem.kind==BasicTypeDeclaration::INT)
- elem_op = (oper=='+' ? OP_I_ADD : oper=='-' ? OP_I_SUB : oper=='*' ? OP_I_MUL : OP_S_DIV);
+ {
+ if(oper=='/')
+ elem_op = (elem.sign ? OP_S_DIV : OP_U_DIV);
+ else
+ elem_op = (oper=='+' ? OP_I_ADD : oper=='-' ? OP_I_SUB : OP_I_MUL);
+ }
else if(elem.kind==BasicTypeDeclaration::FLOAT)
elem_op = (oper=='+' ? OP_F_ADD : oper=='-' ? OP_F_SUB : oper=='*' ? OP_F_MUL : OP_F_DIV);
SetForScope<Id> set_assign(assignment_source_id, r_expression_result_id);
assign.left->visit(*this);
+ r_constant_result = false;
}
void SpirVGenerator::visit(TernaryExpression &ternary)
{
+ if(composite_access)
+ return visit_isolated(ternary);
if(constant_expression)
{
ternary.condition->visit(*this);
writer.write_op_label(true_label_id);
ternary.true_expr->visit(*this);
Id true_result_id = r_expression_result_id;
+ true_label_id = writer.get_current_block();
writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
writer.write_op_label(false_label_id);
ternary.false_expr->visit(*this);
Id false_result_id = r_expression_result_id;
+ false_label_id = writer.get_current_block();
writer.write_op_label(merge_block_id);
r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4);
writer.write(false_result_id);
writer.write(false_label_id);
end_expression(OP_PHI);
+
+ r_constant_result = false;
}
void SpirVGenerator::visit(FunctionCall &call)
{
- if(constant_expression)
- throw internal_error("function call in constant expression");
- else if(assignment_source_id)
+ if(assignment_source_id)
throw internal_error("assignment to function call");
else if(composite_access)
return visit_isolated(call);
vector<Id> argument_ids;
argument_ids.reserve(call.arguments.size());
- for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
+ bool all_args_const = true;
+ for(const RefPtr<Expression> &a: call.arguments)
{
- (*i)->visit(*this);
+ a->visit(*this);
argument_ids.push_back(r_expression_result_id);
+ all_args_const &= r_constant_result;
}
+ if(constant_expression && (!call.constructor || !all_args_const))
+ throw internal_error("function call in constant expression");
+
Id result_type_id = get_id(*call.type);
+ r_constant_result = false;
if(call.constructor)
- visit_constructor(call, argument_ids);
+ visit_constructor(call, argument_ids, all_args_const);
else if(call.declaration->source==BUILTIN_SOURCE)
{
string arg_types;
- for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
- if(BasicTypeDeclaration *basic_arg = dynamic_cast<BasicTypeDeclaration *>((*i)->type))
+ for(const RefPtr<Expression> &a: call.arguments)
+ if(BasicTypeDeclaration *basic_arg = dynamic_cast<BasicTypeDeclaration *>(a->type))
{
BasicTypeDeclaration &elem_arg = *get_element_type(*basic_arg);
switch(elem_arg.kind)
{
case BasicTypeDeclaration::BOOL: arg_types += 'b'; break;
- case BasicTypeDeclaration::INT: arg_types += 'i'; break;
+ case BasicTypeDeclaration::INT: arg_types += (elem_arg.sign ? 'i' : 'u'); break;
case BasicTypeDeclaration::FLOAT: arg_types += 'f'; break;
default: arg_types += '?';
}
if(builtin_info->function==call.name && (!builtin_info->arg_types[0] || builtin_info->arg_types==arg_types))
break;
+ if(builtin_info->capability)
+ use_capability(static_cast<Capability>(builtin_info->capability));
+
if(builtin_info->opcode)
{
Opcode opcode;
{
r_expression_result_id = begin_expression(OP_FUNCTION_CALL, result_type_id, 1+call.arguments.size());
writer.write(get_id(*call.declaration->definition));
- for(vector<Id>::const_iterator i=argument_ids.begin(); i!=argument_ids.end(); ++i)
- writer.write(*i);
+ for(Id i: argument_ids)
+ writer.write(i);
end_expression(OP_FUNCTION_CALL);
// Any global variables the called function uses might have changed value
set<Node *> dependencies = DependencyCollector().apply(*call.declaration->definition);
- for(set<Node *>::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i)
- if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(*i))
+ for(Node *n: dependencies)
+ if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
variable_load_ids.erase(var);
}
}
-void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids)
+void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids, bool all_args_const)
{
Id result_type_id = get_id(*call.type);
return;
}
+ SetFlag set_const(constant_expression, constant_expression || all_args_const);
+
BasicTypeDeclaration &elem = *get_element_type(*basic);
BasicTypeDeclaration &basic_arg0 = dynamic_cast<BasicTypeDeclaration &>(*call.arguments[0]->type);
BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0);
Id zero_id = get_constant_id(get_id(elem), 0.0f);
for(unsigned i=0; i<n_columns; ++i)
{
- column_ids[i] = begin_expression(OP_COMPOSITE_CONSTRUCT, col_type_id, n_rows);;
+ column_ids[i] = begin_expression(OP_COMPOSITE_CONSTRUCT, col_type_id, n_rows);
for(unsigned j=0; j<n_rows; ++j)
writer.write(j==i ? argument_ids[0] : zero_id);
end_expression(OP_COMPOSITE_CONSTRUCT);
}
else if(elem.kind==BasicTypeDeclaration::BOOL)
{
+ if(constant_expression)
+ throw internal_error("unconverted constant");
+
// Conversion to boolean is implemented as comparing against zero.
Id number_type_id = get_id(elem_arg0);
Id zero_id = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ?
}
else if(elem_arg0.kind==BasicTypeDeclaration::BOOL)
{
+ if(constant_expression)
+ throw internal_error("unconverted constant");
+
/* Conversion from boolean is implemented as selecting from zero
or one. */
Id number_type_id = get_id(elem);
}
else
{
+ if(constant_expression)
+ throw internal_error("unconverted constant");
+
// Scalar or vector conversion between types of equal size.
Opcode opcode;
if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::FLOAT)
- opcode = OP_CONVERT_F_TO_S;
+ opcode = (elem.sign ? OP_CONVERT_F_TO_S : OP_CONVERT_F_TO_U);
else if(elem.kind==BasicTypeDeclaration::FLOAT && elem_arg0.kind==BasicTypeDeclaration::INT)
- opcode = OP_CONVERT_S_TO_F;
+ opcode = (elem_arg0.sign ? OP_CONVERT_S_TO_F : OP_CONVERT_U_TO_F);
+ else if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::INT)
+ opcode = OP_BITCAST;
else
throw internal_error("invalid conversion");
r_expression_result_id = write_construct(get_id(*call.type), column_ids, n_columns);
}
+void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vector<Id> &argument_ids)
+{
+ if(argument_ids.size()<1)
+ throw internal_error("invalid texture query call");
+
+ Opcode opcode;
+ if(call.name=="textureSize")
+ opcode = OP_IMAGE_QUERY_SIZE_LOD;
+ else if(call.name=="textureQueryLod")
+ opcode = OP_IMAGE_QUERY_LOD;
+ else if(call.name=="textureQueryLevels")
+ opcode = OP_IMAGE_QUERY_LEVELS;
+ else
+ throw internal_error("invalid texture query call");
+
+ ImageTypeDeclaration &image_arg0 = dynamic_cast<ImageTypeDeclaration &>(*call.arguments[0]->type);
+
+ Id image_id;
+ if(image_arg0.sampled)
+ {
+ Id image_type_id = get_item(image_type_ids, get_id(image_arg0));
+ image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]);
+ }
+ else
+ image_id = argument_ids[0];
+
+ Id result_type_id = get_id(*call.type);
+ r_expression_result_id = begin_expression(opcode, result_type_id, argument_ids.size());
+ writer.write(image_id);
+ for(unsigned i=1; i<argument_ids.size(); ++i)
+ writer.write(argument_ids[i]);
+ end_expression(opcode);
+}
+
void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector<Id> &argument_ids)
{
if(argument_ids.size()<2)
else
throw internal_error("invalid interpolate call");
- use_capability(CAP_INTERPOLATION_FUNCTION);
-
Id ext_id = import_extension("GLSL.std.450");
r_expression_result_id = begin_expression(OP_EXT_INST, get_id(*call.type));
writer.write(ext_id);
writer.write(opcode);
writer.write(get_id(*var->declaration));
- for(vector<Id>::const_iterator i=argument_ids.begin(); ++i!=argument_ids.end(); )
+ for(auto i=argument_ids.begin(); ++i!=argument_ids.end(); )
writer.write(*i);
end_expression(OP_EXT_INST);
}
bool SpirVGenerator::check_duplicate_type(TypeDeclaration &type)
{
- for(map<Node *, Declaration>::const_iterator i=declared_ids.begin(); i!=declared_ids.end(); ++i)
- if(TypeDeclaration *type2 = dynamic_cast<TypeDeclaration *>(i->first))
+ for(const auto &kvp: declared_ids)
+ if(TypeDeclaration *type2 = dynamic_cast<TypeDeclaration *>(kvp.first))
if(TypeComparer().apply(type, *type2))
{
- insert_unique(declared_ids, &type, i->second);
+ insert_unique(declared_ids, &type, kvp.second);
return true;
}
if((elem->kind==BasicTypeDeclaration::INT || elem->kind==BasicTypeDeclaration::FLOAT) && elem->size!=32)
return false;
- Id standard_id = get_standard_type_id(elem->kind, (basic.kind==BasicTypeDeclaration::VECTOR ? basic.size : 1));
+ Id standard_id = get_standard_type_id(elem->kind, (basic.kind==BasicTypeDeclaration::VECTOR ? basic.size : 1), elem->sign);
insert_unique(declared_ids, &basic, Declaration(standard_id, 0));
writer.write_op_name(standard_id, basic.name);
switch(basic.kind)
{
case BasicTypeDeclaration::INT:
- writer.write_op(content.globals, OP_TYPE_INT, type_id, basic.size, 1);
+ writer.write_op(content.globals, OP_TYPE_INT, type_id, basic.size, basic.sign);
break;
case BasicTypeDeclaration::FLOAT:
writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, basic.size);
{
writer.write_op_name(type_id, image.name);
writer.write_op(content.globals, OP_TYPE_SAMPLED_IMAGE, type_id, image_id);
+ insert_unique(image_type_ids, type_id, image_id);
}
if(image.dimensions==ImageTypeDeclaration::ONE)
return;
Id type_id = allocate_id(strct, 0);
- writer.write_op_name(type_id, strct.name);
+ writer.write_op_name(type_id, (strct.block_name.empty() ? strct.name : strct.block_name));
- if(strct.interface_block)
+ if(!strct.block_name.empty())
writer.write_op_decorate(type_id, DECO_BLOCK);
- bool builtin = (strct.interface_block && !strct.interface_block->block_name.compare(0, 3, "gl_"));
+ bool builtin = !strct.block_name.compare(0, 3, "gl_");
vector<Id> member_type_ids;
member_type_ids.reserve(strct.members.body.size());
- for(NodeList<Statement>::const_iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i)
+ for(const RefPtr<Statement> &s: strct.members.body)
{
- const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(i->get());
+ const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(s.get());
if(!var)
continue;
{
if(var->layout)
{
- const vector<Layout::Qualifier> &qualifiers = var->layout->qualifiers;
- for(vector<Layout::Qualifier>::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j)
+ for(const Layout::Qualifier &q: var->layout->qualifiers)
{
- if(j->name=="offset")
- writer.write_op_member_decorate(type_id, index, DECO_OFFSET, j->value);
- else if(j->name=="column_major")
+ if(q.name=="offset")
+ writer.write_op_member_decorate(type_id, index, DECO_OFFSET, q.value);
+ else if(q.name=="column_major")
writer.write_op_member_decorate(type_id, index, DECO_COL_MAJOR);
- else if(j->name=="row_major")
+ else if(q.name=="row_major")
writer.write_op_member_decorate(type_id, index, DECO_ROW_MAJOR);
}
}
writer.begin_op(content.globals, OP_TYPE_STRUCT);
writer.write(type_id);
- for(vector<Id>::const_iterator i=member_type_ids.begin(); i!=member_type_ids.end(); ++i)
- writer.write(*i);
+ for(Id i: member_type_ids)
+ writer.write(i);
writer.end_op(OP_TYPE_STRUCT);
}
void SpirVGenerator::visit(VariableDeclaration &var)
{
- const vector<Layout::Qualifier> *layout_ql = (var.layout ? &var.layout->qualifiers : 0);
-
- int spec_id = -1;
- if(layout_ql)
- {
- for(vector<Layout::Qualifier>::const_iterator i=layout_ql->begin(); (spec_id<0 && i!=layout_ql->end()); ++i)
- if(i->name=="constant_id")
- spec_id = i->value;
- }
-
Id type_id = get_variable_type_id(var);
Id var_id;
if(!var.init_expression)
throw internal_error("const variable without initializer");
+ int spec_id = get_layout_value(var.layout.get(), "constant_id");
+ Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0);
+ if(spec_id>=0 && *spec_var_id)
+ {
+ insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id));
+ return;
+ }
+
SetFlag set_const(constant_expression);
SetFlag set_spec(spec_constant, spec_id>=0);
r_expression_result_id = 0;
var.init_expression->visit(*this);
var_id = r_expression_result_id;
insert_unique(declared_ids, &var, Declaration(var_id, type_id));
- writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
-
- /* It's unclear what should be done if a specialization constant is
- initialized with anything other than a literal. GLSL doesn't seem to
- prohibit that but SPIR-V says OpSpecConstantOp can't be updated via
- specialization. */
+ if(spec_id>=0)
+ {
+ writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
+ *spec_var_id = var_id;
+ }
}
else
{
- StorageClass storage = (current_function ? STORAGE_FUNCTION : get_interface_storage(var.interface, false));
+ bool push_const = has_layout_qualifier(var.layout.get(), "push_constant");
+
+ StorageClass storage;
+ if(current_function)
+ storage = STORAGE_FUNCTION;
+ else if(push_const)
+ storage = STORAGE_PUSH_CONSTANT;
+ else
+ storage = get_interface_storage(var.interface, var.block_declaration);
+
Id ptr_type_id = get_pointer_type_id(type_id, storage);
if(var.interface=="uniform")
{
- Id &uni_id = declared_uniform_ids["v"+var.name];
+ Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name];
if(uni_id)
{
insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id));
{
SetFlag set_const(constant_expression, !current_function);
r_expression_result_id = 0;
+ r_constant_result = false;
var.init_expression->visit(*this);
init_id = r_expression_result_id;
}
writer.write(init_id);
writer.end_op(OP_VARIABLE);
- if(layout_ql)
+ if(var.layout)
{
- for(vector<Layout::Qualifier>::const_iterator i=layout_ql->begin(); i!=layout_ql->end(); ++i)
+ for(const Layout::Qualifier &q: var.layout->qualifiers)
{
- if(i->name=="location")
- writer.write_op_decorate(var_id, DECO_LOCATION, i->value);
- else if(i->name=="set")
- writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, i->value);
- else if(i->name=="binding")
- writer.write_op_decorate(var_id, DECO_BINDING, i->value);
+ if(q.name=="location")
+ writer.write_op_decorate(var_id, DECO_LOCATION, q.value);
+ else if(q.name=="set")
+ writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, q.value);
+ else if(q.name=="binding")
+ writer.write_op_decorate(var_id, DECO_BINDING, q.value);
}
}
+ if(!var.block_declaration && !var.name.compare(0, 3, "gl_"))
+ {
+ BuiltinSemantic semantic = get_builtin_semantic(var.name);
+ writer.write_op_decorate(var_id, DECO_BUILTIN, semantic);
+ }
if(init_id && current_function)
- writer.write_op(content.function_body, OP_STORE, var_id, init_id);
- }
-
- writer.write_op_name(var_id, var.name);
-}
-
-void SpirVGenerator::visit(InterfaceBlock &iface)
-{
- StorageClass storage = get_interface_storage(iface.interface, true);
- Id type_id;
- if(iface.array)
- type_id = get_array_type_id(*iface.struct_declaration, 0);
- else
- type_id = get_id(*iface.struct_declaration);
- Id ptr_type_id = get_pointer_type_id(type_id, storage);
-
- Id block_id;
- if(iface.interface=="uniform")
- {
- Id &uni_id = declared_uniform_ids["b"+iface.block_name];
- if(uni_id)
{
- insert_unique(declared_ids, &iface, Declaration(uni_id, ptr_type_id));
- return;
+ writer.write_op(content.function_body, OP_STORE, var_id, init_id);
+ variable_load_ids[&var] = init_id;
}
-
- uni_id = block_id = allocate_id(iface, ptr_type_id);
}
- else
- block_id = allocate_id(iface, ptr_type_id);
- writer.write_op_name(block_id, iface.instance_name);
-
- writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage);
- if(iface.layout)
- {
- const vector<Layout::Qualifier> &qualifiers = iface.layout->qualifiers;
- for(vector<Layout::Qualifier>::const_iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
- if(i->name=="binding")
- writer.write_op_decorate(block_id, DECO_BINDING, i->value);
- }
+ if(var.name.find(' ')==string::npos)
+ writer.write_op_name(var_id, var.name);
}
void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id)
writer.write_string(func.name);
set<Node *> dependencies = DependencyCollector().apply(func);
- for(set<Node *>::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i)
- {
- if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(*i))
- {
+ for(Node *n: dependencies)
+ if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
if(!var->interface.empty())
- writer.write(get_id(**i));
- }
- else if(dynamic_cast<InterfaceBlock *>(*i))
- writer.write(get_id(**i));
- }
+ writer.write(get_id(*n));
writer.end_op(OP_ENTRY_POINT);
if(stage->type==Stage::FRAGMENT)
- writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ORIGIN_LOWER_LEFT);
+ {
+ SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT);
+ writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin);
+ }
else if(stage->type==Stage::GEOMETRY)
use_capability(CAP_GEOMETRY);
- for(vector<const InterfaceLayout *>::const_iterator i=interface_layouts.begin(); i!=interface_layouts.end(); ++i)
+ for(const InterfaceLayout *i: interface_layouts)
{
- const vector<Layout::Qualifier> &qualifiers = (*i)->layout.qualifiers;
- for(vector<Layout::Qualifier>::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j)
+ for(const Layout::Qualifier &q: i->layout.qualifiers)
{
- if(j->name=="point")
+ if(q.name=="point")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id,
- ((*i)->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS));
- else if(j->name=="lines")
+ (i->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS));
+ else if(q.name=="lines")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES);
- else if(j->name=="lines_adjacency")
+ else if(q.name=="lines_adjacency")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES_ADJACENCY);
- else if(j->name=="triangles")
+ else if(q.name=="triangles")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES);
- else if(j->name=="triangles_adjacency")
+ else if(q.name=="triangles_adjacency")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY);
- else if(j->name=="line_strip")
+ else if(q.name=="line_strip")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP);
- else if(j->name=="triangle_strip")
+ else if(q.name=="triangle_strip")
writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP);
- else if(j->name=="max_vertices")
- writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, j->value);
+ else if(q.name=="max_vertices")
+ writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value);
}
}
}
void SpirVGenerator::visit(FunctionDeclaration &func)
{
- if(func.source==BUILTIN_SOURCE || func.definition!=&func)
+ if(func.source==BUILTIN_SOURCE)
return;
+ else if(func.definition!=&func)
+ {
+ if(func.definition)
+ allocate_forward_id(*func.definition);
+ return;
+ }
Id return_type_id = get_id(*func.return_type_declaration);
vector<unsigned> param_type_ids;
param_type_ids.reserve(func.parameters.size());
- for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
- param_type_ids.push_back(get_variable_type_id(**i));
+ for(const RefPtr<VariableDeclaration> &p: func.parameters)
+ param_type_ids.push_back(get_variable_type_id(*p));
string sig_with_return = func.return_type+func.signature;
Id &type_id = function_type_ids[sig_with_return];
writer.begin_op(content.globals, OP_TYPE_FUNCTION);
writer.write(type_id);
writer.write(return_type_id);
- for(vector<unsigned>::const_iterator i=param_type_ids.begin(); i!=param_type_ids.end(); ++i)
- writer.write(*i);
+ for(unsigned i: param_type_ids)
+ writer.write(i);
writer.end_op(OP_TYPE_FUNCTION);
writer.write_op_name(type_id, sig_with_return);
{
Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]);
writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id);
+ writer.write_op_name(param_id, func.parameters[i]->name);
// TODO This is probably incorrect if the parameter is assigned to.
variable_load_ids[func.parameters[i].get()] = param_id;
}
+ reachable = true;
writer.begin_function_body(next_id++);
SetForScope<FunctionDeclaration *> set_func(current_function, &func);
func.body.visit(*this);
- if(writer.has_current_block())
+ if(writer.get_current_block())
{
if(!reachable)
writer.write_op(content.function_body, OP_UNREACHABLE);
writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
+ std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
+
writer.write_op_label(true_label_id);
cond.body.visit(*this);
- if(writer.has_current_block())
+ if(writer.get_current_block())
writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
bool reachable_if_true = reachable;
reachable = true;
if(!cond.else_body.body.empty())
{
+ swap(saved_load_ids, variable_load_ids);
writer.write_op_label(false_label_id);
cond.else_body.visit(*this);
reachable |= reachable_if_true;
if(iter.init_statement)
iter.init_statement->visit(*this);
+ for(Node *n: AssignmentCollector().apply(iter))
+ if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(n))
+ variable_load_ids.erase(var);
+
Id header_id = next_id++;
Id continue_id = next_id++;
Id merge_block_id = next_id++;
}
+SpirVGenerator::TypeKey::TypeKey(BasicTypeDeclaration::Kind kind, bool sign):
+ type_id(0)
+{
+ switch(kind)
+ {
+ case BasicTypeDeclaration::VOID: detail = 'v'; break;
+ case BasicTypeDeclaration::BOOL: detail = 'b'; break;
+ case BasicTypeDeclaration::INT: detail = (sign ? 'i' : 'u'); break;
+ case BasicTypeDeclaration::FLOAT: detail = 'f'; break;
+ default: throw invalid_argument("TypeKey::TypeKey");
+ }
+}
+
bool SpirVGenerator::TypeKey::operator<(const TypeKey &other) const
{
if(type_id!=other.type_id)