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():
SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id)
{
+ map<Node *, Declaration>::iterator 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++;
+ declared_ids.insert(make_pair(&node, Declaration(id, type_id)));
+ return id;
+}
+
+SpirVGenerator::Id SpirVGenerator::allocate_forward_id(Node &node)
+{
+ map<Node *, Declaration>::iterator i = declared_ids.find(&node);
+ if(i!=declared_ids.end())
+ 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, 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));
+ map<TypeKey, Id>::const_iterator i = standard_type_ids.find(TypeKey(kind, true));
return (i!=standard_type_ids.end() && i->second==type_id);
}
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.function_body, 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.function_body, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
+ writer.begin_op(content.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
Id result_id = next_id++;
if(has_result)
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);
}
return result_id;
}
-BasicTypeDeclaration &SpirVGenerator::get_element_type(BasicTypeDeclaration &basic)
-{
- if(basic.kind==BasicTypeDeclaration::BOOL || basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
- return basic;
- else if((basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX) && basic.base_type)
- return get_element_type(dynamic_cast<BasicTypeDeclaration &>(*basic.base_type));
- else
- throw invalid_argument("SpirVGenerator::get_element_type");
-}
-
void SpirVGenerator::visit(Block &block)
{
for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
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_composite_base = iface.declaration;
r_expression_result_id = 0;
+ r_constant_result = false;
}
void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type)
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)
return;
BasicTypeDeclaration &basic = dynamic_cast<BasicTypeDeclaration &>(*unary.expression->type);
- BasicTypeDeclaration &elem = get_element_type(basic);
+ BasicTypeDeclaration &elem = *get_element_type(basic);
if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
/* SPIR-V allows constant operations on floating-point values only for
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=='~')
BasicTypeDeclaration &basic_left = dynamic_cast<BasicTypeDeclaration &>(*binary.left->type);
BasicTypeDeclaration &basic_right = dynamic_cast<BasicTypeDeclaration &>(*binary.right->type);
// Expression resolver ensures that element types are the same
- BasicTypeDeclaration &elem = get_element_type(basic_left);
+ BasicTypeDeclaration &elem = *get_element_type(basic_left);
if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
/* SPIR-V allows constant operations on floating-point values only for
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)
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());
+ bool all_args_const = true;
for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
{
(*i)->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))
{
- BasicTypeDeclaration &elem_arg = get_element_type(*basic_arg);
+ 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;
}
}
-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;
}
- BasicTypeDeclaration &elem = get_element_type(*basic);
+ 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);
+ BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0);
if(basic->kind==BasicTypeDeclaration::MATRIX)
{
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);
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)
{
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;
}
}
if(init_id && current_function)
+ {
writer.write_op(content.function_body, OP_STORE, var_id, init_id);
+ variable_load_ids[&var] = init_id;
+ }
}
writer.write_op_name(var_id, var.name);
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;
if(iter.init_statement)
iter.init_statement->visit(*this);
+ variable_load_ids.clear();
+
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)